rnd-20050525-1-src
[rocksndiamonds.git] / src / init.c
index c0e3fce0f4b15e05c26ab701cc4bf76dab399e2c..bce313726214736f80f76eca3b800d19ce164e75 100644 (file)
 #define CONFIG_TOKEN_FONT_INITIAL              "font.initial"
 
 
-struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
+static struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
 
+static int copy_properties[][5] =
+{
+  {
+    EL_BUG,
+    EL_BUG_LEFT,               EL_BUG_RIGHT,
+    EL_BUG_UP,                 EL_BUG_DOWN
+  },
+  {
+    EL_SPACESHIP,
+    EL_SPACESHIP_LEFT,         EL_SPACESHIP_RIGHT,
+    EL_SPACESHIP_UP,           EL_SPACESHIP_DOWN
+  },
+  {
+    EL_BD_BUTTERFLY,
+    EL_BD_BUTTERFLY_LEFT,      EL_BD_BUTTERFLY_RIGHT,
+    EL_BD_BUTTERFLY_UP,                EL_BD_BUTTERFLY_DOWN
+  },
+  {
+    EL_BD_FIREFLY,
+    EL_BD_FIREFLY_LEFT,                EL_BD_FIREFLY_RIGHT,
+    EL_BD_FIREFLY_UP,          EL_BD_FIREFLY_DOWN
+  },
+  {
+    EL_PACMAN,
+    EL_PACMAN_LEFT,            EL_PACMAN_RIGHT,
+    EL_PACMAN_UP,              EL_PACMAN_DOWN
+  },
+  {
+    EL_MOLE,
+    EL_MOLE_LEFT,              EL_MOLE_RIGHT,
+    EL_MOLE_UP,                        EL_MOLE_DOWN
+  },
+  {
+    -1,
+    -1, -1, -1, -1
+  }
+};
 
 static void InitTileClipmasks()
 {
@@ -111,7 +148,7 @@ static void InitTileClipmasks()
   int i;
 
   /* initialize pixmap array for special X11 tile clipping to Pixmap 'None' */
-  for (i=0; i<NUM_TILES; i++)
+  for (i = 0; i < NUM_TILES; i++)
     tile_clipmask[i] = None;
 
 #if defined(TARGET_X11)
@@ -126,7 +163,7 @@ static void InitTileClipmasks()
                           clip_gc_valuemask, &clip_gc_values);
 
 #if 0
