rocksndiamonds-3.3.0.0
[rocksndiamonds.git] / src / files.c
index e96f86364e3345f5863bd9d4889bb94a0f939b14..d7837486d401d930248e8bfafe7836753027f1fe 100644 (file)
@@ -1,7 +1,7 @@
 /***********************************************************
 * Rocks'n'Diamonds -- McDuffin Strikes Back!               *
 *----------------------------------------------------------*
-* (c) 1995-2002 Artsoft Entertainment                      *
+* (c) 1995-2006 Artsoft Entertainment                      *
 *               Holger Schemel                             *
 *               Detmolder Strasse 189                      *
 *               33604 Bielefeld                            *
 #define CHUNK_SIZE_UNDEFINED   0       /* undefined chunk size == 0  */
 #define CHUNK_SIZE_NONE                -1      /* do not write chunk size    */
 
+#define LEVEL_CHUNK_NAME_SIZE  MAX_LEVEL_NAME_LEN
+#define LEVEL_CHUNK_AUTH_SIZE  MAX_LEVEL_AUTHOR_LEN
+
 #define LEVEL_CHUNK_VERS_SIZE  8       /* size of file version chunk */
+#define LEVEL_CHUNK_DATE_SIZE  4       /* size of file date chunk    */
 #define LEVEL_CHUNK_HEAD_SIZE  80      /* size of level file header  */
 #define LEVEL_CHUNK_HEAD_UNUSED        0       /* unused level header bytes  */
 #define LEVEL_CHUNK_CNT2_SIZE  160     /* size of level CNT2 chunk   */
 #define LEVEL_CPART_CUS3_UNUSED        15      /* unused CUS3 bytes / part   */
 #define LEVEL_CHUNK_GRP1_SIZE  74      /* size of level GRP1 chunk   */
 
+/* (element number, number of change pages, change page number) */
+#define LEVEL_CHUNK_CUSX_UNCHANGED     (2 + (1 + 1) + (1 + 1))
+
+/* (element number only) */
+#define LEVEL_CHUNK_GRPX_UNCHANGED     2
+#define LEVEL_CHUNK_NOTE_UNCHANGED     2
+
+/* (nothing at all if unchanged) */
+#define LEVEL_CHUNK_ELEM_UNCHANGED     0
+
 #define TAPE_CHUNK_VERS_SIZE   8       /* size of file version chunk */
 #define TAPE_CHUNK_HEAD_SIZE   20      /* size of tape file header   */
 #define TAPE_CHUNK_HEAD_UNUSED 3       /* unused tape header bytes   */
 #define TAPE_COOKIE_TMPL               "ROCKSNDIAMONDS_TAPE_FILE_VERSION_x.x"
 #define SCORE_COOKIE                   "ROCKSNDIAMONDS_SCORE_FILE_VERSION_1.2"
 
-/* values for "CONF" chunk */
+/* values for deciding when (not) to save configuration data */
+#define SAVE_CONF_NEVER                        0
+#define SAVE_CONF_ALWAYS               1
+#define SAVE_CONF_WHEN_CHANGED         -1
+
+/* values for chunks using micro chunks */
 #define CONF_MASK_1_BYTE               0x00
 #define CONF_MASK_2_BYTE               0x40
 #define CONF_MASK_4_BYTE               0x80
 #define CONF_VALUE_4_BYTE(x)           (CONF_MASK_4_BYTE       | (x))
 #define CONF_VALUE_MULTI_BYTES(x)      (CONF_MASK_MULTI_BYTES  | (x))
 
-/* a sequence of configuration values can be terminated by this value */
-#define CONF_LAST_ENTRY                        CONF_VALUE_1_BYTE(0)
-
 /* these definitions are just for convenience of use and readability */
 #define CONF_VALUE_8_BIT(x)            CONF_VALUE_1_BYTE(x)
 #define CONF_VALUE_16_BIT(x)           CONF_VALUE_2_BYTE(x)
 #define CONF_VALUE_32_BIT(x)           CONF_VALUE_4_BYTE(x)
 #define CONF_VALUE_BYTES(x)            CONF_VALUE_MULTI_BYTES(x)
 
-#if 0
-#define CONF_VALUE_INTEGER_1           CONF_VALUE_8_BIT(1)
-#define CONF_VALUE_INTEGER_2           CONF_VALUE_8_BIT(2)
-#define CONF_VALUE_INTEGER_3           CONF_VALUE_8_BIT(3)
-#define CONF_VALUE_INTEGER_4           CONF_VALUE_8_BIT(4)
-#define CONF_VALUE_INTEGER_5           CONF_VALUE_8_BIT(5)
-#define CONF_VALUE_INTEGER_6           CONF_VALUE_8_BIT(6)
-#define CONF_VALUE_INTEGER_7           CONF_VALUE_8_BIT(7)
-#define CONF_VALUE_INTEGER_8           CONF_VALUE_8_BIT(8)
-#define CONF_VALUE_BOOLEAN_1           CONF_VALUE_8_BIT(9)
-#define CONF_VALUE_BOOLEAN_2           CONF_VALUE_8_BIT(10)
-#define CONF_VALUE_BOOLEAN_3           CONF_VALUE_8_BIT(11)
-#define CONF_VALUE_BOOLEAN_4           CONF_VALUE_8_BIT(12)
-#define CONF_VALUE_BOOLEAN_5           CONF_VALUE_8_BIT(13)
-#define CONF_VALUE_BOOLEAN_6           CONF_VALUE_8_BIT(14)
-#define CONF_VALUE_BOOLEAN_7           CONF_VALUE_8_BIT(15)
-#define CONF_VALUE_BOOLEAN_8           CONF_VALUE_8_BIT(16)
-
-#define CONF_VALUE_ELEMENT_1           CONF_VALUE_16_BIT(1)
-#define CONF_VALUE_ELEMENT_2           CONF_VALUE_16_BIT(2)
-#define CONF_VALUE_ELEMENT_3           CONF_VALUE_16_BIT(3)
-#define CONF_VALUE_ELEMENT_4           CONF_VALUE_16_BIT(4)
-#define CONF_VALUE_ELEMENT_5           CONF_VALUE_16_BIT(5)
-#define CONF_VALUE_ELEMENT_6           CONF_VALUE_16_BIT(6)
-#define CONF_VALUE_ELEMENT_7           CONF_VALUE_16_BIT(7)
-#define CONF_VALUE_ELEMENT_8           CONF_VALUE_16_BIT(8)
-
-#define CONF_VALUE_ELEMENTS            CONF_VALUE_BYTES(1)
-#define CONF_VALUE_CONTENTS            CONF_VALUE_BYTES(2)
-#endif
-
-#if 0
-#define CONF_VALUE_INTEGER(x)          ((x) >= CONF_VALUE_INTEGER_1 && \
-                                        (x) <= CONF_VALUE_INTEGER_8)
-
-#define CONF_VALUE_BOOLEAN(x)          ((x) >= CONF_VALUE_BOOLEAN_1 && \
-                                        (x) <= CONF_VALUE_BOOLEAN_8)
-#endif
-
 #define CONF_VALUE_NUM_BYTES(x)                ((x) == CONF_MASK_1_BYTE ? 1 :  \
                                         (x) == CONF_MASK_2_BYTE ? 2 :  \
                                         (x) == CONF_MASK_4_BYTE ? 4 : 0)
 
-#if 0
-#define CONF_CONTENT_NUM_ELEMENTS      (3 * 3)
-#define CONF_CONTENT_NUM_BYTES         (CONF_CONTENT_NUM_ELEMENTS * 2)
-#define CONF_ELEMENT_NUM_BYTES         (2)
-
-#define CONF_ENTITY_NUM_BYTES(t)       ((t) == CONF_VALUE_ELEMENTS ?   \
-                                        CONF_ELEMENT_NUM_BYTES :       \
-                                        (t) == CONF_VALUE_CONTENTS ?   \
-                                        CONF_CONTENT_NUM_BYTES : 1)
-#endif
-
 #define CONF_CONTENT_NUM_ELEMENTS      (3 * 3)
 #define CONF_CONTENT_NUM_BYTES         (CONF_CONTENT_NUM_ELEMENTS * 2)
 #define CONF_ELEMENT_NUM_BYTES         (2)
 #define CONF_CONTENTS_ELEMENT(b,c,x,y) ((b[CONF_CONTENT_BYTE_POS(c,x,y)]<< 8)|\
                                        (b[CONF_CONTENT_BYTE_POS(c,x,y) + 1]))
 
-#if 0
-static void LoadLevel_InitPlayfield(struct LevelInfo *, char *);
-#endif
-
 /* temporary variables used to store pointers to structure members */
 static struct LevelInfo li;
 static struct ElementInfo xx_ei, yy_ei;
 static struct ElementChangeInfo xx_change;
 static struct ElementGroupInfo xx_group;
+static struct EnvelopeInfo xx_envelope;
 static unsigned int xx_event_bits[NUM_CE_BITFIELDS];
 static char xx_default_description[MAX_ELEMENT_NAME_LEN + 1];
-static int xx_default_description_length;
 static int xx_num_contents;
 static int xx_current_change_page;
+static char xx_default_string_empty[1] = "";
+static int xx_string_length_unused;
 
 struct LevelFileConfigInfo
 {
   int element;                 /* element for which data is to be stored */
-  int data_type;               /* internal type of data */
-  int conf_type;               /* special type identifier stored in file */
+  int save_type;               /* save data always, never or when changed */
+  int data_type;               /* data type (used internally, not stored) */
+  int conf_type;               /* micro chunk identifier (stored in file) */
 
   /* (mandatory) */
   void *value;                 /* variable that holds the data to be stored */
@@ -184,458 +149,645 @@ struct LevelFileConfigInfo
   char *default_string;                /* optional default string for string data */
 };
 
-static struct LevelFileConfigInfo chunk_config_CONF[] =
+static struct LevelFileConfigInfo chunk_config_INFO[] =
 {
+  /* ---------- values not related to single elements ----------------------- */
+
   {
-    EL_PLAYER_1,
+    -1,                                        SAVE_CONF_ALWAYS,
     TYPE_INTEGER,                      CONF_VALUE_8_BIT(1),
-    &li.initial_player_stepsize,       STEPSIZE_NORMAL
+    &li.game_engine_type,              GAME_ENGINE_TYPE_RND
+  },
+
+  {
+    -1,                                        SAVE_CONF_ALWAYS,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.fieldx,                                STD_LEV_FIELDX
+  },
+  {
+    -1,                                        SAVE_CONF_ALWAYS,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(2),
+    &li.fieldy,                                STD_LEV_FIELDY
+  },
+
+  {
+    -1,                                        SAVE_CONF_ALWAYS,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(3),
+    &li.time,                          100
+  },
+
+  {
+    -1,                                        SAVE_CONF_ALWAYS,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(4),
+    &li.gems_needed,                   0
   },
+
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_32_BIT(2),
+    &li.random_seed,                   0
+  },
+
   {
-    EL_PLAYER_1,
+    -1,                                        -1,
     TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(2),
+    &li.use_step_counter,              FALSE
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_BITFIELD,                     CONF_VALUE_8_BIT(4),
+    &li.wind_direction_initial,                MV_NONE
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(5),
+    &li.em_slippery_gems,              FALSE
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(6),
+    &li.use_custom_template,           FALSE
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_BITFIELD,                     CONF_VALUE_32_BIT(1),
+    &li.can_move_into_acid_bits,       ~0      /* default: everything can */
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_BITFIELD,                     CONF_VALUE_8_BIT(7),
+    &li.dont_collide_with_bits,                ~0      /* default: always deadly */
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(8),
+    &li.em_explodes_by_fire,           FALSE
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(5),
+    &li.score[SC_TIME_BONUS],          1
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(9),
+    &li.auto_exit_sokoban,             FALSE
+  },
+
+  {
+    -1,                                        -1,
+    -1,                                        -1,
+    NULL,                              -1
+  }
+};
+
+static struct LevelFileConfigInfo chunk_config_ELEM[] =
+{
+  /* (these values are the same for each player) */
+  {
+    EL_PLAYER_1,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(1),
     &li.block_last_field,              FALSE   /* default case for EM levels */
   },
   {
-    EL_PLAYER_1,
-    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(3),
+    EL_PLAYER_1,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(2),
     &li.sp_block_last_field,           TRUE    /* default case for SP levels */
   },
   {
-    EL_PLAYER_1,
-    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(4),
+    EL_PLAYER_1,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(3),
     &li.instant_relocation,            FALSE
   },
   {
-    EL_PLAYER_1,
-    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(5),
+    EL_PLAYER_1,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(4),
     &li.can_pass_to_walkable,          FALSE
   },
   {
-    EL_PLAYER_1,
+    EL_PLAYER_1,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(5),
+    &li.block_snap_field,              TRUE
+  },
+  {
+    EL_PLAYER_1,                       -1,
     TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(6),
-    &li.initial_player_gravity[0],     FALSE
+    &li.continuous_snapping,           TRUE
   },
   {
-    EL_PLAYER_1,
-    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(9),
-    &li.block_snap_field,              TRUE
+    EL_PLAYER_1,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(12),
+    &li.shifted_relocation,            FALSE
+  },
+
+  /* (these values are different for each player) */
+  {
+    EL_PLAYER_1,                       -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(7),
+    &li.initial_player_stepsize[0],    STEPSIZE_NORMAL
   },
   {
-    EL_PLAYER_1,
-    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(10),
+    EL_PLAYER_1,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(8),
+    &li.initial_player_gravity[0],     FALSE
+  },
+  {
+    EL_PLAYER_1,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(9),
     &li.use_start_element[0],          FALSE
   },
   {
-    EL_PLAYER_1,
+    EL_PLAYER_1,                       -1,
     TYPE_ELEMENT,                      CONF_VALUE_16_BIT(1),
     &li.start_element[0],              EL_PLAYER_1
   },
   {
-    EL_PLAYER_1,
-    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(11),
+    EL_PLAYER_1,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(10),
     &li.use_artwork_element[0],                FALSE
   },
   {
-    EL_PLAYER_1,
+    EL_PLAYER_1,                       -1,
     TYPE_ELEMENT,                      CONF_VALUE_16_BIT(2),
     &li.artwork_element[0],            EL_PLAYER_1
   },
   {
-    EL_PLAYER_1,
-    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(12),
+    EL_PLAYER_1,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(11),
     &li.use_explosion_element[0],      FALSE
   },
   {
-    EL_PLAYER_1,
+    EL_PLAYER_1,                       -1,
     TYPE_ELEMENT,                      CONF_VALUE_16_BIT(3),
     &li.explosion_element[0],          EL_PLAYER_1
   },
   {
-    EL_PLAYER_1,
+    EL_PLAYER_1,                       -1,
     TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(13),
-    &li.continuous_snapping,           TRUE
+    &li.use_initial_inventory[0],      FALSE
+  },
+  {
+    EL_PLAYER_1,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(14),
+    &li.initial_inventory_size[0],     1
+  },
+  {
+    EL_PLAYER_1,                       -1,
+    TYPE_ELEMENT_LIST,                 CONF_VALUE_BYTES(1),
+    &li.initial_inventory_content[0][0],EL_EMPTY, NULL,
+    &li.initial_inventory_size[0],     1, MAX_INITIAL_INVENTORY_SIZE
   },
 
   {
-    EL_PLAYER_2,
-    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(6),
+    EL_PLAYER_2,                       -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(7),
+    &li.initial_player_stepsize[1],    STEPSIZE_NORMAL
+  },
+  {
+    EL_PLAYER_2,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(8),
     &li.initial_player_gravity[1],     FALSE
   },
   {
-    EL_PLAYER_2,
-    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(10),
+    EL_PLAYER_2,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(9),
     &li.use_start_element[1],          FALSE
   },
   {
-    EL_PLAYER_2,
+    EL_PLAYER_2,                       -1,
     TYPE_ELEMENT,                      CONF_VALUE_16_BIT(1),
     &li.start_element[1],              EL_PLAYER_2
   },
   {
-    EL_PLAYER_2,
-    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(11),
+    EL_PLAYER_2,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(10),
     &li.use_artwork_element[1],                FALSE
   },
   {
-    EL_PLAYER_2,
+    EL_PLAYER_2,                       -1,
     TYPE_ELEMENT,                      CONF_VALUE_16_BIT(2),
     &li.artwork_element[1],            EL_PLAYER_2
   },
   {
-    EL_PLAYER_2,
-    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(12),
+    EL_PLAYER_2,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(11),
     &li.use_explosion_element[1],      FALSE
   },
   {
-    EL_PLAYER_2,
+    EL_PLAYER_2,                       -1,
     TYPE_ELEMENT,                      CONF_VALUE_16_BIT(3),
     &li.explosion_element[1],          EL_PLAYER_2
   },
+  {
+    EL_PLAYER_2,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(13),
+    &li.use_initial_inventory[1],      FALSE
+  },
+  {
+    EL_PLAYER_2,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(14),
+    &li.initial_inventory_size[1],     1
+  },
+  {
+    EL_PLAYER_2,                       -1,
+    TYPE_ELEMENT_LIST,                 CONF_VALUE_BYTES(1),
+    &li.initial_inventory_content[1][0],EL_EMPTY, NULL,
+    &li.initial_inventory_size[1],     1, MAX_INITIAL_INVENTORY_SIZE
+  },
 
   {
-    EL_PLAYER_3,
-    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(6),
+    EL_PLAYER_3,                       -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(7),
+    &li.initial_player_stepsize[2],    STEPSIZE_NORMAL
+  },
+  {
+    EL_PLAYER_3,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(8),
     &li.initial_player_gravity[2],     FALSE
   },
   {
-    EL_PLAYER_3,
-    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(10),
+    EL_PLAYER_3,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(9),
     &li.use_start_element[2],          FALSE
   },
   {
-    EL_PLAYER_3,
+    EL_PLAYER_3,                       -1,
     TYPE_ELEMENT,                      CONF_VALUE_16_BIT(1),
     &li.start_element[2],              EL_PLAYER_3
   },
   {
-    EL_PLAYER_3,
-    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(11),
+    EL_PLAYER_3,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(10),
     &li.use_artwork_element[2],                FALSE
   },
   {
-    EL_PLAYER_3,
+    EL_PLAYER_3,                       -1,
     TYPE_ELEMENT,                      CONF_VALUE_16_BIT(2),
     &li.artwork_element[2],            EL_PLAYER_3
   },
   {
-    EL_PLAYER_3,
-    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(12),
+    EL_PLAYER_3,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(11),
     &li.use_explosion_element[2],      FALSE
   },
   {
-    EL_PLAYER_3,
+    EL_PLAYER_3,                       -1,
     TYPE_ELEMENT,                      CONF_VALUE_16_BIT(3),
     &li.explosion_element[2],          EL_PLAYER_3
   },
+  {
+    EL_PLAYER_3,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(13),
+    &li.use_initial_inventory[2],      FALSE
+  },
+  {
+    EL_PLAYER_3,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(14),
+    &li.initial_inventory_size[2],     1
+  },
+  {
+    EL_PLAYER_3,                       -1,
+    TYPE_ELEMENT_LIST,                 CONF_VALUE_BYTES(1),
+    &li.initial_inventory_content[2][0],EL_EMPTY, NULL,
+    &li.initial_inventory_size[2],     1, MAX_INITIAL_INVENTORY_SIZE
+  },
 
   {
-    EL_PLAYER_4,
-    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(6),
+    EL_PLAYER_4,                       -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(7),
+    &li.initial_player_stepsize[3],    STEPSIZE_NORMAL
+  },
+  {
+    EL_PLAYER_4,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(8),
     &li.initial_player_gravity[3],     FALSE
   },
   {
-    EL_PLAYER_4,
-    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(10),
+    EL_PLAYER_4,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(9),
     &li.use_start_element[3],          FALSE
   },
   {
-    EL_PLAYER_4,
+    EL_PLAYER_4,                       -1,
     TYPE_ELEMENT,                      CONF_VALUE_16_BIT(1),
     &li.start_element[3],              EL_PLAYER_4
   },
   {
-    EL_PLAYER_4,
-    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(11),
+    EL_PLAYER_4,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(10),
     &li.use_artwork_element[3],                FALSE
   },
   {
-    EL_PLAYER_4,
+    EL_PLAYER_4,                       -1,
     TYPE_ELEMENT,                      CONF_VALUE_16_BIT(2),
     &li.artwork_element[3],            EL_PLAYER_4
   },
   {
-    EL_PLAYER_4,
-    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(12),
+    EL_PLAYER_4,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(11),
     &li.use_explosion_element[3],      FALSE
   },
   {
-    EL_PLAYER_4,
+    EL_PLAYER_4,                       -1,
     TYPE_ELEMENT,                      CONF_VALUE_16_BIT(3),
     &li.explosion_element[3],          EL_PLAYER_4
   },
+  {
+    EL_PLAYER_4,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(13),
+    &li.use_initial_inventory[3],      FALSE
+  },
+  {
+    EL_PLAYER_4,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(14),
+    &li.initial_inventory_size[3],     1
+  },
+  {
+    EL_PLAYER_4,                       -1,
+    TYPE_ELEMENT_LIST,                 CONF_VALUE_BYTES(1),
+    &li.initial_inventory_content[3][0],EL_EMPTY, NULL,
+    &li.initial_inventory_size[3],     1, MAX_INITIAL_INVENTORY_SIZE
+  },
 
   {
-    EL_EMERALD,
+    EL_EMERALD,                                -1,
     TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
     &li.score[SC_EMERALD],             10
   },
 
   {
-    EL_DIAMOND,
+    EL_DIAMOND,                                -1,
     TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
     &li.score[SC_DIAMOND],             10
   },
 
   {
-    EL_BUG,
+    EL_BUG,                            -1,
     TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
     &li.score[SC_BUG],                 10
   },
 
   {
-    EL_SPACESHIP,
+    EL_SPACESHIP,                      -1,
     TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
     &li.score[SC_SPACESHIP],           10
   },
 
   {
-    EL_PACMAN,
+    EL_PACMAN,                         -1,
     TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
     &li.score[SC_PACMAN],              10
   },
 
   {
-    EL_NUT,
+    EL_NUT,                            -1,
     TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
     &li.score[SC_NUT],                 10
   },
 
   {
-    EL_DYNAMITE,
+    EL_DYNAMITE,                       -1,
     TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
     &li.score[SC_DYNAMITE],            10
   },
 
   {
-    EL_KEY_1,
+    EL_KEY_1,                          -1,
     TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
     &li.score[SC_KEY],                 10
   },
 
   {
-    EL_PEARL,
+    EL_PEARL,                          -1,
     TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
     &li.score[SC_PEARL],               10
   },
 
   {
-    EL_CRYSTAL,
+    EL_CRYSTAL,                                -1,
     TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
     &li.score[SC_CRYSTAL],             10
   },
 
   {
-    EL_BD_AMOEBA,
+    EL_BD_AMOEBA,                      -1,
     TYPE_ELEMENT,                      CONF_VALUE_16_BIT(1),
     &li.amoeba_content,                        EL_DIAMOND
   },
   {
-    EL_BD_AMOEBA,
+    EL_BD_AMOEBA,                      -1,
     TYPE_INTEGER,                      CONF_VALUE_16_BIT(2),
     &li.amoeba_speed,                  10
   },
   {
-    EL_BD_AMOEBA,
+    EL_BD_AMOEBA,                      -1,
     TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(1),
     &li.grow_into_diggable,            TRUE
   },
 
   {
-    EL_YAMYAM,
+    EL_YAMYAM,                         -1,
     TYPE_CONTENT_LIST,                 CONF_VALUE_BYTES(1),
     &li.yamyam_content,                        EL_ROCK, NULL,
     &li.num_yamyam_contents,           4, MAX_ELEMENT_CONTENTS
   },
   {
-    EL_YAMYAM,
+    EL_YAMYAM,                         -1,
     TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
     &li.score[SC_YAMYAM],              10
   },
 
   {
-    EL_ROBOT,
+    EL_ROBOT,                          -1,
     TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
     &li.score[SC_ROBOT],               10
   },
   {
-    EL_ROBOT,
+    EL_ROBOT,                          -1,
     TYPE_INTEGER,                      CONF_VALUE_16_BIT(2),
     &li.slurp_score,                   10
   },
 
   {
-    EL_ROBOT_WHEEL,
+    EL_ROBOT_WHEEL,                    -1,
     TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
     &li.time_wheel,                    10
   },
 
   {
-    EL_MAGIC_WALL,
+    EL_MAGIC_WALL,                     -1,
     TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
     &li.time_magic_wall,               10
   },
 
   {
-    EL_GAME_OF_LIFE,
+    EL_GAME_OF_LIFE,                   -1,
     TYPE_INTEGER,                      CONF_VALUE_8_BIT(1),
     &li.game_of_life[0],               2
   },
   {
-    EL_GAME_OF_LIFE,
+    EL_GAME_OF_LIFE,                   -1,
     TYPE_INTEGER,                      CONF_VALUE_8_BIT(2),
     &li.game_of_life[1],               3
   },
   {
-    EL_GAME_OF_LIFE,
+    EL_GAME_OF_LIFE,                   -1,
     TYPE_INTEGER,                      CONF_VALUE_8_BIT(3),
     &li.game_of_life[2],               3
   },
   {
-    EL_GAME_OF_LIFE,
+    EL_GAME_OF_LIFE,                   -1,
     TYPE_INTEGER,                      CONF_VALUE_8_BIT(4),
     &li.game_of_life[3],               3
   },
 
   {
-    EL_BIOMAZE,
+    EL_BIOMAZE,                                -1,
     TYPE_INTEGER,                      CONF_VALUE_8_BIT(1),
     &li.biomaze[0],                    2
   },
   {
-    EL_BIOMAZE,
+    EL_BIOMAZE,                                -1,
     TYPE_INTEGER,                      CONF_VALUE_8_BIT(2),
     &li.biomaze[1],                    3
   },
   {
-    EL_BIOMAZE,
+    EL_BIOMAZE,                                -1,
     TYPE_INTEGER,                      CONF_VALUE_8_BIT(3),
     &li.biomaze[2],                    3
   },
   {
-    EL_BIOMAZE,
+    EL_BIOMAZE,                                -1,
     TYPE_INTEGER,                      CONF_VALUE_8_BIT(4),
     &li.biomaze[3],                    3
   },
 
   {
-    EL_TIMEGATE_SWITCH,
+    EL_TIMEGATE_SWITCH,                        -1,
     TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
     &li.time_timegate,                 10
   },
 
   {
-    EL_LIGHT_SWITCH_ACTIVE,
+    EL_LIGHT_SWITCH_ACTIVE,            -1,
     TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
     &li.time_light,                    10
   },
 
   {
-    EL_SHIELD_NORMAL,
+    EL_SHIELD_NORMAL,                  -1,
     TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
     &li.shield_normal_time,            10
   },
   {
-    EL_SHIELD_NORMAL,
+    EL_SHIELD_NORMAL,                  -1,
     TYPE_INTEGER,                      CONF_VALUE_16_BIT(2),
     &li.score[SC_SHIELD],              10
   },
 
   {
-    EL_SHIELD_DEADLY,
+    EL_SHIELD_DEADLY,                  -1,
     TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
     &li.shield_deadly_time,            10
   },
   {
-    EL_SHIELD_DEADLY,
+    EL_SHIELD_DEADLY,                  -1,
     TYPE_INTEGER,                      CONF_VALUE_16_BIT(2),
     &li.score[SC_SHIELD],              10
   },
 
   {
-    EL_EXTRA_TIME,
+    EL_EXTRA_TIME,                     -1,
     TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
     &li.extra_time,                    10
   },
   {
-    EL_EXTRA_TIME,
+    EL_EXTRA_TIME,                     -1,
     TYPE_INTEGER,                      CONF_VALUE_16_BIT(2),
     &li.extra_time_score,              10
   },
 
   {
-    EL_TIME_ORB_FULL,
+    EL_TIME_ORB_FULL,                  -1,
     TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
     &li.time_orb_time,                 10
   },
   {
-    EL_TIME_ORB_FULL,
+    EL_TIME_ORB_FULL,                  -1,
     TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(1),
     &li.use_time_orb_bug,              FALSE
   },
 
   {
-    EL_SPRING,
+    EL_SPRING,                         -1,
     TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(1),
     &li.use_spring_bug,                        FALSE
   },
 
   {
-    EL_EMC_ANDROID,
+    EL_EMC_ANDROID,                    -1,
     TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
     &li.android_move_time,             10
   },
   {
-    EL_EMC_ANDROID,
+    EL_EMC_ANDROID,                    -1,
     TYPE_INTEGER,                      CONF_VALUE_16_BIT(2),
     &li.android_clone_time,            10
   },
   {
-    EL_EMC_ANDROID,
+    EL_EMC_ANDROID,                    -1,
     TYPE_ELEMENT_LIST,                 CONF_VALUE_BYTES(1),
     &li.android_clone_element[0],      EL_EMPTY, NULL,
     &li.num_android_clone_elements,    1, MAX_ANDROID_ELEMENTS
   },
 
   {
-    EL_EMC_LENSES,
+    EL_EMC_LENSES,                     -1,
     TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
     &li.lenses_score,                  10
   },
   {
-    EL_EMC_LENSES,
+    EL_EMC_LENSES,                     -1,
     TYPE_INTEGER,                      CONF_VALUE_16_BIT(2),
     &li.lenses_time,                   10
   },
 
   {
-    EL_EMC_MAGNIFIER,
+    EL_EMC_MAGNIFIER,                  -1,
     TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
     &li.magnify_score,                 10
   },
   {
-    EL_EMC_MAGNIFIER,
+    EL_EMC_MAGNIFIER,                  -1,
     TYPE_INTEGER,                      CONF_VALUE_16_BIT(2),
     &li.magnify_time,                  10
   },
 
   {
-    EL_EMC_MAGIC_BALL,
+    EL_EMC_MAGIC_BALL,                 -1,
     TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
     &li.ball_time,                     10
   },
   {
-    EL_EMC_MAGIC_BALL,
+    EL_EMC_MAGIC_BALL,                 -1,
     TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(1),
     &li.ball_random,                   FALSE
   },
   {
-    EL_EMC_MAGIC_BALL,
+    EL_EMC_MAGIC_BALL,                 -1,
     TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(2),
     &li.ball_state_initial,            FALSE
   },
   {
-    EL_EMC_MAGIC_BALL,
+    EL_EMC_MAGIC_BALL,                 -1,
     TYPE_CONTENT_LIST,                 CONF_VALUE_BYTES(1),
     &li.ball_content,                  EL_EMPTY, NULL,
     &li.num_ball_contents,             4, MAX_ELEMENT_CONTENTS
@@ -644,132 +796,83 @@ static struct LevelFileConfigInfo chunk_config_CONF[] =
   /* ---------- unused values ----------------------------------------------- */
 
   {
-    EL_UNKNOWN,
+    EL_UNKNOWN,                                SAVE_CONF_NEVER,
     TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
     &li.score[SC_UNKNOWN_14],          10
   },
   {
-    EL_UNKNOWN,
+    EL_UNKNOWN,                                SAVE_CONF_NEVER,
     TYPE_INTEGER,                      CONF_VALUE_16_BIT(2),
     &li.score[SC_UNKNOWN_15],          10
   },
 
   {
-    -1,
     -1,                                        -1,
-    NULL,                              -1,
-  },
+    -1,                                        -1,
+    NULL,                              -1
+  }
 };
 
-static struct LevelFileConfigInfo chunk_config_INFO[] =
+static struct LevelFileConfigInfo chunk_config_NOTE[] =
 {
-  /* ---------- values not related to single elements ----------------------- */
-
   {
-    -1,
+    -1,                                        -1,
     TYPE_INTEGER,                      CONF_VALUE_8_BIT(1),
-    &li.game_engine_type,              GAME_ENGINE_TYPE_RND
-  },
-
-  {
-    -1,
-    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
-    &li.fieldx,                                STD_LEV_FIELDX
+    &xx_envelope.xsize,                        MAX_ENVELOPE_XSIZE,
   },
   {
-    -1,
-    TYPE_INTEGER,                      CONF_VALUE_16_BIT(2),
-    &li.fieldy,                                STD_LEV_FIELDY
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(2),
+    &xx_envelope.ysize,                        MAX_ENVELOPE_YSIZE,
   },
 
   {
-    -1,
-    TYPE_INTEGER,                      CONF_VALUE_16_BIT(3),
-    &li.time,                          100
+    -1,                                        -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(3),
+    &xx_envelope.autowrap,             FALSE
   },
-
   {
-    -1,
-    TYPE_INTEGER,                      CONF_VALUE_16_BIT(4),
-    &li.gems_needed,                   0
+    -1,                                        -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(4),
+    &xx_envelope.centered,             FALSE
   },
 
   {
-    -1,
-    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(2),
-    &li.use_step_counter,              FALSE
+    -1,                                        -1,
+    TYPE_STRING,                       CONF_VALUE_BYTES(1),
+    &xx_envelope.text,                 -1, NULL,
+    &xx_string_length_unused,          -1, MAX_ENVELOPE_TEXT_LEN,
+    &xx_default_string_empty[0]
   },
 
   {
-    -1,
-    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(3),
-    &li.initial_gravity,               FALSE
-  },
+    -1,                                        -1,
+    -1,                                        -1,
+    NULL,                              -1
+  }
+};
 
