rnd-20061003-2-src
[rocksndiamonds.git] / src / files.c
index 121fdf133424bb1bcfb6720e5bc8a65b1a699b36..1287d1ecd2d1fe041f9edf408ffaa75944c49e17 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_ID_LEN           4       /* IFF style chunk id length  */
 #define CHUNK_SIZE_UNDEFINED   0       /* undefined chunk size == 0  */
 #define CHUNK_SIZE_NONE                -1      /* do not write chunk size    */
-#define FILE_VERS_CHUNK_SIZE   8       /* size of file version chunk */
-#define LEVEL_HEADER_SIZE      80      /* size of level file header  */
-#define LEVEL_HEADER_UNUSED    0       /* unused level header bytes  */
+
+#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_CHUNK_CNT2_UNUSED        11      /* unused CNT2 chunk bytes    */
 #define LEVEL_CHUNK_CNT3_HEADER        16      /* size of level CNT3 header  */
 #define LEVEL_CPART_CUS3_SIZE  134     /* size of CUS3 chunk part    */
 #define LEVEL_CPART_CUS3_UNUSED        15      /* unused CUS3 bytes / part   */
 #define LEVEL_CHUNK_GRP1_SIZE  74      /* size of level GRP1 chunk   */
-#define TAPE_HEADER_SIZE       20      /* size of tape file header   */
-#define TAPE_HEADER_UNUSED     3       /* unused tape header bytes   */
-
-#define LEVEL_CHUNK_CNT3_SIZE(x) (LEVEL_CHUNK_CNT3_HEADER + (x))
-#define LEVEL_CHUNK_CUS3_SIZE(x) (2 + (x) * LEVEL_CPART_CUS3_SIZE)
-#define LEVEL_CHUNK_CUS4_SIZE(x) (48 + 48 + (x) * 48)
-
-/* file identifier strings */
-#define LEVEL_COOKIE_TMPL      "ROCKSNDIAMONDS_LEVEL_FILE_VERSION_x.x"
-#define TAPE_COOKIE_TMPL       "ROCKSNDIAMONDS_TAPE_FILE_VERSION_x.x"
-#define SCORE_COOKIE           "ROCKSNDIAMONDS_SCORE_FILE_VERSION_1.2"
-
-/* values for "CONF" chunk */
-#define CONF_MASK_1_BYTE       0x00
-#define CONF_MASK_2_BYTE       0x40
-#define CONF_MASK_4_BYTE       0x80
-#define CONF_MASK_MULTI_BYTES  0xc0
-
-#define CONF_MASK_BYTES                0xc0
-#define CONF_MASK_TOKEN                0x3f
-
-#define CONF_LAST_ENTRY                (CONF_MASK_1_BYTE | 0)
 
-#define CONF_VALUE_INTEGER_1   (CONF_MASK_1_BYTE | 1)
-#define CONF_VALUE_INTEGER_2   (CONF_MASK_1_BYTE | 2)
-#define CONF_VALUE_INTEGER_3   (CONF_MASK_1_BYTE | 3)
-#define CONF_VALUE_INTEGER_4   (CONF_MASK_1_BYTE | 4)
-#define CONF_VALUE_BOOLEAN_1   (CONF_MASK_1_BYTE | 5)
-#define CONF_VALUE_BOOLEAN_2   (CONF_MASK_1_BYTE | 6)
-#define CONF_VALUE_BOOLEAN_3   (CONF_MASK_1_BYTE | 7)
-#define CONF_VALUE_BOOLEAN_4   (CONF_MASK_1_BYTE | 8)
+/* (element number, number of change pages, change page number) */
+#define LEVEL_CHUNK_CUSX_UNCHANGED     (2 + (1 + 1) + (1 + 1))
 
-#define CONF_VALUE_ELEMENT_1   (CONF_MASK_2_BYTE | 1)
-#define CONF_VALUE_ELEMENT_2   (CONF_MASK_2_BYTE | 2)
-#define CONF_VALUE_ELEMENT_3   (CONF_MASK_2_BYTE | 3)
-#define CONF_VALUE_ELEMENT_4   (CONF_MASK_2_BYTE | 4)
+/* (element number only) */
+#define LEVEL_CHUNK_GRPX_UNCHANGED     2
+#define LEVEL_CHUNK_NOTE_UNCHANGED     2
 
-#define CONF_VALUE_CONTENT_1   (CONF_MASK_MULTI_BYTES | 1)
-#define CONF_VALUE_CONTENT_8   (CONF_MASK_MULTI_BYTES | 2)
+/* (nothing at all if unchanged) */
+#define LEVEL_CHUNK_ELEM_UNCHANGED     0
 
-#define CONF_VALUE_INTEGER(x)  ((x) >= CONF_VALUE_INTEGER_1 &&         \
-                                (x) <= CONF_VALUE_INTEGER_4)
+#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 CONF_VALUE_BOOLEAN(x)  ((x) >= CONF_VALUE_BOOLEAN_1 &&         \
-                                (x) <= CONF_VALUE_BOOLEAN_4)
+#define LEVEL_CHUNK_CNT3_SIZE(x)        (LEVEL_CHUNK_CNT3_HEADER + (x))
+#define LEVEL_CHUNK_CUS3_SIZE(x)        (2 + (x) * LEVEL_CPART_CUS3_SIZE)
+#define LEVEL_CHUNK_CUS4_SIZE(x)        (96 + (x) * 48)
 
-#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)
+/* file identifier strings */
+#define LEVEL_COOKIE_TMPL              "ROCKSNDIAMONDS_LEVEL_FILE_VERSION_x.x"
+#define TAPE_COOKIE_TMPL               "ROCKSNDIAMONDS_TAPE_FILE_VERSION_x.x"
+#define SCORE_COOKIE                   "ROCKSNDIAMONDS_SCORE_FILE_VERSION_1.2"
+
+/* 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_MASK_MULTI_BYTES          0xc0
+
+#define CONF_MASK_BYTES                        0xc0
+#define CONF_MASK_TOKEN                        0x3f
+
+#define CONF_VALUE_1_BYTE(x)           (CONF_MASK_1_BYTE       | (x))
+#define CONF_VALUE_2_BYTE(x)           (CONF_MASK_2_BYTE       | (x))
+#define CONF_VALUE_4_BYTE(x)           (CONF_MASK_4_BYTE       | (x))
+#define CONF_VALUE_MULTI_BYTES(x)      (CONF_MASK_MULTI_BYTES  | (x))
+
+/* 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)
+
+#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)
 
 #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) == TYPE_ELEMENT ||         \
+                                        (t) == TYPE_ELEMENT_LIST ?     \
+                                        CONF_ELEMENT_NUM_BYTES :       \
+                                        (t) == TYPE_CONTENT ||         \
+                                        (t) == TYPE_CONTENT_LIST ?     \
+                                        CONF_CONTENT_NUM_BYTES : 1)
+
+#define CONF_ELEMENT_BYTE_POS(i)       ((i) * CONF_ELEMENT_NUM_BYTES)
+#define CONF_ELEMENTS_ELEMENT(b,i)     ((b[CONF_ELEMENT_BYTE_POS(i)] << 8) |  \
+                                       (b[CONF_ELEMENT_BYTE_POS(i) + 1]))
 
 #define CONF_CONTENT_ELEMENT_POS(c,x,y)        ((c) * CONF_CONTENT_NUM_ELEMENTS +    \
                                         (y) * 3 + (x))
-#define CONF_CONTENT_BYTE_POS(c,x,y)   (CONF_CONTENT_ELEMENT_POS(c,x,y) * 2)
-#define CONF_CONTENT_ELEMENT(b,c,x,y) ((b[CONF_CONTENT_BYTE_POS(c,x,y)] << 8)|\
-                                      (b[CONF_CONTENT_BYTE_POS(c,x,y) + 1]))
+#define CONF_CONTENT_BYTE_POS(c,x,y)   (CONF_CONTENT_ELEMENT_POS(c,x,y) *    \
+                                        CONF_ELEMENT_NUM_BYTES)
+#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]))
 
+/* 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_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 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 */
+  int default_value;           /* initial default value for this variable */
+
+  /* (optional) */
+  void *value_copy;            /* variable that holds the data to be copied */
+  void *num_entities;          /* number of entities for multi-byte data */
+  int default_num_entities;    /* default number of entities for this data */
+  int max_num_entities;                /* maximal number of entities for this data */
+  char *default_string;                /* optional default string for string data */
+};
 
-static struct
+static struct LevelFileConfigInfo chunk_config_INFO[] =
 {
-  int element;
-  int type;
-  void *value;
-  int default_value;
-} element_conf[] =
+  /* ---------- values not related to single elements ----------------------- */
+
+  {
+    -1,                                        SAVE_CONF_ALWAYS,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(1),
+    &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_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_INTEGER,                      CONF_VALUE_16_BIT(5),
+    &li.score[SC_TIME_BONUS],          1
+  },
+
+  {
+    -1,                                        -1,
+    -1,                                        -1,
+    NULL,                              -1
+  }
+};
+
+static struct LevelFileConfigInfo chunk_config_ELEM[] =
 {
-  /* ---------- 1-byte values ---------------------------------------------- */
+  /* (these values are the same for each player) */
   {
-    EL_EMC_ANDROID,                    CONF_VALUE_INTEGER_1,
-    &li.android_move_time,             10
+    EL_PLAYER_1,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(1),
+    &li.block_last_field,              FALSE   /* default case for EM levels */
   },
   {
-    EL_EMC_ANDROID,                    CONF_VALUE_INTEGER_2,
-    &li.android_clone_time,            10
+    EL_PLAYER_1,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(2),
+    &li.sp_block_last_field,           TRUE    /* default case for SP levels */
   },
   {
-    EL_EMC_MAGIC_BALL,                 CONF_VALUE_INTEGER_1,
-    &li.ball_time,                     10
+    EL_PLAYER_1,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(3),
+    &li.instant_relocation,            FALSE
   },
   {
-    EL_EMC_LENSES,                     CONF_VALUE_INTEGER_1,
-    &li.lenses_score,                  10
+    EL_PLAYER_1,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(4),
+    &li.can_pass_to_walkable,          FALSE
   },
   {
-    EL_EMC_LENSES,                     CONF_VALUE_INTEGER_2,
-    &li.lenses_time,                   10
+    EL_PLAYER_1,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(5),
+    &li.block_snap_field,              TRUE
   },
   {
-    EL_EMC_MAGNIFIER,                  CONF_VALUE_INTEGER_1,
-    &li.magnify_score,                 10
+    EL_PLAYER_1,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(6),
+    &li.continuous_snapping,           TRUE
   },
+
+  /* (these values are different for each player) */
   {
-    EL_EMC_MAGNIFIER,                  CONF_VALUE_INTEGER_2,
-    &li.magnify_time,                  10
+    EL_PLAYER_1,                       -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(7),
+    &li.initial_player_stepsize[0],    STEPSIZE_NORMAL
+  },
+  {
+    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,                       -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(10),
+    &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(11),
+    &li.use_explosion_element[0],      FALSE
+  },
+  {
+    EL_PLAYER_1,                       -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(3),
+    &li.explosion_element[0],          EL_PLAYER_1
+  },
+
+  {
+    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,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(9),
+    &li.use_start_element[1],          FALSE
+  },
+  {
+    EL_PLAYER_2,                       -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(1),
+    &li.start_element[1],              EL_PLAYER_2
+  },
+  {
+    EL_PLAYER_2,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(10),
+    &li.use_artwork_element[1],                FALSE
+  },
+  {
+    EL_PLAYER_2,                       -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(2),
+    &li.artwork_element[1],            EL_PLAYER_2
+  },
+  {
+    EL_PLAYER_2,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(11),
+    &li.use_explosion_element[1],      FALSE
+  },
+  {
+    EL_PLAYER_2,                       -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(3),
+    &li.explosion_element[1],          EL_PLAYER_2
+  },
+
+  {
+    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,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(9),
+    &li.use_start_element[2],          FALSE
+  },
+  {
+    EL_PLAYER_3,                       -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(1),
+    &li.start_element[2],              EL_PLAYER_3
+  },
+  {
+    EL_PLAYER_3,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(10),
+    &li.use_artwork_element[2],                FALSE
+  },
+  {
+    EL_PLAYER_3,                       -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(2),
+    &li.artwork_element[2],            EL_PLAYER_3
+  },
+  {
+    EL_PLAYER_3,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(11),
+    &li.use_explosion_element[2],      FALSE
+  },
+  {
+    EL_PLAYER_3,                       -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(3),
+    &li.explosion_element[2],          EL_PLAYER_3
+  },
+
+  {
+    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,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(9),
+    &li.use_start_element[3],          FALSE
+  },
+  {
+    EL_PLAYER_4,                       -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(1),
+    &li.start_element[3],              EL_PLAYER_4
+  },
+  {
+    EL_PLAYER_4,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(10),
+    &li.use_artwork_element[3],                FALSE
+  },
+  {
+    EL_PLAYER_4,                       -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(2),
+    &li.artwork_element[3],            EL_PLAYER_4
+  },
+  {
+    EL_PLAYER_4,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(11),
+    &li.use_explosion_element[3],      FALSE
+  },
+  {
+    EL_PLAYER_4,                       -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(3),
+    &li.explosion_element[3],          EL_PLAYER_4
+  },
+
+  {
+    EL_EMERALD,                                -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.score[SC_EMERALD],             10
+  },
+
+  {
+    EL_DIAMOND,                                -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.score[SC_DIAMOND],             10
+  },
+
+  {
+    EL_BUG,                            -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.score[SC_BUG],                 10
+  },
+
+  {
+    EL_SPACESHIP,                      -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.score[SC_SPACESHIP],           10
+  },
+
+  {
+    EL_PACMAN,                         -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.score[SC_PACMAN],              10
+  },
+
+  {
+    EL_NUT,                            -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.score[SC_NUT],                 10
+  },
+
+  {
+    EL_DYNAMITE,                       -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.score[SC_DYNAMITE],            10
+  },
+
+  {
+    EL_KEY_1,                          -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.score[SC_KEY],                 10
+  },
+
+  {
+    EL_PEARL,                          -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.score[SC_PEARL],               10
+  },
+
+  {
+    EL_CRYSTAL,                                -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.score[SC_CRYSTAL],             10
+  },
+
+  {
+    EL_BD_AMOEBA,                      -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(1),
+    &li.amoeba_content,                        EL_DIAMOND
+  },
+  {
+    EL_BD_AMOEBA,                      -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(2),
+    &li.amoeba_speed,                  10
+  },
+  {
+    EL_BD_AMOEBA,                      -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(1),
+    &li.grow_into_diggable,            TRUE
+  },
+
+  {
+    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,                         -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.score[SC_YAMYAM],              10
+  },
+
+  {
+    EL_ROBOT,                          -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.score[SC_ROBOT],               10
   },
   {
-    EL_ROBOT,                          CONF_VALUE_INTEGER_1,
+    EL_ROBOT,                          -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(2),
     &li.slurp_score,                   10
   },
+
+  {
+    EL_ROBOT_WHEEL,                    -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.time_wheel,                    10
+  },
+
   {
-    EL_GAME_OF_LIFE,                   CONF_VALUE_INTEGER_1,
+    EL_MAGIC_WALL,                     -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.time_magic_wall,               10
+  },
+
+  {
+    EL_GAME_OF_LIFE,                   -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(1),
     &li.game_of_life[0],               2
   },
   {
-    EL_GAME_OF_LIFE,                   CONF_VALUE_INTEGER_2,
+    EL_GAME_OF_LIFE,                   -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(2),
     &li.game_of_life[1],               3
   },
   {
-    EL_GAME_OF_LIFE,                   CONF_VALUE_INTEGER_3,
+    EL_GAME_OF_LIFE,                   -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(3),
     &li.game_of_life[2],               3
   },
   {
-    EL_GAME_OF_LIFE,                   CONF_VALUE_INTEGER_4,
+    EL_GAME_OF_LIFE,                   -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(4),
     &li.game_of_life[3],               3
   },
+
   {
-    EL_BIOMAZE,                                CONF_VALUE_INTEGER_1,
+    EL_BIOMAZE,                                -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(1),
     &li.biomaze[0],                    2
   },
   {
-    EL_BIOMAZE,                                CONF_VALUE_INTEGER_2,
+    EL_BIOMAZE,                                -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(2),
     &li.biomaze[1],                    3
   },
   {
-    EL_BIOMAZE,                                CONF_VALUE_INTEGER_3,
+    EL_BIOMAZE,                                -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(3),
     &li.biomaze[2],                    3
   },
   {
-    EL_BIOMAZE,                                CONF_VALUE_INTEGER_4,
+    EL_BIOMAZE,                                -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(4),
     &li.biomaze[3],                    3
   },
+
   {
-    EL_BALLOON,                                CONF_VALUE_INTEGER_1,
-    &li.wind_direction_initial,                MV_NONE
-  },
-  {
-    EL_TIMEGATE_SWITCH,                        CONF_VALUE_INTEGER_1,
+    EL_TIMEGATE_SWITCH,                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
     &li.time_timegate,                 10
   },
+
   {
-    EL_LIGHT_SWITCH_ACTIVE,            CONF_VALUE_INTEGER_1,
+    EL_LIGHT_SWITCH_ACTIVE,            -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
     &li.time_light,                    10
   },
+
   {
-    EL_SHIELD_NORMAL,                  CONF_VALUE_INTEGER_1,
+    EL_SHIELD_NORMAL,                  -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
     &li.shield_normal_time,            10
   },
   {
-    EL_SHIELD_DEADLY,                  CONF_VALUE_INTEGER_1,
+    EL_SHIELD_NORMAL,                  -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(2),
+    &li.score[SC_SHIELD],              10
+  },
+
+  {
+    EL_SHIELD_DEADLY,                  -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
     &li.shield_deadly_time,            10
   },
   {
-    EL_EXTRA_TIME,                     CONF_VALUE_INTEGER_1,
+    EL_SHIELD_DEADLY,                  -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(2),
+    &li.score[SC_SHIELD],              10
+  },
+
+  {
+    EL_EXTRA_TIME,                     -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
     &li.extra_time,                    10
   },
   {
-    EL_TIME_ORB_FULL,                  CONF_VALUE_INTEGER_1,
+    EL_EXTRA_TIME,                     -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(2),
+    &li.extra_time_score,              10
+  },
+
+  {
+    EL_TIME_ORB_FULL,                  -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
     &li.time_orb_time,                 10
   },
+  {
+    EL_TIME_ORB_FULL,                  -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(1),
+    &li.use_time_orb_bug,              FALSE
+  },
+
+  {
+    EL_SPRING,                         -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(1),
+    &li.use_spring_bug,                        FALSE
+  },
+
+  {
+    EL_EMC_ANDROID,                    -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.android_move_time,             10
+  },
+  {
+    EL_EMC_ANDROID,                    -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(2),
+    &li.android_clone_time,            10
+  },
+  {
+    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,                     -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.lenses_score,                  10
+  },
+  {
+    EL_EMC_LENSES,                     -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(2),
+    &li.lenses_time,                   10
+  },
+
+  {
+    EL_EMC_MAGNIFIER,                  -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.magnify_score,                 10
+  },
+  {
+    EL_EMC_MAGNIFIER,                  -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(2),
+    &li.magnify_time,                  10
+  },
+
+  {
+    EL_EMC_MAGIC_BALL,                 -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.ball_time,                     10
+  },
+  {
+    EL_EMC_MAGIC_BALL,                 -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(1),
+    &li.ball_random,                   FALSE
+  },
+  {
+    EL_EMC_MAGIC_BALL,                 -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(2),
+    &li.ball_state_initial,            FALSE
+  },
+  {
+    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
+  },
+
+  /* ---------- unused values ----------------------------------------------- */
 
-  /* ---------- multi-byte values ------------------------------------------ */
   {
-    EL_EMC_MAGIC_BALL,                 CONF_VALUE_CONTENT_8,
-    &li.ball_content,                  EL_EMPTY
+    EL_UNKNOWN,                                SAVE_CONF_NEVER,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.score[SC_UNKNOWN_14],          10
+  },
+  {
+    EL_UNKNOWN,                                SAVE_CONF_NEVER,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(2),
+    &li.score[SC_UNKNOWN_15],          10
   },
 
   {
+    -1,                                        -1,
     -1,                                        -1,
     NULL,                              -1
-  },
+  }
 };
 