-  for (i=0; i<NUM_BITMAPS; i++)
+  for (i = 0; i < NUM_BITMAPS; i++)
   {
     if (pix[i]->clip_mask)
     {
@@ -149,11 +186,11 @@ static void InitTileClipmasks()
                               clip_gc_valuemask, &clip_gc_values);
 
   /* create only those clipping Pixmaps we really need */
-  for (i=0; tile_needs_clipping[i].start>=0; i++)
+  for (i = 0; tile_needs_clipping[i].start >= 0; i++)
   {
     int j;
 
-    for (j=0; j<tile_needs_clipping[i].count; j++)
+    for (j = 0; j < tile_needs_clipping[i].count; j++)
     {
       int tile = tile_needs_clipping[i].start + j;
       int graphic = tile;
@@ -186,7 +223,7 @@ void FreeTileClipmasks()
 #if defined(TARGET_X11)
   int i;
 
-  for (i=0; i<NUM_TILES; i++)
+  for (i = 0; i < NUM_TILES; i++)
   {
     if (tile_clipmask[i] != None)
     {
@@ -200,7 +237,7 @@ void FreeTileClipmasks()
   tile_clip_gc = None;
 
 #if 0
-  for (i=0; i<NUM_BITMAPS; i++)
+  for (i = 0; i < NUM_BITMAPS; i++)
   {
     if (pix[i] != NULL && pix[i]->stored_clip_gc)
     {
@@ -239,6 +276,11 @@ void InitGadgets()
   gadgets_initialized = TRUE;
 }
 
+inline void InitElementSmallImagesScaledUp(int graphic)
+{
+  CreateImageWithSmallImages(graphic, graphic_info[graphic].scale_up_factor);
+}
+
 void InitElementSmallImages()
 {
   struct PropertyMapping *property_mapping = getImageListPropertyMapping();
@@ -246,18 +288,40 @@ void InitElementSmallImages()
   int i;
 
   /* initialize normal images from static configuration */
-  for (i=0; element_to_graphic[i].element > -1; i++)
-    CreateImageWithSmallImages(element_to_graphic[i].graphic);
+  for (i = 0; element_to_graphic[i].element > -1; i++)
+    InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
 
   /* initialize special images from static configuration */
-  for (i=0; element_to_special_graphic[i].element > -1; i++)
-    CreateImageWithSmallImages(element_to_special_graphic[i].graphic);
+  for (i = 0; element_to_special_graphic[i].element > -1; i++)
+    InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
 
-  /* initialize images from dynamic configuration */
-  for (i=0; i < num_property_mappings; i++)
+  /* initialize images from dynamic configuration (may be elements or other) */
+#if 1
+  for (i = 0; i < num_property_mappings; i++)
+    InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
+#else
+  /* !!! THIS DOES NOT WORK -- "artwork_index" is graphic, not element !!! */
+  /* !!! ALSO, non-element graphics might need scaling-up !!! */
+  for (i = 0; i < num_property_mappings; i++)
     if (property_mapping[i].artwork_index < MAX_NUM_ELEMENTS)
-      CreateImageWithSmallImages(property_mapping[i].artwork_index);
+      InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
+#endif
+
+#if 0
+  /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
+  for (i = IMG_EMC_OBJECT; i <= IMG_EMC_SPRITE; i++)
+    InitElementSmallImagesScaledUp(i);
+#endif
+}
+
+#if 1
+/* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
+void SetBitmaps_EM(Bitmap **em_bitmap)
+{
+  em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
+  em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
 }
+#endif
 
 static int getFontBitmapID(int font_nr)
 {
@@ -295,15 +359,15 @@ void InitFontGraphicInfo()
 
   /* always start with reliable default values (normal font graphics) */
 #if 1
-  for (i=0; i < NUM_FONTS; i++)
+  for (i = 0; i < NUM_FONTS; i++)
     font_info[i].graphic = IMG_FONT_INITIAL_1;
 #else
-  for (i=0; i < NUM_FONTS; i++)
+  for (i = 0; i < NUM_FONTS; i++)
     font_info[i].graphic = FONT_INITIAL_1;
 #endif
 
   /* initialize normal font/graphic mapping from static configuration */
-  for (i=0; font_to_graphic[i].font_nr > -1; i++)
+  for (i = 0; font_to_graphic[i].font_nr > -1; i++)
   {
     int font_nr = font_to_graphic[i].font_nr;
     int special = font_to_graphic[i].special;
@@ -316,9 +380,9 @@ void InitFontGraphicInfo()
   }
 
   /* always start with reliable default values (special font graphics) */
-  for (i=0; i < NUM_FONTS; i++)
+  for (i = 0; i < NUM_FONTS; i++)
   {
-    for (j=0; j < NUM_SPECIAL_GFX_ARGS; j++)
+    for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
     {
       font_info[i].special_graphic[j] = font_info[i].graphic;
       font_info[i].special_bitmap_id[j] = i;
@@ -326,7 +390,7 @@ void InitFontGraphicInfo()
   }
 
   /* initialize special font/graphic mapping from static configuration */
-  for (i=0; font_to_graphic[i].font_nr > -1; i++)
+  for (i = 0; font_to_graphic[i].font_nr > -1; i++)
   {
     int font_nr = font_to_graphic[i].font_nr;
     int special = font_to_graphic[i].special;
@@ -341,7 +405,7 @@ void InitFontGraphicInfo()
   }
 
   /* initialize special element/graphic mapping from dynamic configuration */
-  for (i=0; i < num_property_mappings; i++)
+  for (i = 0; i < num_property_mappings; i++)
   {
     int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
     int special = property_mapping[i].ext3_index;
@@ -368,7 +432,7 @@ void InitFontGraphicInfo()
 
   /* ---------- initialize font bitmap definitions ---------- */
 
-  for (i=0; i < NUM_FONTS; i++)
+  for (i = 0; i < NUM_FONTS; i++)
   {
     if (i < NUM_INITIAL_FONTS)
     {
@@ -376,7 +440,7 @@ void InitFontGraphicInfo()
       continue;
     }
 
-    for (j=0; j < NUM_SPECIAL_GFX_ARGS; j++)
+    for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
     {
       int font_bitmap_id = font_info[i].special_bitmap_id[j];
       int graphic = font_info[i].special_graphic[j];
@@ -413,15 +477,18 @@ void InitElementGraphicInfo()
   int num_property_mappings = getImageListPropertyMappingSize();
   int i, act, dir;
 
+  if (graphic_info == NULL)            /* still at startup phase */
+    return;
+
   /* set values to -1 to identify later as "uninitialized" values */
-  for (i=0; i<MAX_NUM_ELEMENTS; i++)
+  for (i = 0; i < MAX_NUM_ELEMENTS; i++)
   {
-    for (act=0; act<NUM_ACTIONS; act++)
+    for (act = 0; act < NUM_ACTIONS; act++)
     {
       element_info[i].graphic[act] = -1;
       element_info[i].crumbled[act] = -1;
 
-      for (dir=0; dir<NUM_DIRECTIONS; dir++)
+      for (dir = 0; dir < NUM_DIRECTIONS; dir++)
       {
        element_info[i].direction_graphic[act][dir] = -1;
        element_info[i].direction_crumbled[act][dir] = -1;
@@ -430,22 +497,25 @@ void InitElementGraphicInfo()
   }
 
   /* initialize normal element/graphic mapping from static configuration */
-  for (i=0; element_to_graphic[i].element > -1; i++)
+  for (i = 0; element_to_graphic[i].element > -1; i++)
   {
     int element      = element_to_graphic[i].element;
     int action       = element_to_graphic[i].action;
     int direction    = element_to_graphic[i].direction;
     boolean crumbled = element_to_graphic[i].crumbled;
     int graphic      = element_to_graphic[i].graphic;
+    int base_graphic = el2baseimg(element);
 
     if (graphic_info[graphic].bitmap == NULL)
       continue;
 
     if ((action > -1 || direction > -1 || crumbled == TRUE) &&
-       el2img(element) != -1)
+       base_graphic != -1)
     {
-      boolean base_redefined = getImageListEntry(el2img(element))->redefined;
-      boolean act_dir_redefined = getImageListEntry(graphic)->redefined;
+      boolean base_redefined =
+       getImageListEntryFromImageID(base_graphic)->redefined;
+      boolean act_dir_redefined =
+       getImageListEntryFromImageID(graphic)->redefined;
 
       /* if the base graphic ("emerald", for example) has been redefined,
         but not the action graphic ("emerald.falling", for example), do not
@@ -475,7 +545,7 @@ void InitElementGraphicInfo()
   }
 
   /* initialize normal element/graphic mapping from dynamic configuration */
-  for (i=0; i < num_property_mappings; i++)
+  for (i = 0; i < num_property_mappings; i++)
   {
     int element   = property_mapping[i].base_index;
     int action    = property_mapping[i].ext1_index;
@@ -502,7 +572,7 @@ void InitElementGraphicInfo()
     if (crumbled)
     {
       if (direction < 0)
-       for (dir=0; dir<NUM_DIRECTIONS; dir++)
+       for (dir = 0; dir < NUM_DIRECTIONS; dir++)
          element_info[element].direction_crumbled[action][dir] = -1;
 
       if (direction > -1)
@@ -513,7 +583,7 @@ void InitElementGraphicInfo()
     else
     {
       if (direction < 0)
-       for (dir=0; dir<NUM_DIRECTIONS; dir++)
+       for (dir = 0; dir < NUM_DIRECTIONS; dir++)
          element_info[element].direction_graphic[action][dir] = -1;
 
       if (direction > -1)
@@ -524,7 +594,7 @@ void InitElementGraphicInfo()
   }
 
   /* now copy all graphics that are defined to be cloned from other graphics */
-  for (i=0; i<MAX_NUM_ELEMENTS; i++)
+  for (i = 0; i < MAX_NUM_ELEMENTS; i++)
   {
     int graphic = element_info[i].graphic[ACTION_DEFAULT];
     int crumbled_like, diggable_like;
@@ -537,11 +607,11 @@ void InitElementGraphicInfo()
 
     if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
     {
-      for (act=0; act<NUM_ACTIONS; act++)
+      for (act = 0; act < NUM_ACTIONS; act++)
        element_info[i].crumbled[act] =
          element_info[crumbled_like].crumbled[act];
-      for (act=0; act<NUM_ACTIONS; act++)
-       for (dir=0; dir<NUM_DIRECTIONS; dir++)
+      for (act = 0; act < NUM_ACTIONS; act++)
+       for (dir = 0; dir < NUM_DIRECTIONS; dir++)
          element_info[i].direction_crumbled[act][dir] =
            element_info[crumbled_like].direction_crumbled[act][dir];
     }
@@ -550,17 +620,22 @@ void InitElementGraphicInfo()
     {
       element_info[i].graphic[ACTION_DIGGING] =
        element_info[diggable_like].graphic[ACTION_DIGGING];
-      for (dir=0; dir<NUM_DIRECTIONS; dir++)
+      for (dir = 0; dir < NUM_DIRECTIONS; dir++)
        element_info[i].direction_graphic[ACTION_DIGGING][dir] =
          element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
     }
   }
 
+#if 1
+  /* set hardcoded definitions for some runtime elements without graphic */
+  element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
+#endif
+
 #if 1
   /* now set all undefined/invalid graphics to -1 to set to default after it */
-  for (i=0; i<MAX_NUM_ELEMENTS; i++)
+  for (i = 0; i < MAX_NUM_ELEMENTS; i++)
   {
-    for (act=0; act<NUM_ACTIONS; act++)
+    for (act = 0; act < NUM_ACTIONS; act++)
     {
       int graphic;
 
@@ -572,7 +647,7 @@ void InitElementGraphicInfo()
       if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
        element_info[i].crumbled[act] = -1;
 
-      for (dir=0; dir<NUM_DIRECTIONS; dir++)
+      for (dir = 0; dir < NUM_DIRECTIONS; dir++)
       {
        graphic = element_info[i].direction_graphic[act][dir];
        if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
@@ -586,8 +661,96 @@ void InitElementGraphicInfo()
   }
 #endif
 
+#if 1
+  /* adjust graphics with 2nd tile for movement according to direction
+     (do this before correcting '-1' values to minimize calculations) */
+  for (i = 0; i < MAX_NUM_ELEMENTS; i++)
+  {
+    for (act = 0; act < NUM_ACTIONS; act++)
+    {
+      for (dir = 0; dir < NUM_DIRECTIONS; dir++)
+      {
+       int graphic = element_info[i].direction_graphic[act][dir];
+       int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
+
+       if (act == ACTION_FALLING)      /* special case */
+         graphic = element_info[i].graphic[act];
+
+       if (graphic != -1 &&
+           graphic_info[graphic].double_movement &&
+           graphic_info[graphic].swap_double_tiles != 0)
+       {
+         struct GraphicInfo *g = &graphic_info[graphic];
+         int src_x_front = g->src_x;
+         int src_y_front = g->src_y;
+         int src_x_back = g->src_x + g->offset2_x;
+         int src_y_back = g->src_y + g->offset2_y;
+         boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
+                                                  g->offset_y != 0);
+         boolean front_is_left_or_upper = (src_x_front < src_x_back ||
+                                           src_y_front < src_y_back);
+#if 0
+         boolean second_tile_is_back =
+           ((move_dir == MV_BIT_LEFT  && front_is_left_or_upper) ||
+            (move_dir == MV_BIT_UP    && front_is_left_or_upper));
+         boolean second_tile_is_front =
+           ((move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
+            (move_dir == MV_BIT_DOWN  && front_is_left_or_upper));
+         boolean second_tile_should_be_front =
+           (g->second_tile_is_start == 0);
+         boolean second_tile_should_be_back =
+           (g->second_tile_is_start == 1);
+#endif
+         boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
+         boolean swap_movement_tiles_autodetected =
+           (!frames_are_ordered_diagonally &&
+            ((move_dir == MV_BIT_LEFT  && !front_is_left_or_upper) ||
+             (move_dir == MV_BIT_UP    && !front_is_left_or_upper) ||
+             (move_dir == MV_BIT_RIGHT &&  front_is_left_or_upper) ||
+             (move_dir == MV_BIT_DOWN  &&  front_is_left_or_upper)));
+         Bitmap *dummy;
+
+#if 0
+         printf("::: CHECKING element %d ('%s'), '%s', dir %d [(%d -> %d, %d), %d => %d]\n",
+                i, element_info[i].token_name,
+                element_action_info[act].suffix, move_dir,
+                g->swap_double_tiles,
+                swap_movement_tiles_never,
+                swap_movement_tiles_always,
+                swap_movement_tiles_autodetected,
+                swap_movement_tiles);
+#endif
+
+         /* swap frontside and backside graphic tile coordinates, if needed */
+         if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
+         {
+           /* get current (wrong) backside tile coordinates */
+           getGraphicSourceExt(graphic, 0, &dummy, &src_x_back, &src_y_back,
+                               TRUE);
+
+           /* set frontside tile coordinates to backside tile coordinates */
+           g->src_x = src_x_back;
+           g->src_y = src_y_back;
+
+           /* invert tile offset to point to new backside tile coordinates */
+           g->offset2_x *= -1;
+           g->offset2_y *= -1;
+
+           /* do not swap front and backside tiles again after correction */
+           g->swap_double_tiles = 0;
+
+#if 0
+           printf("    CORRECTED\n");
+#endif
+         }
+       }
+      }
+    }
+  }
+#endif
+
   /* now set all '-1' values to element specific default values */
-  for (i=0; i<MAX_NUM_ELEMENTS; i++)
+  for (i = 0; i < MAX_NUM_ELEMENTS; i++)
   {
     int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
     int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
@@ -595,11 +758,17 @@ void InitElementGraphicInfo()
     int default_direction_crumbled[NUM_DIRECTIONS];
 
     if (default_graphic == -1)
-      default_graphic = IMG_CHAR_QUESTION;
+      default_graphic = IMG_UNKNOWN;
+#if 1
+    if (default_crumbled == -1)
+      default_crumbled = default_graphic;
+#else
+    /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
     if (default_crumbled == -1)
       default_crumbled = IMG_EMPTY;
+#endif
 
-    for (dir=0; dir<NUM_DIRECTIONS; dir++)
+    for (dir = 0; dir < NUM_DIRECTIONS; dir++)
     {
       default_direction_graphic[dir] =
        element_info[i].direction_graphic[ACTION_DEFAULT][dir];
@@ -608,11 +777,17 @@ void InitElementGraphicInfo()
 
       if (default_direction_graphic[dir] == -1)
        default_direction_graphic[dir] = default_graphic;
+#if 1
+      if (default_direction_crumbled[dir] == -1)
+       default_direction_crumbled[dir] = default_direction_graphic[dir];
+#else
+      /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
       if (default_direction_crumbled[dir] == -1)
        default_direction_crumbled[dir] = default_crumbled;
+#endif
     }
 
-    for (act=0; act<NUM_ACTIONS; act++)
+    for (act = 0; act < NUM_ACTIONS; act++)
     {
       boolean act_remove = ((IS_DIGGABLE(i)    && act == ACTION_DIGGING)  ||
                            (IS_SNAPPABLE(i)   && act == ACTION_SNAPPING) ||
@@ -625,6 +800,10 @@ void InitElementGraphicInfo()
       /* generic default action graphic (defined by "[default]" directive) */
       int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
       int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
+      int default_remove_graphic = IMG_EMPTY;
+
+      if (act_remove && default_action_graphic != -1)
+       default_remove_graphic = default_action_graphic;
 
       /* look for special default action graphic (classic game specific) */
       if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
@@ -641,57 +820,101 @@ void InitElementGraphicInfo()
       if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
        default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
 
+#if 1
+      /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
+      /* !!! make this better !!! */
+      if (i == EL_EMPTY_SPACE)
+      {
+       default_action_graphic = element_info[EL_DEFAULT].graphic[act];
+       default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
+      }
+#endif
+
       if (default_action_graphic == -1)
        default_action_graphic = default_graphic;
+#if 1
+      if (default_action_crumbled == -1)
+       default_action_crumbled = default_action_graphic;
+#else
+      /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
       if (default_action_crumbled == -1)
        default_action_crumbled = default_crumbled;
+#endif
 
-      for (dir=0; dir<NUM_DIRECTIONS; dir++)
+      for (dir = 0; dir < NUM_DIRECTIONS; dir++)
       {
+       /* use action graphic as the default direction graphic, if undefined */
        int default_action_direction_graphic = element_info[i].graphic[act];
        int default_action_direction_crumbled = element_info[i].crumbled[act];
 
        /* no graphic for current action -- use default direction graphic */
        if (default_action_direction_graphic == -1)
          default_action_direction_graphic =
-           (act_remove ? IMG_EMPTY :
+           (act_remove ? default_remove_graphic :
             act_turning ?
             element_info[i].direction_graphic[ACTION_TURNING][dir] :
+            default_action_graphic != default_graphic ?
+            default_action_graphic :
             default_direction_graphic[dir]);
+
+       if (element_info[i].direction_graphic[act][dir] == -1)
+         element_info[i].direction_graphic[act][dir] =
+           default_action_direction_graphic;
+
+#if 1
        if (default_action_direction_crumbled == -1)
          default_action_direction_crumbled =
-           (act_remove ? IMG_EMPTY :
+           element_info[i].direction_graphic[act][dir];
+#else
+       if (default_action_direction_crumbled == -1)
+         default_action_direction_crumbled =
+           (act_remove ? default_remove_graphic :
             act_turning ?
             element_info[i].direction_crumbled[ACTION_TURNING][dir] :
+            default_action_crumbled != default_crumbled ?
+            default_action_crumbled :
             default_direction_crumbled[dir]);
+#endif
 
-       if (element_info[i].direction_graphic[act][dir] == -1)
-         element_info[i].direction_graphic[act][dir] =
-           default_action_direction_graphic;
        if (element_info[i].direction_crumbled[act][dir] == -1)
          element_info[i].direction_crumbled[act][dir] =
            default_action_direction_crumbled;
+
+#if 0
+       if (i == EL_EMC_GRASS &&
+           act == ACTION_DIGGING &&
+           dir == MV_BIT_DOWN)
+         printf("::: direction_crumbled == %d, %d, %d\n",
+                element_info[i].direction_crumbled[act][dir],
+                default_action_direction_crumbled,
+                element_info[i].crumbled[act]);
+#endif
       }
 
       /* no graphic for this specific action -- use default action graphic */
       if (element_info[i].graphic[act] == -1)
        element_info[i].graphic[act] =
-         (act_remove ? IMG_EMPTY :
+         (act_remove ? default_remove_graphic :
           act_turning ? element_info[i].graphic[ACTION_TURNING] :
           default_action_graphic);
+#if 1
+      if (element_info[i].crumbled[act] == -1)
+       element_info[i].crumbled[act] = element_info[i].graphic[act];
+#else
       if (element_info[i].crumbled[act] == -1)
        element_info[i].crumbled[act] =
-         (act_remove ? IMG_EMPTY :
+         (act_remove ? default_remove_graphic :
           act_turning ? element_info[i].crumbled[ACTION_TURNING] :
           default_action_crumbled);
+#endif
     }
   }
 
 #if 1
   /* set animation mode to "none" for each graphic with only 1 frame */
-  for (i=0; i<MAX_NUM_ELEMENTS; i++)
+  for (i = 0; i < MAX_NUM_ELEMENTS; i++)
   {
-    for (act=0; act<NUM_ACTIONS; act++)
+    for (act = 0; act < NUM_ACTIONS; act++)
     {
       int graphic = element_info[i].graphic[act];
       int crumbled = element_info[i].crumbled[act];
@@ -701,7 +924,7 @@ void InitElementGraphicInfo()
       if (graphic_info[crumbled].anim_frames == 1)
        graphic_info[crumbled].anim_mode = ANIM_NONE;
 
-      for (dir=0; dir<NUM_DIRECTIONS; dir++)
+      for (dir = 0; dir < NUM_DIRECTIONS; dir++)
       {
        graphic = element_info[i].direction_graphic[act][dir];
        crumbled = element_info[i].direction_crumbled[act][dir];
@@ -719,9 +942,9 @@ void InitElementGraphicInfo()
 #if DEBUG
   if (options.verbose)
   {
-    for (i=0; i<MAX_NUM_ELEMENTS; i++)
-      if (element_info[i].graphic[ACTION_DEFAULT] == IMG_CHAR_QUESTION &&
-         i != EL_CHAR_QUESTION)
+    for (i = 0; i < MAX_NUM_ELEMENTS; i++)
+      if (element_info[i].graphic[ACTION_DEFAULT] == IMG_UNKNOWN &&
+         i != EL_UNKNOWN)
        Error(ERR_RETURN, "warning: no graphic for element '%s' (%d)",
              element_info[i].token_name, i);
   }
@@ -736,19 +959,22 @@ void InitElementSpecialGraphicInfo()
   int i, j;
 
   /* always start with reliable default values */
-  for (i=0; i < MAX_NUM_ELEMENTS; i++)
-    for (j=0; j < NUM_SPECIAL_GFX_ARGS; j++)
+  for (i = 0; i < MAX_NUM_ELEMENTS; i++)
+    for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
       element_info[i].special_graphic[j] =
        element_info[i].graphic[ACTION_DEFAULT];
 
   /* initialize special element/graphic mapping from static configuration */
-  for (i=0; element_to_special_graphic[i].element > -1; i++)
+  for (i = 0; element_to_special_graphic[i].element > -1; i++)
   {
     int element = element_to_special_graphic[i].element;
     int special = element_to_special_graphic[i].special;
     int graphic = element_to_special_graphic[i].graphic;
-    boolean base_redefined = getImageListEntry(el2img(element))->redefined;
-    boolean special_redefined = getImageListEntry(graphic)->redefined;
+    int base_graphic = el2baseimg(element);
+    boolean base_redefined =
+      getImageListEntryFromImageID(base_graphic)->redefined;
+    boolean special_redefined =
+      getImageListEntryFromImageID(graphic)->redefined;
 
     /* if the base graphic ("emerald", for example) has been redefined,
        but not the special graphic ("emerald.EDITOR", for example), do not
@@ -761,7 +987,7 @@ void InitElementSpecialGraphicInfo()
   }
 
   /* initialize special element/graphic mapping from dynamic configuration */
-  for (i=0; i < num_property_mappings; i++)
+  for (i = 0; i < num_property_mappings; i++)
   {
     int element = property_mapping[i].base_index;
     int special = property_mapping[i].ext3_index;
@@ -776,8 +1002,8 @@ void InitElementSpecialGraphicInfo()
 
 #if 1
   /* now set all undefined/invalid graphics to default */
-  for (i=0; i < MAX_NUM_ELEMENTS; i++)
-    for (j=0; j < NUM_SPECIAL_GFX_ARGS; j++)
+  for (i = 0; i < MAX_NUM_ELEMENTS; i++)
+    for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
       if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
        element_info[i].special_graphic[j] =
          element_info[i].graphic[ACTION_DEFAULT];
@@ -788,23 +1014,84 @@ static int get_element_from_token(char *token)
 {
   int i;
 
-  for (i=0; i < MAX_NUM_ELEMENTS; i++)
+  for (i = 0; i < MAX_NUM_ELEMENTS; i++)
     if (strcmp(element_info[i].token_name, token) == 0)
       return i;
 
   return -1;
 }
 
-static void set_graphic_parameters(int graphic, char **parameter_raw)
+static int get_scaled_graphic_width(int graphic)
 {
-  Bitmap *src_bitmap = getBitmapFromImageID(graphic);
+  int original_width = getOriginalImageWidthFromImageID(graphic);
+  int scale_up_factor = graphic_info[graphic].scale_up_factor;
+
+  return original_width * scale_up_factor;
+}
+
+static int get_scaled_graphic_height(int graphic)
+{
+  int original_height = getOriginalImageHeightFromImageID(graphic);
+  int scale_up_factor = graphic_info[graphic].scale_up_factor;
+
+  return original_height * scale_up_factor;
+}
+
+static void set_graphic_parameters(int graphic, int graphic_copy_from)
+{
+  struct FileInfo *image = getImageListEntryFromImageID(graphic_copy_from);
+  char **parameter_raw = image->parameter;
+  Bitmap *src_bitmap = getBitmapFromImageID(graphic_copy_from);
   int parameter[NUM_GFX_ARGS];
   int anim_frames_per_row = 1, anim_frames_per_col = 1;
   int anim_frames_per_line = 1;
   int i;
 
+#if 1
+#if 1
+
+  /* !!! NEW ARTWORK FALLBACK CODE !!! NEARLY UNTESTED !!! */
+  /* if fallback to default artwork is done, also use the default parameters */
+  if (image->fallback_to_default)
+  {
+#if 0
+    printf("::: FALLBACK for %d\n", graphic_copy_from);
+#endif
+
+    parameter_raw = image->default_parameter;
+  }
+
+#else
+
+  /* !!! ARTWORK FALLBACK CODE !!! NEARLY UNTESTED !!! */
+  /* (better try to set a "fallback -> use default parameters" flag) */
+  if (src_bitmap)
+  {
+    int len_source_filename = strlen(src_bitmap->source_filename);
+    int len_default_filename = strlen(image->default_filename);
+    int pos_basename = len_source_filename - len_default_filename;
+    char *source_basename = &src_bitmap->source_filename[pos_basename];
+
+#if 0
+    printf("::: src_bitmap->source_filename -> '%s'\n",
+          src_bitmap->source_filename);
+    printf("::: image->default_filename     -> '%s'\n",
+          image->default_filename);
+    printf("::: image->filename             -> '%s'\n",
+          image->filename);
+#endif
+
+    /* check if there was a fallback to the default artwork file */
+    if (strcmp(image->filename, image->default_filename) != 0 &&
+       pos_basename >= 0 &&
+       strcmp(source_basename, image->default_filename) == 0)
+      parameter_raw = image->default_parameter;
+  }
+#endif
+#endif
+
   /* get integer values from string parameters */
-  for (i=0; i < NUM_GFX_ARGS; i++)
+  for (i = 0; i < NUM_GFX_ARGS; i++)
   {
     parameter[i] =
       get_parameter_value(image_config_suffix[i].token, parameter_raw[i],
@@ -823,9 +1110,17 @@ static void set_graphic_parameters(int graphic, char **parameter_raw)
   graphic_info[graphic].height = TILEY;
   graphic_info[graphic].offset_x = 0;  /* one or both of these values ... */
   graphic_info[graphic].offset_y = 0;  /* ... will be corrected later */
+  graphic_info[graphic].offset2_x = 0; /* one or both of these values ... */
+  graphic_info[graphic].offset2_y = 0; /* ... will be corrected later */
+  graphic_info[graphic].swap_double_tiles = -1;        /* auto-detect tile swapping */
   graphic_info[graphic].crumbled_like = -1;    /* do not use clone element */
   graphic_info[graphic].diggable_like = -1;    /* do not use clone element */
   graphic_info[graphic].border_size = TILEX / 8;  /* "CRUMBLED" border size */
+  graphic_info[graphic].scale_up_factor = 1;   /* default: no scaling up */
+  graphic_info[graphic].anim_delay_fixed = 0;
+  graphic_info[graphic].anim_delay_random = 0;
+  graphic_info[graphic].post_delay_fixed = 0;
+  graphic_info[graphic].post_delay_random = 0;
 
   /* optional x and y tile position of animation frame sequence */
   if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
@@ -845,10 +1140,20 @@ static void set_graphic_parameters(int graphic, char **parameter_raw)
   if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
     graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
 
+  /* optional zoom factor for scaling up the image to a larger size */
+  if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
+    graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
+  if (graphic_info[graphic].scale_up_factor < 1)
+    graphic_info[graphic].scale_up_factor = 1;         /* no scaling */
+
   if (src_bitmap)
   {
-    anim_frames_per_row = src_bitmap->width  / graphic_info[graphic].width;
-    anim_frames_per_col = src_bitmap->height / graphic_info[graphic].height;
+    /* get final bitmap size (with scaling, but without small images) */
+    int src_bitmap_width  = get_scaled_graphic_width(graphic);
+    int src_bitmap_height = get_scaled_graphic_height(graphic);
+
+    anim_frames_per_row = src_bitmap_width  / graphic_info[graphic].width;
+    anim_frames_per_col = src_bitmap_height / graphic_info[graphic].height;
   }
 
   /* correct x or y offset dependent of vertical or horizontal frame order */
@@ -873,6 +1178,32 @@ static void set_graphic_parameters(int graphic, char **parameter_raw)
   if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
     graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
 
+  /* optionally, moving animations may have separate start and end graphics */
+  graphic_info[graphic].double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
+
+  if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
+    parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
+
+  /* correct x or y offset2 dependent of vertical or horizontal frame order */
+  if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
+    graphic_info[graphic].offset2_y =
+      (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
+       parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].height);
+  else                                 /* frames are ordered horizontally */
+    graphic_info[graphic].offset2_x =
+      (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
+       parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].width);
+
+  /* optionally, the x and y offset of 2nd graphic can be specified directly */
+  if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
+    graphic_info[graphic].offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
+  if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
+    graphic_info[graphic].offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
+
+  /* optionally, the second movement tile can be specified as start tile */
+  if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
+    graphic_info[graphic].swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
+
   /* automatically determine correct number of frames, if not defined */
   if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
     graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
@@ -921,6 +1252,20 @@ static void set_graphic_parameters(int graphic, char **parameter_raw)
   if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
     graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
 
+  /* this is only used for player "boring" and "sleeping" actions */
+  if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
+    graphic_info[graphic].anim_delay_fixed =
+      parameter[GFX_ARG_ANIM_DELAY_FIXED];
+  if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
+    graphic_info[graphic].anim_delay_random =
+      parameter[GFX_ARG_ANIM_DELAY_RANDOM];
+  if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
+    graphic_info[graphic].post_delay_fixed =
+      parameter[GFX_ARG_POST_DELAY_FIXED];
+  if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
+    graphic_info[graphic].post_delay_random =
+      parameter[GFX_ARG_POST_DELAY_RANDOM];
+
   /* this is only used for toon animations */
   graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
   graphic_info[graphic].step_delay  = parameter[GFX_ARG_STEP_DELAY];
@@ -936,8 +1281,6 @@ static void set_graphic_parameters(int graphic, char **parameter_raw)
 static void InitGraphicInfo()
 {
   int fallback_graphic = IMG_CHAR_EXCLAM;
-  struct FileInfo *fallback_image = getImageListEntry(fallback_graphic);
-  Bitmap *fallback_bitmap = getBitmapFromImageID(fallback_graphic);
   int num_images = getImageListSize();
   int i;
 
@@ -949,8 +1292,7 @@ static void InitGraphicInfo()
   GC copy_clipmask_gc = None;
 #endif
 
-  if (graphic_info != NULL)
-    free(graphic_info);
+  checked_free(graphic_info);
 
   graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
 
@@ -961,7 +1303,7 @@ static void InitGraphicInfo()
 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
   if (clipmasks_initialized)
   {
-    for (i=0; i<num_images; i++)
+    for (i = 0; i < num_images; i++)
     {
       if (graphic_info[i].clip_mask)
        XFreePixmap(display, graphic_info[i].clip_mask);
@@ -974,12 +1316,12 @@ static void InitGraphicInfo()
   }
 #endif
 
-  for (i=0; i<num_images; i++)
+  for (i = 0; i < num_images; i++)
   {
-    struct FileInfo *image = getImageListEntry(i);
     Bitmap *src_bitmap;
     int src_x, src_y;
     int first_frame, last_frame;
+    int src_bitmap_width, src_bitmap_height;
 
 #if 0
     printf("::: image: '%s' [%d]\n", image->token, i);
@@ -991,18 +1333,22 @@ static void InitGraphicInfo()
           getTokenFromImageID(i));
 #endif
 
-    set_graphic_parameters(i, image->parameter);
+    set_graphic_parameters(i, i);
 
     /* now check if no animation frames are outside of the loaded image */
 
     if (graphic_info[i].bitmap == NULL)
       continue;                /* skip check for optional images that are undefined */
 
+    /* get final bitmap size (with scaling, but without small images) */
+    src_bitmap_width  = get_scaled_graphic_width(i);
+    src_bitmap_height = get_scaled_graphic_height(i);
+
     first_frame = 0;
     getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
     if (src_x < 0 || src_y < 0 ||
-       src_x + TILEX > src_bitmap->width ||
-       src_y + TILEY > src_bitmap->height)
+       src_x + TILEX > src_bitmap_width ||
+       src_y + TILEY > src_bitmap_height)
     {
       Error(ERR_RETURN_LINE, "-");
       Error(ERR_RETURN, "warning: error found in config file:");
@@ -1017,21 +1363,24 @@ static void InitGraphicInfo()
            src_x, src_y);
       Error(ERR_RETURN, "custom graphic rejected for this element/action");
 
+#if 0
+      Error(ERR_RETURN, "scale_up_factor == %d", scale_up_factor);
+#endif
+
       if (i == fallback_graphic)
        Error(ERR_EXIT, "fatal error: no fallback graphic available");
 
       Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
       Error(ERR_RETURN_LINE, "-");
 
-      set_graphic_parameters(i, fallback_image->default_parameter);
-      graphic_info[i].bitmap = fallback_bitmap;
+      set_graphic_parameters(i, fallback_graphic);
     }
 
     last_frame = graphic_info[i].anim_frames - 1;
     getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
     if (src_x < 0 || src_y < 0 ||
-       src_x + TILEX > src_bitmap->width ||
-       src_y + TILEY > src_bitmap->height)
+       src_x + TILEX > src_bitmap_width ||
+       src_y + TILEY > src_bitmap_height)
     {
       Error(ERR_RETURN_LINE, "-");
       Error(ERR_RETURN, "warning: error found in config file:");
@@ -1052,12 +1401,11 @@ static void InitGraphicInfo()
       Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
       Error(ERR_RETURN_LINE, "-");
 
-      set_graphic_parameters(i, fallback_image->default_parameter);
-      graphic_info[i].bitmap = fallback_bitmap;
+      set_graphic_parameters(i, fallback_graphic);
     }
 
 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
-    /* currently we need only a tile clip mask from the first frame */
+    /* currently we only need a tile clip mask from the first frame */
     getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
 
     if (copy_clipmask_gc == None)
@@ -1099,12 +1447,12 @@ static void InitElementSoundInfo()
   int i, j, act;
 
   /* set values to -1 to identify later as "uninitialized" values */
-  for (i=0; i < MAX_NUM_ELEMENTS; i++)
-    for (act=0; act < NUM_ACTIONS; act++)
+  for (i = 0; i < MAX_NUM_ELEMENTS; i++)
+    for (act = 0; act < NUM_ACTIONS; act++)
       element_info[i].sound[act] = -1;
 
   /* initialize element/sound mapping from static configuration */
-  for (i=0; element_to_sound[i].element > -1; i++)
+  for (i = 0; element_to_sound[i].element > -1; i++)
   {
     int element      = element_to_sound[i].element;
     int action       = element_to_sound[i].action;
@@ -1117,14 +1465,14 @@ static void InitElementSoundInfo()
     if (!is_class)
       element_info[element].sound[action] = sound;
     else
-      for (j=0; j < MAX_NUM_ELEMENTS; j++)
+      for (j = 0; j < MAX_NUM_ELEMENTS; j++)
        if (strcmp(element_info[j].class_name,
                   element_info[element].class_name) == 0)
          element_info[j].sound[action] = sound;
   }
 
   /* initialize element class/sound mapping from dynamic configuration */
-  for (i=0; i < num_property_mappings; i++)
+  for (i = 0; i < num_property_mappings; i++)
   {
     int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
     int action        = property_mapping[i].ext1_index;
@@ -1136,14 +1484,14 @@ static void InitElementSoundInfo()
     if (action < 0)
       action = ACTION_DEFAULT;
 
-    for (j=0; j < MAX_NUM_ELEMENTS; j++)
+    for (j = 0; j < MAX_NUM_ELEMENTS; j++)
       if (strcmp(element_info[j].class_name,
                 element_info[element_class].class_name) == 0)
        element_info[j].sound[action] = sound;
   }
 
   /* initialize element/sound mapping from dynamic configuration */
-  for (i=0; i < num_property_mappings; i++)
+  for (i = 0; i < num_property_mappings; i++)
   {
     int element = property_mapping[i].base_index;
     int action  = property_mapping[i].ext1_index;
@@ -1159,9 +1507,9 @@ static void InitElementSoundInfo()
   }
 
   /* now set all '-1' values to element specific default values */
-  for (i=0; i<MAX_NUM_ELEMENTS; i++)
+  for (i = 0; i < MAX_NUM_ELEMENTS; i++)
   {
-    for (act=0; act < NUM_ACTIONS; act++)
+    for (act = 0; act < NUM_ACTIONS; act++)
     {
       /* generic default action sound (defined by "[default]" directive) */
       int default_action_sound = element_info[EL_DEFAULT].sound[act];
@@ -1174,15 +1522,35 @@ static void InitElementSoundInfo()
       if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
        default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
 
+      /* !!! there's no such thing as a "default action sound" !!! */
+#if 0
       /* look for element specific default sound (independent from action) */
       if (element_info[i].sound[ACTION_DEFAULT] != -1)
        default_action_sound = element_info[i].sound[ACTION_DEFAULT];
+#endif
+
+#if 1
+      /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
+      /* !!! make this better !!! */
+      if (i == EL_EMPTY_SPACE)
+       default_action_sound = element_info[EL_DEFAULT].sound[act];
+#endif
 
       /* no sound for this specific action -- use default action sound */
       if (element_info[i].sound[act] == -1)
        element_info[i].sound[act] = default_action_sound;
     }
   }
+
+#if 1
+  /* copy sound settings to some elements that are only stored in level file
+     in native R'n'D levels, but are used by game engine in native EM levels */
+  for (i = 0; copy_properties[i][0] != -1; i++)
+    for (j = 1; j <= 4; j++)
+      for (act = 0; act < NUM_ACTIONS; act++)
+       element_info[copy_properties[i][j]].sound[act] =
+         element_info[copy_properties[i][0]].sound[act];
+#endif
 }
 
 static void InitGameModeSoundInfo()
@@ -1190,11 +1558,11 @@ static void InitGameModeSoundInfo()
   int i;
 
   /* set values to -1 to identify later as "uninitialized" values */
-  for (i=0; i < NUM_SPECIAL_GFX_ARGS; i++)
+  for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
     menu.sound[i] = -1;
 
   /* initialize gamemode/sound mapping from static configuration */
-  for (i=0; gamemode_to_sound[i].sound > -1; i++)
+  for (i = 0; gamemode_to_sound[i].sound > -1; i++)
   {
     int gamemode = gamemode_to_sound[i].gamemode;
     int sound    = gamemode_to_sound[i].sound;
@@ -1206,13 +1574,13 @@ static void InitGameModeSoundInfo()
   }
 
   /* now set all '-1' values to levelset specific default values */
-  for (i=0; i < NUM_SPECIAL_GFX_ARGS; i++)
+  for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
     if (menu.sound[i] == -1)
       menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
 
 #if 0
   /* TEST ONLY */
-  for (i=0; i < NUM_SPECIAL_GFX_ARGS; i++)
+  for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
     if (menu.sound[i] != -1)
       printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
 #endif
@@ -1224,7 +1592,7 @@ static void set_sound_parameters(int sound, char **parameter_raw)
   int i;
 
   /* get integer values from string parameters */
-  for (i=0; i < NUM_SND_ARGS; i++)
+  for (i = 0; i < NUM_SND_ARGS; i++)
     parameter[i] =
       get_parameter_value(sound_config_suffix[i].token, parameter_raw[i],
                          sound_config_suffix[i].type);
@@ -1232,6 +1600,12 @@ static void set_sound_parameters(int sound, char **parameter_raw)
   /* explicit loop mode setting in configuration overrides default value */
   if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
     sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
+
+  /* sound volume to change the original volume when loading the sound file */
+  sound_info[sound].volume = parameter[SND_ARG_VOLUME];
+
+  /* sound priority to give certain sounds a higher or lower priority */
+  sound_info[sound].volume = parameter[SND_ARG_VOLUME];
 }
 
 static void InitSoundInfo()
@@ -1244,18 +1618,17 @@ static void InitSoundInfo()
   int num_sounds = getSoundListSize();
   int i, j;
 
-  if (sound_info != NULL)
-    free(sound_info);
+  checked_free(sound_info);
 
   sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
   sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
 
   /* initialize sound effect for all elements to "no sound" */
-  for (i=0; i < MAX_NUM_ELEMENTS; i++)
-    for (j=0; j < NUM_ACTIONS; j++)
+  for (i = 0; i < MAX_NUM_ELEMENTS; i++)
+    for (j = 0; j < NUM_ACTIONS; j++)
       element_info[i].sound[j] = SND_UNDEFINED;
 
-  for (i=0; i < num_sounds; i++)
+  for (i = 0; i < num_sounds; i++)
   {
     struct FileInfo *sound = getSoundListEntry(i);
     int len_effect_text = strlen(sound->token);
@@ -1269,7 +1642,7 @@ static void InitSoundInfo()
 
     /* determine all loop sounds and identify certain sound classes */
 
-    for (j=0; element_action_info[j].suffix; j++)
+    for (j = 0; element_action_info[j].suffix; j++)
     {
       int len_action_text = strlen(element_action_info[j].suffix);
 
@@ -1291,7 +1664,7 @@ static void InitSoundInfo()
 
     /* associate elements and some selected sound actions */
 
-    for (j=0; j < MAX_NUM_ELEMENTS; j++)
+    for (j = 0; j < MAX_NUM_ELEMENTS; j++)
     {
       if (element_info[j].class_name)
       {
@@ -1314,10 +1687,26 @@ static void InitSoundInfo()
 
   free(sound_effect_properties);
 
+#if 0
+  /* !!! MOVED TO "InitElementSoundInfo()" !!! */
+  /* !!! everything defined here gets overwritten there !!! */
+
+  /* copy sound settings to some elements that are only stored in level file
+     in native R'n'D levels, but are used by game engine in native EM levels */
+  for (i = 0; i < NUM_ACTIONS; i++)
+    for (j = 0; copy_properties[j][0] != -1; j++)
+      for (k = 1; k <= 4; k++)
+       element_info[copy_properties[j][k]].sound[i] =
+         element_info[copy_properties[j][0]].sound[i];
+
+  printf("::: bug   -> %d\n", element_info[EL_BUG].sound[ACTION_MOVING]);
+  printf("::: bug_r -> %d\n", element_info[EL_BUG_RIGHT].sound[ACTION_MOVING]);
+#endif
+
 #if 0
   /* !!! now handled in InitElementSoundInfo() !!! */
   /* initialize element/sound mapping from dynamic configuration */
-  for (i=0; i < num_property_mappings; i++)
+  for (i = 0; i < num_property_mappings; i++)
   {
     int element   = property_mapping[i].base_index;
     int action    = property_mapping[i].ext1_index;
@@ -1378,13 +1767,13 @@ static void InitGameModeMusicInfo()
   int i;
 
   /* set values to -1 to identify later as "uninitialized" values */
-  for (i=0; i < MAX_LEVELS; i++)
+  for (i = 0; i < MAX_LEVELS; i++)
     levelset.music[i] = -1;
-  for (i=0; i < NUM_SPECIAL_GFX_ARGS; i++)
+  for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
     menu.music[i] = -1;
 
   /* initialize gamemode/music mapping from static configuration */
-  for (i=0; gamemode_to_music[i].music > -1; i++)
+  for (i = 0; gamemode_to_music[i].music > -1; i++)
   {
     int gamemode = gamemode_to_music[i].gamemode;
     int music    = gamemode_to_music[i].music;
@@ -1400,7 +1789,7 @@ static void InitGameModeMusicInfo()
   }
 
   /* initialize gamemode/music mapping from dynamic configuration */
-  for (i=0; i < num_property_mappings; i++)
+  for (i = 0; i < num_property_mappings; i++)
   {
     int prefix   = property_mapping[i].base_index;
     int gamemode = property_mapping[i].ext1_index;
@@ -1437,19 +1826,19 @@ static void InitGameModeMusicInfo()
   /* now set all '-1' values to menu specific default values */
   /* (undefined values of "levelset.music[]" might stay at "-1" to
      allow dynamic selection of music files from music directory!) */
-  for (i=0; i < MAX_LEVELS; i++)
+  for (i = 0; i < MAX_LEVELS; i++)
     if (levelset.music[i] == -1)
       levelset.music[i] = default_levelset_music;
-  for (i=0; i < NUM_SPECIAL_GFX_ARGS; i++)
+  for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
     if (menu.music[i] == -1)
       menu.music[i] = menu.music[GAME_MODE_DEFAULT];
 
 #if 0
   /* TEST ONLY */
-  for (i=0; i < MAX_LEVELS; i++)
+  for (i = 0; i < MAX_LEVELS; i++)
     if (levelset.music[i] != -1)
       printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
-  for (i=0; i < NUM_SPECIAL_GFX_ARGS; i++)
+  for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
     if (menu.music[i] != -1)
       printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
 #endif
@@ -1461,7 +1850,7 @@ static void set_music_parameters(int music, char **parameter_raw)
   int i;
 
   /* get integer values from string parameters */
-  for (i=0; i < NUM_MUS_ARGS; i++)
+  for (i = 0; i < NUM_MUS_ARGS; i++)
     parameter[i] =
       get_parameter_value(music_config_suffix[i].token, parameter_raw[i],
                          music_config_suffix[i].type);
@@ -1476,12 +1865,11 @@ static void InitMusicInfo()
   int num_music = getMusicListSize();
   int i, j;
 
-  if (music_info != NULL)
-    free(music_info);
+  checked_free(music_info);
 
   music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
 
-  for (i=0; i < num_music; i++)
+  for (i = 0; i < num_music; i++)
   {
     struct FileInfo *music = getMusicListEntry(i);
     int len_music_text = strlen(music->token);
@@ -1490,7 +1878,7 @@ static void InitMusicInfo()
 
     /* determine all loop music */
 
-    for (j=0; music_prefix_info[j].prefix; j++)
+    for (j = 0; music_prefix_info[j].prefix; j++)
     {
       int len_prefix_text = strlen(music_prefix_info[j].prefix);
 
@@ -1514,9 +1902,11 @@ static void ReinitializeGraphics()
   InitElementGraphicInfo();            /* element game graphic mapping */
   InitElementSpecialGraphicInfo();     /* element special graphic mapping */
 
-  InitElementSmallImages();            /* create editor and preview images */
+  InitElementSmallImages();            /* scale images to all needed sizes */
   InitFontGraphicInfo();               /* initialize text drawing functions */
 
+  InitGraphicInfo_EM();                        /* graphic mapping for EM engine */
+
   SetMainBackgroundImage(IMG_BACKGROUND);
   SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
 
@@ -1539,6 +1929,158 @@ static void ReinitializeMusic()
   InitGameModeMusicInfo();     /* game mode music mapping */
 }
 
+static int get_special_property_bit(int element, int property_bit_nr)
+{
+  struct PropertyBitInfo
+  {
+    int element;
+    int bit_nr;
+  };
+
+  static struct PropertyBitInfo pb_can_move_into_acid[] =
+  {
+    /* the player may be able fall into acid when gravity is activated */
+    { EL_PLAYER_1,             0       },
+    { EL_PLAYER_2,             0       },
+    { EL_PLAYER_3,             0       },
+    { EL_PLAYER_4,             0       },
+    { EL_SP_MURPHY,            0       },
+    { EL_SOKOBAN_FIELD_PLAYER, 0       },
+
+    /* all element that can move may be able to also move into acid */
+    { EL_BUG,                  1       },
+    { EL_BUG_LEFT,             1       },
+    { EL_BUG_RIGHT,            1       },
+    { EL_BUG_UP,               1       },
+    { EL_BUG_DOWN,             1       },
+    { EL_SPACESHIP,            2       },
+    { EL_SPACESHIP_LEFT,       2       },
+    { EL_SPACESHIP_RIGHT,      2       },
+    { EL_SPACESHIP_UP,         2       },
+    { EL_SPACESHIP_DOWN,       2       },
+    { EL_BD_BUTTERFLY,         3       },
+    { EL_BD_BUTTERFLY_LEFT,    3       },
+    { EL_BD_BUTTERFLY_RIGHT,   3       },
+    { EL_BD_BUTTERFLY_UP,      3       },
+    { EL_BD_BUTTERFLY_DOWN,    3       },
+    { EL_BD_FIREFLY,           4       },
+    { EL_BD_FIREFLY_LEFT,      4       },
+    { EL_BD_FIREFLY_RIGHT,     4       },
+    { EL_BD_FIREFLY_UP,                4       },
+    { EL_BD_FIREFLY_DOWN,      4       },
+    { EL_YAMYAM,               5       },
+    { EL_DARK_YAMYAM,          6       },
+    { EL_ROBOT,                        7       },
+    { EL_PACMAN,               8       },
+    { EL_PACMAN_LEFT,          8       },
+    { EL_PACMAN_RIGHT,         8       },
+    { EL_PACMAN_UP,            8       },
+    { EL_PACMAN_DOWN,          8       },
+    { EL_MOLE,                 9       },
+    { EL_MOLE_LEFT,            9       },
+    { EL_MOLE_RIGHT,           9       },
+    { EL_MOLE_UP,              9       },
+    { EL_MOLE_DOWN,            9       },
+    { EL_PENGUIN,              10      },
+    { EL_PIG,                  11      },
+    { EL_DRAGON,               12      },
+    { EL_SATELLITE,            13      },
+    { EL_SP_SNIKSNAK,          14      },
+    { EL_SP_ELECTRON,          15      },
+    { EL_BALLOON,              16      },
+    { EL_SPRING,               17      },
+
+    { -1,                      -1      },
+  };
+
+  static struct PropertyBitInfo pb_dont_collide_with[] =
+  {
+    { EL_SP_SNIKSNAK,          0       },
+    { EL_SP_ELECTRON,          1       },
+
+    { -1,                      -1      },
+  };
+
+  static struct
+  {
+    int bit_nr;
+    struct PropertyBitInfo *pb_info;
+  } pb_definition[] =
+  {
+    { EP_CAN_MOVE_INTO_ACID,   pb_can_move_into_acid   },
+    { EP_DONT_COLLIDE_WITH,    pb_dont_collide_with    },
+
+    { -1,                      NULL                    },
+  };
+
+  struct PropertyBitInfo *pb_info = NULL;
+  int i;
+
+  for (i = 0; pb_definition[i].bit_nr != -1; i++)
+    if (pb_definition[i].bit_nr == property_bit_nr)
+      pb_info = pb_definition[i].pb_info;
+
+  if (pb_info == NULL)
+    return -1;
+
+  for (i = 0; pb_info[i].element != -1; i++)
+    if (pb_info[i].element == element)
+      return pb_info[i].bit_nr;
+
+  return -1;
+}
+
+#if 1
+void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
+                        boolean property_value)
+{
+  int bit_nr = get_special_property_bit(element, property_bit_nr);
+
+  if (bit_nr > -1)
+  {
+    if (property_value)
+      *bitfield |=  (1 << bit_nr);
+    else
+      *bitfield &= ~(1 << bit_nr);
+  }
+}
+
+boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
+{
+  int bit_nr = get_special_property_bit(element, property_bit_nr);
+
+  if (bit_nr > -1)
+    return ((*bitfield & (1 << bit_nr)) != 0);
+
+  return FALSE;
+}
+
+#else
+
+void setMoveIntoAcidProperty(struct LevelInfo *level, int element, boolean set)
+{
+  int bit_nr = get_special_property_bit(element, EP_CAN_MOVE_INTO_ACID);
+
+  if (bit_nr > -1)
+  {
+    level->can_move_into_acid_bits &= ~(1 << bit_nr);
+
+    if (set)
+      level->can_move_into_acid_bits |= (1 << bit_nr);
+  }
+}
+
+boolean getMoveIntoAcidProperty(struct LevelInfo *level, int element)
+{
+  int bit_nr = get_special_property_bit(element, EP_CAN_MOVE_INTO_ACID);
+
+  if (bit_nr > -1)
+    return ((level->can_move_into_acid_bits & (1 << bit_nr)) != 0);
+
+  return FALSE;
+}
+#endif
+
 void InitElementPropertiesStatic()
 {
   static int ep_diggable[] =
@@ -1550,12 +2092,15 @@ void InitElementPropertiesStatic()
     EL_TRAP,
     EL_INVISIBLE_SAND,
     EL_INVISIBLE_SAND_ACTIVE,
+    EL_EMC_GRASS,
 
     /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
+    /* (if amoeba can grow into anything diggable, maybe keep these out) */
 #if 0
     EL_LANDMINE,
     EL_TRAP_ACTIVE,
     EL_SP_BUGGY_BASE_ACTIVE,
+    EL_EMC_PLANT,
 #endif
     -1
   };
@@ -1576,6 +2121,10 @@ void InitElementPropertiesStatic()
     EL_EM_KEY_2,
     EL_EM_KEY_3,
     EL_EM_KEY_4,
+    EL_EMC_KEY_5,
+    EL_EMC_KEY_6,
+    EL_EMC_KEY_7,
+    EL_EMC_KEY_8,
     EL_DYNAMITE,
     EL_DYNABOMB_INCREASE_NUMBER,
     EL_DYNABOMB_INCREASE_SIZE,
@@ -1593,6 +2142,8 @@ void InitElementPropertiesStatic()
     EL_ENVELOPE_3,
     EL_ENVELOPE_4,
     EL_SPEED_PILL,
+    EL_EMC_LENSES,
+    EL_EMC_MAGNIFIER,
     -1
   };
 
@@ -1621,6 +2172,7 @@ void InitElementPropertiesStatic()
     EL_LANDMINE,
     EL_TRAP_ACTIVE,
     EL_SP_BUGGY_BASE_ACTIVE,
+    EL_EMC_PLANT,
 #endif
     -1
   };
@@ -1722,6 +2274,14 @@ void InitElementPropertiesStatic()
     EL_EM_GATE_2_GRAY,
     EL_EM_GATE_3_GRAY,
     EL_EM_GATE_4_GRAY,
+    EL_EMC_GATE_5,
+    EL_EMC_GATE_6,
+    EL_EMC_GATE_7,
+    EL_EMC_GATE_8,
+    EL_EMC_GATE_5_GRAY,
+    EL_EMC_GATE_6_GRAY,
+    EL_EMC_GATE_7_GRAY,
+    EL_EMC_GATE_8_GRAY,
     EL_SWITCHGATE_OPEN,
     EL_SWITCHGATE_OPENING,
     EL_SWITCHGATE_CLOSED,
@@ -1786,6 +2346,10 @@ void InitElementPropertiesStatic()
     EL_STEELWALL_SLIPPERY,
     EL_PEARL,
     EL_CRYSTAL,
+    EL_EMC_WALL_SLIPPERY_1,
+    EL_EMC_WALL_SLIPPERY_2,
+    EL_EMC_WALL_SLIPPERY_3,
+    EL_EMC_WALL_SLIPPERY_4,
     -1
   };
 
@@ -1796,6 +2360,7 @@ void InitElementPropertiesStatic()
 
   static int ep_can_move[] =
   {
+    /* same elements as in 'pb_can_move_into_acid' */
     EL_BUG,
     EL_SPACESHIP,
     EL_BD_BUTTERFLY,
@@ -1813,6 +2378,7 @@ void InitElementPropertiesStatic()
     EL_SP_ELECTRON,
     EL_BALLOON,
     EL_SPRING,
+    EL_EMC_ANDROID,
     -1
   };
 
@@ -1885,14 +2451,14 @@ void InitElementPropertiesStatic()
     -1
   };
 
-  static int ep_can_explode_by_fire[] =
+  static int ep_explodes_by_fire[] =
   {
-    /* same elements as in 'ep_can_explode_impact' */
+    /* same elements as in 'ep_explodes_impact' */
     EL_BOMB,
     EL_SP_DISK_ORANGE,
     EL_DX_SUPABOMB,
 
-    /* same elements as in 'ep_can_explode_smashed' */
+    /* same elements as in 'ep_explodes_smashed' */
     EL_SATELLITE,
     EL_PIG,
     EL_DRAGON,
@@ -1915,12 +2481,15 @@ void InitElementPropertiesStatic()
     EL_SP_DISK_YELLOW,
     EL_SP_SNIKSNAK,
     EL_SP_ELECTRON,
+#if 0
+    EL_BLACK_ORB,
+#endif
     -1
   };
 
-  static int ep_can_explode_smashed[] =
+  static int ep_explodes_smashed[] =
   {
-    /* same elements as in 'ep_can_explode_impact' */
+    /* same elements as in 'ep_explodes_impact' */
     EL_BOMB,
     EL_SP_DISK_ORANGE,
     EL_DX_SUPABOMB,
@@ -1933,7 +2502,7 @@ void InitElementPropertiesStatic()
     -1
   };
 
-  static int ep_can_explode_impact[] =
+  static int ep_explodes_impact[] =
   {
     EL_BOMB,
     EL_SP_DISK_ORANGE,
@@ -1960,6 +2529,7 @@ void InitElementPropertiesStatic()
     EL_PENGUIN,
     EL_PIG,
     EL_DRAGON,
+    EL_PLAYER_IS_LEAVING,      /* needed for gravity + "block last field" */
     -1
   };
 
@@ -1994,6 +2564,14 @@ void InitElementPropertiesStatic()
     EL_EM_GATE_2_GRAY,
     EL_EM_GATE_3_GRAY,
     EL_EM_GATE_4_GRAY,
+    EL_EMC_GATE_5,
+    EL_EMC_GATE_6,
+    EL_EMC_GATE_7,
+    EL_EMC_GATE_8,
+    EL_EMC_GATE_5_GRAY,
+    EL_EMC_GATE_6_GRAY,
+    EL_EMC_GATE_7_GRAY,
+    EL_EMC_GATE_8_GRAY,
     EL_SWITCHGATE_OPEN,
     EL_TIMEGATE_OPEN,
     -1
@@ -2012,6 +2590,14 @@ void InitElementPropertiesStatic()
     EL_SP_GRAVITY_PORT_RIGHT,
     EL_SP_GRAVITY_PORT_UP,
     EL_SP_GRAVITY_PORT_DOWN,
+    EL_SP_GRAVITY_ON_PORT_LEFT,
+    EL_SP_GRAVITY_ON_PORT_RIGHT,
+    EL_SP_GRAVITY_ON_PORT_UP,
+    EL_SP_GRAVITY_ON_PORT_DOWN,
+    EL_SP_GRAVITY_OFF_PORT_LEFT,
+    EL_SP_GRAVITY_OFF_PORT_RIGHT,
+    EL_SP_GRAVITY_OFF_PORT_UP,
+    EL_SP_GRAVITY_OFF_PORT_DOWN,
     -1
   };
 
@@ -2025,7 +2611,7 @@ void InitElementPropertiesStatic()
     -1
   };
 
-  static int ep_can_explode_1x1[] =
+  static int ep_explodes_1x1_old[] =
   {
     -1
   };
@@ -2046,6 +2632,141 @@ void InitElementPropertiesStatic()
     EL_SATELLITE,
     EL_SP_DISK_YELLOW,
     EL_BALLOON,
+    EL_EMC_ANDROID,
+    -1
+  };
+
+  static int ep_explodes_cross_old[] =
+  {
+    -1
+  };
+
+  static int ep_protected[] =
+  {
+    /* same elements as in 'ep_walkable_inside' */
+    EL_TUBE_ANY,
+    EL_TUBE_VERTICAL,
+    EL_TUBE_HORIZONTAL,
+    EL_TUBE_VERTICAL_LEFT,
+    EL_TUBE_VERTICAL_RIGHT,
+    EL_TUBE_HORIZONTAL_UP,
+    EL_TUBE_HORIZONTAL_DOWN,
+    EL_TUBE_LEFT_UP,
+    EL_TUBE_LEFT_DOWN,
+    EL_TUBE_RIGHT_UP,
+    EL_TUBE_RIGHT_DOWN,
+
+    /* same elements as in 'ep_passable_over' */
+    EL_EM_GATE_1,
+    EL_EM_GATE_2,
+    EL_EM_GATE_3,
+    EL_EM_GATE_4,
+    EL_EM_GATE_1_GRAY,
+    EL_EM_GATE_2_GRAY,
+    EL_EM_GATE_3_GRAY,
+    EL_EM_GATE_4_GRAY,
+    EL_EMC_GATE_5,
+    EL_EMC_GATE_6,
+    EL_EMC_GATE_7,
+    EL_EMC_GATE_8,
+    EL_EMC_GATE_5_GRAY,
+    EL_EMC_GATE_6_GRAY,
+    EL_EMC_GATE_7_GRAY,
+    EL_EMC_GATE_8_GRAY,
+    EL_SWITCHGATE_OPEN,
+    EL_TIMEGATE_OPEN,
+
+    /* same elements as in 'ep_passable_inside' */
+    EL_SP_PORT_LEFT,
+    EL_SP_PORT_RIGHT,
+    EL_SP_PORT_UP,
+    EL_SP_PORT_DOWN,
+    EL_SP_PORT_HORIZONTAL,
+    EL_SP_PORT_VERTICAL,
+    EL_SP_PORT_ANY,
+    EL_SP_GRAVITY_PORT_LEFT,
+    EL_SP_GRAVITY_PORT_RIGHT,
+    EL_SP_GRAVITY_PORT_UP,
+    EL_SP_GRAVITY_PORT_DOWN,
+    EL_SP_GRAVITY_ON_PORT_LEFT,
+    EL_SP_GRAVITY_ON_PORT_RIGHT,
+    EL_SP_GRAVITY_ON_PORT_UP,
+    EL_SP_GRAVITY_ON_PORT_DOWN,
+    EL_SP_GRAVITY_OFF_PORT_LEFT,
+    EL_SP_GRAVITY_OFF_PORT_RIGHT,
+    EL_SP_GRAVITY_OFF_PORT_UP,
+    EL_SP_GRAVITY_OFF_PORT_DOWN,
+    -1
+  };
+
+  static int ep_throwable[] =
+  {
+    -1
+  };
+
+  static int ep_can_explode[] =
+  {
+    /* same elements as in 'ep_explodes_impact' */
+    EL_BOMB,
+    EL_SP_DISK_ORANGE,
+    EL_DX_SUPABOMB,
+
+    /* same elements as in 'ep_explodes_smashed' */
+    EL_SATELLITE,
+    EL_PIG,
+    EL_DRAGON,
+    EL_MOLE,
+
+    /* elements that can explode by explosion or by dragonfire */
+    EL_DYNAMITE_ACTIVE,
+    EL_DYNAMITE,
+    EL_DYNABOMB_PLAYER_1_ACTIVE,
+    EL_DYNABOMB_PLAYER_2_ACTIVE,
+    EL_DYNABOMB_PLAYER_3_ACTIVE,
+    EL_DYNABOMB_PLAYER_4_ACTIVE,
+    EL_DYNABOMB_INCREASE_NUMBER,
+    EL_DYNABOMB_INCREASE_SIZE,
+    EL_DYNABOMB_INCREASE_POWER,
+    EL_SP_DISK_RED_ACTIVE,
+    EL_BUG,
+    EL_PENGUIN,
+    EL_SP_DISK_RED,
+    EL_SP_DISK_YELLOW,
+    EL_SP_SNIKSNAK,
+    EL_SP_ELECTRON,
+
+    /* elements that can explode only by explosion */
+    EL_BLACK_ORB,
+    -1
+  };
+
+  static int ep_gravity_reachable[] =
+  {
+    EL_SAND,
+    EL_SP_BASE,
+    EL_TRAP,
+    EL_INVISIBLE_SAND,
+    EL_INVISIBLE_SAND_ACTIVE,
+    EL_SP_PORT_LEFT,
+    EL_SP_PORT_RIGHT,
+    EL_SP_PORT_UP,
+    EL_SP_PORT_DOWN,
+    EL_SP_PORT_HORIZONTAL,
+    EL_SP_PORT_VERTICAL,
+    EL_SP_PORT_ANY,
+    EL_SP_GRAVITY_PORT_LEFT,
+    EL_SP_GRAVITY_PORT_RIGHT,
+    EL_SP_GRAVITY_PORT_UP,
+    EL_SP_GRAVITY_PORT_DOWN,
+    EL_SP_GRAVITY_ON_PORT_LEFT,
+    EL_SP_GRAVITY_ON_PORT_RIGHT,
+    EL_SP_GRAVITY_ON_PORT_UP,
+    EL_SP_GRAVITY_ON_PORT_DOWN,
+    EL_SP_GRAVITY_OFF_PORT_LEFT,
+    EL_SP_GRAVITY_OFF_PORT_RIGHT,
+    EL_SP_GRAVITY_OFF_PORT_UP,
+    EL_SP_GRAVITY_OFF_PORT_DOWN,
+    EL_EMC_GRASS,
     -1
   };
 
@@ -2056,6 +2777,8 @@ void InitElementPropertiesStatic()
     EL_PLAYER_3,
     EL_PLAYER_4,
     EL_SP_MURPHY,
+    EL_SOKOBAN_FIELD_PLAYER,
+    EL_TRIGGER_PLAYER,
     -1
   };
 
@@ -2100,6 +2823,7 @@ void InitElementPropertiesStatic()
     EL_BALLOON_SWITCH_ANY,
     EL_LAMP,
     EL_TIME_ORB_FULL,
+    EL_EMC_MAGIC_BALL_SWITCH,
     -1
   };
 
@@ -2117,6 +2841,9 @@ void InitElementPropertiesStatic()
     EL_EXIT_OPEN,
     EL_STEELWALL,
     EL_PLAYER_1,
+    EL_PLAYER_2,
+    EL_PLAYER_3,
+    EL_PLAYER_4,
     EL_BD_FIREFLY,
     EL_BD_FIREFLY_1,
     EL_BD_FIREFLY_2,
@@ -2129,6 +2856,7 @@ void InitElementPropertiesStatic()
     EL_BD_BUTTERFLY_4,
     EL_BD_AMOEBA,
     EL_CHAR_QUESTION,
+    EL_UNKNOWN,
     -1
   };
 
@@ -2137,6 +2865,7 @@ void InitElementPropertiesStatic()
     /* should always be valid */
     EL_EMPTY,
 
+    /* standard classic Supaplex elements */
     EL_SP_EMPTY,
     EL_SP_ZONK,
     EL_SP_BASE,
@@ -2178,11 +2907,24 @@ void InitElementPropertiesStatic()
     EL_SP_HARDWARE_BASE_6,
     EL_SP_CHIP_TOP,
     EL_SP_CHIP_BOTTOM,
+
     /* additional elements that appeared in newer Supaplex levels */
     EL_INVISIBLE_WALL,
-    /* more than one murphy in a level results in an inactive clone */
+
+    /* additional gravity port elements (not switching, but setting gravity) */
+    EL_SP_GRAVITY_ON_PORT_LEFT,
+    EL_SP_GRAVITY_ON_PORT_RIGHT,
+    EL_SP_GRAVITY_ON_PORT_UP,
+    EL_SP_GRAVITY_ON_PORT_DOWN,
+    EL_SP_GRAVITY_OFF_PORT_LEFT,
+    EL_SP_GRAVITY_OFF_PORT_RIGHT,
+    EL_SP_GRAVITY_OFF_PORT_UP,
+    EL_SP_GRAVITY_OFF_PORT_DOWN,
+
+    /* more than one Murphy in a level results in an inactive clone */
     EL_SP_MURPHY_CLONE,
-    /* runtime elements*/
+
+    /* runtime Supaplex elements */
     EL_SP_DISK_RED_ACTIVE,
     EL_SP_TERMINAL_ACTIVE,
     EL_SP_BUGGY_BASE_ACTIVATING,
@@ -2199,7 +2941,11 @@ void InitElementPropertiesStatic()
     EL_SOKOBAN_OBJECT,
     EL_SOKOBAN_FIELD_EMPTY,
     EL_SOKOBAN_FIELD_FULL,
+    EL_SOKOBAN_FIELD_PLAYER,
     EL_PLAYER_1,
+    EL_PLAYER_2,
+    EL_PLAYER_3,
+    EL_PLAYER_4,
     EL_INVISIBLE_STEELWALL,
     -1
   };
@@ -2592,6 +3338,14 @@ void InitElementPropertiesStatic()
     EL_EM_GATE_2_GRAY,
     EL_EM_GATE_3_GRAY,
     EL_EM_GATE_4_GRAY,
+    EL_EMC_GATE_5,
+    EL_EMC_GATE_6,
+    EL_EMC_GATE_7,
+    EL_EMC_GATE_8,
+    EL_EMC_GATE_5_GRAY,
+    EL_EMC_GATE_6_GRAY,
+    EL_EMC_GATE_7_GRAY,
+    EL_EMC_GATE_8_GRAY,
     -1
   };
 
@@ -2624,6 +3378,24 @@ void InitElementPropertiesStatic()
     -1
   };
 
+  static int ep_can_turn_each_move[] =
+  {
+    /* !!! do something with this one !!! */
+    -1
+  };
+
+  static int ep_can_grow[] =
+  {
+    EL_BD_AMOEBA,
+    EL_AMOEBA_DROP,
+    EL_AMOEBA_WET,
+    EL_AMOEBA_DRY,
+    EL_AMOEBA_FULL,
+    EL_GAME_OF_LIFE,
+    EL_BIOMAZE,
+    -1
+  };
+
   static int ep_active_bomb[] =
   {
     EL_DYNAMITE_ACTIVE,
@@ -2655,6 +3427,10 @@ void InitElementPropertiesStatic()
     EL_EM_KEY_2,
     EL_EM_KEY_3,
     EL_EM_KEY_4,
+    EL_EMC_KEY_5,
+    EL_EMC_KEY_6,
+    EL_EMC_KEY_7,
+    EL_EMC_KEY_8,
     EL_GATE_1,
     EL_GATE_2,
     EL_GATE_3,
@@ -2671,6 +3447,14 @@ void InitElementPropertiesStatic()
     EL_EM_GATE_2_GRAY,
     EL_EM_GATE_3_GRAY,
     EL_EM_GATE_4_GRAY,
+    EL_EMC_GATE_5,
+    EL_EMC_GATE_6,
+    EL_EMC_GATE_7,
+    EL_EMC_GATE_8,
+    EL_EMC_GATE_5_GRAY,
+    EL_EMC_GATE_6_GRAY,
+    EL_EMC_GATE_7_GRAY,
+    EL_EMC_GATE_8_GRAY,
     EL_DYNAMITE,
     EL_INVISIBLE_STEELWALL,
     EL_INVISIBLE_WALL,
@@ -2735,6 +3519,14 @@ void InitElementPropertiesStatic()
     EL_SP_HARDWARE_BASE_4,
     EL_SP_HARDWARE_BASE_5,
     EL_SP_HARDWARE_BASE_6,
+    EL_SP_GRAVITY_ON_PORT_LEFT,
+    EL_SP_GRAVITY_ON_PORT_RIGHT,
+    EL_SP_GRAVITY_ON_PORT_UP,
+    EL_SP_GRAVITY_ON_PORT_DOWN,
+    EL_SP_GRAVITY_OFF_PORT_LEFT,
+    EL_SP_GRAVITY_OFF_PORT_RIGHT,
+    EL_SP_GRAVITY_OFF_PORT_UP,
+    EL_SP_GRAVITY_OFF_PORT_DOWN,
     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
@@ -2764,6 +3556,10 @@ void InitElementPropertiesStatic()
     EL_EMC_STEELWALL_2,
     EL_EMC_STEELWALL_3,
     EL_EMC_STEELWALL_4,
+    EL_EMC_WALL_SLIPPERY_1,
+    EL_EMC_WALL_SLIPPERY_2,
+    EL_EMC_WALL_SLIPPERY_3,
+    EL_EMC_WALL_SLIPPERY_4,
     EL_EMC_WALL_1,
     EL_EMC_WALL_2,
     EL_EMC_WALL_3,
@@ -2772,6 +3568,14 @@ void InitElementPropertiesStatic()
     EL_EMC_WALL_6,
     EL_EMC_WALL_7,
     EL_EMC_WALL_8,
+    EL_EMC_WALL_9,
+    EL_EMC_WALL_10,
+    EL_EMC_WALL_11,
+    EL_EMC_WALL_12,
+    EL_EMC_WALL_13,
+    EL_EMC_WALL_14,
+    EL_EMC_WALL_15,
+    EL_EMC_WALL_16,
     -1
   };
 
@@ -2808,9 +3612,9 @@ void InitElementPropertiesStatic()
     { ep_can_smash_player,     EP_CAN_SMASH_PLAYER     },
     { ep_can_smash_enemies,    EP_CAN_SMASH_ENEMIES    },
     { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
-    { ep_can_explode_by_fire,  EP_CAN_EXPLODE_BY_FIRE  },
-    { ep_can_explode_smashed,  EP_CAN_EXPLODE_SMASHED  },
-    { ep_can_explode_impact,   EP_CAN_EXPLODE_IMPACT   },
+    { ep_explodes_by_fire,     EP_EXPLODES_BY_FIRE     },
+    { ep_explodes_smashed,     EP_EXPLODES_SMASHED     },
+    { ep_explodes_impact,      EP_EXPLODES_IMPACT      },
     { ep_walkable_over,                EP_WALKABLE_OVER        },
     { ep_walkable_inside,      EP_WALKABLE_INSIDE      },
     { ep_walkable_under,       EP_WALKABLE_UNDER       },
@@ -2818,8 +3622,13 @@ void InitElementPropertiesStatic()
     { ep_passable_inside,      EP_PASSABLE_INSIDE      },
     { ep_passable_under,       EP_PASSABLE_UNDER       },
     { ep_droppable,            EP_DROPPABLE            },
-    { ep_can_explode_1x1,      EP_CAN_EXPLODE_1X1      },
+    { ep_explodes_1x1_old,     EP_EXPLODES_1X1_OLD     },
     { ep_pushable,             EP_PUSHABLE             },
+    { ep_explodes_cross_old,   EP_EXPLODES_CROSS_OLD   },
+    { ep_protected,            EP_PROTECTED            },
+    { ep_throwable,            EP_THROWABLE            },
+    { ep_can_explode,          EP_CAN_EXPLODE          },
+    { ep_gravity_reachable,    EP_GRAVITY_REACHABLE    },
 
     { ep_player,               EP_PLAYER               },
     { ep_can_pass_magic_wall,  EP_CAN_PASS_MAGIC_WALL  },
@@ -2842,6 +3651,8 @@ void InitElementPropertiesStatic()
     { ep_amoeboid,             EP_AMOEBOID             },
     { ep_amoebalive,           EP_AMOEBALIVE           },
     { ep_has_content,          EP_HAS_CONTENT          },
+    { ep_can_turn_each_move,   EP_CAN_TURN_EACH_MOVE   },
+    { ep_can_grow,             EP_CAN_GROW             },
     { ep_active_bomb,          EP_ACTIVE_BOMB          },
     { ep_inactive,             EP_INACTIVE             },
 
@@ -2852,57 +3663,24 @@ void InitElementPropertiesStatic()
     { NULL,                    -1                      }
   };
 
-  static int copy_properties[][5] =
-  {
-    {
-      EL_BUG,
-      EL_BUG_LEFT,             EL_BUG_RIGHT,
-      EL_BUG_UP,               EL_BUG_DOWN
-    },
-    {
-      EL_SPACESHIP,
-      EL_SPACESHIP_LEFT,       EL_SPACESHIP_RIGHT,
-      EL_SPACESHIP_UP,         EL_SPACESHIP_DOWN
-    },
-    {
-      EL_BD_BUTTERFLY,
-      EL_BD_BUTTERFLY_LEFT,    EL_BD_BUTTERFLY_RIGHT,
-      EL_BD_BUTTERFLY_UP,      EL_BD_BUTTERFLY_DOWN
-    },
-    {
-      EL_BD_FIREFLY,
-      EL_BD_FIREFLY_LEFT,      EL_BD_FIREFLY_RIGHT,
-      EL_BD_FIREFLY_UP,                EL_BD_FIREFLY_DOWN
-    },
-    {
-      EL_PACMAN,
-      EL_PACMAN_LEFT,          EL_PACMAN_RIGHT,
-      EL_PACMAN_UP,            EL_PACMAN_DOWN
-    },
-    {
-      -1,
-      -1, -1, -1, -1
-    }
-  };
-
   int i, j, k;
 
   /* always start with reliable default values (element has no properties) */
-  for (i=0; i < MAX_NUM_ELEMENTS; i++)
-    for (j=0; j < NUM_ELEMENT_PROPERTIES; j++)
+  for (i = 0; i < MAX_NUM_ELEMENTS; i++)
+    for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
       SET_PROPERTY(i, j, FALSE);
 
   /* set all base element properties from above array definitions */
-  for (i=0; element_properties[i].elements != NULL; i++)
-    for (j=0; (element_properties[i].elements)[j] != -1; j++)
+  for (i = 0; element_properties[i].elements != NULL; i++)
+    for (j = 0; (element_properties[i].elements)[j] != -1; j++)
       SET_PROPERTY((element_properties[i].elements)[j],
                   element_properties[i].property, TRUE);
 
   /* copy properties to some elements that are only stored in level file */
-  for (i=0; i < NUM_ELEMENT_PROPERTIES; i++)
-    for (j=0; copy_properties[j][0] != -1; j++)
+  for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
+    for (j = 0; copy_properties[j][0] != -1; j++)
       if (HAS_PROPERTY(copy_properties[j][0], i))
-       for (k=1; k<=4; k++)
+       for (k = 1; k <= 4; k++)
          SET_PROPERTY(copy_properties[j][k], i, TRUE);
 }
 
@@ -2923,7 +3701,7 @@ void InitElementPropertiesEngine(int engine_version)
     EP_DONT_TOUCH,
     EP_DONT_RUN_INTO,
     EP_GEM,
-    EP_CAN_EXPLODE_BY_FIRE,
+    EP_EXPLODES_BY_FIRE,
     EP_PUSHABLE,
     EP_PLAYER,
     EP_HAS_CONTENT,
@@ -2965,6 +3743,7 @@ void InitElementPropertiesEngine(int engine_version)
     EP_ACTIVE_BOMB,
 
     EP_ACCESSIBLE,
+
     -1
   };
 
@@ -2974,17 +3753,22 @@ void InitElementPropertiesEngine(int engine_version)
   InitElementPropertiesStatic();
 #endif
 
+  /* important: after initialization in InitElementPropertiesStatic(), the
+     elements are not again initialized to a default value; therefore all
+     changes have to make sure that they leave the element with a defined
+     property (which means that conditional property changes must be set to
+     a reliable default value before) */
+
   /* set all special, combined or engine dependent element properties */
-  for (i=0; i < MAX_NUM_ELEMENTS; i++)
+  for (i = 0; i < MAX_NUM_ELEMENTS; i++)
   {
 #if 0
-    for (j=EP_ACCESSIBLE_OVER; j < NUM_ELEMENT_PROPERTIES; j++)
+    for (j = EP_ACCESSIBLE_OVER; j < NUM_ELEMENT_PROPERTIES; j++)
       SET_PROPERTY(i, j, FALSE);
 #endif
 
     /* ---------- INACTIVE ------------------------------------------------- */
-    if (i >= EL_CHAR_START && i <= EL_CHAR_END)
-      SET_PROPERTY(i, EP_INACTIVE, TRUE);
+    SET_PROPERTY(i, EP_INACTIVE, (i >= EL_CHAR_START && i <= EL_CHAR_END));
 
     /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
     SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
@@ -3009,7 +3793,8 @@ void InitElementPropertiesEngine(int engine_version)
 
     /* ---------- COLLECTIBLE ---------------------------------------------- */
     SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
-                                    IS_DROPPABLE(i)));
+                                    IS_DROPPABLE(i) ||
+                                    IS_THROWABLE(i)));
 
     /* ---------- SNAPPABLE ------------------------------------------------ */
     SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
@@ -3020,7 +3805,7 @@ void InitElementPropertiesEngine(int engine_version)
     /* ---------- WALL ----------------------------------------------------- */
     SET_PROPERTY(i, EP_WALL, TRUE);    /* default: element is wall */
 
-    for (j=0; no_wall_properties[j] != -1; j++)
+    for (j = 0; no_wall_properties[j] != -1; j++)
       if (HAS_PROPERTY(i, no_wall_properties[j]) ||
          i >= EL_FIRST_RUNTIME_UNREAL)
        SET_PROPERTY(i, EP_WALL, FALSE);
@@ -3036,6 +3821,12 @@ void InitElementPropertiesEngine(int engine_version)
                                             !IS_DIGGABLE(i) &&
                                             !IS_COLLECTIBLE(i)));
 
+#if 0
+    /* ---------- PROTECTED ------------------------------------------------ */
+    if (IS_ACCESSIBLE_INSIDE(i))
+      SET_PROPERTY(i, EP_PROTECTED, TRUE);
+#endif
+
     /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
 
     if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
@@ -3050,12 +3841,25 @@ void InitElementPropertiesEngine(int engine_version)
     else if (engine_version < VERSION_IDENT(2,2,0,0))
       SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
     else
+#if 1
+      SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
+                                          (!IS_WALKABLE(i) ||
+                                           IS_PROTECTED(i))));
+#else
+#if 1
       SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
                                           !IS_WALKABLE_OVER(i) &&
                                           !IS_WALKABLE_UNDER(i)));
+#else
+      SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
+                                          IS_PROTECTED(i)));
+#endif
+#endif
 
     if (IS_CUSTOM_ELEMENT(i))
     {
+      /* these are additional properties which are initially false when set */
+
       /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
       if (DONT_TOUCH(i))
        SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
@@ -3074,33 +3878,92 @@ void InitElementPropertiesEngine(int engine_version)
                                   CAN_SMASH_ENEMIES(i) ||
                                   CAN_SMASH_EVERYTHING(i)));
 
+#if 0
     /* ---------- CAN_EXPLODE ---------------------------------------------- */
     SET_PROPERTY(i, EP_CAN_EXPLODE, (CAN_EXPLODE_BY_FIRE(i) ||
                                     CAN_EXPLODE_SMASHED(i) ||
                                     CAN_EXPLODE_IMPACT(i)));
+#endif
 
+#if 0
     /* ---------- CAN_EXPLODE_3X3 ------------------------------------------ */
+#if 0
+    SET_PROPERTY(i, EP_CAN_EXPLODE_3X3, (!CAN_EXPLODE_1X1(i) &&
+                                        !CAN_EXPLODE_CROSS(i)));
+#else
     SET_PROPERTY(i, EP_CAN_EXPLODE_3X3, (CAN_EXPLODE(i) &&
-                                        !CAN_EXPLODE_1X1(i)));
+                                        !CAN_EXPLODE_1X1(i) &&
+                                        !CAN_EXPLODE_CROSS(i)));
+#endif
+#endif
+
+    /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
+    SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
+                                            EXPLODES_BY_FIRE(i)));
+
+    /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
+    SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
+                                            EXPLODES_SMASHED(i)));
+
+    /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
+    SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
+                                           EXPLODES_IMPACT(i)));
+
+    /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
+    SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
+
+    /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
+    SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
+                                                 i == EL_BLACK_ORB));
+
+    /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
+    SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
+                                             CAN_MOVE(i) ||
+                                             IS_CUSTOM_ELEMENT(i)));
+
+    /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
+    SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
+                                                i == EL_SP_ELECTRON));
+
+    /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
+    if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
+      SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
+                  getMoveIntoAcidProperty(&level, i));
+
+    /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
+    if (MAYBE_DONT_COLLIDE_WITH(i))
+      SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
+                  getDontCollideWithProperty(&level, i));
+
+    /* ---------- SP_PORT -------------------------------------------------- */
+    SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
+                                IS_PASSABLE_INSIDE(i)));
 
     /* ---------- CAN_CHANGE ----------------------------------------------- */
     SET_PROPERTY(i, EP_CAN_CHANGE, FALSE);     /* default: cannot change */