+static struct LevelFileConfigInfo chunk_config_CUSX_base[] =
+{
   {
-    -1,
-    TYPE_BITFIELD,                     CONF_VALUE_8_BIT(4),
-    &li.wind_direction_initial,                MV_NONE
+    -1,                                        -1,
+    TYPE_STRING,                       CONF_VALUE_BYTES(1),
+    &xx_ei.description[0],             -1,
+    &yy_ei.description[0],
+    &xx_string_length_unused,          -1, MAX_ELEMENT_NAME_LEN,
+    &xx_default_description[0]
   },
 
   {
-    -1,
-    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(5),
-    &li.em_slippery_gems,              FALSE
-  },
-
-  {
-    -1,
-    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(6),
-    &li.use_custom_template,           FALSE
-  },
-
-  {
-    -1,
-    TYPE_BITFIELD,                     CONF_VALUE_32_BIT(1),
-    &li.can_move_into_acid_bits,       ~0      /* default: everything can */
-  },
-
-  {
-    -1,
-    TYPE_BITFIELD,                     CONF_VALUE_8_BIT(7),
-    &li.dont_collide_with_bits,                ~0      /* default: always deadly */
-  },
-
-  {
-    -1,
-    TYPE_INTEGER,                      CONF_VALUE_16_BIT(5),
-    &li.score[SC_TIME_BONUS],          1
-  },
-
-  {
-    -1,
-    -1,                                        -1,
-    NULL,                              -1,
-  },
-};
-
-static struct LevelFileConfigInfo chunk_config_CUSX_base[] =
-{
-  {
-    -1,
-    TYPE_STRING,                       CONF_VALUE_BYTES(1),
-    &xx_ei.description[0],             -1,
-    &yy_ei.description[0],
-    &xx_default_description_length,    -1, MAX_ELEMENT_NAME_LEN,
-    &xx_default_description[0]
-  },
-
-  {
-    -1,
-    TYPE_BITFIELD,                     CONF_VALUE_32_BIT(1),
-    &xx_ei.properties[EP_BITFIELD_BASE_NR], EP_BITMASK_BASE_DEFAULT,
-    &yy_ei.properties[EP_BITFIELD_BASE_NR]
+    -1,                                        -1,
+    TYPE_BITFIELD,                     CONF_VALUE_32_BIT(1),
+    &xx_ei.properties[EP_BITFIELD_BASE_NR], EP_BITMASK_BASE_DEFAULT,
+    &yy_ei.properties[EP_BITFIELD_BASE_NR]
   },
 #if 0
   /* (reserved) */
   {
-    -1,
+    -1,                                        -1,
     TYPE_BITFIELD,                     CONF_VALUE_32_BIT(2),
     &xx_ei.properties[EP_BITFIELD_BASE_NR + 1], EP_BITMASK_DEFAULT,
     &yy_ei.properties[EP_BITFIELD_BASE_NR + 1]
@@ -777,160 +880,160 @@ static struct LevelFileConfigInfo chunk_config_CUSX_base[] =
 #endif
 
   {
-    -1,
+    -1,                                        -1,
     TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(1),
     &xx_ei.use_gfx_element,            FALSE,
     &yy_ei.use_gfx_element
   },
   {
-    -1,
+    -1,                                        -1,
     TYPE_ELEMENT,                      CONF_VALUE_16_BIT(1),
-    &xx_ei.gfx_element,                        EL_EMPTY_SPACE,
-    &yy_ei.gfx_element
+    &xx_ei.gfx_element_initial,                EL_EMPTY_SPACE,
+    &yy_ei.gfx_element_initial
   },
 
   {
-    -1,
+    -1,                                        -1,
     TYPE_BITFIELD,                     CONF_VALUE_8_BIT(2),
     &xx_ei.access_direction,           MV_ALL_DIRECTIONS,
     &yy_ei.access_direction
   },
 
   {
-    -1,
+    -1,                                        -1,
     TYPE_INTEGER,                      CONF_VALUE_16_BIT(2),
     &xx_ei.collect_score_initial,      10,
     &yy_ei.collect_score_initial
   },
   {
-    -1,
+    -1,                                        -1,
     TYPE_INTEGER,                      CONF_VALUE_16_BIT(3),
     &xx_ei.collect_count_initial,      1,
     &yy_ei.collect_count_initial
   },
 
   {
-    -1,
+    -1,                                        -1,
     TYPE_INTEGER,                      CONF_VALUE_16_BIT(4),
     &xx_ei.ce_value_fixed_initial,     0,
     &yy_ei.ce_value_fixed_initial
   },
   {
-    -1,
+    -1,                                        -1,
     TYPE_INTEGER,                      CONF_VALUE_16_BIT(5),
     &xx_ei.ce_value_random_initial,    0,
     &yy_ei.ce_value_random_initial
   },
   {
-    -1,
+    -1,                                        -1,
     TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(3),
     &xx_ei.use_last_ce_value,          FALSE,
     &yy_ei.use_last_ce_value
   },
 
   {
-    -1,
+    -1,                                        -1,
     TYPE_INTEGER,                      CONF_VALUE_16_BIT(6),
     &xx_ei.push_delay_fixed,           8,
     &yy_ei.push_delay_fixed
   },
   {
-    -1,
+    -1,                                        -1,
     TYPE_INTEGER,                      CONF_VALUE_16_BIT(7),
     &xx_ei.push_delay_random,          8,
     &yy_ei.push_delay_random
   },
   {
-    -1,
+    -1,                                        -1,
     TYPE_INTEGER,                      CONF_VALUE_16_BIT(8),
     &xx_ei.drop_delay_fixed,           0,
     &yy_ei.drop_delay_fixed
   },
   {
-    -1,
+    -1,                                        -1,
     TYPE_INTEGER,                      CONF_VALUE_16_BIT(9),
     &xx_ei.drop_delay_random,          0,
     &yy_ei.drop_delay_random
   },
   {
-    -1,
+    -1,                                        -1,
     TYPE_INTEGER,                      CONF_VALUE_16_BIT(10),
     &xx_ei.move_delay_fixed,           0,
     &yy_ei.move_delay_fixed
   },
   {
-    -1,
+    -1,                                        -1,
     TYPE_INTEGER,                      CONF_VALUE_16_BIT(11),
     &xx_ei.move_delay_random,          0,
     &yy_ei.move_delay_random
   },
 
   {
-    -1,
+    -1,                                        -1,
     TYPE_BITFIELD,                     CONF_VALUE_32_BIT(3),
     &xx_ei.move_pattern,               MV_ALL_DIRECTIONS,
     &yy_ei.move_pattern
   },
   {
-    -1,
+    -1,                                        -1,
     TYPE_BITFIELD,                     CONF_VALUE_8_BIT(4),
     &xx_ei.move_direction_initial,     MV_START_AUTOMATIC,
     &yy_ei.move_direction_initial
   },
   {
-    -1,
+    -1,                                        -1,
     TYPE_INTEGER,                      CONF_VALUE_8_BIT(5),
     &xx_ei.move_stepsize,              TILEX / 8,
     &yy_ei.move_stepsize
   },
 
   {
-    -1,
+    -1,                                        -1,
     TYPE_ELEMENT,                      CONF_VALUE_16_BIT(12),
     &xx_ei.move_enter_element,         EL_EMPTY_SPACE,
     &yy_ei.move_enter_element
   },
   {
-    -1,
+    -1,                                        -1,
     TYPE_ELEMENT,                      CONF_VALUE_16_BIT(13),
     &xx_ei.move_leave_element,         EL_EMPTY_SPACE,
     &yy_ei.move_leave_element
   },
   {
-    -1,
+    -1,                                        -1,
     TYPE_INTEGER,                      CONF_VALUE_8_BIT(6),
     &xx_ei.move_leave_type,            LEAVE_TYPE_UNLIMITED,
     &yy_ei.move_leave_type
   },
 
   {
-    -1,
+    -1,                                        -1,
     TYPE_INTEGER,                      CONF_VALUE_8_BIT(7),
     &xx_ei.slippery_type,              SLIPPERY_ANY_RANDOM,
     &yy_ei.slippery_type
   },
 
   {
-    -1,
+    -1,                                        -1,
     TYPE_INTEGER,                      CONF_VALUE_8_BIT(8),
     &xx_ei.explosion_type,             EXPLODES_3X3,
     &yy_ei.explosion_type
   },
   {
-    -1,
+    -1,                                        -1,
     TYPE_INTEGER,                      CONF_VALUE_16_BIT(14),
     &xx_ei.explosion_delay,            16,
     &yy_ei.explosion_delay
   },
   {
-    -1,
+    -1,                                        -1,
     TYPE_INTEGER,                      CONF_VALUE_16_BIT(15),
     &xx_ei.ignition_delay,             8,
     &yy_ei.ignition_delay
   },
 
   {
-    -1,
+    -1,                                        -1,
     TYPE_CONTENT_LIST,                 CONF_VALUE_BYTES(2),
     &xx_ei.content,                    EL_EMPTY_SPACE,
     &yy_ei.content,
@@ -940,18 +1043,18 @@ static struct LevelFileConfigInfo chunk_config_CUSX_base[] =
   /* ---------- "num_change_pages" must be the last entry ------------------- */
 
   {
-    -1,
+    -1,                                        SAVE_CONF_ALWAYS,
     TYPE_INTEGER,                      CONF_VALUE_8_BIT(9),
-    &xx_ei.num_change_pages,           -1,     /* value must always be saved */
+    &xx_ei.num_change_pages,           1,
     &yy_ei.num_change_pages
   },
 
   {
-    -1,
+    -1,                                        -1,
     -1,                                        -1,
     NULL,                              -1,
     NULL
-  },
+  }
 };
 
 static struct LevelFileConfigInfo chunk_config_CUSX_change[] =
@@ -959,179 +1062,240 @@ static struct LevelFileConfigInfo chunk_config_CUSX_change[] =
   /* ---------- "current_change_page" must be the first entry --------------- */
 
   {
-    -1,
+    -1,                                        SAVE_CONF_ALWAYS,
     TYPE_INTEGER,                      CONF_VALUE_8_BIT(1),
-    &xx_current_change_page,           -1      /* value must always be saved */
+    &xx_current_change_page,           -1
   },
 
   /* ---------- (the remaining entries can be in any order) ----------------- */
 
   {
-    -1,
+    -1,                                        -1,
     TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(2),
     &xx_change.can_change,             FALSE
   },
 
   {
-    -1,
+    -1,                                        -1,
     TYPE_BITFIELD,                     CONF_VALUE_32_BIT(1),
     &xx_event_bits[0],                 0
   },
   {
-    -1,
+    -1,                                        -1,
     TYPE_BITFIELD,                     CONF_VALUE_32_BIT(2),
     &xx_event_bits[1],                 0
   },
 
   {
-    -1,
+    -1,                                        -1,
     TYPE_BITFIELD,                     CONF_VALUE_8_BIT(3),
     &xx_change.trigger_player,         CH_PLAYER_ANY
   },
   {
-    -1,
+    -1,                                        -1,
     TYPE_BITFIELD,                     CONF_VALUE_8_BIT(4),
     &xx_change.trigger_side,           CH_SIDE_ANY
   },
   {
-    -1,
+    -1,                                        -1,
     TYPE_BITFIELD,                     CONF_VALUE_32_BIT(3),
     &xx_change.trigger_page,           CH_PAGE_ANY
   },
 
   {
-    -1,
+    -1,                                        -1,
     TYPE_ELEMENT,                      CONF_VALUE_16_BIT(1),
     &xx_change.target_element,         EL_EMPTY_SPACE
   },
 
   {
-    -1,
+    -1,                                        -1,
     TYPE_INTEGER,                      CONF_VALUE_16_BIT(2),
     &xx_change.delay_fixed,            0
   },
   {
-    -1,
+    -1,                                        -1,
     TYPE_INTEGER,                      CONF_VALUE_16_BIT(3),
     &xx_change.delay_random,           0
   },
   {
-    -1,
+    -1,                                        -1,
     TYPE_INTEGER,                      CONF_VALUE_16_BIT(4),
     &xx_change.delay_frames,           FRAMES_PER_SECOND
   },
 
   {
-    -1,
+    -1,                                        -1,
     TYPE_ELEMENT,                      CONF_VALUE_16_BIT(5),
-    &xx_change.trigger_element,                EL_EMPTY_SPACE
+    &xx_change.initial_trigger_element,        EL_EMPTY_SPACE
   },
 
   {
-    -1,
+    -1,                                        -1,
     TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(6),
     &xx_change.explode,                        FALSE
   },
   {
-    -1,
+    -1,                                        -1,
     TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(7),
     &xx_change.use_target_content,     FALSE
   },
   {
-    -1,
+    -1,                                        -1,
     TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(8),
     &xx_change.only_if_complete,       FALSE
   },
   {
-    -1,
+    -1,                                        -1,
     TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(9),
     &xx_change.use_random_replace,     FALSE
   },
   {
-    -1,
+    -1,                                        -1,
     TYPE_INTEGER,                      CONF_VALUE_8_BIT(10),
     &xx_change.random_percentage,      100
   },
   {
-    -1,
+    -1,                                        -1,
     TYPE_INTEGER,                      CONF_VALUE_8_BIT(11),
     &xx_change.replace_when,           CP_WHEN_EMPTY
   },
 
   {
-    -1,
+    -1,                                        -1,
     TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(12),
     &xx_change.has_action,             FALSE
   },
   {
-    -1,
+    -1,                                        -1,
     TYPE_INTEGER,                      CONF_VALUE_8_BIT(13),
     &xx_change.action_type,            CA_NO_ACTION
   },
   {
-    -1,
+    -1,                                        -1,
     TYPE_INTEGER,                      CONF_VALUE_8_BIT(14),
     &xx_change.action_mode,            CA_MODE_UNDEFINED
   },
   {
-    -1,
+    -1,                                        -1,
     TYPE_INTEGER,                      CONF_VALUE_16_BIT(6),
     &xx_change.action_arg,             CA_ARG_UNDEFINED
   },
 
   {
-    -1,
+    -1,                                        -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(7),
+    &xx_change.action_element,         EL_EMPTY_SPACE
+  },
+
+  {
+    -1,                                        -1,
     TYPE_CONTENT_LIST,                 CONF_VALUE_BYTES(1),
     &xx_change.target_content,         EL_EMPTY_SPACE, NULL,
     &xx_num_contents,                  1, 1
   },
 
   {
-    -1,
     -1,                                        -1,
-    NULL,                              -1,
-  },
+    -1,                                        -1,
+    NULL,                              -1
+  }
 };
 
 static struct LevelFileConfigInfo chunk_config_GRPX[] =
 {
   {
-    -1,
+    -1,                                        -1,
     TYPE_STRING,                       CONF_VALUE_BYTES(1),
     &xx_ei.description[0],             -1, NULL,
-    &xx_default_description_length,    -1, MAX_ELEMENT_NAME_LEN,
+    &xx_string_length_unused,          -1, MAX_ELEMENT_NAME_LEN,
     &xx_default_description[0]
   },
 
   {
-    -1,
+    -1,                                        -1,
     TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(1),
     &xx_ei.use_gfx_element,            FALSE
   },
   {
-    -1,
+    -1,                                        -1,
     TYPE_ELEMENT,                      CONF_VALUE_16_BIT(1),
-    &xx_ei.gfx_element,                        EL_EMPTY_SPACE
+    &xx_ei.gfx_element_initial,                EL_EMPTY_SPACE
   },
 
   {
-    -1,
+    -1,                                        -1,
     TYPE_INTEGER,                      CONF_VALUE_8_BIT(2),
     &xx_group.choice_mode,             ANIM_RANDOM
   },
 
   {
-    -1,
+    -1,                                        -1,
     TYPE_ELEMENT_LIST,                 CONF_VALUE_BYTES(2),
     &xx_group.element[0],              EL_EMPTY_SPACE, NULL,
     &xx_group.num_elements,            1, MAX_ELEMENTS_IN_GROUP
   },
 
   {
-    -1,
     -1,                                        -1,
-    NULL,                              -1,
+    -1,                                        -1,
+    NULL,                              -1
+  }
+};
+
+static struct LevelFileConfigInfo chunk_config_CONF[] =                /* (OBSOLETE) */
+{
+  {
+    EL_PLAYER_1,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(9),
+    &li.block_snap_field,              TRUE
+  },
+  {
+    EL_PLAYER_1,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(13),
+    &li.continuous_snapping,           TRUE
+  },
+  {
+    EL_PLAYER_1,                       -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(1),
+    &li.initial_player_stepsize[0],    STEPSIZE_NORMAL
+  },
+  {
+    EL_PLAYER_1,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(10),
+    &li.use_start_element[0],          FALSE
+  },
+  {
+    EL_PLAYER_1,                       -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(1),
+    &li.start_element[0],              EL_PLAYER_1
+  },
+  {
+    EL_PLAYER_1,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(11),
+    &li.use_artwork_element[0],                FALSE
+  },
+  {
+    EL_PLAYER_1,                       -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(2),
+    &li.artwork_element[0],            EL_PLAYER_1
+  },
+  {
+    EL_PLAYER_1,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(12),
+    &li.use_explosion_element[0],      FALSE
+  },
+  {
+    EL_PLAYER_1,                       -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(3),
+    &li.explosion_element[0],          EL_PLAYER_1
   },
+
+  {
+    -1,                                        -1,
+    -1,                                        -1,
+    NULL,                              -1
+  }
 };
 
 static struct
@@ -1156,6 +1320,37 @@ filetype_id_list[] =
 /* level file functions                                                      */
 /* ========================================================================= */
 
+static boolean check_special_flags(char *flag)
+{
+#if 0
+  printf("::: '%s', '%s', '%s'\n",
+        flag,
+        options.special_flags,
+        leveldir_current->special_flags);
+#endif
+
+  if (strEqual(options.special_flags, flag) ||
+      strEqual(leveldir_current->special_flags, flag))
+    return TRUE;
+
+  return FALSE;
+}
+
+static struct DateInfo getCurrentDate()
+{
+  time_t epoch_seconds = time(NULL);
+  struct tm *now = localtime(&epoch_seconds);
+  struct DateInfo date;
+
+  date.year  = now->tm_year + 1900;
+  date.month = now->tm_mon  + 1;
+  date.day   = now->tm_mday;
+
+  date.src   = DATE_SRC_CLOCK;
+
+  return date;
+}
+
 static void resetEventFlags(struct ElementChangeInfo *change)
 {
   int i;
@@ -1176,7 +1371,11 @@ static void setEventFlagsFromEventBits(struct ElementChangeInfo *change)
 {
   int i;
 
-  /* important: only change event flag if corresponding event bit is set */
+  /* important: only change event flag if corresponding event bit is set
+     (this is because all xx_event_bits[] values are loaded separately,
+     and all xx_event_bits[] values are set back to zero before loading
+     another value xx_event_bits[x] (each value representing 32 flags)) */
+
   for (i = 0; i < NUM_CHANGE_EVENTS; i++)
     if (xx_event_bits[CH_EVENT_BITFIELD_NR(i)] & CH_EVENT_BIT(i))
       change->has_event[i] = TRUE;
@@ -1186,7 +1385,11 @@ static void setEventBitsFromEventFlags(struct ElementChangeInfo *change)
 {
   int i;
 
-  /* important: only change event bit if corresponding event flag is set */
+  /* in contrast to the above function setEventFlagsFromEventBits(), it
+     would also be possible to set all bits in xx_event_bits[] to 0 or 1
+     depending on the corresponding change->has_event[i] values here, as
+     all xx_event_bits[] values are reset in resetEventBits() before */
+
   for (i = 0; i < NUM_CHANGE_EVENTS; i++)
     if (change->has_event[i])
       xx_event_bits[CH_EVENT_BITFIELD_NR(i)] |= CH_EVENT_BIT(i);
@@ -1325,16 +1528,10 @@ static void copyConfigFromConfigList(struct LevelFileConfigInfo *conf)
   }
 }
 
-#if 1
 void copyElementInfo(struct ElementInfo *ei_from, struct ElementInfo *ei_to)
 {
-#if 1
   int i;
-#else
-  int i, x, y;
-#endif
 
-#if 1
   xx_ei = *ei_from;    /* copy element data into temporary buffer */
   yy_ei = *ei_to;      /* copy element data into temporary buffer */
 
@@ -1342,56 +1539,6 @@ void copyElementInfo(struct ElementInfo *ei_from, struct ElementInfo *ei_to)
 
   *ei_from = xx_ei;
   *ei_to   = yy_ei;
-#endif
-
-#if 0
-  /* ---------- copy element description ---------- */
-  for (i = 0; i < MAX_ELEMENT_NAME_LEN + 1; i++)
-    ei_to->description[i] = ei_from->description[i];
-
-  /* ---------- copy element base properties ---------- */
-  ei_to->properties[EP_BITFIELD_BASE_NR] =
-    ei_from->properties[EP_BITFIELD_BASE_NR];
-
-  /* ---------- copy custom property values ---------- */
-
-  ei_to->use_gfx_element = ei_from->use_gfx_element;
-  ei_to->gfx_element = ei_from->gfx_element;
-
-  ei_to->access_direction = ei_from->access_direction;
-
-  ei_to->collect_score_initial = ei_from->collect_score_initial;
-  ei_to->collect_count_initial = ei_from->collect_count_initial;
-
-  ei_to->ce_value_fixed_initial = ei_from->ce_value_fixed_initial;
-  ei_to->ce_value_random_initial = ei_from->ce_value_random_initial;
-  ei_to->use_last_ce_value = ei_from->use_last_ce_value;
-
-  ei_to->push_delay_fixed = ei_from->push_delay_fixed;
-  ei_to->push_delay_random = ei_from->push_delay_random;
-  ei_to->drop_delay_fixed = ei_from->drop_delay_fixed;
-  ei_to->drop_delay_random = ei_from->drop_delay_random;
-  ei_to->move_delay_fixed = ei_from->move_delay_fixed;
-  ei_to->move_delay_random = ei_from->move_delay_random;
-
-  ei_to->move_pattern = ei_from->move_pattern;
-  ei_to->move_direction_initial = ei_from->move_direction_initial;
-  ei_to->move_stepsize = ei_from->move_stepsize;
-
-  ei_to->move_enter_element = ei_from->move_enter_element;
-  ei_to->move_leave_element = ei_from->move_leave_element;
-  ei_to->move_leave_type = ei_from->move_leave_type;
-
-  ei_to->slippery_type = ei_from->slippery_type;
-
-  ei_to->explosion_type = ei_from->explosion_type;
-  ei_to->explosion_delay = ei_from->explosion_delay;
-  ei_to->ignition_delay = ei_from->ignition_delay;
-
-  for (y = 0; y < 3; y++)
-    for (x = 0; x < 3; x++)
-      ei_to->content.e[x][y] = ei_from->content.e[x][y];
-#endif
 
   /* ---------- reinitialize and copy change pages ---------- */
 
@@ -1410,7 +1557,6 @@ void copyElementInfo(struct ElementInfo *ei_from, struct ElementInfo *ei_to)
   /* mark this custom element as modified */
   ei_to->modified_settings = TRUE;
 }
-#endif
 
 void setElementChangePages(struct ElementInfo *ei, int change_pages)
 {
@@ -1429,55 +1575,18 @@ void setElementChangePages(struct ElementInfo *ei, int change_pages)
 
 void setElementChangeInfoToDefaults(struct ElementChangeInfo *change)
 {
-#if 0
-  int i, x, y;
-#endif
-
-#if 1
   xx_change = *change;         /* copy change data into temporary buffer */
+
+#if 0
+  /* (not needed; set by setConfigToDefaultsFromConfigList()) */
   xx_num_contents = 1;
+#endif
 
   setConfigToDefaultsFromConfigList(chunk_config_CUSX_change);
 
   *change = xx_change;
 
   resetEventFlags(change);
-#endif
-
-#if 0
-  change->can_change = FALSE;
-
-  for (i = 0; i < NUM_CHANGE_EVENTS; i++)
-    change->has_event[i] = FALSE;
-
-  change->trigger_player = CH_PLAYER_ANY;
-  change->trigger_side = CH_SIDE_ANY;
-  change->trigger_page = CH_PAGE_ANY;
-
-  change->target_element = EL_EMPTY_SPACE;
-
-  change->delay_fixed = 0;
-  change->delay_random = 0;
-  change->delay_frames = FRAMES_PER_SECOND;
-
-  change->trigger_element = EL_EMPTY_SPACE;
-
-  change->explode = FALSE;
-  change->use_target_content = FALSE;
-  change->only_if_complete = FALSE;
-  change->use_random_replace = FALSE;
-  change->random_percentage = 100;
-  change->replace_when = CP_WHEN_EMPTY;
-
-  change->has_action = FALSE;
-  change->action_type = CA_NO_ACTION;
-  change->action_mode = CA_MODE_UNDEFINED;
-  change->action_arg = CA_ARG_UNDEFINED;
-
-  for (x = 0; x < 3; x++)
-    for (y = 0; y < 3; y++)
-      change->target_content.e[x][y] = EL_EMPTY_SPACE;
-#endif
 
   change->direct_action = 0;
   change->other_action = 0;
@@ -1490,172 +1599,66 @@ void setElementChangeInfoToDefaults(struct ElementChangeInfo *change)
 static void setLevelInfoToDefaults(struct LevelInfo *level)
 {
   static boolean clipboard_elements_initialized = FALSE;
-#if 0
-  int i, j, x, y;
-#else
   int i, x, y;
-#endif
 
-#if 1
   InitElementPropertiesStatic();
-#endif
 
-#if 1
   li = *level;         /* copy level data into temporary buffer */
 
   setConfigToDefaultsFromConfigList(chunk_config_INFO);
-  setConfigToDefaultsFromConfigList(chunk_config_CONF);
+  setConfigToDefaultsFromConfigList(chunk_config_ELEM);
 
   *level = li;         /* copy temporary buffer back to level data */
-#endif
 
   setLevelInfoToDefaults_EM();
+  setLevelInfoToDefaults_SP();
 
   level->native_em_level = &native_em_level;
-
-#if 0
-  level->game_engine_type = GAME_ENGINE_TYPE_RND;
-#endif
+  level->native_sp_level = &native_sp_level;
 
   level->file_version = FILE_VERSION_ACTUAL;
   level->game_version = GAME_VERSION_ACTUAL;
 
-  level->encoding_16bit_field  = FALSE;        /* default: only 8-bit elements */
-  level->encoding_16bit_yamyam = FALSE;        /* default: only 8-bit elements */
-  level->encoding_16bit_amoeba = FALSE;        /* default: only 8-bit elements */
+  level->creation_date = getCurrentDate();
 
-#if 0
-  level->fieldx = STD_LEV_FIELDX;
-  level->fieldy = STD_LEV_FIELDY;
-#endif
+  level->encoding_16bit_field  = TRUE;
+  level->encoding_16bit_yamyam = TRUE;
+  level->encoding_16bit_amoeba = TRUE;
 
   for (x = 0; x < MAX_LEV_FIELDX; x++)
     for (y = 0; y < MAX_LEV_FIELDY; y++)
       level->field[x][y] = EL_SAND;
 
-#if 0
-  level->time = 100;
-  level->gems_needed = 0;
+  for (i = 0; i < MAX_LEVEL_NAME_LEN; i++)
+    level->name[i] = '\0';
+  for (i = 0; i < MAX_LEVEL_AUTHOR_LEN; i++)
+    level->author[i] = '\0';
 
-  level->amoeba_speed = 10;
+  strcpy(level->name, NAMELESS_LEVEL_NAME);
+  strcpy(level->author, ANONYMOUS_NAME);
 
-  level->time_magic_wall = 10;
-  level->time_wheel = 10;
-#endif
-#if 0
-  level->time_light = 10;
-  level->time_timegate = 10;
-#endif
+  level->field[0][0] = EL_PLAYER_1;
+  level->field[STD_LEV_FIELDX - 1][STD_LEV_FIELDY - 1] = EL_EXIT_CLOSED;
 
-#if 0
-  level->amoeba_content = EL_DIAMOND;
-#endif
+  for (i = 0; i < MAX_NUM_ELEMENTS; i++)
+  {
+    int element = i;
+    struct ElementInfo *ei = &element_info[element];
 
-#if 0
-  level->game_of_life[0] = 2;
-  level->game_of_life[1] = 3;
-  level->game_of_life[2] = 3;
-  level->game_of_life[3] = 3;
-
-  level->biomaze[0] = 2;
-  level->biomaze[1] = 3;
-  level->biomaze[2] = 3;
-  level->biomaze[3] = 3;
-#endif
+    /* never initialize clipboard elements after the very first time */
+    /* (to be able to use clipboard elements between several levels) */
+    if (IS_CLIPBOARD_ELEMENT(element) && clipboard_elements_initialized)
+      continue;
 
-#if 0
-  level->double_speed = FALSE;
-#endif
-#if 0
-  level->initial_gravity = FALSE;
-  level->em_slippery_gems = FALSE;
-  level->instant_relocation = FALSE;
-  level->can_pass_to_walkable = FALSE;
-  level->grow_into_diggable = TRUE;
-#endif
-
-#if 0
-  level->block_snap_field = TRUE;
-#endif
-
-#if 0
-  level->block_last_field = FALSE;     /* EM does not block by default */
-  level->sp_block_last_field = TRUE;   /* SP blocks the last field */
-
-  level->can_move_into_acid_bits = ~0; /* everything can move into acid */
-  level->dont_collide_with_bits = ~0;  /* always deadly when colliding */
-
-  level->use_spring_bug = FALSE;
-  level->use_time_orb_bug = FALSE;
-
-  level->use_step_counter = FALSE;
-#endif
-
-  /* values for the new EMC elements */
-#if 0
-  level->android_move_time = 10;
-  level->android_clone_time = 10;
-  level->ball_time = 10;
-  level->lenses_score = 10;
-  level->lenses_time = 10;
-  level->magnify_score = 10;
-  level->magnify_time = 10;
-  level->slurp_score = 10;
-  level->wind_direction_initial = MV_NONE;
-  level->ball_random = FALSE;
-  level->ball_state_initial = FALSE;
-
-  for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
-    for (x = 0; x < 3; x++)
-      for (y = 0; y < 3; y++)
-       level->ball_content[i].e[x][y] = EL_EMPTY;
-
-  for (i = 0; i < 16; i++)
-    level->android_array[i] = FALSE;
-#endif
-
-#if 0
-  level->use_custom_template = FALSE;
-#endif
-
-  for (i = 0; i < MAX_LEVEL_NAME_LEN; i++)
-    level->name[i] = '\0';
-  for (i = 0; i < MAX_LEVEL_AUTHOR_LEN; i++)
-    level->author[i] = '\0';
-
-  strcpy(level->name, NAMELESS_LEVEL_NAME);
-  strcpy(level->author, ANONYMOUS_NAME);
-
-  for (i = 0; i < 4; i++)
-  {
-    level->envelope_text[i][0] = '\0';
-    level->envelope_xsize[i] = MAX_ENVELOPE_XSIZE;
-    level->envelope_ysize[i] = MAX_ENVELOPE_YSIZE;
-  }
-
-#if 0
-  for (i = 0; i < LEVEL_SCORE_ELEMENTS; i++)
-    level->score[i] = (i == SC_TIME_BONUS ? 1 : 10);
-#endif
-
-#if 0
-  level->num_yamyam_contents = STD_ELEMENT_CONTENTS;
-  for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
-    for (x = 0; x < 3; x++)
-      for (y = 0; y < 3; y++)
-       level->yamyam_content[i].e[x][y] =
-         (i < STD_ELEMENT_CONTENTS ? EL_ROCK : EL_EMPTY);
-#endif
+    if (IS_ENVELOPE(element))
+    {
+      int envelope_nr = element - EL_ENVELOPE_1;
 
-  level->field[0][0] = EL_PLAYER_1;
-  level->field[STD_LEV_FIELDX - 1][STD_LEV_FIELDY - 1] = EL_EXIT_CLOSED;
+      setConfigToDefaultsFromConfigList(chunk_config_NOTE);
 
-  for (i = 0; i < MAX_NUM_ELEMENTS; i++)
-  {
-    int element = i;
-    struct ElementInfo *ei = &element_info[element];
+      level->envelope[envelope_nr] = xx_envelope;
+    }
 
-#if 1
     if (IS_CUSTOM_ELEMENT(element) ||
        IS_GROUP_ELEMENT(element) ||
        IS_INTERNAL_ELEMENT(element))
@@ -1666,12 +1669,6 @@ static void setLevelInfoToDefaults(struct LevelInfo *level)
 
       *ei = xx_ei;
     }
-#endif
-
-    /* never initialize clipboard elements after the very first time */
-    /* (to be able to use clipboard elements between several levels) */
-    if (IS_CLIPBOARD_ELEMENT(element) && clipboard_elements_initialized)
-      continue;
 
     setElementChangePages(ei, 1);
     setElementChangeInfoToDefaults(ei->change);
@@ -1680,22 +1677,7 @@ static void setLevelInfoToDefaults(struct LevelInfo *level)
        IS_GROUP_ELEMENT(element) ||
        IS_INTERNAL_ELEMENT(element))
     {
-#if 1
       setElementDescriptionToDefault(ei);
-#else
-      for (j = 0; j < MAX_ELEMENT_NAME_LEN + 1; j++)
-       ei->description[j] = '\0';
-
-      if (ei->custom_description != NULL)
-       strncpy(ei->description, ei->custom_description,MAX_ELEMENT_NAME_LEN);
-      else
-       strcpy(ei->description, ei->editor_description);
-#endif
-
-#if 0
-      ei->use_gfx_element = FALSE;
-      ei->gfx_element = EL_EMPTY_SPACE;
-#endif
 
       ei->modified_settings = FALSE;
     }
@@ -1703,46 +1685,6 @@ static void setLevelInfoToDefaults(struct LevelInfo *level)
     if (IS_CUSTOM_ELEMENT(element) ||
        IS_INTERNAL_ELEMENT(element))
     {
-#if 0
-      ei->access_direction = MV_ALL_DIRECTIONS;
-
-      ei->collect_score_initial = 10;  /* special default */
-      ei->collect_count_initial = 1;   /* special default */
-
-      ei->ce_value_fixed_initial = 0;
-      ei->ce_value_random_initial = 0;
-      ei->use_last_ce_value = FALSE;
-
-#endif
-#if 0
-      ei->push_delay_fixed = -1;       /* initialize later */
-      ei->push_delay_random = -1;      /* initialize later */
-#endif
-#if 0
-      ei->drop_delay_fixed = 0;
-      ei->drop_delay_random = 0;
-      ei->move_delay_fixed = 0;
-      ei->move_delay_random = 0;
-
-      ei->move_pattern = MV_ALL_DIRECTIONS;
-      ei->move_direction_initial = MV_START_AUTOMATIC;
-      ei->move_stepsize = TILEX / 8;
-
-      ei->move_enter_element = EL_EMPTY_SPACE;
-      ei->move_leave_element = EL_EMPTY_SPACE;
-      ei->move_leave_type = LEAVE_TYPE_UNLIMITED;
-
-      ei->slippery_type = SLIPPERY_ANY_RANDOM;
-
-      ei->explosion_type = EXPLODES_3X3;
-      ei->explosion_delay = 16;
-      ei->ignition_delay = 8;
-
-      for (x = 0; x < 3; x++)
-       for (y = 0; y < 3; y++)
-         ei->content.e[x][y] = EL_EMPTY_SPACE;
-#endif
-
       /* internal values used in level editor */
 
       ei->access_type = 0;
@@ -1757,24 +1699,6 @@ static void setLevelInfoToDefaults(struct LevelInfo *level)
       ei->can_explode_impact = FALSE;
 
       ei->current_change_page = 0;
-
-#if 0
-      /* !!! now done in InitElementPropertiesStatic() (see above) !!! */
-      /* !!! (else properties set there will be overwritten here)  !!! */
-      /* start with no properties at all */
-#if 1
-      for (j = 0; j < NUM_EP_BITFIELDS; j++)
-       ei->properties[j] = EP_BITMASK_DEFAULT;
-#else
-      for (j = 0; j < NUM_EP_BITFIELDS; j++)
-       Properties[element][j] = EP_BITMASK_DEFAULT;
-#endif
-#endif
-
-#if 0
-      /* now set default properties */
-      SET_PROPERTY(element, EP_CAN_MOVE_INTO_ACID, TRUE);
-#endif
     }
 
     if (IS_GROUP_ELEMENT(element) ||
@@ -1788,23 +1712,11 @@ static void setLevelInfoToDefaults(struct LevelInfo *level)
 
       group = ei->group;
 
-#if 1
       xx_group = *group;       /* copy group data into temporary buffer */
 
       setConfigToDefaultsFromConfigList(chunk_config_GRPX);
 
       *group = xx_group;
-#endif
-
-#if 0
-      for (j = 0; j < MAX_ELEMENTS_IN_GROUP; j++)
-       group->element[j] = EL_EMPTY_SPACE;
-
-      /* default: only one element in group */
-      group->num_elements = 1;
-
-      group->choice_mode = ANIM_RANDOM;
-#endif
     }
   }
 
@@ -1816,6 +1728,9 @@ static void setLevelInfoToDefaults(struct LevelInfo *level)
 
   level->changed = FALSE;
 
+  /* set all bug compatibility flags to "false" => do not emulate this bug */
+  level->use_action_after_change_bug = FALSE;
+
   if (leveldir_current == NULL)                /* only when dumping level */
     return;
 
@@ -1861,15 +1776,44 @@ static void setFileInfoToDefaults(struct LevelFileInfo *level_file_info)
 
 static void ActivateLevelTemplate()
 {
-#if 1
+  int x, y;
+
   /* Currently there is no special action needed to activate the template
      data, because 'element_info' property settings overwrite the original
      level data, while all other variables do not change. */
-#else
-  /* Currently there is no special action needed to activate the template
-     data, because 'element_info' and 'Properties' overwrite the original
-     level data, while all other variables do not change. */
-#endif
+
+  /* Exception: 'from_level_template' elements in the original level playfield
+     are overwritten with the corresponding elements at the same position in
+     playfield from the level template. */
+
+  for (x = 0; x < level.fieldx; x++)
+    for (y = 0; y < level.fieldy; y++)
+      if (level.field[x][y] == EL_FROM_LEVEL_TEMPLATE)
+       level.field[x][y] = level_template.field[x][y];
+
+  if (check_special_flags("load_xsb_to_ces"))
+  {
+    struct LevelInfo level_backup = level;
+
+    /* overwrite all individual level settings from template level settings */
+    level = level_template;
+
+    /* restore playfield size */
+    level.fieldx = level_backup.fieldx;
+    level.fieldy = level_backup.fieldy;
+
+    /* restore playfield content */
+    for (x = 0; x < level.fieldx; x++)
+      for (y = 0; y < level.fieldy; y++)
+       level.field[x][y] = level_backup.field[x][y];
+
+    /* restore name and author from individual level */
+    strcpy(level.name,   level_backup.name);
+    strcpy(level.author, level_backup.author);
+
+    /* restore flag "use_custom_template" */
+    level.use_custom_template = level_backup.use_custom_template;
+  }
 }
 
 static char *getLevelFilenameFromBasename(char *basename)
@@ -1885,15 +1829,32 @@ static char *getLevelFilenameFromBasename(char *basename)
 
 static int getFileTypeFromBasename(char *basename)
 {
+  /* !!! ALSO SEE COMMENT IN checkForPackageFromBasename() !!! */
+
   static char *filename = NULL;
   struct stat file_status;
 
   /* ---------- try to determine file type from filename ---------- */
 
   /* check for typical filename of a Supaplex level package file */
+#if 1
+  if (strlen(basename) == 10 && strPrefixLower(basename, "levels.d"))
+    return LEVEL_FILE_TYPE_SP;
+#else
   if (strlen(basename) == 10 && (strncmp(basename, "levels.d", 8) == 0 ||
                                 strncmp(basename, "LEVELS.D", 8) == 0))
     return LEVEL_FILE_TYPE_SP;
+#endif
+
+  /* check for typical filename of a Diamond Caves II level package file */
+  if (strSuffixLower(basename, ".dc") ||
+      strSuffixLower(basename, ".dc2"))
+    return LEVEL_FILE_TYPE_DC;
+
+  /* check for typical filename of a Sokoban level package file */
+  if (strSuffixLower(basename, ".xsb") &&
+      strchr(basename, '%') == NULL)
+    return LEVEL_FILE_TYPE_SB;
 
   /* ---------- try to determine file type from filesize ---------- */
 
@@ -1910,18 +1871,31 @@ static int getFileTypeFromBasename(char *basename)
   return LEVEL_FILE_TYPE_UNKNOWN;
 }
 
-static char *getSingleLevelBasename(int nr)
+static boolean checkForPackageFromBasename(char *basename)
+{
+  /* !!! WON'T WORK ANYMORE IF getFileTypeFromBasename() ALSO DETECTS !!!
+     !!! SINGLE LEVELS (CURRENTLY ONLY DETECTS LEVEL PACKAGES         !!! */
+
+  return (getFileTypeFromBasename(basename) != LEVEL_FILE_TYPE_UNKNOWN);
+}
+
+static char *getSingleLevelBasenameExt(int nr, char *extension)
 {
   static char basename[MAX_FILENAME_LEN];
 
   if (nr < 0)
-    sprintf(basename, "template.%s", LEVELFILE_EXTENSION);
+    sprintf(basename, "template.%s", extension);
   else
-    sprintf(basename, "%03d.%s", nr, LEVELFILE_EXTENSION);
+    sprintf(basename, "%03d.%s", nr, extension);
 
   return basename;
 }
 
+static char *getSingleLevelBasename(int nr)
+{
+  return getSingleLevelBasenameExt(nr, LEVELFILE_EXTENSION);
+}
+
 static char *getPackedLevelBasename(int type)
 {
   static char basename[MAX_FILENAME_LEN];
@@ -2049,9 +2023,33 @@ static void determineLevelFileInfo_Filename(struct LevelFileInfo *lfi)
   /* special case: level number is negative => check for level template file */
   if (nr < 0)
   {
+#if 1
+    /* global variable "leveldir_current" must be modified in the loop below */
+    LevelDirTree *leveldir_current_last = leveldir_current;
+
+    /* check for template level in path from current to topmost tree node */
+
+    while (leveldir_current != NULL)
+    {
+      setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_RND,
+                                          "template.%s", LEVELFILE_EXTENSION);
+
+      if (fileExists(lfi->filename))
+       break;
+
+      leveldir_current = leveldir_current->node_parent;
+    }
+
+    /* restore global variable "leveldir_current" modified in above loop */
+    leveldir_current = leveldir_current_last;
+
+#else
+
     setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_RND,
                                         "template.%s", LEVELFILE_EXTENSION);
 
+#endif
+
     /* no fallback if template file not existing */
     return;
   }
@@ -2063,6 +2061,9 @@ static void determineLevelFileInfo_Filename(struct LevelFileInfo *lfi)
 
     setLevelFileInfo_FormatLevelFilename(lfi, filetype,
                                         leveldir_current->level_filename, nr);
+
+    lfi->packed = checkForPackageFromBasename(leveldir_current->level_filename);
+
     if (fileExists(lfi->filename))
       return;
   }
@@ -2147,6 +2148,7 @@ int getMappedElement(int element)
 
     case EL_KEY_OBSOLETE:
       element = EL_KEY_1;
+      break;
 
     case EL_EM_KEY_1_FILE_OBSOLETE:
       element = EL_EM_KEY_1;
@@ -2219,8 +2221,21 @@ static int LoadLevel_VERS(FILE *file, int chunk_size, struct LevelInfo *level)
   return chunk_size;
 }
 