-static struct
+static struct LevelFileConfigInfo chunk_config_NOTE[] =
 {
-  int filetype;
-  char *id;
-}
-filetype_id_list[] =
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(1),
+    &xx_envelope.xsize,                        MAX_ENVELOPE_XSIZE,
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(2),
+    &xx_envelope.ysize,                        MAX_ENVELOPE_YSIZE,
+  },
+
+  {
+    -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,                                        -1,
+    -1,                                        -1,
+    NULL,                              -1
+  }
+};
+
+static struct LevelFileConfigInfo chunk_config_CUSX_base[] =
+{
+  {
+    -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,                                        -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,
+    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]
+  },
+#endif
+
+  {
+    -1,                                        -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(1),
+    &xx_ei.use_gfx_element,            FALSE,
+    &yy_ei.use_gfx_element
+  },
+  {
+    -1,                                        -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(1),
+    &xx_ei.gfx_element,                        EL_EMPTY_SPACE,
+    &yy_ei.gfx_element
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_BITFIELD,                     CONF_VALUE_8_BIT(2),
+    &xx_ei.access_direction,           MV_ALL_DIRECTIONS,
+    &yy_ei.access_direction
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(2),
+    &xx_ei.collect_score_initial,      10,
+    &yy_ei.collect_score_initial
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(3),
+    &xx_ei.collect_count_initial,      1,
+    &yy_ei.collect_count_initial
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(4),
+    &xx_ei.ce_value_fixed_initial,     0,
+    &yy_ei.ce_value_fixed_initial
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(5),
+    &xx_ei.ce_value_random_initial,    0,
+    &yy_ei.ce_value_random_initial
+  },
+  {
+    -1,                                        -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(3),
+    &xx_ei.use_last_ce_value,          FALSE,
+    &yy_ei.use_last_ce_value
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(6),
+    &xx_ei.push_delay_fixed,           8,
+    &yy_ei.push_delay_fixed
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(7),
+    &xx_ei.push_delay_random,          8,
+    &yy_ei.push_delay_random
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(8),
+    &xx_ei.drop_delay_fixed,           0,
+    &yy_ei.drop_delay_fixed
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(9),
+    &xx_ei.drop_delay_random,          0,
+    &yy_ei.drop_delay_random
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(10),
+    &xx_ei.move_delay_fixed,           0,
+    &yy_ei.move_delay_fixed
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(11),
+    &xx_ei.move_delay_random,          0,
+    &yy_ei.move_delay_random
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_BITFIELD,                     CONF_VALUE_32_BIT(3),
+    &xx_ei.move_pattern,               MV_ALL_DIRECTIONS,
+    &yy_ei.move_pattern
+  },
+  {
+    -1,                                        -1,
+    TYPE_BITFIELD,                     CONF_VALUE_8_BIT(4),
+    &xx_ei.move_direction_initial,     MV_START_AUTOMATIC,
+    &yy_ei.move_direction_initial
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(5),
+    &xx_ei.move_stepsize,              TILEX / 8,
+    &yy_ei.move_stepsize
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(12),
+    &xx_ei.move_enter_element,         EL_EMPTY_SPACE,
+    &yy_ei.move_enter_element
+  },
+  {
+    -1,                                        -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(13),
+    &xx_ei.move_leave_element,         EL_EMPTY_SPACE,
+    &yy_ei.move_leave_element
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(6),
+    &xx_ei.move_leave_type,            LEAVE_TYPE_UNLIMITED,
+    &yy_ei.move_leave_type
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(7),
+    &xx_ei.slippery_type,              SLIPPERY_ANY_RANDOM,
+    &yy_ei.slippery_type
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(8),
+    &xx_ei.explosion_type,             EXPLODES_3X3,
+    &yy_ei.explosion_type
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(14),
+    &xx_ei.explosion_delay,            16,
+    &yy_ei.explosion_delay
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(15),
+    &xx_ei.ignition_delay,             8,
+    &yy_ei.ignition_delay
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_CONTENT_LIST,                 CONF_VALUE_BYTES(2),
+    &xx_ei.content,                    EL_EMPTY_SPACE,
+    &yy_ei.content,
+    &xx_num_contents,                  1, 1
+  },
+
+  /* ---------- "num_change_pages" must be the last entry ------------------- */
+
+  {
+    -1,                                        SAVE_CONF_ALWAYS,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(9),
+    &xx_ei.num_change_pages,           1,
+    &yy_ei.num_change_pages
+  },
+
+  {
+    -1,                                        -1,
+    -1,                                        -1,
+    NULL,                              -1,
+    NULL
+  }
+};
+
+static struct LevelFileConfigInfo chunk_config_CUSX_change[] =
+{
+  /* ---------- "current_change_page" must be the first entry --------------- */
+
+  {
+    -1,                                        SAVE_CONF_ALWAYS,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(1),
+    &xx_current_change_page,           -1
+  },
+
+  /* ---------- (the remaining entries can be in any order) ----------------- */
+
+  {
+    -1,                                        -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(2),
+    &xx_change.can_change,             FALSE
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_BITFIELD,                     CONF_VALUE_32_BIT(1),
+    &xx_event_bits[0],                 0
+  },
+  {
+    -1,                                        -1,
+    TYPE_BITFIELD,                     CONF_VALUE_32_BIT(2),
+    &xx_event_bits[1],                 0
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_BITFIELD,                     CONF_VALUE_8_BIT(3),
+    &xx_change.trigger_player,         CH_PLAYER_ANY
+  },
+  {
+    -1,                                        -1,
+    TYPE_BITFIELD,                     CONF_VALUE_8_BIT(4),
+    &xx_change.trigger_side,           CH_SIDE_ANY
+  },
+  {
+    -1,                                        -1,
+    TYPE_BITFIELD,                     CONF_VALUE_32_BIT(3),
+    &xx_change.trigger_page,           CH_PAGE_ANY
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(1),
+    &xx_change.target_element,         EL_EMPTY_SPACE
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(2),
+    &xx_change.delay_fixed,            0
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(3),
+    &xx_change.delay_random,           0
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(4),
+    &xx_change.delay_frames,           FRAMES_PER_SECOND
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(5),
+    &xx_change.trigger_element,                EL_EMPTY_SPACE
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(6),
+    &xx_change.explode,                        FALSE
+  },
+  {
+    -1,                                        -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(7),
+    &xx_change.use_target_content,     FALSE
+  },
+  {
+    -1,                                        -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(8),
+    &xx_change.only_if_complete,       FALSE
+  },
+  {
+    -1,                                        -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(9),
+    &xx_change.use_random_replace,     FALSE
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(10),
+    &xx_change.random_percentage,      100
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(11),
+    &xx_change.replace_when,           CP_WHEN_EMPTY
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(12),
+    &xx_change.has_action,             FALSE
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(13),
+    &xx_change.action_type,            CA_NO_ACTION
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(14),
+    &xx_change.action_mode,            CA_MODE_UNDEFINED
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(6),
+    &xx_change.action_arg,             CA_ARG_UNDEFINED
+  },
+
+  {
+    -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,                                        -1,
+    NULL,                              -1
+  }
+};
+
+static struct LevelFileConfigInfo chunk_config_GRPX[] =
+{
+  {
+    -1,                                        -1,
+    TYPE_STRING,                       CONF_VALUE_BYTES(1),
+    &xx_ei.description[0],             -1, NULL,
+    &xx_string_length_unused,          -1, MAX_ELEMENT_NAME_LEN,
+    &xx_default_description[0]
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(1),
+    &xx_ei.use_gfx_element,            FALSE
+  },
+  {
+    -1,                                        -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(1),
+    &xx_ei.gfx_element,                        EL_EMPTY_SPACE
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(2),
+    &xx_group.choice_mode,             ANIM_RANDOM
+  },
+
+  {
+    -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,                                        -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
+{
+  int filetype;
+  char *id;
+}
+filetype_id_list[] =
 {
   { LEVEL_FILE_TYPE_RND,       "RND"   },
   { LEVEL_FILE_TYPE_BD,                "BD"    },
@@ -230,42 +1212,220 @@ filetype_id_list[] =
 };
 
 
-/* ========================================================================= */
-/* level file functions                                                      */
-/* ========================================================================= */
+/* ========================================================================= */
+/* level file functions                                                      */
+/* ========================================================================= */
+
+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;
+
+  return date;
+}
+
+static void resetEventFlags(struct ElementChangeInfo *change)
+{
+  int i;
+
+  for (i = 0; i < NUM_CHANGE_EVENTS; i++)
+    change->has_event[i] = FALSE;
+}
+
+static void resetEventBits()
+{
+  int i;
+
+  for (i = 0; i < NUM_CE_BITFIELDS; i++)
+    xx_event_bits[i] = 0;
+}
+
+static void setEventFlagsFromEventBits(struct ElementChangeInfo *change)
+{
+  int i;
+
+  /* important: only change event flag if corresponding event bit is set */
+  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;
+}
+
+static void setEventBitsFromEventFlags(struct ElementChangeInfo *change)
+{
+  int i;
+
+  /* important: only change event bit if corresponding event flag is set */
+  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);
+}
+
+static char *getDefaultElementDescription(struct ElementInfo *ei)
+{
+  static char description[MAX_ELEMENT_NAME_LEN + 1];
+  char *default_description = (ei->custom_description != NULL ?
+                              ei->custom_description :
+                              ei->editor_description);
+  int i;
+
+  /* always start with reliable default values */
+  for (i = 0; i < MAX_ELEMENT_NAME_LEN + 1; i++)
+    description[i] = '\0';
+
+  /* truncate element description to MAX_ELEMENT_NAME_LEN bytes */
+  strncpy(description, default_description, MAX_ELEMENT_NAME_LEN);
+
+  return &description[0];
+}
+
+static void setElementDescriptionToDefault(struct ElementInfo *ei)
+{
+  char *default_description = getDefaultElementDescription(ei);
+  int i;
+
+  for (i = 0; i < MAX_ELEMENT_NAME_LEN + 1; i++)
+    ei->description[i] = default_description[i];
+}
+
+static void setConfigToDefaultsFromConfigList(struct LevelFileConfigInfo *conf)
+{
+  int i;
+
+  for (i = 0; conf[i].data_type != -1; i++)
+  {
+    int default_value = conf[i].default_value;
+    int data_type = conf[i].data_type;
+    int conf_type = conf[i].conf_type;
+    int byte_mask = conf_type & CONF_MASK_BYTES;
+
+    if (byte_mask == CONF_MASK_MULTI_BYTES)
+    {
+      int default_num_entities = conf[i].default_num_entities;
+      int max_num_entities = conf[i].max_num_entities;
+
+      *(int *)(conf[i].num_entities) = default_num_entities;
+
+      if (data_type == TYPE_STRING)
+      {
+       char *default_string = conf[i].default_string;
+       char *string = (char *)(conf[i].value);
+
+       strncpy(string, default_string, max_num_entities);
+      }
+      else if (data_type == TYPE_ELEMENT_LIST)
+      {
+       int *element_array = (int *)(conf[i].value);
+       int j;
+
+       for (j = 0; j < max_num_entities; j++)
+         element_array[j] = default_value;
+      }
+      else if (data_type == TYPE_CONTENT_LIST)
+      {
+       struct Content *content = (struct Content *)(conf[i].value);
+       int c, x, y;
+
+       for (c = 0; c < max_num_entities; c++)
+         for (y = 0; y < 3; y++)
+           for (x = 0; x < 3; x++)
+             content[c].e[x][y] = default_value;
+      }
+    }
+    else       /* constant size configuration data (1, 2 or 4 bytes) */
+    {
+      if (data_type == TYPE_BOOLEAN)
+       *(boolean *)(conf[i].value) = default_value;
+      else
+       *(int *)    (conf[i].value) = default_value;
+    }
+  }
+}
 