-    for (j=0; j < element_info[i].num_change_pages; j++)
+    for (j = 0; j < element_info[i].num_change_pages; j++)
       if (element_info[i].change_page[j].can_change)
        SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
 
     /* ---------- GFX_CRUMBLED --------------------------------------------- */
+#if 1
+    SET_PROPERTY(i, EP_GFX_CRUMBLED,
+                element_info[i].crumbled[ACTION_DEFAULT] !=
+                element_info[i].graphic[ACTION_DEFAULT]);
+#else
+    /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
     SET_PROPERTY(i, EP_GFX_CRUMBLED,
                 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
+#endif
   }
 
 #if 0
   /* determine inactive elements (used for engine main loop optimization) */
-  for (i=0; i < MAX_NUM_ELEMENTS; i++)
+  for (i = 0; i < MAX_NUM_ELEMENTS; i++)
   {
     boolean active = FALSE;
 
-    for (j=0; i < NUM_ELEMENT_PROPERTIES; j++)
+    for (j = 0; i < NUM_ELEMENT_PROPERTIES; j++)
     {
       if (HAS_PROPERTY(i, j))
        active = TRUE;
@@ -3127,7 +3990,7 @@ void InitElementPropertiesEngine(int engine_version)
     };
 
     /* special EM style gems behaviour */
-    for (i=0; ep_em_slippery_wall[i] != -1; i++)
+    for (i = 0; ep_em_slippery_wall[i] != -1; i++)
       SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
                   level.em_slippery_gems);
 