+static int LoadLevel_DATE(FILE *file, int chunk_size, struct LevelInfo *level)
+{
+  level->creation_date.year  = getFile16BitBE(file);
+  level->creation_date.month = getFile8Bit(file);
+  level->creation_date.day   = getFile8Bit(file);
+
+  level->creation_date.src   = DATE_SRC_LEVELFILE;
+
+  return chunk_size;
+}
+
 static int LoadLevel_HEAD(FILE *file, int chunk_size, struct LevelInfo *level)
 {
+  int initial_player_stepsize;
+  int initial_player_gravity;
   int i, x, y;
 
   level->fieldx = getFile8Bit(file);
@@ -2247,10 +2262,17 @@ static int LoadLevel_HEAD(FILE *file, int chunk_size, struct LevelInfo *level)
   level->time_wheel            = getFile8Bit(file);
   level->amoeba_content                = getMappedElement(getFile8Bit(file));
 
-  level->initial_player_stepsize = (getFile8Bit(file) == 1 ? STEPSIZE_FAST :
-                                   STEPSIZE_NORMAL);
+  initial_player_stepsize      = (getFile8Bit(file) == 1 ? STEPSIZE_FAST :
+                                  STEPSIZE_NORMAL);
+
+  for (i = 0; i < MAX_PLAYERS; i++)
+    level->initial_player_stepsize[i] = initial_player_stepsize;
+
+  initial_player_gravity       = (getFile8Bit(file) == 1 ? TRUE : FALSE);
+
+  for (i = 0; i < MAX_PLAYERS; i++)
+    level->initial_player_gravity[i] = initial_player_gravity;
 
-  level->initial_gravity       = (getFile8Bit(file) == 1 ? TRUE : FALSE);
   level->encoding_16bit_field  = (getFile8Bit(file) == 1 ? TRUE : FALSE);
   level->em_slippery_gems      = (getFile8Bit(file) == 1 ? TRUE : FALSE);
 
@@ -2275,13 +2297,24 @@ static int LoadLevel_HEAD(FILE *file, int chunk_size, struct LevelInfo *level)
   return chunk_size;
 }
 
+static int LoadLevel_NAME(FILE *file, int chunk_size, struct LevelInfo *level)
+{
+  int i;
+
+  for (i = 0; i < MAX_LEVEL_NAME_LEN; i++)
+    level->name[i] = getFile8Bit(file);
+  level->name[MAX_LEVEL_NAME_LEN] = 0;
+
+  return chunk_size;
+}
+
 static int LoadLevel_AUTH(FILE *file, int chunk_size, struct LevelInfo *level)
 {
   int i;
 
   for (i = 0; i < MAX_LEVEL_AUTHOR_LEN; i++)
     level->author[i] = getFile8Bit(file);
-  level->author[MAX_LEVEL_NAME_LEN] = 0;
+  level->author[MAX_LEVEL_AUTHOR_LEN] = 0;
 
   return chunk_size;
 }
@@ -2413,8 +2446,8 @@ static int LoadLevel_CNT3(FILE *file, int chunk_size, struct LevelInfo *level)
 
   envelope_len = getFile16BitBE(file);
 
-  level->envelope_xsize[envelope_nr] = getFile8Bit(file);
-  level->envelope_ysize[envelope_nr] = getFile8Bit(file);
+  level->envelope[envelope_nr].xsize = getFile8Bit(file);
+  level->envelope[envelope_nr].ysize = getFile8Bit(file);
 
   ReadUnusedBytesFromFile(file, LEVEL_CHUNK_CNT3_UNUSED);
 
@@ -2426,7 +2459,7 @@ static int LoadLevel_CNT3(FILE *file, int chunk_size, struct LevelInfo *level)
   }
 
   for (i = 0; i < envelope_len; i++)
-    level->envelope_text[envelope_nr][i] = getFile8Bit(file);
+    level->envelope[envelope_nr].text[i] = getFile8Bit(file);
 
   return chunk_size;
 }
@@ -2445,26 +2478,18 @@ static int LoadLevel_CUS1(FILE *file, int chunk_size, struct LevelInfo *level)
 
   for (i = 0; i < num_changed_custom_elements; i++)
   {
-    int element = getFile16BitBE(file);
+    int element = getMappedElement(getFile16BitBE(file));
     int properties = getFile32BitBE(file);
 
-#if 1
     if (IS_CUSTOM_ELEMENT(element))
       element_info[element].properties[EP_BITFIELD_BASE_NR] = properties;
     else
       Error(ERR_WARN, "invalid custom element number %d", element);
-#else
-    if (IS_CUSTOM_ELEMENT(element))
-      Properties[element][EP_BITFIELD_BASE_NR] = properties;
-    else
-      Error(ERR_WARN, "invalid custom element number %d", element);
-#endif
 
-#if 1
-    /* needed for older levels (see src/init.c for details) */
-    element_info[element].push_delay_fixed = -1;       /* initialize later */
-    element_info[element].push_delay_random = -1;      /* initialize later */
-#endif
+    /* older game versions that wrote level files with CUS1 chunks used
+       different default push delay values (not yet stored in level file) */
+    element_info[element].push_delay_fixed = 2;
+    element_info[element].push_delay_random = 8;
   }
 
   return chunk_size;