-static void setLevelInfoToDefaultsFromConfigList(struct LevelInfo *level)
+static void copyConfigFromConfigList(struct LevelFileConfigInfo *conf)
 {
   int i;
 
-  li = *level;         /* copy level information into temporary buffer */
-
-  for (i = 0; element_conf[i].element != -1; i++)
+  for (i = 0; conf[i].data_type != -1; i++)
   {
-    int default_value = element_conf[i].default_value;
-    int type = element_conf[i].type;
-    int bytes = type & CONF_MASK_BYTES;
+    int data_type = conf[i].data_type;
+    int conf_type = conf[i].conf_type;
+    int byte_mask = conf_type & CONF_MASK_BYTES;
 
-    if (bytes != CONF_MASK_MULTI_BYTES)
+    if (byte_mask == CONF_MASK_MULTI_BYTES)
     {
-      if (CONF_VALUE_BOOLEAN(type))
-       *(boolean *)(element_conf[i].value) = default_value;
-      else
-       *(int *)    (element_conf[i].value) = default_value;
+      int max_num_entities = conf[i].max_num_entities;
+
+      if (data_type == TYPE_STRING)
+      {
+       char *string      = (char *)(conf[i].value);
+       char *string_copy = (char *)(conf[i].value_copy);
+
+       strncpy(string_copy, string, max_num_entities);
+      }
+      else if (data_type == TYPE_ELEMENT_LIST)
+      {
+       int *element_array      = (int *)(conf[i].value);
+       int *element_array_copy = (int *)(conf[i].value_copy);
+       int j;
+
+       for (j = 0; j < max_num_entities; j++)
+         element_array_copy[j] = element_array[j];
+      }
+      else if (data_type == TYPE_CONTENT_LIST)
+      {
+       struct Content *content      = (struct Content *)(conf[i].value);
+       struct Content *content_copy = (struct Content *)(conf[i].value_copy);
+       int c, x, y;
+
+       for (c = 0; c < max_num_entities; c++)
+         for (y = 0; y < 3; y++)
+           for (x = 0; x < 3; x++)
+             content_copy[c].e[x][y] = content[c].e[x][y];
+      }
     }
-    else if (type == CONF_VALUE_CONTENT_8)
+    else       /* constant size configuration data (1, 2 or 4 bytes) */
     {
-      struct Content *content = (struct Content *)(element_conf[i].value);
-      int c, x, y;
-
-      for (c = 0; c < MAX_ELEMENT_CONTENTS; c++)
-       for (y = 0; y < 3; y++)
-         for (x = 0; x < 3; x++)
-           content[c].e[x][y] = default_value;
+      if (data_type == TYPE_BOOLEAN)
+       *(boolean *)(conf[i].value_copy) = *(boolean *)(conf[i].value);
+      else
+       *(int *)    (conf[i].value_copy) = *(int *)    (conf[i].value);
     }
   }
+}
+
+void copyElementInfo(struct ElementInfo *ei_from, struct ElementInfo *ei_to)
+{
+  int i;
+
+  xx_ei = *ei_from;    /* copy element data into temporary buffer */
+  yy_ei = *ei_to;      /* copy element data into temporary buffer */
+
+  copyConfigFromConfigList(chunk_config_CUSX_base);
+
+  *ei_from = xx_ei;
+  *ei_to   = yy_ei;
 
-  *level = li;         /* copy temporary buffer back to level information */
+  /* ---------- reinitialize and copy change pages ---------- */
+
+  ei_to->num_change_pages = ei_from->num_change_pages;
+  ei_to->current_change_page = ei_from->current_change_page;
+
+  setElementChangePages(ei_to, ei_to->num_change_pages);
+
+  for (i = 0; i < ei_to->num_change_pages; i++)
+    ei_to->change_page[i] = ei_from->change_page[i];
+
+  /* ---------- copy group element info ---------- */
+  if (ei_from->group != NULL && ei_to->group != NULL)  /* group or internal */
+    *ei_to->group = *ei_from->group;
+
+  /* mark this custom element as modified */
+  ei_to->modified_settings = TRUE;
 }
 
 void setElementChangePages(struct ElementInfo *ei, int change_pages)
@@ -285,40 +1445,14 @@ void setElementChangePages(struct ElementInfo *ei, int change_pages)
 
 void setElementChangeInfoToDefaults(struct ElementChangeInfo *change)
 {
-  int i, x, y;
-
-  change->can_change = FALSE;
+  xx_change = *change;         /* copy change data into temporary buffer */
+  xx_num_contents = 1;
 
-  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;
+  setConfigToDefaultsFromConfigList(chunk_config_CUSX_change);
 
-  change->delay_fixed = 0;
-  change->delay_random = 0;
-  change->delay_frames = 1;
+  *change = xx_change;
 
-  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;
+  resetEventFlags(change);
 
   change->direct_action = 0;
   change->other_action = 0;
@@ -331,94 +1465,34 @@ void setElementChangeInfoToDefaults(struct ElementChangeInfo *change)
 static void setLevelInfoToDefaults(struct LevelInfo *level)
 {
   static boolean clipboard_elements_initialized = FALSE;
-  int i, j, x, y;
+  int i, x, y;
+
+  InitElementPropertiesStatic();
+
+  li = *level;         /* copy level data into temporary buffer */
+
+  setConfigToDefaultsFromConfigList(chunk_config_INFO);
+  setConfigToDefaultsFromConfigList(chunk_config_ELEM);
+
+  *level = li;         /* copy temporary buffer back to level data */
 
-  setLevelInfoToDefaultsFromConfigList(level);
   setLevelInfoToDefaults_EM();
 
   level->native_em_level = &native_em_level;
 
-  level->game_engine_type = GAME_ENGINE_TYPE_RND;
-
   level->file_version = FILE_VERSION_ACTUAL;
   level->game_version = GAME_VERSION_ACTUAL;
 
-  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();
 
-  level->fieldx = STD_LEV_FIELDX;
-  level->fieldy = STD_LEV_FIELDY;
+  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;
 
-  level->time = 100;
-  level->gems_needed = 0;
-
-  level->amoeba_speed = 10;
-
-  level->time_magic_wall = 10;
-  level->time_wheel = 10;
-#if 0
-  level->time_light = 10;
-  level->time_timegate = 10;
-#endif
-
-  level->amoeba_content = EL_DIAMOND;
-
-  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;
-
-  level->double_speed = FALSE;
-  level->initial_gravity = FALSE;
-  level->em_slippery_gems = FALSE;
-  level->instant_relocation = FALSE;
-  level->can_pass_to_walkable = FALSE;
-  level->grow_into_diggable = TRUE;
-
-  level->block_last_field = FALSE;     /* EM does not block by default */
-  level->sp_block_last_field = TRUE;   /* SP blocks the last field */
-
-  level->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_step_counter = FALSE;
-
-  /* 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;
-#endif
-  level->ball_random = FALSE;
-  level->ball_state_initial = FALSE;
-#if 0
-  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;
-#endif
-  for (i = 0; i < 16; i++)
-    level->android_array[i] = FALSE;
-
-  level->use_custom_template = FALSE;
-
   for (i = 0; i < MAX_LEVEL_NAME_LEN; i++)
     level->name[i] = '\0';
   for (i = 0; i < MAX_LEVEL_AUTHOR_LEN; i++)
@@ -427,126 +1501,86 @@ static void setLevelInfoToDefaults(struct LevelInfo *level)
   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;
-  }
-
-  for (i = 0; i < LEVEL_SCORE_ELEMENTS; i++)
-    level->score[i] = 10;
-
-  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);
-
   level->field[0][0] = EL_PLAYER_1;
   level->field[STD_LEV_FIELDX - 1][STD_LEV_FIELDY - 1] = EL_EXIT_CLOSED;
 
   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
   {
     int element = i;
+    struct ElementInfo *ei = &element_info[element];
 
     /* 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(&element_info[element], 1);
-    setElementChangeInfoToDefaults(element_info[element].change);
-
-    if (IS_CUSTOM_ELEMENT(element) ||
-       IS_GROUP_ELEMENT(element) ||
-       IS_INTERNAL_ELEMENT(element))
+    if (IS_ENVELOPE(element))
     {
-      for (j = 0; j < MAX_ELEMENT_NAME_LEN + 1; j++)
-       element_info[element].description[j] = '\0';
-
-      if (element_info[element].custom_description != NULL)
-       strncpy(element_info[element].description,
-               element_info[element].custom_description,MAX_ELEMENT_NAME_LEN);
-      else
-       strcpy(element_info[element].description,
-              element_info[element].editor_description);
+      int envelope_nr = element - EL_ENVELOPE_1;
 
-      element_info[element].use_gfx_element = FALSE;
-      element_info[element].gfx_element = EL_EMPTY_SPACE;
+      setConfigToDefaultsFromConfigList(chunk_config_NOTE);
 
-      element_info[element].modified_settings = FALSE;
+      level->envelope[envelope_nr] = xx_envelope;
     }
 
     if (IS_CUSTOM_ELEMENT(element) ||
+       IS_GROUP_ELEMENT(element) ||
        IS_INTERNAL_ELEMENT(element))
     {
-      element_info[element].access_direction = MV_ALL_DIRECTIONS;
-
-      element_info[element].collect_score_initial = 10;        /* special default */
-      element_info[element].collect_count_initial = 1; /* special default */
-
-      element_info[element].push_delay_fixed = -1;     /* initialize later */
-      element_info[element].push_delay_random = -1;    /* initialize later */
-      element_info[element].drop_delay_fixed = 0;
-      element_info[element].drop_delay_random = 0;
-      element_info[element].move_delay_fixed = 0;
-      element_info[element].move_delay_random = 0;
+      xx_ei = *ei;     /* copy element data into temporary buffer */
 
-      element_info[element].move_pattern = MV_ALL_DIRECTIONS;
-      element_info[element].move_direction_initial = MV_START_AUTOMATIC;
-      element_info[element].move_stepsize = TILEX / 8;
+      setConfigToDefaultsFromConfigList(chunk_config_CUSX_base);
 
-      element_info[element].move_enter_element = EL_EMPTY_SPACE;
-      element_info[element].move_leave_element = EL_EMPTY_SPACE;
-      element_info[element].move_leave_type = LEAVE_TYPE_UNLIMITED;
-
-      element_info[element].slippery_type = SLIPPERY_ANY_RANDOM;
+      *ei = xx_ei;
+    }
 
-      element_info[element].explosion_type = EXPLODES_3X3;
-      element_info[element].explosion_delay = 16;
-      element_info[element].ignition_delay = 8;
+    setElementChangePages(ei, 1);
+    setElementChangeInfoToDefaults(ei->change);
 
-      for (x = 0; x < 3; x++)
-       for (y = 0; y < 3; y++)
-         element_info[element].content.e[x][y] = EL_EMPTY_SPACE;
+    if (IS_CUSTOM_ELEMENT(element) ||
+       IS_GROUP_ELEMENT(element) ||
+       IS_INTERNAL_ELEMENT(element))
+    {
+      setElementDescriptionToDefault(ei);
 
-      element_info[element].access_type = 0;
-      element_info[element].access_layer = 0;
-      element_info[element].access_protected = 0;
-      element_info[element].walk_to_action = 0;
-      element_info[element].smash_targets = 0;
-      element_info[element].deadliness = 0;
+      ei->modified_settings = FALSE;
+    }
 
-      element_info[element].can_explode_by_fire = FALSE;
-      element_info[element].can_explode_smashed = FALSE;
-      element_info[element].can_explode_impact = FALSE;
+    if (IS_CUSTOM_ELEMENT(element) ||
+       IS_INTERNAL_ELEMENT(element))
+    {
+      /* internal values used in level editor */
 
-      element_info[element].current_change_page = 0;
+      ei->access_type = 0;
+      ei->access_layer = 0;
+      ei->access_protected = 0;
+      ei->walk_to_action = 0;
+      ei->smash_targets = 0;
+      ei->deadliness = 0;
 
-      /* start with no properties at all */
-      for (j = 0; j < NUM_EP_BITFIELDS; j++)
-       Properties[element][j] = EP_BITMASK_DEFAULT;
+      ei->can_explode_by_fire = FALSE;
+      ei->can_explode_smashed = FALSE;
+      ei->can_explode_impact = FALSE;
 
-      /* now set default properties */
-      SET_PROPERTY(element, EP_CAN_MOVE_INTO_ACID, TRUE);
+      ei->current_change_page = 0;
     }
 
     if (IS_GROUP_ELEMENT(element) ||
        IS_INTERNAL_ELEMENT(element))
     {
+      struct ElementGroupInfo *group;
+
       /* initialize memory for list of elements in group */
-      if (element_info[element].group == NULL)
-       element_info[element].group =
-         checked_malloc(sizeof(struct ElementGroupInfo));
+      if (ei->group == NULL)
+       ei->group = checked_malloc(sizeof(struct ElementGroupInfo));
+
+      group = ei->group;
 
-      for (j = 0; j < MAX_ELEMENTS_IN_GROUP; j++)
-       element_info[element].group->element[j] = EL_EMPTY_SPACE;
+      xx_group = *group;       /* copy group data into temporary buffer */
 
-      /* default: only one element in group */
-      element_info[element].group->num_elements = 1;
+      setConfigToDefaultsFromConfigList(chunk_config_GRPX);
 
-      element_info[element].group->choice_mode = ANIM_RANDOM;
+      *group = xx_group;
     }
   }
 
@@ -562,7 +1596,7 @@ static void setLevelInfoToDefaults(struct LevelInfo *level)
     return;
 
   /* try to determine better author name than 'anonymous' */
-  if (strcmp(leveldir_current->author, ANONYMOUS_NAME) != 0)
+  if (!strEqual(leveldir_current->author, ANONYMOUS_NAME))
   {
     strncpy(level->author, leveldir_current->author, MAX_LEVEL_AUTHOR_LEN);
     level->author[MAX_LEVEL_AUTHOR_LEN] = '\0';
@@ -604,7 +1638,7 @@ static void setFileInfoToDefaults(struct LevelFileInfo *level_file_info)
 static void ActivateLevelTemplate()
 {
   /* Currently there is no special action needed to activate the template
-     data, because 'element_info' and 'Properties' overwrite the original
+     data, because 'element_info' property settings overwrite the original
      level data, while all other variables do not change. */
 }
 
@@ -764,7 +1798,7 @@ static int getFiletypeFromID(char *filetype_id)
   {
     char *id_lower = getStringToLower(filetype_id_list[i].id);
     
-    if (strcmp(filetype_id_lower, id_lower) == 0)
+    if (strEqual(filetype_id_lower, id_lower))
       filetype = filetype_id_list[i].filetype;
 
     free(id_lower);
@@ -955,8 +1989,19 @@ 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);
+
+  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);
@@ -982,8 +2027,18 @@ static int LoadLevel_HEAD(FILE *file, int chunk_size, struct LevelInfo *level)
   level->time_magic_wall       = getFile8Bit(file);
   level->time_wheel            = getFile8Bit(file);
   level->amoeba_content                = getMappedElement(getFile8Bit(file));
-  level->double_speed          = (getFile8Bit(file) == 1 ? TRUE : FALSE);
-  level->initial_gravity       = (getFile8Bit(file) == 1 ? TRUE : FALSE);
+
+  initial_player_stepsize      = (getFile8Bit(file) == 1 ? STEPSIZE_FAST :
+                                  STEPSIZE_NORMAL);
+
+  for (i = 0; i < MAX_PLAYERS; i++)
+    level->initial_player_stepsize[0] = initial_player_stepsize;
+
+  initial_player_gravity       = (getFile8Bit(file) == 1 ? TRUE : FALSE);
+
+  for (i = 0; i < MAX_PLAYERS; i++)
+    level->initial_player_gravity[0] = initial_player_gravity;
+
   level->encoding_16bit_field  = (getFile8Bit(file) == 1 ? TRUE : FALSE);
   level->em_slippery_gems      = (getFile8Bit(file) == 1 ? TRUE : FALSE);
 
@@ -1003,7 +2058,18 @@ static int LoadLevel_HEAD(FILE *file, int chunk_size, struct LevelInfo *level)
 
   level->game_engine_type      = getFile8Bit(file);
 
-  ReadUnusedBytesFromFile(file, LEVEL_HEADER_UNUSED);
+  ReadUnusedBytesFromFile(file, LEVEL_CHUNK_HEAD_UNUSED);
+
+  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;
 }
@@ -1014,7 +2080,7 @@ static int LoadLevel_AUTH(FILE *file, int chunk_size, struct LevelInfo *level)
 
   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;
 }
@@ -1146,8 +2212,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);
 
@@ -1159,7 +2225,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;
 }
@@ -1178,13 +2244,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 (IS_CUSTOM_ELEMENT(element))
-      Properties[element][EP_BITFIELD_BASE] = properties;
+      element_info[element].properties[EP_BITFIELD_BASE_NR] = properties;
     else
       Error(ERR_WARN, "invalid custom element number %d", element);
+
+    /* 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;
@@ -1204,8 +2275,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;
@@ -1230,8 +2301,9 @@ 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);
-    unsigned long event_bits;
+    int element = getMappedElement(getFile16BitBE(file));
+    struct ElementInfo *ei = &element_info[element];
+    unsigned int event_bits;
 
     if (!IS_CUSTOM_ELEMENT(element))
     {
@@ -1241,70 +2313,66 @@ static int LoadLevel_CUS3(FILE *file, int chunk_size, struct LevelInfo *level)
     }
 
     for (j = 0; j < MAX_ELEMENT_NAME_LEN; j++)
-      element_info[element].description[j] = getFile8Bit(file);
-    element_info[element].description[MAX_ELEMENT_NAME_LEN] = 0;
+      ei->description[j] = getFile8Bit(file);
+    ei->description[MAX_ELEMENT_NAME_LEN] = 0;
 
-    Properties[element][EP_BITFIELD_BASE] = getFile32BitBE(file);
+    ei->properties[EP_BITFIELD_BASE_NR] = getFile32BitBE(file);
 
     /* some free bytes for future properties and padding */
     ReadUnusedBytesFromFile(file, 7);
 
-    element_info[element].use_gfx_element = getFile8Bit(file);
-    element_info[element].gfx_element =
-      getMappedElement(getFile16BitBE(file));
+    ei->use_gfx_element = getFile8Bit(file);
+    ei->gfx_element = getMappedElement(getFile16BitBE(file));
 