@@ -3151,7 +4014,7 @@ void InitElementPropertiesEngine(int engine_version)
   }
 
   /* set uninitialized push delay values of custom elements in older levels */
-  for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
+  for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
   {
     int element = EL_CUSTOM_START + i;
 
@@ -3160,12 +4023,54 @@ void InitElementPropertiesEngine(int engine_version)
     if (element_info[element].push_delay_random == -1)
       element_info[element].push_delay_random = game.default_push_delay_random;
   }
+
+  /* set some other uninitialized values of custom elements in older levels */
+  if (engine_version < VERSION_IDENT(3,1,0,0))
+  {
+    for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
+    {
+      int element = EL_CUSTOM_START + i;
+
+      element_info[element].access_direction = MV_ALL_DIRECTIONS;
+
+      element_info[element].explosion_delay = 17;
+      element_info[element].ignition_delay = 8;
+    }
+  }
+
+#if 0
+  /* set element properties that were handled incorrectly in older levels */
+  if (engine_version < VERSION_IDENT(3,1,0,0))
+  {
+    SET_PROPERTY(EL_SP_SNIKSNAK, EP_DONT_COLLIDE_WITH, FALSE);
+    SET_PROPERTY(EL_SP_ELECTRON, EP_DONT_COLLIDE_WITH, FALSE);
+  }
 #endif