@@ -2484,8 +2509,8 @@ static int LoadLevel_CUS2(FILE *file, int chunk_size, struct LevelInfo *level)
 
   for (i = 0; i < num_changed_custom_elements; i++)
   {
-    int element = getFile16BitBE(file);
-    int custom_target_element = getFile16BitBE(file);
+    int element = getMappedElement(getFile16BitBE(file));
+    int custom_target_element = getMappedElement(getFile16BitBE(file));
 
     if (IS_CUSTOM_ELEMENT(element))
       element_info[element].change->target_element = custom_target_element;
@@ -2510,7 +2535,7 @@ static int LoadLevel_CUS3(FILE *file, int chunk_size, struct LevelInfo *level)
 
   for (i = 0; i < num_changed_custom_elements; i++)
   {
-    int element = getFile16BitBE(file);
+    int element = getMappedElement(getFile16BitBE(file));
     struct ElementInfo *ei = &element_info[element];
     unsigned int event_bits;
 
@@ -2525,17 +2550,13 @@ static int LoadLevel_CUS3(FILE *file, int chunk_size, struct LevelInfo *level)
       ei->description[j] = getFile8Bit(file);
     ei->description[MAX_ELEMENT_NAME_LEN] = 0;
 
-#if 1
     ei->properties[EP_BITFIELD_BASE_NR] = getFile32BitBE(file);
-#else
-    Properties[element][EP_BITFIELD_BASE_NR] = getFile32BitBE(file);
-#endif
 
     /* some free bytes for future properties and padding */
     ReadUnusedBytesFromFile(file, 7);
 
     ei->use_gfx_element = getFile8Bit(file);
-    ei->gfx_element = getMappedElement(getFile16BitBE(file));
+    ei->gfx_element_initial = getMappedElement(getFile16BitBE(file));
 
     ei->collect_score_initial = getFile8Bit(file);
     ei->collect_count_initial = getFile8Bit(file);
@@ -2564,7 +2585,7 @@ static int LoadLevel_CUS3(FILE *file, int chunk_size, struct LevelInfo *level)
     ei->change->delay_random = getFile16BitBE(file);
     ei->change->delay_frames = getFile16BitBE(file);
 
-    ei->change->trigger_element = getMappedElement(getFile16BitBE(file));
+    ei->change->initial_trigger_element= getMappedElement(getFile16BitBE(file));
 
     ei->change->explode = getFile8Bit(file);
     ei->change->use_target_content = getFile8Bit(file);
@@ -2600,7 +2621,7 @@ static int LoadLevel_CUS4(FILE *file, int chunk_size, struct LevelInfo *level)
 
   /* ---------- custom element base property values (96 bytes) ------------- */
 
-  element = getFile16BitBE(file);
+  element = getMappedElement(getFile16BitBE(file));
 
   if (!IS_CUSTOM_ELEMENT(element))
   {
@@ -2616,11 +2637,8 @@ static int LoadLevel_CUS4(FILE *file, int chunk_size, struct LevelInfo *level)
     ei->description[i] = getFile8Bit(file);
   ei->description[MAX_ELEMENT_NAME_LEN] = 0;
 
-#if 1
   ei->properties[EP_BITFIELD_BASE_NR] = getFile32BitBE(file);
-#else
-  Properties[element][EP_BITFIELD_BASE_NR] = getFile32BitBE(file);
-#endif
+
   ReadUnusedBytesFromFile(file, 4);    /* reserved for more base properties */
 
   ei->num_change_pages = getFile8Bit(file);
@@ -2637,7 +2655,7 @@ static int LoadLevel_CUS4(FILE *file, int chunk_size, struct LevelInfo *level)
   ei->use_last_ce_value = getFile8Bit(file);
 
   ei->use_gfx_element = getFile8Bit(file);
-  ei->gfx_element = getMappedElement(getFile16BitBE(file));
+  ei->gfx_element_initial = getMappedElement(getFile16BitBE(file));
 
   ei->collect_score_initial = getFile8Bit(file);
   ei->collect_count_initial = getFile8Bit(file);
@@ -2700,7 +2718,7 @@ static int LoadLevel_CUS4(FILE *file, int chunk_size, struct LevelInfo *level)
     change->delay_random = getFile16BitBE(file);
     change->delay_frames = getFile16BitBE(file);
 
-    change->trigger_element = getMappedElement(getFile16BitBE(file));
+    change->initial_trigger_element = getMappedElement(getFile16BitBE(file));
 
     change->explode = getFile8Bit(file);
     change->use_target_content = getFile8Bit(file);
@@ -2749,7 +2767,7 @@ static int LoadLevel_GRP1(FILE *file, int chunk_size, struct LevelInfo *level)
   int element;
   int i;
 
-  element = getFile16BitBE(file);
+  element = getMappedElement(getFile16BitBE(file));
 
   if (!IS_GROUP_ELEMENT(element))
   {
@@ -2770,7 +2788,7 @@ static int LoadLevel_GRP1(FILE *file, int chunk_size, struct LevelInfo *level)
   group->num_elements = getFile8Bit(file);
 
   ei->use_gfx_element = getFile8Bit(file);
-  ei->gfx_element = getMappedElement(getFile16BitBE(file));
+  ei->gfx_element_initial = getMappedElement(getFile16BitBE(file));
 
   group->choice_mode = getFile8Bit(file);
 
@@ -2802,10 +2820,6 @@ static int LoadLevel_MicroChunk(FILE *file, struct LevelFileConfigInfo *conf,
     int num_bytes = getFile16BitBE(file);
     byte *buffer = checked_malloc(num_bytes);
 
-#if 0
-    printf("::: - found multi bytes\n");
-#endif
-
     ReadBytesFromFile(file, buffer, num_bytes);
 
     for (i = 0; conf[i].data_type != -1; i++)
@@ -2826,7 +2840,21 @@ static int LoadLevel_MicroChunk(FILE *file, struct LevelFileConfigInfo *conf,
          num_entities = max_num_entities;
        }
 
-       *(int *)(conf[i].num_entities) = num_entities;
+       if (num_entities == 0 && (data_type == TYPE_ELEMENT_LIST ||
+                                 data_type == TYPE_CONTENT_LIST))
+       {
+         /* for element and content lists, zero entities are not allowed */
+         Error(ERR_WARN, "found empty list of entities for element %d",
+               element);
+
+         /* do not set "num_entities" here to prevent reading behind buffer */
+
+         *(int *)(conf[i].num_entities) = 1;   /* at least one is required */
+       }
+       else
+       {
+         *(int *)(conf[i].num_entities) = num_entities;
+       }
 
        element_found = TRUE;
 
@@ -2875,10 +2903,6 @@ static int LoadLevel_MicroChunk(FILE *file, struct LevelFileConfigInfo *conf,
                 byte_mask == CONF_MASK_2_BYTE ? getFile16BitBE(file) :
                 byte_mask == CONF_MASK_4_BYTE ? getFile32BitBE(file) : 0);
 
-#if 0
-    printf("::: - found single bytes\n");
-#endif
-
     for (i = 0; conf[i].data_type != -1; i++)
     {
       if (conf[i].element == element &&
@@ -2886,6 +2910,9 @@ static int LoadLevel_MicroChunk(FILE *file, struct LevelFileConfigInfo *conf,
       {
        int data_type = conf[i].data_type;
 
+       if (data_type == TYPE_ELEMENT)
+         value = getMappedElement(value);
+
        if (data_type == TYPE_BOOLEAN)
          *(boolean *)(conf[i].value) = value;
        else
@@ -2940,151 +2967,73 @@ static int LoadLevel_CONF(FILE *file, int chunk_size, struct LevelInfo *level)
 {
   int real_chunk_size = 0;
 
-#if 1
   li = *level;         /* copy level data into temporary buffer */
-#endif
 
   while (!feof(file))
   {
-    int element = getFile16BitBE(file);
-#if 1
+    int element = getMappedElement(getFile16BitBE(file));
+
     real_chunk_size += 2;
     real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_CONF,
                                            element, element);
-#else
-    int conf_type = getFile8Bit(file);
-    int byte_mask = conf_type & CONF_MASK_BYTES;
-    boolean element_found = FALSE;
-    int i;
-
-    real_chunk_size += 3;
+    if (real_chunk_size >= chunk_size)
+      break;
+  }
 
-#if 0
-    li = *level;       /* copy level data into temporary buffer */
-#endif
+  *level = li;         /* copy temporary buffer back to level data */
 
-    if (byte_mask == CONF_MASK_MULTI_BYTES)
-    {
-      int num_bytes = getFile16BitBE(file);
-      byte *buffer = checked_malloc(num_bytes);
+  return real_chunk_size;
+}
 
-      ReadBytesFromFile(file, buffer, num_bytes);
+static int LoadLevel_ELEM(FILE *file, int chunk_size, struct LevelInfo *level)
+{
+  int real_chunk_size = 0;
 
-      for (i = 0; chunk_config_CONF[i].data_type != -1; i++)
-      {
-       if (chunk_config_CONF[i].element == element &&
-           chunk_config_CONF[i].conf_type == conf_type)
-       {
-         int data_type = chunk_config_CONF[i].data_type;
-         int num_entities = num_bytes / CONF_ENTITY_NUM_BYTES(data_type);
-         int max_num_entities = chunk_config_CONF[i].max_num_entities;
-
-         if (num_entities > max_num_entities)
-         {
-           Error(ERR_WARN,
-                 "truncating number of entities for element %d from %d to %d",
-                 element, num_entities, max_num_entities);
-
-           num_entities = max_num_entities;
-         }
-
-         *(int *)(chunk_config_CONF[i].num_entities) = num_entities;
-
-         element_found = TRUE;
-
-         if (data_type == TYPE_ELEMENT_LIST)
-         {
-           int *element_array = (int *)(chunk_config_CONF[i].value);
-           int j;
-
-           for (j = 0; j < num_entities; j++)
-             element_array[j] =
-               getMappedElement(CONF_ELEMENTS_ELEMENT(buffer, j));
-         }
-         else if (data_type == TYPE_CONTENT_LIST)
-         {
-           struct Content *content= (struct Content *)(chunk_config_CONF[i].value);
-           int c, x, y;
-
-           for (c = 0; c < num_entities; c++)
-             for (y = 0; y < 3; y++)
-               for (x = 0; x < 3; x++)
-                 content[c].e[x][y] =
-                   getMappedElement(CONF_CONTENTS_ELEMENT(buffer, c, x, y));
-         }
-         else
-           element_found = FALSE;
+  li = *level;         /* copy level data into temporary buffer */
 
-         break;
-       }
-      }
+  while (!feof(file))
+  {
+    int element = getMappedElement(getFile16BitBE(file));
 
-      checked_free(buffer);
+    real_chunk_size += 2;
+    real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_ELEM,
+                                           element, element);
+    if (real_chunk_size >= chunk_size)
+      break;
+  }
 
-      real_chunk_size += 2 + num_bytes;
-    }
-    else       /* constant size configuration data (1, 2 or 4 bytes) */
-    {
-      int value = (byte_mask == CONF_MASK_1_BYTE ? getFile8Bit   (file) :
-                  byte_mask == CONF_MASK_2_BYTE ? getFile16BitBE(file) :
-                  byte_mask == CONF_MASK_4_BYTE ? getFile32BitBE(file) : 0);
+  *level = li;         /* copy temporary buffer back to level data */
 
-      for (i = 0; chunk_config_CONF[i].data_type != -1; i++)
-      {
-       if (chunk_config_CONF[i].element == element &&
-           chunk_config_CONF[i].conf_type == conf_type)
-       {
-         int data_type = chunk_config_CONF[i].data_type;
+  return real_chunk_size;
+}
 
-         if (data_type == TYPE_BOOLEAN)
-           *(boolean *)(chunk_config_CONF[i].value) = value;
-         else
-           *(int *)    (chunk_config_CONF[i].value) = value;
+static int LoadLevel_NOTE(FILE *file, int chunk_size, struct LevelInfo *level)
+{
+  int element = getMappedElement(getFile16BitBE(file));
+  int envelope_nr = element - EL_ENVELOPE_1;
+  int real_chunk_size = 2;
 
-         element_found = TRUE;
+  while (!feof(file))
+  {
+    real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_NOTE,
+                                           -1, element);
 
-         break;
-       }
-      }
+    if (real_chunk_size >= chunk_size)
+      break;
+  }
 
-      real_chunk_size += CONF_VALUE_NUM_BYTES(byte_mask);
-    }
-
-    if (!element_found)
-      Error(ERR_WARN, "cannot load CONF value for element %d", element);
-#endif
-
-#if 0
-    *level = li;       /* copy temporary buffer back to level data */
-#endif
-
-#if 1
-    if (real_chunk_size >= chunk_size)
-      break;
-#else
-    if (conf_type == CONF_LAST_ENTRY || real_chunk_size >= chunk_size)
-      break;
-#endif
-  }
-
-#if 1
-  *level = li;         /* copy temporary buffer back to level data */
-#endif
+  level->envelope[envelope_nr] = xx_envelope;
 
   return real_chunk_size;
 }
 
 static int LoadLevel_CUSX(FILE *file, int chunk_size, struct LevelInfo *level)
 {
-  int element = getFile16BitBE(file);
+  int element = getMappedElement(getFile16BitBE(file));
   int real_chunk_size = 2;
   struct ElementInfo *ei = &element_info[element];
   int i;
 
-#if 0
-  printf("::: CUSX: loading element '%s' ...\n", EL_NAME(element));
-#endif
-
   xx_ei = *ei;         /* copy element data into temporary buffer */
 
   xx_ei.num_change_pages = -1;
@@ -3093,11 +3042,6 @@ static int LoadLevel_CUSX(FILE *file, int chunk_size, struct LevelInfo *level)
   {
     real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_CUSX_base,
                                            -1, element);
-
-#if 0
-    printf("::: - real_chunk_size now %d\n", real_chunk_size);
-#endif
-
     if (xx_ei.num_change_pages != -1)
       break;
 
@@ -3152,7 +3096,7 @@ static int LoadLevel_CUSX(FILE *file, int chunk_size, struct LevelInfo *level)
 
 static int LoadLevel_GRPX(FILE *file, int chunk_size, struct LevelInfo *level)
 {
-  int element = getFile16BitBE(file);
+  int element = getMappedElement(getFile16BitBE(file));
   int real_chunk_size = 2;
   struct ElementInfo *ei = &element_info[element];
   struct ElementGroupInfo *group = ei->group;
@@ -3188,8 +3132,12 @@ static void LoadLevelFromFileInfo_RND(struct LevelInfo *level,
   {
     level->no_valid_file = TRUE;
 
+#if 1
+    Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename);
+#else
     if (level != &level_template)
       Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename);
+#endif
 
     return;
   }
@@ -3255,8 +3203,11 @@ static void LoadLevelFromFileInfo_RND(struct LevelInfo *level,
     chunk_info[] =
     {
       { "VERS", LEVEL_CHUNK_VERS_SIZE, LoadLevel_VERS },
+      { "DATE", LEVEL_CHUNK_DATE_SIZE, LoadLevel_DATE },
       { "HEAD", LEVEL_CHUNK_HEAD_SIZE, LoadLevel_HEAD },
-      { "AUTH", MAX_LEVEL_AUTHOR_LEN,  LoadLevel_AUTH },
+      { "NAME", LEVEL_CHUNK_NAME_SIZE, LoadLevel_NAME },
+      { "AUTH", LEVEL_CHUNK_AUTH_SIZE, LoadLevel_AUTH },
+      { "INFO", -1,                    LoadLevel_INFO },
       { "BODY", -1,                    LoadLevel_BODY },
       { "CONT", -1,                    LoadLevel_CONT },
       { "CNT2", LEVEL_CHUNK_CNT2_SIZE, LoadLevel_CNT2 },
@@ -3266,8 +3217,9 @@ static void LoadLevelFromFileInfo_RND(struct LevelInfo *level,
       { "CUS3", -1,                    LoadLevel_CUS3 },
       { "CUS4", -1,                    LoadLevel_CUS4 },
       { "GRP1", -1,                    LoadLevel_GRP1 },
-      { "INFO", -1,                    LoadLevel_INFO },
       { "CONF", -1,                    LoadLevel_CONF },
+      { "ELEM", -1,                    LoadLevel_ELEM },
+      { "NOTE", -1,                    LoadLevel_NOTE },
       { "CUSX", -1,                    LoadLevel_CUSX },
       { "GRPX", -1,                    LoadLevel_GRPX },
 
@@ -3760,14 +3712,6 @@ void CopyNativeLevel_RND_to_EM(struct LevelInfo *level)
   struct PLAYER **ply = level_em->ply;
   int i, j, x, y;
 
-#if 0
-  printf("::: A\n");
-  for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
-    for (j = 0; j < 8; j++)
-      printf("::: ball %d, %d: %d\n", i, j,
-            level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
-#endif
-
   lev->width  = MIN(level->fieldx, EM_MAX_CAVE_WIDTH);
   lev->height = MIN(level->fieldy, EM_MAX_CAVE_HEIGHT);
 
@@ -3820,41 +3764,13 @@ void CopyNativeLevel_RND_to_EM(struct LevelInfo *level)
        map_element_RND_to_EM(level->
                              ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
 
-#if 0
-  for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
-    for (j = 0; j < 8; j++)
-      printf("::: ball %d, %d: %d\n", i, j,
-            level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
-#endif
-
   map_android_clone_elements_RND_to_EM(level);
 
-#if 0
-  for (i = 0; i < 16; i++)
-    lev->android_array[i] = FALSE;     /* !!! YET TO COME !!! */
-#endif
-
   /* 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;
 
-#if 1
-
-#if 0
-#if 1
-  LoadLevel_InitPlayfield();
-#else
-  lev_fieldx = lev->width;     /* !!! also in LoadLevel_InitPlayfield() !!! */
-  lev_fieldy = lev->height;    /* !!! also in LoadLevel_InitPlayfield() !!! */
-  SetBorderElement();          /* !!! also in LoadLevel_InitPlayfield() !!! */
-#endif
-#endif
-
-#if 0
-  printf("::: BorderElement == %d\n", BorderElement);
-#endif
-
   if (BorderElement == EL_STEELWALL)
   {
     for (y = 0; y < lev->height + 2; y++)
@@ -3876,44 +3792,15 @@ void CopyNativeLevel_RND_to_EM(struct LevelInfo *level)
     level_em->cave[xx][yy] = new_element;
   }
 
-#else
-
-  /* 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]);
-
-    if (level->field[x][y] == EL_AMOEBA_DEAD)
-      new_element = map_element_RND_to_EM(EL_AMOEBA_WET);
-
-    level_em->cave[x + 1][y + 1] = new_element;
-  }
-
-#endif
-
-#if 1
-
   for (i = 0; i < MAX_PLAYERS; i++)
   {
     ply[i]->x_initial = 0;
     ply[i]->y_initial = 0;
   }
 
-#else
-
-  ply1->x_initial = 0;
-  ply1->y_initial = 0;
-
-  ply2->x_initial = 0;
-  ply2->y_initial = 0;
-
-#endif
-
   /* initialize player positions and delete players from the playfield */
   for (y = 0; y < lev->height; y++) for (x = 0; x < lev->width; x++)
   {
-
-#if 1
     if (ELEM_IS_PLAYER(level->field[x][y]))
     {
       int player_nr = GET_PLAYER_NR(level->field[x][y]);
@@ -3926,43 +3813,12 @@ void CopyNativeLevel_RND_to_EM(struct LevelInfo *level)
 
       level_em->cave[xx][yy] = map_element_RND_to_EM(EL_EMPTY);
     }
-
-#else
-
-#if 1
-    /* !!! CURRENTLY ONLY SUPPORT FOR ONE PLAYER !!! */
-    if (ELEM_IS_PLAYER(level->field[x][y]))
-    {
-      ply1->x_initial = x + 1;
-      ply1->y_initial = y + 1;
-      level_em->cave[x + 1][y + 1] = map_element_RND_to_EM(EL_EMPTY);
-    }
-#else
-    /* !!! ADD SUPPORT FOR MORE THAN ONE PLAYER !!! */
-    if (level->field[x][y] == EL_PLAYER_1)
-    {
-      ply1->x_initial = x + 1;
-      ply1->y_initial = y + 1;
-      level_em->cave[x + 1][y + 1] = map_element_RND_to_EM(EL_EMPTY);
-    }
-    else if (level->field[x][y] == EL_PLAYER_2)
-    {
-      ply2->x_initial = x + 1;
-      ply2->y_initial = y + 1;
-      level_em->cave[x + 1][y + 1] = map_element_RND_to_EM(EL_EMPTY);
-    }
-#endif
-
-#endif
-
   }
 
   if (BorderElement == EL_STEELWALL)
   {
-#if 1
     lev->width  += 2;
     lev->height += 2;
-#endif
   }
 }
 
@@ -4032,34 +3888,13 @@ void CopyNativeLevel_EM_to_RND(struct LevelInfo *level)
   level->wind_direction_initial =
     map_direction_EM_to_RND(lev->wind_direction_initial);
 
-#if 0
-  printf("::: foo\n");
-  for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
-    for (j = 0; j < 8; j++)
-      printf("::: ball %d, %d: %d\n", i, j,
-            level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
-#endif
-
   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
     for (j = 0; j < 8; j++)
       level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]] =
        map_element_EM_to_RND(lev->ball_array[i][j]);
 
-#if 0
-  printf("::: bar\n");
-  for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
-    for (j = 0; j < 8; j++)
-      printf("::: ball %d, %d: %d\n", i, j,
-            level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
-#endif
-
   map_android_clone_elements_EM_to_RND(level);
 
-#if 0
-  for (i = 0; i < 16; i++)
-    level->android_array[i] = FALSE;   /* !!! YET TO COME !!! */
-#endif
-
   /* convert the playfield (some elements need special treatment) */
   for (y = 0; y < level->fieldy; y++) for (x = 0; x < level->fieldx; x++)
   {
@@ -4071,16 +3906,6 @@ void CopyNativeLevel_EM_to_RND(struct LevelInfo *level)
     level->field[x][y] = new_element;
   }
 
-#if 0
-  printf("::: bar 0\n");
-  for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
-    for (j = 0; j < 8; j++)
-      printf("::: ball %d, %d: %d\n", i, j,
-            level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
-#endif
-
-#if 1
-
   for (i = 0; i < MAX_PLAYERS; i++)
   {
     /* in case of all players set to the same field, use the first player */
@@ -4088,76 +3913,9 @@ void CopyNativeLevel_EM_to_RND(struct LevelInfo *level)
     int jx = ply[nr]->x_initial - 1;
     int jy = ply[nr]->y_initial - 1;
 
-#if 0
-    printf("::: player %d: %d, %d\n", nr, jx, jy);
-#endif
-
     if (jx != -1 && jy != -1)
       level->field[jx][jy] = EL_PLAYER_1 + nr;
   }
-
-#else
-
-  /* in case of both players set to the same field, use the first player */
-  level->field[ply2->x_initial - 1][ply2->y_initial - 1] = EL_PLAYER_2;
-  level->field[ply1->x_initial - 1][ply1->y_initial - 1] = EL_PLAYER_1;
-
-#endif
-
-#if 0
-  printf("::: native Emerald Mine file version: %d\n", level_em->file_version);
-#endif
-
-#if 0
-  printf("::: bar 2\n");
-  for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
-    for (j = 0; j < 8; j++)
-      printf("::: ball %d, %d: %d\n", i, j,
-            level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
-#endif
-}
-
-static void LoadLevelFromFileInfo_EM(struct LevelInfo *level,
-                                    struct LevelFileInfo *level_file_info)
-{
-  if (!LoadNativeLevel_EM(level_file_info->filename))
-    level->no_valid_file = TRUE;
-}
-
-void CopyNativeLevel_RND_to_Native(struct LevelInfo *level)
-{
-  if (level->game_engine_type == GAME_ENGINE_TYPE_EM)
-    CopyNativeLevel_RND_to_EM(level);
-}
-
-void CopyNativeLevel_Native_to_RND(struct LevelInfo *level)
-{
-
-#if 0
-  {
-    static int ball_xy[8][2] =
-      {
-       { 0, 0 },
-       { 1, 0 },
-       { 2, 0 },
-       { 0, 1 },
-       { 2, 1 },
-       { 0, 2 },
-       { 1, 2 },
-       { 2, 2 },
-      };
-    int i, j;
-
-    printf("::: A6\n");
-    for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
-      for (j = 0; j < 8; j++)
-       printf("::: ball %d, %d: %d\n", i, j,
-              level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
-  }
-#endif
-
-  if (level->game_engine_type == GAME_ENGINE_TYPE_EM)
-    CopyNativeLevel_EM_to_RND(level);
 }
 
 
@@ -4165,6 +3923,8 @@ void CopyNativeLevel_Native_to_RND(struct LevelInfo *level)
 /* functions for loading SP level                                            */
 /* ------------------------------------------------------------------------- */
 
+#if 0
+
 #define NUM_SUPAPLEX_LEVELS_PER_PACKAGE        111
 #define SP_LEVEL_SIZE                  1536
 #define SP_LEVEL_XSIZE                 60
@@ -4174,6 +3934,7 @@ void CopyNativeLevel_Native_to_RND(struct LevelInfo *level)
 static void LoadLevelFromFileStream_SP(FILE *file, struct LevelInfo *level,
                                       int nr)
 {
+  int initial_player_gravity;
   int num_special_ports;
   int i, x, y;
 
@@ -4207,7 +3968,10 @@ static void LoadLevelFromFileStream_SP(FILE *file, struct LevelInfo *level,
   ReadUnusedBytesFromFile(file, 4);    /* (not used by Supaplex engine) */
 
   /* initial gravity: 1 == "on", anything else (0) == "off" */
-  level->initial_gravity = (fgetc(file) == 1 ? TRUE : FALSE);
+  initial_player_gravity = (fgetc(file) == 1 ? TRUE : FALSE);
+
+  for (i = 0; i < MAX_PLAYERS; i++)
+    level->initial_player_gravity[i] = initial_player_gravity;
 
   ReadUnusedBytesFromFile(file, 1);    /* (not used by Supaplex engine) */
 
@@ -4316,7 +4080,7 @@ static void LoadLevelFromFileStream_SP(FILE *file, struct LevelInfo *level,
   /* original Supaplex does not use score values -- use default values */
 #else
   for (i = 0; i < LEVEL_SCORE_ELEMENTS; i++)
-    level->score[i] = 0;               /* !!! CORRECT THIS !!! */
+    level->score[i] = 0;
 #endif
 
   /* there are no yamyams in supaplex levels */
@@ -4351,11 +4115,12 @@ static void LoadLevelFromFileInfo_SP(struct LevelInfo *level,
   }
 
   /* position file stream to the requested level inside the level package */
-  if (fseek(file, nr * SP_LEVEL_SIZE, SEEK_SET) != 0)
+  if (level_file_info->packed &&
+      fseek(file, nr * SP_LEVEL_SIZE, SEEK_SET) != 0)
   {
     level->no_valid_file = TRUE;
 
-    Error(ERR_WARN, "cannot fseek level '%s' -- using empty level", filename);
+    Error(ERR_WARN, "cannot fseek in file '%s' -- using empty level", filename);
 
     return;
   }
@@ -4390,7 +4155,7 @@ static void LoadLevelFromFileInfo_SP(struct LevelInfo *level,
       level->name[i] = '-';
 
     /* correct trailing multipart level meta information in level name */
-    for (i = SP_LEVEL_NAME_LEN - 1; i>=0 && level->name[i] == name_last; i--)
+    for (i = SP_LEVEL_NAME_LEN - 1; i >= 0 && level->name[i] == name_last; i--)
       level->name[i] = '-';
 
     /* ---------- check for normal single level ---------- */
@@ -4505,91 +4270,2715 @@ static void LoadLevelFromFileInfo_SP(struct LevelInfo *level,
     *level = multipart_level;
 }
 
-/* ------------------------------------------------------------------------- */
-/* functions for loading generic level                                       */
-/* ------------------------------------------------------------------------- */
+#endif
 
-void LoadLevelFromFileInfo(struct LevelInfo *level,
-                          struct LevelFileInfo *level_file_info)
+void CopyNativeLevel_RND_to_SP(struct LevelInfo *level)
 {
-  /* always start with reliable default values */
-  setLevelInfoToDefaults(level);
+  struct LevelInfo_SP *level_sp = level->native_sp_level;
+  LevelInfoType *header = &level_sp->header;
+  int i, x, y;
 
-  switch (level_file_info->type)
-  {
-    case LEVEL_FILE_TYPE_RND:
-      LoadLevelFromFileInfo_RND(level, level_file_info);
-      break;
+  level_sp->width  = level->fieldx;
+  level_sp->height = level->fieldy;
 
-    case LEVEL_FILE_TYPE_EM:
-      LoadLevelFromFileInfo_EM(level, level_file_info);
-      level->game_engine_type = GAME_ENGINE_TYPE_EM;
-      break;
+  for (x = 0; x < level->fieldx; x++)
+    for (y = 0; y < level->fieldy; y++)
+      level_sp->playfield[x][y] = map_element_RND_to_SP(level->field[x][y]);
 
-    case LEVEL_FILE_TYPE_SP:
-      LoadLevelFromFileInfo_SP(level, level_file_info);
-      break;
+  header->InitialGravity = (level->initial_player_gravity[0] ? 1 : 0);
 
-    default:
-      LoadLevelFromFileInfo_RND(level, level_file_info);
-      break;
-  }
+  for (i = 0; i < SP_LEVEL_NAME_LEN; i++)
+    header->LevelTitle[i] = level->name[i];
+  /* !!! NO STRING TERMINATION IN SUPAPLEX VB CODE YET -- FIX THIS !!! */
 
-  /* if level file is invalid, restore level structure to default values */
-  if (level->no_valid_file)
-    setLevelInfoToDefaults(level);
+  header->InfotronsNeeded = level->gems_needed;
 
-  if (level->game_engine_type == GAME_ENGINE_TYPE_UNKNOWN)
-    level->game_engine_type = GAME_ENGINE_TYPE_RND;
+  header->SpecialPortCount = 0;
 
-#if 1
-  if (level_file_info->type != LEVEL_FILE_TYPE_RND)
-    CopyNativeLevel_Native_to_RND(level);
-#else
-  if (level_file_info->type == LEVEL_FILE_TYPE_RND)
-    CopyNativeLevel_RND_to_Native(level);
-  else
-    CopyNativeLevel_Native_to_RND(level);
-#endif
-}
+  for (x = 0; x < level->fieldx; x++) for (y = 0; y < level->fieldy; y++)
+  {
+    boolean gravity_port_found = FALSE;
+    boolean gravity_port_valid = FALSE;
+    int gravity_port_flag;
+    int gravity_port_base_element;
+    int element = level->field[x][y];
 
-void LoadLevelFromFilename(struct LevelInfo *level, char *filename)
-{
-  static struct LevelFileInfo level_file_info;
+    if (element >= EL_SP_GRAVITY_ON_PORT_RIGHT &&
+       element <= EL_SP_GRAVITY_ON_PORT_UP)
+    {
+      gravity_port_found = TRUE;
+      gravity_port_valid = TRUE;
+      gravity_port_flag = 1;
+      gravity_port_base_element = EL_SP_GRAVITY_ON_PORT_RIGHT;
+    }
+    else if (element >= EL_SP_GRAVITY_OFF_PORT_RIGHT &&
+            element <= EL_SP_GRAVITY_OFF_PORT_UP)
+    {
+      gravity_port_found = TRUE;
+      gravity_port_valid = TRUE;
+      gravity_port_flag = 0;
+      gravity_port_base_element = EL_SP_GRAVITY_OFF_PORT_RIGHT;
+    }
+    else if (element >= EL_SP_GRAVITY_PORT_RIGHT &&
+            element <= EL_SP_GRAVITY_PORT_UP)
+    {
+      /* change R'n'D style gravity inverting special port to normal port
+        (there are no gravity inverting ports in native Supaplex engine) */
 
-  /* always start with reliable default values */
-  setFileInfoToDefaults(&level_file_info);
+      gravity_port_found = TRUE;
+      gravity_port_valid = FALSE;
+      gravity_port_base_element = EL_SP_GRAVITY_PORT_RIGHT;
+    }
 
-  level_file_info.nr = 0;                      /* unknown level number */
-  level_file_info.type = LEVEL_FILE_TYPE_RND;  /* no others supported yet */
-  level_file_info.filename = filename;
+    if (gravity_port_found)
+    {
+      if (gravity_port_valid &&
+         header->SpecialPortCount < SP_MAX_SPECIAL_PORTS)
+      {
+       SpecialPortType *port = &header->SpecialPort[header->SpecialPortCount];
 
-  LoadLevelFromFileInfo(level, &level_file_info);
+       port->PortLocation = (y * level->fieldx + x) * 2;
+       port->Gravity = gravity_port_flag;
+
+       element += EL_SP_GRAVITY_PORT_RIGHT - gravity_port_base_element;
+
+       header->SpecialPortCount++;
+      }
+      else
+      {
+       /* change special gravity port to normal port */
+
+       element += EL_SP_PORT_RIGHT - gravity_port_base_element;
+      }
+
+      level_sp->playfield[x][y] = element - EL_SP_START;
+    }
+  }
 }
 
-static void LoadLevel_InitVersion(struct LevelInfo *level, char *filename)
+void CopyNativeLevel_SP_to_RND(struct LevelInfo *level)
 {
-  if (leveldir_current == NULL)                /* only when dumping level */
-    return;
+  struct LevelInfo_SP *level_sp = level->native_sp_level;
+  LevelInfoType *header = &level_sp->header;
+  int i, x, y;
 
-  /* all engine modifications also valid for levels which use latest engine */
-#if 1
-  if (level->game_version < VERSION_IDENT(3,2,0,5))
+  level->fieldx = level_sp->width;
+  level->fieldy = level_sp->height;
+
+  for (x = 0; x < level->fieldx; x++)
   {
-    /* time bonus score was given for 10 s instead of 1 s before 3.2.0-5 */
-    level->score[SC_TIME_BONUS] /= 10;
-  }
-#endif
+    for (y = 0; y < level->fieldy; y++)
+    {
+      int element_old = level_sp->playfield[x][y];
+      int element_new = getMappedElement(map_element_SP_to_RND(element_old));
 
-#if 0
-  leveldir_current->latest_engine = TRUE;      /* !!! TEST ONLY !!! */
-#endif
+      if (element_new == EL_UNKNOWN)
+       Error(ERR_WARN, "invalid element %d at position %d, %d",
+             element_old, x, y);
 
-  if (leveldir_current->latest_engine)
-  {
-    /* ---------- use latest game engine ----------------------------------- */
+      level->field[x][y] = element_new;
+    }
+  }
 
-    /* For all levels which are forced to use the latest game engine version
+  for (i = 0; i < MAX_PLAYERS; i++)
+    level->initial_player_gravity[i] =
+      (header->InitialGravity == 1 ? TRUE : FALSE);
+
+  for (i = 0; i < SP_LEVEL_NAME_LEN; i++)
+    level->name[i] = header->LevelTitle[i];
+  level->name[SP_LEVEL_NAME_LEN] = '\0';
+
+  level->gems_needed = header->InfotronsNeeded;
+
+  for (i = 0; i < header->SpecialPortCount; i++)
+  {
+    SpecialPortType *port = &header->SpecialPort[i];
+    int port_location = port->PortLocation;
+    int gravity = port->Gravity;
+    int port_x, port_y, port_element;
+
+    port_x = (port_location / 2) % level->fieldx;
+    port_y = (port_location / 2) / level->fieldx;
+
+    if (port_x < 0 || port_x >= level->fieldx ||
+       port_y < 0 || port_y >= level->fieldy)
+    {
+      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;
+  }
+
+  /* change special gravity ports without database entries to normal ports */
+  for (x = 0; x < level->fieldx; x++)
+    for (y = 0; y < level->fieldy; y++)
+      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;
+
+  level->time = 0;                     /* no time limit */
+  level->amoeba_speed = 0;
+  level->time_magic_wall = 0;
+  level->time_wheel = 0;
+  level->amoeba_content = EL_EMPTY;
+
+#if 1
+  /* original Supaplex does not use score values -- use default values */
+#else
+  for (i = 0; i < LEVEL_SCORE_ELEMENTS; i++)
+    level->score[i] = 0;
+#endif
+
+  /* there are no yamyams in supaplex levels */
+  for (i = 0; i < level->num_yamyam_contents; i++)
+    for (x = 0; x < 3; x++)
+      for (y = 0; y < 3; y++)
+       level->yamyam_content[i].e[x][y] = EL_EMPTY;
+}
+
+static void CopyNativeTape_RND_to_SP(struct LevelInfo *level)
+{
+  struct LevelInfo_SP *level_sp = level->native_sp_level;
+  struct DemoInfo_SP *demo = &level_sp->demo;
+  int i, j;
+
+  /* always start with reliable default values */
+  demo->is_available = FALSE;
+  demo->length = 0;
+
+  if (TAPE_IS_EMPTY(tape))
+    return;
+
+  demo->level_nr = tape.level_nr;      /* (currently not used) */
+
+  level_sp->header.DemoRandomSeed = tape.random_seed;
+
+  demo->length = 0;
+  for (i = 0; i < tape.length; i++)
+  {
+    int demo_action = map_key_RND_to_SP(tape.pos[i].action[0]);
+    int demo_repeat = tape.pos[i].delay;
+
+    for (j = 0; j < demo_repeat / 16; j++)
+      demo->data[demo->length++] = 0xf0 | demo_action;
+
+    if (demo_repeat % 16)
+      demo->data[demo->length++] = ((demo_repeat % 16 - 1) << 4) | demo_action;
+  }
+
+  demo->data[demo->length++] = 0xff;
+
+  demo->is_available = TRUE;
+}
+
+static void setTapeInfoToDefaults();
+
+static void CopyNativeTape_SP_to_RND(struct LevelInfo *level)
+{
+  struct LevelInfo_SP *level_sp = level->native_sp_level;
+  struct DemoInfo_SP *demo = &level_sp->demo;
+  char *filename = level->file_info.filename;
+  int i;
+
+  /* always start with reliable default values */
+  setTapeInfoToDefaults();
+
+  if (!demo->is_available)
+    return;
+
+  tape.level_nr = demo->level_nr;      /* (currently not used) */
+  tape.length = demo->length - 1;      /* without "end of demo" byte */
+  tape.random_seed = level_sp->header.DemoRandomSeed;
+
+  TapeSetDateFromEpochSeconds(getFileTimestampEpochSeconds(filename));
+
+  for (i = 0; i < demo->length - 1; i++)
+  {
+    int demo_action = demo->data[i] & 0x0f;
+    int demo_repeat = (demo->data[i] & 0xf0) >> 4;
+
+    tape.pos[i].action[0] = map_key_SP_to_RND(demo_action);
+    tape.pos[i].delay = demo_repeat + 1;
+  }
+
+  tape.length_seconds = GetTapeLength();
+}
+
+
+/* ------------------------------------------------------------------------- */
+/* functions for loading DC level                                            */
+/* ------------------------------------------------------------------------- */
+
+#define DC_LEVEL_HEADER_SIZE           344
+
+unsigned short getDecodedWord_DC(unsigned short data_encoded, boolean init)
+{
+  static int last_data_encoded;
+  static int offset1;
+  static int offset2;
+  int diff;
+  int diff_hi, diff_lo;
+  int data_hi, data_lo;
+  unsigned short data_decoded;
+
+  if (init)
+  {
+    last_data_encoded = 0;
+    offset1 = -1;
+    offset2 = 0;
+
+    return 0;
+  }
+
+  diff = data_encoded - last_data_encoded;
+  diff_hi = diff & ~0xff;
+  diff_lo = diff &  0xff;
+
+  offset2 += diff_lo;
+
+  data_hi = diff_hi - (offset1 << 8) + (offset2 & 0xff00);
+  data_lo = (diff_lo + (data_hi >> 16)) & 0x00ff;
+  data_hi = data_hi & 0xff00;
+
+  data_decoded = data_hi | data_lo;
+
+  last_data_encoded = data_encoded;
+
+  offset1 = (offset1 + 1) % 31;
+  offset2 = offset2 & 0xff;
+
+  return data_decoded;
+}
+
+int getMappedElement_DC(int element)
+{
+  switch (element)
+  {
+    case 0x0000:
+      element = EL_ROCK;
+      break;
+
+      /* 0x0117 - 0x036e: (?) */
+      /* EL_DIAMOND */
+
+      /* 0x042d - 0x0684: (?) */
+      /* EL_EMERALD */
+
+    case 0x06f1:
+      element = EL_NUT;
+      break;
+
+    case 0x074c:
+      element = EL_BOMB;
+      break;
+
+    case 0x07a4:
+      element = EL_PEARL;
+      break;
+
+    case 0x0823:
+      element = EL_CRYSTAL;
+      break;
+
+    case 0x0e77:       /* quicksand (boulder) */
+      element = EL_QUICKSAND_FAST_FULL;
+      break;
+
+    case 0x0e99:       /* slow quicksand (boulder) */
+      element = EL_QUICKSAND_FULL;
+      break;
+
+    case 0x0ed2:
+      element = EL_EM_EXIT_OPEN;
+      break;
+
+    case 0x0ee3:
+      element = EL_EM_EXIT_CLOSED;
+      break;
+
+    case 0x0eeb:
+      element = EL_EM_STEEL_EXIT_OPEN;
+      break;
+
+    case 0x0efc:
+      element = EL_EM_STEEL_EXIT_CLOSED;
+      break;
+
+    case 0x0f4f:       /* dynamite (lit 1) */
+      element = EL_EM_DYNAMITE_ACTIVE;
+      break;
+
+    case 0x0f57:       /* dynamite (lit 2) */
+      element = EL_EM_DYNAMITE_ACTIVE;
+      break;
+
+    case 0x0f5f:       /* dynamite (lit 3) */
+      element = EL_EM_DYNAMITE_ACTIVE;
+      break;
+
+    case 0x0f67:       /* dynamite (lit 4) */
+      element = EL_EM_DYNAMITE_ACTIVE;
+      break;
+
+    case 0x0f81:
+    case 0x0f82:
+    case 0x0f83:
+    case 0x0f84:
+      element = EL_AMOEBA_WET;
+      break;
+
+    case 0x0f85:
+      element = EL_AMOEBA_DROP;
+      break;
+
+    case 0x0fb9:
+      element = EL_DC_MAGIC_WALL;
+      break;
+
+    case 0x0fd0:
+      element = EL_SPACESHIP_UP;
+      break;
+
+    case 0x0fd9:
+      element = EL_SPACESHIP_DOWN;
+      break;
+
+    case 0x0ff1:
+      element = EL_SPACESHIP_LEFT;
+      break;
+
+    case 0x0ff9:
+      element = EL_SPACESHIP_RIGHT;
+      break;
+
+    case 0x1057:
+      element = EL_BUG_UP;
+      break;
+
+    case 0x1060:
+      element = EL_BUG_DOWN;
+      break;
+
+    case 0x1078:
+      element = EL_BUG_LEFT;
+      break;
+
+    case 0x1080:
+      element = EL_BUG_RIGHT;
+      break;
+
+    case 0x10de:
+      element = EL_MOLE_UP;
+      break;
+
+    case 0x10e7:
+      element = EL_MOLE_DOWN;
+      break;
+
+    case 0x10ff:
+      element = EL_MOLE_LEFT;
+      break;
+
+    case 0x1107:
+      element = EL_MOLE_RIGHT;
+      break;
+
+    case 0x11c0:
+      element = EL_ROBOT;
+      break;
+
+    case 0x13f5:
+      element = EL_YAMYAM;
+      break;
+
+    case 0x1425:
+      element = EL_SWITCHGATE_OPEN;
+      break;
+
+    case 0x1426:
+      element = EL_SWITCHGATE_CLOSED;
+      break;
+
+    case 0x1437:
+      element = EL_DC_SWITCHGATE_SWITCH_UP;
+      break;
+
+    case 0x143a:
+      element = EL_TIMEGATE_CLOSED;
+      break;
+
+    case 0x144c:       /* conveyor belt switch (green) */
+      element = EL_CONVEYOR_BELT_3_SWITCH_MIDDLE;
+      break;
+
+    case 0x144f:       /* conveyor belt switch (red) */
+      element = EL_CONVEYOR_BELT_1_SWITCH_MIDDLE;
+      break;
+
+    case 0x1452:       /* conveyor belt switch (blue) */
+      element = EL_CONVEYOR_BELT_4_SWITCH_MIDDLE;
+      break;
+
+    case 0x145b:
+      element = EL_CONVEYOR_BELT_3_MIDDLE;
+      break;
+
+    case 0x1463:
+      element = EL_CONVEYOR_BELT_3_LEFT;
+      break;
+
+    case 0x146b:
+      element = EL_CONVEYOR_BELT_3_RIGHT;
+      break;
+
+    case 0x1473:
+      element = EL_CONVEYOR_BELT_1_MIDDLE;
+      break;
+
+    case 0x147b:
+      element = EL_CONVEYOR_BELT_1_LEFT;
+      break;
+
+    case 0x1483:
+      element = EL_CONVEYOR_BELT_1_RIGHT;
+      break;
+
+    case 0x148b:
+      element = EL_CONVEYOR_BELT_4_MIDDLE;
+      break;
+
+    case 0x1493:
+      element = EL_CONVEYOR_BELT_4_LEFT;
+      break;
+
+    case 0x149b:
+      element = EL_CONVEYOR_BELT_4_RIGHT;
+      break;
+
+    case 0x14ac:
+      element = EL_EXPANDABLE_WALL_HORIZONTAL;
+      break;
+
+    case 0x14bd:
+      element = EL_EXPANDABLE_WALL_VERTICAL;
+      break;
+
+    case 0x14c6:
+      element = EL_EXPANDABLE_WALL_ANY;
+      break;
+
+    case 0x14ce:       /* growing steel wall (left/right) */
+      element = EL_EXPANDABLE_STEELWALL_HORIZONTAL;
+      break;
+
+    case 0x14df:       /* growing steel wall (up/down) */
+      element = EL_EXPANDABLE_STEELWALL_VERTICAL;
+      break;
+
+    case 0x14e8:       /* growing steel wall (up/down/left/right) */
+      element = EL_EXPANDABLE_STEELWALL_ANY;
+      break;
+
+    case 0x14e9:
+      element = EL_SHIELD_DEADLY;
+      break;
+
+    case 0x1501:
+      element = EL_EXTRA_TIME;
+      break;
+
+    case 0x154f:
+      element = EL_ACID;
+      break;
+
+    case 0x1577:
+      element = EL_EMPTY_SPACE;
+      break;
+
+    case 0x1578:       /* quicksand (empty) */
+      element = EL_QUICKSAND_FAST_EMPTY;
+      break;
+
+    case 0x1579:       /* slow quicksand (empty) */
+      element = EL_QUICKSAND_EMPTY;
+      break;
+
+      /* 0x157c - 0x158b: */
+      /* EL_SAND */
+
+      /* 0x1590 - 0x159f: */
+      /* EL_DC_LANDMINE */
+
+    case 0x15a0:
+      element = EL_EM_DYNAMITE;
+      break;
+
+    case 0x15a1:       /* key (red) */
+      element = EL_EM_KEY_1;
+      break;
+
+    case 0x15a2:       /* key (yellow) */
+      element = EL_EM_KEY_2;
+      break;
+
+    case 0x15a3:       /* key (blue) */
+      element = EL_EM_KEY_4;
+      break;
+
+    case 0x15a4:       /* key (green) */
+      element = EL_EM_KEY_3;
+      break;
+
+    case 0x15a5:       /* key (white) */
+      element = EL_DC_KEY_WHITE;
+      break;
+
+    case 0x15a6:
+      element = EL_WALL_SLIPPERY;
+      break;
+
+    case 0x15a7:
+      element = EL_WALL;
+      break;
+
+    case 0x15a8:       /* wall (not round) */
+      element = EL_WALL;
+      break;
+
+    case 0x15a9:       /* (blue) */
+      element = EL_CHAR_A;
+      break;
+
+    case 0x15aa:       /* (blue) */
+      element = EL_CHAR_B;
+      break;
+
+    case 0x15ab:       /* (blue) */
+      element = EL_CHAR_C;
+      break;
+
+    case 0x15ac:       /* (blue) */
+      element = EL_CHAR_D;
+      break;
+
+    case 0x15ad:       /* (blue) */
+      element = EL_CHAR_E;
+      break;
+
+    case 0x15ae:       /* (blue) */
+      element = EL_CHAR_F;
+      break;
+
+    case 0x15af:       /* (blue) */
+      element = EL_CHAR_G;
+      break;
+
+    case 0x15b0:       /* (blue) */
+      element = EL_CHAR_H;
+      break;
+
+    case 0x15b1:       /* (blue) */
+      element = EL_CHAR_I;
+      break;
+
+    case 0x15b2:       /* (blue) */
+      element = EL_CHAR_J;
+      break;
+
+    case 0x15b3:       /* (blue) */
+      element = EL_CHAR_K;
+      break;
+
+    case 0x15b4:       /* (blue) */
+      element = EL_CHAR_L;
+      break;
+
+    case 0x15b5:       /* (blue) */
+      element = EL_CHAR_M;
+      break;
+
+    case 0x15b6:       /* (blue) */
+      element = EL_CHAR_N;
+      break;
+
+    case 0x15b7:       /* (blue) */
+      element = EL_CHAR_O;
+      break;
+
+    case 0x15b8:       /* (blue) */
+      element = EL_CHAR_P;
+      break;
+
+    case 0x15b9:       /* (blue) */
+      element = EL_CHAR_Q;
+      break;
+
+    case 0x15ba:       /* (blue) */
+      element = EL_CHAR_R;
+      break;
+
+    case 0x15bb:       /* (blue) */
+      element = EL_CHAR_S;
+      break;
+
+    case 0x15bc:       /* (blue) */
+      element = EL_CHAR_T;
+      break;
+
+    case 0x15bd:       /* (blue) */
+      element = EL_CHAR_U;
+      break;
+
+    case 0x15be:       /* (blue) */
+      element = EL_CHAR_V;
+      break;
+
+    case 0x15bf:       /* (blue) */
+      element = EL_CHAR_W;
+      break;
+
+    case 0x15c0:       /* (blue) */
+      element = EL_CHAR_X;
+      break;
+
+    case 0x15c1:       /* (blue) */
+      element = EL_CHAR_Y;
+      break;
+
+    case 0x15c2:       /* (blue) */
+      element = EL_CHAR_Z;
+      break;
+
+    case 0x15c3:       /* (blue) */
+      element = EL_CHAR_AUMLAUT;
+      break;
+
+    case 0x15c4:       /* (blue) */
+      element = EL_CHAR_OUMLAUT;
+      break;
+
+    case 0x15c5:       /* (blue) */
+      element = EL_CHAR_UUMLAUT;
+      break;
+
+    case 0x15c6:       /* (blue) */
+      element = EL_CHAR_0;
+      break;
+
+    case 0x15c7:       /* (blue) */
+      element = EL_CHAR_1;
+      break;
+
+    case 0x15c8:       /* (blue) */
+      element = EL_CHAR_2;
+      break;
+
+    case 0x15c9:       /* (blue) */
+      element = EL_CHAR_3;
+      break;
+
+    case 0x15ca:       /* (blue) */
+      element = EL_CHAR_4;
+      break;
+
+    case 0x15cb:       /* (blue) */
+      element = EL_CHAR_5;
+      break;
+
+    case 0x15cc:       /* (blue) */
+      element = EL_CHAR_6;
+      break;
+
+    case 0x15cd:       /* (blue) */
+      element = EL_CHAR_7;
+      break;
+
+    case 0x15ce:       /* (blue) */
+      element = EL_CHAR_8;
+      break;
+
+    case 0x15cf:       /* (blue) */
+      element = EL_CHAR_9;
+      break;
+
+    case 0x15d0:       /* (blue) */
+      element = EL_CHAR_PERIOD;
+      break;
+
+    case 0x15d1:       /* (blue) */
+      element = EL_CHAR_EXCLAM;
+      break;
+
+    case 0x15d2:       /* (blue) */
+      element = EL_CHAR_COLON;
+      break;
+
+    case 0x15d3:       /* (blue) */
+      element = EL_CHAR_LESS;
+      break;
+
+    case 0x15d4:       /* (blue) */
+      element = EL_CHAR_GREATER;
+      break;
+
+    case 0x15d5:       /* (blue) */
+      element = EL_CHAR_QUESTION;
+      break;
+
+    case 0x15d6:       /* (blue) */
+      element = EL_CHAR_COPYRIGHT;
+      break;
+
+    case 0x15d7:       /* (blue) */
+      element = EL_CHAR_UP;
+      break;
+
+    case 0x15d8:       /* (blue) */
+      element = EL_CHAR_DOWN;
+      break;
+
+    case 0x15d9:       /* (blue) */
+      element = EL_CHAR_BUTTON;
+      break;
+
+    case 0x15da:       /* (blue) */
+      element = EL_CHAR_PLUS;
+      break;
+
+    case 0x15db:       /* (blue) */
+      element = EL_CHAR_MINUS;
+      break;
+
+    case 0x15dc:       /* (blue) */
+      element = EL_CHAR_APOSTROPHE;
+      break;
+
+    case 0x15dd:       /* (blue) */
+      element = EL_CHAR_PARENLEFT;
+      break;
+
+    case 0x15de:       /* (blue) */
+      element = EL_CHAR_PARENRIGHT;
+      break;
+
+    case 0x15df:       /* (green) */
+      element = EL_CHAR_A;
+      break;
+
+    case 0x15e0:       /* (green) */
+      element = EL_CHAR_B;
+      break;
+
+    case 0x15e1:       /* (green) */
+      element = EL_CHAR_C;
+      break;
+
+    case 0x15e2:       /* (green) */
+      element = EL_CHAR_D;
+      break;
+
+    case 0x15e3:       /* (green) */
+      element = EL_CHAR_E;
+      break;
+
+    case 0x15e4:       /* (green) */
+      element = EL_CHAR_F;
+      break;
+
+    case 0x15e5:       /* (green) */
+      element = EL_CHAR_G;
+      break;
+
+    case 0x15e6:       /* (green) */
+      element = EL_CHAR_H;
+      break;
+
+    case 0x15e7:       /* (green) */
+      element = EL_CHAR_I;
+      break;
+
+    case 0x15e8:       /* (green) */
+      element = EL_CHAR_J;
+      break;
+
+    case 0x15e9:       /* (green) */
+      element = EL_CHAR_K;
+      break;
+
+    case 0x15ea:       /* (green) */
+      element = EL_CHAR_L;
+      break;
+
+    case 0x15eb:       /* (green) */
+      element = EL_CHAR_M;
+      break;
+
+    case 0x15ec:       /* (green) */
+      element = EL_CHAR_N;
+      break;
+
+    case 0x15ed:       /* (green) */
+      element = EL_CHAR_O;
+      break;
+
+    case 0x15ee:       /* (green) */
+      element = EL_CHAR_P;
+      break;
+
+    case 0x15ef:       /* (green) */
+      element = EL_CHAR_Q;
+      break;
+
+    case 0x15f0:       /* (green) */
+      element = EL_CHAR_R;
+      break;
+
+    case 0x15f1:       /* (green) */
+      element = EL_CHAR_S;
+      break;
+
+    case 0x15f2:       /* (green) */
+      element = EL_CHAR_T;
+      break;
+
+    case 0x15f3:       /* (green) */
+      element = EL_CHAR_U;
+      break;
+
+    case 0x15f4:       /* (green) */
+      element = EL_CHAR_V;
+      break;
+
+    case 0x15f5:       /* (green) */
+      element = EL_CHAR_W;
+      break;
+
+    case 0x15f6:       /* (green) */
+      element = EL_CHAR_X;
+      break;
+
+    case 0x15f7:       /* (green) */
+      element = EL_CHAR_Y;
+      break;
+
+    case 0x15f8:       /* (green) */
+      element = EL_CHAR_Z;
+      break;
+
+    case 0x15f9:       /* (green) */
+      element = EL_CHAR_AUMLAUT;
+      break;
+
+    case 0x15fa:       /* (green) */
+      element = EL_CHAR_OUMLAUT;
+      break;
+
+    case 0x15fb:       /* (green) */
+      element = EL_CHAR_UUMLAUT;
+      break;
+
+    case 0x15fc:       /* (green) */
+      element = EL_CHAR_0;
+      break;
+
+    case 0x15fd:       /* (green) */
+      element = EL_CHAR_1;
+      break;
+
+    case 0x15fe:       /* (green) */
+      element = EL_CHAR_2;
+      break;
+
+    case 0x15ff:       /* (green) */
+      element = EL_CHAR_3;
+      break;
+
+    case 0x1600:       /* (green) */
+      element = EL_CHAR_4;
+      break;
+
+    case 0x1601:       /* (green) */
+      element = EL_CHAR_5;
+      break;
+
+    case 0x1602:       /* (green) */
+      element = EL_CHAR_6;
+      break;
+
+    case 0x1603:       /* (green) */
+      element = EL_CHAR_7;
+      break;
+
+    case 0x1604:       /* (green) */
+      element = EL_CHAR_8;
+      break;
+
+    case 0x1605:       /* (green) */
+      element = EL_CHAR_9;
+      break;
+
+    case 0x1606:       /* (green) */
+      element = EL_CHAR_PERIOD;
+      break;
+
+    case 0x1607:       /* (green) */
+      element = EL_CHAR_EXCLAM;
+      break;
+
+    case 0x1608:       /* (green) */
+      element = EL_CHAR_COLON;
+      break;
+
+    case 0x1609:       /* (green) */
+      element = EL_CHAR_LESS;
+      break;
+
+    case 0x160a:       /* (green) */
+      element = EL_CHAR_GREATER;
+      break;
+
+    case 0x160b:       /* (green) */
+      element = EL_CHAR_QUESTION;
+      break;
+
+    case 0x160c:       /* (green) */
+      element = EL_CHAR_COPYRIGHT;
+      break;
+
+    case 0x160d:       /* (green) */
+      element = EL_CHAR_UP;
+      break;
+
+    case 0x160e:       /* (green) */
+      element = EL_CHAR_DOWN;
+      break;
+
+    case 0x160f:       /* (green) */
+      element = EL_CHAR_BUTTON;
+      break;
+
+    case 0x1610:       /* (green) */
+      element = EL_CHAR_PLUS;
+      break;
+
+    case 0x1611:       /* (green) */
+      element = EL_CHAR_MINUS;
+      break;
+
+    case 0x1612:       /* (green) */
+      element = EL_CHAR_APOSTROPHE;
+      break;
+
+    case 0x1613:       /* (green) */
+      element = EL_CHAR_PARENLEFT;
+      break;
+
+    case 0x1614:       /* (green) */
+      element = EL_CHAR_PARENRIGHT;
+      break;
+
+    case 0x1615:       /* (blue steel) */
+      element = EL_STEEL_CHAR_A;
+      break;
+
+    case 0x1616:       /* (blue steel) */
+      element = EL_STEEL_CHAR_B;
+      break;
+
+    case 0x1617:       /* (blue steel) */
+      element = EL_STEEL_CHAR_C;
+      break;
+
+    case 0x1618:       /* (blue steel) */
+      element = EL_STEEL_CHAR_D;
+      break;
+
+    case 0x1619:       /* (blue steel) */
+      element = EL_STEEL_CHAR_E;
+      break;
+
+    case 0x161a:       /* (blue steel) */
+      element = EL_STEEL_CHAR_F;
+      break;
+
+    case 0x161b:       /* (blue steel) */
+      element = EL_STEEL_CHAR_G;
+      break;
+
+    case 0x161c:       /* (blue steel) */
+      element = EL_STEEL_CHAR_H;
+      break;
+
+    case 0x161d:       /* (blue steel) */
+      element = EL_STEEL_CHAR_I;
+      break;
+
+    case 0x161e:       /* (blue steel) */
+      element = EL_STEEL_CHAR_J;
+      break;
+
+    case 0x161f:       /* (blue steel) */
+      element = EL_STEEL_CHAR_K;
+      break;
+
+    case 0x1620:       /* (blue steel) */
+      element = EL_STEEL_CHAR_L;
+      break;
+
+    case 0x1621:       /* (blue steel) */
+      element = EL_STEEL_CHAR_M;
+      break;
+
+    case 0x1622:       /* (blue steel) */
+      element = EL_STEEL_CHAR_N;
+      break;
+
+    case 0x1623:       /* (blue steel) */
+      element = EL_STEEL_CHAR_O;
+      break;
+
+    case 0x1624:       /* (blue steel) */
+      element = EL_STEEL_CHAR_P;
+      break;
+
+    case 0x1625:       /* (blue steel) */
+      element = EL_STEEL_CHAR_Q;
+      break;
+
+    case 0x1626:       /* (blue steel) */
+      element = EL_STEEL_CHAR_R;
+      break;
+
+    case 0x1627:       /* (blue steel) */
+      element = EL_STEEL_CHAR_S;
+      break;
+
+    case 0x1628:       /* (blue steel) */
+      element = EL_STEEL_CHAR_T;
+      break;
+
+    case 0x1629:       /* (blue steel) */
+      element = EL_STEEL_CHAR_U;
+      break;
+
+    case 0x162a:       /* (blue steel) */
+      element = EL_STEEL_CHAR_V;
+      break;
+
+    case 0x162b:       /* (blue steel) */
+      element = EL_STEEL_CHAR_W;
+      break;
+
+    case 0x162c:       /* (blue steel) */
+      element = EL_STEEL_CHAR_X;
+      break;
+
+    case 0x162d:       /* (blue steel) */
+      element = EL_STEEL_CHAR_Y;
+      break;
+
+    case 0x162e:       /* (blue steel) */
+      element = EL_STEEL_CHAR_Z;
+      break;
+
+    case 0x162f:       /* (blue steel) */
+      element = EL_STEEL_CHAR_AUMLAUT;
+      break;
+
+    case 0x1630:       /* (blue steel) */
+      element = EL_STEEL_CHAR_OUMLAUT;
+      break;
+
+    case 0x1631:       /* (blue steel) */
+      element = EL_STEEL_CHAR_UUMLAUT;
+      break;
+
+    case 0x1632:       /* (blue steel) */
+      element = EL_STEEL_CHAR_0;
+      break;
+
+    case 0x1633:       /* (blue steel) */
+      element = EL_STEEL_CHAR_1;
+      break;
+
+    case 0x1634:       /* (blue steel) */
+      element = EL_STEEL_CHAR_2;
+      break;
+
+    case 0x1635:       /* (blue steel) */
+      element = EL_STEEL_CHAR_3;
+      break;
+
+    case 0x1636:       /* (blue steel) */
+      element = EL_STEEL_CHAR_4;
+      break;
+
+    case 0x1637:       /* (blue steel) */
+      element = EL_STEEL_CHAR_5;
+      break;
+
+    case 0x1638:       /* (blue steel) */
+      element = EL_STEEL_CHAR_6;
+      break;
+
+    case 0x1639:       /* (blue steel) */
+      element = EL_STEEL_CHAR_7;
+      break;
+
+    case 0x163a:       /* (blue steel) */
+      element = EL_STEEL_CHAR_8;
+      break;
+
+    case 0x163b:       /* (blue steel) */
+      element = EL_STEEL_CHAR_9;
+      break;
+
+    case 0x163c:       /* (blue steel) */
+      element = EL_STEEL_CHAR_PERIOD;
+      break;
+
+    case 0x163d:       /* (blue steel) */
+      element = EL_STEEL_CHAR_EXCLAM;
+      break;
+
+    case 0x163e:       /* (blue steel) */
+      element = EL_STEEL_CHAR_COLON;
+      break;
+
+    case 0x163f:       /* (blue steel) */
+      element = EL_STEEL_CHAR_LESS;
+      break;
+
+    case 0x1640:       /* (blue steel) */
+      element = EL_STEEL_CHAR_GREATER;
+      break;
+
+    case 0x1641:       /* (blue steel) */
+      element = EL_STEEL_CHAR_QUESTION;
+      break;
+
+    case 0x1642:       /* (blue steel) */
+      element = EL_STEEL_CHAR_COPYRIGHT;
+      break;
+
+    case 0x1643:       /* (blue steel) */
+      element = EL_STEEL_CHAR_UP;
+      break;
+
+    case 0x1644:       /* (blue steel) */
+      element = EL_STEEL_CHAR_DOWN;
+      break;
+
+    case 0x1645:       /* (blue steel) */
+      element = EL_STEEL_CHAR_BUTTON;
+      break;
+
+    case 0x1646:       /* (blue steel) */
+      element = EL_STEEL_CHAR_PLUS;
+      break;
+
+    case 0x1647:       /* (blue steel) */
+      element = EL_STEEL_CHAR_MINUS;
+      break;
+
+    case 0x1648:       /* (blue steel) */
+      element = EL_STEEL_CHAR_APOSTROPHE;
+      break;
+
+    case 0x1649:       /* (blue steel) */
+      element = EL_STEEL_CHAR_PARENLEFT;
+      break;
+
+    case 0x164a:       /* (blue steel) */
+      element = EL_STEEL_CHAR_PARENRIGHT;
+      break;
+
+    case 0x164b:       /* (green steel) */
+      element = EL_STEEL_CHAR_A;
+      break;
+
+    case 0x164c:       /* (green steel) */
+      element = EL_STEEL_CHAR_B;
+      break;
+
+    case 0x164d:       /* (green steel) */
+      element = EL_STEEL_CHAR_C;
+      break;
+
+    case 0x164e:       /* (green steel) */
+      element = EL_STEEL_CHAR_D;
+      break;
+
+    case 0x164f:       /* (green steel) */
+      element = EL_STEEL_CHAR_E;
+      break;
+
+    case 0x1650:       /* (green steel) */
+      element = EL_STEEL_CHAR_F;
+      break;
+
+    case 0x1651:       /* (green steel) */
+      element = EL_STEEL_CHAR_G;
+      break;
+
+    case 0x1652:       /* (green steel) */
+      element = EL_STEEL_CHAR_H;
+      break;
+
+    case 0x1653:       /* (green steel) */
+      element = EL_STEEL_CHAR_I;
+      break;
+
+    case 0x1654:       /* (green steel) */
+      element = EL_STEEL_CHAR_J;
+      break;
+
+    case 0x1655:       /* (green steel) */
+      element = EL_STEEL_CHAR_K;
+      break;
+
+    case 0x1656:       /* (green steel) */
+      element = EL_STEEL_CHAR_L;
+      break;
+
+    case 0x1657:       /* (green steel) */
+      element = EL_STEEL_CHAR_M;
+      break;
+
+    case 0x1658:       /* (green steel) */
+      element = EL_STEEL_CHAR_N;
+      break;
+
+    case 0x1659:       /* (green steel) */
+      element = EL_STEEL_CHAR_O;
+      break;
+
+    case 0x165a:       /* (green steel) */
+      element = EL_STEEL_CHAR_P;
+      break;
+
+    case 0x165b:       /* (green steel) */
+      element = EL_STEEL_CHAR_Q;
+      break;
+
+    case 0x165c:       /* (green steel) */
+      element = EL_STEEL_CHAR_R;
+      break;
+
+    case 0x165d:       /* (green steel) */
+      element = EL_STEEL_CHAR_S;
+      break;
+
+    case 0x165e:       /* (green steel) */
+      element = EL_STEEL_CHAR_T;
+      break;
+
+    case 0x165f:       /* (green steel) */
+      element = EL_STEEL_CHAR_U;
+      break;
+
+    case 0x1660:       /* (green steel) */
+      element = EL_STEEL_CHAR_V;
+      break;
+
+    case 0x1661:       /* (green steel) */
+      element = EL_STEEL_CHAR_W;
+      break;
+
+    case 0x1662:       /* (green steel) */
+      element = EL_STEEL_CHAR_X;
+      break;
+
+    case 0x1663:       /* (green steel) */
+      element = EL_STEEL_CHAR_Y;
+      break;
+
+    case 0x1664:       /* (green steel) */
+      element = EL_STEEL_CHAR_Z;
+      break;
+
+    case 0x1665:       /* (green steel) */
+      element = EL_STEEL_CHAR_AUMLAUT;
+      break;
+
+    case 0x1666:       /* (green steel) */
+      element = EL_STEEL_CHAR_OUMLAUT;
+      break;
+
+    case 0x1667:       /* (green steel) */
+      element = EL_STEEL_CHAR_UUMLAUT;
+      break;
+
+    case 0x1668:       /* (green steel) */
+      element = EL_STEEL_CHAR_0;
+      break;
+
+    case 0x1669:       /* (green steel) */
+      element = EL_STEEL_CHAR_1;
+      break;
+
+    case 0x166a:       /* (green steel) */
+      element = EL_STEEL_CHAR_2;
+      break;
+
+    case 0x166b:       /* (green steel) */
+      element = EL_STEEL_CHAR_3;
+      break;
+
+    case 0x166c:       /* (green steel) */
+      element = EL_STEEL_CHAR_4;
+      break;
+
+    case 0x166d:       /* (green steel) */
+      element = EL_STEEL_CHAR_5;
+      break;
+
+    case 0x166e:       /* (green steel) */
+      element = EL_STEEL_CHAR_6;
+      break;
+
+    case 0x166f:       /* (green steel) */
+      element = EL_STEEL_CHAR_7;
+      break;
+
+    case 0x1670:       /* (green steel) */
+      element = EL_STEEL_CHAR_8;
+      break;
+
+    case 0x1671:       /* (green steel) */
+      element = EL_STEEL_CHAR_9;
+      break;
+
+    case 0x1672:       /* (green steel) */
+      element = EL_STEEL_CHAR_PERIOD;
+      break;
+
+    case 0x1673:       /* (green steel) */
+      element = EL_STEEL_CHAR_EXCLAM;
+      break;
+
+    case 0x1674:       /* (green steel) */
+      element = EL_STEEL_CHAR_COLON;
+      break;
+
+    case 0x1675:       /* (green steel) */
+      element = EL_STEEL_CHAR_LESS;
+      break;
+
+    case 0x1676:       /* (green steel) */
+      element = EL_STEEL_CHAR_GREATER;
+      break;
+
+    case 0x1677:       /* (green steel) */
+      element = EL_STEEL_CHAR_QUESTION;
+      break;
+
+    case 0x1678:       /* (green steel) */
+      element = EL_STEEL_CHAR_COPYRIGHT;
+      break;
+
+    case 0x1679:       /* (green steel) */
+      element = EL_STEEL_CHAR_UP;
+      break;
+
+    case 0x167a:       /* (green steel) */
+      element = EL_STEEL_CHAR_DOWN;
+      break;
+
+    case 0x167b:       /* (green steel) */
+      element = EL_STEEL_CHAR_BUTTON;
+      break;
+
+    case 0x167c:       /* (green steel) */
+      element = EL_STEEL_CHAR_PLUS;
+      break;
+
+    case 0x167d:       /* (green steel) */
+      element = EL_STEEL_CHAR_MINUS;
+      break;
+
+    case 0x167e:       /* (green steel) */
+      element = EL_STEEL_CHAR_APOSTROPHE;
+      break;
+
+    case 0x167f:       /* (green steel) */
+      element = EL_STEEL_CHAR_PARENLEFT;
+      break;
+
+    case 0x1680:       /* (green steel) */
+      element = EL_STEEL_CHAR_PARENRIGHT;
+      break;
+
+    case 0x1681:       /* gate (red) */
+      element = EL_EM_GATE_1;
+      break;
+
+    case 0x1682:       /* secret gate (red) */
+      element = EL_GATE_1_GRAY;
+      break;
+
+    case 0x1683:       /* gate (yellow) */
+      element = EL_EM_GATE_2;
+      break;
+
+    case 0x1684:       /* secret gate (yellow) */
+      element = EL_GATE_2_GRAY;
+      break;
+
+    case 0x1685:       /* gate (blue) */
+      element = EL_EM_GATE_4;
+      break;
+
+    case 0x1686:       /* secret gate (blue) */
+      element = EL_GATE_4_GRAY;
+      break;
+
+    case 0x1687:       /* gate (green) */
+      element = EL_EM_GATE_3;
+      break;
+
+    case 0x1688:       /* secret gate (green) */
+      element = EL_GATE_3_GRAY;
+      break;
+
+    case 0x1689:       /* gate (white) */
+      element = EL_DC_GATE_WHITE;
+      break;
+
+    case 0x168a:       /* secret gate (white) */
+      element = EL_DC_GATE_WHITE_GRAY;
+      break;
+
+    case 0x168b:       /* secret gate (no key) */
+      element = EL_DC_GATE_FAKE_GRAY;
+      break;
+
+    case 0x168c:
+      element = EL_ROBOT_WHEEL;
+      break;
+
+    case 0x168d:
+      element = EL_DC_TIMEGATE_SWITCH;
+      break;
+
+    case 0x168e:
+      element = EL_ACID_POOL_BOTTOM;
+      break;
+
+    case 0x168f:
+      element = EL_ACID_POOL_TOPLEFT;
+      break;
+
+    case 0x1690:
+      element = EL_ACID_POOL_TOPRIGHT;
+      break;
+
+    case 0x1691:
+      element = EL_ACID_POOL_BOTTOMLEFT;
+      break;
+
+    case 0x1692:
+      element = EL_ACID_POOL_BOTTOMRIGHT;
+      break;
+
+    case 0x1693:
+      element = EL_STEELWALL;
+      break;
+
+    case 0x1694:
+      element = EL_STEELWALL_SLIPPERY;
+      break;
+
+    case 0x1695:       /* steel wall (not round) */
+      element = EL_STEELWALL;
+      break;
+
+    case 0x1696:       /* steel wall (left) */
+      element = EL_DC_STEELWALL_1_LEFT;
+      break;
+
+    case 0x1697:       /* steel wall (bottom) */
+      element = EL_DC_STEELWALL_1_BOTTOM;
+      break;
+
+    case 0x1698:       /* steel wall (right) */
+      element = EL_DC_STEELWALL_1_RIGHT;
+      break;
+
+    case 0x1699:       /* steel wall (top) */
+      element = EL_DC_STEELWALL_1_TOP;
+      break;
+
+    case 0x169a:       /* steel wall (left/bottom) */
+      element = EL_DC_STEELWALL_1_BOTTOMLEFT;
+      break;
+
+    case 0x169b:       /* steel wall (right/bottom) */
+      element = EL_DC_STEELWALL_1_BOTTOMRIGHT;
+      break;
+
+    case 0x169c:       /* steel wall (right/top) */
+      element = EL_DC_STEELWALL_1_TOPRIGHT;
+      break;
+
+    case 0x169d:       /* steel wall (left/top) */
+      element = EL_DC_STEELWALL_1_TOPLEFT;
+      break;
+
+    case 0x169e:       /* steel wall (right/bottom small) */
+      element = EL_DC_STEELWALL_1_BOTTOMRIGHT_2;
+      break;
+
+    case 0x169f:       /* steel wall (left/bottom small) */
+      element = EL_DC_STEELWALL_1_BOTTOMLEFT_2;
+      break;
+
+    case 0x16a0:       /* steel wall (right/top small) */
+      element = EL_DC_STEELWALL_1_TOPRIGHT_2;
+      break;
+
+    case 0x16a1:       /* steel wall (left/top small) */
+      element = EL_DC_STEELWALL_1_TOPLEFT_2;
+      break;
+
+    case 0x16a2:       /* steel wall (left/right) */
+      element = EL_DC_STEELWALL_1_VERTICAL;
+      break;
+
+    case 0x16a3:       /* steel wall (top/bottom) */
+      element = EL_DC_STEELWALL_1_HORIZONTAL;
+      break;
+
+    case 0x16a4:       /* steel wall 2 (left end) */
+      element = EL_DC_STEELWALL_2_LEFT;
+      break;
+
+    case 0x16a5:       /* steel wall 2 (right end) */
+      element = EL_DC_STEELWALL_2_RIGHT;
+      break;
+
+    case 0x16a6:       /* steel wall 2 (top end) */
+      element = EL_DC_STEELWALL_2_TOP;
+      break;
+
+    case 0x16a7:       /* steel wall 2 (bottom end) */
+      element = EL_DC_STEELWALL_2_BOTTOM;
+      break;
+
+    case 0x16a8:       /* steel wall 2 (left/right) */
+      element = EL_DC_STEELWALL_2_HORIZONTAL;
+      break;
+
+    case 0x16a9:       /* steel wall 2 (up/down) */
+      element = EL_DC_STEELWALL_2_VERTICAL;
+      break;
+
+    case 0x16aa:       /* steel wall 2 (mid) */
+      element = EL_DC_STEELWALL_2_MIDDLE;
+      break;
+
+    case 0x16ab:
+      element = EL_SIGN_EXCLAMATION;
+      break;
+
+    case 0x16ac:
+      element = EL_SIGN_RADIOACTIVITY;
+      break;
+
+    case 0x16ad:
+      element = EL_SIGN_STOP;
+      break;
+
+    case 0x16ae:
+      element = EL_SIGN_WHEELCHAIR;
+      break;
+
+    case 0x16af:
+      element = EL_SIGN_PARKING;
+      break;
+
+    case 0x16b0:
+      element = EL_SIGN_NO_ENTRY;
+      break;
+
+    case 0x16b1:
+      element = EL_SIGN_HEART;
+      break;
+
+    case 0x16b2:
+      element = EL_SIGN_GIVE_WAY;
+      break;
+
+    case 0x16b3:
+      element = EL_SIGN_ENTRY_FORBIDDEN;
+      break;
+
+    case 0x16b4:
+      element = EL_SIGN_EMERGENCY_EXIT;
+      break;
+
+    case 0x16b5:
+      element = EL_SIGN_YIN_YANG;
+      break;
+
+    case 0x16b6:
+      element = EL_WALL_EMERALD;
+      break;
+
+    case 0x16b7:
+      element = EL_WALL_DIAMOND;
+      break;
+
+    case 0x16b8:
+      element = EL_WALL_PEARL;
+      break;
+
+    case 0x16b9:
+      element = EL_WALL_CRYSTAL;
+      break;
+
+    case 0x16ba:
+      element = EL_INVISIBLE_WALL;
+      break;
+
+    case 0x16bb:
+      element = EL_INVISIBLE_STEELWALL;
+      break;
+
+      /* 0x16bc - 0x16cb: */
+      /* EL_INVISIBLE_SAND */
+
+    case 0x16cc:
+      element = EL_LIGHT_SWITCH;
+      break;
+
+    case 0x16cd:
+      element = EL_ENVELOPE_1;
+      break;
+
+    default:
+      if (element >= 0x0117 && element <= 0x036e)      /* (?) */
+       element = EL_DIAMOND;
+      else if (element >= 0x042d && element <= 0x0684) /* (?) */
+       element = EL_EMERALD;
+      else if (element >= 0x157c && element <= 0x158b)
+       element = EL_SAND;
+      else if (element >= 0x1590 && element <= 0x159f)
+       element = EL_DC_LANDMINE;
+      else if (element >= 0x16bc && element <= 0x16cb)
+       element = EL_INVISIBLE_SAND;
+      else
+      {
+       Error(ERR_WARN, "unknown Diamond Caves element 0x%04x", element);
+       element = EL_UNKNOWN;
+      }
+      break;
+  }
+
+  return getMappedElement(element);
+}
+
+#if 1
+
+static void LoadLevelFromFileStream_DC(FILE *file, struct LevelInfo *level,
+                                      int nr)
+{
+  byte header[DC_LEVEL_HEADER_SIZE];
+  int envelope_size;
+  int envelope_header_pos = 62;
+  int envelope_content_pos = 94;
+  int level_name_pos = 251;
+  int level_author_pos = 292;
+  int envelope_header_len;
+  int envelope_content_len;
+  int level_name_len;
+  int level_author_len;
+  int fieldx, fieldy;
+  int num_yamyam_contents;
+  int i, x, y;
+
+  getDecodedWord_DC(0, TRUE);          /* initialize DC2 decoding engine */
+
+  for (i = 0; i < DC_LEVEL_HEADER_SIZE / 2; i++)
+  {
+    unsigned short header_word = getDecodedWord_DC(getFile16BitBE(file), FALSE);
+
+    header[i * 2 + 0] = header_word >> 8;
+    header[i * 2 + 1] = header_word & 0xff;
+  }
+
+  /* read some values from level header to check level decoding integrity */
+  fieldx = header[6] | (header[7] << 8);
+  fieldy = header[8] | (header[9] << 8);
+  num_yamyam_contents = header[60] | (header[61] << 8);
+
+  /* do some simple sanity checks to ensure that level was correctly decoded */
+  if (fieldx < 1 || fieldx > 256 ||
+      fieldy < 1 || fieldy > 256 ||
+      num_yamyam_contents < 1 || num_yamyam_contents > 8)
+  {
+    level->no_valid_file = TRUE;
+
+    Error(ERR_WARN, "cannot decode level from stream -- using empty level");
+
+    return;
+  }
+
+  /* maximum envelope header size is 31 bytes */
+  envelope_header_len  = header[envelope_header_pos];
+  /* maximum envelope content size is 110 (156?) bytes */
+  envelope_content_len = header[envelope_content_pos];
+
+  /* maximum level title size is 40 bytes */
+  level_name_len       = MIN(header[level_name_pos],   MAX_LEVEL_NAME_LEN);
+  /* maximum level author size is 30 (51?) bytes */
+  level_author_len     = MIN(header[level_author_pos], MAX_LEVEL_AUTHOR_LEN);
+
+  envelope_size = 0;
+
+  for (i = 0; i < envelope_header_len; i++)
+    if (envelope_size < MAX_ENVELOPE_TEXT_LEN)
+      level->envelope[0].text[envelope_size++] =
+       header[envelope_header_pos + 1 + i];
+
+  if (envelope_header_len > 0 && envelope_content_len > 0)
+  {
+    if (envelope_size < MAX_ENVELOPE_TEXT_LEN)
+      level->envelope[0].text[envelope_size++] = '\n';
+    if (envelope_size < MAX_ENVELOPE_TEXT_LEN)
+      level->envelope[0].text[envelope_size++] = '\n';
+  }
+
+  for (i = 0; i < envelope_content_len; i++)
+    if (envelope_size < MAX_ENVELOPE_TEXT_LEN)
+      level->envelope[0].text[envelope_size++] =
+       header[envelope_content_pos + 1 + i];
+
+  level->envelope[0].text[envelope_size] = '\0';
+
+  level->envelope[0].xsize = MAX_ENVELOPE_XSIZE;
+  level->envelope[0].ysize = 10;
+  level->envelope[0].autowrap = TRUE;
+  level->envelope[0].centered = TRUE;
+
+  for (i = 0; i < level_name_len; i++)
+    level->name[i] = header[level_name_pos + 1 + i];
+  level->name[level_name_len] = '\0';
+
+  for (i = 0; i < level_author_len; i++)
+    level->author[i] = header[level_author_pos + 1 + i];
+  level->author[level_author_len] = '\0';
+
+  num_yamyam_contents = header[60] | (header[61] << 8);
+  level->num_yamyam_contents =
+    MIN(MAX(MIN_ELEMENT_CONTENTS, num_yamyam_contents), MAX_ELEMENT_CONTENTS);
+
+  for (i = 0; i < num_yamyam_contents; i++)
+  {
+    for (y = 0; y < 3; y++) for (x = 0; x < 3; x++)
+    {
+      unsigned short word = getDecodedWord_DC(getFile16BitBE(file), FALSE);
+#if 1
+      int element_dc = ((word & 0xff) << 8) | ((word >> 8) & 0xff);
+#else
+      int element_dc = word;
+#endif
+
+      if (i < MAX_ELEMENT_CONTENTS)
+       level->yamyam_content[i].e[x][y] = getMappedElement_DC(element_dc);
+    }
+  }
+
+  fieldx = header[6] | (header[7] << 8);
+  fieldy = header[8] | (header[9] << 8);
+  level->fieldx = MIN(MAX(MIN_LEV_FIELDX, fieldx), MAX_LEV_FIELDX);
+  level->fieldy = MIN(MAX(MIN_LEV_FIELDY, fieldy), MAX_LEV_FIELDY);
+
+  for (y = 0; y < fieldy; y++) for (x = 0; x < fieldx; x++)
+  {
+    unsigned short word = getDecodedWord_DC(getFile16BitBE(file), FALSE);
+#if 1
+    int element_dc = ((word & 0xff) << 8) | ((word >> 8) & 0xff);
+#else
+    int element_dc = word;
+#endif
+
+    if (x < MAX_LEV_FIELDX && y < MAX_LEV_FIELDY)
+      level->field[x][y] = getMappedElement_DC(element_dc);
+  }
+
+  x = MIN(MAX(0, (header[10] | (header[11] << 8)) - 1), MAX_LEV_FIELDX - 1);
+  y = MIN(MAX(0, (header[12] | (header[13] << 8)) - 1), MAX_LEV_FIELDY - 1);
+  level->field[x][y] = EL_PLAYER_1;
+
+  x = MIN(MAX(0, (header[14] | (header[15] << 8)) - 1), MAX_LEV_FIELDX - 1);
+  y = MIN(MAX(0, (header[16] | (header[17] << 8)) - 1), MAX_LEV_FIELDY - 1);
+  level->field[x][y] = EL_PLAYER_2;
+
+  level->gems_needed           = header[18] | (header[19] << 8);
+
+  level->score[SC_EMERALD]     = header[20] | (header[21] << 8);
+  level->score[SC_DIAMOND]     = header[22] | (header[23] << 8);
+  level->score[SC_PEARL]       = header[24] | (header[25] << 8);
+  level->score[SC_CRYSTAL]     = header[26] | (header[27] << 8);
+  level->score[SC_NUT]         = header[28] | (header[29] << 8);
+  level->score[SC_ROBOT]       = header[30] | (header[31] << 8);
+  level->score[SC_SPACESHIP]   = header[32] | (header[33] << 8);
+  level->score[SC_BUG]         = header[34] | (header[35] << 8);
+  level->score[SC_YAMYAM]      = header[36] | (header[37] << 8);
+  level->score[SC_DYNAMITE]    = header[38] | (header[39] << 8);
+  level->score[SC_KEY]         = header[40] | (header[41] << 8);
+  level->score[SC_TIME_BONUS]  = header[42] | (header[43] << 8);
+
+  level->time                  = header[44] | (header[45] << 8);
+
+  level->amoeba_speed          = header[46] | (header[47] << 8);
+  level->time_light            = header[48] | (header[49] << 8);
+  level->time_timegate         = header[50] | (header[51] << 8);
+  level->time_wheel            = header[52] | (header[53] << 8);
+  level->time_magic_wall       = header[54] | (header[55] << 8);
+  level->extra_time            = header[56] | (header[57] << 8);
+  level->shield_normal_time    = header[58] | (header[59] << 8);
+
+  /* Diamond Caves has the same (strange) behaviour as Emerald Mine that gems
+     can slip down from flat walls, like normal walls and steel walls */
+  level->em_slippery_gems = TRUE;
+
+#if 0
+  /* Diamond Caves II levels are always surrounded by indestructible wall, but
+     not necessarily in a rectangular way -- fill with invisible steel wall */
+
+  /* !!! not always true !!! keep level and set BorderElement instead !!! */
+
+  for (y = 0; y < level->fieldy; y++) for (x = 0; x < level->fieldx; x++)
+  {
+#if 1
+    if ((x == 0 || x == level->fieldx - 1 ||
+        y == 0 || y == level->fieldy - 1) &&
+       level->field[x][y] == EL_EMPTY)
+      level->field[x][y] = EL_INVISIBLE_STEELWALL;
+#else
+    if ((x == 0 || x == level->fieldx - 1 ||
+        y == 0 || y == level->fieldy - 1) &&
+       level->field[x][y] == EL_EMPTY)
+      FloodFillLevel(x, y, EL_INVISIBLE_STEELWALL,
+                    level->field, level->fieldx, level->fieldy);
+#endif
+  }
+#endif
+}
+
+static void LoadLevelFromFileInfo_DC(struct LevelInfo *level,
+                                    struct LevelFileInfo *level_file_info)
+{
+  char *filename = level_file_info->filename;
+  FILE *file;
+  int num_magic_bytes = 8;
+  char magic_bytes[num_magic_bytes + 1];
+  int num_levels_to_skip = level_file_info->nr - leveldir_current->first_level;
+
+  if (!(file = fopen(filename, MODE_READ)))
+  {
+    level->no_valid_file = TRUE;
+
+    Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename);
+
+    return;
+  }
+
+  // fseek(file, 0x0000, SEEK_SET);
+
+  if (level_file_info->packed)
+  {
+    /* read "magic bytes" from start of file */
+    fgets(magic_bytes, num_magic_bytes + 1, file);
+
+    /* check "magic bytes" for correct file format */
+    if (!strPrefix(magic_bytes, "DC2"))
+    {
+      level->no_valid_file = TRUE;
+
+      Error(ERR_WARN, "unknown DC level file '%s' -- using empty level",
+           filename);
+
+      return;
+    }
+
+    if (strPrefix(magic_bytes, "DC2Win95") ||
+       strPrefix(magic_bytes, "DC2Win98"))
+    {
+      int position_first_level = 0x00fa;
+      int extra_bytes = 4;
+      int skip_bytes;
+
+      /* advance file stream to first level inside the level package */
+      skip_bytes = position_first_level - num_magic_bytes - extra_bytes;
+
+      /* each block of level data is followed by block of non-level data */
+      num_levels_to_skip *= 2;
+
+      /* at least skip header bytes, therefore use ">= 0" instead of "> 0" */
+      while (num_levels_to_skip >= 0)
+      {
+       /* advance file stream to next level inside the level package */
+       if (fseek(file, skip_bytes, SEEK_CUR) != 0)
+       {
+         level->no_valid_file = TRUE;
+
+         Error(ERR_WARN, "cannot fseek in file '%s' -- using empty level",
+               filename);
+
+         return;
+       }
+
+       /* skip apparently unused extra bytes following each level */
+       ReadUnusedBytesFromFile(file, extra_bytes);
+
+       /* read size of next level in level package */
+       skip_bytes = getFile32BitLE(file);
+
+       num_levels_to_skip--;
+      }
+    }
+    else
+    {
+      level->no_valid_file = TRUE;
+
+      Error(ERR_WARN, "unknown DC2 level file '%s' -- using empty level",
+           filename);
+
+      return;
+    }
+  }
+
+  LoadLevelFromFileStream_DC(file, level, level_file_info->nr);
+
+  fclose(file);
+}
+
+#else
+
+static void LoadLevelFromFileInfo_DC(struct LevelInfo *level,
+                                    struct LevelFileInfo *level_file_info)
+{
+  char *filename = level_file_info->filename;
+  FILE *file;
+#if 0
+  int nr = level_file_info->nr - leveldir_current->first_level;
+#endif
+  byte header[DC_LEVEL_HEADER_SIZE];
+  int envelope_size;
+  int envelope_header_pos = 62;
+  int envelope_content_pos = 94;
+  int level_name_pos = 251;
+  int level_author_pos = 292;
+  int envelope_header_len;
+  int envelope_content_len;
+  int level_name_len;
+  int level_author_len;
+  int fieldx, fieldy;
+  int num_yamyam_contents;
+  int i, x, y;
+
+  if (!(file = fopen(filename, MODE_READ)))
+  {
+    level->no_valid_file = TRUE;
+
+    Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename);
+
+    return;
+  }
+
+#if 0
+  /* position file stream to the requested level inside the level package */
+  if (fseek(file, nr * SP_LEVEL_SIZE, SEEK_SET) != 0)
+  {
+    level->no_valid_file = TRUE;
+
+    Error(ERR_WARN, "cannot fseek in file '%s' -- using empty level", filename);
+
+    return;
+  }
+#endif
+
+  getDecodedWord_DC(0, TRUE);          /* initialize DC2 decoding engine */
+
+  for (i = 0; i < DC_LEVEL_HEADER_SIZE / 2; i++)
+  {
+    unsigned short header_word = getDecodedWord_DC(getFile16BitBE(file), FALSE);
+
+    header[i * 2 + 0] = header_word >> 8;
+    header[i * 2 + 1] = header_word & 0xff;
+  }
+
+  /* read some values from level header to check level decoding integrity */
+  fieldx = header[6] | (header[7] << 8);
+  fieldy = header[8] | (header[9] << 8);
+  num_yamyam_contents = header[60] | (header[61] << 8);
+
+  /* do some simple sanity checks to ensure that level was correctly decoded */
+  if (fieldx < 1 || fieldx > 256 ||
+      fieldy < 1 || fieldy > 256 ||
+      num_yamyam_contents < 1 || num_yamyam_contents > 8)
+  {
+    level->no_valid_file = TRUE;
+
+    Error(ERR_WARN, "cannot read level from file '%s' -- using empty level",
+         filename);
+
+    return;
+  }
+
+  /* maximum envelope header size is 31 bytes */
+  envelope_header_len  = header[envelope_header_pos];
+  /* maximum envelope content size is 110 (156?) bytes */
+  envelope_content_len = header[envelope_content_pos];
+
+  /* maximum level title size is 40 bytes */
+  level_name_len       = MIN(header[level_name_pos],   MAX_LEVEL_NAME_LEN);
+  /* maximum level author size is 30 (51?) bytes */
+  level_author_len     = MIN(header[level_author_pos], MAX_LEVEL_AUTHOR_LEN);
+
+  envelope_size = 0;
+
+  for (i = 0; i < envelope_header_len; i++)
+    if (envelope_size < MAX_ENVELOPE_TEXT_LEN)
+      level->envelope[0].text[envelope_size++] =
+       header[envelope_header_pos + 1 + i];
+
+  if (envelope_header_len > 0 && envelope_content_len > 0)
+  {
+    if (envelope_size < MAX_ENVELOPE_TEXT_LEN)
+      level->envelope[0].text[envelope_size++] = '\n';
+    if (envelope_size < MAX_ENVELOPE_TEXT_LEN)
+      level->envelope[0].text[envelope_size++] = '\n';
+  }
+
+  for (i = 0; i < envelope_content_len; i++)
+    if (envelope_size < MAX_ENVELOPE_TEXT_LEN)
+      level->envelope[0].text[envelope_size++] =
+       header[envelope_content_pos + 1 + i];
+
+  level->envelope[0].text[envelope_size] = '\0';
+
+  level->envelope[0].xsize = MAX_ENVELOPE_XSIZE;
+  level->envelope[0].ysize = 10;
+  level->envelope[0].autowrap = TRUE;
+  level->envelope[0].centered = TRUE;
+
+  for (i = 0; i < level_name_len; i++)
+    level->name[i] = header[level_name_pos + 1 + i];
+  level->name[level_name_len] = '\0';
+
+  for (i = 0; i < level_author_len; i++)
+    level->author[i] = header[level_author_pos + 1 + i];
+  level->author[level_author_len] = '\0';
+
+  num_yamyam_contents = header[60] | (header[61] << 8);
+  level->num_yamyam_contents =
+    MIN(MAX(MIN_ELEMENT_CONTENTS, num_yamyam_contents), MAX_ELEMENT_CONTENTS);
+
+  for (i = 0; i < num_yamyam_contents; i++)
+  {
+    for (y = 0; y < 3; y++) for (x = 0; x < 3; x++)
+    {
+      unsigned short word = getDecodedWord_DC(getFile16BitBE(file), FALSE);
+#if 1
+      int element_dc = ((word & 0xff) << 8) | ((word >> 8) & 0xff);
+#else
+      int element_dc = word;
+#endif
+
+      if (i < MAX_ELEMENT_CONTENTS)
+       level->yamyam_content[i].e[x][y] = getMappedElement_DC(element_dc);
+    }
+  }
+
+  fieldx = header[6] | (header[7] << 8);
+  fieldy = header[8] | (header[9] << 8);
+  level->fieldx = MIN(MAX(MIN_LEV_FIELDX, fieldx), MAX_LEV_FIELDX);
+  level->fieldy = MIN(MAX(MIN_LEV_FIELDY, fieldy), MAX_LEV_FIELDY);
+
+  for (y = 0; y < fieldy; y++) for (x = 0; x < fieldx; x++)
+  {
+    unsigned short word = getDecodedWord_DC(getFile16BitBE(file), FALSE);
+#if 1
+    int element_dc = ((word & 0xff) << 8) | ((word >> 8) & 0xff);
+#else
+    int element_dc = word;
+#endif
+
+    if (x < MAX_LEV_FIELDX && y < MAX_LEV_FIELDY)
+      level->field[x][y] = getMappedElement_DC(element_dc);
+  }
+
+  x = MIN(MAX(0, (header[10] | (header[11] << 8)) - 1), MAX_LEV_FIELDX - 1);
+  y = MIN(MAX(0, (header[12] | (header[13] << 8)) - 1), MAX_LEV_FIELDY - 1);
+  level->field[x][y] = EL_PLAYER_1;
+
+  x = MIN(MAX(0, (header[14] | (header[15] << 8)) - 1), MAX_LEV_FIELDX - 1);
+  y = MIN(MAX(0, (header[16] | (header[17] << 8)) - 1), MAX_LEV_FIELDY - 1);
+  level->field[x][y] = EL_PLAYER_2;
+
+  level->gems_needed           = header[18] | (header[19] << 8);
+
+  level->score[SC_EMERALD]     = header[20] | (header[21] << 8);
+  level->score[SC_DIAMOND]     = header[22] | (header[23] << 8);
+  level->score[SC_PEARL]       = header[24] | (header[25] << 8);
+  level->score[SC_CRYSTAL]     = header[26] | (header[27] << 8);
+  level->score[SC_NUT]         = header[28] | (header[29] << 8);
+  level->score[SC_ROBOT]       = header[30] | (header[31] << 8);
+  level->score[SC_SPACESHIP]   = header[32] | (header[33] << 8);
+  level->score[SC_BUG]         = header[34] | (header[35] << 8);
+  level->score[SC_YAMYAM]      = header[36] | (header[37] << 8);
+  level->score[SC_DYNAMITE]    = header[38] | (header[39] << 8);
+  level->score[SC_KEY]         = header[40] | (header[41] << 8);
+  level->score[SC_TIME_BONUS]  = header[42] | (header[43] << 8);
+
+  level->time                  = header[44] | (header[45] << 8);
+
+  level->amoeba_speed          = header[46] | (header[47] << 8);
+  level->time_light            = header[48] | (header[49] << 8);
+  level->time_timegate         = header[50] | (header[51] << 8);
+  level->time_wheel            = header[52] | (header[53] << 8);
+  level->time_magic_wall       = header[54] | (header[55] << 8);
+  level->extra_time            = header[56] | (header[57] << 8);
+  level->shield_normal_time    = header[58] | (header[59] << 8);
+
+  fclose(file);
+
+  /* Diamond Caves has the same (strange) behaviour as Emerald Mine that gems
+     can slip down from flat walls, like normal walls and steel walls */
+  level->em_slippery_gems = TRUE;
+
+#if 0
+  /* Diamond Caves II levels are always surrounded by indestructible wall, but
+     not necessarily in a rectangular way -- fill with invisible steel wall */
+
+  /* !!! not always true !!! keep level and set BorderElement instead !!! */
+
+  for (y = 0; y < level->fieldy; y++) for (x = 0; x < level->fieldx; x++)
+  {
+#if 1
+    if ((x == 0 || x == level->fieldx - 1 ||
+        y == 0 || y == level->fieldy - 1) &&
+       level->field[x][y] == EL_EMPTY)
+      level->field[x][y] = EL_INVISIBLE_STEELWALL;
+#else
+    if ((x == 0 || x == level->fieldx - 1 ||
+        y == 0 || y == level->fieldy - 1) &&
+       level->field[x][y] == EL_EMPTY)
+      FloodFillLevel(x, y, EL_INVISIBLE_STEELWALL,
+                    level->field, level->fieldx, level->fieldy);
+#endif
+  }
+#endif
+}
+
+#endif
+
+
+/* ------------------------------------------------------------------------- */
+/* functions for loading SB level                                            */
+/* ------------------------------------------------------------------------- */
+
+int getMappedElement_SB(int element_ascii, boolean use_ces)
+{
+  static struct
+  {
+    int ascii;
+    int sb;
+    int ce;
+  }
+  sb_element_mapping[] =
+  {
+    { ' ', EL_EMPTY,                EL_CUSTOM_1 },  /* floor (space) */
+    { '#', EL_STEELWALL,            EL_CUSTOM_2 },  /* wall */
+    { '@', EL_PLAYER_1,             EL_CUSTOM_3 },  /* player */
+    { '$', EL_SOKOBAN_OBJECT,       EL_CUSTOM_4 },  /* box */
+    { '.', EL_SOKOBAN_FIELD_EMPTY,  EL_CUSTOM_5 },  /* goal square */
+    { '*', EL_SOKOBAN_FIELD_FULL,   EL_CUSTOM_6 },  /* box on goal square */
+    { '+', EL_SOKOBAN_FIELD_PLAYER, EL_CUSTOM_7 },  /* player on goal square */
+#if 0
+    { '_', EL_INVISIBLE_STEELWALL,  EL_CUSTOM_8 },  /* floor beyond border */
+#else
+    { '_', EL_INVISIBLE_STEELWALL,  EL_FROM_LEVEL_TEMPLATE },  /* floor beyond border */
+#endif
+
+    { 0,   -1,                      -1          },
+  };
+
+  int i;
+
+  for (i = 0; sb_element_mapping[i].ascii != 0; i++)
+    if (element_ascii == sb_element_mapping[i].ascii)
+      return (use_ces ? sb_element_mapping[i].ce : sb_element_mapping[i].sb);
+
+  return EL_UNDEFINED;
+}
+
+static void LoadLevelFromFileInfo_SB(struct LevelInfo *level,
+                                    struct LevelFileInfo *level_file_info)
+{
+  char *filename = level_file_info->filename;
+  char line[MAX_LINE_LEN], line_raw[MAX_LINE_LEN], previous_line[MAX_LINE_LEN];
+  char last_comment[MAX_LINE_LEN];
+  char level_name[MAX_LINE_LEN];
+  char *line_ptr;
+  FILE *file;
+  int num_levels_to_skip = level_file_info->nr - leveldir_current->first_level;
+  boolean read_continued_line = FALSE;
+  boolean reading_playfield = FALSE;
+  boolean got_valid_playfield_line = FALSE;
+  boolean invalid_playfield_char = FALSE;
+  boolean load_xsb_to_ces = check_special_flags("load_xsb_to_ces");
+  int file_level_nr = 0;
+  int line_nr = 0;
+  int x = 0, y = 0;            /* initialized to make compilers happy */
+
+#if 0
+  printf("::: looking for level number %d [%d]\n",
+        level_file_info->nr, num_levels_to_skip);
+#endif
+
+  last_comment[0] = '\0';
+  level_name[0] = '\0';
+
+  if (!(file = fopen(filename, MODE_READ)))
+  {
+    level->no_valid_file = TRUE;
+
+    Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename);
+
+    return;
+  }
+
+  while (!feof(file))
+  {
+    /* level successfully read, but next level may follow here */
+    if (!got_valid_playfield_line && reading_playfield)
+    {
+#if 0
+      printf("::: read complete playfield\n");
+#endif
+
+      /* read playfield from single level file -- skip remaining file */
+      if (!level_file_info->packed)
+       break;
+
+      if (file_level_nr >= num_levels_to_skip)
+       break;
+
+      file_level_nr++;
+
+      last_comment[0] = '\0';
+      level_name[0] = '\0';
+
+      reading_playfield = FALSE;
+    }
+
+    got_valid_playfield_line = FALSE;
+
+    /* read next line of input file */
+    if (!fgets(line, MAX_LINE_LEN, file))
+      break;
+
+    /* check if line was completely read and is terminated by line break */
+    if (strlen(line) > 0 && line[strlen(line) - 1] == '\n')
+      line_nr++;
+
+    /* cut trailing line break (this can be newline and/or carriage return) */
+    for (line_ptr = &line[strlen(line)]; line_ptr >= line; line_ptr--)
+      if ((*line_ptr == '\n' || *line_ptr == '\r') && *(line_ptr + 1) == '\0')
+        *line_ptr = '\0';
+
+    /* copy raw input line for later use (mainly debugging output) */
+    strcpy(line_raw, line);
+
+    if (read_continued_line)
+    {
+      /* append new line to existing line, if there is enough space */
+      if (strlen(previous_line) + strlen(line_ptr) < MAX_LINE_LEN)
+        strcat(previous_line, line_ptr);
+
+      strcpy(line, previous_line);      /* copy storage buffer to line */
+
+      read_continued_line = FALSE;
+    }
+
+    /* if the last character is '\', continue at next line */
+    if (strlen(line) > 0 && line[strlen(line) - 1] == '\\')
+    {
+      line[strlen(line) - 1] = '\0';    /* cut off trailing backslash */
+      strcpy(previous_line, line);      /* copy line to storage buffer */
+
+      read_continued_line = TRUE;
+
+      continue;
+    }
+
+    /* skip empty lines */
+    if (line[0] == '\0')
+      continue;
+
+    /* extract comment text from comment line */
+    if (line[0] == ';')
+    {
+      for (line_ptr = line; *line_ptr; line_ptr++)
+        if (*line_ptr != ' ' && *line_ptr != '\t' && *line_ptr != ';')
+          break;
+
+      strcpy(last_comment, line_ptr);
+
+#if 0
+      printf("::: found comment '%s' in line %d\n", last_comment, line_nr);
+#endif
+
+      continue;
+    }
+
+    /* extract level title text from line containing level title */
+    if (line[0] == '\'')
+    {
+      strcpy(level_name, &line[1]);
+
+      if (strlen(level_name) > 0 && level_name[strlen(level_name) - 1] == '\'')
+       level_name[strlen(level_name) - 1] = '\0';
+
+#if 0
+      printf("::: found level name '%s' in line %d\n", level_name, line_nr);
+#endif
+
+      continue;
+    }
+
+    /* skip lines containing only spaces (or empty lines) */
+    for (line_ptr = line; *line_ptr; line_ptr++)
+      if (*line_ptr != ' ')
+       break;
+    if (*line_ptr == '\0')
+      continue;
+
+    /* at this point, we have found a line containing part of a playfield */
+
+#if 0
+    printf("::: found playfield row in line %d\n", line_nr);
+#endif
+
+    got_valid_playfield_line = TRUE;
+
+    if (!reading_playfield)
+    {
+      reading_playfield = TRUE;
+      invalid_playfield_char = FALSE;
+
+      for (x = 0; x < MAX_LEV_FIELDX; x++)
+       for (y = 0; y < MAX_LEV_FIELDY; y++)
+         level->field[x][y] = getMappedElement_SB(' ', load_xsb_to_ces);
+
+      level->fieldx = 0;
+      level->fieldy = 0;
+
+      /* start with topmost tile row */
+      y = 0;
+    }
+
+    /* skip playfield line if larger row than allowed */
+    if (y >= MAX_LEV_FIELDY)
+      continue;
+
+    /* start with leftmost tile column */
+    x = 0;
+
+    /* read playfield elements from line */
+    for (line_ptr = line; *line_ptr; line_ptr++)
+    {
+      int mapped_sb_element = getMappedElement_SB(*line_ptr, load_xsb_to_ces);
+
+      /* stop parsing playfield line if larger column than allowed */
+      if (x >= MAX_LEV_FIELDX)
+       break;
+
+      if (mapped_sb_element == EL_UNDEFINED)
+      {
+       invalid_playfield_char = TRUE;
+
+       break;
+      }
+
+      level->field[x][y] = mapped_sb_element;
+
+      /* continue with next tile column */
+      x++;
+
+      level->fieldx = MAX(x, level->fieldx);
+    }
+
+    if (invalid_playfield_char)
+    {
+      /* if first playfield line, treat invalid lines as comment lines */
+      if (y == 0)
+       reading_playfield = FALSE;
+
+      continue;
+    }
+
+    /* continue with next tile row */
+    y++;
+  }
+
+  fclose(file);
+
+  level->fieldy = y;
+
+  level->fieldx = MIN(MAX(MIN_LEV_FIELDX, level->fieldx), MAX_LEV_FIELDX);
+  level->fieldy = MIN(MAX(MIN_LEV_FIELDY, level->fieldy), MAX_LEV_FIELDY);
+
+  if (!reading_playfield)
+  {
+    level->no_valid_file = TRUE;
+
+    Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename);
+
+    return;
+  }
+
+  if (*level_name != '\0')
+  {
+    strncpy(level->name, level_name, MAX_LEVEL_NAME_LEN);
+    level->name[MAX_LEVEL_NAME_LEN] = '\0';
+
+#if 0
+    printf(":1: level name: '%s'\n", level->name);
+#endif
+  }
+  else if (*last_comment != '\0')
+  {
+    strncpy(level->name, last_comment, MAX_LEVEL_NAME_LEN);
+    level->name[MAX_LEVEL_NAME_LEN] = '\0';
+
+#if 0
+    printf(":2: level name: '%s'\n", level->name);
+#endif
+  }
+  else
+  {
+    sprintf(level->name, "--> Level %d <--", level_file_info->nr);
+  }
+
+  /* set all empty fields beyond the border walls to invisible steel wall */
+  for (y = 0; y < level->fieldy; y++) for (x = 0; x < level->fieldx; x++)
+  {
+    if ((x == 0 || x == level->fieldx - 1 ||
+        y == 0 || y == level->fieldy - 1) &&
+       level->field[x][y] == getMappedElement_SB(' ', load_xsb_to_ces))
+      FloodFillLevel(x, y, getMappedElement_SB('_', load_xsb_to_ces),
+                    level->field, level->fieldx, level->fieldy);
+  }
+
+  /* set special level settings for Sokoban levels */
+
+  level->time = 0;
+  level->use_step_counter = TRUE;
+
+  if (load_xsb_to_ces)
+  {
+#if 1
+    /* !!! special global settings can now be set in level template !!! */
+#else
+    level->initial_player_stepsize[0] = STEPSIZE_SLOW;
+#endif
+
+    /* fill smaller playfields with padding "beyond border wall" elements */
+    if (level->fieldx < SCR_FIELDX ||
+       level->fieldy < SCR_FIELDY)
+    {
+      short field[level->fieldx][level->fieldy];
+      int new_fieldx = MAX(level->fieldx, SCR_FIELDX);
+      int new_fieldy = MAX(level->fieldy, SCR_FIELDY);
+      int pos_fieldx = (new_fieldx - level->fieldx) / 2;
+      int pos_fieldy = (new_fieldy - level->fieldy) / 2;
+
+      /* copy old playfield (which is smaller than the visible area) */
+      for (y = 0; y < level->fieldy; y++) for (x = 0; x < level->fieldx; x++)
+       field[x][y] = level->field[x][y];
+
+      /* fill new, larger playfield with "beyond border wall" elements */
+      for (y = 0; y < new_fieldy; y++) for (x = 0; x < new_fieldx; x++)
+       level->field[x][y] = getMappedElement_SB('_', load_xsb_to_ces);
+
+      /* copy the old playfield to the middle of the new playfield */
+      for (y = 0; y < level->fieldy; y++) for (x = 0; x < level->fieldx; x++)
+       level->field[pos_fieldx + x][pos_fieldy + y] = field[x][y];
+
+      level->fieldx = new_fieldx;
+      level->fieldy = new_fieldy;
+    }
+
+    level->use_custom_template = TRUE;
+  }
+}
+
+
+/* ------------------------------------------------------------------------- */
+/* functions for handling native levels                                      */
+/* ------------------------------------------------------------------------- */
+
+static void LoadLevelFromFileInfo_EM(struct LevelInfo *level,
+                                    struct LevelFileInfo *level_file_info)
+{
+  if (!LoadNativeLevel_EM(level_file_info->filename))
+    level->no_valid_file = TRUE;
+}
+
+static void LoadLevelFromFileInfo_SP(struct LevelInfo *level,
+                                    struct LevelFileInfo *level_file_info)
+{
+  int pos = 0;
+
+  /* determine position of requested level inside level package */
+  if (level_file_info->packed)
+    pos = level_file_info->nr - leveldir_current->first_level;
+
+  if (!LoadNativeLevel_SP(level_file_info->filename, pos))
+    level->no_valid_file = TRUE;
+}
+
+void CopyNativeLevel_RND_to_Native(struct LevelInfo *level)
+{
+  if (level->game_engine_type == GAME_ENGINE_TYPE_EM)
+    CopyNativeLevel_RND_to_EM(level);
+  else if (level->game_engine_type == GAME_ENGINE_TYPE_SP)
+    CopyNativeLevel_RND_to_SP(level);
+}
+
+void CopyNativeLevel_Native_to_RND(struct LevelInfo *level)
+{
+  if (level->game_engine_type == GAME_ENGINE_TYPE_EM)
+    CopyNativeLevel_EM_to_RND(level);
+  else if (level->game_engine_type == GAME_ENGINE_TYPE_SP)
+    CopyNativeLevel_SP_to_RND(level);
+}
+
+void SaveNativeLevel(struct LevelInfo *level)
+{
+  if (level->game_engine_type == GAME_ENGINE_TYPE_SP)
+  {
+    char *basename = getSingleLevelBasenameExt(level->file_info.nr, "sp");
+    char *filename = getLevelFilenameFromBasename(basename);
+
+    CopyNativeLevel_RND_to_SP(level);
+    CopyNativeTape_RND_to_SP(level);
+
+    SaveNativeLevel_SP(filename);
+  }
+}
+
+
+/* ------------------------------------------------------------------------- */
+/* functions for loading generic level                                       */
+/* ------------------------------------------------------------------------- */
+
+void LoadLevelFromFileInfo(struct LevelInfo *level,
+                          struct LevelFileInfo *level_file_info)
+{
+  /* always start with reliable default values */
+  setLevelInfoToDefaults(level);
+
+  switch (level_file_info->type)
+  {
+    case LEVEL_FILE_TYPE_RND:
+      LoadLevelFromFileInfo_RND(level, level_file_info);
+      break;
+
+    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:
+      LoadLevelFromFileInfo_SP(level, level_file_info);
+      level->game_engine_type = GAME_ENGINE_TYPE_SP;
+      break;
+
+    case LEVEL_FILE_TYPE_DC:
+      LoadLevelFromFileInfo_DC(level, level_file_info);
+      break;
+
+    case LEVEL_FILE_TYPE_SB:
+      LoadLevelFromFileInfo_SB(level, level_file_info);
+      break;
+
+    default:
+      LoadLevelFromFileInfo_RND(level, level_file_info);
+      break;
+  }
+
+  /* if level file is invalid, restore level structure to default values */
+  if (level->no_valid_file)
+    setLevelInfoToDefaults(level);
+
+  if (level->game_engine_type == GAME_ENGINE_TYPE_UNKNOWN)
+    level->game_engine_type = GAME_ENGINE_TYPE_RND;
+
+  if (level_file_info->type != LEVEL_FILE_TYPE_RND)
+    CopyNativeLevel_Native_to_RND(level);
+}
+
+void LoadLevelFromFilename(struct LevelInfo *level, char *filename)
+{
+  static struct LevelFileInfo level_file_info;
+
+  /* always start with reliable default values */
+  setFileInfoToDefaults(&level_file_info);
+
+  level_file_info.nr = 0;                      /* unknown level number */
+  level_file_info.type = LEVEL_FILE_TYPE_RND;  /* no others supported yet */
+  level_file_info.filename = filename;
+
+  LoadLevelFromFileInfo(level, &level_file_info);
+}
+
+static void LoadLevel_InitVersion(struct LevelInfo *level, char *filename)
+{
+  int i, j;
+
+  if (leveldir_current == NULL)                /* only when dumping level */
+    return;
+
+  /* all engine modifications also valid for levels which use latest engine */
+  if (level->game_version < VERSION_IDENT(3,2,0,5))
+  {
+    /* time bonus score was given for 10 s instead of 1 s before 3.2.0-5 */
+    level->score[SC_TIME_BONUS] /= 10;
+  }
+
+#if 0
+  leveldir_current->latest_engine = TRUE;      /* !!! TEST ONLY !!! */
+#endif
+
+  if (leveldir_current->latest_engine)
+  {
+    /* ---------- use latest game engine ----------------------------------- */
+
+    /* For all levels which are forced to use the latest game engine version
        (normally all but user contributed, private and undefined levels), set
        the game engine version to the actual version; this allows for actual
        corrections in the game engine to take effect for existing, converted
@@ -4626,7 +7015,8 @@ static void LoadLevel_InitVersion(struct LevelInfo *level, char *filename)
 
   /* player was faster than enemies in 1.0.0 and before */
   if (level->file_version == FILE_VERSION_1_0)
-    level->initial_player_stepsize = STEPSIZE_FAST;
+    for (i = 0; i < MAX_PLAYERS; i++)
+      level->initial_player_stepsize[i] = STEPSIZE_FAST;
 
   /* default behaviour for EM style gems was "slippery" only in 2.0.1 */
   if (level->game_version == VERSION_IDENT(2,0,1,0))
@@ -4663,8 +7053,6 @@ static void LoadLevel_InitVersion(struct LevelInfo *level, char *filename)
   /* trigger settings did not exist before 3.1.0; set to default "any" */
   if (level->game_version < VERSION_IDENT(3,1,0,0))
   {
-    int i, j;
-
     /* correct "can move into acid" settings (all zero in old levels) */
 
     level->can_move_into_acid_bits = 0; /* nothing can move into acid */
@@ -4694,6 +7082,90 @@ static void LoadLevel_InitVersion(struct LevelInfo *level, char *filename)
       }
     }
   }
+
+  /* try to detect and fix "Snake Bite" levels, which are broken with 3.2.0 */
+  {
+    int element = EL_CUSTOM_256;
+    struct ElementInfo *ei = &element_info[element];
+    struct ElementChangeInfo *change = &ei->change_page[0];
+
+    /* This is needed to fix a problem that was caused by a bugfix in function
+       game.c/CreateFieldExt() introduced with 3.2.0 that corrects the behaviour
+       when a custom element changes to EL_SOKOBAN_FIELD_PLAYER (before, it did
+       not replace walkable elements, but instead just placed the player on it,
+       without placing the Sokoban field under the player). Unfortunately, this
+       breaks "Snake Bite" style levels when the snake is halfway through a door
+       that just closes (the snake head is still alive and can be moved in this
+       case). This can be fixed by replacing the EL_SOKOBAN_FIELD_PLAYER by the
+       player (without Sokoban element) which then gets killed as designed). */
+
+    if ((strncmp(leveldir_current->identifier, "snake_bite", 10) == 0 ||
+        strncmp(ei->description, "pause b4 death", 14) == 0) &&
+       change->target_element == EL_SOKOBAN_FIELD_PLAYER)
+      change->target_element = EL_PLAYER_1;
+  }
+
+#if 1
+  /* try to detect and fix "Zelda" style levels, which are broken with 3.2.5 */
+  if (level->game_version < VERSION_IDENT(3,2,5,0))
+  {
+    /* This is needed to fix a problem that was caused by a bugfix in function
+       game.c/CheckTriggeredElementChangeExt() introduced with 3.2.5 that
+       corrects the behaviour when a custom element changes to another custom
+       element with a higher element number that has change actions defined.
+       Normally, only one change per frame is allowed for custom elements.
+       Therefore, it is checked if a custom element already changed in the
+       current frame; if it did, subsequent changes are suppressed.
+       Unfortunately, this is only checked for element changes, but not for
+       change actions, which are still executed. As the function above loops
+       through all custom elements from lower to higher, an element change
+       resulting in a lower CE number won't be checked again, while a target
+       element with a higher number will also be checked, and potential change
+       actions will get executed for this CE, too (which is wrong), while
+       further changes are ignored (which is correct). As this bugfix breaks
+       Zelda II (and introduces graphical bugs to Zelda I, and also breaks a
+       few other levels like Alan Bond's "FMV"), allow the previous, incorrect
+       behaviour for existing levels and tapes that make use of this bug */
+
+    level->use_action_after_change_bug = TRUE;
+  }
+#else
+  /* !!! THIS DOES NOT FIX "Zelda I" (GRAPHICALLY) AND "Alan's FMV" LEVELS */
+  /* try to detect and fix "Zelda II" levels, which are broken with 3.2.5 */
+  {
+    int element = EL_CUSTOM_16;
+    struct ElementInfo *ei = &element_info[element];
+
+    /* This is needed to fix a problem that was caused by a bugfix in function
+       game.c/CheckTriggeredElementChangeExt() introduced with 3.2.5 that
+       corrects the behaviour when a custom element changes to another custom
+       element with a higher element number that has change actions defined.
+       Normally, only one change per frame is allowed for custom elements.
+       Therefore, it is checked if a custom element already changed in the
+       current frame; if it did, subsequent changes are suppressed.
+       Unfortunately, this is only checked for element changes, but not for
+       change actions, which are still executed. As the function above loops
+       through all custom elements from lower to higher, an element change
+       resulting in a lower CE number won't be checked again, while a target
+       element with a higher number will also be checked, and potential change
+       actions will get executed for this CE, too (which is wrong), while
+       further changes are ignored (which is correct). As this bugfix breaks
+       Zelda II (but no other levels), allow the previous, incorrect behaviour
+       for this outstanding level set to not break the game or existing tapes */
+
+    if (strncmp(leveldir_current->identifier, "zelda2", 6) == 0 ||
+       strncmp(ei->description, "scanline - row 1", 16) == 0)
+      level->use_action_after_change_bug = TRUE;
+  }
+#endif
+
+  /* not centering level after relocating player was default only in 3.2.3 */
+  if (level->game_version == VERSION_IDENT(3,2,3,0))   /* (no pre-releases) */
+    level->shifted_relocation = TRUE;
+
+  /* EM style elements always chain-exploded in R'n'D engine before 3.2.6 */
+  if (level->game_version < VERSION_IDENT(3,2,6,0))
+    level->em_explodes_by_fire = TRUE;
 }
 
 static void LoadLevel_InitElements(struct LevelInfo *level, char *filename)
@@ -4755,20 +7227,9 @@ static void LoadLevel_InitElements(struct LevelInfo *level, char *filename)
 
       if (ei->access_direction == MV_NO_DIRECTION)
        ei->access_direction = MV_ALL_DIRECTIONS;
-
-#if 0
-      for (j = 0; j < ei->num_change_pages; j++)
-      {
-       struct ElementChangeInfo *change = &ei->change_page[j];
-
-       if (change->trigger_side == CH_SIDE_NONE)
-         change->trigger_side = CH_SIDE_ANY;
-      }
-#endif
     }
   }
 
-#if 1
   /* correct custom element values (fix invalid values for all versions) */
   if (1)
   {
@@ -4789,7 +7250,6 @@ static void LoadLevel_InitElements(struct LevelInfo *level, char *filename)
       }
     }
   }
-#endif
 
   /* initialize "can_explode" field for old levels which did not store this */
   /* !!! CHECK THIS -- "<= 3,1,0,0" IS PROBABLY WRONG !!! */
@@ -4836,6 +7296,8 @@ static void LoadLevel_InitElements(struct LevelInfo *level, char *filename)
 
   /* initialize element properties for level editor etc. */
   InitElementPropertiesEngine(level->game_version);
+  InitElementPropertiesAfterLoading(level->game_version);
+  InitElementPropertiesGfxElement();
 }
 
 static void LoadLevel_InitPlayfield(struct LevelInfo *level, char *filename)
@@ -4858,22 +7320,18 @@ static void LoadLevel_InitPlayfield(struct LevelInfo *level, char *filename)
   lev_fieldy = level->fieldy;
 
   /* determine border element for this level */
-  SetBorderElement();
+  if (level->file_info.type == LEVEL_FILE_TYPE_DC)
+    BorderElement = EL_EMPTY;  /* (in editor, SetBorderElement() is used) */
+  else
+    SetBorderElement();
 }
 
 static void LoadLevel_InitNativeEngines(struct LevelInfo *level,char *filename)
 {
   struct LevelFileInfo *level_file_info = &level->file_info;
 
-#if 1
-  if (level_file_info->type == LEVEL_FILE_TYPE_RND)
-    CopyNativeLevel_RND_to_Native(level);
-#else
   if (level_file_info->type == LEVEL_FILE_TYPE_RND)
     CopyNativeLevel_RND_to_Native(level);
-  else
-    CopyNativeLevel_Native_to_RND(level);
-#endif
 }
 
 void LoadLevelTemplate(int nr)
@@ -4910,12 +7368,28 @@ void LoadLevel(int nr)
   LoadLevel_InitNativeEngines(&level, filename);
 }
 
-static void SaveLevel_VERS(FILE *file, struct LevelInfo *level)
+static int SaveLevel_VERS(FILE *file, struct LevelInfo *level)
+{
+  int chunk_size = 0;
+
+  chunk_size += putFileVersion(file, level->file_version);
+  chunk_size += putFileVersion(file, level->game_version);
+
+  return chunk_size;
+}
+
+static int SaveLevel_DATE(FILE *file, struct LevelInfo *level)
 {
-  putFileVersion(file, level->file_version);
-  putFileVersion(file, level->game_version);
+  int chunk_size = 0;
+
+  chunk_size += putFile16BitBE(file, level->creation_date.year);
+  chunk_size += putFile8Bit(file,    level->creation_date.month);
+  chunk_size += putFile8Bit(file,    level->creation_date.day);
+
+  return chunk_size;
 }
 
+#if 0
 static void SaveLevel_HEAD(FILE *file, struct LevelInfo *level)
 {
   int i, x, y;
@@ -4961,39 +7435,61 @@ 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);
+  putFile8Bit(file, level->game_engine_type);
+
+  WriteUnusedBytesToFile(file, LEVEL_CHUNK_HEAD_UNUSED);
+}
+#endif
+
+static int SaveLevel_NAME(FILE *file, struct LevelInfo *level)
+{
+  int chunk_size = 0;
+  int i;
+
+  for (i = 0; i < MAX_LEVEL_NAME_LEN; i++)
+    chunk_size += putFile8Bit(file, level->name[i]);
 
-  WriteUnusedBytesToFile(file, LEVEL_CHUNK_HEAD_UNUSED);
+  return chunk_size;
 }
 
-static void SaveLevel_AUTH(FILE *file, struct LevelInfo *level)
+static int SaveLevel_AUTH(FILE *file, struct LevelInfo *level)
 {
+  int chunk_size = 0;
   int i;
 
   for (i = 0; i < MAX_LEVEL_AUTHOR_LEN; i++)
-    putFile8Bit(file, level->author[i]);
+    chunk_size += putFile8Bit(file, level->author[i]);
+
+  return chunk_size;
 }
 
 #if 0
-static void SaveLevel_TITL(FILE *file, struct LevelInfo *level)
+static int SaveLevel_BODY(FILE *file, struct LevelInfo *level)
 {
-  int i;
+  int chunk_size = 0;
+  int x, y;
 
-  for (i = 0; i < MAX_LEVEL_NAME_LEN; i++)
-    putFile8Bit(file, level->name[i]);
+  for (y = 0; y < level->fieldy; y++) 
+    for (x = 0; x < level->fieldx; x++) 
+      if (level->encoding_16bit_field)
+       chunk_size += putFile16BitBE(file, level->field[x][y]);
+      else
+       chunk_size += putFile8Bit(file, level->field[x][y]);
+
+  return chunk_size;
 }
 #endif
 
-static void SaveLevel_BODY(FILE *file, struct LevelInfo *level)
+static int SaveLevel_BODY(FILE *file, struct LevelInfo *level)
 {
+  int chunk_size = 0;
   int x, y;
 
   for (y = 0; y < level->fieldy; y++) 
     for (x = 0; x < level->fieldx; x++) 
-      if (level->encoding_16bit_field)
-       putFile16BitBE(file, level->field[x][y]);
-      else
-       putFile8Bit(file, level->field[x][y]);
+      chunk_size += putFile16BitBE(file, level->field[x][y]);
+
+  return chunk_size;
 }
 
 #if 0
@@ -5069,22 +7565,28 @@ static void SaveLevel_CNT2(FILE *file, struct LevelInfo *level, int element)
 }
 #endif
 
-static void SaveLevel_CNT3(FILE *file, struct LevelInfo *level, int element)
+#if 0
+static int SaveLevel_CNT3(FILE *file, struct LevelInfo *level, int element)
 {
-  int i;
   int envelope_nr = element - EL_ENVELOPE_1;
   int envelope_len = strlen(level->envelope_text[envelope_nr]) + 1;
+  int chunk_size = 0;
+  int i;
 
-  putFile16BitBE(file, element);
-  putFile16BitBE(file, envelope_len);
-  putFile8Bit(file, level->envelope_xsize[envelope_nr]);
-  putFile8Bit(file, level->envelope_ysize[envelope_nr]);
+  chunk_size += putFile16BitBE(file, element);
+  chunk_size += putFile16BitBE(file, envelope_len);
+  chunk_size += putFile8Bit(file, level->envelope_xsize[envelope_nr]);
+  chunk_size += putFile8Bit(file, level->envelope_ysize[envelope_nr]);
 
   WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT3_UNUSED);
+  chunk_size += LEVEL_CHUNK_CNT3_UNUSED;
 
   for (i = 0; i < envelope_len; i++)
-    putFile8Bit(file, level->envelope_text[envelope_nr][i]);
+    chunk_size += putFile8Bit(file, level->envelope_text[envelope_nr][i]);
+
+  return chunk_size;
 }
+#endif
 
 #if 0
 static void SaveLevel_CUS1(FILE *file, struct LevelInfo *level,
@@ -5098,7 +7600,6 @@ static void SaveLevel_CUS1(FILE *file, struct LevelInfo *level,
   {
     int element = EL_CUSTOM_START + i;
 
-#if 1
     struct ElementInfo *ei = &element_info[element];
 
     if (ei->properties[EP_BITFIELD_BASE_NR] != EP_BITMASK_DEFAULT)
@@ -5111,18 +7612,6 @@ static void SaveLevel_CUS1(FILE *file, struct LevelInfo *level,
 
       check++;
     }
-#else
-    if (Properties[element][EP_BITFIELD_BASE_NR] != EP_BITMASK_DEFAULT)
-    {
-      if (check < num_changed_custom_elements)
-      {
-       putFile16BitBE(file, element);
-       putFile32BitBE(file, Properties[element][EP_BITFIELD_BASE_NR]);
-      }
-
-      check++;
-    }
-#endif
   }
 
   if (check != num_changed_custom_elements)    /* should not happen */
@@ -5181,17 +7670,13 @@ static void SaveLevel_CUS3(FILE *file, struct LevelInfo *level,
        for (j = 0; j < MAX_ELEMENT_NAME_LEN; j++)
          putFile8Bit(file, ei->description[j]);
 
-#if 1
        putFile32BitBE(file, ei->properties[EP_BITFIELD_BASE_NR]);
-#else
-       putFile32BitBE(file, Properties[element][EP_BITFIELD_BASE_NR]);
-#endif
 
        /* some free bytes for future properties and padding */
        WriteUnusedBytesToFile(file, 7);
 
        putFile8Bit(file, ei->use_gfx_element);
-       putFile16BitBE(file, ei->gfx_element);
+       putFile16BitBE(file, ei->gfx_element_initial);
 
        putFile8Bit(file, ei->collect_score_initial);
        putFile8Bit(file, ei->collect_count_initial);
@@ -5217,7 +7702,7 @@ static void SaveLevel_CUS3(FILE *file, struct LevelInfo *level,
        putFile16BitBE(file, ei->change->delay_random);
        putFile16BitBE(file, ei->change->delay_frames);
 
-       putFile16BitBE(file, ei->change->trigger_element);
+       putFile16BitBE(file, ei->change->initial_trigger_element);
 
        putFile8Bit(file, ei->change->explode);
        putFile8Bit(file, ei->change->use_target_content);
@@ -5259,11 +7744,8 @@ static void SaveLevel_CUS4(FILE *file, struct LevelInfo *level, int element)
   for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++)
     putFile8Bit(file, ei->description[i]);
 
-#if 1
   putFile32BitBE(file, ei->properties[EP_BITFIELD_BASE_NR]);
-#else
-  putFile32BitBE(file, Properties[element][EP_BITFIELD_BASE_NR]);
-#endif
+
   WriteUnusedBytesToFile(file, 4);     /* reserved for more base properties */
 
   putFile8Bit(file, ei->num_change_pages);
@@ -5273,7 +7755,7 @@ static void SaveLevel_CUS4(FILE *file, struct LevelInfo *level, int element)
   putFile8Bit(file, ei->use_last_ce_value);
 
   putFile8Bit(file, ei->use_gfx_element);
-  putFile16BitBE(file, ei->gfx_element);
+  putFile16BitBE(file, ei->gfx_element_initial);
 
   putFile8Bit(file, ei->collect_score_initial);
   putFile8Bit(file, ei->collect_count_initial);
@@ -5332,7 +7814,7 @@ static void SaveLevel_CUS4(FILE *file, struct LevelInfo *level, int element)
     putFile16BitBE(file, change->delay_random);
     putFile16BitBE(file, change->delay_frames);
 
-    putFile16BitBE(file, change->trigger_element);
+    putFile16BitBE(file, change->initial_trigger_element);
 
     putFile8Bit(file, change->explode);
     putFile8Bit(file, change->use_target_content);
@@ -5384,7 +7866,7 @@ static void SaveLevel_GRP1(FILE *file, struct LevelInfo *level, int element)
   putFile8Bit(file, group->num_elements);
 
   putFile8Bit(file, ei->use_gfx_element);
-  putFile16BitBE(file, ei->gfx_element);
+  putFile16BitBE(file, ei->gfx_element_initial);
 
   putFile8Bit(file, group->choice_mode);
 
@@ -5399,6 +7881,7 @@ static void SaveLevel_GRP1(FILE *file, struct LevelInfo *level, int element)
 static int SaveLevel_MicroChunk(FILE *file, struct LevelFileConfigInfo *entry,
                                boolean write_element)
 {
+  int save_type = entry->save_type;
   int data_type = entry->data_type;
   int conf_type = entry->conf_type;
   int byte_mask = conf_type & CONF_MASK_BYTES;
@@ -5417,7 +7900,9 @@ static int SaveLevel_MicroChunk(FILE *file, struct LevelFileConfigInfo *entry,
     if (value != default_value)
       modified = TRUE;
 
-    if (!modified)             /* do not save unmodified default settings */
+    /* do not save if explicitly told or if unmodified default settings */
+    if ((save_type == SAVE_CONF_NEVER) ||
+       (save_type == SAVE_CONF_WHEN_CHANGED && !modified))
       return 0;
 
     if (write_element)
@@ -5428,8 +7913,6 @@ static int SaveLevel_MicroChunk(FILE *file, struct LevelFileConfigInfo *entry,
                  byte_mask == CONF_MASK_2_BYTE ? putFile16BitBE(file, value) :
                  byte_mask == CONF_MASK_4_BYTE ? putFile32BitBE(file, value) :
                  0);
-
-    return num_bytes;
   }
   else if (data_type == TYPE_STRING)
   {
@@ -5442,7 +7925,9 @@ static int SaveLevel_MicroChunk(FILE *file, struct LevelFileConfigInfo *entry,
     if (!strEqual(string, default_string))
       modified = TRUE;
 
-    if (!modified)             /* do not save unmodified default settings */
+    /* do not save if explicitly told or if unmodified default settings */
+    if ((save_type == SAVE_CONF_NEVER) ||
+       (save_type == SAVE_CONF_WHEN_CHANGED && !modified))
       return 0;
 
     if (write_element)
@@ -5453,8 +7938,6 @@ static int SaveLevel_MicroChunk(FILE *file, struct LevelFileConfigInfo *entry,
 
     for (i = 0; i < string_length; i++)
       num_bytes += putFile8Bit(file, string[i]);
-
-    return num_bytes;
   }
   else if (data_type == TYPE_ELEMENT_LIST)
   {
@@ -5467,7 +7950,9 @@ static int SaveLevel_MicroChunk(FILE *file, struct LevelFileConfigInfo *entry,
       if (element_array[i] != default_value)
        modified = TRUE;
 
-    if (!modified)             /* do not save unmodified default settings */
+    /* do not save if explicitly told or if unmodified default settings */
+    if ((save_type == SAVE_CONF_NEVER) ||
+       (save_type == SAVE_CONF_WHEN_CHANGED && !modified))
       return 0;
 
     if (write_element)
@@ -5478,8 +7963,6 @@ static int SaveLevel_MicroChunk(FILE *file, struct LevelFileConfigInfo *entry,
 
     for (i = 0; i < num_elements; i++)
       num_bytes += putFile16BitBE(file, element_array[i]);
-
-    return num_bytes;
   }
   else if (data_type == TYPE_CONTENT_LIST)
   {
@@ -5494,7 +7977,9 @@ static int SaveLevel_MicroChunk(FILE *file, struct LevelFileConfigInfo *entry,
          if (content[i].e[x][y] != default_value)
            modified = TRUE;
 
-    if (!modified)             /* do not save unmodified default settings */
+    /* do not save if explicitly told or if unmodified default settings */
+    if ((save_type == SAVE_CONF_NEVER) ||
+       (save_type == SAVE_CONF_WHEN_CHANGED && !modified))
       return 0;
 
     if (write_element)
@@ -5507,161 +7992,50 @@ static int SaveLevel_MicroChunk(FILE *file, struct LevelFileConfigInfo *entry,
       for (y = 0; y < 3; y++)
        for (x = 0; x < 3; x++)
          num_bytes += putFile16BitBE(file, content[i].e[x][y]);
-
-    return num_bytes;
   }
 
-  return 0;
-}
-
-#if 0
-
-static int SaveLevel_MicroChunk_SingleValue(FILE *file,
-                                           struct LevelFileConfigInfo *entry)
-{
-  int default_value = entry->default_value;
-  int element = entry->element;
-  int data_type = entry->data_type;
-  int conf_type = entry->conf_type;
-  int byte_mask = conf_type & CONF_MASK_BYTES;
-  void *value_ptr = entry->value;
-  int value = (data_type == TYPE_BOOLEAN ? *(boolean *)value_ptr :
-              *(int *)value_ptr);
-  int num_bytes = 0;
-  boolean modified = FALSE;
-
-  /* check if any settings have been modified before saving them */
-  if (value != default_value)
-    modified = TRUE;
-
-  if (!modified)               /* do not save unmodified default settings */
-    return 0;
-
-#if 0
-  printf("::: %02x, %d: %d != %d\n",
-        byte_mask, conf_type & CONF_MASK_TOKEN,
-        value, default_value);
-#endif
-
-  if (element != -1)
-    num_bytes += putFile16BitBE(file, element);
-
-  num_bytes += putFile8Bit(file, conf_type);
-  num_bytes += (byte_mask == CONF_MASK_1_BYTE ? putFile8Bit   (file, value) :
-               byte_mask == CONF_MASK_2_BYTE ? putFile16BitBE(file, value) :
-               byte_mask == CONF_MASK_4_BYTE ? putFile32BitBE(file, value) :0);
-
   return num_bytes;
 }
 
-static int SaveLevel_MicroChunk_ElementList(FILE *file,
-                                           struct LevelFileConfigInfo *entry)
+static int SaveLevel_INFO(FILE *file, struct LevelInfo *level)
 {
-  int *element_array = (int *)(entry->value);
-  int num_elements = *(int *)(entry->num_entities);
-  int default_value = entry->default_value;
-  int element = entry->element;
-  int conf_type = entry->conf_type;
-  int num_bytes = 0;
-  boolean modified = FALSE;
+  int chunk_size = 0;
   int i;
 
-  /* check if any settings have been modified before saving them */
-  for (i = 0; i < num_elements; i++)
-    if (element_array[i] != default_value)
-      modified = TRUE;
-
-  if (!modified)               /* do not save unmodified default settings */
-    return 0;
-
-  if (element != -1)
-    num_bytes += putFile16BitBE(file, element);
-
-  num_bytes += putFile8Bit(file, conf_type);
-  num_bytes += putFile16BitBE(file, num_elements * CONF_ELEMENT_NUM_BYTES);
-
-  for (i = 0; i < num_elements; i++)
-    num_bytes += putFile16BitBE(file, element_array[i]);
-
-  return num_bytes;
-}
-
-static int SaveLevel_MicroChunk_ContentList(FILE *file,
-                                           struct LevelFileConfigInfo *entry)
-{
-  struct Content *content = (struct Content *)(entry->value);
-  int num_contents = *(int *)(entry->num_entities);
-  int default_value = entry->default_value;
-  int element = entry->element;
-  int conf_type = entry->conf_type;
-  int num_bytes = 0;
-  boolean modified = FALSE;
-  int i, x, y;
-
-  /* check if any settings have been modified before saving them */
-  for (i = 0; i < num_contents; i++)
-    for (y = 0; y < 3; y++)
-      for (x = 0; x < 3; x++)
-       if (content[i].e[x][y] != default_value)
-         modified = TRUE;
-
-  if (!modified)               /* do not save unmodified default settings */
-    return 0;
-
-  if (element != -1)
-    num_bytes += putFile16BitBE(file, element);
-
-  num_bytes += putFile8Bit(file, conf_type);
-  num_bytes += putFile16BitBE(file, num_contents * CONF_CONTENT_NUM_BYTES);
+  li = *level;         /* copy level data into temporary buffer */
 
-  for (i = 0; i < num_contents; i++)
-    for (y = 0; y < 3; y++)
-      for (x = 0; x < 3; x++)
-       num_bytes += putFile16BitBE(file, content[i].e[x][y]);
+  for (i = 0; chunk_config_INFO[i].data_type != -1; i++)
+    chunk_size += SaveLevel_MicroChunk(file, &chunk_config_INFO[i], FALSE);
 
-  return num_bytes;
+  return chunk_size;
 }
 
-#endif
-
-static int SaveLevel_INFO(FILE *file, struct LevelInfo *level)
+static int SaveLevel_ELEM(FILE *file, struct LevelInfo *level)
 {
   int chunk_size = 0;
   int i;
 
   li = *level;         /* copy level data into temporary buffer */
 
-  for (i = 0; chunk_config_INFO[i].data_type != -1; i++)
-    chunk_size += SaveLevel_MicroChunk(file, &chunk_config_INFO[i], FALSE);
+  for (i = 0; chunk_config_ELEM[i].data_type != -1; i++)
+    chunk_size += SaveLevel_MicroChunk(file, &chunk_config_ELEM[i], TRUE);
 
   return chunk_size;
 }
 
-static int SaveLevel_CONF(FILE *file, struct LevelInfo *level)
+static int SaveLevel_NOTE(FILE *file, struct LevelInfo *level, int element)
 {
+  int envelope_nr = element - EL_ENVELOPE_1;
   int chunk_size = 0;
   int i;
 
-  li = *level;         /* copy level data into temporary buffer */
+  chunk_size += putFile16BitBE(file, element);
 
-  for (i = 0; chunk_config_CONF[i].data_type != -1; i++)
-  {
-#if 1
-    chunk_size += SaveLevel_MicroChunk(file, &chunk_config_CONF[i], TRUE);
-#else
-    struct LevelFileConfigInfo *conf = &chunk_config_CONF[i];
-    int data_type = conf->data_type;
-    int conf_type = conf->conf_type;
-    int byte_mask = conf_type & CONF_MASK_BYTES;
+  /* copy envelope data into temporary buffer */
+  xx_envelope = level->envelope[envelope_nr];
 
-    if (byte_mask != CONF_MASK_MULTI_BYTES)
-      chunk_size += SaveLevel_MicroChunk_SingleValue(file, conf);
-    else if (data_type == TYPE_ELEMENT_LIST)
-      chunk_size += SaveLevel_MicroChunk_ElementList(file, conf);
-    else if (data_type == TYPE_CONTENT_LIST)
-      chunk_size += SaveLevel_MicroChunk_ContentList(file, conf);
-#endif
-  }
+  for (i = 0; chunk_config_NOTE[i].data_type != -1; i++)
+    chunk_size += SaveLevel_MicroChunk(file, &chunk_config_NOTE[i], FALSE);
 
   return chunk_size;
 }
@@ -5679,20 +8053,15 @@ static int SaveLevel_CUSX(FILE *file, struct LevelInfo *level, int element)
   /* set default description string for this specific element */
   strcpy(xx_default_description, getDefaultElementDescription(ei));
 
-  /* set (fixed) number of content areas (may have been overwritten earlier) */
-  xx_num_contents = 1;
-
 #if 0
-  printf("::: - element config\n");
+  /* set (fixed) number of content areas (may be wrong by broken level file) */
+  /* (this is now directly corrected for broken level files after loading) */
+  xx_num_contents = 1;
 #endif
 
   for (i = 0; chunk_config_CUSX_base[i].data_type != -1; i++)
     chunk_size += SaveLevel_MicroChunk(file, &chunk_config_CUSX_base[i], FALSE);
 
-#if 0
-  printf("::: - change pages\n");
-#endif
-
   for (i = 0; i < ei->num_change_pages; i++)
   {
     struct ElementChangeInfo *change = &ei->change_page[i];
@@ -5701,25 +8070,12 @@ static int SaveLevel_CUSX(FILE *file, struct LevelInfo *level, int element)
 
     xx_change = *change;       /* copy change data into temporary buffer */
 
-#if 0
-    printf(":::   %d: xx_change.action_mode == %d\n",
-          i, xx_change.action_mode);
-    printf(":::   %d: xx_change.action_arg == %d\n",
-          i, xx_change.action_arg);
-#endif
-
     resetEventBits();
     setEventBitsFromEventFlags(change);
 
     for (j = 0; chunk_config_CUSX_change[j].data_type != -1; j++)
       chunk_size += SaveLevel_MicroChunk(file, &chunk_config_CUSX_change[j],
                                         FALSE);
-
-#if 0
-    if (element == EL_CUSTOM_START)
-      printf("::: - saving change page %d / %d (%d bytes)\n",
-            i, ei->num_change_pages, chunk_size);
-#endif
   }
 
   return chunk_size;
@@ -5748,8 +8104,8 @@ static int SaveLevel_GRPX(FILE *file, struct LevelInfo *level, int element)
 
 static void SaveLevelFromFilename(struct LevelInfo *level, char *filename)
 {
-  int body_chunk_size, info_chunk_size, conf_chunk_size;
-  int i, x, y;
+  int chunk_size;
+  int i;
   FILE *file;
 
   if (!(file = fopen(filename, MODE_WRITE)))
@@ -5761,142 +8117,65 @@ static void SaveLevelFromFilename(struct LevelInfo *level, char *filename)
   level->file_version = FILE_VERSION_ACTUAL;
   level->game_version = GAME_VERSION_ACTUAL;
 
-  /* check level field for 16-bit elements */
-  level->encoding_16bit_field = FALSE;
-  for (y = 0; y < level->fieldy; y++) 
-    for (x = 0; x < level->fieldx; x++) 
-      if (level->field[x][y] > 255)
-       level->encoding_16bit_field = TRUE;
-
-  /* check yamyam content for 16-bit elements */
-  level->encoding_16bit_yamyam = FALSE;
-  for (i = 0; i < level->num_yamyam_contents; i++)
-    for (y = 0; y < 3; y++)
-      for (x = 0; x < 3; x++)
-       if (level->yamyam_content[i].e[x][y] > 255)
-         level->encoding_16bit_yamyam = TRUE;
-
-  /* check amoeba content for 16-bit elements */
-  level->encoding_16bit_amoeba = FALSE;
-  if (level->amoeba_content > 255)
-    level->encoding_16bit_amoeba = TRUE;
-
-  /* calculate size of "BODY" chunk */
-  body_chunk_size =
-    level->fieldx * level->fieldy * (level->encoding_16bit_field ? 2 : 1);
+  level->creation_date = getCurrentDate();
 
   putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED);
   putFileChunkBE(file, "CAVE", CHUNK_SIZE_NONE);
 
-  putFileChunkBE(file, "VERS", LEVEL_CHUNK_VERS_SIZE);
+  chunk_size = SaveLevel_VERS(NULL, level);
+  putFileChunkBE(file, "VERS", chunk_size);
   SaveLevel_VERS(file, level);
 
-  putFileChunkBE(file, "HEAD", LEVEL_CHUNK_HEAD_SIZE);
-  SaveLevel_HEAD(file, level);
+  chunk_size = SaveLevel_DATE(NULL, level);
+  putFileChunkBE(file, "DATE", chunk_size);
+  SaveLevel_DATE(file, level);
 
-  putFileChunkBE(file, "AUTH", MAX_LEVEL_AUTHOR_LEN);
-  SaveLevel_AUTH(file, level);
+  chunk_size = SaveLevel_NAME(NULL, level);
+  putFileChunkBE(file, "NAME", chunk_size);
+  SaveLevel_NAME(file, level);
 
-  putFileChunkBE(file, "BODY", body_chunk_size);
-  SaveLevel_BODY(file, level);
+  chunk_size = SaveLevel_AUTH(NULL, level);
+  putFileChunkBE(file, "AUTH", chunk_size);
+  SaveLevel_AUTH(file, level);
 
-#if 0
-  if (level->encoding_16bit_yamyam ||
-      level->num_yamyam_contents != STD_ELEMENT_CONTENTS)
-  {
-    putFileChunkBE(file, "CNT2", LEVEL_CHUNK_CNT2_SIZE);
-    SaveLevel_CNT2(file, level, EL_YAMYAM);
-  }
+  chunk_size = SaveLevel_INFO(NULL, level);
+  putFileChunkBE(file, "INFO", chunk_size);
+  SaveLevel_INFO(file, level);
 
-  if (level->encoding_16bit_amoeba)
-  {
-    putFileChunkBE(file, "CNT2", LEVEL_CHUNK_CNT2_SIZE);
-    SaveLevel_CNT2(file, level, EL_BD_AMOEBA);
-  }
-#endif
+  chunk_size = SaveLevel_BODY(NULL, level);
+  putFileChunkBE(file, "BODY", chunk_size);
+  SaveLevel_BODY(file, level);
 
-  /* check for envelope content */
-  for (i = 0; i < 4; i++)
+  chunk_size = SaveLevel_ELEM(NULL, level);
+  if (chunk_size > LEVEL_CHUNK_ELEM_UNCHANGED)         /* save if changed */
   {
-    if (strlen(level->envelope_text[i]) > 0)
-    {
-      int envelope_len = strlen(level->envelope_text[i]) + 1;
-
-      putFileChunkBE(file, "CNT3", LEVEL_CHUNK_CNT3_SIZE(envelope_len));
-      SaveLevel_CNT3(file, level, EL_ENVELOPE_1 + i);
-    }
+    putFileChunkBE(file, "ELEM", chunk_size);
+    SaveLevel_ELEM(file, level);
   }
 
-  /* if not using template level, check for non-default custom/group elements */
-  if (!level->use_custom_template)
+  for (i = 0; i < NUM_ENVELOPES; i++)
   {
-#if 0
-    for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
-    {
-      int element = EL_CUSTOM_START + i;
-
-      if (element_info[element].modified_settings)
-      {
-       int num_change_pages = element_info[element].num_change_pages;
-
-       putFileChunkBE(file, "CUS4", LEVEL_CHUNK_CUS4_SIZE(num_change_pages));
-       SaveLevel_CUS4(file, level, element);
-      }
-    }
+    int element = EL_ENVELOPE_1 + i;
 
-    for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
+    chunk_size = SaveLevel_NOTE(NULL, level, element);
+    if (chunk_size > LEVEL_CHUNK_NOTE_UNCHANGED)       /* save if changed */
     {
-      int element = EL_GROUP_START + i;
-
-      if (element_info[element].modified_settings)
-      {
-       putFileChunkBE(file, "GRP1", LEVEL_CHUNK_GRP1_SIZE);
-       SaveLevel_GRP1(file, level, element);
-      }
+      putFileChunkBE(file, "NOTE", chunk_size);
+      SaveLevel_NOTE(file, level, element);
     }
-#endif
-  }
-
-  info_chunk_size = SaveLevel_INFO(NULL, level);
-
-  /* check if non-default level settings need to be saved */
-  if (info_chunk_size > 0)
-  {
-    putFileChunkBE(file, "INFO", info_chunk_size);
-    SaveLevel_INFO(file, level);
-  }
-
-  conf_chunk_size = SaveLevel_CONF(NULL, level);
-
-  /* check if non-default element settings need to be saved */
-  if (conf_chunk_size > 0)
-  {
-    putFileChunkBE(file, "CONF", conf_chunk_size);
-    SaveLevel_CONF(file, level);
   }
 
   /* if not using template level, check for non-default custom/group elements */
   if (!level->use_custom_template)
   {
-    /* (element number, number of change pages, change page number) */
-    int cusx_chunk_size_no_changes = (2) + (1 + 1) + (1 + 1);
-    /* (element number only) */
-    int grpx_chunk_size_no_changes = (2);
-
-#if 1
     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
     {
       int element = EL_CUSTOM_START + i;
-      int cusx_chunk_size = SaveLevel_CUSX(NULL, level, element);
 
-      /* check if non-default element settings need to be saved */
-      if (cusx_chunk_size > cusx_chunk_size_no_changes)
+      chunk_size = SaveLevel_CUSX(NULL, level, element);
+      if (chunk_size > LEVEL_CHUNK_CUSX_UNCHANGED)     /* save if changed */
       {
-#if 0
-       printf("::: SAVING CE %d\n", i + 1);
-#endif
-
-       putFileChunkBE(file, "CUSX", cusx_chunk_size);
+       putFileChunkBE(file, "CUSX", chunk_size);
        SaveLevel_CUSX(file, level, element);
       }
     }
@@ -5904,20 +8183,14 @@ static void SaveLevelFromFilename(struct LevelInfo *level, char *filename)
     for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
     {
       int element = EL_GROUP_START + i;
-      int grpx_chunk_size = SaveLevel_GRPX(NULL, level, element);
 
-      /* check if non-default element settings need to be saved */
-      if (grpx_chunk_size > grpx_chunk_size_no_changes)
+      chunk_size = SaveLevel_GRPX(NULL, level, element);
+      if (chunk_size > LEVEL_CHUNK_GRPX_UNCHANGED)     /* save if changed */
       {
-#if 0
-       printf("::: SAVING GE %d\n", i + 1);
-#endif
-
-       putFileChunkBE(file, "GRPX", grpx_chunk_size);
+       putFileChunkBE(file, "GRPX", chunk_size);
        SaveLevel_GRPX(file, level, element);
       }
     }
-#endif
   }
 
   fclose(file);
@@ -5939,6 +8212,25 @@ void SaveLevelTemplate()
   SaveLevelFromFilename(&level, filename);
 }
 
+boolean SaveLevelChecked(int nr)
+{
+  char *filename = getDefaultLevelFilename(nr);
+  boolean new_level = !fileExists(filename);
+  boolean level_saved = FALSE;
+
+  if (new_level || Request("Save this level and kill the old ?", REQ_ASK))
+  {
+    SaveLevel(nr);
+
+    if (new_level)
+      Request("Level saved !", REQ_CONFIRM);
+
+    level_saved = TRUE;
+  }
+
+  return level_saved;
+}
+
 void DumpLevel(struct LevelInfo *level)
 {
   if (level->no_valid_file)
@@ -5968,8 +8260,7 @@ void DumpLevel(struct LevelInfo *level)
   printf("\n");
   printf("Amoeba speed: %d\n", level->amoeba_speed);
   printf("\n");
-  printf("Initial gravity:             %s\n", (level->initial_gravity ? "yes" : "no"));
-  printf("Initial player stepsize:     %d\n", level->initial_player_stepsize);
+
   printf("EM style slippery gems:      %s\n", (level->em_slippery_gems ? "yes" : "no"));
   printf("Player blocks last field:    %s\n", (level->block_last_field ? "yes" : "no"));
   printf("SP player blocks last field: %s\n", (level->sp_block_last_field ? "yes" : "no"));
@@ -6161,6 +8452,79 @@ static int LoadTape_BODY(FILE *file, int chunk_size, struct TapeInfo *tape)
   return chunk_size;
 }
 
+void LoadTape_SokobanSolution(char *filename)
+{
+  FILE *file;
+  int move_delay = TILESIZE / level.initial_player_stepsize[0];
+
+  if (!(file = fopen(filename, MODE_READ)))
+  {
+    tape.no_valid_file = TRUE;
+
+    return;
+  }
+
+  while (!feof(file))
+  {
+    unsigned char c = fgetc(file);
+
+    if (feof(file))
+      break;
+
+    switch (c)
+    {
+      case 'u':
+      case 'U':
+       tape.pos[tape.length].action[0] = MV_UP;
+       tape.pos[tape.length].delay = move_delay + (c < 'a' ? 2 : 0);
+       tape.length++;
+       break;
+
+      case 'd':
+      case 'D':
+       tape.pos[tape.length].action[0] = MV_DOWN;
+       tape.pos[tape.length].delay = move_delay + (c < 'a' ? 2 : 0);
+       tape.length++;
+       break;
+
+      case 'l':
+      case 'L':
+       tape.pos[tape.length].action[0] = MV_LEFT;
+       tape.pos[tape.length].delay = move_delay + (c < 'a' ? 2 : 0);
+       tape.length++;
+       break;
+
+      case 'r':
+      case 'R':
+       tape.pos[tape.length].action[0] = MV_RIGHT;
+       tape.pos[tape.length].delay = move_delay + (c < 'a' ? 2 : 0);
+       tape.length++;
+       break;
+
+      case '\n':
+      case '\r':
+      case '\t':
+      case ' ':
+       /* ignore white-space characters */
+       break;
+
+      default:
+       tape.no_valid_file = TRUE;
+
+       Error(ERR_WARN, "unsupported Sokoban solution file '%s' ['%d']", filename, c);
+
+       break;
+    }
+  }
+
+  fclose(file);
+
+  if (tape.no_valid_file)
+    return;
+
+  tape.length_seconds = GetTapeLength();
+}
+
 void LoadTapeFromFilename(char *filename)
 {
   char cookie[MAX_LINE_LEN];
@@ -6171,6 +8535,13 @@ void LoadTapeFromFilename(char *filename)
   /* always start with reliable default values */
   setTapeInfoToDefaults();
 
+  if (strSuffix(filename, ".sln"))
+  {
+    LoadTape_SokobanSolution(filename);
+
+    return;
+  }
+
   if (!(file = fopen(filename, MODE_READ)))
   {
     tape.no_valid_file = TRUE;
@@ -6215,6 +8586,7 @@ void LoadTapeFromFilename(char *filename)
 
       Error(ERR_WARN, "unsupported version of tape file '%s'", filename);
       fclose(file);
+
       return;
     }
 
@@ -6289,6 +8661,7 @@ void LoadTapeFromFilename(char *filename)
   tape.length_seconds = GetTapeLength();
 
 #if 0
+  printf("::: tape file version: %d\n", tape.file_version);
   printf("::: tape game version: %d\n", tape.game_version);
   printf("::: tape engine version: %d\n", tape.engine_version);
 #endif
@@ -6306,6 +8679,13 @@ void LoadSolutionTape(int nr)
   char *filename = getSolutionTapeFilename(nr);
 
   LoadTapeFromFilename(filename);
+
+#if 1
+  if (TAPE_IS_EMPTY(tape) &&
+      level.game_engine_type == GAME_ENGINE_TYPE_SP &&
+      level.native_sp_level->demo.is_available)
+    CopyNativeTape_SP_to_RND(&level);
+#endif
 }
 
 static void SaveTape_VERS(FILE *file, struct TapeInfo *tape)
@@ -6367,7 +8747,9 @@ void SaveTape(int nr)
 {
   char *filename = getTapeFilename(nr);
   FILE *file;
+#if 0
   boolean new_tape = TRUE;
+#endif
   int num_participating_players = 0;
   int info_chunk_size;
   int body_chunk_size;
@@ -6375,6 +8757,7 @@ void SaveTape(int nr)
 
   InitTapeDirectory(leveldir_current->subdir);
 
+#if 0
   /* if a tape still exists, ask to overwrite it */
   if (fileExists(filename))
   {
@@ -6382,6 +8765,7 @@ void SaveTape(int nr)
     if (!Request("Replace old tape ?", REQ_ASK))
       return;
   }
+#endif
 
   if (!(file = fopen(filename, MODE_WRITE)))
   {
@@ -6421,8 +8805,29 @@ void SaveTape(int nr)
 
   tape.changed = FALSE;
 
+#if 0
   if (new_tape)
     Request("Tape saved !", REQ_CONFIRM);
+#endif
+}
+
+boolean SaveTapeChecked(int nr)
+{
+  char *filename = getTapeFilename(nr);
+  boolean new_tape = !fileExists(filename);
+  boolean tape_saved = FALSE;
+
+  if (new_tape || Request("Replace old tape ?", REQ_ASK))
+  {
+    SaveTape(nr);
+
+    if (new_tape)
+      Request("Tape saved !", REQ_CONFIRM);
+
+    tape_saved = TRUE;
+  }
+
+  return tape_saved;
 }
 
 void DumpTape(struct TapeInfo *tape)
@@ -6577,29 +8982,33 @@ void SaveScore(int nr)
 #define SETUP_TOKEN_SOUND_SIMPLE               4
 #define SETUP_TOKEN_TOONS                      5
 #define SETUP_TOKEN_SCROLL_DELAY               6
-#define SETUP_TOKEN_SOFT_SCROLLING             7
-#define SETUP_TOKEN_FADING                     8
-#define SETUP_TOKEN_AUTORECORD                 9
-#define SETUP_TOKEN_SHOW_TITLESCREEN           10
-#define SETUP_TOKEN_QUICK_DOORS                        11
-#define SETUP_TOKEN_TEAM_MODE                  12
-#define SETUP_TOKEN_HANDICAP                   13
-#define SETUP_TOKEN_SKIP_LEVELS                        14
-#define SETUP_TOKEN_TIME_LIMIT                 15
-#define SETUP_TOKEN_FULLSCREEN                 16
-#define SETUP_TOKEN_ASK_ON_ESCAPE              17
-#define SETUP_TOKEN_ASK_ON_ESCAPE_EDITOR       18
-#define SETUP_TOKEN_QUICK_SWITCH               19
-#define SETUP_TOKEN_INPUT_ON_FOCUS             20
-#define SETUP_TOKEN_PREFER_AGA_GRAPHICS                21
-#define SETUP_TOKEN_GRAPHICS_SET               22
-#define SETUP_TOKEN_SOUNDS_SET                 23
-#define SETUP_TOKEN_MUSIC_SET                  24
-#define SETUP_TOKEN_OVERRIDE_LEVEL_GRAPHICS    25
-#define SETUP_TOKEN_OVERRIDE_LEVEL_SOUNDS      26
-#define SETUP_TOKEN_OVERRIDE_LEVEL_MUSIC       27
-
-#define NUM_GLOBAL_SETUP_TOKENS                        28
+#define SETUP_TOKEN_SCROLL_DELAY_VALUE         7
+#define SETUP_TOKEN_SOFT_SCROLLING             8
+#define SETUP_TOKEN_FADE_SCREENS               9
+#define SETUP_TOKEN_AUTORECORD                 10
+#define SETUP_TOKEN_SHOW_TITLESCREEN           11
+#define SETUP_TOKEN_QUICK_DOORS                        12
+#define SETUP_TOKEN_TEAM_MODE                  13
+#define SETUP_TOKEN_HANDICAP                   14
+#define SETUP_TOKEN_SKIP_LEVELS                        15
+#define SETUP_TOKEN_TIME_LIMIT                 16
+#define SETUP_TOKEN_FULLSCREEN                 17
+#define SETUP_TOKEN_FULLSCREEN_MODE            18
+#define SETUP_TOKEN_ASK_ON_ESCAPE              19
+#define SETUP_TOKEN_ASK_ON_ESCAPE_EDITOR       20
+#define SETUP_TOKEN_QUICK_SWITCH               21
+#define SETUP_TOKEN_INPUT_ON_FOCUS             22
+#define SETUP_TOKEN_PREFER_AGA_GRAPHICS                23
+#define SETUP_TOKEN_GAME_FRAME_DELAY           24
+#define SETUP_TOKEN_SP_SHOW_BORDER_ELEMENTS    25
+#define SETUP_TOKEN_GRAPHICS_SET               26
+#define SETUP_TOKEN_SOUNDS_SET                 27
+#define SETUP_TOKEN_MUSIC_SET                  28
+#define SETUP_TOKEN_OVERRIDE_LEVEL_GRAPHICS    29
+#define SETUP_TOKEN_OVERRIDE_LEVEL_SOUNDS      30
+#define SETUP_TOKEN_OVERRIDE_LEVEL_MUSIC       31
+
+#define NUM_GLOBAL_SETUP_TOKENS                        32
 
 /* editor setup */
 #define SETUP_TOKEN_EDITOR_EL_BOULDERDASH      0
@@ -6611,13 +9020,16 @@ void SaveScore(int nr)
 #define SETUP_TOKEN_EDITOR_EL_DIAMOND_CAVES    6
 #define SETUP_TOKEN_EDITOR_EL_DX_BOULDERDASH   7
 #define SETUP_TOKEN_EDITOR_EL_CHARS            8
-#define SETUP_TOKEN_EDITOR_EL_CUSTOM           9
-#define SETUP_TOKEN_EDITOR_EL_HEADLINES                10
-#define SETUP_TOKEN_EDITOR_EL_USER_DEFINED     11
-#define SETUP_TOKEN_EDITOR_EL_DYNAMIC          12
-#define SETUP_TOKEN_EDITOR_SHOW_ELEMENT_TOKEN  13
+#define SETUP_TOKEN_EDITOR_EL_STEEL_CHARS      9
+#define SETUP_TOKEN_EDITOR_EL_CUSTOM           10
+#define SETUP_TOKEN_EDITOR_EL_HEADLINES                11
+#define SETUP_TOKEN_EDITOR_EL_USER_DEFINED     12
+#define SETUP_TOKEN_EDITOR_EL_DYNAMIC          13
+#define SETUP_TOKEN_EDITOR_EL_BY_GAME          14
+#define SETUP_TOKEN_EDITOR_EL_BY_TYPE          15
+#define SETUP_TOKEN_EDITOR_SHOW_ELEMENT_TOKEN  16
 
-#define NUM_EDITOR_SETUP_TOKENS                        14
+#define NUM_EDITOR_SETUP_TOKENS                        17
 
 /* editor cascade setup */
 #define SETUP_TOKEN_EDITOR_CASCADE_BD          0
@@ -6629,13 +9041,14 @@ void SaveScore(int nr)
 #define SETUP_TOKEN_EDITOR_CASCADE_DC          6
 #define SETUP_TOKEN_EDITOR_CASCADE_DX          7
 #define SETUP_TOKEN_EDITOR_CASCADE_TEXT                8
-#define SETUP_TOKEN_EDITOR_CASCADE_CE          9
-#define SETUP_TOKEN_EDITOR_CASCADE_GE          10
-#define SETUP_TOKEN_EDITOR_CASCADE_USER                11
-#define SETUP_TOKEN_EDITOR_CASCADE_GENERIC     12
-#define SETUP_TOKEN_EDITOR_CASCADE_DYNAMIC     13
+#define SETUP_TOKEN_EDITOR_CASCADE_STEELTEXT   9
+#define SETUP_TOKEN_EDITOR_CASCADE_CE          10
+#define SETUP_TOKEN_EDITOR_CASCADE_GE          11
+#define SETUP_TOKEN_EDITOR_CASCADE_REF         12
+#define SETUP_TOKEN_EDITOR_CASCADE_USER                13
+#define SETUP_TOKEN_EDITOR_CASCADE_DYNAMIC     14
 
-#define NUM_EDITOR_CASCADE_SETUP_TOKENS                14
+#define NUM_EDITOR_CASCADE_SETUP_TOKENS                15
 
 /* shortcut setup */
 #define SETUP_TOKEN_SHORTCUT_SAVE_GAME         0
@@ -6646,8 +9059,16 @@ void SaveScore(int nr)
 #define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_3    5
 #define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_4    6
 #define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_ALL  7
+#define SETUP_TOKEN_SHORTCUT_TAPE_EJECT                8
+#define SETUP_TOKEN_SHORTCUT_TAPE_STOP         9
+#define SETUP_TOKEN_SHORTCUT_TAPE_PAUSE                10
+#define SETUP_TOKEN_SHORTCUT_TAPE_RECORD       11
+#define SETUP_TOKEN_SHORTCUT_TAPE_PLAY         12
+#define SETUP_TOKEN_SHORTCUT_SOUND_SIMPLE      13
+#define SETUP_TOKEN_SHORTCUT_SOUND_LOOPS       14
+#define SETUP_TOKEN_SHORTCUT_SOUND_MUSIC       15
 
-#define NUM_SHORTCUT_SETUP_TOKENS              8
+#define NUM_SHORTCUT_SETUP_TOKENS              16
 
 /* player setup */
 #define SETUP_TOKEN_PLAYER_USE_JOYSTICK                0
@@ -6670,10 +9091,11 @@ void SaveScore(int nr)
 #define NUM_PLAYER_SETUP_TOKENS                        16
 
 /* system setup */
-#define SETUP_TOKEN_SYSTEM_SDL_AUDIODRIVER     0
-#define SETUP_TOKEN_SYSTEM_AUDIO_FRAGMENT_SIZE 1
+#define SETUP_TOKEN_SYSTEM_SDL_VIDEODRIVER     0
+#define SETUP_TOKEN_SYSTEM_SDL_AUDIODRIVER     1
+#define SETUP_TOKEN_SYSTEM_AUDIO_FRAGMENT_SIZE 2
 
-#define NUM_SYSTEM_SETUP_TOKENS                        2
+#define NUM_SYSTEM_SETUP_TOKENS                        3
 
 /* options setup */
 #define SETUP_TOKEN_OPTIONS_VERBOSE            0
@@ -6691,38 +9113,53 @@ static struct OptionInfo soi;
 
 static struct TokenInfo global_setup_tokens[] =
 {
-  { TYPE_STRING, &si.player_name,      "player_name"                   },
-  { TYPE_SWITCH, &si.sound,            "sound"                         },
-  { TYPE_SWITCH, &si.sound_loops,      "repeating_sound_loops"         },
-  { TYPE_SWITCH, &si.sound_music,      "background_music"              },
-  { TYPE_SWITCH, &si.sound_simple,     "simple_sound_effects"          },
-  { TYPE_SWITCH, &si.toons,            "toons"                         },
-  { TYPE_SWITCH, &si.scroll_delay,     "scroll_delay"                  },
-  { TYPE_SWITCH, &si.soft_scrolling,   "soft_scrolling"                },
-  { TYPE_SWITCH, &si.fading,           "screen_fading"                 },
-  { TYPE_SWITCH, &si.autorecord,       "automatic_tape_recording"      },
-  { TYPE_SWITCH, &si.show_titlescreen, "show_titlescreen"              },
-  { TYPE_SWITCH, &si.quick_doors,      "quick_doors"                   },
-  { TYPE_SWITCH, &si.team_mode,                "team_mode"                     },
-  { TYPE_SWITCH, &si.handicap,         "handicap"                      },
-  { TYPE_SWITCH, &si.skip_levels,      "skip_levels"                   },
-  { TYPE_SWITCH, &si.time_limit,       "time_limit"                    },
-  { TYPE_SWITCH, &si.fullscreen,       "fullscreen"                    },
-  { TYPE_SWITCH, &si.ask_on_escape,    "ask_on_escape"                 },
-  { TYPE_SWITCH, &si.ask_on_escape_editor, "ask_on_escape_editor"      },
-  { TYPE_SWITCH, &si.quick_switch,     "quick_player_switch"           },
-  { TYPE_SWITCH, &si.input_on_focus,   "input_on_focus"                },
-  { TYPE_SWITCH, &si.prefer_aga_graphics, "prefer_aga_graphics"                },
-  { TYPE_STRING, &si.graphics_set,     "graphics_set"                  },
-  { TYPE_STRING, &si.sounds_set,       "sounds_set"                    },
-  { TYPE_STRING, &si.music_set,                "music_set"                     },
-  { TYPE_SWITCH, &si.override_level_graphics, "override_level_graphics"        },
-  { TYPE_SWITCH, &si.override_level_sounds,   "override_level_sounds"  },
-  { TYPE_SWITCH, &si.override_level_music,    "override_level_music"   },
+  { TYPE_STRING, &si.player_name,             "player_name"            },
+  { TYPE_SWITCH, &si.sound,                   "sound"                  },
+  { TYPE_SWITCH, &si.sound_loops,             "repeating_sound_loops"  },
+  { TYPE_SWITCH, &si.sound_music,             "background_music"       },
+  { TYPE_SWITCH, &si.sound_simple,            "simple_sound_effects"   },
+  { TYPE_SWITCH, &si.toons,                   "toons"                  },
+  { TYPE_SWITCH, &si.scroll_delay,            "scroll_delay"           },
+  { TYPE_INTEGER,&si.scroll_delay_value,      "scroll_delay_value"     },
+  { TYPE_SWITCH, &si.soft_scrolling,          "soft_scrolling"         },
+  { TYPE_SWITCH, &si.fade_screens,            "fade_screens"           },
+  { TYPE_SWITCH, &si.autorecord,              "automatic_tape_recording"},
+  { TYPE_SWITCH, &si.show_titlescreen,        "show_titlescreen"       },
+  { TYPE_SWITCH, &si.quick_doors,             "quick_doors"            },
+  { TYPE_SWITCH, &si.team_mode,               "team_mode"              },
+  { TYPE_SWITCH, &si.handicap,                "handicap"               },
+  { TYPE_SWITCH, &si.skip_levels,             "skip_levels"            },
+  { TYPE_SWITCH, &si.time_limit,              "time_limit"             },
+  { TYPE_SWITCH, &si.fullscreen,              "fullscreen"             },
+  { TYPE_STRING, &si.fullscreen_mode,         "fullscreen_mode"                },
+  { TYPE_SWITCH, &si.ask_on_escape,           "ask_on_escape"          },
+  { TYPE_SWITCH, &si.ask_on_escape_editor,    "ask_on_escape_editor"   },
+  { TYPE_SWITCH, &si.quick_switch,            "quick_player_switch"    },
+  { TYPE_SWITCH, &si.input_on_focus,          "input_on_focus"         },
+  { TYPE_SWITCH, &si.prefer_aga_graphics,     "prefer_aga_graphics"    },
+  { TYPE_INTEGER,&si.game_frame_delay,        "game_frame_delay"       },
+  { TYPE_SWITCH, &si.sp_show_border_elements, "sp_show_border_elements"        },
+  { TYPE_STRING, &si.graphics_set,            "graphics_set"           },
+  { TYPE_STRING, &si.sounds_set,              "sounds_set"             },
+  { TYPE_STRING, &si.music_set,               "music_set"              },
+  { TYPE_SWITCH3,&si.override_level_graphics, "override_level_graphics"        },
+  { TYPE_SWITCH3,&si.override_level_sounds,   "override_level_sounds"  },
+  { TYPE_SWITCH3,&si.override_level_music,    "override_level_music"   },
 };
 
+static boolean not_used = FALSE;
 static struct TokenInfo editor_setup_tokens[] =
 {
+#if 1
+  { TYPE_SWITCH, &not_used,            "editor.el_boulderdash"         },
+  { TYPE_SWITCH, &not_used,            "editor.el_emerald_mine"        },
+  { TYPE_SWITCH, &not_used,            "editor.el_emerald_mine_club"   },
+  { TYPE_SWITCH, &not_used,            "editor.el_more"                },
+  { TYPE_SWITCH, &not_used,            "editor.el_sokoban"             },
+  { TYPE_SWITCH, &not_used,            "editor.el_supaplex"            },
+  { TYPE_SWITCH, &not_used,            "editor.el_diamond_caves"       },
+  { TYPE_SWITCH, &not_used,            "editor.el_dx_boulderdash"      },
+#else
   { TYPE_SWITCH, &sei.el_boulderdash,  "editor.el_boulderdash"         },
   { TYPE_SWITCH, &sei.el_emerald_mine, "editor.el_emerald_mine"        },
   { TYPE_SWITCH, &sei.el_emerald_mine_club,"editor.el_emerald_mine_club"},
@@ -6731,11 +9168,19 @@ static struct TokenInfo editor_setup_tokens[] =
   { TYPE_SWITCH, &sei.el_supaplex,     "editor.el_supaplex"            },
   { TYPE_SWITCH, &sei.el_diamond_caves,        "editor.el_diamond_caves"       },
   { TYPE_SWITCH, &sei.el_dx_boulderdash,"editor.el_dx_boulderdash"     },
+#endif
   { TYPE_SWITCH, &sei.el_chars,                "editor.el_chars"               },
+  { TYPE_SWITCH, &sei.el_steel_chars,  "editor.el_steel_chars"         },
   { TYPE_SWITCH, &sei.el_custom,       "editor.el_custom"              },
+#if 1
+  { TYPE_SWITCH, &not_used,            "editor.el_headlines"           },
+#else
   { TYPE_SWITCH, &sei.el_headlines,    "editor.el_headlines"           },
+#endif
   { TYPE_SWITCH, &sei.el_user_defined, "editor.el_user_defined"        },
   { TYPE_SWITCH, &sei.el_dynamic,      "editor.el_dynamic"             },
+  { TYPE_SWITCH, &sei.el_by_game,      "editor.el_by_game"             },
+  { TYPE_SWITCH, &sei.el_by_type,      "editor.el_by_type"             },
   { TYPE_SWITCH, &sei.show_element_token,"editor.show_element_token"   },
 };
 
@@ -6750,8 +9195,10 @@ static struct TokenInfo editor_cascade_setup_tokens[] =
   { TYPE_SWITCH, &seci.el_dc,          "editor.cascade.el_dc"          },
   { TYPE_SWITCH, &seci.el_dx,          "editor.cascade.el_dx"          },
   { TYPE_SWITCH, &seci.el_chars,       "editor.cascade.el_chars"       },
+  { TYPE_SWITCH, &seci.el_steel_chars, "editor.cascade.el_steel_chars" },
   { TYPE_SWITCH, &seci.el_ce,          "editor.cascade.el_ce"          },
   { TYPE_SWITCH, &seci.el_ge,          "editor.cascade.el_ge"          },
+  { TYPE_SWITCH, &seci.el_ref,         "editor.cascade.el_ref"         },
   { TYPE_SWITCH, &seci.el_user,                "editor.cascade.el_user"        },
   { TYPE_SWITCH, &seci.el_dynamic,     "editor.cascade.el_dynamic"     },
 };
@@ -6766,6 +9213,14 @@ static struct TokenInfo shortcut_setup_tokens[] =
   { TYPE_KEY_X11, &ssi.focus_player[2],        "shortcut.focus_player_3"       },
   { TYPE_KEY_X11, &ssi.focus_player[3],        "shortcut.focus_player_4"       },
   { TYPE_KEY_X11, &ssi.focus_player_all,"shortcut.focus_player_all"    },
+  { TYPE_KEY_X11, &ssi.tape_eject,     "shortcut.tape_eject"           },
+  { TYPE_KEY_X11, &ssi.tape_stop,      "shortcut.tape_stop"            },
+  { TYPE_KEY_X11, &ssi.tape_pause,     "shortcut.tape_pause"           },
+  { TYPE_KEY_X11, &ssi.tape_record,    "shortcut.tape_record"          },
+  { TYPE_KEY_X11, &ssi.tape_play,      "shortcut.tape_play"            },
+  { TYPE_KEY_X11, &ssi.sound_simple,   "shortcut.sound_simple"         },
+  { TYPE_KEY_X11, &ssi.sound_loops,    "shortcut.sound_loops"          },
+  { TYPE_KEY_X11, &ssi.sound_music,    "shortcut.sound_music"          },
 };
 
 static struct TokenInfo player_setup_tokens[] =
@@ -6790,6 +9245,7 @@ static struct TokenInfo player_setup_tokens[] =
 
 static struct TokenInfo system_setup_tokens[] =
 {
+  { TYPE_STRING,  &syi.sdl_videodriver,        "system.sdl_videodriver"        },
   { TYPE_STRING,  &syi.sdl_audiodriver,        "system.sdl_audiodriver"        },
   { TYPE_INTEGER, &syi.audio_fragment_size,"system.audio_fragment_size"        },
 };
@@ -6825,11 +9281,10 @@ static void setSetupInfoToDefaults(struct SetupInfo *si)
   si->sound_music = TRUE;
   si->sound_simple = TRUE;
   si->toons = TRUE;
-  si->double_buffering = TRUE;
-  si->direct_draw = !si->double_buffering;
   si->scroll_delay = TRUE;
+  si->scroll_delay_value = STD_SCROLL_DELAY;
   si->soft_scrolling = TRUE;
-  si->fading = FALSE;
+  si->fade_screens = TRUE;
   si->autorecord = TRUE;
   si->show_titlescreen = TRUE;
   si->quick_doors = FALSE;
@@ -6838,29 +9293,33 @@ static void setSetupInfoToDefaults(struct SetupInfo *si)
   si->skip_levels = TRUE;
   si->time_limit = TRUE;
   si->fullscreen = FALSE;
+  si->fullscreen_mode = getStringCopy(DEFAULT_FULLSCREEN_MODE);
   si->ask_on_escape = TRUE;
   si->ask_on_escape_editor = TRUE;
   si->quick_switch = FALSE;
   si->input_on_focus = FALSE;
   si->prefer_aga_graphics = TRUE;
+  si->game_frame_delay = GAME_FRAME_DELAY;
+  si->sp_show_border_elements = FALSE;
 
-  si->graphics_set = getStringCopy(GFX_CLASSIC_SUBDIR);
-  si->sounds_set = getStringCopy(SND_CLASSIC_SUBDIR);
-  si->music_set = getStringCopy(MUS_CLASSIC_SUBDIR);
+  si->graphics_set = getStringCopy(GFX_DEFAULT_SUBDIR);
+  si->sounds_set = getStringCopy(SND_DEFAULT_SUBDIR);
+  si->music_set = getStringCopy(MUS_DEFAULT_SUBDIR);
   si->override_level_graphics = FALSE;
   si->override_level_sounds = FALSE;
   si->override_level_music = FALSE;
 
-  si->editor.el_boulderdash       = TRUE;
-  si->editor.el_emerald_mine      = TRUE;
-  si->editor.el_emerald_mine_club = TRUE;
-  si->editor.el_more              = TRUE;
-  si->editor.el_sokoban           = TRUE;
-  si->editor.el_supaplex          = TRUE;
-  si->editor.el_diamond_caves     = TRUE;
-  si->editor.el_dx_boulderdash    = TRUE;
-  si->editor.el_chars             = TRUE;
-  si->editor.el_custom            = TRUE;
+  si->editor.el_boulderdash            = TRUE;
+  si->editor.el_emerald_mine           = TRUE;
+  si->editor.el_emerald_mine_club      = TRUE;
+  si->editor.el_more                   = TRUE;
+  si->editor.el_sokoban                        = TRUE;
+  si->editor.el_supaplex               = TRUE;
+  si->editor.el_diamond_caves          = TRUE;
+  si->editor.el_dx_boulderdash         = TRUE;
+  si->editor.el_chars                  = TRUE;
+  si->editor.el_steel_chars            = TRUE;
+  si->editor.el_custom                 = TRUE;
 
   si->editor.el_headlines = TRUE;
   si->editor.el_user_defined = FALSE;
@@ -6868,15 +9327,25 @@ static void setSetupInfoToDefaults(struct SetupInfo *si)
 
   si->editor.show_element_token = FALSE;
 
-  si->shortcut.save_game = DEFAULT_KEY_SAVE_GAME;
-  si->shortcut.load_game = DEFAULT_KEY_LOAD_GAME;
-  si->shortcut.toggle_pause = DEFAULT_KEY_TOGGLE_PAUSE;
+  si->shortcut.save_game       = DEFAULT_KEY_SAVE_GAME;
+  si->shortcut.load_game       = DEFAULT_KEY_LOAD_GAME;
+  si->shortcut.toggle_pause    = DEFAULT_KEY_TOGGLE_PAUSE;
 
-  si->shortcut.focus_player[0] = DEFAULT_KEY_FOCUS_PLAYER_1;
-  si->shortcut.focus_player[1] = DEFAULT_KEY_FOCUS_PLAYER_2;
-  si->shortcut.focus_player[2] = DEFAULT_KEY_FOCUS_PLAYER_3;
-  si->shortcut.focus_player[3] = DEFAULT_KEY_FOCUS_PLAYER_4;
-  si->shortcut.focus_player_all = DEFAULT_KEY_FOCUS_PLAYER_ALL;
+  si->shortcut.focus_player[0] = DEFAULT_KEY_FOCUS_PLAYER_1;
+  si->shortcut.focus_player[1] = DEFAULT_KEY_FOCUS_PLAYER_2;
+  si->shortcut.focus_player[2] = DEFAULT_KEY_FOCUS_PLAYER_3;
+  si->shortcut.focus_player[3] = DEFAULT_KEY_FOCUS_PLAYER_4;
+  si->shortcut.focus_player_all        = DEFAULT_KEY_FOCUS_PLAYER_ALL;
+
+  si->shortcut.tape_eject      = DEFAULT_KEY_TAPE_EJECT;
+  si->shortcut.tape_stop       = DEFAULT_KEY_TAPE_STOP;
+  si->shortcut.tape_pause      = DEFAULT_KEY_TAPE_PAUSE;
+  si->shortcut.tape_record     = DEFAULT_KEY_TAPE_RECORD;
+  si->shortcut.tape_play       = DEFAULT_KEY_TAPE_PLAY;
+
+  si->shortcut.sound_simple    = DEFAULT_KEY_SOUND_SIMPLE;
+  si->shortcut.sound_loops     = DEFAULT_KEY_SOUND_LOOPS;
+  si->shortcut.sound_music     = DEFAULT_KEY_SOUND_MUSIC;
 
   for (i = 0; i < MAX_PLAYERS; i++)
   {
@@ -6898,28 +9367,40 @@ static void setSetupInfoToDefaults(struct SetupInfo *si)
     si->input[i].key.drop  = (i == 0 ? DEFAULT_KEY_DROP  : KSYM_UNDEFINED);
   }
 
+  si->system.sdl_videodriver = getStringCopy(ARG_DEFAULT);
   si->system.sdl_audiodriver = getStringCopy(ARG_DEFAULT);
   si->system.audio_fragment_size = DEFAULT_AUDIO_FRAGMENT_SIZE;
 
   si->options.verbose = FALSE;
+
+#if defined(CREATE_SPECIAL_EDITION_RND_JUE)
+  si->toons = FALSE;
+  si->handicap = FALSE;
+  si->fullscreen = TRUE;
+  si->override_level_graphics = AUTO;
+  si->override_level_sounds = AUTO;
+  si->override_level_music = AUTO;
+#endif
 }
 
 static void setSetupInfoToDefaults_EditorCascade(struct SetupInfo *si)
 {
-  si->editor_cascade.el_bd     = TRUE;
-  si->editor_cascade.el_em     = TRUE;
-  si->editor_cascade.el_emc    = TRUE;
-  si->editor_cascade.el_rnd    = TRUE;
-  si->editor_cascade.el_sb     = TRUE;
-  si->editor_cascade.el_sp     = TRUE;
-  si->editor_cascade.el_dc     = TRUE;
-  si->editor_cascade.el_dx     = TRUE;
+  si->editor_cascade.el_bd             = TRUE;
+  si->editor_cascade.el_em             = TRUE;
+  si->editor_cascade.el_emc            = TRUE;
+  si->editor_cascade.el_rnd            = TRUE;
+  si->editor_cascade.el_sb             = TRUE;
+  si->editor_cascade.el_sp             = TRUE;
+  si->editor_cascade.el_dc             = TRUE;
+  si->editor_cascade.el_dx             = TRUE;
 
-  si->editor_cascade.el_chars  = FALSE;
-  si->editor_cascade.el_ce     = FALSE;
-  si->editor_cascade.el_ge     = FALSE;
-  si->editor_cascade.el_user   = FALSE;
-  si->editor_cascade.el_dynamic        = FALSE;
+  si->editor_cascade.el_chars          = FALSE;
+  si->editor_cascade.el_steel_chars    = FALSE;
+  si->editor_cascade.el_ce             = FALSE;
+  si->editor_cascade.el_ge             = FALSE;
+  si->editor_cascade.el_ref            = FALSE;
+  si->editor_cascade.el_user           = FALSE;
+  si->editor_cascade.el_dynamic                = FALSE;
 }
 
 static void decodeSetupFileHash(SetupFileHash *setup_file_hash)
@@ -7017,14 +9498,23 @@ void LoadSetup()
     checkSetupFileHashIdentifier(setup_file_hash, filename,getCookie("SETUP"));
     decodeSetupFileHash(setup_file_hash);
 
-    setup.direct_draw = !setup.double_buffering;
-
     freeSetupFileHash(setup_file_hash);
 
     /* needed to work around problems with fixed length strings */
     player_name_new = get_corrected_login_name(setup.player_name);
     free(setup.player_name);
     setup.player_name = player_name_new;
+
+    /* "scroll_delay: on(3) / off(0)" was replaced by scroll delay value */
+    if (setup.scroll_delay == FALSE)
+    {
+      setup.scroll_delay_value = MIN_SCROLL_DELAY;
+      setup.scroll_delay = TRUE;                       /* now always "on" */
+    }
+
+    /* make sure that scroll delay value stays inside valid range */
+    setup.scroll_delay_value =
+      MIN(MAX(MIN_SCROLL_DELAY, setup.scroll_delay_value), MAX_SCROLL_DELAY);
   }
   else
     Error(ERR_WARN, "using default setup values");
@@ -7144,7 +9634,7 @@ void SaveSetup_EditorCascade()
 
   seci = setup.editor_cascade;
   fprintf(file, "\n");
-  for (i = 0; i < NUM_EDITOR_SETUP_TOKENS; i++)
+  for (i = 0; i < NUM_EDITOR_CASCADE_SETUP_TOKENS; i++)
     fprintf(file, "%s\n", getSetupLine(editor_cascade_setup_tokens, "", i));
 
   fclose(file);
@@ -7186,31 +9676,360 @@ void LoadCustomElementDescriptions()
   freeSetupFileHash(setup_file_hash);
 }
 
-static void LoadSpecialMenuDesignSettingsFromFilename(char *filename)
+static int getElementFromToken(char *token)
+{
+#if 1
+  char *value = getHashEntry(element_token_hash, token);
+
+  if (value != NULL)
+    return atoi(value);
+#else
+  int i;
+
+  /* !!! OPTIMIZE THIS BY USING HASH !!! */
+  for (i = 0; i < MAX_NUM_ELEMENTS; i++)
+    if (strEqual(token, element_info[i].token_name))
+      return i;
+#endif
+
+  Error(ERR_WARN, "unknown element token '%s'", token);
+
+  return EL_UNDEFINED;
+}
+
+static int get_token_parameter_value(char *token, char *value_raw)
+{
+  char *suffix;
+
+  if (token == NULL || value_raw == NULL)
+    return ARG_UNDEFINED_VALUE;
+
+  suffix = strrchr(token, '.');
+  if (suffix == NULL)
+    suffix = token;
+
+#if 1
+  if (strEqual(suffix, ".element"))
+    return getElementFromToken(value_raw);
+#endif
+
+#if 0
+  if (strncmp(suffix, ".font", 5) == 0)
+  {
+    int i;
+
+    /* !!! OPTIMIZE THIS BY USING HASH !!! */
+    for (i = 0; i < NUM_FONTS; i++)
+      if (strEqual(value_raw, font_info[i].token_name))
+       return i;
+
+    /* if font not found, use reliable default value */
+    return FONT_INITIAL_1;
+  }
+#endif
+
+  /* !!! USE CORRECT VALUE TYPE (currently works also for TYPE_BOOLEAN) !!! */
+  return get_parameter_value(value_raw, suffix, TYPE_INTEGER);
+}
+
+void InitMenuDesignSettings_Static()
+{
+#if 0
+  static SetupFileHash *image_config_hash = NULL;
+#endif
+  int i;
+
+#if 0
+  if (image_config_hash == NULL)
+  {
+    image_config_hash = newSetupFileHash();
+
+    for (i = 0; image_config[i].token != NULL; i++)
+      setHashEntry(image_config_hash,
+                  image_config[i].token,
+                  image_config[i].value);
+  }
+#endif
+
+#if 1
+  /* always start with reliable default values from static default config */
+  for (i = 0; image_config_vars[i].token != NULL; i++)
+  {
+    char *value = getHashEntry(image_config_hash, image_config_vars[i].token);
+
+    if (value != NULL)
+      *image_config_vars[i].value =
+       get_token_parameter_value(image_config_vars[i].token, value);
+  }
+
+#else
+
+  int j;
+
+  /* always start with reliable default values from static default config */
+  for (i = 0; image_config_vars[i].token != NULL; i++)
+    for (j = 0; image_config[j].token != NULL; j++)
+      if (strEqual(image_config_vars[i].token, image_config[j].token))
+       *image_config_vars[i].value =
+         get_token_parameter_value(image_config_vars[i].token,
+                                   image_config[j].value);
+#endif
+}
+
+static void InitMenuDesignSettings_SpecialPreProcessing()
 {
-  SetupFileHash *setup_file_hash;
   int i;
 
+  /* the following initializes hierarchical values from static configuration */
+
+  /* special case: initialize "ARG_DEFAULT" values in static default config */
+  /* (e.g., initialize "[titlemessage].fade_mode" from "[title].fade_mode") */
+  titlemessage_initial_default.fade_mode  = title_initial_default.fade_mode;
+  titlemessage_initial_default.fade_delay = title_initial_default.fade_delay;
+  titlemessage_initial_default.post_delay = title_initial_default.post_delay;
+  titlemessage_initial_default.auto_delay = title_initial_default.auto_delay;
+  titlemessage_default.fade_mode  = title_default.fade_mode;
+  titlemessage_default.fade_delay = title_default.fade_delay;
+  titlemessage_default.post_delay = title_default.post_delay;
+  titlemessage_default.auto_delay = title_default.auto_delay;
+
+  /* special case: initialize "ARG_DEFAULT" values in static default config */
+  /* (e.g., init "titlemessage_1.fade_mode" from "[titlemessage].fade_mode") */
+  for (i = 0; i < MAX_NUM_TITLE_MESSAGES; i++)
+  {
+    titlemessage_initial[i] = titlemessage_initial_default;
+    titlemessage[i] = titlemessage_default;
+  }
+
+  /* special case: initialize "ARG_DEFAULT" values in static default config */
+  /* (eg, init "menu.enter_screen.SCORES.xyz" from "menu.enter_screen.xyz") */
+  for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
+  {
+    menu.enter_screen[i] = menu.enter_screen[GFX_SPECIAL_ARG_DEFAULT];
+    menu.leave_screen[i] = menu.leave_screen[GFX_SPECIAL_ARG_DEFAULT];
+  }
+
+  /* special case: initialize "ARG_DEFAULT" values in static default config */
+  /* (eg, init "viewport.door_1.MAIN.xyz" from "viewport.door_1.xyz") */
+  for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
+  {
+    viewport.playfield[i] = viewport.playfield[GFX_SPECIAL_ARG_DEFAULT];
+    viewport.door_1[i] = viewport.door_1[GFX_SPECIAL_ARG_DEFAULT];
+    if (i != GFX_SPECIAL_ARG_EDITOR)   /* editor value already initialized */
+      viewport.door_2[i] = viewport.door_2[GFX_SPECIAL_ARG_DEFAULT];
+  }
+}
+
+static void InitMenuDesignSettings_SpecialPostProcessing()
+{
+  /* special case: initialize later added SETUP list size from LEVELS value */
+  if (menu.list_size[GAME_MODE_SETUP] == -1)
+    menu.list_size[GAME_MODE_SETUP] = menu.list_size[GAME_MODE_LEVELS];
+}
+
+static void LoadMenuDesignSettingsFromFilename(char *filename)
+{
+  static struct TitleMessageInfo tmi;
+  static struct TokenInfo titlemessage_tokens[] =
+  {
+    { TYPE_INTEGER,    &tmi.x,                 ".x"                    },
+    { TYPE_INTEGER,    &tmi.y,                 ".y"                    },
+    { TYPE_INTEGER,    &tmi.width,             ".width"                },
+    { TYPE_INTEGER,    &tmi.height,            ".height"               },
+    { TYPE_INTEGER,    &tmi.chars,             ".chars"                },
+    { TYPE_INTEGER,    &tmi.lines,             ".lines"                },
+    { TYPE_INTEGER,    &tmi.align,             ".align"                },
+    { TYPE_INTEGER,    &tmi.valign,            ".valign"               },
+    { TYPE_INTEGER,    &tmi.font,              ".font"                 },
+    { TYPE_BOOLEAN,    &tmi.autowrap,          ".autowrap"             },
+    { TYPE_BOOLEAN,    &tmi.centered,          ".centered"             },
+    { TYPE_BOOLEAN,    &tmi.parse_comments,    ".parse_comments"       },
+    { TYPE_INTEGER,    &tmi.sort_priority,     ".sort_priority"        },
+    { TYPE_INTEGER,    &tmi.fade_mode,         ".fade_mode"            },
+    { TYPE_INTEGER,    &tmi.fade_delay,        ".fade_delay"           },
+    { TYPE_INTEGER,    &tmi.post_delay,        ".post_delay"           },
+    { TYPE_INTEGER,    &tmi.auto_delay,        ".auto_delay"           },
+
+    { -1,              NULL,                   NULL                    }
+  };
+  static struct
+  {
+    struct TitleMessageInfo *array;
+    char *text;
+  }
+  titlemessage_arrays[] =
+  {
+    { titlemessage_initial,            "[titlemessage_initial]"        },
+    { titlemessage,                    "[titlemessage]"                },
+
+    { NULL,                            NULL                            }
+  };
+  SetupFileHash *setup_file_hash;
+  int i, j, k;
+
 #if 0
-  printf("LoadSpecialMenuDesignSettings from file '%s' ...\n", filename);
+  printf("LoadMenuDesignSettings from file '%s' ...\n", filename);
 #endif
 
   if ((setup_file_hash = loadSetupFileHash(filename)) == NULL)
     return;
 
+  /* the following initializes hierarchical values from dynamic configuration */
+
+  /* special case: initialize with default values that may be overwritten */
+  /* (e.g., init "menu.draw_xoffset.INFO" from "menu.draw_xoffset") */
+  for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
+  {
+    char *value_1 = getHashEntry(setup_file_hash, "menu.draw_xoffset");
+    char *value_2 = getHashEntry(setup_file_hash, "menu.draw_yoffset");
+    char *value_3 = getHashEntry(setup_file_hash, "menu.list_size");
+
+    if (value_1 != NULL)
+      menu.draw_xoffset[i] = get_integer_from_string(value_1);
+    if (value_2 != NULL)
+      menu.draw_yoffset[i] = get_integer_from_string(value_2);
+    if (value_3 != NULL)
+      menu.list_size[i] = get_integer_from_string(value_3);
+  }
+
+  /* special case: initialize with default values that may be overwritten */
+  /* (eg, init "menu.draw_xoffset.INFO[XXX]" from "menu.draw_xoffset.INFO") */
+  for (i = 0; i < NUM_SPECIAL_GFX_INFO_ARGS; i++)
+  {
+    char *value_1 = getHashEntry(setup_file_hash, "menu.draw_xoffset.INFO");
+    char *value_2 = getHashEntry(setup_file_hash, "menu.draw_yoffset.INFO");
+
+    if (value_1 != NULL)
+      menu.draw_xoffset_info[i] = get_integer_from_string(value_1);
+    if (value_2 != NULL)
+      menu.draw_yoffset_info[i] = get_integer_from_string(value_2);
+  }
+
+  /* special case: initialize with default values that may be overwritten */
+  /* (eg, init "menu.draw_xoffset.SETUP[XXX]" from "menu.draw_xoffset.SETUP") */
+  for (i = 0; i < NUM_SPECIAL_GFX_SETUP_ARGS; i++)
+  {
+    char *value_1 = getHashEntry(setup_file_hash, "menu.draw_xoffset.SETUP");
+    char *value_2 = getHashEntry(setup_file_hash, "menu.draw_yoffset.SETUP");
+
+    if (value_1 != NULL)
+      menu.draw_xoffset_setup[i] = get_integer_from_string(value_1);
+    if (value_2 != NULL)
+      menu.draw_yoffset_setup[i] = get_integer_from_string(value_2);
+  }
+
+  /* special case: initialize with default values that may be overwritten */
+  /* (eg, init "menu.enter_screen.SCORES.xyz" from "menu.enter_screen.xyz") */
+  for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
+  {
+    char *token_1 = "menu.enter_screen.fade_mode";
+    char *token_2 = "menu.enter_screen.fade_delay";
+    char *token_3 = "menu.enter_screen.post_delay";
+    char *token_4 = "menu.leave_screen.fade_mode";
+    char *token_5 = "menu.leave_screen.fade_delay";
+    char *token_6 = "menu.leave_screen.post_delay";
+    char *value_1 = getHashEntry(setup_file_hash, token_1);
+    char *value_2 = getHashEntry(setup_file_hash, token_2);
+    char *value_3 = getHashEntry(setup_file_hash, token_3);
+    char *value_4 = getHashEntry(setup_file_hash, token_4);
+    char *value_5 = getHashEntry(setup_file_hash, token_5);
+    char *value_6 = getHashEntry(setup_file_hash, token_6);
+
+    if (value_1 != NULL)
+      menu.enter_screen[i].fade_mode = get_token_parameter_value(token_1,
+                                                                value_1);
+    if (value_2 != NULL)
+      menu.enter_screen[i].fade_delay = get_token_parameter_value(token_2,
+                                                                 value_2);
+    if (value_3 != NULL)
+      menu.enter_screen[i].post_delay = get_token_parameter_value(token_3,
+                                                                 value_3);
+    if (value_4 != NULL)
+      menu.leave_screen[i].fade_mode = get_token_parameter_value(token_4,
+                                                                value_4);
+    if (value_5 != NULL)
+      menu.leave_screen[i].fade_delay = get_token_parameter_value(token_5,
+                                                                 value_5);
+    if (value_6 != NULL)
+      menu.leave_screen[i].post_delay = get_token_parameter_value(token_6,
+                                                                 value_6);
+  }
+
   /* special case: initialize with default values that may be overwritten */
+  /* (eg, init "viewport.door_1.MAIN.xyz" from "viewport.door_1.xyz") */
   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
   {
-    char *value_x = getHashEntry(setup_file_hash, "menu.draw_xoffset");
-    char *value_y = getHashEntry(setup_file_hash, "menu.draw_yoffset");
-    char *list_size = getHashEntry(setup_file_hash, "menu.list_size");
+    char *token_1 = "viewport.playfield.x";
+    char *token_2 = "viewport.playfield.y";
+    char *token_3 = "viewport.playfield.width";
+    char *token_4 = "viewport.playfield.height";
+    char *token_5 = "viewport.playfield.border_size";
+    char *token_6 = "viewport.door_1.x";
+    char *token_7 = "viewport.door_1.y";
+    char *token_8 = "viewport.door_2.x";
+    char *token_9 = "viewport.door_2.y";
+    char *value_1 = getHashEntry(setup_file_hash, token_1);
+    char *value_2 = getHashEntry(setup_file_hash, token_2);
+    char *value_3 = getHashEntry(setup_file_hash, token_3);
+    char *value_4 = getHashEntry(setup_file_hash, token_4);
+    char *value_5 = getHashEntry(setup_file_hash, token_5);
+    char *value_6 = getHashEntry(setup_file_hash, token_6);
+    char *value_7 = getHashEntry(setup_file_hash, token_7);
+    char *value_8 = getHashEntry(setup_file_hash, token_8);
+    char *value_9 = getHashEntry(setup_file_hash, token_9);
+
+    if (value_1 != NULL)
+      viewport.playfield[i].x = get_token_parameter_value(token_1, value_1);
+    if (value_2 != NULL)
+      viewport.playfield[i].y = get_token_parameter_value(token_2, value_2);
+    if (value_3 != NULL)
+      viewport.playfield[i].width = get_token_parameter_value(token_3, value_3);
+    if (value_4 != NULL)
+      viewport.playfield[i].height = get_token_parameter_value(token_4,value_4);
+    if (value_5 != NULL)
+      viewport.playfield[i].border_size = get_token_parameter_value(token_5,
+                                                                   value_5);
+    if (value_6 != NULL)
+      viewport.door_1[i].x = get_token_parameter_value(token_6, value_6);
+    if (value_7 != NULL)
+      viewport.door_1[i].y = get_token_parameter_value(token_7, value_7);
+    if (value_8 != NULL)
+      viewport.door_2[i].x = get_token_parameter_value(token_8, value_8);
+    if (value_9 != NULL)
+      viewport.door_2[i].y = get_token_parameter_value(token_9, value_9);
+  }
+
+  /* special case: initialize with default values that may be overwritten */
+  /* (e.g., init "titlemessage_1.fade_mode" from "[titlemessage].fade_mode") */
+  for (i = 0; titlemessage_arrays[i].array != NULL; i++)
+  {
+    struct TitleMessageInfo *array = titlemessage_arrays[i].array;
+    char *base_token = titlemessage_arrays[i].text;
+
+    for (j = 0; titlemessage_tokens[j].type != -1; j++)
+    {
+      char *token = getStringCat2(base_token, titlemessage_tokens[j].text);
+      char *value = getHashEntry(setup_file_hash, token);
+
+      if (value != NULL)
+      {
+       int parameter_value = get_token_parameter_value(token, value);
+
+       for (k = 0; k < MAX_NUM_TITLE_MESSAGES; k++)
+       {
+         tmi = array[k];
+
+         if (titlemessage_tokens[j].type == TYPE_INTEGER)
+           *(boolean *)titlemessage_tokens[j].value = (boolean)parameter_value;
+         else
+           *(int     *)titlemessage_tokens[j].value = (int)parameter_value;
 
-    if (value_x != NULL)
-      menu.draw_xoffset[i] = get_integer_from_string(value_x);
-    if (value_y != NULL)
-      menu.draw_yoffset[i] = get_integer_from_string(value_y);
-    if (list_size != NULL)
-      menu.list_size[i] = get_integer_from_string(list_size);
+         array[k] = tmi;
+       }
+      }
+
+      free(token);
+    }
   }
 
   /* read (and overwrite with) values that may be specified in config file */
@@ -7218,48 +10037,41 @@ static void LoadSpecialMenuDesignSettingsFromFilename(char *filename)
   {
     char *value = getHashEntry(setup_file_hash, image_config_vars[i].token);
 
-    if (value != NULL)
+    /* (ignore definitions set to "[DEFAULT]" which are already initialized) */
+    if (value != NULL && !strEqual(value, ARG_DEFAULT))
       *image_config_vars[i].value =
-       get_auto_parameter_value(image_config_vars[i].token, value);
+       get_token_parameter_value(image_config_vars[i].token, value);
   }
 
   freeSetupFileHash(setup_file_hash);
 }
 
-void LoadSpecialMenuDesignSettings()
+void LoadMenuDesignSettings()
 {
   char *filename_base = UNDEFINED_FILENAME, *filename_local;
-  int i, j;
 
-  /* always start with reliable default values from default config */
-  for (i = 0; image_config_vars[i].token != NULL; i++)
-    for (j = 0; image_config[j].token != NULL; j++)
-      if (strEqual(image_config_vars[i].token, image_config[j].token))
-       *image_config_vars[i].value =
-         get_auto_parameter_value(image_config_vars[i].token,
-                                  image_config[j].value);
+  InitMenuDesignSettings_Static();
+  InitMenuDesignSettings_SpecialPreProcessing();
 
 #if 1
+  if (!GFX_OVERRIDE_ARTWORK(ARTWORK_TYPE_GRAPHICS))
+#else
   if (!SETUP_OVERRIDE_ARTWORK(setup, ARTWORK_TYPE_GRAPHICS))
+#endif
   {
     /* first look for special settings configured in level series config */
     filename_base = getCustomArtworkLevelConfigFilename(ARTWORK_TYPE_GRAPHICS);
 
     if (fileExists(filename_base))
-      LoadSpecialMenuDesignSettingsFromFilename(filename_base);
+      LoadMenuDesignSettingsFromFilename(filename_base);
   }
 
   filename_local = getCustomArtworkConfigFilename(ARTWORK_TYPE_GRAPHICS);
 
   if (filename_local != NULL && !strEqual(filename_base, filename_local))
-    LoadSpecialMenuDesignSettingsFromFilename(filename_local);
-
-#else
-
-  filename_local = getCustomArtworkConfigFilename(ARTWORK_TYPE_GRAPHICS);
+    LoadMenuDesignSettingsFromFilename(filename_local);
 
-  LoadSpecialMenuDesignSettingsFromFilename(filename_local);
-#endif
+  InitMenuDesignSettings_SpecialPostProcessing();
 }
 
 void LoadUserDefinedEditorElementList(int **elements, int *num_elements)
@@ -7317,19 +10129,19 @@ void LoadUserDefinedEditorElementList(int **elements, int *num_elements)
     {
       if (num_unknown_tokens == 0)
       {
-       Error(ERR_RETURN_LINE, "-");
-       Error(ERR_RETURN, "warning: unknown token(s) found in config file:");
-       Error(ERR_RETURN, "- config file: '%s'", filename);
+       Error(ERR_INFO_LINE, "-");
+       Error(ERR_INFO, "warning: unknown token(s) found in config file:");
+       Error(ERR_INFO, "- config file: '%s'", filename);
 
        num_unknown_tokens++;
       }
 
-      Error(ERR_RETURN, "- token: '%s'", list->token);
+      Error(ERR_INFO, "- token: '%s'", list->token);
     }
   }
 
   if (num_unknown_tokens > 0)
-    Error(ERR_RETURN_LINE, "-");
+    Error(ERR_INFO_LINE, "-");
 
   while (*num_elements % 4)    /* pad with empty elements, if needed */
     (*elements)[(*num_elements)++] = EL_EMPTY;
@@ -7417,7 +10229,7 @@ static struct MusicFileInfo *get_music_file_info_ext(char *basename, int music,
 
   /* ---------- music file info found ---------- */
 
-  memset(&tmp_music_file_info, 0, sizeof(struct MusicFileInfo));
+  clear_mem(&tmp_music_file_info, sizeof(struct MusicFileInfo));
 
   for (i = 0; token_to_value_ptr[i].token != NULL; i++)
   {
@@ -7523,6 +10335,10 @@ void LoadMusicInfo()
     if (!music_info_listed(music_file_info, music->filename))
     {
       *new = get_music_file_info(music->filename, i);
+#if 0
+      if (*new != NULL)
+       printf(":1: adding '%s' ['%s'] ...\n", (*new)->title, music->filename);
+#endif
       if (*new != NULL)
        new = &(*new)->next;
     }
@@ -7568,6 +10384,10 @@ void LoadMusicInfo()
     if (!music_info_listed(music_file_info, basename))
     {
       *new = get_music_file_info(basename, MAP_NOCONF_MUSIC(num_music_noconf));
+#if 0
+      if (*new != NULL)
+       printf(":2: adding '%s' ['%s'] ...\n", (*new)->title, basename);
+#endif
       if (*new != NULL)
        new = &(*new)->next;
     }
@@ -7630,18 +10450,18 @@ void print_unknown_token(char *filename, char *token, int token_nr)
 {
   if (token_nr == 0)
   {
-    Error(ERR_RETURN_LINE, "-");
-    Error(ERR_RETURN, "warning: unknown token(s) found in config file:");
-    Error(ERR_RETURN, "- config file: '%s'", filename);
+    Error(ERR_INFO_LINE, "-");
+    Error(ERR_INFO, "warning: unknown token(s) found in config file:");
+    Error(ERR_INFO, "- config file: '%s'", filename);
   }
 
-  Error(ERR_RETURN, "- token: '%s'", token);
+  Error(ERR_INFO, "- token: '%s'", token);
 }
 
 void print_unknown_token_end(int token_nr)
 {
   if (token_nr > 0)
-    Error(ERR_RETURN_LINE, "-");
+    Error(ERR_INFO_LINE, "-");
 }
 
 void LoadHelpAnimInfo()
@@ -7890,9 +10710,9 @@ void LoadHelpTextInfo()
 }
 
 
-/* ------------------------------------------------------------------------- *
- * convert levels
- * ------------------------------------------------------------------------- */
+/* ------------------------------------------------------------------------- */
+/* convert levels                                                            */
+/* ------------------------------------------------------------------------- */
 
 #define MAX_NUM_CONVERT_LEVELS         1000
 
@@ -8002,3 +10822,165 @@ void ConvertLevels()
 
   CloseAllAndExit(0);
 }
+
+
+/* ------------------------------------------------------------------------- */
+/* create and save images for use in level sketches (raw BMP format)         */
+/* ------------------------------------------------------------------------- */
+
+void CreateLevelSketchImages()
+{
+#if defined(TARGET_SDL)
+  Bitmap *bitmap1;
+  Bitmap *bitmap2;
+  int i;
+
+  InitElementPropertiesGfxElement();
+
+  bitmap1 = CreateBitmap(TILEX, TILEY, DEFAULT_DEPTH);
+  bitmap2 = CreateBitmap(MINI_TILEX, MINI_TILEY, DEFAULT_DEPTH);
+
+  for (i = 0; i < NUM_FILE_ELEMENTS; i++)
+  {
+    Bitmap *src_bitmap;
+    int src_x, src_y;
+    int element = getMappedElement(i);
+    int graphic = el2edimg(element);
+    char basename1[16];
+    char basename2[16];
+    char *filename1;
+    char *filename2;
+
+    sprintf(basename1, "%03d.bmp", i);
+    sprintf(basename2, "%03ds.bmp", i);
+
+    filename1 = getPath2(global.create_images_dir, basename1);
+    filename2 = getPath2(global.create_images_dir, basename2);
+
+    getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
+    BlitBitmap(src_bitmap, bitmap1, src_x, src_y, TILEX, TILEY, 0, 0);
+
+    if (SDL_SaveBMP(bitmap1->surface, filename1) != 0)
+      Error(ERR_EXIT, "cannot save level sketch image file '%s'", filename1);
+
+    getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
+    BlitBitmap(src_bitmap, bitmap2, src_x, src_y, MINI_TILEX, MINI_TILEY, 0, 0);
+
+    if (SDL_SaveBMP(bitmap2->surface, filename2) != 0)
+      Error(ERR_EXIT, "cannot save level sketch image file '%s'", filename2);
+
+    free(filename1);
+    free(filename2);
+
+    if (options.debug)
+      printf("%03d `%03d%c", i, i, (i % 10 < 9 ? ' ' : '\n'));
+  }
+
+  FreeBitmap(bitmap1);
+  FreeBitmap(bitmap2);
+
+  if (options.debug)
+    printf("\n");
+
+  Error(ERR_INFO, "%d normal and small images created", NUM_FILE_ELEMENTS);
+
+  CloseAllAndExit(0);
+#endif
+}
+
+
+/* ------------------------------------------------------------------------- */
+/* create and save images for custom and group elements (raw BMP format)     */
+/* ------------------------------------------------------------------------- */
+
+void CreateCustomElementImages()
+{
+#if defined(TARGET_SDL)
+  char *filename = "graphics.classic/RocksCE.bmp";
+  Bitmap *bitmap;
+  Bitmap *src_bitmap;
+  int dummy_graphic = IMG_CUSTOM_99;
+  int yoffset_ce = 0;
+  int yoffset_ge = (TILEY * NUM_CUSTOM_ELEMENTS / 16);
+  int src_x, src_y;
+  int i;
+
+  bitmap = CreateBitmap(TILEX * 16 * 2,
+                       TILEY * (NUM_CUSTOM_ELEMENTS + NUM_GROUP_ELEMENTS) / 16,
+                       DEFAULT_DEPTH);
+
+  getGraphicSource(dummy_graphic, 0, &src_bitmap, &src_x, &src_y);
+
+  for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
+  {
+    int x = i % 16;
+    int y = i / 16;
+    int ii = i + 1;
+    int j;
+
+    BlitBitmap(src_bitmap, bitmap, 0, 0, TILEX, TILEY,
+              TILEX * x, TILEY * y + yoffset_ce);
+
+    BlitBitmap(src_bitmap, bitmap, 0, TILEY, TILEX, TILEY,
+              TILEX * x + TILEX * 16, TILEY * y + yoffset_ce);
+
+    for (j = 2; j >= 0; j--)
+    {
+      int c = ii % 10;
+
+      BlitBitmap(src_bitmap, bitmap, TILEX + c * 7, 0, 6, 10,
+                TILEX * x + 6 + j * 7,
+                TILEY * y + 11 + yoffset_ce);
+
+      BlitBitmap(src_bitmap, bitmap, TILEX + c * 8, TILEY, 6, 10,
+                TILEX * 16 + TILEX * x + 6 + j * 8,
+                TILEY * y + 10 + yoffset_ce);
+
+      ii /= 10;
+    }
+  }
+
+  for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
+  {
+    int x = i % 16;
+    int y = i / 16;
+    int ii = i + 1;
+    int j;
+
+    BlitBitmap(src_bitmap, bitmap, 0, 0, TILEX, TILEY,
+              TILEX * x, TILEY * y + yoffset_ge);
+
+    BlitBitmap(src_bitmap, bitmap, 0, TILEY, TILEX, TILEY,
+              TILEX * x + TILEX * 16, TILEY * y + yoffset_ge);
+
+    for (j = 1; j >= 0; j--)
+    {
+      int c = ii % 10;
+
+      BlitBitmap(src_bitmap, bitmap, TILEX + c * 10, 11, 10, 10,
+                TILEX * x + 6 + j * 10,
+                TILEY * y + 11 + yoffset_ge);
+
+      BlitBitmap(src_bitmap, bitmap, TILEX + c * 8, TILEY + 12, 6, 10,
+                TILEX * 16 + TILEX * x + 10 + j * 8,
+                TILEY * y + 10 + yoffset_ge);
+
+      ii /= 10;
+    }
+  }
+
+  if (SDL_SaveBMP(bitmap->surface, filename) != 0)
+    Error(ERR_EXIT, "cannot save CE graphics file '%s'", filename);
+
+  FreeBitmap(bitmap);
+
+  CloseAllAndExit(0);
+#endif
+}
+
+#if 0
+void CreateLevelSketchImages_TEST()
+{
+  void CreateCustomElementImages()
+}
+#endif