-    element_info[element].collect_score_initial = getFile8Bit(file);
-    element_info[element].collect_count_initial = getFile8Bit(file);
+    ei->collect_score_initial = getFile8Bit(file);
+    ei->collect_count_initial = getFile8Bit(file);
 
-    element_info[element].push_delay_fixed = getFile16BitBE(file);
-    element_info[element].push_delay_random = getFile16BitBE(file);
-    element_info[element].move_delay_fixed = getFile16BitBE(file);
-    element_info[element].move_delay_random = getFile16BitBE(file);
+    ei->push_delay_fixed = getFile16BitBE(file);
+    ei->push_delay_random = getFile16BitBE(file);
+    ei->move_delay_fixed = getFile16BitBE(file);
+    ei->move_delay_random = getFile16BitBE(file);
 
-    element_info[element].move_pattern = getFile16BitBE(file);
-    element_info[element].move_direction_initial = getFile8Bit(file);
-    element_info[element].move_stepsize = getFile8Bit(file);
+    ei->move_pattern = getFile16BitBE(file);
+    ei->move_direction_initial = getFile8Bit(file);
+    ei->move_stepsize = getFile8Bit(file);
 
     for (y = 0; y < 3; y++)
       for (x = 0; x < 3; x++)
-       element_info[element].content.e[x][y] =
-         getMappedElement(getFile16BitBE(file));
+       ei->content.e[x][y] = getMappedElement(getFile16BitBE(file));
 
     event_bits = getFile32BitBE(file);
     for (j = 0; j < NUM_CHANGE_EVENTS; j++)
       if (event_bits & (1 << j))
-       element_info[element].change->has_event[j] = TRUE;
+       ei->change->has_event[j] = TRUE;
 
-    element_info[element].change->target_element =
-      getMappedElement(getFile16BitBE(file));
+    ei->change->target_element = getMappedElement(getFile16BitBE(file));
 
-    element_info[element].change->delay_fixed = getFile16BitBE(file);
-    element_info[element].change->delay_random = getFile16BitBE(file);
-    element_info[element].change->delay_frames = getFile16BitBE(file);
+    ei->change->delay_fixed = getFile16BitBE(file);
+    ei->change->delay_random = getFile16BitBE(file);
+    ei->change->delay_frames = getFile16BitBE(file);
 
-    element_info[element].change->trigger_element =
-      getMappedElement(getFile16BitBE(file));
+    ei->change->trigger_element = getMappedElement(getFile16BitBE(file));
 
-    element_info[element].change->explode = getFile8Bit(file);
-    element_info[element].change->use_target_content = getFile8Bit(file);
-    element_info[element].change->only_if_complete = getFile8Bit(file);
-    element_info[element].change->use_random_replace = getFile8Bit(file);
+    ei->change->explode = getFile8Bit(file);
+    ei->change->use_target_content = getFile8Bit(file);
+    ei->change->only_if_complete = getFile8Bit(file);
+    ei->change->use_random_replace = getFile8Bit(file);
 
-    element_info[element].change->random_percentage = getFile8Bit(file);
-    element_info[element].change->replace_when = getFile8Bit(file);
+    ei->change->random_percentage = getFile8Bit(file);
+    ei->change->replace_when = getFile8Bit(file);
 
     for (y = 0; y < 3; y++)
       for (x = 0; x < 3; x++)
-       element_info[element].change->target_content.e[x][y] =
+       ei->change->target_content.e[x][y] =
          getMappedElement(getFile16BitBE(file));
 
-    element_info[element].slippery_type = getFile8Bit(file);
+    ei->slippery_type = getFile8Bit(file);
 
     /* some free bytes for future properties and padding */
     ReadUnusedBytesFromFile(file, LEVEL_CPART_CUS3_UNUSED);
 
     /* mark that this custom element has been modified */
-    element_info[element].modified_settings = TRUE;
+    ei->modified_settings = TRUE;
   }
 
   return chunk_size;
@@ -1317,7 +2385,9 @@ static int LoadLevel_CUS4(FILE *file, int chunk_size, struct LevelInfo *level)
   int element;
   int i, j, x, y;
 
-  element = getFile16BitBE(file);
+  /* ---------- custom element base property values (96 bytes) ------------- */
+
+  element = getMappedElement(getFile16BitBE(file));
 
   if (!IS_CUSTOM_ELEMENT(element))
   {
@@ -1333,22 +2403,22 @@ static int LoadLevel_CUS4(FILE *file, int chunk_size, struct LevelInfo *level)
     ei->description[i] = getFile8Bit(file);
   ei->description[MAX_ELEMENT_NAME_LEN] = 0;
 
-  Properties[element][EP_BITFIELD_BASE] = getFile32BitBE(file);
+  ei->properties[EP_BITFIELD_BASE_NR] = getFile32BitBE(file);
+
   ReadUnusedBytesFromFile(file, 4);    /* reserved for more base properties */
 
   ei->num_change_pages = getFile8Bit(file);
 
-  /* some free bytes for future base property values and padding */
-  ReadUnusedBytesFromFile(file, 5);
-
   chunk_size_expected = LEVEL_CHUNK_CUS4_SIZE(ei->num_change_pages);
   if (chunk_size_expected != chunk_size)
   {
-    ReadUnusedBytesFromFile(file, chunk_size - 48);
+    ReadUnusedBytesFromFile(file, chunk_size - 43);
     return chunk_size_expected;
   }
 
-  /* read custom property values */
+  ei->ce_value_fixed_initial = getFile16BitBE(file);
+  ei->ce_value_random_initial = getFile16BitBE(file);
+  ei->use_last_ce_value = getFile8Bit(file);
 
   ei->use_gfx_element = getFile8Bit(file);
   ei->gfx_element = getMappedElement(getFile16BitBE(file));
@@ -1390,20 +2460,21 @@ static int LoadLevel_CUS4(FILE *file, int chunk_size, struct LevelInfo *level)
   /* some free bytes for future custom property values and padding */
   ReadUnusedBytesFromFile(file, 1);
 
-  /* read change property values */
+  /* ---------- change page property values (48 bytes) --------------------- */
 
   setElementChangePages(ei, ei->num_change_pages);
 
   for (i = 0; i < ei->num_change_pages; i++)
   {
     struct ElementChangeInfo *change = &ei->change_page[i];
-    unsigned long event_bits;
+    unsigned int event_bits;
 
     /* always start with reliable default values */
     setElementChangeInfoToDefaults(change);
 
+    /* bits 0 - 31 of "has_event[]" ... */
     event_bits = getFile32BitBE(file);
-    for (j = 0; j < NUM_CHANGE_EVENTS; j++)
+    for (j = 0; j < MIN(NUM_CHANGE_EVENTS, 32); j++)
       if (event_bits & (1 << j))
        change->has_event[j] = TRUE;
 
@@ -1442,147 +2513,361 @@ static int LoadLevel_CUS4(FILE *file, int chunk_size, struct LevelInfo *level)
     change->action_mode = getFile8Bit(file);
     change->action_arg = getFile16BitBE(file);
 
-    /* some free bytes for future change property values and padding */
-    ReadUnusedBytesFromFile(file, 1);
+    /* ... bits 32 - 39 of "has_event[]" (not nice, but downward compatible) */
+    event_bits = getFile8Bit(file);
+    for (j = 32; j < NUM_CHANGE_EVENTS; j++)
+      if (event_bits & (1 << (j - 32)))
+       change->has_event[j] = TRUE;
+  }
+
+  /* mark this custom element as modified */
+  ei->modified_settings = TRUE;
+
+  return chunk_size;
+}
+
+static int LoadLevel_GRP1(FILE *file, int chunk_size, struct LevelInfo *level)
+{
+  struct ElementInfo *ei;
+  struct ElementGroupInfo *group;
+  int element;
+  int i;
+
+  element = getMappedElement(getFile16BitBE(file));
+
+  if (!IS_GROUP_ELEMENT(element))
+  {
+    Error(ERR_WARN, "invalid group element number %d", element);
+
+    ReadUnusedBytesFromFile(file, chunk_size - 2);
+    return chunk_size;
+  }
+
+  ei = &element_info[element];
+
+  for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++)
+    ei->description[i] = getFile8Bit(file);
+  ei->description[MAX_ELEMENT_NAME_LEN] = 0;
+
+  group = element_info[element].group;
+
+  group->num_elements = getFile8Bit(file);
+
+  ei->use_gfx_element = getFile8Bit(file);
+  ei->gfx_element = getMappedElement(getFile16BitBE(file));
+
+  group->choice_mode = getFile8Bit(file);
+
+  /* some free bytes for future values and padding */
+  ReadUnusedBytesFromFile(file, 3);
+
+  for (i = 0; i < MAX_ELEMENTS_IN_GROUP; i++)
+    group->element[i] = getMappedElement(getFile16BitBE(file));
+
+  /* mark this group element as modified */
+  element_info[element].modified_settings = TRUE;
+
+  return chunk_size;
+}
+
+static int LoadLevel_MicroChunk(FILE *file, struct LevelFileConfigInfo *conf,
+                               int element, int real_element)
+{
+  int micro_chunk_size = 0;
+  int conf_type = getFile8Bit(file);
+  int byte_mask = conf_type & CONF_MASK_BYTES;
+  boolean element_found = FALSE;
+  int i;
+
+  micro_chunk_size += 1;
+
+  if (byte_mask == CONF_MASK_MULTI_BYTES)
+  {
+    int num_bytes = getFile16BitBE(file);
+    byte *buffer = checked_malloc(num_bytes);
+
+    ReadBytesFromFile(file, buffer, num_bytes);
+
+    for (i = 0; conf[i].data_type != -1; i++)
+    {
+      if (conf[i].element == element &&
+         conf[i].conf_type == conf_type)
+      {
+       int data_type = conf[i].data_type;
+       int num_entities = num_bytes / CONF_ENTITY_NUM_BYTES(data_type);
+       int max_num_entities = 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 *)(conf[i].num_entities) = num_entities;
+
+       element_found = TRUE;
+
+       if (data_type == TYPE_STRING)
+       {
+         char *string = (char *)(conf[i].value);
+         int j;
+
+         for (j = 0; j < max_num_entities; j++)
+           string[j] = (j < num_entities ? buffer[j] : '\0');
+       }
+       else if (data_type == TYPE_ELEMENT_LIST)
+       {
+         int *element_array = (int *)(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 *)(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;
+
+       break;
+      }
+    }
+
+    checked_free(buffer);
+
+    micro_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);
+
+    for (i = 0; conf[i].data_type != -1; i++)
+    {
+      if (conf[i].element == element &&
+         conf[i].conf_type == conf_type)
+      {
+       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
+         *(int *)    (conf[i].value) = value;
+
+       element_found = TRUE;
+
+       break;
+      }
+    }
+
+    micro_chunk_size += CONF_VALUE_NUM_BYTES(byte_mask);
+  }
+
+  if (!element_found)
+  {
+    char *error_conf_chunk_bytes =
+      (byte_mask == CONF_MASK_1_BYTE ? "CONF_VALUE_8_BIT" :
+       byte_mask == CONF_MASK_2_BYTE ? "CONF_VALUE_16_BIT" :
+       byte_mask == CONF_MASK_4_BYTE ? "CONF_VALUE_32_BIT" :"CONF_VALUE_BYTES");
+    int error_conf_chunk_token = conf_type & CONF_MASK_TOKEN;
+    int error_element = real_element;
+
+    Error(ERR_WARN, "cannot load micro chunk '%s(%d)' value for element %d ['%s']",
+         error_conf_chunk_bytes, error_conf_chunk_token,
+         error_element, EL_NAME(error_element));
+  }
+
+  return micro_chunk_size;
+}
+
+static int LoadLevel_INFO(FILE *file, int chunk_size, struct LevelInfo *level)
+{
+  int real_chunk_size = 0;
+
+  li = *level;         /* copy level data into temporary buffer */
+
+  while (!feof(file))
+  {
+    real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_INFO, -1, -1);
+
+    if (real_chunk_size >= chunk_size)
+      break;
   }
 
-  /* mark this custom element as modified */
-  ei->modified_settings = TRUE;
+  *level = li;         /* copy temporary buffer back to level data */
 
-  return chunk_size;
+  return real_chunk_size;
 }
 
-static int LoadLevel_GRP1(FILE *file, int chunk_size, struct LevelInfo *level)
+static int LoadLevel_CONF(FILE *file, int chunk_size, struct LevelInfo *level)
 {
-  struct ElementInfo *ei;
-  struct ElementGroupInfo *group;
-  int element;
-  int i;
+  int real_chunk_size = 0;
 
-  element = getFile16BitBE(file);
+  li = *level;         /* copy level data into temporary buffer */
 
-  if (!IS_GROUP_ELEMENT(element))
+  while (!feof(file))
   {
-    Error(ERR_WARN, "invalid group element number %d", element);
+    int element = getMappedElement(getFile16BitBE(file));
 
-    ReadUnusedBytesFromFile(file, chunk_size - 2);
-    return chunk_size;
+    real_chunk_size += 2;
+    real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_CONF,
+                                           element, element);
+    if (real_chunk_size >= chunk_size)
+      break;
   }
 
-  ei = &element_info[element];
+  *level = li;         /* copy temporary buffer back to level data */
 
-  for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++)
-    ei->description[i] = getFile8Bit(file);
-  ei->description[MAX_ELEMENT_NAME_LEN] = 0;
+  return real_chunk_size;
+}
 
-  group = element_info[element].group;
+static int LoadLevel_ELEM(FILE *file, int chunk_size, struct LevelInfo *level)
+{
+  int real_chunk_size = 0;
 
-  group->num_elements = getFile8Bit(file);
+  li = *level;         /* copy level data into temporary buffer */
 
-  ei->use_gfx_element = getFile8Bit(file);
-  ei->gfx_element = getMappedElement(getFile16BitBE(file));
+  while (!feof(file))
+  {
+    int element = getMappedElement(getFile16BitBE(file));
 
-  group->choice_mode = getFile8Bit(file);
+    real_chunk_size += 2;
+    real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_ELEM,
+                                           element, element);
+    if (real_chunk_size >= chunk_size)
+      break;
+  }
 
-  /* some free bytes for future values and padding */
-  ReadUnusedBytesFromFile(file, 3);
+  *level = li;         /* copy temporary buffer back to level data */
 
-  for (i = 0; i < MAX_ELEMENTS_IN_GROUP; i++)
-    group->element[i] = getMappedElement(getFile16BitBE(file));
+  return real_chunk_size;
+}
 
-  /* mark this group element as modified */
-  element_info[element].modified_settings = TRUE;
+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;
 
-  return chunk_size;
+  while (!feof(file))
+  {
+    real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_NOTE,
+                                           -1, element);
+
+    if (real_chunk_size >= chunk_size)
+      break;
+  }
+
+  level->envelope[envelope_nr] = xx_envelope;
+
+  return real_chunk_size;
 }
 