+
+#endif
+
+  /* this is needed because some graphics depend on element properties */
+  if (game_status == GAME_MODE_PLAYING)
+    InitElementGraphicInfo();
 }
 
 static void InitGlobal()
 {
+  int i;
+
+  for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
+  {
+    /* check if element_name_info entry defined for each element in "main.h" */
+    if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
+      Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
+
+    element_info[i].token_name = element_name_info[i].token_name;
+    element_info[i].class_name = element_name_info[i].class_name;
+    element_info[i].editor_description=element_name_info[i].editor_description;
+  }
+
   global.autoplay_leveldir = NULL;
+  global.convert_leveldir = NULL;
 
   global.frames_per_second = 0;
   global.fps_slowdown = FALSE;
@@ -3174,51 +4079,92 @@ static void InitGlobal()
 
 void Execute_Command(char *command)
 {
+  int i;
+
   if (strcmp(command, "print graphicsinfo.conf") == 0)
   {
-    int i;
-
     printf("# You can configure additional/alternative image files here.\n");
-    printf("# (The images below are default and therefore commented out.)\n");
+    printf("# (The entries below are default and therefore commented out.)\n");
     printf("\n");
     printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
     printf("\n");
     printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
     printf("\n");
 
-    for (i=0; image_config[i].token != NULL; i++)
-      printf("# %s\n",
-            getFormattedSetupEntry(image_config[i].token,
-                                   image_config[i].value));
+    for (i = 0; image_config[i].token != NULL; i++)
+      printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
+                                             image_config[i].value));
 
     exit(0);
   }
   else if (strcmp(command, "print soundsinfo.conf") == 0)
   {
-    int i;
-
     printf("# You can configure additional/alternative sound files here.\n");
-    printf("# (The sounds below are default and therefore commented out.)\n");
+    printf("# (The entries below are default and therefore commented out.)\n");
     printf("\n");
     printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
     printf("\n");
     printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
     printf("\n");
 
-    for (i=0; sound_config[i].token != NULL; i++)
-      printf("# %s\n",
-            getFormattedSetupEntry(sound_config[i].token,
-                                   sound_config[i].value));
+    for (i = 0; sound_config[i].token != NULL; i++)
+      printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
+                                             sound_config[i].value));
 
     exit(0);
   }
   else if (strcmp(command, "print musicinfo.conf") == 0)
   {
-    printf("# (Currently only \"name\" and \"sort_priority\" recognized.)\n");
+    printf("# You can configure additional/alternative music files here.\n");
+    printf("# (The entries below are default and therefore commented out.)\n");
     printf("\n");
     printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
     printf("\n");
     printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
+    printf("\n");
+
+    for (i = 0; music_config[i].token != NULL; i++)
+      printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
+                                             music_config[i].value));
+
+    exit(0);
+  }
+  else if (strcmp(command, "print editorsetup.conf") == 0)
+  {
+    printf("# You can configure your personal editor element list here.\n");
+    printf("# (The entries below are default and therefore commented out.)\n");
+    printf("\n");
+
+    PrintEditorElementList();
+
+    exit(0);
+  }
+  else if (strcmp(command, "print helpanim.conf") == 0)
+  {
+    printf("# You can configure different element help animations here.\n");
+    printf("# (The entries below are default and therefore commented out.)\n");
+    printf("\n");
+
+    for (i = 0; helpanim_config[i].token != NULL; i++)
+    {
+      printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
+                                             helpanim_config[i].value));
+
+      if (strcmp(helpanim_config[i].token, "end") == 0)
+       printf("#\n");
+    }
+
+    exit(0);
+  }
+  else if (strcmp(command, "print helptext.conf") == 0)
+  {
+    printf("# You can configure different element help text here.\n");
+    printf("# (The entries below are default and therefore commented out.)\n");
+    printf("\n");
+
+    for (i = 0; helptext_config[i].token != NULL; i++)
+      printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
+                                             helptext_config[i].value));
 
     exit(0);
   }
