rnd-20040918-1-src
[rocksndiamonds.git] / src / files.c
index fa71b1771f72e6b4d7c21558cdb5da454061d264..4b4ddebd95e8b808c7f9005d410d9c64999b42b7 100644 (file)
@@ -29,7 +29,7 @@
 #define CHUNK_SIZE_NONE                -1      /* do not write chunk size    */
 #define FILE_VERS_CHUNK_SIZE   8       /* size of file version chunk */
 #define LEVEL_HEADER_SIZE      80      /* size of level file header  */
-#define LEVEL_HEADER_UNUSED    1       /* unused level header bytes  */
+#define LEVEL_HEADER_UNUSED    0       /* unused level header bytes  */
 #define LEVEL_CHUNK_CNT2_SIZE  160     /* size of level CNT2 chunk   */
 #define LEVEL_CHUNK_CNT2_UNUSED        11      /* unused CNT2 chunk bytes    */
 #define LEVEL_CHUNK_CNT3_HEADER        16      /* size of level CNT3 header  */
 #define TAPE_COOKIE_TMPL       "ROCKSNDIAMONDS_TAPE_FILE_VERSION_x.x"
 #define SCORE_COOKIE           "ROCKSNDIAMONDS_SCORE_FILE_VERSION_1.2"
 
-/* values for level file type identifier */
-#define LEVEL_FILE_TYPE_UNKNOWN                0
-#define LEVEL_FILE_TYPE_RND            1
-#define LEVEL_FILE_TYPE_BD             2
-#define LEVEL_FILE_TYPE_EM             3
-#define LEVEL_FILE_TYPE_SP             4
-#define LEVEL_FILE_TYPE_DX             5
-#define LEVEL_FILE_TYPE_SB             6
-#define LEVEL_FILE_TYPE_DC             7
-
-#define LEVEL_FILE_TYPE_RND_PACKED     (10 + LEVEL_FILE_TYPE_RND)
-#define LEVEL_FILE_TYPE_EM_PACKED      (10 + LEVEL_FILE_TYPE_EM)
-
-#define IS_SINGLE_LEVEL_FILE(x)                (x < 10)
-#define IS_PACKED_LEVEL_FILE(x)                (x > 10)
-
 
 /* ========================================================================= */
 /* level file functions                                                      */
@@ -130,6 +114,10 @@ static void setLevelInfoToDefaults(struct LevelInfo *level)
 
   int i, j, x, y;
 
+  level->native_em_level = &native_em_level;
+
+  level->game_engine_type = GAME_ENGINE_TYPE_RND;
+
   level->file_version = FILE_VERSION_ACTUAL;
   level->game_version = GAME_VERSION_ACTUAL;
 
@@ -159,14 +147,17 @@ static void setLevelInfoToDefaults(struct LevelInfo *level)
   level->double_speed = FALSE;
   level->initial_gravity = FALSE;
   level->em_slippery_gems = FALSE;
-  level->block_last_field = FALSE;
-  level->sp_block_last_field = TRUE;
   level->instant_relocation = FALSE;
   level->can_pass_to_walkable = FALSE;
   level->grow_into_diggable = TRUE;
 
+  level->block_last_field = FALSE;     /* EM does not block by default */
+  level->sp_block_last_field = TRUE;   /* SP blocks the last field */
+  level->block_delay = 8;              /* when blocking, block 8 frames */
+  level->sp_block_delay = 9;           /* SP indeed blocks 9 frames, not 8 */
+
   level->can_move_into_acid_bits = ~0; /* everything can move into acid */
-  level->dont_collide_with_bits = ~0;  /* always deadly when colliding  */
+  level->dont_collide_with_bits = ~0;  /* always deadly when colliding */
 
   level->use_spring_bug = FALSE;
   level->use_step_counter = FALSE;
@@ -228,6 +219,8 @@ static void setLevelInfoToDefaults(struct LevelInfo *level)
 
       element_info[element].use_gfx_element = FALSE;
       element_info[element].gfx_element = EL_EMPTY_SPACE;
+
+      element_info[element].modified_settings = FALSE;
     }
 
     if (IS_CUSTOM_ELEMENT(element) ||
@@ -282,8 +275,6 @@ static void setLevelInfoToDefaults(struct LevelInfo *level)
 
       /* now set default properties */
       SET_PROPERTY(element, EP_CAN_MOVE_INTO_ACID, TRUE);
-
-      element_info[element].modified_settings = FALSE;
     }
 
     if (IS_GROUP_ELEMENT(element) ||
@@ -310,6 +301,8 @@ static void setLevelInfoToDefaults(struct LevelInfo *level)
 
   level->no_valid_file = FALSE;
 
+  level->changed = FALSE;
+
   if (leveldir_current == NULL)                /* only when dumping level */
     return;
 
@@ -546,6 +539,20 @@ static void determineLevelFileInfo_Filetype(struct LevelFileInfo *lfi)
     lfi->type = getFileTypeFromBasename(lfi->basename);
 }
 
+#if 1
+static void setLevelFileInfo(struct LevelFileInfo *level_file_info, int nr)
+{
+  /* always start with reliable default values */
+  setFileInfoToDefaults(level_file_info);
+
+  level_file_info->nr = nr;    /* set requested level number */
+
+  determineLevelFileInfo_Filename(level_file_info);
+  determineLevelFileInfo_Filetype(level_file_info);
+}
+
+#else
+
 static struct LevelFileInfo *getLevelFileInfo(int nr)
 {
   static struct LevelFileInfo level_file_info;
@@ -560,7 +567,7 @@ static struct LevelFileInfo *getLevelFileInfo(int nr)
 
   return &level_file_info;
 }
-
+#endif
 
 /* ------------------------------------------------------------------------- */
 /* functions for loading R'n'D level                                         */
@@ -709,6 +716,8 @@ static int LoadLevel_HEAD(FILE *file, int chunk_size, struct LevelInfo *level)
   level->can_pass_to_walkable  = (getFile8Bit(file) == 1 ? TRUE : FALSE);
   level->grow_into_diggable    = (getFile8Bit(file) == 1 ? TRUE : FALSE);
 
+  level->game_engine_type      = getFile8Bit(file);
+
   ReadUnusedBytesFromFile(file, LEVEL_HEADER_UNUSED);
 
   return chunk_size;