-static int LoadLevel_CONF(FILE *file, int chunk_size, struct LevelInfo *level)
+static int LoadLevel_CUSX(FILE *file, int chunk_size, struct LevelInfo *level)
 {
-  int real_chunk_size = 0;
+  int element = getMappedElement(getFile16BitBE(file));
+  int real_chunk_size = 2;
+  struct ElementInfo *ei = &element_info[element];
   int i;
 
+  xx_ei = *ei;         /* copy element data into temporary buffer */
+
+  xx_ei.num_change_pages = -1;
+
   while (!feof(file))
   {
-    int element = getFile16BitBE(file);
-    int type = getFile8Bit(file);
-    int bytes = type & CONF_MASK_BYTES;
-    boolean element_found = FALSE;
+    real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_CUSX_base,
+                                           -1, element);
+    if (xx_ei.num_change_pages != -1)
+      break;
+
+    if (real_chunk_size >= chunk_size)
+      break;
+  }
+
+  *ei = xx_ei;
+
+  if (ei->num_change_pages == -1)
+  {
+    Error(ERR_WARN, "LoadLevel_CUSX(): missing 'num_change_pages' for '%s'",
+         EL_NAME(element));
 
-    real_chunk_size += 3;
+    ei->num_change_pages = 1;
 
-    li = *level;       /* copy level information into temporary buffer */
+    setElementChangePages(ei, 1);
+    setElementChangeInfoToDefaults(ei->change);
 
-    if (bytes == CONF_MASK_MULTI_BYTES)
-    {
-      int num_bytes = getFile16BitBE(file);
-      byte *buffer = checked_malloc(num_bytes);
+    return real_chunk_size;
+  }
 
-      ReadBytesFromFile(file, buffer, num_bytes);
+  /* initialize number of change pages stored for this custom element */
+  setElementChangePages(ei, ei->num_change_pages);
+  for (i = 0; i < ei->num_change_pages; i++)
+    setElementChangeInfoToDefaults(&ei->change_page[i]);
 
-      for (i = 0; element_conf[i].element != -1; i++)
-      {
-       if (element_conf[i].element == element &&
-           element_conf[i].type    == type)
-       {
-         element_found = TRUE;
-
-         if (type == CONF_VALUE_CONTENT_8)
-         {
-           struct Content *content= (struct Content *)(element_conf[i].value);
-           int num_contents = num_bytes / CONF_CONTENT_NUM_BYTES;
-           int c, x, y;
-
-           for (c = 0; c < num_contents; c++)
-             for (y = 0; y < 3; y++)
-               for (x = 0; x < 3; x++)
-                 content[c].e[x][y] =
-                   getMappedElement(CONF_CONTENT_ELEMENT(buffer, c, x, y));
-         }
-         else
-           element_found = FALSE;
-
-         break;
-       }
-      }
+  /* start with reading properties for the first change page */
+  xx_current_change_page = 0;
+
+  while (!feof(file))
+  {
+    struct ElementChangeInfo *change = &ei->change_page[xx_current_change_page];
 
-      checked_free(buffer);
+    xx_change = *change;       /* copy change data into temporary buffer */
 
-      real_chunk_size += 2 + num_bytes;
-    }
-    else
-    {
-      int value = (bytes == CONF_MASK_1_BYTE ? getFile8Bit   (file) :
-                  bytes == CONF_MASK_2_BYTE ? getFile16BitBE(file) :
-                  bytes == CONF_MASK_4_BYTE ? getFile32BitBE(file) : 0);
+    resetEventBits();          /* reset bits; change page might have changed */
 
-      for (i = 0; element_conf[i].element != -1; i++)
-      {
-       if (element_conf[i].element == element &&
-           element_conf[i].type    == type)
-       {
-         if (CONF_VALUE_BOOLEAN(type))
-           *(boolean *)(element_conf[i].value) = value;
-         else
-           *(int *)    (element_conf[i].value) = value;
+    real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_CUSX_change,
+                                           -1, element);
 
-         element_found = TRUE;
+    *change = xx_change;
 
-         break;
-       }
-      }
+    setEventFlagsFromEventBits(change);
 
-      real_chunk_size += CONF_VALUE_NUM_BYTES(bytes);
-    }
+    if (real_chunk_size >= chunk_size)
+      break;
+  }
+
+  return real_chunk_size;
+}
+
+static int LoadLevel_GRPX(FILE *file, int chunk_size, struct LevelInfo *level)
+{
+  int element = getMappedElement(getFile16BitBE(file));
+  int real_chunk_size = 2;
+  struct ElementInfo *ei = &element_info[element];
+  struct ElementGroupInfo *group = ei->group;
 
-    *level = li;       /* copy temporary buffer back to level information */
+  xx_ei = *ei;         /* copy element data into temporary buffer */
+  xx_group = *group;   /* copy group data into temporary buffer */
 
-    if (!element_found)
-      Error(ERR_WARN, "cannot load CONF value for element %d", element);
+  while (!feof(file))
+  {
+    real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_GRPX,
+                                           -1, element);
 
-    if (type == CONF_LAST_ENTRY || real_chunk_size >= chunk_size)
+    if (real_chunk_size >= chunk_size)
       break;
   }
 
+  *ei = xx_ei;
+  *group = xx_group;
+
   return real_chunk_size;
 }
 
@@ -1606,12 +2891,12 @@ static void LoadLevelFromFileInfo_RND(struct LevelInfo *level,
   }
 
   getFileChunkBE(file, chunk_name, NULL);
-  if (strcmp(chunk_name, "RND1") == 0)
+  if (strEqual(chunk_name, "RND1"))
   {
     getFile32BitBE(file);              /* not used */
 
     getFileChunkBE(file, chunk_name, NULL);
-    if (strcmp(chunk_name, "CAVE") != 0)
+    if (!strEqual(chunk_name, "CAVE"))
     {
       level->no_valid_file = TRUE;
 
@@ -1652,7 +2937,7 @@ static void LoadLevelFromFileInfo_RND(struct LevelInfo *level,
   if (level->file_version < FILE_VERSION_1_2)
   {
     /* level files from versions before 1.2.0 without chunk structure */
-    LoadLevel_HEAD(file, LEVEL_HEADER_SIZE,             level);
+    LoadLevel_HEAD(file, LEVEL_CHUNK_HEAD_SIZE,         level);
     LoadLevel_BODY(file, level->fieldx * level->fieldy, level);
   }
   else
@@ -1665,9 +2950,12 @@ static void LoadLevelFromFileInfo_RND(struct LevelInfo *level,
     }
     chunk_info[] =
     {
-      { "VERS", FILE_VERS_CHUNK_SIZE,  LoadLevel_VERS },
-      { "HEAD", LEVEL_HEADER_SIZE,     LoadLevel_HEAD },
-      { "AUTH", MAX_LEVEL_AUTHOR_LEN,  LoadLevel_AUTH },
+      { "VERS", LEVEL_CHUNK_VERS_SIZE, LoadLevel_VERS },
+      { "DATE", LEVEL_CHUNK_DATE_SIZE, LoadLevel_DATE },
+      { "HEAD", LEVEL_CHUNK_HEAD_SIZE, LoadLevel_HEAD },
+      { "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 },
@@ -1678,6 +2966,10 @@ static void LoadLevelFromFileInfo_RND(struct LevelInfo *level,
       { "CUS4", -1,                    LoadLevel_CUS4 },
       { "GRP1", -1,                    LoadLevel_GRP1 },
       { "CONF", -1,                    LoadLevel_CONF },
+      { "ELEM", -1,                    LoadLevel_ELEM },
+      { "NOTE", -1,                    LoadLevel_NOTE },
+      { "CUSX", -1,                    LoadLevel_CUSX },
+      { "GRPX", -1,                    LoadLevel_GRPX },
 
       {  NULL,  0,                     NULL }
     };
@@ -1687,7 +2979,7 @@ static void LoadLevelFromFileInfo_RND(struct LevelInfo *level,
       int i = 0;
 
       while (chunk_info[i].name != NULL &&
-            strcmp(chunk_name, chunk_info[i].name) != 0)
+            !strEqual(chunk_name, chunk_info[i].name))
        i++;
 
       if (chunk_info[i].name == NULL)
@@ -2165,8 +3457,7 @@ void CopyNativeLevel_RND_to_EM(struct LevelInfo *level)
   };
   struct LevelInfo_EM *level_em = level->native_em_level;
   struct LEVEL *lev = level_em->lev;
-  struct PLAYER *ply1 = level_em->ply1;
-  struct PLAYER *ply2 = level_em->ply2;
+  struct PLAYER **ply = level_em->ply;
   int i, j, x, y;
 
   lev->width  = MIN(level->fieldx, EM_MAX_CAVE_WIDTH);
@@ -2201,6 +3492,7 @@ void CopyNativeLevel_RND_to_EM(struct LevelInfo *level)
   lev->ball_random             = level->ball_random;
   lev->ball_state_initial      = level->ball_state_initial;
   lev->ball_time               = level->ball_time;
+  lev->num_ball_arrays         = level->num_ball_contents;
 
   lev->lenses_score            = level->lenses_score;
   lev->magnify_score           = level->magnify_score;
@@ -2208,7 +3500,11 @@ void CopyNativeLevel_RND_to_EM(struct LevelInfo *level)
 
   lev->lenses_time             = level->lenses_time;
   lev->magnify_time            = level->magnify_time;
-  lev->wind_direction_initial  = level->wind_direction_initial;
+
+  lev->wind_direction_initial =
+    map_direction_RND_to_EM(level->wind_direction_initial);
+  lev->wind_cnt_initial = (level->wind_direction_initial != MV_NONE ?
+                          lev->wind_time : 0);
 
   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
     for (j = 0; j < 8; j++)
@@ -2216,47 +3512,62 @@ 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]]);
 
-  for (i = 0; i < 16; i++)
-    lev->android_array[i] = FALSE;     /* !!! YET TO COME !!! */
+  map_android_clone_elements_RND_to_EM(level);
 
   /* 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 (BorderElement == EL_STEELWALL)
+  {
+    for (y = 0; y < lev->height + 2; y++)
+      for (x = 0; x < lev->width + 2; x++)
+       level_em->cave[x + 1][y + 1] = map_element_RND_to_EM(EL_STEELWALL);
+  }
+
   /* 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]);
+    int offset = (BorderElement == EL_STEELWALL ? 1 : 0);
+    int xx = x + 1 + offset;
+    int yy = y + 1 + offset;
 
     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;
+    level_em->cave[xx][yy] = new_element;
   }
 
-  ply1->x_initial = 0;
-  ply1->y_initial = 0;
-
-  ply2->x_initial = 0;
-  ply2->y_initial = 0;
+  for (i = 0; i < MAX_PLAYERS; i++)
+  {
+    ply[i]->x_initial = 0;
+    ply[i]->y_initial = 0;
+  }
 
   /* initialize player positions and delete players from the playfield */
   for (y = 0; y < lev->height; y++) for (x = 0; x < lev->width; x++)
   {
-    if (level->field[x][y] == EL_PLAYER_1)
-    {
-      ply1->x_initial = x + 1;
-      ply1->y_initial = y + 1;
-      level_em->cave[x + 1][y + 1] = map_element_RND_to_EM(EL_EMPTY);
-    }
-    else if (level->field[x][y] == EL_PLAYER_2)
+    if (ELEM_IS_PLAYER(level->field[x][y]))
     {
-      ply2->x_initial = x + 1;
-      ply2->y_initial = y + 1;
-      level_em->cave[x + 1][y + 1] = map_element_RND_to_EM(EL_EMPTY);
+      int player_nr = GET_PLAYER_NR(level->field[x][y]);
+      int offset = (BorderElement == EL_STEELWALL ? 1 : 0);
+      int xx = x + 1 + offset;
+      int yy = y + 1 + offset;
+
+      ply[player_nr]->x_initial = xx;
+      ply[player_nr]->y_initial = yy;
+
+      level_em->cave[xx][yy] = map_element_RND_to_EM(EL_EMPTY);
     }
   }
+
+  if (BorderElement == EL_STEELWALL)
+  {
+    lev->width  += 2;
+    lev->height += 2;
+  }
 }
 
 void CopyNativeLevel_EM_to_RND(struct LevelInfo *level)
@@ -2274,8 +3585,7 @@ void CopyNativeLevel_EM_to_RND(struct LevelInfo *level)
   };
   struct LevelInfo_EM *level_em = level->native_em_level;
   struct LEVEL *lev = level_em->lev;
-  struct PLAYER *ply1 = level_em->ply1;
-  struct PLAYER *ply2 = level_em->ply2;
+  struct PLAYER **ply = level_em->ply;
   int i, j, x, y;
 
   level->fieldx = MIN(lev->width,  MAX_LEV_FIELDX);
@@ -2314,6 +3624,7 @@ void CopyNativeLevel_EM_to_RND(struct LevelInfo *level)
   level->ball_random           = lev->ball_random;
   level->ball_state_initial    = lev->ball_state_initial;
   level->ball_time             = lev->ball_time;
+  level->num_ball_contents     = lev->num_ball_arrays;
 
   level->lenses_score          = lev->lenses_score;
   level->magnify_score         = lev->magnify_score;
@@ -2321,15 +3632,16 @@ void CopyNativeLevel_EM_to_RND(struct LevelInfo *level)
 
   level->lenses_time           = lev->lenses_time;
   level->magnify_time          = lev->magnify_time;
-  level->wind_direction_initial        = lev->wind_direction_initial;
+
+  level->wind_direction_initial =
+    map_direction_EM_to_RND(lev->wind_direction_initial);
 
   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]);
 
-  for (i = 0; i < 16; i++)
-    level->android_array[i] = FALSE;   /* !!! YET TO COME !!! */
+  map_android_clone_elements_EM_to_RND(level);
 
   /* convert the playfield (some elements need special treatment) */
   for (y = 0; y < level->fieldy; y++) for (x = 0; x < level->fieldx; x++)
@@ -2342,13 +3654,16 @@ void CopyNativeLevel_EM_to_RND(struct LevelInfo *level)
     level->field[x][y] = new_element;
   }
 
-  /* 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;
+  for (i = 0; i < MAX_PLAYERS; i++)
+  {
+    /* in case of all players set to the same field, use the first player */
+    int nr = MAX_PLAYERS - i - 1;
+    int jx = ply[nr]->x_initial - 1;
+    int jy = ply[nr]->y_initial - 1;
 
-#if 0
-  printf("::: native Emerald Mine file version: %d\n", level_em->file_version);
-#endif
+    if (jx != -1 && jy != -1)
+      level->field[jx][jy] = EL_PLAYER_1 + nr;
+  }
 }
 
 static void LoadLevelFromFileInfo_EM(struct LevelInfo *level,
@@ -2384,6 +3699,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;
 
@@ -2417,7 +3733,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) */
 
@@ -2522,8 +3841,12 @@ static void LoadLevelFromFileStream_SP(FILE *file, struct LevelInfo *level,
   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;               /* !!! CORRECT THIS !!! */
+    level->score[i] = 0;
+#endif
 
   /* there are no yamyams in supaplex levels */
   for (i = 0; i < level->num_yamyam_contents; i++)
@@ -2626,7 +3949,7 @@ static void LoadLevelFromFileInfo_SP(struct LevelInfo *level,
 
     if (reading_multipart_level &&
        (!is_multipart_level ||
-        strcmp(level->name, multipart_level.name) != 0))
+        !strEqual(level->name, multipart_level.name)))
     {
       /* we are already reading parts of a multi-part level, but this level is
         either not a multi-part level, or a part of a different multi-part
@@ -2748,9 +4071,7 @@ void LoadLevelFromFileInfo(struct LevelInfo *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_RND_to_Native(level);
-  else
+  if (level_file_info->type != LEVEL_FILE_TYPE_RND)
     CopyNativeLevel_Native_to_RND(level);
 }
 
@@ -2770,76 +4091,26 @@ void LoadLevelFromFilename(struct LevelInfo *level, char *filename)
 
 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
-  printf("::: sort_priority: %d\n", leveldir_current->sort_priority);
+  leveldir_current->latest_engine = TRUE;      /* !!! TEST ONLY !!! */
 #endif
 
-  /* determine correct game engine version of current level */
-  if (!leveldir_current->latest_engine)
+  if (leveldir_current->latest_engine)
   {
-    /* For all levels which are not forced to use the latest game engine
-       version (normally user contributed, private and undefined levels),
-       use the version of the game engine the levels were created for.
-
-       Since 2.0.1, the game engine version is now directly stored
-       in the level file (chunk "VERS"), so there is no need anymore
-       to set the game version from the file version (except for old,
-       pre-2.0 levels, where the game version is still taken from the
-       file format version used to store the level -- see above). */
-
-    /* player was faster than enemies in 1.0.0 and before */
-    if (level->file_version == FILE_VERSION_1_0)
-      level->double_speed = TRUE;
-
-    /* default behaviour for EM style gems was "slippery" only in 2.0.1 */
-    if (level->game_version == VERSION_IDENT(2,0,1,0))
-      level->em_slippery_gems = TRUE;
-
-    /* springs could be pushed over pits before (pre-release version) 2.2.0 */
-    if (level->game_version < VERSION_IDENT(2,2,0,0))
-      level->use_spring_bug = TRUE;
-
-    /* only few elements were able to actively move into acid before 3.1.0 */
-    /* 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 */
-      level->dont_collide_with_bits = 0; /* nothing is deadly when colliding */
-
-      setMoveIntoAcidProperty(level, EL_ROBOT,     TRUE);
-      setMoveIntoAcidProperty(level, EL_SATELLITE, TRUE);
-      setMoveIntoAcidProperty(level, EL_PENGUIN,   TRUE);
-      setMoveIntoAcidProperty(level, EL_BALLOON,   TRUE);
+    /* ---------- use latest game engine ----------------------------------- */
 
-      for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
-       SET_PROPERTY(EL_CUSTOM_START + i, EP_CAN_MOVE_INTO_ACID, TRUE);
-
-      /* correct trigger settings (stored as zero == "none" in old levels) */
-
-      for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
-      {
-       int element = EL_CUSTOM_START + i;
-       struct ElementInfo *ei = &element_info[element];
-
-       for (j = 0; j < ei->num_change_pages; j++)
-       {
-         struct ElementChangeInfo *change = &ei->change_page[j];
-
-         change->trigger_player = CH_PLAYER_ANY;
-         change->trigger_page = CH_PAGE_ANY;
-       }
-      }
-    }
-  }
-  else         /* always use the latest game engine version */
-  {
     /* 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
@@ -2859,6 +4130,112 @@ static void LoadLevel_InitVersion(struct LevelInfo *level, char *filename)
 
     if (level->file_version < FILE_VERSION_2_0)
       level->em_slippery_gems = TRUE;
+
+    return;
+  }
+
+  /* ---------- use game engine the level was created with ----------------- */
+
+  /* For all levels which are not forced to use the latest game engine
+     version (normally user contributed, private and undefined levels),
+     use the version of the game engine the levels were created for.
+
+     Since 2.0.1, the game engine version is now directly stored
+     in the level file (chunk "VERS"), so there is no need anymore
+     to set the game version from the file version (except for old,
+     pre-2.0 levels, where the game version is still taken from the
+     file format version used to store the level -- see above). */
+
+  /* player was faster than enemies in 1.0.0 and before */
+  if (level->file_version == FILE_VERSION_1_0)
+    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))
+    level->em_slippery_gems = TRUE;
+
+  /* springs could be pushed over pits before (pre-release version) 2.2.0 */
+  if (level->game_version < VERSION_IDENT(2,2,0,0))
+    level->use_spring_bug = TRUE;
+
+  if (level->game_version < VERSION_IDENT(3,2,0,5))
+  {
+    /* time orb caused limited time in endless time levels before 3.2.0-5 */
+    level->use_time_orb_bug = TRUE;
+
+    /* default behaviour for snapping was "no snap delay" before 3.2.0-5 */
+    level->block_snap_field = FALSE;
+
+    /* extra time score was same value as time left score before 3.2.0-5 */
+    level->extra_time_score = level->score[SC_TIME_BONUS];
+
+#if 0
+    /* time bonus score was given for 10 s instead of 1 s before 3.2.0-5 */
+    level->score[SC_TIME_BONUS] /= 10;
+#endif
+  }
+
+  if (level->game_version < VERSION_IDENT(3,2,0,7))
+  {
+    /* default behaviour for snapping was "not continuous" before 3.2.0-7 */
+    level->continuous_snapping = FALSE;
+  }
+
+  /* only few elements were able to actively move into acid before 3.1.0 */
+  /* trigger settings did not exist before 3.1.0; set to default "any" */
+  if (level->game_version < VERSION_IDENT(3,1,0,0))
+  {
+    /* correct "can move into acid" settings (all zero in old levels) */
+
+    level->can_move_into_acid_bits = 0; /* nothing can move into acid */
+    level->dont_collide_with_bits = 0; /* nothing is deadly when colliding */
+
+    setMoveIntoAcidProperty(level, EL_ROBOT,     TRUE);
+    setMoveIntoAcidProperty(level, EL_SATELLITE, TRUE);
+    setMoveIntoAcidProperty(level, EL_PENGUIN,   TRUE);
+    setMoveIntoAcidProperty(level, EL_BALLOON,   TRUE);
+
+    for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
+      SET_PROPERTY(EL_CUSTOM_START + i, EP_CAN_MOVE_INTO_ACID, TRUE);
+
+    /* correct trigger settings (stored as zero == "none" in old levels) */
+
+    for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
+    {
+      int element = EL_CUSTOM_START + i;
+      struct ElementInfo *ei = &element_info[element];
+
+      for (j = 0; j < ei->num_change_pages; j++)
+      {
+       struct ElementChangeInfo *change = &ei->change_page[j];
+
+       change->trigger_player = CH_PLAYER_ANY;
+       change->trigger_page = CH_PAGE_ANY;
+      }
+    }
+  }
+
+  /* try to detect and fix "Snake Bite" levels, which are broken with 3.2.0 */
+  {
+    int element = EL_CUSTOM_START + 255;
+    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;
   }
 }
 