@@ -3260,6 +4206,20 @@ void Execute_Command(char *command)
       global.autoplay_level_nr = atoi(str_ptr);        /* get level_nr value */
     }
   }
+  else if (strncmp(command, "convert ", 8) == 0)
+  {
+    char *str_copy = getStringCopy(&command[8]);
+    char *str_ptr = strchr(str_copy, ' ');
+
+    global.convert_leveldir = str_copy;
+    global.convert_level_nr = -1;
+
+    if (str_ptr != NULL)
+    {
+      *str_ptr++ = '\0';                       /* terminate leveldir string */
+      global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
+    }
+  }
   else
   {
     Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
@@ -3283,7 +4243,7 @@ static void InitPlayerInfo()
   /* choose default local player */
   local_player = &stored_player[0];
 
-  for (i=0; i<MAX_PLAYERS; i++)
+  for (i = 0; i < MAX_PLAYERS; i++)
     stored_player[i].connected = FALSE;
 
   local_player->connected = TRUE;
@@ -3364,18 +4324,18 @@ static void InitArtworkConfig()
 
   /* dynamically determine list of generic tokens to be ignored */
   num_ignore_generic_tokens = 0;
-  for (i=0; ignore_generic_tokens[i] != NULL; i++)
+  for (i = 0; ignore_generic_tokens[i] != NULL; i++)
     num_ignore_generic_tokens++;
 
   /* dynamically determine list of image tokens to be ignored */
   num_ignore_image_tokens = num_ignore_generic_tokens;
-  for (i=0; image_config_vars[i].token != NULL; i++)
+  for (i = 0; image_config_vars[i].token != NULL; i++)
     num_ignore_image_tokens++;
   ignore_image_tokens =
     checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
-  for (i=0; i < num_ignore_generic_tokens; i++)
+  for (i = 0; i < num_ignore_generic_tokens; i++)
     ignore_image_tokens[i] = ignore_generic_tokens[i];
-  for (i=0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
+  for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
     ignore_image_tokens[num_ignore_generic_tokens + i] =
       image_config_vars[i].token;
   ignore_image_tokens[num_ignore_image_tokens] = NULL;
@@ -3384,7 +4344,7 @@ static void InitArtworkConfig()
   num_ignore_sound_tokens = num_ignore_generic_tokens;
   ignore_sound_tokens =
     checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
-  for (i=0; i < num_ignore_generic_tokens; i++)
+  for (i = 0; i < num_ignore_generic_tokens; i++)
     ignore_sound_tokens[i] = ignore_generic_tokens[i];
   ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
 
@@ -3392,40 +4352,40 @@ static void InitArtworkConfig()
   num_ignore_music_tokens = num_ignore_generic_tokens;
   ignore_music_tokens =
     checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
-  for (i=0; i < num_ignore_generic_tokens; i++)
+  for (i = 0; i < num_ignore_generic_tokens; i++)
     ignore_music_tokens[i] = ignore_generic_tokens[i];
   ignore_music_tokens[num_ignore_music_tokens] = NULL;
 
-  for (i=0; i < MAX_NUM_ELEMENTS; i++)
+  for (i = 0; i < MAX_NUM_ELEMENTS; i++)
     image_id_prefix[i] = element_info[i].token_name;
-  for (i=0; i < NUM_FONTS; i++)
+  for (i = 0; i < NUM_FONTS; i++)
     image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
   image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
 
-  for (i=0; i < MAX_NUM_ELEMENTS; i++)
+  for (i = 0; i < MAX_NUM_ELEMENTS; i++)
     sound_id_prefix[i] = element_info[i].token_name;
-  for (i=0; i < MAX_NUM_ELEMENTS; i++)
+  for (i = 0; i < MAX_NUM_ELEMENTS; i++)
     sound_id_prefix[MAX_NUM_ELEMENTS + i] =
       get_string_in_brackets(element_info[i].class_name);
   sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
 
-  for (i=0; i < NUM_MUSIC_PREFIXES; i++)
+  for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
     music_id_prefix[i] = music_prefix_info[i].prefix;
   music_id_prefix[MAX_LEVELS] = NULL;
 
-  for (i=0; i < NUM_ACTIONS; i++)
+  for (i = 0; i < NUM_ACTIONS; i++)
     action_id_suffix[i] = element_action_info[i].suffix;
   action_id_suffix[NUM_ACTIONS] = NULL;
 
-  for (i=0; i < NUM_DIRECTIONS; i++)
+  for (i = 0; i < NUM_DIRECTIONS; i++)
     direction_id_suffix[i] = element_direction_info[i].suffix;
   direction_id_suffix[NUM_DIRECTIONS] = NULL;
 
-  for (i=0; i < NUM_SPECIAL_GFX_ARGS; i++)
+  for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
     special_id_suffix[i] = special_suffix_info[i].suffix;
   special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
 
-  for (i=0; i < MAX_LEVELS; i++)
+  for (i = 0; i < MAX_LEVELS; i++)
     level_id_suffix[i] = get_level_id_suffix(i);
   level_id_suffix[MAX_LEVELS] = NULL;
 
@@ -3453,9 +4413,9 @@ void InitGfx()
   int i, j;
 
   /* determine settings for initial font (for displaying startup messages) */
-  for (i=0; image_config[i].token != NULL; i++)
+  for (i = 0; image_config[i].token != NULL; i++)
   {
-    for (j=0; j < NUM_INITIAL_FONTS; j++)
+    for (j = 0; j < NUM_INITIAL_FONTS; j++)
     {
       char font_token[128];
       int len_font_token;
@@ -3480,7 +4440,7 @@ void InitGfx()
     }
   }
 
-  for (j=0; j < NUM_INITIAL_FONTS; j++)
+  for (j = 0; j < NUM_INITIAL_FONTS; j++)
   {
     font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
     font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
@@ -3503,7 +4463,7 @@ void InitGfx()
 
   bitmap_font_initial = LoadCustomImage(filename_font_initial);
 
-  for (j=0; j < NUM_INITIAL_FONTS; j++)
+  for (j = 0; j < NUM_INITIAL_FONTS; j++)
     font_initial[j].bitmap = bitmap_font_initial;
 
   InitFontGraphicInfo();
@@ -3529,8 +4489,8 @@ void InitGfxBackground()
   ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
   ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
 
-  for (x=0; x<MAX_BUF_XSIZE; x++)
-    for (y=0; y<MAX_BUF_YSIZE; y++)
+  for (x = 0; x < MAX_BUF_XSIZE; x++)
+    for (y = 0; y < MAX_BUF_YSIZE; y++)
       redraw[x][y] = 0;
   redraw_tiles = 0;
   redraw_mask = REDRAW_ALL;
@@ -3601,14 +4561,14 @@ static void InitMusic(char *identifier)
 
 void InitNetworkServer()
 {
-#if defined(PLATFORM_UNIX)
+#if defined(NETWORK_AVALIABLE)
   int nr_wanted;
 #endif
 
   if (!options.network)
     return;
 
-#if defined(PLATFORM_UNIX)
+#if defined(NETWORK_AVALIABLE)
   nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
 
   if (!ConnectToServer(options.server_host, options.server_port))
@@ -3735,14 +4695,17 @@ static char *getNewArtworkIdentifier(int type)
   return artwork_new_identifier;
 }
 
-void ReloadCustomArtwork()
+void ReloadCustomArtwork(int force_reload)
 {
   char *gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
   char *snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
   char *mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
+  boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
+  boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
+  boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
   boolean redraw_screen = FALSE;
 
-  if (gfx_new_identifier != NULL)
+  if (gfx_new_identifier != NULL || force_reload_gfx)
   {
 #if 0
     printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
@@ -3767,7 +4730,7 @@ void ReloadCustomArtwork()
     redraw_screen = TRUE;
   }
 
-  if (snd_new_identifier != NULL)
+  if (snd_new_identifier != NULL || force_reload_snd)
   {
     ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
 
@@ -3776,7 +4739,7 @@ void ReloadCustomArtwork()
     redraw_screen = TRUE;
   }
 
-  if (mus_new_identifier != NULL)
+  if (mus_new_identifier != NULL || force_reload_mus)
   {
     ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
 
@@ -3808,7 +4771,7 @@ void KeyboardAutoRepeatOffUnlessAutoplay()
 
 void OpenAll()
 {
-  InitGlobal();                /* initialize some global variables */
+  InitGlobal();                        /* initialize some global variables */
 
   if (options.execute_command)
     Execute_Command(options.execute_command);
@@ -3820,7 +4783,8 @@ void OpenAll()
 #else
     Error(ERR_WARN, "networking only supported in Unix version");
 #endif
-    exit(0);   /* never reached */
+
+    exit(0);                   /* never reached, server loops forever */
   }
 
   InitSetup();
@@ -3862,9 +4826,18 @@ void OpenAll()
     AutoPlayTape();
     return;
   }
+  else if (global.convert_leveldir)
+  {
+    ConvertLevels();
+    return;
+  }
 
   game_status = GAME_MODE_MAIN;
 
+#if 1
+  em_open_all();
+#endif
+
   DrawMainMenu();
 
   InitNetworkServer();
@@ -3877,9 +4850,18 @@ void CloseAllAndExit(int exit_value)
   FreeAllMusic();
   CloseAudio();                /* called after freeing sounds (needed for SDL) */
 
+#if 1
+  em_close_all();
+#endif
+
   FreeAllImages();
   FreeTileClipmasks();
 
+#if defined(TARGET_SDL)
+  if (network_server)  /* terminate network server */
+    SDL_KillThread(server_thread);
+#endif
+
   CloseVideoDisplay();
   ClosePlatformDependentStuff();