@@ -1336,6 +1345,8 @@ static void LoadLevelFromFileInfo_RND(struct LevelInfo *level,
 /* functions for loading EM level                                            */
 /* ------------------------------------------------------------------------- */
 
+#if 0
+
 static int map_em_element_yam(int element)
 {
   switch (element)
@@ -1648,16 +1659,13 @@ static int map_em_element_field(int element)
 #define EM_LEVEL_XSIZE                 64
 #define EM_LEVEL_YSIZE                 32
 
-static void LoadLevelFromFileInfo_EM(struct LevelInfo *level,
-                                    struct LevelFileInfo *level_file_info)
+static void OLD_LoadLevelFromFileInfo_EM(struct LevelInfo *level,
+                                        struct LevelFileInfo *level_file_info)
 {
   char *filename = level_file_info->filename;
   FILE *file;
   unsigned char leveldata[EM_LEVEL_SIZE];
   unsigned char *header = &leveldata[EM_LEVEL_XSIZE * EM_LEVEL_YSIZE];
-  unsigned char code0 = 0x65;
-  unsigned char code1 = 0x11;
-  boolean level_is_crypted = FALSE;
   int nr = level_file_info->nr;
   int i, x, y;
 
@@ -1670,7 +1678,7 @@ static void LoadLevelFromFileInfo_EM(struct LevelInfo *level,
     return;
   }
 
-  for(i = 0; i < EM_LEVEL_SIZE; i++)
+  for (i = 0; i < EM_LEVEL_SIZE; i++)
     leveldata[i] = fgetc(file);
 
   fclose(file);
@@ -1681,20 +1689,20 @@ static void LoadLevelFromFileInfo_EM(struct LevelInfo *level,
   if ((leveldata[0] == 0xf1 ||
        leveldata[0] == 0xf5) && leveldata[2] == 0xe7 && leveldata[3] == 0xee)
   {
-    level_is_crypted = TRUE;
+    unsigned char code0 = 0x65;
+    unsigned char code1 = 0x11;
 
     if (leveldata[0] == 0xf5)  /* error in crypted Emerald Mine 2 levels */
       leveldata[0] = 0xf1;
-  }
 
-  if (level_is_crypted)                /* decode crypted level data */
-  {
-    for(i = 0; i < EM_LEVEL_SIZE; i++)
+    /* decode crypted level data */
+
+    for (i = 0; i < EM_LEVEL_SIZE; i++)
     {
       leveldata[i] ^= code0;
       leveldata[i] -= code1;
 
-      code0  = (code0 + 7) & 0xff;
+      code0 = (code0 + 7) & 0xff;
     }
   }
 
@@ -1727,9 +1735,9 @@ static void LoadLevelFromFileInfo_EM(struct LevelInfo *level,
 
   level->num_yamyam_contents = 4;
 
-  for(i = 0; i < level->num_yamyam_contents; i++)
-    for(y = 0; y < 3; y++)
-      for(x = 0; x < 3; x++)
+  for (i = 0; i < level->num_yamyam_contents; i++)
+    for (y = 0; y < 3; y++)
+      for (x = 0; x < 3; x++)
        level->yamyam_content[i][x][y] =
          map_em_element_yam(header[i * 9 + y * 3 + x]);
 
@@ -1757,6 +1765,771 @@ static void LoadLevelFromFileInfo_EM(struct LevelInfo *level,
   level->field[x][y] = EL_PLAYER_2;
 }
 
+#else
+
+static int map_element_RND_to_EM(int element_rnd)
+{
+  static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
+  static boolean mapping_initialized = FALSE;
+
+  struct
+  {
+    int element_em;
+    int element_rnd;
+  }
+  mapping_RND_to_EM_list[] =
+  {
+    { Xblank,                  EL_EMPTY                        },
+    { Xstone,                  EL_ROCK                         },
+    { Xnut,                    EL_NUT                          },
+    { Xbug_n,                  EL_BUG_UP                       },
+    { Xbug_e,                  EL_BUG_RIGHT                    },
+    { Xbug_s,                  EL_BUG_DOWN                     },
+    { Xbug_w,                  EL_BUG_LEFT                     },
+    { Xtank_n,                 EL_SPACESHIP_UP                 },
+    { Xtank_e,                 EL_SPACESHIP_RIGHT              },
+    { Xtank_s,                 EL_SPACESHIP_DOWN               },
+    { Xtank_w,                 EL_SPACESHIP_LEFT               },
+    { Xandroid,                        EL_EMC_ANDROID                  },
+    { Xandroid_1_n,            EL_EMC_ANDROID_UP               },
+    { Xandroid_1_e,            EL_EMC_ANDROID_RIGHT            },
+    { Xandroid_1_w,            EL_EMC_ANDROID_LEFT             },
+    { Xandroid_1_s,            EL_EMC_ANDROID_DOWN             },
+    { Xspring,                 EL_SPRING                       },
+    { Xeater_n,                        EL_YAMYAM                       },
+    { Xalien,                  EL_ROBOT                        },
+    { Xemerald,                        EL_EMERALD                      },
+    { Xdiamond,                        EL_DIAMOND                      },
+    { Xdrip_fall,              EL_AMOEBA_DROP                  },
+    { Xbomb,                   EL_BOMB                         },
+    { Xballoon,                        EL_BALLOON                      },
+    { Xgrass,                  EL_EMC_GRASS                    },
+    { Xdirt,                   EL_SAND                         },
+    { Xacid_ne,                        EL_ACID_POOL_TOPRIGHT           },
+    { Xacid_se,                        EL_ACID_POOL_BOTTOMRIGHT        },
+    { Xacid_s,                 EL_ACID_POOL_BOTTOM             },
+    { Xacid_sw,                        EL_ACID_POOL_BOTTOMLEFT         },
+    { Xacid_nw,                        EL_ACID_POOL_TOPLEFT            },
+    { Xacid_1,                 EL_ACID                         },
+    { Xball_1,                 EL_EMC_GENERATOR_BALL           },
+    { Xgrow_ns,                        EL_EMC_GROW                     },
+    { Xwonderwall,             EL_MAGIC_WALL                   },
+    { Xameuba_1,               EL_AMOEBA_WET                   },
+    { Xdoor_1,                 EL_EM_GATE_1                    },
+    { Xdoor_2,                 EL_EM_GATE_2                    },
+    { Xdoor_3,                 EL_EM_GATE_3                    },
+    { Xdoor_4,                 EL_EM_GATE_4                    },
+    { Xdoor_5,                 EL_EMC_GATE_5                   },
+    { Xdoor_6,                 EL_EMC_GATE_6                   },
+    { Xdoor_7,                 EL_EMC_GATE_7                   },
+    { Xdoor_8,                 EL_EMC_GATE_8                   },
+    { Xkey_1,                  EL_EM_KEY_1                     },
+    { Xkey_2,                  EL_EM_KEY_2                     },
+    { Xkey_3,                  EL_EM_KEY_3                     },
+    { Xkey_4,                  EL_EM_KEY_4                     },
+    { Xkey_5,                  EL_EMC_KEY_5                    },
+    { Xkey_6,                  EL_EMC_KEY_6                    },
+    { Xkey_7,                  EL_EMC_KEY_7                    },
+    { Xkey_8,                  EL_EMC_KEY_8                    },
+    { Xwind_n,                 EL_BALLOON_SWITCH_UP            },
+    { Xwind_e,                 EL_BALLOON_SWITCH_RIGHT         },
+    { Xwind_s,                 EL_BALLOON_SWITCH_DOWN          },
+    { Xwind_w,                 EL_BALLOON_SWITCH_LEFT          },
+    { Xwind_nesw,              EL_BALLOON_SWITCH_ANY           },
+    { Xwind_stop,              EL_BALLOON_SWITCH_NONE          },
+    { Xexit,                   EL_EXIT_CLOSED                  },
+    { Xexit_1,                 EL_EXIT_OPEN                    },
+    { Xdynamite,               EL_DYNAMITE                     },
+    { Xdynamite_1,             EL_DYNAMITE_ACTIVE              },
+    { Xbumper,                 EL_EMC_BUMPER                   },
+    { Xwheel,                  EL_ROBOT_WHEEL                  },
+    { Xswitch,                 EL_UNKNOWN                      },
+    { Xsand,                   EL_QUICKSAND_EMPTY              },
+    { Xsand_stone,             EL_QUICKSAND_FULL               },
+    { Xplant,                  EL_EMC_PLANT                    },
+    { Xlenses,                 EL_EMC_LENSES                   },
+    { Xmagnify,                        EL_EMC_MAGNIFY                  },
+    { Xdripper,                        EL_UNKNOWN                      },
+    { Xfake_blank,             EL_INVISIBLE_WALL               },
+    { Xfake_grass,             EL_INVISIBLE_SAND               },
+    { Xfake_door_1,            EL_EM_GATE_1_GRAY               },
+    { Xfake_door_2,            EL_EM_GATE_2_GRAY               },
+    { Xfake_door_3,            EL_EM_GATE_3_GRAY               },
+    { Xfake_door_4,            EL_EM_GATE_4_GRAY               },
+    { Xfake_door_5,            EL_EMC_GATE_5_GRAY              },
+    { Xfake_door_6,            EL_EMC_GATE_6_GRAY              },
+    { Xfake_door_7,            EL_EMC_GATE_7_GRAY              },
+    { Xfake_door_8,            EL_EMC_GATE_8_GRAY              },
+    { Xsteel_1,                        EL_UNKNOWN                      },
+    { Xsteel_2,                        EL_UNKNOWN                      },
+    { Xsteel_3,                        EL_UNKNOWN                      },
+    { Xsteel_4,                        EL_UNKNOWN                      },
+    { Xwall_1,                 EL_UNKNOWN                      },
+    { Xwall_2,                 EL_UNKNOWN                      },
+    { Xwall_3,                 EL_UNKNOWN                      },
+    { Xwall_4,                 EL_UNKNOWN                      },
+    { Xround_wall_1,           EL_UNKNOWN                      },
+    { Xround_wall_2,           EL_UNKNOWN                      },
+    { Xround_wall_3,           EL_UNKNOWN                      },
+    { Xround_wall_4,           EL_UNKNOWN                      },
+    { Xdecor_1,                        EL_UNKNOWN                      },
+    { Xdecor_2,                        EL_UNKNOWN                      },
+    { Xdecor_3,                        EL_UNKNOWN                      },
+    { Xdecor_4,                        EL_UNKNOWN                      },
+    { Xdecor_5,                        EL_UNKNOWN                      },
+    { Xdecor_6,                        EL_UNKNOWN                      },
+    { Xdecor_7,                        EL_UNKNOWN                      },
+    { Xdecor_8,                        EL_UNKNOWN                      },
+    { Xdecor_9,                        EL_UNKNOWN                      },
+    { Xdecor_10,               EL_UNKNOWN                      },
+    { Xdecor_11,               EL_UNKNOWN                      },
+    { Xdecor_12,               EL_UNKNOWN                      },
+    { Xalpha_0,                        EL_CHAR('0')                    },
+    { Xalpha_1,                        EL_CHAR('1')                    },
+    { Xalpha_2,                        EL_CHAR('2')                    },
+    { Xalpha_3,                        EL_CHAR('3')                    },
+    { Xalpha_4,                        EL_CHAR('4')                    },
+    { Xalpha_5,                        EL_CHAR('5')                    },
+    { Xalpha_6,                        EL_CHAR('6')                    },
+    { Xalpha_7,                        EL_CHAR('7')                    },
+    { Xalpha_8,                        EL_CHAR('8')                    },
+    { Xalpha_9,                        EL_CHAR('9')                    },
+    { Xalpha_excla,            EL_CHAR('!')                    },
+    { Xalpha_quote,            EL_CHAR('"')                    },
+    { Xalpha_comma,            EL_CHAR(',')                    },
+    { Xalpha_minus,            EL_CHAR('-')                    },
+    { Xalpha_perio,            EL_CHAR('.')                    },
+    { Xalpha_colon,            EL_CHAR(':')                    },
+    { Xalpha_quest,            EL_CHAR('?')                    },
+    { Xalpha_a,                        EL_CHAR('A')                    },
+    { Xalpha_b,                        EL_CHAR('B')                    },
+    { Xalpha_c,                        EL_CHAR('C')                    },
+    { Xalpha_d,                        EL_CHAR('D')                    },
+    { Xalpha_e,                        EL_CHAR('E')                    },
+    { Xalpha_f,                        EL_CHAR('F')                    },
+    { Xalpha_g,                        EL_CHAR('G')                    },
+    { Xalpha_h,                        EL_CHAR('H')                    },
+    { Xalpha_i,                        EL_CHAR('I')                    },
+    { Xalpha_j,                        EL_CHAR('J')                    },
+    { Xalpha_k,                        EL_CHAR('K')                    },
+    { Xalpha_l,                        EL_CHAR('L')                    },
+    { Xalpha_m,                        EL_CHAR('M')                    },
+    { Xalpha_n,                        EL_CHAR('N')                    },
+    { Xalpha_o,                        EL_CHAR('O')                    },
+    { Xalpha_p,                        EL_CHAR('P')                    },
+    { Xalpha_q,                        EL_CHAR('Q')                    },
+    { Xalpha_r,                        EL_CHAR('R')                    },
+    { Xalpha_s,                        EL_CHAR('S')                    },
+    { Xalpha_t,                        EL_CHAR('T')                    },
+    { Xalpha_u,                        EL_CHAR('U')                    },
+    { Xalpha_v,                        EL_CHAR('V')                    },
+    { Xalpha_w,                        EL_CHAR('W')                    },
+    { Xalpha_x,                        EL_CHAR('X')                    },
+    { Xalpha_y,                        EL_CHAR('Y')                    },
+    { Xalpha_z,                        EL_CHAR('Z')                    },
+    { Xalpha_arrow_e,          EL_CHAR('>')                    },
+    { Xalpha_arrow_w,          EL_CHAR('<')                    },
+    { Xalpha_copyr,            EL_CHAR('©')                    },
+
+    { Zplayer,                 EL_PLAYER_1                     },
+    { Zplayer,                 EL_PLAYER_2                     },
+    { Zplayer,                 EL_PLAYER_3                     },
+    { Zplayer,                 EL_PLAYER_4                     },
+
+    { ZBORDER,                 EL_EMC_LEVEL_BORDER             },
+
+    { -1,                      -1                              }
+  };
+
+  if (!mapping_initialized)
+  {
+    int i;
+
+    /* return "Xalpha_quest" for all undefined elements in mapping array */
+    for (i = 0; i < NUM_FILE_ELEMENTS; i++)
+      mapping_RND_to_EM[i] = Xalpha_quest;
+
+    for (i = 0; mapping_RND_to_EM_list[i].element_rnd != -1; i++)
+      mapping_RND_to_EM[mapping_RND_to_EM_list[i].element_rnd] =
+       mapping_RND_to_EM_list[i].element_em;
+
+    mapping_initialized = TRUE;
+  }
+
+  if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
+    return mapping_RND_to_EM[element_rnd];
+
+  Error(ERR_WARN, "invalid RND level element %d", element_rnd);
+
+  return EL_UNKNOWN;
+}
+
+static int map_element_EM_to_RND(int element_em)
+{
+  static unsigned short mapping_EM_to_RND[TILE_MAX];
+  static boolean mapping_initialized = FALSE;
+
+  struct
+  {
+    int element_em;
+    int element_rnd;
+  }
+  mapping_EM_to_RND_list[] =
+  {
+    { Xblank,                  EL_EMPTY                        },
+    { Yacid_splash_eB,         EL_EMPTY                        },
+    { Yacid_splash_wB,         EL_EMPTY                        },
+
+#ifdef EM_ENGINE_BAD_ROLL
+    { Xstone_force_e,          EL_ROCK                         },
+    { Xstone_force_w,          EL_ROCK                         },
+    { Xnut_force_e,            EL_NUT                          },
+    { Xnut_force_w,            EL_NUT                          },
+    { Xspring_force_e,         EL_SPRING                       },
+    { Xspring_force_w,         EL_SPRING                       },
+    { Xemerald_force_e,                EL_EMERALD                      },
+    { Xemerald_force_w,                EL_EMERALD                      },
+    { Xdiamond_force_e,                EL_DIAMOND                      },
+    { Xdiamond_force_w,                EL_DIAMOND                      },
+    { Xbomb_force_e,           EL_BOMB                         },
+    { Xbomb_force_w,           EL_BOMB                         },
+#endif
+
+    { Xstone,                  EL_ROCK                         },
+    { Xstone_pause,            EL_ROCK                         },
+    { Xstone_fall,             EL_ROCK                         },
+    { Ystone_s,                        EL_ROCK                         },
+    { Ystone_sB,               EL_ROCK                         },
+    { Ystone_e,                        EL_ROCK                         },
+    { Ystone_eB,               EL_ROCK                         },
+    { Ystone_w,                        EL_ROCK                         },
+    { Ystone_wB,               EL_ROCK                         },
+    { Xnut,                    EL_NUT                          },
+    { Xnut_pause,              EL_NUT                          },
+    { Xnut_fall,               EL_NUT                          },
+    { Ynut_s,                  EL_NUT                          },
+    { Ynut_sB,                 EL_NUT                          },
+    { Ynut_e,                  EL_NUT                          },
+    { Ynut_eB,                 EL_NUT                          },
+    { Ynut_w,                  EL_NUT                          },
+    { Ynut_wB,                 EL_NUT                          },
+    { Xbug_n,                  EL_BUG_UP                       },
+    { Xbug_e,                  EL_BUG_RIGHT                    },
+    { Xbug_s,                  EL_BUG_DOWN                     },
+    { Xbug_w,                  EL_BUG_LEFT                     },
+    { Xbug_gon,                        EL_BUG_UP                       },
+    { Xbug_goe,                        EL_BUG_RIGHT                    },
+    { Xbug_gos,                        EL_BUG_DOWN                     },
+    { Xbug_gow,                        EL_BUG_LEFT                     },
+    { Ybug_n,                  EL_BUG_UP                       },
+    { Ybug_nB,                 EL_BUG_UP                       },
+    { Ybug_e,                  EL_BUG_RIGHT                    },
+    { Ybug_eB,                 EL_BUG_RIGHT                    },
+    { Ybug_s,                  EL_BUG_DOWN                     },
+    { Ybug_sB,                 EL_BUG_DOWN                     },
+    { Ybug_w,                  EL_BUG_LEFT                     },
+    { Ybug_wB,                 EL_BUG_LEFT                     },
+    { Ybug_w_n,                        EL_BUG_UP                       },
+    { Ybug_n_e,                        EL_BUG_RIGHT                    },
+    { Ybug_e_s,                        EL_BUG_DOWN                     },
+    { Ybug_s_w,                        EL_BUG_LEFT                     },
+    { Ybug_e_n,                        EL_BUG_UP                       },
+    { Ybug_s_e,                        EL_BUG_RIGHT                    },
+    { Ybug_w_s,                        EL_BUG_DOWN                     },
+    { Ybug_n_w,                        EL_BUG_LEFT                     },
+    { Ybug_stone,              EL_ROCK                         },
+    { Ybug_spring,             EL_SPRING                       },
+    { Xtank_n,                 EL_SPACESHIP_UP                 },
+    { Xtank_e,                 EL_SPACESHIP_RIGHT              },
+    { Xtank_s,                 EL_SPACESHIP_DOWN               },
+    { Xtank_w,                 EL_SPACESHIP_LEFT               },
+    { Xtank_gon,               EL_SPACESHIP_UP                 },
+    { Xtank_goe,               EL_SPACESHIP_RIGHT              },
+    { Xtank_gos,               EL_SPACESHIP_DOWN               },
+    { Xtank_gow,               EL_SPACESHIP_LEFT               },
+    { Ytank_n,                 EL_SPACESHIP_UP                 },
+    { Ytank_nB,                        EL_SPACESHIP_UP                 },
+    { Ytank_e,                 EL_SPACESHIP_RIGHT              },
+    { Ytank_eB,                        EL_SPACESHIP_RIGHT              },
+    { Ytank_s,                 EL_SPACESHIP_DOWN               },
+    { Ytank_sB,                        EL_SPACESHIP_DOWN               },
+    { Ytank_w,                 EL_SPACESHIP_LEFT               },
+    { Ytank_wB,                        EL_SPACESHIP_LEFT               },
+    { Ytank_w_n,               EL_SPACESHIP_UP                 },
+    { Ytank_n_e,               EL_SPACESHIP_RIGHT              },
+    { Ytank_e_s,               EL_SPACESHIP_DOWN               },
+    { Ytank_s_w,               EL_SPACESHIP_LEFT               },
+    { Ytank_e_n,               EL_SPACESHIP_UP                 },
+    { Ytank_s_e,               EL_SPACESHIP_RIGHT              },
+    { Ytank_w_s,               EL_SPACESHIP_DOWN               },
+    { Ytank_n_w,               EL_SPACESHIP_LEFT               },
+    { Ytank_stone,             EL_ROCK                         },
+    { Ytank_spring,            EL_SPRING                       },
+    { Xandroid,                        EL_EMC_ANDROID                  },
+    { Xandroid_1_n,            EL_EMC_ANDROID_UP               },
+    { Xandroid_2_n,            EL_EMC_ANDROID_UP               },
+    { Xandroid_1_e,            EL_EMC_ANDROID_RIGHT            },
+    { Xandroid_2_e,            EL_EMC_ANDROID_RIGHT            },
+    { Xandroid_1_w,            EL_EMC_ANDROID_LEFT             },
+    { Xandroid_2_w,            EL_EMC_ANDROID_LEFT             },
+    { Xandroid_1_s,            EL_EMC_ANDROID_DOWN             },
+    { Xandroid_2_s,            EL_EMC_ANDROID_DOWN             },
+    { Yandroid_n,              EL_EMC_ANDROID_UP               },
+    { Yandroid_nB,             EL_EMC_ANDROID_UP               },
+    { Yandroid_ne,             EL_EMC_ANDROID_RIGHT_UP         },
+    { Yandroid_neB,            EL_EMC_ANDROID_RIGHT_UP         },
+    { Yandroid_e,              EL_EMC_ANDROID_RIGHT            },
+    { Yandroid_eB,             EL_EMC_ANDROID_RIGHT            },
+    { Yandroid_se,             EL_EMC_ANDROID_RIGHT_DOWN       },
+    { Yandroid_seB,            EL_EMC_ANDROID_RIGHT_DOWN       },
+    { Yandroid_s,              EL_EMC_ANDROID_DOWN             },
+    { Yandroid_sB,             EL_EMC_ANDROID_DOWN             },
+    { Yandroid_sw,             EL_EMC_ANDROID_LEFT_DOWN        },
+    { Yandroid_swB,            EL_EMC_ANDROID_LEFT_DOWN        },
+    { Yandroid_w,              EL_EMC_ANDROID_LEFT             },
+    { Yandroid_wB,             EL_EMC_ANDROID_LEFT             },
+    { Yandroid_nw,             EL_EMC_ANDROID_LEFT_UP          },
+    { Yandroid_nwB,            EL_EMC_ANDROID_LEFT_UP          },
+    { Xspring,                 EL_SPRING                       },
+    { Xspring_pause,           EL_SPRING                       },
+    { Xspring_e,               EL_SPRING                       },
+    { Xspring_w,               EL_SPRING                       },
+    { Xspring_fall,            EL_SPRING                       },
+    { Yspring_s,               EL_SPRING                       },
+    { Yspring_sB,              EL_SPRING                       },
+    { Yspring_e,               EL_SPRING                       },
+    { Yspring_eB,              EL_SPRING                       },
+    { Yspring_w,               EL_SPRING                       },
+    { Yspring_wB,              EL_SPRING                       },
+    { Yspring_kill_e,          EL_SPRING                       },
+    { Yspring_kill_eB,         EL_SPRING                       },
+    { Yspring_kill_w,          EL_SPRING                       },
+    { Yspring_kill_wB,         EL_SPRING                       },
+    { Xeater_n,                        EL_YAMYAM                       },
+    { Xeater_e,                        EL_YAMYAM                       },
+    { Xeater_w,                        EL_YAMYAM                       },
+    { Xeater_s,                        EL_YAMYAM                       },
+    { Yeater_n,                        EL_YAMYAM                       },
+    { Yeater_nB,               EL_YAMYAM                       },
+    { Yeater_e,                        EL_YAMYAM                       },
+    { Yeater_eB,               EL_YAMYAM                       },
+    { Yeater_s,                        EL_YAMYAM                       },
+    { Yeater_sB,               EL_YAMYAM                       },
+    { Yeater_w,                        EL_YAMYAM                       },
+    { Yeater_wB,               EL_YAMYAM                       },
+    { Yeater_stone,            EL_ROCK                         },
+    { Yeater_spring,           EL_SPRING                       },
+    { Xalien,                  EL_ROBOT                        },
+    { Xalien_pause,            EL_ROBOT                        },
+    { Yalien_n,                        EL_ROBOT                        },
+    { Yalien_nB,               EL_ROBOT                        },
+    { Yalien_e,                        EL_ROBOT                        },
+    { Yalien_eB,               EL_ROBOT                        },
+    { Yalien_s,                        EL_ROBOT                        },
+    { Yalien_sB,               EL_ROBOT                        },
+    { Yalien_w,                        EL_ROBOT                        },
+    { Yalien_wB,               EL_ROBOT                        },
+    { Yalien_stone,            EL_ROCK                         },
+    { Yalien_spring,           EL_SPRING                       },
+    { Xemerald,                        EL_EMERALD                      },
+    { Xemerald_pause,          EL_EMERALD                      },
+    { Xemerald_fall,           EL_EMERALD                      },
+    { Xemerald_shine,          EL_EMERALD                      },
+    { Yemerald_s,              EL_EMERALD                      },
+    { Yemerald_sB,             EL_EMERALD                      },
+    { Yemerald_e,              EL_EMERALD                      },
+    { Yemerald_eB,             EL_EMERALD                      },
+    { Yemerald_w,              EL_EMERALD                      },
+    { Yemerald_wB,             EL_EMERALD                      },
+    { Yemerald_eat,            EL_EMERALD                      },
+    { Yemerald_stone,          EL_ROCK                         },
+    { Xdiamond,                        EL_DIAMOND                      },
+    { Xdiamond_pause,          EL_DIAMOND                      },
+    { Xdiamond_fall,           EL_DIAMOND                      },
+    { Xdiamond_shine,          EL_DIAMOND                      },
+    { Ydiamond_s,              EL_DIAMOND                      },
+    { Ydiamond_sB,             EL_DIAMOND                      },
+    { Ydiamond_e,              EL_DIAMOND                      },
+    { Ydiamond_eB,             EL_DIAMOND                      },
+    { Ydiamond_w,              EL_DIAMOND                      },
+    { Ydiamond_wB,             EL_DIAMOND                      },
+    { Ydiamond_eat,            EL_DIAMOND                      },
+    { Ydiamond_stone,          EL_ROCK                         },
+    { Xdrip_fall,              EL_AMOEBA_DROP                  },
+    { Xdrip_stretch,           EL_AMOEBA_DROP                  },
+    { Xdrip_stretchB,          EL_AMOEBA_DROP                  },
+    { Xdrip_eat,               EL_AMOEBA_DROP                  },
+    { Ydrip_s1,                        EL_AMOEBA_DROP                  },
+    { Ydrip_s1B,               EL_AMOEBA_DROP                  },
+    { Ydrip_s2,                        EL_AMOEBA_DROP                  },
+    { Ydrip_s2B,               EL_AMOEBA_DROP                  },
+    { Xbomb,                   EL_BOMB                         },
+    { Xbomb_pause,             EL_BOMB                         },
+    { Xbomb_fall,              EL_BOMB                         },
+    { Ybomb_s,                 EL_BOMB                         },
+    { Ybomb_sB,                        EL_BOMB                         },
+    { Ybomb_e,                 EL_BOMB                         },
+    { Ybomb_eB,                        EL_BOMB                         },
+    { Ybomb_w,                 EL_BOMB                         },
+    { Ybomb_wB,                        EL_BOMB                         },
+    { Ybomb_eat,               EL_BOMB                         },
+    { Xballoon,                        EL_BALLOON                      },
+    { Yballoon_n,              EL_BALLOON                      },
+    { Yballoon_nB,             EL_BALLOON                      },
+    { Yballoon_e,              EL_BALLOON                      },
+    { Yballoon_eB,             EL_BALLOON                      },
+    { Yballoon_s,              EL_BALLOON                      },
+    { Yballoon_sB,             EL_BALLOON                      },
+    { Yballoon_w,              EL_BALLOON                      },
+    { Yballoon_wB,             EL_BALLOON                      },
+    { Xgrass,                  EL_SAND                         },
+    { Ygrass_nB,               EL_SAND                         },
+    { Ygrass_eB,               EL_SAND                         },
+    { Ygrass_sB,               EL_SAND                         },
+    { Ygrass_wB,               EL_SAND                         },
+    { Xdirt,                   EL_SAND                         },
+    { Ydirt_nB,                        EL_SAND                         },
+    { Ydirt_eB,                        EL_SAND                         },
+    { Ydirt_sB,                        EL_SAND                         },
+    { Ydirt_wB,                        EL_SAND                         },
+    { Xacid_ne,                        EL_ACID_POOL_TOPRIGHT           },
+    { Xacid_se,                        EL_ACID_POOL_BOTTOMRIGHT        },
+    { Xacid_s,                 EL_ACID_POOL_BOTTOM             },
+    { Xacid_sw,                        EL_ACID_POOL_BOTTOMLEFT         },
+    { Xacid_nw,                        EL_ACID_POOL_TOPLEFT            },
+    { Xacid_1,                 EL_ACID                         },
+    { Xacid_2,                 EL_ACID                         },
+    { Xacid_3,                 EL_ACID                         },
+    { Xacid_4,                 EL_ACID                         },
+    { Xacid_5,                 EL_ACID                         },
+    { Xacid_6,                 EL_ACID                         },
+    { Xacid_7,                 EL_ACID                         },
+    { Xacid_8,                 EL_ACID                         },
+    { Xball_1,                 EL_EMC_GENERATOR_BALL           },
+    { Xball_1B,                        EL_EMC_GENERATOR_BALL           },
+    { Xball_2,                 EL_EMC_GENERATOR_BALL           },
+    { Xball_2B,                        EL_EMC_GENERATOR_BALL           },
+    { Yball_eat,               EL_EMC_GENERATOR_BALL           },
+    { Xgrow_ns,                        EL_EMC_GROW                     },
+    { Ygrow_ns_eat,            EL_EMC_GROW                     },
+    { Xgrow_ew,                        EL_EMC_GROW                     },
+    { Ygrow_ew_eat,            EL_EMC_GROW                     },
+    { Xwonderwall,             EL_MAGIC_WALL                   },
+    { XwonderwallB,            EL_MAGIC_WALL                   },
+    { Xameuba_1,               EL_AMOEBA_WET                   },
+    { Xameuba_2,               EL_AMOEBA_WET                   },
+    { Xameuba_3,               EL_AMOEBA_WET                   },
+    { Xameuba_4,               EL_AMOEBA_WET                   },
+    { Xameuba_5,               EL_AMOEBA_WET                   },
+    { Xameuba_6,               EL_AMOEBA_WET                   },
+    { Xameuba_7,               EL_AMOEBA_WET                   },
+    { Xameuba_8,               EL_AMOEBA_WET                   },
+    { Xdoor_1,                 EL_EM_GATE_1                    },
+    { Xdoor_2,                 EL_EM_GATE_2                    },
+    { Xdoor_3,                 EL_EM_GATE_3                    },
+    { Xdoor_4,                 EL_EM_GATE_4                    },
+    { Xdoor_5,                 EL_EMC_GATE_5                   },
+    { Xdoor_6,                 EL_EMC_GATE_6                   },
+    { Xdoor_7,                 EL_EMC_GATE_7                   },
+    { Xdoor_8,                 EL_EMC_GATE_8                   },
+    { Xkey_1,                  EL_EM_KEY_1                     },
+    { Xkey_2,                  EL_EM_KEY_2                     },
+    { Xkey_3,                  EL_EM_KEY_3                     },
+    { Xkey_4,                  EL_EM_KEY_4                     },
+    { Xkey_5,                  EL_EMC_KEY_5                    },
+    { Xkey_6,                  EL_EMC_KEY_6                    },
+    { Xkey_7,                  EL_EMC_KEY_7                    },
+    { Xkey_8,                  EL_EMC_KEY_8                    },
+    { Xwind_n,                 EL_BALLOON_SWITCH_UP            },
+    { Xwind_e,                 EL_BALLOON_SWITCH_RIGHT         },
+    { Xwind_s,                 EL_BALLOON_SWITCH_DOWN          },
+    { Xwind_w,                 EL_BALLOON_SWITCH_LEFT          },
+    { Xwind_nesw,              EL_BALLOON_SWITCH_ANY           },
+    { Xwind_stop,              EL_BALLOON_SWITCH_NONE          },
+    { Xexit,                   EL_EXIT_CLOSED                  },
+    { Xexit_1,                 EL_EXIT_OPEN                    },
+    { Xexit_2,                 EL_EXIT_OPEN                    },
+    { Xexit_3,                 EL_EXIT_OPEN                    },
+    { Xdynamite,               EL_DYNAMITE                     },
+    { Ydynamite_eat,           EL_DYNAMITE                     },
+    { Xdynamite_1,             EL_DYNAMITE_ACTIVE              },
+    { Xdynamite_2,             EL_DYNAMITE_ACTIVE              },
+    { Xdynamite_3,             EL_DYNAMITE_ACTIVE              },
+    { Xdynamite_4,             EL_DYNAMITE_ACTIVE              },
+    { Xbumper,                 EL_EMC_BUMPER                   },
+    { XbumperB,                        EL_EMC_BUMPER                   },
+    { Xwheel,                  EL_ROBOT_WHEEL                  },
+    { XwheelB,                 EL_ROBOT_WHEEL                  },
+    { Xswitch,                 EL_UNKNOWN                      },
+    { XswitchB,                        EL_UNKNOWN                      },
+    { Xsand,                   EL_QUICKSAND_EMPTY              },
+    { Xsand_stone,             EL_QUICKSAND_FULL               },
+    { Xsand_stonein_1,         EL_QUICKSAND_FULL               },
+    { Xsand_stonein_2,         EL_QUICKSAND_FULL               },
+    { Xsand_stonein_3,         EL_QUICKSAND_FULL               },
+    { Xsand_stonein_4,         EL_QUICKSAND_FULL               },
+    { Xsand_stonesand_1,       EL_QUICKSAND_FULL               },
+    { Xsand_stonesand_2,       EL_QUICKSAND_FULL               },
+    { Xsand_stonesand_3,       EL_QUICKSAND_FULL               },
+    { Xsand_stonesand_4,       EL_QUICKSAND_FULL               },
+    { Xsand_stoneout_1,                EL_QUICKSAND_FULL               },
+    { Xsand_stoneout_2,                EL_QUICKSAND_FULL               },
+    { Xsand_sandstone_1,       EL_QUICKSAND_FULL               },
+    { Xsand_sandstone_2,       EL_QUICKSAND_FULL               },
+    { Xsand_sandstone_3,       EL_QUICKSAND_FULL               },
+    { Xsand_sandstone_4,       EL_QUICKSAND_FULL               },
+    { Xplant,                  EL_EMC_PLANT                    },
+    { Yplant,                  EL_EMC_PLANT                    },
+    { Xlenses,                 EL_EMC_LENSES                   },
+    { Xmagnify,                        EL_EMC_MAGNIFY                  },
+    { Xdripper,                        EL_UNKNOWN                      },
+    { XdripperB,               EL_UNKNOWN                      },
+    { Xfake_blank,             EL_INVISIBLE_WALL               },
+    { Xfake_blankB,            EL_INVISIBLE_WALL               },
+    { Xfake_grass,             EL_INVISIBLE_SAND               },
+    { Xfake_grassB,            EL_INVISIBLE_SAND               },
+    { Xfake_door_1,            EL_EM_GATE_1_GRAY               },
+    { Xfake_door_2,            EL_EM_GATE_2_GRAY               },
+    { Xfake_door_3,            EL_EM_GATE_3_GRAY               },
+    { Xfake_door_4,            EL_EM_GATE_4_GRAY               },
+    { Xfake_door_5,            EL_EMC_GATE_5_GRAY              },
+    { Xfake_door_6,            EL_EMC_GATE_6_GRAY              },
+    { Xfake_door_7,            EL_EMC_GATE_7_GRAY              },
+    { Xfake_door_8,            EL_EMC_GATE_8_GRAY              },
+    { Xsteel_1,                        EL_STEELWALL                    },
+    { Xsteel_2,                        EL_UNKNOWN                      },
+    { Xsteel_3,                        EL_EMC_STEELWALL_1              },
+    { Xsteel_4,                        EL_UNKNOWN                      },
+    { Xwall_1,                 EL_WALL                         },
+    { Xwall_2,                 EL_UNKNOWN                      },
+    { Xwall_3,                 EL_UNKNOWN                      },
+    { Xwall_4,                 EL_UNKNOWN                      },
+    { Xround_wall_1,           EL_WALL_SLIPPERY                },
+    { Xround_wall_2,           EL_UNKNOWN                      },
+    { Xround_wall_3,           EL_UNKNOWN                      },
+    { Xround_wall_4,           EL_UNKNOWN                      },
+    { Xdecor_1,                        EL_UNKNOWN                      },
+    { Xdecor_2,                        EL_EMC_WALL_6                   },
+    { Xdecor_3,                        EL_EMC_WALL_4                   },
+    { Xdecor_4,                        EL_EMC_WALL_5                   },
+    { Xdecor_5,                        EL_EMC_WALL_7                   },
+    { Xdecor_6,                        EL_EMC_WALL_8                   },
+    { Xdecor_7,                        EL_UNKNOWN                      },
+    { Xdecor_8,                        EL_EMC_WALL_1                   },
+    { Xdecor_9,                        EL_EMC_WALL_2                   },
+    { Xdecor_10,               EL_EMC_WALL_3                   },
+    { Xdecor_11,               EL_UNKNOWN                      },
+    { Xdecor_12,               EL_UNKNOWN                      },
+    { Xalpha_0,                        EL_CHAR('0')                    },
+    { Xalpha_1,                        EL_CHAR('1')                    },
+    { Xalpha_2,                        EL_CHAR('2')                    },
+    { Xalpha_3,                        EL_CHAR('3')                    },
+    { Xalpha_4,                        EL_CHAR('4')                    },
+    { Xalpha_5,                        EL_CHAR('5')                    },
+    { Xalpha_6,                        EL_CHAR('6')                    },
+    { Xalpha_7,                        EL_CHAR('7')                    },
+    { Xalpha_8,                        EL_CHAR('8')                    },
+    { Xalpha_9,                        EL_CHAR('9')                    },
+    { Xalpha_excla,            EL_CHAR('!')                    },
+    { Xalpha_quote,            EL_CHAR('"')                    },
+    { Xalpha_comma,            EL_CHAR(',')                    },
+    { Xalpha_minus,            EL_CHAR('-')                    },
+    { Xalpha_perio,            EL_CHAR('.')                    },
+    { Xalpha_colon,            EL_CHAR(':')                    },
+    { Xalpha_quest,            EL_CHAR('?')                    },
+    { Xalpha_a,                        EL_CHAR('A')                    },
+    { Xalpha_b,                        EL_CHAR('B')                    },
+    { Xalpha_c,                        EL_CHAR('C')                    },
+    { Xalpha_d,                        EL_CHAR('D')                    },
+    { Xalpha_e,                        EL_CHAR('E')                    },
+    { Xalpha_f,                        EL_CHAR('F')                    },
+    { Xalpha_g,                        EL_CHAR('G')                    },
+    { Xalpha_h,                        EL_CHAR('H')                    },
+    { Xalpha_i,                        EL_CHAR('I')                    },
+    { Xalpha_j,                        EL_CHAR('J')                    },
+    { Xalpha_k,                        EL_CHAR('K')                    },
+    { Xalpha_l,                        EL_CHAR('L')                    },
+    { Xalpha_m,                        EL_CHAR('M')                    },
+    { Xalpha_n,                        EL_CHAR('N')                    },
+    { Xalpha_o,                        EL_CHAR('O')                    },
+    { Xalpha_p,                        EL_CHAR('P')                    },
+    { Xalpha_q,                        EL_CHAR('Q')                    },
+    { Xalpha_r,                        EL_CHAR('R')                    },
+    { Xalpha_s,                        EL_CHAR('S')                    },
+    { Xalpha_t,                        EL_CHAR('T')                    },
+    { Xalpha_u,                        EL_CHAR('U')                    },
+    { Xalpha_v,                        EL_CHAR('V')                    },
+    { Xalpha_w,                        EL_CHAR('W')                    },
+    { Xalpha_x,                        EL_CHAR('X')                    },
+    { Xalpha_y,                        EL_CHAR('Y')                    },
+    { Xalpha_z,                        EL_CHAR('Z')                    },
+    { Xalpha_arrow_e,          EL_CHAR('>')                    },
+    { Xalpha_arrow_w,          EL_CHAR('<')                    },
+    { Xalpha_copyr,            EL_CHAR('©')                    },
+
+    { Zplayer,                 EL_PLAYER_1                     },
+
+    { ZBORDER,                 EL_EMC_LEVEL_BORDER             },
+
+    { -1,                      -1                              }
+  };
+
+  if (!mapping_initialized)
+  {
+    int i;
+
+    /* return "EL_UNKNOWN" for all undefined elements in mapping array */
+    for (i = 0; i < TILE_MAX; i++)
+      mapping_EM_to_RND[i] = EL_UNKNOWN;
+
+    for (i = 0; mapping_EM_to_RND_list[i].element_em != -1; i++)
+      mapping_EM_to_RND[mapping_EM_to_RND_list[i].element_em] =
+       mapping_EM_to_RND_list[i].element_rnd;
+
+    mapping_initialized = TRUE;
+  }
+
+  if (element_em >= 0 && element_em < TILE_MAX)
+    return mapping_EM_to_RND[element_em];
+
+  Error(ERR_WARN, "invalid EM level element %d", element_em);
+
+  return EL_UNKNOWN;
+}
+
+void CopyNativeLevel_RND_to_EM(struct LevelInfo *level)
+{
+  struct LevelInfo_EM *level_em = level->native_em_level;
+  struct LEVEL *lev = level_em->lev;
+  struct PLAYER *ply1 = level_em->ply1;
+  struct PLAYER *ply2 = level_em->ply2;
+  int i, x, y;
+
+  lev->width  = MIN(level->fieldx, EM_MAX_CAVE_WIDTH);
+  lev->height = MIN(level->fieldy, EM_MAX_CAVE_HEIGHT);
+
+  lev->time_initial = level->time;
+  lev->required_initial = level->gems_needed;
+
+  lev->emerald_score   = level->score[SC_EMERALD];
+  lev->diamond_score   = level->score[SC_DIAMOND];
+  lev->alien_score     = level->score[SC_ROBOT];
+  lev->tank_score      = level->score[SC_SPACESHIP];
+  lev->bug_score       = level->score[SC_BUG];
+  lev->eater_score     = level->score[SC_YAMYAM];
+  lev->nut_score       = level->score[SC_NUT];
+  lev->dynamite_score  = level->score[SC_DYNAMITE];
+  lev->key_score       = level->score[SC_TIME_BONUS];  /* ??? CHECK THIS */
+
+  for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
+    for (y = 0; y < 3; y++)
+      for (x = 0; x < 3; x++)
+       lev->eater_array[i][y * 3 + x] =
+         map_element_RND_to_EM(level->yamyam_content[i][x][y]);
+
+  lev->ameuba_time             = level->amoeba_speed;
+  lev->wonderwall_time_initial = level->time_magic_wall;
+  lev->wheel_time              = level->time_wheel;
+
+  /* first fill the complete playfield with the default border element */
+  for (y = 0; y < EM_MAX_CAVE_HEIGHT; y++)
+    for (x = 0; x < EM_MAX_CAVE_WIDTH; x++)
+      level_em->cave[x][y] = ZBORDER;
+
+  /* then copy the real level contents from level file into the playfield */
+  for (y = 0; y < lev->height; y++) for (x = 0; x < lev->width; x++)
+  {
+    int new_element = map_element_RND_to_EM(level->field[x][y]);
+
+    level_em->cave[x + 1][y + 1] = new_element;
+  }
+
+  ply1->x_initial = 0;
+  ply1->y_initial = 0;
+
+  ply2->x_initial = 0;
+  ply2->y_initial = 0;
+
+  /* at last, set the two players at their positions in the playfield */
+  for (y = 0; y < lev->height; y++) for (x = 0; x < lev->width; x++)
+  {
+    if (level->field[x][y] == EL_PLAYER_1)
+    {
+      ply1->x_initial = x + 1;
+      ply1->y_initial = y + 1;
+    }
+    else if (level->field[x][y] == EL_PLAYER_2)
+    {
+      ply2->x_initial = x + 1;
+      ply2->y_initial = y + 1;
+    }
+  }
+}
+
+void CopyNativeLevel_EM_to_RND(struct LevelInfo *level)
+{
+  struct LevelInfo_EM *level_em = level->native_em_level;
+  struct LEVEL *lev = level_em->lev;
+  struct PLAYER *ply1 = level_em->ply1;
+  struct PLAYER *ply2 = level_em->ply2;
+  int i, x, y;
+
+  level->fieldx = MIN(lev->width,  MAX_LEV_FIELDX);
+  level->fieldy = MIN(lev->height, MAX_LEV_FIELDY);
+
+  level->time = lev->time_initial;
+  level->gems_needed = lev->required_initial;
+
+  sprintf(level->name, "Level %d", level->file_info.nr);
+
+  level->score[SC_EMERALD]     = lev->emerald_score;
+  level->score[SC_DIAMOND]     = lev->diamond_score;
+  level->score[SC_ROBOT]       = lev->alien_score;
+  level->score[SC_SPACESHIP]   = lev->tank_score;
+  level->score[SC_BUG]         = lev->bug_score;
+  level->score[SC_YAMYAM]      = lev->eater_score;
+  level->score[SC_NUT]         = lev->nut_score;
+  level->score[SC_DYNAMITE]    = lev->dynamite_score;
+  level->score[SC_TIME_BONUS]  = lev->key_score;       /* ??? CHECK THIS */
+
+  level->num_yamyam_contents = MAX_ELEMENT_CONTENTS;
+
+  for (i = 0; i < level->num_yamyam_contents; i++)
+    for (y = 0; y < 3; y++)
+      for (x = 0; x < 3; x++)
+       level->yamyam_content[i][x][y] =
+         map_element_EM_to_RND(lev->eater_array[i][y * 3 + x]);
+
+  level->amoeba_speed          = lev->ameuba_time;
+  level->time_magic_wall       = lev->wonderwall_time_initial;
+  level->time_wheel            = lev->wheel_time;
+
+  for (y = 0; y < level->fieldy; y++) for (x = 0; x < level->fieldx; x++)
+  {
+    int new_element = map_element_EM_to_RND(level_em->cave[x + 1][y + 1]);
+
+    if (new_element == EL_AMOEBA_WET && level->amoeba_speed == 0)
+      new_element = EL_AMOEBA_DEAD;
+
+    level->field[x][y] = new_element;
+  }
+
+  level->field[ply1->x_initial - 1][ply1->y_initial - 1] = EL_PLAYER_1;
+  level->field[ply2->x_initial - 1][ply2->y_initial - 1] = EL_PLAYER_2;
+}
+
+static void LoadLevelFromFileInfo_EM(struct LevelInfo *level,
+                                    struct LevelFileInfo *level_file_info)
+{
+  if (!LoadNativeLevel_EM(level_file_info->filename))
+    level->no_valid_file = TRUE;
+
+  CopyNativeLevel_EM_to_RND(level);
+}
+
+#endif
+
+
 /* ------------------------------------------------------------------------- */
 /* functions for loading SP level                                            */
 /* ------------------------------------------------------------------------- */
@@ -1770,8 +2543,12 @@ static void LoadLevelFromFileInfo_EM(struct LevelInfo *level,
 static void LoadLevelFromFileStream_SP(FILE *file, struct LevelInfo *level,
                                       int nr)
 {
+  int num_special_ports;
   int i, x, y;
 
+  /* for details of the Supaplex level format, see Herman Perk's Supaplex
+     documentation file "SPFIX63.DOC" from his Supaplex "SpeedFix" package */
+
   /* read level body (width * height == 60 * 24 tiles == 1440 bytes) */
   for (y = 0; y < SP_LEVEL_YSIZE; y++)
   {
@@ -1796,28 +2573,104 @@ static void LoadLevelFromFileStream_SP(FILE *file, struct LevelInfo *level,
     }
   }
 
-  ReadUnusedBytesFromFile(file, 4);
+  ReadUnusedBytesFromFile(file, 4);    /* (not used by Supaplex engine) */
 
-  /* Initial gravitation: 1 == "on", anything else (0) == "off" */
+  /* initial gravity: 1 == "on", anything else (0) == "off" */
   level->initial_gravity = (fgetc(file) == 1 ? TRUE : FALSE);
 
-  ReadUnusedBytesFromFile(file, 1);
+  ReadUnusedBytesFromFile(file, 1);    /* (not used by Supaplex engine) */
 
   /* level title in uppercase letters, padded with dashes ("-") (23 bytes) */
   for (i = 0; i < SP_LEVEL_NAME_LEN; i++)
     level->name[i] = fgetc(file);
   level->name[SP_LEVEL_NAME_LEN] = '\0';
 
-  /* initial "freeze zonks": 2 == "on", anything else (0) == "off" */
-  ReadUnusedBytesFromFile(file, 1);    /* !!! NOT SUPPORTED YET !!! */
+  /* initial "freeze zonks": 2 == "on", anything else (0, 1) == "off" */
+  ReadUnusedBytesFromFile(file, 1);    /* (not used by R'n'D engine) */
 
   /* number of infotrons needed; 0 means that Supaplex will count the total
-     amount of infotrons in the level and use the low byte of that number.
+     amount of infotrons in the level and use the low byte of that number
      (a multiple of 256 infotrons will result in "0 infotrons needed"!) */
   level->gems_needed = fgetc(file);
 
-  /* information about special gravity port entries */
-  ReadUnusedBytesFromFile(file, 65);   /* !!! NOT SUPPORTED YET !!! */
+  /* number of special ("gravity") port entries below (maximum 10 allowed) */
+  num_special_ports = fgetc(file);
+
+  /* database of properties of up to 10 special ports (6 bytes per port) */
+  for (i = 0; i < 10; i++)
+  {
+    int port_location, port_x, port_y, port_element;
+    int gravity;
+
+    /* high and low byte of the location of a special port; if (x, y) are the
+       coordinates of a port in the field and (0, 0) is the top-left corner,
+       the 16 bit value here calculates as 2 * (x + (y * 60)) (this is twice
+       of what may be expected: Supaplex works with a game field in memory
+       which is 2 bytes per tile) */
+    port_location = getFile16BitBE(file);
+
+    /* change gravity: 1 == "turn on", anything else (0) == "turn off" */
+    gravity = fgetc(file);
+
+    /* "freeze zonks": 2 == "turn on", anything else (0, 1) == "turn off" */
+    ReadUnusedBytesFromFile(file, 1);  /* (not used by R'n'D engine) */
+
+    /* "freeze enemies": 1 == "turn on", anything else (0) == "turn off" */
+    ReadUnusedBytesFromFile(file, 1);  /* (not used by R'n'D engine) */
+
+    ReadUnusedBytesFromFile(file, 1);  /* (not used by Supaplex engine) */
+
+    if (i >= num_special_ports)
+      continue;
+
+    port_x = (port_location / 2) % SP_LEVEL_XSIZE;
+    port_y = (port_location / 2) / SP_LEVEL_XSIZE;
+
+    if (port_x < 0 || port_x >= SP_LEVEL_XSIZE ||
+       port_y < 0 || port_y >= SP_LEVEL_YSIZE)
+    {
+      Error(ERR_WARN, "special port position (%d, %d) out of bounds",
+           port_x, port_y);
+
+      continue;
+    }
+
+    port_element = level->field[port_x][port_y];
+
+    if (port_element < EL_SP_GRAVITY_PORT_RIGHT ||
+       port_element > EL_SP_GRAVITY_PORT_UP)
+    {
+      Error(ERR_WARN, "no special port at position (%d, %d)", port_x, port_y);
+
+      continue;
+    }
+
+    /* change previous (wrong) gravity inverting special port to either
+       gravity enabling special port or gravity disabling special port */
+    level->field[port_x][port_y] +=
+      (gravity == 1 ? EL_SP_GRAVITY_ON_PORT_RIGHT :
+       EL_SP_GRAVITY_OFF_PORT_RIGHT) - EL_SP_GRAVITY_PORT_RIGHT;
+  }
+
+  ReadUnusedBytesFromFile(file, 4);    /* (not used by Supaplex engine) */
+
+  /* change special gravity ports without database entries to normal ports */
+  for (y = 0; y < SP_LEVEL_YSIZE; y++)
+    for (x = 0; x < SP_LEVEL_XSIZE; x++)
+      if (level->field[x][y] >= EL_SP_GRAVITY_PORT_RIGHT &&
+         level->field[x][y] <= EL_SP_GRAVITY_PORT_UP)
+       level->field[x][y] += EL_SP_PORT_RIGHT - EL_SP_GRAVITY_PORT_RIGHT;
+
+  /* auto-determine number of infotrons if it was stored as "0" -- see above */
+  if (level->gems_needed == 0)
+  {
+    for (y = 0; y < SP_LEVEL_YSIZE; y++)
+      for (x = 0; x < SP_LEVEL_XSIZE; x++)
+       if (level->field[x][y] == EL_SP_INFOTRON)
+         level->gems_needed++;
+
+    level->gems_needed &= 0xff;                /* only use low byte -- see above */
+  }
 
   level->fieldx = SP_LEVEL_XSIZE;
   level->fieldy = SP_LEVEL_YSIZE;
@@ -1828,13 +2681,13 @@ static void LoadLevelFromFileStream_SP(FILE *file, struct LevelInfo *level,
   level->time_wheel = 0;
   level->amoeba_content = EL_EMPTY;
 
-  for(i = 0; i < LEVEL_SCORE_ELEMENTS; i++)
+  for (i = 0; i < LEVEL_SCORE_ELEMENTS; i++)
     level->score[i] = 0;               /* !!! CORRECT THIS !!! */
 
   /* there are no yamyams in supaplex levels */
-  for(i = 0; i < level->num_yamyam_contents; i++)
-    for(y = 0; y < 3; y++)
-      for(x = 0; x < 3; x++)
+  for (i = 0; i < level->num_yamyam_contents; i++)
+    for (y = 0; y < 3; y++)
+      for (x = 0; x < 3; x++)
        level->yamyam_content[i][x][y] = EL_EMPTY;
 }
 
@@ -2035,6 +2888,7 @@ void LoadLevelFromFileInfo(struct LevelInfo *level,
 
     case LEVEL_FILE_TYPE_EM:
       LoadLevelFromFileInfo_EM(level, level_file_info);
+      level->game_engine_type = GAME_ENGINE_TYPE_EM;
       break;
 
     case LEVEL_FILE_TYPE_SP:
@@ -2045,6 +2899,9 @@ void LoadLevelFromFileInfo(struct LevelInfo *level,
       LoadLevelFromFileInfo_RND(level, level_file_info);
       break;
   }
+
+  if (level->game_engine_type == GAME_ENGINE_TYPE_UNKNOWN)
+    level->game_engine_type = GAME_ENGINE_TYPE_RND;
 }
 
 void LoadLevelFromFilename(struct LevelInfo *level, char *filename)
@@ -2117,9 +2974,11 @@ static void LoadLevel_InitVersion(struct LevelInfo *level, char *filename)
     if (level->game_version == VERSION_IDENT(2,0,1,0))
       level->em_slippery_gems = TRUE;
 
+    /* springs could be pushed over pits before (pre-release version) 2.2.0 */
     if (level->game_version < VERSION_IDENT(2,2,0,0))
       level->use_spring_bug = TRUE;
 
+    /* only few elements were able to actively move into acid before 3.1.0 */
     if (level->game_version < VERSION_IDENT(3,1,0,0))
     {
       int i, j;
@@ -2149,8 +3008,25 @@ static void LoadLevel_InitVersion(struct LevelInfo *level, char *filename)
        }
       }
     }
+
+#if 1  /* USE_NEW_BLOCK_STYLE */
+    /* blocking the last field when moving was corrected in version 3.1.1 */
+    if (level->game_version < VERSION_IDENT(3,1,1,0))
+    {
+#if 0
+      printf("::: %d\n", level->block_last_field);
+#endif
+
+      /* even "not blocking" was blocking the last field for one frame */
+      level->block_delay    = (level->block_last_field    ? 7 : 1);
+      level->sp_block_delay = (level->sp_block_last_field ? 7 : 1);
+
+      level->block_last_field = TRUE;
+      level->sp_block_last_field = TRUE;
+    }
+#endif
   }
-  else
+  else         /* always use the latest game engine version */
   {
 #if 0
     printf("\n::: ALWAYS USE LATEST ENGINE FOR THIS LEVEL: [%d] '%s'\n",
@@ -2272,7 +3148,8 @@ static void LoadLevel_InitElements(struct LevelInfo *level, char *filename)
   }
 
   /* initialize "can_explode" field for old levels which did not store this */
-  if (level->game_version <= VERSION_IDENT(3,1,0,2))
+  /* !!! CHECK THIS -- "<= 3,1,0,0" IS PROBABLY WRONG !!! */
+  if (level->game_version <= VERSION_IDENT(3,1,0,0))
   {
     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
     {
@@ -2287,6 +3164,22 @@ static void LoadLevel_InitElements(struct LevelInfo *level, char *filename)
     }
   }
 
+  /* correct previously hard-coded move delay values for maze runner style */
+  if (level->game_version < VERSION_IDENT(3,1,1,0))
+  {
+    for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
+    {
+      int element = EL_CUSTOM_START + i;
+
+      if (element_info[element].move_pattern & MV_MAZE_RUNNER_STYLE)
+      {
+       /* previously hard-coded and therefore ignored */
+       element_info[element].move_delay_fixed = 9;
+       element_info[element].move_delay_random = 0;
+      }
+    }
+  }
+
 #if 0
   /* set default push delay values (corrected since version 3.0.7-1) */
   if (level->game_version < VERSION_IDENT(3,0,7,1))
@@ -2379,6 +3272,16 @@ static void LoadLevel_InitPlayfield(struct LevelInfo *level, char *filename)
 
 void LoadLevelTemplate(int nr)
 {
+#if 1
+  char *filename;
+
+  setLevelFileInfo(&level_template.file_info, nr);
+  filename = level_template.file_info.filename;
+
+  LoadLevelFromFileInfo(&level_template, &level_template.file_info);
+
+#else
+
 #if 1
   struct LevelFileInfo *level_file_info = getLevelFileInfo(nr);
   char *filename = level_file_info->filename;
@@ -2389,15 +3292,31 @@ void LoadLevelTemplate(int nr)
 
   LoadLevelFromFilename_RND(&level_template, filename);
 #endif
+#endif
 
+#if 1
+  LoadLevel_InitVersion(&level_template, filename);
+  LoadLevel_InitElements(&level_template, filename);
+#else
   LoadLevel_InitVersion(&level, filename);
   LoadLevel_InitElements(&level, filename);
+#endif
 
   ActivateLevelTemplate();
 }
 
 void LoadLevel(int nr)
 {
+#if 1
+  char *filename;
+
+  setLevelFileInfo(&level.file_info, nr);
+  filename = level.file_info.filename;
+
+  LoadLevelFromFileInfo(&level, &level.file_info);
+
+#else
+
 #if 1
   struct LevelFileInfo *level_file_info = getLevelFileInfo(nr);
   char *filename = level_file_info->filename;
@@ -2407,6 +3326,7 @@ void LoadLevel(int nr)
   char *filename = getLevelFilename(nr);
 
   LoadLevelFromFilename_RND(&level, filename);
+#endif
 #endif
 
   if (level.use_custom_template)
@@ -2472,6 +3392,8 @@ static void SaveLevel_HEAD(FILE *file, struct LevelInfo *level)
   putFile8Bit(file, (level->can_pass_to_walkable ? 1 : 0));
   putFile8Bit(file, (level->grow_into_diggable ? 1 : 0));
 
+  putFile8Bit(file, level->game_engine_type);
+
   WriteUnusedBytesToFile(file, LEVEL_HEADER_UNUSED);
 }
 
@@ -3499,6 +4421,8 @@ void DumpTape(struct TapeInfo *tape)
   printf_line("-", 79);
   printf("Tape of Level %03d (file version %08d, game version %08d)\n",
         tape->level_nr, tape->file_version, tape->game_version);
+  printf("                  (effective engine version %08d)\n",
+        tape->engine_version);
   printf("Level series identifier: '%s'\n", tape->level_identifier);
   printf_line("-", 79);
 
@@ -4741,3 +5665,117 @@ void LoadHelpTextInfo()
   END_HASH_ITERATION(hash, itr)
 #endif
 }
+
+
+/* ------------------------------------------------------------------------- *
+ * convert levels
+ * ------------------------------------------------------------------------- */
+
+#define MAX_NUM_CONVERT_LEVELS         1000
+
+void ConvertLevels()
+{
+  static LevelDirTree *convert_leveldir = NULL;
+  static int convert_level_nr = -1;
+  static int num_levels_handled = 0;
+  static int num_levels_converted = 0;
+  static boolean levels_failed[MAX_NUM_CONVERT_LEVELS];
+  int i;
+
+  convert_leveldir = getTreeInfoFromIdentifier(leveldir_first,
+                                              global.convert_leveldir);
+
+  if (convert_leveldir == NULL)
+    Error(ERR_EXIT, "no such level identifier: '%s'",
+         global.convert_leveldir);
+
+  leveldir_current = convert_leveldir;
+
+  if (global.convert_level_nr != -1)
+  {
+    convert_leveldir->first_level = global.convert_level_nr;
+    convert_leveldir->last_level  = global.convert_level_nr;
+  }
+
+  convert_level_nr = convert_leveldir->first_level;
+
+  printf_line("=", 79);
+  printf("Converting levels\n");
+  printf_line("-", 79);
+  printf("Level series identifier: '%s'\n", convert_leveldir->identifier);
+  printf("Level series name:       '%s'\n", convert_leveldir->name);
+  printf("Level series author:     '%s'\n", convert_leveldir->author);
+  printf("Number of levels:        %d\n",   convert_leveldir->levels);
+  printf_line("=", 79);
+  printf("\n");
+
+  for (i = 0; i < MAX_NUM_CONVERT_LEVELS; i++)
+    levels_failed[i] = FALSE;
+
+  while (convert_level_nr <= convert_leveldir->last_level)
+  {
+    char *level_filename;
+    boolean new_level;
+
+    level_nr = convert_level_nr++;
+
+    printf("Level %03d: ", level_nr);
+
+    LoadLevel(level_nr);
+    if (level.no_valid_file)
+    {
+      printf("(no level)\n");
+      continue;
+    }
+
+    printf("converting level ... ");
+
+    level_filename = getDefaultLevelFilename(level_nr);
+    new_level = !fileExists(level_filename);
+
+    if (new_level)
+    {
+      SaveLevel(level_nr);
+
+      num_levels_converted++;
+
+      printf("converted.\n");
+    }
+    else
+    {
+      if (level_nr >= 0 && level_nr < MAX_NUM_CONVERT_LEVELS)
+       levels_failed[level_nr] = TRUE;
+
+      printf("NOT CONVERTED -- LEVEL ALREADY EXISTS.\n");
+    }
+
+    num_levels_handled++;
+  }
+
+  printf("\n");
+  printf_line("=", 79);
+  printf("Number of levels handled: %d\n", num_levels_handled);
+  printf("Number of levels converted: %d (%d%%)\n", num_levels_converted,
+        (num_levels_handled ?
+         num_levels_converted * 100 / num_levels_handled : 0));
+  printf_line("-", 79);
+  printf("Summary (for automatic parsing by scripts):\n");
+  printf("LEVELDIR '%s', CONVERTED %d/%d (%d%%)",
+        convert_leveldir->identifier, num_levels_converted,
+        num_levels_handled,
+        (num_levels_handled ?
+         num_levels_converted * 100 / num_levels_handled : 0));
+
+  if (num_levels_handled != num_levels_converted)
+  {
+    printf(", FAILED:");
+    for (i = 0; i < MAX_NUM_CONVERT_LEVELS; i++)
+      if (levels_failed[i])
+       printf(" %03d", i);
+  }
+
+  printf("\n");
+  printf_line("=", 79);
+
+  CloseAllAndExit(0);
+}