@@ -2876,7 +4253,8 @@ static void LoadLevel_InitElements(struct LevelInfo *level, char *filename)
       int element = EL_CUSTOM_START + i;
 
       /* order of checking and copying events to be mapped is important */
-      for (j = CE_BY_OTHER_ACTION; j >= CE_COUNT_AT_ZERO; j--)
+      /* (do not change the start and end value -- they are constant) */
+      for (j = CE_BY_OTHER_ACTION; j >= CE_VALUE_GETS_ZERO; j--)
       {
        if (HAS_CHANGE_EVENT(element, j - 2))
        {
@@ -2886,6 +4264,7 @@ static void LoadLevel_InitElements(struct LevelInfo *level, char *filename)
       }
 
       /* order of checking and copying events to be mapped is important */
+      /* (do not change the start and end value -- they are constant) */
       for (j = CE_PLAYER_COLLECTS_X; j >= CE_HITTING_SOMETHING; j--)
       {
        if (HAS_CHANGE_EVENT(element, j - 1))
@@ -2919,20 +4298,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)
   {
@@ -2953,7 +4321,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 !!! */
@@ -3000,6 +4367,7 @@ static void LoadLevel_InitElements(struct LevelInfo *level, char *filename)
 
   /* initialize element properties for level editor etc. */
   InitElementPropertiesEngine(level->game_version);
+  InitElementPropertiesAfterLoading(level->game_version);
 }
 
 static void LoadLevel_InitPlayfield(struct LevelInfo *level, char *filename)
@@ -3025,6 +4393,14 @@ static void LoadLevel_InitPlayfield(struct LevelInfo *level, char *filename)
   SetBorderElement();
 }
 
+static void LoadLevel_InitNativeEngines(struct LevelInfo *level,char *filename)
+{
+  struct LevelFileInfo *level_file_info = &level->file_info;
+
+  if (level_file_info->type == LEVEL_FILE_TYPE_RND)
+    CopyNativeLevel_RND_to_Native(level);
+}
+
 void LoadLevelTemplate(int nr)
 {
   char *filename;
@@ -3055,14 +4431,32 @@ void LoadLevel(int nr)
   LoadLevel_InitVersion(&level, filename);
   LoadLevel_InitElements(&level, filename);
   LoadLevel_InitPlayfield(&level, filename);
+
+  LoadLevel_InitNativeEngines(&level, filename);
+}
+
+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 void SaveLevel_VERS(FILE *file, struct LevelInfo *level)
+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;
@@ -3089,7 +4483,7 @@ static void SaveLevel_HEAD(FILE *file, struct LevelInfo *level)
   putFile8Bit(file, level->time_wheel);
   putFile8Bit(file, (level->encoding_16bit_amoeba ? EL_EMPTY :
                     level->amoeba_content));
-  putFile8Bit(file, (level->double_speed ? 1 : 0));
+  putFile8Bit(file, (level->initial_player_stepsize == STEPSIZE_FAST ? 1 : 0));
   putFile8Bit(file, (level->initial_gravity ? 1 : 0));
   putFile8Bit(file, (level->encoding_16bit_field ? 1 : 0));
   putFile8Bit(file, (level->em_slippery_gems ? 1 : 0));
@@ -3110,27 +4504,59 @@ static void SaveLevel_HEAD(FILE *file, struct LevelInfo *level)
 
   putFile8Bit(file, level->game_engine_type);
 
-  WriteUnusedBytesToFile(file, LEVEL_HEADER_UNUSED);
+  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]);
+
+  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 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)
+       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
@@ -3153,6 +4579,7 @@ static void SaveLevel_CONT(FILE *file, struct LevelInfo *level)
 }
 #endif
 
+#if 0
 static void SaveLevel_CNT2(FILE *file, struct LevelInfo *level, int element)
 {
   int i, x, y;
@@ -3203,23 +4630,30 @@ static void SaveLevel_CNT2(FILE *file, struct LevelInfo *level, int element)
       for (x = 0; x < 3; x++)
        putFile16BitBE(file, content_array[i][x][y]);
 }
+#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,
@@ -3233,12 +4667,14 @@ static void SaveLevel_CUS1(FILE *file, struct LevelInfo *level,
   {
     int element = EL_CUSTOM_START + i;
 
-    if (Properties[element][EP_BITFIELD_BASE] != EP_BITMASK_DEFAULT)
+    struct ElementInfo *ei = &element_info[element];
+
+    if (ei->properties[EP_BITFIELD_BASE_NR] != EP_BITMASK_DEFAULT)
     {
       if (check < num_changed_custom_elements)
       {
        putFile16BitBE(file, element);
-       putFile32BitBE(file, Properties[element][EP_BITFIELD_BASE]);
+       putFile32BitBE(file, ei->properties[EP_BITFIELD_BASE_NR]);
       }
 
       check++;
@@ -3290,63 +4726,64 @@ static void SaveLevel_CUS3(FILE *file, struct LevelInfo *level,
   for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
   {
     int element = EL_CUSTOM_START + i;
+    struct ElementInfo *ei = &element_info[element];
 
-    if (element_info[element].modified_settings)
+    if (ei->modified_settings)
     {
       if (check < num_changed_custom_elements)
       {
        putFile16BitBE(file, element);
 
        for (j = 0; j < MAX_ELEMENT_NAME_LEN; j++)
-         putFile8Bit(file, element_info[element].description[j]);
+         putFile8Bit(file, ei->description[j]);
 
-       putFile32BitBE(file, Properties[element][EP_BITFIELD_BASE]);
+       putFile32BitBE(file, ei->properties[EP_BITFIELD_BASE_NR]);
 
        /* some free bytes for future properties and padding */
        WriteUnusedBytesToFile(file, 7);
 
-       putFile8Bit(file, element_info[element].use_gfx_element);
-       putFile16BitBE(file, element_info[element].gfx_element);
+       putFile8Bit(file, ei->use_gfx_element);
+       putFile16BitBE(file, ei->gfx_element);
 
-       putFile8Bit(file, element_info[element].collect_score_initial);
-       putFile8Bit(file, element_info[element].collect_count_initial);
+       putFile8Bit(file, ei->collect_score_initial);
+       putFile8Bit(file, ei->collect_count_initial);
 
-       putFile16BitBE(file, element_info[element].push_delay_fixed);
-       putFile16BitBE(file, element_info[element].push_delay_random);
-       putFile16BitBE(file, element_info[element].move_delay_fixed);
-       putFile16BitBE(file, element_info[element].move_delay_random);
+       putFile16BitBE(file, ei->push_delay_fixed);
+       putFile16BitBE(file, ei->push_delay_random);
+       putFile16BitBE(file, ei->move_delay_fixed);
+       putFile16BitBE(file, ei->move_delay_random);
 
-       putFile16BitBE(file, element_info[element].move_pattern);
-       putFile8Bit(file, element_info[element].move_direction_initial);
-       putFile8Bit(file, element_info[element].move_stepsize);
+       putFile16BitBE(file, ei->move_pattern);
+       putFile8Bit(file, ei->move_direction_initial);
+       putFile8Bit(file, ei->move_stepsize);
 
        for (y = 0; y < 3; y++)
          for (x = 0; x < 3; x++)
-           putFile16BitBE(file, element_info[element].content.e[x][y]);
+           putFile16BitBE(file, ei->content.e[x][y]);
 
-       putFile32BitBE(file, element_info[element].change->events);
+       putFile32BitBE(file, ei->change->events);
 
-       putFile16BitBE(file, element_info[element].change->target_element);
+       putFile16BitBE(file, ei->change->target_element);
 
-       putFile16BitBE(file, element_info[element].change->delay_fixed);
-       putFile16BitBE(file, element_info[element].change->delay_random);
-       putFile16BitBE(file, element_info[element].change->delay_frames);
+       putFile16BitBE(file, ei->change->delay_fixed);
+       putFile16BitBE(file, ei->change->delay_random);
+       putFile16BitBE(file, ei->change->delay_frames);
 
-       putFile16BitBE(file, element_info[element].change->trigger_element);
+       putFile16BitBE(file, ei->change->trigger_element);
 
-       putFile8Bit(file, element_info[element].change->explode);
-       putFile8Bit(file, element_info[element].change->use_target_content);
-       putFile8Bit(file, element_info[element].change->only_if_complete);
-       putFile8Bit(file, element_info[element].change->use_random_replace);
+       putFile8Bit(file, ei->change->explode);
+       putFile8Bit(file, ei->change->use_target_content);
+       putFile8Bit(file, ei->change->only_if_complete);
+       putFile8Bit(file, ei->change->use_random_replace);
 
-       putFile8Bit(file, element_info[element].change->random_percentage);
-       putFile8Bit(file, element_info[element].change->replace_when);
+       putFile8Bit(file, ei->change->random_percentage);
+       putFile8Bit(file, ei->change->replace_when);
 
        for (y = 0; y < 3; y++)
          for (x = 0; x < 3; x++)
-           putFile16BitBE(file,element_info[element].change->content.e[x][y]);
+           putFile16BitBE(file, ei->change->content.e[x][y]);
 
-       putFile8Bit(file, element_info[element].slippery_type);
+       putFile8Bit(file, ei->slippery_type);
 
        /* some free bytes for future properties and padding */
        WriteUnusedBytesToFile(file, LEVEL_CPART_CUS3_UNUSED);
@@ -3361,25 +4798,28 @@ static void SaveLevel_CUS3(FILE *file, struct LevelInfo *level,
 }
 #endif
 
+#if 0
 static void SaveLevel_CUS4(FILE *file, struct LevelInfo *level, int element)
 {
   struct ElementInfo *ei = &element_info[element];
   int i, j, x, y;
 
+  /* ---------- custom element base property values (96 bytes) ------------- */
+
   putFile16BitBE(file, element);
 
   for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++)
     putFile8Bit(file, ei->description[i]);
 
-  putFile32BitBE(file, Properties[element][EP_BITFIELD_BASE]);
+  putFile32BitBE(file, ei->properties[EP_BITFIELD_BASE_NR]);
+
   WriteUnusedBytesToFile(file, 4);     /* reserved for more base properties */
 
   putFile8Bit(file, ei->num_change_pages);
 
-  /* some free bytes for future base property values and padding */
-  WriteUnusedBytesToFile(file, 5);
-
-  /* write custom property values */
+  putFile16BitBE(file, ei->ce_value_fixed_initial);
+  putFile16BitBE(file, ei->ce_value_random_initial);
+  putFile8Bit(file, ei->use_last_ce_value);
 
   putFile8Bit(file, ei->use_gfx_element);
   putFile16BitBE(file, ei->gfx_element);
@@ -3421,17 +4861,18 @@ static void SaveLevel_CUS4(FILE *file, struct LevelInfo *level, int element)
   /* some free bytes for future custom property values and padding */
   WriteUnusedBytesToFile(file, 1);
 
-  /* write change property values */
+  /* ---------- change page property values (48 bytes) --------------------- */
 
   for (i = 0; i < ei->num_change_pages; i++)
   {
     struct ElementChangeInfo *change = &ei->change_page[i];
-    unsigned long event_bits = 0;
+    unsigned int event_bits;
 
-    for (j = 0; j < NUM_CHANGE_EVENTS; j++)
+    /* bits 0 - 31 of "has_event[]" ... */
+    event_bits = 0;
+    for (j = 0; j < MIN(NUM_CHANGE_EVENTS, 32); j++)
       if (change->has_event[j])
        event_bits |= (1 << j);
-
     putFile32BitBE(file, event_bits);
 
     putFile16BitBE(file, change->target_element);
@@ -3467,11 +4908,17 @@ static void SaveLevel_CUS4(FILE *file, struct LevelInfo *level, int element)
     putFile8Bit(file, change->action_mode);
     putFile16BitBE(file, change->action_arg);
 
-    /* some free bytes for future change property values and padding */
-    WriteUnusedBytesToFile(file, 1);
+    /* ... bits 32 - 39 of "has_event[]" (not nice, but downward compatible) */
+    event_bits = 0;
+    for (j = 32; j < NUM_CHANGE_EVENTS; j++)
+      if (change->has_event[j])
+       event_bits |= (1 << (j - 32));
+    putFile8Bit(file, event_bits);
   }
 }
+#endif
 
+#if 0
 static void SaveLevel_GRP1(FILE *file, struct LevelInfo *level, int element)
 {
   struct ElementInfo *ei = &element_info[element];
@@ -3496,95 +4943,233 @@ static void SaveLevel_GRP1(FILE *file, struct LevelInfo *level, int element)
   for (i = 0; i < MAX_ELEMENTS_IN_GROUP; i++)
     putFile16BitBE(file, group->element[i]);
 }
+#endif
 
-static int SaveLevel_CONF_Value(FILE *file, int pos)
+static int SaveLevel_MicroChunk(FILE *file, struct LevelFileConfigInfo *entry,
+                               boolean write_element)
 {
-  int default_value = element_conf[pos].default_value;
-  int element = element_conf[pos].element;
-  int type = element_conf[pos].type;
-  int bytes = type & CONF_MASK_BYTES;
-  void *value_ptr = element_conf[pos].value;
-  int value = (CONF_VALUE_BOOLEAN(type) ? *(boolean *)value_ptr :
-              *(int *)value_ptr);
+  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;
+  int element = entry->element;
+  int default_value = entry->default_value;
   int num_bytes = 0;
   boolean modified = FALSE;
 
-  /* check if any settings have been modified before saving them */
-  if (value != default_value)
-    modified = TRUE;
+  if (byte_mask != CONF_MASK_MULTI_BYTES)
+  {
+    void *value_ptr = entry->value;
+    int value = (data_type == TYPE_BOOLEAN ? *(boolean *)value_ptr :
+                *(int *)value_ptr);
+
+    /* check if any settings have been modified before saving them */
+    if (value != default_value)
+      modified = TRUE;
+
+    /* 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)
+      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);
+  }
+  else if (data_type == TYPE_STRING)
+  {
+    char *default_string = entry->default_string;
+    char *string = (char *)(entry->value);
+    int string_length = strlen(string);
+    int i;
+
+    /* check if any settings have been modified before saving them */
+    if (!strEqual(string, default_string))
+      modified = TRUE;
+
+    /* 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)
+      num_bytes += putFile16BitBE(file, element);
+
+    num_bytes += putFile8Bit(file, conf_type);
+    num_bytes += putFile16BitBE(file, string_length);
+
+    for (i = 0; i < string_length; i++)
+      num_bytes += putFile8Bit(file, string[i]);
+  }
+  else if (data_type == TYPE_ELEMENT_LIST)
+  {
+    int *element_array = (int *)(entry->value);
+    int num_elements = *(int *)(entry->num_entities);
+    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;
+
+    /* 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)
+      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]);
+  }
+  else if (data_type == TYPE_CONTENT_LIST)
+  {
+    struct Content *content = (struct Content *)(entry->value);
+    int num_contents = *(int *)(entry->num_entities);
+    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;
+    /* 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 (bytes == CONF_MASK_MULTI_BYTES)
-    Error(ERR_EXIT, "SaveLevel_CONF_Value: cannot save multi-byte values");
+    if (write_element)
+      num_bytes += putFile16BitBE(file, element);
 
-  num_bytes += putFile16BitBE(file, element);
-  num_bytes += putFile8Bit(file, type);
-  num_bytes += (bytes == CONF_MASK_1_BYTE ? putFile8Bit   (file, value) :
-               bytes == CONF_MASK_2_BYTE ? putFile16BitBE(file, value) :
-               bytes == CONF_MASK_4_BYTE ? putFile32BitBE(file, value) : 0);
+    num_bytes += putFile8Bit(file, conf_type);
+    num_bytes += putFile16BitBE(file, num_contents * CONF_CONTENT_NUM_BYTES);
+
+    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]);
+  }
 
   return num_bytes;
 }
 
-static int SaveLevel_CONF_Content(FILE *file, int pos, int num_contents)
+static int SaveLevel_INFO(FILE *file, struct LevelInfo *level)
 {
-  struct Content *content = (struct Content *)(element_conf[pos].value);
-  int default_value = element_conf[pos].default_value;
-  int element = element_conf[pos].element;
-  int type = element_conf[pos].type;
-  int num_bytes = 0;
-  boolean modified = FALSE;
-  int i, x, y;
+  int chunk_size = 0;
+  int i;
 
-  /* 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;
+  li = *level;         /* copy level data into temporary buffer */
 
-  if (!modified)               /* do not save unmodified default settings */
-    return 0;
+  for (i = 0; chunk_config_INFO[i].data_type != -1; i++)
+    chunk_size += SaveLevel_MicroChunk(file, &chunk_config_INFO[i], FALSE);
 
-  num_bytes += putFile16BitBE(file, element);
-  num_bytes += putFile8Bit(file, type);
-  num_bytes += putFile16BitBE(file, num_contents * CONF_CONTENT_NUM_BYTES);
+  return chunk_size;
+}
 
-  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]);
+static int SaveLevel_ELEM(FILE *file, struct LevelInfo *level)
+{
+  int chunk_size = 0;
+  int i;
 
-  return num_bytes;
+  li = *level;         /* copy level data into temporary buffer */
+
+  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 information into temporary buffer */
+  chunk_size += putFile16BitBE(file, element);
+
+  /* copy envelope data into temporary buffer */
+  xx_envelope = level->envelope[envelope_nr];
+
+  for (i = 0; chunk_config_NOTE[i].data_type != -1; i++)
+    chunk_size += SaveLevel_MicroChunk(file, &chunk_config_NOTE[i], FALSE);
 
-  for (i = 0; element_conf[i].element != -1; i++)
+  return chunk_size;
+}
+
+static int SaveLevel_CUSX(FILE *file, struct LevelInfo *level, int element)
+{
+  struct ElementInfo *ei = &element_info[element];
+  int chunk_size = 0;
+  int i, j;
+
+  chunk_size += putFile16BitBE(file, element);
+
+  xx_ei = *ei;         /* copy element data into temporary buffer */
+
+  /* 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;
+
+  for (i = 0; chunk_config_CUSX_base[i].data_type != -1; i++)
+    chunk_size += SaveLevel_MicroChunk(file, &chunk_config_CUSX_base[i], FALSE);
+
+  for (i = 0; i < ei->num_change_pages; i++)
   {
-    int type = element_conf[i].type;
-    int bytes = type & CONF_MASK_BYTES;
+    struct ElementChangeInfo *change = &ei->change_page[i];
+
+    xx_current_change_page = i;
 
-    if (bytes != CONF_MASK_MULTI_BYTES)
-      chunk_size += SaveLevel_CONF_Value(file, i);
-    else if (type == CONF_VALUE_CONTENT_8)
-      chunk_size += SaveLevel_CONF_Content(file, i, MAX_ELEMENT_CONTENTS);
+    xx_change = *change;       /* copy change data into temporary buffer */
+
+    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);
   }
 
   return chunk_size;
 }
 
+static int SaveLevel_GRPX(FILE *file, struct LevelInfo *level, int element)
+{
+  struct ElementInfo *ei = &element_info[element];
+  struct ElementGroupInfo *group = ei->group;
+  int chunk_size = 0;
+  int i;
+
+  chunk_size += putFile16BitBE(file, element);
+
+  xx_ei = *ei;         /* copy element data into temporary buffer */
+  xx_group = *group;   /* copy group data into temporary buffer */
+
+  /* set default description string for this specific element */
+  strcpy(xx_default_description, getDefaultElementDescription(ei));
+
+  for (i = 0; chunk_config_GRPX[i].data_type != -1; i++)
+    chunk_size += SaveLevel_MicroChunk(file, &chunk_config_GRPX[i], FALSE);
+
+  return chunk_size;
+}
+
 static void SaveLevelFromFilename(struct LevelInfo *level, char *filename)
 {
-  int body_chunk_size, conf_chunk_size;
-  int i, x, y;
+  int chunk_size;
+  int i;
   FILE *file;
 
   if (!(file = fopen(filename, MODE_WRITE)))
@@ -3596,111 +5181,82 @@ 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", FILE_VERS_CHUNK_SIZE);
+  chunk_size = SaveLevel_VERS(NULL, level);
+  putFileChunkBE(file, "VERS", chunk_size);
   SaveLevel_VERS(file, level);
 
-  putFileChunkBE(file, "HEAD", LEVEL_HEADER_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);
+  chunk_size = SaveLevel_NAME(NULL, level);
+  putFileChunkBE(file, "NAME", chunk_size);
+  SaveLevel_NAME(file, level);
+
+  chunk_size = SaveLevel_AUTH(NULL, level);
+  putFileChunkBE(file, "AUTH", chunk_size);
   SaveLevel_AUTH(file, level);
 
-  putFileChunkBE(file, "BODY", body_chunk_size);
+  chunk_size = SaveLevel_INFO(NULL, level);
+  putFileChunkBE(file, "INFO", chunk_size);
+  SaveLevel_INFO(file, level);
+
+  chunk_size = SaveLevel_BODY(NULL, level);
+  putFileChunkBE(file, "BODY", chunk_size);
   SaveLevel_BODY(file, level);
 
-  if (level->encoding_16bit_yamyam ||
-      level->num_yamyam_contents != STD_ELEMENT_CONTENTS)
+  chunk_size = SaveLevel_ELEM(NULL, level);
+  if (chunk_size > LEVEL_CHUNK_ELEM_UNCHANGED)         /* save if changed */
   {
-    putFileChunkBE(file, "CNT2", LEVEL_CHUNK_CNT2_SIZE);
-    SaveLevel_CNT2(file, level, EL_YAMYAM);
+    putFileChunkBE(file, "ELEM", chunk_size);
+    SaveLevel_ELEM(file, level);
   }
 
-  if (level->encoding_16bit_amoeba)
+  for (i = 0; i < NUM_ENVELOPES; i++)
   {
-    putFileChunkBE(file, "CNT2", LEVEL_CHUNK_CNT2_SIZE);
-    SaveLevel_CNT2(file, level, EL_BD_AMOEBA);
-  }
+    int element = EL_ENVELOPE_1 + i;
 
-  /* check for envelope content */
-  for (i = 0; i < 4; i++)
-  {
-    if (strlen(level->envelope_text[i]) > 0)
+    chunk_size = SaveLevel_NOTE(NULL, level, element);
+    if (chunk_size > LEVEL_CHUNK_NOTE_UNCHANGED)       /* save if changed */
     {
-      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, "NOTE", chunk_size);
+      SaveLevel_NOTE(file, level, element);
     }
   }
 
-  /* check for non-default custom elements (unless using template level) */
+  /* if not using template level, check for non-default custom/group elements */
   if (!level->use_custom_template)
   {
     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
     {
       int element = EL_CUSTOM_START + i;
 
-      if (element_info[element].modified_settings)
+      chunk_size = SaveLevel_CUSX(NULL, level, element);
+      if (chunk_size > LEVEL_CHUNK_CUSX_UNCHANGED)     /* save if changed */
       {
-       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);
+       putFileChunkBE(file, "CUSX", chunk_size);
+       SaveLevel_CUSX(file, level, element);
       }
     }
-  }
 
-  /* check for non-default group elements (unless using template level) */
-  if (!level->use_custom_template)
-  {
     for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
     {
       int element = EL_GROUP_START + i;
 
-      if (element_info[element].modified_settings)
+      chunk_size = SaveLevel_GRPX(NULL, level, element);
+      if (chunk_size > LEVEL_CHUNK_GRPX_UNCHANGED)     /* save if changed */
       {
-       putFileChunkBE(file, "GRP1", LEVEL_CHUNK_GRP1_SIZE);
-       SaveLevel_GRP1(file, level, element);
+       putFileChunkBE(file, "GRPX", chunk_size);
+       SaveLevel_GRPX(file, level, element);
       }
     }
   }
 
-  conf_chunk_size = SaveLevel_CONF(NULL, level);       /* get chunk size */
-
-  /* check for non-default configuration settings to be saved in CONF chunk */
-  if (conf_chunk_size > 0)
-  {
-    putFileChunkBE(file, "CONF", conf_chunk_size);
-    SaveLevel_CONF(file, level);
-  }
-
   fclose(file);
 
   SetFilePermissions(filename, PERMS_PRIVATE);
@@ -3720,6 +5276,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)
@@ -3749,8 +5324,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("Double speed movement:       %s\n", (level->double_speed ? "yes" : "no"));
+
   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"));
@@ -3826,7 +5400,7 @@ static int LoadTape_HEAD(FILE *file, int chunk_size, struct TapeInfo *tape)
       }
     }
 
-    ReadUnusedBytesFromFile(file, TAPE_HEADER_UNUSED);
+    ReadUnusedBytesFromFile(file, TAPE_CHUNK_HEAD_UNUSED);
 
     engine_version = getFileVersion(file);
     if (engine_version > 0)
@@ -3960,12 +5534,12 @@ void LoadTapeFromFilename(char *filename)
   }
 
   getFileChunkBE(file, chunk_name, NULL);
-  if (strcmp(chunk_name, "RND1") == 0)
+  if (strEqual(chunk_name, "RND1"))
   {
     getFile32BitBE(file);              /* not used */
 
     getFileChunkBE(file, chunk_name, NULL);
-    if (strcmp(chunk_name, "TAPE") != 0)
+    if (!strEqual(chunk_name, "TAPE"))
     {
       tape.no_valid_file = TRUE;
 
@@ -4006,8 +5580,8 @@ void LoadTapeFromFilename(char *filename)
   if (tape.file_version < FILE_VERSION_1_2)
   {
     /* tape files from versions before 1.2.0 without chunk structure */
-    LoadTape_HEAD(file, TAPE_HEADER_SIZE, &tape);
-    LoadTape_BODY(file, 2 * tape.length,  &tape);
+    LoadTape_HEAD(file, TAPE_CHUNK_HEAD_SIZE, &tape);
+    LoadTape_BODY(file, 2 * tape.length,      &tape);
   }
   else
   {
@@ -4019,8 +5593,8 @@ void LoadTapeFromFilename(char *filename)
     }
     chunk_info[] =
     {
-      { "VERS", FILE_VERS_CHUNK_SIZE,  LoadTape_VERS },
-      { "HEAD", TAPE_HEADER_SIZE,      LoadTape_HEAD },
+      { "VERS", TAPE_CHUNK_VERS_SIZE,  LoadTape_VERS },
+      { "HEAD", TAPE_CHUNK_HEAD_SIZE,  LoadTape_HEAD },
       { "INFO", -1,                    LoadTape_INFO },
       { "BODY", -1,                    LoadTape_BODY },
       {  NULL,  0,                     NULL }
@@ -4031,7 +5605,7 @@ void LoadTapeFromFilename(char *filename)
       int i = 0;
 
       while (chunk_info[i].name != NULL &&
-            strcmp(chunk_name, chunk_info[i].name) != 0)
+            !strEqual(chunk_name, chunk_info[i].name))
        i++;
 
       if (chunk_info[i].name == NULL)
@@ -4070,6 +5644,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
@@ -4112,7 +5687,7 @@ static void SaveTape_HEAD(FILE *file, struct TapeInfo *tape)
   putFile8Bit(file, store_participating_players);
 
   /* unused bytes not at the end here for 4-byte alignment of engine_version */
-  WriteUnusedBytesToFile(file, TAPE_HEADER_UNUSED);
+  WriteUnusedBytesToFile(file, TAPE_CHUNK_HEAD_UNUSED);
 
   putFileVersion(file, tape->engine_version);
 }
@@ -4148,7 +5723,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;
@@ -4156,6 +5733,7 @@ void SaveTape(int nr)
 
   InitTapeDirectory(leveldir_current->subdir);
 
+#if 0
   /* if a tape still exists, ask to overwrite it */
   if (fileExists(filename))
   {
@@ -4163,6 +5741,7 @@ void SaveTape(int nr)
     if (!Request("Replace old tape ?", REQ_ASK))
       return;
   }
+#endif
 
   if (!(file = fopen(filename, MODE_WRITE)))
   {
@@ -4184,10 +5763,10 @@ void SaveTape(int nr)
   putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED);
   putFileChunkBE(file, "TAPE", CHUNK_SIZE_NONE);
 
-  putFileChunkBE(file, "VERS", FILE_VERS_CHUNK_SIZE);
+  putFileChunkBE(file, "VERS", TAPE_CHUNK_VERS_SIZE);
   SaveTape_VERS(file, &tape);
 
-  putFileChunkBE(file, "HEAD", TAPE_HEADER_SIZE);
+  putFileChunkBE(file, "HEAD", TAPE_CHUNK_HEAD_SIZE);
   SaveTape_HEAD(file, &tape);
 
   putFileChunkBE(file, "INFO", info_chunk_size);
@@ -4202,12 +5781,34 @@ 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)
 {
+  int tape_frame_counter;
   int i, j;
 
   if (tape->no_valid_file)
@@ -4225,12 +5826,14 @@ void DumpTape(struct TapeInfo *tape)
   printf("Level series identifier: '%s'\n", tape->level_identifier);
   printf_line("-", 79);
 
+  tape_frame_counter = 0;
+
   for (i = 0; i < tape->length; i++)
   {
     if (i >= MAX_TAPE_LEN)
       break;
 
-    printf("%03d: ", i);
+    printf("%04d: ", i);
 
     for (j = 0; j < MAX_PLAYERS; j++)
     {
@@ -4249,7 +5852,10 @@ void DumpTape(struct TapeInfo *tape)
       }
     }
 
-    printf("(%03d)\n", tape->pos[i].delay);
+    printf("(%03d) ", tape->pos[i].delay);
+    printf("[%05d]\n", tape_frame_counter);
+
+    tape_frame_counter += tape->pos[i].delay;
   }
 
   printf_line("-", 79);
@@ -4353,23 +5959,29 @@ void SaveScore(int nr)
 #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_FADE_SCREENS               8
 #define SETUP_TOKEN_AUTORECORD                 9
-#define SETUP_TOKEN_QUICK_DOORS                        10
-#define SETUP_TOKEN_TEAM_MODE                  11
-#define SETUP_TOKEN_HANDICAP                   12
-#define SETUP_TOKEN_SKIP_LEVELS                        13
-#define SETUP_TOKEN_TIME_LIMIT                 14
-#define SETUP_TOKEN_FULLSCREEN                 15
-#define SETUP_TOKEN_ASK_ON_ESCAPE              16
-#define SETUP_TOKEN_GRAPHICS_SET               17
-#define SETUP_TOKEN_SOUNDS_SET                 18
-#define SETUP_TOKEN_MUSIC_SET                  19
-#define SETUP_TOKEN_OVERRIDE_LEVEL_GRAPHICS    20
-#define SETUP_TOKEN_OVERRIDE_LEVEL_SOUNDS      21
-#define SETUP_TOKEN_OVERRIDE_LEVEL_MUSIC       22
-
-#define NUM_GLOBAL_SETUP_TOKENS                        23
+#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_FULLSCREEN_MODE            17
+#define SETUP_TOKEN_ASK_ON_ESCAPE              18
+#define SETUP_TOKEN_ASK_ON_ESCAPE_EDITOR       19
+#define SETUP_TOKEN_QUICK_SWITCH               20
+#define SETUP_TOKEN_INPUT_ON_FOCUS             21
+#define SETUP_TOKEN_PREFER_AGA_GRAPHICS                22
+#define SETUP_TOKEN_GRAPHICS_SET               23
+#define SETUP_TOKEN_SOUNDS_SET                 24
+#define SETUP_TOKEN_MUSIC_SET                  25
+#define SETUP_TOKEN_OVERRIDE_LEVEL_GRAPHICS    26
+#define SETUP_TOKEN_OVERRIDE_LEVEL_SOUNDS      27
+#define SETUP_TOKEN_OVERRIDE_LEVEL_MUSIC       28
+
+#define NUM_GLOBAL_SETUP_TOKENS                        29
 
 /* editor setup */
 #define SETUP_TOKEN_EDITOR_EL_BOULDERDASH      0
@@ -4382,18 +5994,44 @@ void SaveScore(int nr)
 #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_CUSTOM_MORE      10
-#define SETUP_TOKEN_EDITOR_EL_HEADLINES                11
-#define SETUP_TOKEN_EDITOR_EL_USER_DEFINED     12
-
-#define NUM_EDITOR_SETUP_TOKENS                        13
+#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_EL_BY_GAME          13
+#define SETUP_TOKEN_EDITOR_EL_BY_TYPE          14
+#define SETUP_TOKEN_EDITOR_SHOW_ELEMENT_TOKEN  15
+
+#define NUM_EDITOR_SETUP_TOKENS                        16
+
+/* editor cascade setup */
+#define SETUP_TOKEN_EDITOR_CASCADE_BD          0
+#define SETUP_TOKEN_EDITOR_CASCADE_EM          1
+#define SETUP_TOKEN_EDITOR_CASCADE_EMC         2
+#define SETUP_TOKEN_EDITOR_CASCADE_RND         3
+#define SETUP_TOKEN_EDITOR_CASCADE_SB          4
+#define SETUP_TOKEN_EDITOR_CASCADE_SP          5
+#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_REF         11
+#define SETUP_TOKEN_EDITOR_CASCADE_USER                12
+#define SETUP_TOKEN_EDITOR_CASCADE_DYNAMIC     13
+
+#define NUM_EDITOR_CASCADE_SETUP_TOKENS                14
 
 /* shortcut setup */
 #define SETUP_TOKEN_SHORTCUT_SAVE_GAME         0
 #define SETUP_TOKEN_SHORTCUT_LOAD_GAME         1
 #define SETUP_TOKEN_SHORTCUT_TOGGLE_PAUSE      2
+#define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_1    3
+#define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_2    4
+#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 NUM_SHORTCUT_SETUP_TOKENS              3
+#define NUM_SHORTCUT_SETUP_TOKENS              8
 
 /* player setup */
 #define SETUP_TOKEN_PLAYER_USE_JOYSTICK                0
@@ -4429,6 +6067,7 @@ void SaveScore(int nr)
 
 static struct SetupInfo si;
 static struct SetupEditorInfo sei;
+static struct SetupEditorCascadeInfo seci;
 static struct SetupShortcutInfo ssi;
 static struct SetupInputInfo sii;
 static struct SetupSystemInfo syi;
@@ -4444,15 +6083,21 @@ static struct TokenInfo global_setup_tokens[] =
   { 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.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_STRING, &si.graphics_set,     "graphics_set"                  },
   { TYPE_STRING, &si.sounds_set,       "sounds_set"                    },
   { TYPE_STRING, &si.music_set,                "music_set"                     },
@@ -4461,8 +6106,19 @@ static struct TokenInfo global_setup_tokens[] =
   { TYPE_SWITCH, &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"},
@@ -4471,18 +6127,49 @@ 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_custom,       "editor.el_custom"              },
-  { TYPE_SWITCH, &sei.el_custom_more,  "editor.el_custom_more"         },
+#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"   },
+};
+
+static struct TokenInfo editor_cascade_setup_tokens[] =
+{
+  { TYPE_SWITCH, &seci.el_bd,          "editor.cascade.el_bd"          },
+  { TYPE_SWITCH, &seci.el_em,          "editor.cascade.el_em"          },
+  { TYPE_SWITCH, &seci.el_emc,         "editor.cascade.el_emc"         },
+  { TYPE_SWITCH, &seci.el_rnd,         "editor.cascade.el_rnd"         },
+  { TYPE_SWITCH, &seci.el_sb,          "editor.cascade.el_sb"          },
+  { TYPE_SWITCH, &seci.el_sp,          "editor.cascade.el_sp"          },
+  { 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_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"     },
 };
 
 static struct TokenInfo shortcut_setup_tokens[] =
 {
   { TYPE_KEY_X11, &ssi.save_game,      "shortcut.save_game"            },
   { TYPE_KEY_X11, &ssi.load_game,      "shortcut.load_game"            },
-  { TYPE_KEY_X11, &ssi.toggle_pause,   "shortcut.toggle_pause"         }
+  { TYPE_KEY_X11, &ssi.toggle_pause,   "shortcut.toggle_pause"         },
+  { TYPE_KEY_X11, &ssi.focus_player[0],        "shortcut.focus_player_1"       },
+  { TYPE_KEY_X11, &ssi.focus_player[1],        "shortcut.focus_player_2"       },
+  { 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"    },
 };
 
 static struct TokenInfo player_setup_tokens[] =
@@ -4502,18 +6189,18 @@ static struct TokenInfo player_setup_tokens[] =
   { TYPE_KEY_X11, &sii.key.up,         ".key.move_up"                  },
   { TYPE_KEY_X11, &sii.key.down,       ".key.move_down"                },
   { TYPE_KEY_X11, &sii.key.snap,       ".key.snap_field"               },
-  { TYPE_KEY_X11, &sii.key.drop,       ".key.place_bomb"               }
+  { TYPE_KEY_X11, &sii.key.drop,       ".key.place_bomb"               },
 };
 
 static struct TokenInfo system_setup_tokens[] =
 {
   { TYPE_STRING,  &syi.sdl_audiodriver,        "system.sdl_audiodriver"        },
-  { TYPE_INTEGER, &syi.audio_fragment_size,"system.audio_fragment_size"        }
+  { TYPE_INTEGER, &syi.audio_fragment_size,"system.audio_fragment_size"        },
 };
 
 static struct TokenInfo options_setup_tokens[] =
 {
-  { TYPE_BOOLEAN, &soi.verbose,                "options.verbose"               }
+  { TYPE_BOOLEAN, &soi.verbose,                "options.verbose"               },
 };
 
 static char *get_corrected_login_name(char *login_name)
@@ -4546,15 +6233,21 @@ static void setSetupInfoToDefaults(struct SetupInfo *si)
   si->direct_draw = !si->double_buffering;
   si->scroll_delay = TRUE;
   si->soft_scrolling = TRUE;
-  si->fading = FALSE;
+  si->fade_screens = TRUE;
   si->autorecord = TRUE;
+  si->show_titlescreen = TRUE;
   si->quick_doors = FALSE;
   si->team_mode = FALSE;
   si->handicap = TRUE;
   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->graphics_set = getStringCopy(GFX_CLASSIC_SUBDIR);
   si->sounds_set = getStringCopy(SND_CLASSIC_SUBDIR);
@@ -4573,15 +6266,23 @@ static void setSetupInfoToDefaults(struct SetupInfo *si)
   si->editor.el_dx_boulderdash    = TRUE;
   si->editor.el_chars             = TRUE;
   si->editor.el_custom            = TRUE;
-  si->editor.el_custom_more       = FALSE;
 
   si->editor.el_headlines = TRUE;
   si->editor.el_user_defined = FALSE;
+  si->editor.el_dynamic = TRUE;
+
+  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.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;
+
   for (i = 0; i < MAX_PLAYERS; i++)
   {
     si->input[i].use_joystick = FALSE;
@@ -4608,6 +6309,25 @@ static void setSetupInfoToDefaults(struct SetupInfo *si)
   si->options.verbose = FALSE;
 }
 
+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_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)
 {
   int i, pnr;
@@ -4670,6 +6390,22 @@ static void decodeSetupFileHash(SetupFileHash *setup_file_hash)
   setup.options = soi;
 }
 
+static void decodeSetupFileHash_EditorCascade(SetupFileHash *setup_file_hash)
+{
+  int i;
+
+  if (!setup_file_hash)
+    return;
+
+  /* editor cascade setup */
+  seci = setup.editor_cascade;
+  for (i = 0; i < NUM_EDITOR_CASCADE_SETUP_TOKENS; i++)
+    setSetupInfo(editor_cascade_setup_tokens, i,
+                getHashEntry(setup_file_hash,
+                             editor_cascade_setup_tokens[i].text));
+  setup.editor_cascade = seci;
+}
+
 void LoadSetup()
 {
   char *filename = getSetupFilename();
@@ -4684,7 +6420,7 @@ void LoadSetup()
   {
     char *player_name_new;
 
-    checkSetupFileHashIdentifier(setup_file_hash, getCookie("SETUP"));
+    checkSetupFileHashIdentifier(setup_file_hash, filename,getCookie("SETUP"));
     decodeSetupFileHash(setup_file_hash);
 
     setup.direct_draw = !setup.double_buffering;
@@ -4700,6 +6436,27 @@ void LoadSetup()
     Error(ERR_WARN, "using default setup values");
 }
 
+void LoadSetup_EditorCascade()
+{
+  char *filename = getPath2(getSetupDir(), EDITORCASCADE_FILENAME);
+  SetupFileHash *setup_file_hash = NULL;
+
+  /* always start with reliable default values */
+  setSetupInfoToDefaults_EditorCascade(&setup);
+
+  setup_file_hash = loadSetupFileHash(filename);
+
+  if (setup_file_hash)
+  {
+    checkSetupFileHashIdentifier(setup_file_hash, filename,getCookie("SETUP"));
+    decodeSetupFileHash_EditorCascade(setup_file_hash);
+
+    freeSetupFileHash(setup_file_hash);
+  }
+
+  free(filename);
+}
+
 void SaveSetup()
 {
   char *filename = getSetupFilename();
@@ -4772,6 +6529,37 @@ void SaveSetup()
   SetFilePermissions(filename, PERMS_PRIVATE);
 }
 
+void SaveSetup_EditorCascade()
+{
+  char *filename = getPath2(getSetupDir(), EDITORCASCADE_FILENAME);
+  FILE *file;
+  int i;
+
+  InitUserDataDirectory();
+
+  if (!(file = fopen(filename, MODE_WRITE)))
+  {
+    Error(ERR_WARN, "cannot write editor cascade state file '%s'", filename);
+    free(filename);
+    return;
+  }
+
+  fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER,
+                                              getCookie("SETUP")));
+  fprintf(file, "\n");
+
+  seci = setup.editor_cascade;
+  fprintf(file, "\n");
+  for (i = 0; i < NUM_EDITOR_CASCADE_SETUP_TOKENS; i++)
+    fprintf(file, "%s\n", getSetupLine(editor_cascade_setup_tokens, "", i));
+
+  fclose(file);
+
+  SetFilePermissions(filename, PERMS_PRIVATE);
+
+  free(filename);
+}
+
 void LoadCustomElementDescriptions()
 {
   char *filename = getCustomArtworkConfigFilename(ARTWORK_TYPE_GRAPHICS);
@@ -4804,19 +6592,14 @@ void LoadCustomElementDescriptions()
   freeSetupFileHash(setup_file_hash);
 }
 
-void LoadSpecialMenuDesignSettings()
+static void LoadSpecialMenuDesignSettingsFromFilename(char *filename)
 {
-  char *filename = getCustomArtworkConfigFilename(ARTWORK_TYPE_GRAPHICS);
   SetupFileHash *setup_file_hash;
-  int i, j;
+  int i;
 
-  /* 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 (strcmp(image_config_vars[i].token, image_config[j].token) == 0)
-       *image_config_vars[i].value =
-         get_auto_parameter_value(image_config_vars[i].token,
-                                  image_config[j].value);
+#if 0
+  printf("LoadSpecialMenuDesignSettings from file '%s' ...\n", filename);
+#endif
 
   if ((setup_file_hash = loadSetupFileHash(filename)) == NULL)
     return;
@@ -4849,6 +6632,34 @@ void LoadSpecialMenuDesignSettings()
   freeSetupFileHash(setup_file_hash);
 }
 
+void LoadSpecialMenuDesignSettings()
+{
+  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);
+
+  if (!SETUP_OVERRIDE_ARTWORK(setup, ARTWORK_TYPE_GRAPHICS))
+  {
+    /* first look for special settings configured in level series config */
+    filename_base = getCustomArtworkLevelConfigFilename(ARTWORK_TYPE_GRAPHICS);
+
+    if (fileExists(filename_base))
+      LoadSpecialMenuDesignSettingsFromFilename(filename_base);
+  }
+
+  filename_local = getCustomArtworkConfigFilename(ARTWORK_TYPE_GRAPHICS);
+
+  if (filename_local != NULL && !strEqual(filename_base, filename_local))
+    LoadSpecialMenuDesignSettingsFromFilename(filename_local);
+}
+
 void LoadUserDefinedEditorElementList(int **elements, int *num_elements)
 {
   char *filename = getEditorSetupFilename();
@@ -4873,6 +6684,10 @@ void LoadUserDefinedEditorElementList(int **elements, int *num_elements)
   /* add space for up to 3 more elements for padding that may be needed */
   *num_elements += 3;
 
+  /* free memory for old list of elements, if needed */
+  checked_free(*elements);
+
+  /* allocate memory for new list of elements */
   *elements = checked_malloc(*num_elements * sizeof(int));
 
   *num_elements = 0;
@@ -5034,7 +6849,7 @@ static boolean music_info_listed_ext(struct MusicFileInfo *list,
                                     char *basename, boolean is_sound)
 {
   for (; list != NULL; list = list->next)
-    if (list->is_sound == is_sound && strcmp(list->basename, basename) == 0)
+    if (list->is_sound == is_sound && strEqual(list->basename, basename))
       return TRUE;
 
   return FALSE;
@@ -5092,7 +6907,7 @@ void LoadMusicInfo()
     if (music->filename == NULL)
       continue;
 
-    if (strcmp(music->filename, UNDEFINED_FILENAME) == 0)
+    if (strEqual(music->filename, UNDEFINED_FILENAME))
       continue;
 
     /* a configured file may be not recognized as music */
@@ -5131,7 +6946,7 @@ void LoadMusicInfo()
       if (music->filename == NULL)
        continue;
 
-      if (strcmp(basename, music->filename) == 0)
+      if (strEqual(basename, music->filename))
       {
        music_already_used = TRUE;
        break;
@@ -5167,7 +6982,7 @@ void LoadMusicInfo()
     if (sound->filename == NULL)
       continue;
 
-    if (strcmp(sound->filename, UNDEFINED_FILENAME) == 0)
+    if (strEqual(sound->filename, UNDEFINED_FILENAME))
       continue;
 
     /* a configured file may be not recognized as sound */
@@ -5266,7 +7081,7 @@ void LoadHelpAnimInfo()
                 i_to_a(element_action_info[i].value));
 
   /* do not store direction index (bit) here, but direction value! */
-  for (i = 0; i < NUM_DIRECTIONS; i++)
+  for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
     setHashEntry(direction_hash, element_direction_info[i].suffix,
                 i_to_a(1 << element_direction_info[i].value));
 
@@ -5276,7 +7091,7 @@ void LoadHelpAnimInfo()
     char *element_value, *action_value, *direction_value;
     int delay = atoi(list->value);
 
-    if (strcmp(list->token, "end") == 0)
+    if (strEqual(list->token, "end"))
     {
       add_helpanim_entry(HELPANIM_LIST_NEXT, -1, -1, -1, &num_list_entries);
 
@@ -5428,7 +7243,8 @@ void LoadHelpAnimInfo()
 
 #if 0
   for (i = 0; i < num_list_entries; i++)
-    printf("::: %d, %d, %d => %d\n",
+    printf("::: '%s': %d, %d, %d => %d\n",
+          EL_NAME(helpanim_info[i].element),
           helpanim_info[i].element,
           helpanim_info[i].action,
           helpanim_info[i].direction,