rnd-20090623-1-src
[rocksndiamonds.git] / src / files.c
index b8abfca89de018adfb4097c580fac30cc036cf65..239b85ec89a51863584162e5c2a7a9f840016854 100644 (file)
@@ -182,6 +182,12 @@ static struct LevelFileConfigInfo chunk_config_INFO[] =
     &li.gems_needed,                   0
   },
 
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_32_BIT(2),
+    &li.random_seed,                   0
+  },
+
   {
     -1,                                        -1,
     TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(2),
@@ -218,6 +224,12 @@ static struct LevelFileConfigInfo chunk_config_INFO[] =
     &li.dont_collide_with_bits,                ~0      /* default: always deadly */
   },
 
+  {
+    -1,                                        -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(8),
+    &li.em_explodes_by_fire,           FALSE
+  },
+
   {
     -1,                                        -1,
     TYPE_INTEGER,                      CONF_VALUE_16_BIT(5),
@@ -264,6 +276,11 @@ static struct LevelFileConfigInfo chunk_config_ELEM[] =
     TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(6),
     &li.continuous_snapping,           TRUE
   },
+  {
+    EL_PLAYER_1,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(12),
+    &li.shifted_relocation,            FALSE
+  },
 
   /* (these values are different for each player) */
   {
@@ -306,6 +323,22 @@ static struct LevelFileConfigInfo chunk_config_ELEM[] =
     TYPE_ELEMENT,                      CONF_VALUE_16_BIT(3),
     &li.explosion_element[0],          EL_PLAYER_1
   },
+  {
+    EL_PLAYER_1,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(13),
+    &li.use_initial_inventory[0],      FALSE
+  },
+  {
+    EL_PLAYER_1,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(14),
+    &li.initial_inventory_size[0],     1
+  },
+  {
+    EL_PLAYER_1,                       -1,
+    TYPE_ELEMENT_LIST,                 CONF_VALUE_BYTES(1),
+    &li.initial_inventory_content[0][0],EL_EMPTY, NULL,
+    &li.initial_inventory_size[0],     1, MAX_INITIAL_INVENTORY_SIZE
+  },
 
   {
     EL_PLAYER_2,                       -1,
@@ -347,6 +380,22 @@ static struct LevelFileConfigInfo chunk_config_ELEM[] =
     TYPE_ELEMENT,                      CONF_VALUE_16_BIT(3),
     &li.explosion_element[1],          EL_PLAYER_2
   },
+  {
+    EL_PLAYER_2,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(13),
+    &li.use_initial_inventory[1],      FALSE
+  },
+  {
+    EL_PLAYER_2,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(14),
+    &li.initial_inventory_size[1],     1
+  },
+  {
+    EL_PLAYER_2,                       -1,
+    TYPE_ELEMENT_LIST,                 CONF_VALUE_BYTES(1),
+    &li.initial_inventory_content[1][0],EL_EMPTY, NULL,
+    &li.initial_inventory_size[1],     1, MAX_INITIAL_INVENTORY_SIZE
+  },
 
   {
     EL_PLAYER_3,                       -1,
@@ -388,6 +437,22 @@ static struct LevelFileConfigInfo chunk_config_ELEM[] =
     TYPE_ELEMENT,                      CONF_VALUE_16_BIT(3),
     &li.explosion_element[2],          EL_PLAYER_3
   },
+  {
+    EL_PLAYER_3,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(13),
+    &li.use_initial_inventory[2],      FALSE
+  },
+  {
+    EL_PLAYER_3,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(14),
+    &li.initial_inventory_size[2],     1
+  },
+  {
+    EL_PLAYER_3,                       -1,
+    TYPE_ELEMENT_LIST,                 CONF_VALUE_BYTES(1),
+    &li.initial_inventory_content[2][0],EL_EMPTY, NULL,
+    &li.initial_inventory_size[2],     1, MAX_INITIAL_INVENTORY_SIZE
+  },
 
   {
     EL_PLAYER_4,                       -1,
@@ -429,6 +494,22 @@ static struct LevelFileConfigInfo chunk_config_ELEM[] =
     TYPE_ELEMENT,                      CONF_VALUE_16_BIT(3),
     &li.explosion_element[3],          EL_PLAYER_4
   },
+  {
+    EL_PLAYER_4,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(13),
+    &li.use_initial_inventory[3],      FALSE
+  },
+  {
+    EL_PLAYER_4,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(14),
+    &li.initial_inventory_size[3],     1
+  },
+  {
+    EL_PLAYER_4,                       -1,
+    TYPE_ELEMENT_LIST,                 CONF_VALUE_BYTES(1),
+    &li.initial_inventory_content[3][0],EL_EMPTY, NULL,
+    &li.initial_inventory_size[3],     1, MAX_INITIAL_INVENTORY_SIZE
+  },
 
   {
     EL_EMERALD,                                -1,
@@ -739,6 +820,17 @@ static struct LevelFileConfigInfo chunk_config_NOTE[] =
     &xx_envelope.ysize,                        MAX_ENVELOPE_YSIZE,
   },
 
+  {
+    -1,                                        -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(3),
+    &xx_envelope.autowrap,             FALSE
+  },
+  {
+    -1,                                        -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(4),
+    &xx_envelope.centered,             FALSE
+  },
+
   {
     -1,                                        -1,
     TYPE_STRING,                       CONF_VALUE_BYTES(1),
@@ -790,8 +882,8 @@ static struct LevelFileConfigInfo chunk_config_CUSX_base[] =
   {
     -1,                                        -1,
     TYPE_ELEMENT,                      CONF_VALUE_16_BIT(1),
-    &xx_ei.gfx_element,                        EL_EMPTY_SPACE,
-    &yy_ei.gfx_element
+    &xx_ei.gfx_element_initial,                EL_EMPTY_SPACE,
+    &yy_ei.gfx_element_initial
   },
 
   {
@@ -1029,7 +1121,7 @@ static struct LevelFileConfigInfo chunk_config_CUSX_change[] =
   {
     -1,                                        -1,
     TYPE_ELEMENT,                      CONF_VALUE_16_BIT(5),
-    &xx_change.trigger_element,                EL_EMPTY_SPACE
+    &xx_change.initial_trigger_element,        EL_EMPTY_SPACE
   },
 
   {
@@ -1084,6 +1176,12 @@ static struct LevelFileConfigInfo chunk_config_CUSX_change[] =
     &xx_change.action_arg,             CA_ARG_UNDEFINED
   },
 
+  {
+    -1,                                        -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(7),
+    &xx_change.action_element,         EL_EMPTY_SPACE
+  },
+
   {
     -1,                                        -1,
     TYPE_CONTENT_LIST,                 CONF_VALUE_BYTES(1),
@@ -1116,7 +1214,7 @@ static struct LevelFileConfigInfo chunk_config_GRPX[] =
   {
     -1,                                        -1,
     TYPE_ELEMENT,                      CONF_VALUE_16_BIT(1),
-    &xx_ei.gfx_element,                        EL_EMPTY_SPACE
+    &xx_ei.gfx_element_initial,                EL_EMPTY_SPACE
   },
 
   {
@@ -1604,6 +1702,9 @@ static void setLevelInfoToDefaults(struct LevelInfo *level)
 
   level->changed = FALSE;
 
+  /* set all bug compatibility flags to "false" => do not emulate this bug */
+  level->use_action_after_change_bug = FALSE;
+
   if (leveldir_current == NULL)                /* only when dumping level */
     return;
 
@@ -1677,6 +1778,11 @@ static int getFileTypeFromBasename(char *basename)
                                 strncmp(basename, "LEVELS.D", 8) == 0))
     return LEVEL_FILE_TYPE_SP;
 
+  /* check for typical filename of a Diamond Caves II level package file */
+  if (strSuffix(basename, ".dc") ||
+      strSuffix(basename, ".dc2"))
+    return LEVEL_FILE_TYPE_DC;
+
   /* ---------- try to determine file type from filesize ---------- */
 
   checked_free(filename);
@@ -1929,6 +2035,7 @@ int getMappedElement(int element)
 
     case EL_KEY_OBSOLETE:
       element = EL_KEY_1;
+      break;
 
     case EL_EM_KEY_1_FILE_OBSOLETE:
       element = EL_EM_KEY_1;
@@ -2334,7 +2441,7 @@ static int LoadLevel_CUS3(FILE *file, int chunk_size, struct LevelInfo *level)
     ReadUnusedBytesFromFile(file, 7);
 
     ei->use_gfx_element = getFile8Bit(file);
-    ei->gfx_element = getMappedElement(getFile16BitBE(file));
+    ei->gfx_element_initial = getMappedElement(getFile16BitBE(file));
 
     ei->collect_score_initial = getFile8Bit(file);
     ei->collect_count_initial = getFile8Bit(file);
@@ -2363,7 +2470,7 @@ static int LoadLevel_CUS3(FILE *file, int chunk_size, struct LevelInfo *level)
     ei->change->delay_random = getFile16BitBE(file);
     ei->change->delay_frames = getFile16BitBE(file);
 
-    ei->change->trigger_element = getMappedElement(getFile16BitBE(file));
+    ei->change->initial_trigger_element= getMappedElement(getFile16BitBE(file));
 
     ei->change->explode = getFile8Bit(file);
     ei->change->use_target_content = getFile8Bit(file);
@@ -2433,7 +2540,7 @@ static int LoadLevel_CUS4(FILE *file, int chunk_size, struct LevelInfo *level)
   ei->use_last_ce_value = getFile8Bit(file);
 
   ei->use_gfx_element = getFile8Bit(file);
-  ei->gfx_element = getMappedElement(getFile16BitBE(file));
+  ei->gfx_element_initial = getMappedElement(getFile16BitBE(file));
 
   ei->collect_score_initial = getFile8Bit(file);
   ei->collect_count_initial = getFile8Bit(file);
@@ -2496,7 +2603,7 @@ static int LoadLevel_CUS4(FILE *file, int chunk_size, struct LevelInfo *level)
     change->delay_random = getFile16BitBE(file);
     change->delay_frames = getFile16BitBE(file);
 
-    change->trigger_element = getMappedElement(getFile16BitBE(file));
+    change->initial_trigger_element = getMappedElement(getFile16BitBE(file));
 
     change->explode = getFile8Bit(file);
     change->use_target_content = getFile8Bit(file);
@@ -2566,7 +2673,7 @@ static int LoadLevel_GRP1(FILE *file, int chunk_size, struct LevelInfo *level)
   group->num_elements = getFile8Bit(file);
 
   ei->use_gfx_element = getFile8Bit(file);
-  ei->gfx_element = getMappedElement(getFile16BitBE(file));
+  ei->gfx_element_initial = getMappedElement(getFile16BitBE(file));
 
   group->choice_mode = getFile8Bit(file);
 
@@ -3910,7 +4017,7 @@ static void LoadLevelFromFileInfo_SP(struct LevelInfo *level,
   {
     level->no_valid_file = TRUE;
 
-    Error(ERR_WARN, "cannot fseek level '%s' -- using empty level", filename);
+    Error(ERR_WARN, "cannot fseek in file '%s' -- using empty level", filename);
 
     return;
   }
@@ -4133,7 +4240,7 @@ int getMappedElement_DC(int element)
       break;
 
     case 0x0e77:       /* quicksand (boulder) */
-      element = EL_QUICKSAND_FULL;
+      element = EL_QUICKSAND_FAST_FULL;
       break;
 
     case 0x0e99:       /* slow quicksand (boulder) */
@@ -4141,35 +4248,35 @@ int getMappedElement_DC(int element)
       break;
 
     case 0x0ed2:
-      element = EL_EXIT_OPEN;
+      element = EL_EM_EXIT_OPEN;
       break;
 
     case 0x0ee3:
-      element = EL_EXIT_CLOSED;
+      element = EL_EM_EXIT_CLOSED;
       break;
 
-    case 0x0eeb:       /* steel exit (open) */
-      element = EL_EXIT_OPEN;
+    case 0x0eeb:
+      element = EL_EM_STEEL_EXIT_OPEN;
       break;
 
-    case 0x0efc:       /* steel exit (closed) */
-      element = EL_EXIT_CLOSED;
+    case 0x0efc:
+      element = EL_EM_STEEL_EXIT_CLOSED;
       break;
 
     case 0x0f4f:       /* dynamite (lit 1) */
-      element = EL_DYNAMITE_ACTIVE;
+      element = EL_EM_DYNAMITE_ACTIVE;
       break;
 
     case 0x0f57:       /* dynamite (lit 2) */
-      element = EL_DYNAMITE_ACTIVE;
+      element = EL_EM_DYNAMITE_ACTIVE;
       break;
 
     case 0x0f5f:       /* dynamite (lit 3) */
-      element = EL_DYNAMITE_ACTIVE;
+      element = EL_EM_DYNAMITE_ACTIVE;
       break;
 
     case 0x0f67:       /* dynamite (lit 4) */
-      element = EL_DYNAMITE_ACTIVE;
+      element = EL_EM_DYNAMITE_ACTIVE;
       break;
 
     case 0x0f81:
@@ -4184,7 +4291,7 @@ int getMappedElement_DC(int element)
       break;
 
     case 0x0fb9:
-      element = EL_MAGIC_WALL;
+      element = EL_DC_MAGIC_WALL;
       break;
 
     case 0x0fd0:
@@ -4252,7 +4359,7 @@ int getMappedElement_DC(int element)
       break;
 
     case 0x1437:
-      element = EL_SWITCHGATE_SWITCH_UP;
+      element = EL_DC_SWITCHGATE_SWITCH_UP;
       break;
 
     case 0x143a:
@@ -4320,19 +4427,19 @@ int getMappedElement_DC(int element)
       break;
 
     case 0x14ce:       /* growing steel wall (left/right) */
-      element = EL_EXPANDABLE_WALL_HORIZONTAL;
+      element = EL_EXPANDABLE_STEELWALL_HORIZONTAL;
       break;
 
     case 0x14df:       /* growing steel wall (up/down) */
-      element = EL_EXPANDABLE_WALL_VERTICAL;
+      element = EL_EXPANDABLE_STEELWALL_VERTICAL;
       break;
 
     case 0x14e8:       /* growing steel wall (up/down/left/right) */
-      element = EL_EXPANDABLE_WALL_ANY;
+      element = EL_EXPANDABLE_STEELWALL_ANY;
       break;
 
     case 0x14e9:
-      element = EL_SHIELD_NORMAL;
+      element = EL_SHIELD_DEADLY;
       break;
 
     case 0x1501:
@@ -4348,7 +4455,7 @@ int getMappedElement_DC(int element)
       break;
 
     case 0x1578:       /* quicksand (empty) */
-      element = EL_QUICKSAND_EMPTY;
+      element = EL_QUICKSAND_FAST_EMPTY;
       break;
 
     case 0x1579:       /* slow quicksand (empty) */
@@ -4359,10 +4466,10 @@ int getMappedElement_DC(int element)
       /* EL_SAND */
 
       /* 0x1590 - 0x159f: */
-      /* EL_LANDMINE */
+      /* EL_DC_LANDMINE */
 
     case 0x15a0:
-      element = EL_DYNAMITE;
+      element = EL_EM_DYNAMITE;
       break;
 
     case 0x15a1:       /* key (red) */
@@ -4382,7 +4489,7 @@ int getMappedElement_DC(int element)
       break;
 
     case 0x15a5:       /* key (white) */
-      element = EL_KEY_WHITE;
+      element = EL_DC_KEY_WHITE;
       break;
 
     case 0x15a6:
@@ -4830,435 +4937,435 @@ int getMappedElement_DC(int element)
       break;
 
     case 0x1615:       /* (blue steel) */
-      element = EL_STEELCHAR_A;
+      element = EL_STEEL_CHAR_A;
       break;
 
     case 0x1616:       /* (blue steel) */
-      element = EL_STEELCHAR_B;
+      element = EL_STEEL_CHAR_B;
       break;
 
     case 0x1617:       /* (blue steel) */
-      element = EL_STEELCHAR_C;
+      element = EL_STEEL_CHAR_C;
       break;
 
     case 0x1618:       /* (blue steel) */
-      element = EL_STEELCHAR_D;
+      element = EL_STEEL_CHAR_D;
       break;
 
     case 0x1619:       /* (blue steel) */
-      element = EL_STEELCHAR_E;
+      element = EL_STEEL_CHAR_E;
       break;
 
     case 0x161a:       /* (blue steel) */
-      element = EL_STEELCHAR_F;
+      element = EL_STEEL_CHAR_F;
       break;
 
     case 0x161b:       /* (blue steel) */
-      element = EL_STEELCHAR_G;
+      element = EL_STEEL_CHAR_G;
       break;
 
     case 0x161c:       /* (blue steel) */
-      element = EL_STEELCHAR_H;
+      element = EL_STEEL_CHAR_H;
       break;
 
     case 0x161d:       /* (blue steel) */
-      element = EL_STEELCHAR_I;
+      element = EL_STEEL_CHAR_I;
       break;
 
     case 0x161e:       /* (blue steel) */
-      element = EL_STEELCHAR_J;
+      element = EL_STEEL_CHAR_J;
       break;
 
     case 0x161f:       /* (blue steel) */
-      element = EL_STEELCHAR_K;
+      element = EL_STEEL_CHAR_K;
       break;
 
     case 0x1620:       /* (blue steel) */
-      element = EL_STEELCHAR_L;
+      element = EL_STEEL_CHAR_L;
       break;
 
     case 0x1621:       /* (blue steel) */
-      element = EL_STEELCHAR_M;
+      element = EL_STEEL_CHAR_M;
       break;
 
     case 0x1622:       /* (blue steel) */
-      element = EL_STEELCHAR_N;
+      element = EL_STEEL_CHAR_N;
       break;
 
     case 0x1623:       /* (blue steel) */
-      element = EL_STEELCHAR_O;
+      element = EL_STEEL_CHAR_O;
       break;
 
     case 0x1624:       /* (blue steel) */
-      element = EL_STEELCHAR_P;
+      element = EL_STEEL_CHAR_P;
       break;
 
     case 0x1625:       /* (blue steel) */
-      element = EL_STEELCHAR_Q;
+      element = EL_STEEL_CHAR_Q;
       break;
 
     case 0x1626:       /* (blue steel) */
-      element = EL_STEELCHAR_R;
+      element = EL_STEEL_CHAR_R;
       break;
 
     case 0x1627:       /* (blue steel) */
-      element = EL_STEELCHAR_S;
+      element = EL_STEEL_CHAR_S;
       break;
 
     case 0x1628:       /* (blue steel) */
-      element = EL_STEELCHAR_T;
+      element = EL_STEEL_CHAR_T;
       break;
 
     case 0x1629:       /* (blue steel) */
-      element = EL_STEELCHAR_U;
+      element = EL_STEEL_CHAR_U;
       break;
 
     case 0x162a:       /* (blue steel) */
-      element = EL_STEELCHAR_V;
+      element = EL_STEEL_CHAR_V;
       break;
 
     case 0x162b:       /* (blue steel) */
-      element = EL_STEELCHAR_W;
+      element = EL_STEEL_CHAR_W;
       break;
 
     case 0x162c:       /* (blue steel) */
-      element = EL_STEELCHAR_X;
+      element = EL_STEEL_CHAR_X;
       break;
 
     case 0x162d:       /* (blue steel) */
-      element = EL_STEELCHAR_Y;
+      element = EL_STEEL_CHAR_Y;
       break;
 
     case 0x162e:       /* (blue steel) */
-      element = EL_STEELCHAR_Z;
+      element = EL_STEEL_CHAR_Z;
       break;
 
     case 0x162f:       /* (blue steel) */
-      element = EL_STEELCHAR_AUMLAUT;
+      element = EL_STEEL_CHAR_AUMLAUT;
       break;
 
     case 0x1630:       /* (blue steel) */
-      element = EL_STEELCHAR_OUMLAUT;
+      element = EL_STEEL_CHAR_OUMLAUT;
       break;
 
     case 0x1631:       /* (blue steel) */
-      element = EL_STEELCHAR_UUMLAUT;
+      element = EL_STEEL_CHAR_UUMLAUT;
       break;
 
     case 0x1632:       /* (blue steel) */
-      element = EL_STEELCHAR_0;
+      element = EL_STEEL_CHAR_0;
       break;
 
     case 0x1633:       /* (blue steel) */
-      element = EL_STEELCHAR_1;
+      element = EL_STEEL_CHAR_1;
       break;
 
     case 0x1634:       /* (blue steel) */
-      element = EL_STEELCHAR_2;
+      element = EL_STEEL_CHAR_2;
       break;
 
     case 0x1635:       /* (blue steel) */
-      element = EL_STEELCHAR_3;
+      element = EL_STEEL_CHAR_3;
       break;
 
     case 0x1636:       /* (blue steel) */
-      element = EL_STEELCHAR_4;
+      element = EL_STEEL_CHAR_4;
       break;
 
     case 0x1637:       /* (blue steel) */
-      element = EL_STEELCHAR_5;
+      element = EL_STEEL_CHAR_5;
       break;
 
     case 0x1638:       /* (blue steel) */
-      element = EL_STEELCHAR_6;
+      element = EL_STEEL_CHAR_6;
       break;
 
     case 0x1639:       /* (blue steel) */
-      element = EL_STEELCHAR_7;
+      element = EL_STEEL_CHAR_7;
       break;
 
     case 0x163a:       /* (blue steel) */
-      element = EL_STEELCHAR_8;
+      element = EL_STEEL_CHAR_8;
       break;
 
     case 0x163b:       /* (blue steel) */
-      element = EL_STEELCHAR_9;
+      element = EL_STEEL_CHAR_9;
       break;
 
     case 0x163c:       /* (blue steel) */
-      element = EL_STEELCHAR_PERIOD;
+      element = EL_STEEL_CHAR_PERIOD;
       break;
 
     case 0x163d:       /* (blue steel) */
-      element = EL_STEELCHAR_EXCLAM;
+      element = EL_STEEL_CHAR_EXCLAM;
       break;
 
     case 0x163e:       /* (blue steel) */
-      element = EL_STEELCHAR_COLON;
+      element = EL_STEEL_CHAR_COLON;
       break;
 
     case 0x163f:       /* (blue steel) */
-      element = EL_STEELCHAR_LESS;
+      element = EL_STEEL_CHAR_LESS;
       break;
 
     case 0x1640:       /* (blue steel) */
-      element = EL_STEELCHAR_GREATER;
+      element = EL_STEEL_CHAR_GREATER;
       break;
 
     case 0x1641:       /* (blue steel) */
-      element = EL_STEELCHAR_QUESTION;
+      element = EL_STEEL_CHAR_QUESTION;
       break;
 
     case 0x1642:       /* (blue steel) */
-      element = EL_STEELCHAR_COPYRIGHT;
+      element = EL_STEEL_CHAR_COPYRIGHT;
       break;
 
     case 0x1643:       /* (blue steel) */
-      element = EL_STEELCHAR_UP;
+      element = EL_STEEL_CHAR_UP;
       break;
 
     case 0x1644:       /* (blue steel) */
-      element = EL_STEELCHAR_DOWN;
+      element = EL_STEEL_CHAR_DOWN;
       break;
 
     case 0x1645:       /* (blue steel) */
-      element = EL_STEELCHAR_BUTTON;
+      element = EL_STEEL_CHAR_BUTTON;
       break;
 
     case 0x1646:       /* (blue steel) */
-      element = EL_STEELCHAR_PLUS;
+      element = EL_STEEL_CHAR_PLUS;
       break;
 
     case 0x1647:       /* (blue steel) */
-      element = EL_STEELCHAR_MINUS;
+      element = EL_STEEL_CHAR_MINUS;
       break;
 
     case 0x1648:       /* (blue steel) */
-      element = EL_STEELCHAR_APOSTROPHE;
+      element = EL_STEEL_CHAR_APOSTROPHE;
       break;
 
     case 0x1649:       /* (blue steel) */
-      element = EL_STEELCHAR_PARENLEFT;
+      element = EL_STEEL_CHAR_PARENLEFT;
       break;
 
     case 0x164a:       /* (blue steel) */
-      element = EL_STEELCHAR_PARENRIGHT;
+      element = EL_STEEL_CHAR_PARENRIGHT;
       break;
 
     case 0x164b:       /* (green steel) */
-      element = EL_STEELCHAR_A;
+      element = EL_STEEL_CHAR_A;
       break;
 
     case 0x164c:       /* (green steel) */
-      element = EL_STEELCHAR_B;
+      element = EL_STEEL_CHAR_B;
       break;
 
     case 0x164d:       /* (green steel) */
-      element = EL_STEELCHAR_C;
+      element = EL_STEEL_CHAR_C;
       break;
 
     case 0x164e:       /* (green steel) */
-      element = EL_STEELCHAR_D;
+      element = EL_STEEL_CHAR_D;
       break;
 
     case 0x164f:       /* (green steel) */
-      element = EL_STEELCHAR_E;
+      element = EL_STEEL_CHAR_E;
       break;
 
     case 0x1650:       /* (green steel) */
-      element = EL_STEELCHAR_F;
+      element = EL_STEEL_CHAR_F;
       break;
 
     case 0x1651:       /* (green steel) */
-      element = EL_STEELCHAR_G;
+      element = EL_STEEL_CHAR_G;
       break;
 
     case 0x1652:       /* (green steel) */
-      element = EL_STEELCHAR_H;
+      element = EL_STEEL_CHAR_H;
       break;
 
     case 0x1653:       /* (green steel) */
-      element = EL_STEELCHAR_I;
+      element = EL_STEEL_CHAR_I;
       break;
 
     case 0x1654:       /* (green steel) */
-      element = EL_STEELCHAR_J;
+      element = EL_STEEL_CHAR_J;
       break;
 
     case 0x1655:       /* (green steel) */
-      element = EL_STEELCHAR_K;
+      element = EL_STEEL_CHAR_K;
       break;
 
     case 0x1656:       /* (green steel) */
-      element = EL_STEELCHAR_L;
+      element = EL_STEEL_CHAR_L;
       break;
 
     case 0x1657:       /* (green steel) */
-      element = EL_STEELCHAR_M;
+      element = EL_STEEL_CHAR_M;
       break;
 
     case 0x1658:       /* (green steel) */
-      element = EL_STEELCHAR_N;
+      element = EL_STEEL_CHAR_N;
       break;
 
     case 0x1659:       /* (green steel) */
-      element = EL_STEELCHAR_O;
+      element = EL_STEEL_CHAR_O;
       break;
 
     case 0x165a:       /* (green steel) */
-      element = EL_STEELCHAR_P;
+      element = EL_STEEL_CHAR_P;
       break;
 
     case 0x165b:       /* (green steel) */
-      element = EL_STEELCHAR_Q;
+      element = EL_STEEL_CHAR_Q;
       break;
 
     case 0x165c:       /* (green steel) */
-      element = EL_STEELCHAR_R;
+      element = EL_STEEL_CHAR_R;
       break;
 
     case 0x165d:       /* (green steel) */
-      element = EL_STEELCHAR_S;
+      element = EL_STEEL_CHAR_S;
       break;
 
     case 0x165e:       /* (green steel) */
-      element = EL_STEELCHAR_T;
+      element = EL_STEEL_CHAR_T;
       break;
 
     case 0x165f:       /* (green steel) */
-      element = EL_STEELCHAR_U;
+      element = EL_STEEL_CHAR_U;
       break;
 
     case 0x1660:       /* (green steel) */
-      element = EL_STEELCHAR_V;
+      element = EL_STEEL_CHAR_V;
       break;
 
     case 0x1661:       /* (green steel) */
-      element = EL_STEELCHAR_W;
+      element = EL_STEEL_CHAR_W;
       break;
 
     case 0x1662:       /* (green steel) */
-      element = EL_STEELCHAR_X;
+      element = EL_STEEL_CHAR_X;
       break;
 
     case 0x1663:       /* (green steel) */
-      element = EL_STEELCHAR_Y;
+      element = EL_STEEL_CHAR_Y;
       break;
 
     case 0x1664:       /* (green steel) */
-      element = EL_STEELCHAR_Z;
+      element = EL_STEEL_CHAR_Z;
       break;
 
     case 0x1665:       /* (green steel) */
-      element = EL_STEELCHAR_AUMLAUT;
+      element = EL_STEEL_CHAR_AUMLAUT;
       break;
 
     case 0x1666:       /* (green steel) */
-      element = EL_STEELCHAR_OUMLAUT;
+      element = EL_STEEL_CHAR_OUMLAUT;
       break;
 
     case 0x1667:       /* (green steel) */
-      element = EL_STEELCHAR_UUMLAUT;
+      element = EL_STEEL_CHAR_UUMLAUT;
       break;
 
     case 0x1668:       /* (green steel) */
-      element = EL_STEELCHAR_0;
+      element = EL_STEEL_CHAR_0;
       break;
 
     case 0x1669:       /* (green steel) */
-      element = EL_STEELCHAR_1;
+      element = EL_STEEL_CHAR_1;
       break;
 
     case 0x166a:       /* (green steel) */
-      element = EL_STEELCHAR_2;
+      element = EL_STEEL_CHAR_2;
       break;
 
     case 0x166b:       /* (green steel) */
-      element = EL_STEELCHAR_3;
+      element = EL_STEEL_CHAR_3;
       break;
 
     case 0x166c:       /* (green steel) */
-      element = EL_STEELCHAR_4;
+      element = EL_STEEL_CHAR_4;
       break;
 
     case 0x166d:       /* (green steel) */
-      element = EL_STEELCHAR_5;
+      element = EL_STEEL_CHAR_5;
       break;
 
     case 0x166e:       /* (green steel) */
-      element = EL_STEELCHAR_6;
+      element = EL_STEEL_CHAR_6;
       break;
 
     case 0x166f:       /* (green steel) */
-      element = EL_STEELCHAR_7;
+      element = EL_STEEL_CHAR_7;
       break;
 
     case 0x1670:       /* (green steel) */
-      element = EL_STEELCHAR_8;
+      element = EL_STEEL_CHAR_8;
       break;
 
     case 0x1671:       /* (green steel) */
-      element = EL_STEELCHAR_9;
+      element = EL_STEEL_CHAR_9;
       break;
 
     case 0x1672:       /* (green steel) */
-      element = EL_STEELCHAR_PERIOD;
+      element = EL_STEEL_CHAR_PERIOD;
       break;
 
     case 0x1673:       /* (green steel) */
-      element = EL_STEELCHAR_EXCLAM;
+      element = EL_STEEL_CHAR_EXCLAM;
       break;
 
     case 0x1674:       /* (green steel) */
-      element = EL_STEELCHAR_COLON;
+      element = EL_STEEL_CHAR_COLON;
       break;
 
     case 0x1675:       /* (green steel) */
-      element = EL_STEELCHAR_LESS;
+      element = EL_STEEL_CHAR_LESS;
       break;
 
     case 0x1676:       /* (green steel) */
-      element = EL_STEELCHAR_GREATER;
+      element = EL_STEEL_CHAR_GREATER;
       break;
 
     case 0x1677:       /* (green steel) */
-      element = EL_STEELCHAR_QUESTION;
+      element = EL_STEEL_CHAR_QUESTION;
       break;
 
     case 0x1678:       /* (green steel) */
-      element = EL_STEELCHAR_COPYRIGHT;
+      element = EL_STEEL_CHAR_COPYRIGHT;
       break;
 
     case 0x1679:       /* (green steel) */
-      element = EL_STEELCHAR_UP;
+      element = EL_STEEL_CHAR_UP;
       break;
 
     case 0x167a:       /* (green steel) */
-      element = EL_STEELCHAR_DOWN;
+      element = EL_STEEL_CHAR_DOWN;
       break;
 
     case 0x167b:       /* (green steel) */
-      element = EL_STEELCHAR_BUTTON;
+      element = EL_STEEL_CHAR_BUTTON;
       break;
 
     case 0x167c:       /* (green steel) */
-      element = EL_STEELCHAR_PLUS;
+      element = EL_STEEL_CHAR_PLUS;
       break;
 
     case 0x167d:       /* (green steel) */
-      element = EL_STEELCHAR_MINUS;
+      element = EL_STEEL_CHAR_MINUS;
       break;
 
     case 0x167e:       /* (green steel) */
-      element = EL_STEELCHAR_APOSTROPHE;
+      element = EL_STEEL_CHAR_APOSTROPHE;
       break;
 
     case 0x167f:       /* (green steel) */
-      element = EL_STEELCHAR_PARENLEFT;
+      element = EL_STEEL_CHAR_PARENLEFT;
       break;
 
     case 0x1680:       /* (green steel) */
-      element = EL_STEELCHAR_PARENRIGHT;
+      element = EL_STEEL_CHAR_PARENRIGHT;
       break;
 
     case 0x1681:       /* gate (red) */
@@ -5294,15 +5401,15 @@ int getMappedElement_DC(int element)
       break;
 
     case 0x1689:       /* gate (white) */
-      element = EL_DOOR_WHITE;
+      element = EL_DC_GATE_WHITE;
       break;
 
     case 0x168a:       /* secret gate (white) */
-      element = EL_DOOR_WHITE_GRAY;
+      element = EL_DC_GATE_WHITE_GRAY;
       break;
 
     case 0x168b:       /* secret gate (no key) */
-      element = EL_UNKNOWN;
+      element = EL_DC_GATE_FAKE_GRAY;
       break;
 
     case 0x168c:
@@ -5310,7 +5417,7 @@ int getMappedElement_DC(int element)
       break;
 
     case 0x168d:
-      element = EL_TIMEGATE_SWITCH;
+      element = EL_DC_TIMEGATE_SWITCH;
       break;
 
     case 0x168e:
@@ -5346,87 +5453,87 @@ int getMappedElement_DC(int element)
       break;
 
     case 0x1696:       /* steel wall (left) */
-      element = EL_STEELWALL;
+      element = EL_DC_STEELWALL_1_LEFT;
       break;
 
     case 0x1697:       /* steel wall (bottom) */
-      element = EL_STEELWALL;
+      element = EL_DC_STEELWALL_1_BOTTOM;
       break;
 
     case 0x1698:       /* steel wall (right) */
-      element = EL_STEELWALL;
+      element = EL_DC_STEELWALL_1_RIGHT;
       break;
 
     case 0x1699:       /* steel wall (top) */
-      element = EL_STEELWALL;
+      element = EL_DC_STEELWALL_1_TOP;
       break;
 
     case 0x169a:       /* steel wall (left/bottom) */
-      element = EL_STEELWALL;
+      element = EL_DC_STEELWALL_1_BOTTOMLEFT;
       break;
 
     case 0x169b:       /* steel wall (right/bottom) */
-      element = EL_STEELWALL;
+      element = EL_DC_STEELWALL_1_BOTTOMRIGHT;
       break;
 
     case 0x169c:       /* steel wall (right/top) */
-      element = EL_STEELWALL;
+      element = EL_DC_STEELWALL_1_TOPRIGHT;
       break;
 
     case 0x169d:       /* steel wall (left/top) */
-      element = EL_STEELWALL;
+      element = EL_DC_STEELWALL_1_TOPLEFT;
       break;
 
     case 0x169e:       /* steel wall (right/bottom small) */
-      element = EL_STEELWALL;
+      element = EL_DC_STEELWALL_1_BOTTOMRIGHT_2;
       break;
 
     case 0x169f:       /* steel wall (left/bottom small) */
-      element = EL_STEELWALL;
+      element = EL_DC_STEELWALL_1_BOTTOMLEFT_2;
       break;
 
     case 0x16a0:       /* steel wall (right/top small) */
-      element = EL_STEELWALL;
+      element = EL_DC_STEELWALL_1_TOPRIGHT_2;
       break;
 
     case 0x16a1:       /* steel wall (left/top small) */
-      element = EL_STEELWALL;
+      element = EL_DC_STEELWALL_1_TOPLEFT_2;
       break;
 
     case 0x16a2:       /* steel wall (left/right) */
-      element = EL_STEELWALL;
+      element = EL_DC_STEELWALL_1_VERTICAL;
       break;
 
     case 0x16a3:       /* steel wall (top/bottom) */
-      element = EL_STEELWALL;
+      element = EL_DC_STEELWALL_1_HORIZONTAL;
       break;
 
     case 0x16a4:       /* steel wall 2 (left end) */
-      element = EL_STEELWALL;
+      element = EL_DC_STEELWALL_2_LEFT;
       break;
 
     case 0x16a5:       /* steel wall 2 (right end) */
-      element = EL_STEELWALL;
+      element = EL_DC_STEELWALL_2_RIGHT;
       break;
 
     case 0x16a6:       /* steel wall 2 (top end) */
-      element = EL_STEELWALL;
+      element = EL_DC_STEELWALL_2_TOP;
       break;
 
     case 0x16a7:       /* steel wall 2 (bottom end) */
-      element = EL_STEELWALL;
+      element = EL_DC_STEELWALL_2_BOTTOM;
       break;
 
     case 0x16a8:       /* steel wall 2 (left/right) */
-      element = EL_STEELWALL;
+      element = EL_DC_STEELWALL_2_HORIZONTAL;
       break;
 
     case 0x16a9:       /* steel wall 2 (up/down) */
-      element = EL_STEELWALL;
+      element = EL_DC_STEELWALL_2_VERTICAL;
       break;
 
     case 0x16aa:       /* steel wall 2 (mid) */
-      element = EL_STEELWALL;
+      element = EL_DC_STEELWALL_2_MIDDLE;
       break;
 
     case 0x16ab:
@@ -5450,7 +5557,7 @@ int getMappedElement_DC(int element)
       break;
 
     case 0x16b0:
-      element = EL_SIGN_ONEWAY;
+      element = EL_SIGN_NO_ENTRY;
       break;
 
     case 0x16b1:
@@ -5458,19 +5565,19 @@ int getMappedElement_DC(int element)
       break;
 
     case 0x16b2:
-      element = EL_SIGN_TRIANGLE;
+      element = EL_SIGN_GIVE_WAY;
       break;
 
     case 0x16b3:
-      element = EL_SIGN_ROUND;
+      element = EL_SIGN_ENTRY_FORBIDDEN;
       break;
 
     case 0x16b4:
-      element = EL_SIGN_EXIT;
+      element = EL_SIGN_EMERGENCY_EXIT;
       break;
 
     case 0x16b5:
-      element = EL_SIGN_YINYANG;
+      element = EL_SIGN_YIN_YANG;
       break;
 
     case 0x16b6:
@@ -5516,7 +5623,7 @@ int getMappedElement_DC(int element)
       else if (element >= 0x157c && element <= 0x158b)
        element = EL_SAND;
       else if (element >= 0x1590 && element <= 0x159f)
-       element = EL_LANDMINE;
+       element = EL_DC_LANDMINE;
       else if (element >= 0x16bc && element <= 0x16cb)
        element = EL_INVISIBLE_SAND;
       else
@@ -5530,14 +5637,11 @@ int getMappedElement_DC(int element)
   return getMappedElement(element);
 }
 
-static void LoadLevelFromFileInfo_DC(struct LevelInfo *level,
-                                    struct LevelFileInfo *level_file_info)
+#if 1
+
+static void LoadLevelFromFileStream_DC(FILE *file, struct LevelInfo *level,
+                                      int nr)
 {
-  char *filename = level_file_info->filename;
-  FILE *file;
-#if 0
-  int nr = level_file_info->nr - leveldir_current->first_level;
-#endif
   byte header[DC_LEVEL_HEADER_SIZE];
   int envelope_size;
   int envelope_header_pos = 62;
@@ -5552,36 +5656,32 @@ static void LoadLevelFromFileInfo_DC(struct LevelInfo *level,
   int num_yamyam_contents;
   int i, x, y;
 
-  if (!(file = fopen(filename, MODE_READ)))
-  {
-    level->no_valid_file = TRUE;
+  getDecodedWord_DC(0, TRUE);          /* initialize DC2 decoding engine */
 
-    Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename);
+  for (i = 0; i < DC_LEVEL_HEADER_SIZE / 2; i++)
+  {
+    unsigned short header_word = getDecodedWord_DC(getFile16BitBE(file), FALSE);
 
-    return;
+    header[i * 2 + 0] = header_word >> 8;
+    header[i * 2 + 1] = header_word & 0xff;
   }
 
-#if 0
-  /* position file stream to the requested level inside the level package */
-  if (fseek(file, nr * SP_LEVEL_SIZE, SEEK_SET) != 0)
+  /* read some values from level header to check level decoding integrity */
+  fieldx = header[6] | (header[7] << 8);
+  fieldy = header[8] | (header[9] << 8);
+  num_yamyam_contents = header[60] | (header[61] << 8);
+
+  /* do some simple sanity checks to ensure that level was correctly decoded */
+  if (fieldx < 1 || fieldx > 256 ||
+      fieldy < 1 || fieldy > 256 ||
+      num_yamyam_contents < 1 || num_yamyam_contents > 8)
   {
     level->no_valid_file = TRUE;
 
-    Error(ERR_WARN, "cannot fseek level '%s' -- using empty level", filename);
+    Error(ERR_WARN, "cannot decode level from stream -- using empty level");
 
     return;
   }
-#endif
-
-  getDecodedWord_DC(0, TRUE);          /* initialize DC2 decoding engine */
-
-  for (i = 0; i < DC_LEVEL_HEADER_SIZE / 2; i++)
-  {
-    unsigned short header_word = getDecodedWord_DC(getFile16BitBE(file), FALSE);
-
-    header[i * 2 + 0] = header_word >> 8;
-    header[i * 2 + 1] = header_word & 0xff;
-  }
 
   /* maximum envelope header size is 31 bytes */
   envelope_header_len  = header[envelope_header_pos];
@@ -5615,6 +5715,11 @@ static void LoadLevelFromFileInfo_DC(struct LevelInfo *level,
 
   level->envelope[0].text[envelope_size] = '\0';
 
+  level->envelope[0].xsize = MAX_ENVELOPE_XSIZE;
+  level->envelope[0].ysize = 10;
+  level->envelope[0].autowrap = TRUE;
+  level->envelope[0].centered = TRUE;
+
   for (i = 0; i < level_name_len; i++)
     level->name[i] = header[level_name_pos + 1 + i];
   level->name[level_name_len] = '\0';
@@ -5694,117 +5799,454 @@ static void LoadLevelFromFileInfo_DC(struct LevelInfo *level,
   level->extra_time            = header[56] | (header[57] << 8);
   level->shield_normal_time    = header[58] | (header[59] << 8);
 
-  fclose(file);
-}
-
+  /* Diamond Caves has the same (strange) behaviour as Emerald Mine that gems
+     can slip down from flat walls, like normal walls and steel walls */
+  level->em_slippery_gems = TRUE;
 
-/* ------------------------------------------------------------------------- */
-/* functions for loading generic level                                       */
-/* ------------------------------------------------------------------------- */
+#if 0
+  /* Diamond Caves II levels are always surrounded by indestructible wall, but
+     not necessarily in a rectangular way -- fill with invisible steel wall */
 
-void LoadLevelFromFileInfo(struct LevelInfo *level,
-                          struct LevelFileInfo *level_file_info)
-{
-  /* always start with reliable default values */
-  setLevelInfoToDefaults(level);
+  /* !!! not always true !!! keep level and set BorderElement instead !!! */
 
-  switch (level_file_info->type)
+  for (y = 0; y < level->fieldy; y++) for (x = 0; x < level->fieldx; x++)
   {
-    case LEVEL_FILE_TYPE_RND:
-      LoadLevelFromFileInfo_RND(level, level_file_info);
-      break;
+#if 1
+    if ((x == 0 || x == level->fieldx - 1 ||
+        y == 0 || y == level->fieldy - 1) &&
+       level->field[x][y] == EL_EMPTY)
+      level->field[x][y] = EL_INVISIBLE_STEELWALL;
+#else
+    if ((x == 0 || x == level->fieldx - 1 ||
+        y == 0 || y == level->fieldy - 1) &&
+       level->field[x][y] == EL_EMPTY)
+      FloodFillLevel(x, y, EL_INVISIBLE_STEELWALL,
+                    level->field, level->fieldx, level->fieldy);
+#endif
+  }
+#endif
+}
 
-    case LEVEL_FILE_TYPE_EM:
-      LoadLevelFromFileInfo_EM(level, level_file_info);
-      level->game_engine_type = GAME_ENGINE_TYPE_EM;
-      break;
+static void LoadLevelFromFileInfo_DC(struct LevelInfo *level,
+                                    struct LevelFileInfo *level_file_info)
+{
+  char *filename = level_file_info->filename;
+  FILE *file;
+  int num_magic_bytes = 8;
+  char magic_bytes[num_magic_bytes + 1];
+  int num_levels_to_skip = level_file_info->nr - leveldir_current->first_level;
 
-    case LEVEL_FILE_TYPE_SP:
-      LoadLevelFromFileInfo_SP(level, level_file_info);
-      break;
+  if (!(file = fopen(filename, MODE_READ)))
+  {
+    level->no_valid_file = TRUE;
 
-    case LEVEL_FILE_TYPE_DC:
-      LoadLevelFromFileInfo_DC(level, level_file_info);
-      break;
+    Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename);
 
-    default:
-      LoadLevelFromFileInfo_RND(level, level_file_info);
-      break;
+    return;
   }
 
-  /* if level file is invalid, restore level structure to default values */
-  if (level->no_valid_file)
-    setLevelInfoToDefaults(level);
-
-  if (level->game_engine_type == GAME_ENGINE_TYPE_UNKNOWN)
-    level->game_engine_type = GAME_ENGINE_TYPE_RND;
+  // fseek(file, 0x0000, SEEK_SET);
 
-  if (level_file_info->type != LEVEL_FILE_TYPE_RND)
-    CopyNativeLevel_Native_to_RND(level);
-}
+  if (level_file_info->packed)
+  {
+    /* read "magic bytes" from start of file */
+    fgets(magic_bytes, num_magic_bytes + 1, file);
 
-void LoadLevelFromFilename(struct LevelInfo *level, char *filename)
-{
-  static struct LevelFileInfo level_file_info;
+    /* check "magic bytes" for correct file format */
+    if (!strPrefix(magic_bytes, "DC2"))
+    {
+      level->no_valid_file = TRUE;
 
-  /* always start with reliable default values */
-  setFileInfoToDefaults(&level_file_info);
+      Error(ERR_WARN, "unknown DC level file '%s' -- using empty level",
+           filename);
 
-  level_file_info.nr = 0;                      /* unknown level number */
-  level_file_info.type = LEVEL_FILE_TYPE_RND;  /* no others supported yet */
-  level_file_info.filename = filename;
+      return;
+    }
 
-  LoadLevelFromFileInfo(level, &level_file_info);
-}
+    if (strPrefix(magic_bytes, "DC2Win95") ||
+       strPrefix(magic_bytes, "DC2Win98"))
+    {
+      int position_first_level = 0x00fa;
+      int extra_bytes = 4;
+      int skip_bytes;
 
-static void LoadLevel_InitVersion(struct LevelInfo *level, char *filename)
-{
-  int i, j;
+      /* advance file stream to first level inside the level package */
+      skip_bytes = position_first_level - num_magic_bytes - extra_bytes;
 
-  if (leveldir_current == NULL)                /* only when dumping level */
-    return;
+      /* each block of level data is followed by block of non-level data */
+      num_levels_to_skip *= 2;
 
-  /* 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;
-  }
+      /* at least skip header bytes, therefore use ">= 0" instead of "> 0" */
+      while (num_levels_to_skip >= 0)
+      {
+       /* advance file stream to next level inside the level package */
+       if (fseek(file, skip_bytes, SEEK_CUR) != 0)
+       {
+         level->no_valid_file = TRUE;
 
-#if 0
-  leveldir_current->latest_engine = TRUE;      /* !!! TEST ONLY !!! */
-#endif
+         Error(ERR_WARN, "cannot fseek in file '%s' -- using empty level",
+               filename);
 
-  if (leveldir_current->latest_engine)
-  {
-    /* ---------- use latest game engine ----------------------------------- */
+         return;
+       }
 
-    /* For all levels which are forced to use the latest game engine version
-       (normally all but user contributed, private and undefined levels), set
-       the game engine version to the actual version; this allows for actual
-       corrections in the game engine to take effect for existing, converted
-       levels (from "classic" or other existing games) to make the emulation
-       of the corresponding game more accurate, while (hopefully) not breaking
-       existing levels created from other players. */
+       /* skip apparently unused extra bytes following each level */
+       ReadUnusedBytesFromFile(file, extra_bytes);
 
-    level->game_version = GAME_VERSION_ACTUAL;
+       /* read size of next level in level package */
+       skip_bytes = getFile32BitLE(file);
 
-    /* Set special EM style gems behaviour: EM style gems slip down from
-       normal, steel and growing wall. As this is a more fundamental change,
-       it seems better to set the default behaviour to "off" (as it is more
-       natural) and make it configurable in the level editor (as a property
-       of gem style elements). Already existing converted levels (neither
-       private nor contributed levels) are changed to the new behaviour. */
+       num_levels_to_skip--;
+      }
+    }
+    else
+    {
+      level->no_valid_file = TRUE;
 
-    if (level->file_version < FILE_VERSION_2_0)
-      level->em_slippery_gems = TRUE;
+      Error(ERR_WARN, "unknown DC2 level file '%s' -- using empty level",
+           filename);
 
-    return;
+      return;
+    }
   }
 
-  /* ---------- use game engine the level was created with ----------------- */
+  LoadLevelFromFileStream_DC(file, level, level_file_info->nr);
 
-  /* For all levels which are not forced to use the latest game engine
+  fclose(file);
+}
+
+#else
+
+static void LoadLevelFromFileInfo_DC(struct LevelInfo *level,
+                                    struct LevelFileInfo *level_file_info)
+{
+  char *filename = level_file_info->filename;
+  FILE *file;
+#if 0
+  int nr = level_file_info->nr - leveldir_current->first_level;
+#endif
+  byte header[DC_LEVEL_HEADER_SIZE];
+  int envelope_size;
+  int envelope_header_pos = 62;
+  int envelope_content_pos = 94;
+  int level_name_pos = 251;
+  int level_author_pos = 292;
+  int envelope_header_len;
+  int envelope_content_len;
+  int level_name_len;
+  int level_author_len;
+  int fieldx, fieldy;
+  int num_yamyam_contents;
+  int i, x, y;
+
+  if (!(file = fopen(filename, MODE_READ)))
+  {
+    level->no_valid_file = TRUE;
+
+    Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename);
+
+    return;
+  }
+
+#if 0
+  /* position file stream to the requested level inside the level package */
+  if (fseek(file, nr * SP_LEVEL_SIZE, SEEK_SET) != 0)
+  {
+    level->no_valid_file = TRUE;
+
+    Error(ERR_WARN, "cannot fseek in file '%s' -- using empty level", filename);
+
+    return;
+  }
+#endif
+
+  getDecodedWord_DC(0, TRUE);          /* initialize DC2 decoding engine */
+
+  for (i = 0; i < DC_LEVEL_HEADER_SIZE / 2; i++)
+  {
+    unsigned short header_word = getDecodedWord_DC(getFile16BitBE(file), FALSE);
+
+    header[i * 2 + 0] = header_word >> 8;
+    header[i * 2 + 1] = header_word & 0xff;
+  }
+
+  /* read some values from level header to check level decoding integrity */
+  fieldx = header[6] | (header[7] << 8);
+  fieldy = header[8] | (header[9] << 8);
+  num_yamyam_contents = header[60] | (header[61] << 8);
+
+  /* do some simple sanity checks to ensure that level was correctly decoded */
+  if (fieldx < 1 || fieldx > 256 ||
+      fieldy < 1 || fieldy > 256 ||
+      num_yamyam_contents < 1 || num_yamyam_contents > 8)
+  {
+    level->no_valid_file = TRUE;
+
+    Error(ERR_WARN, "cannot read level from file '%s' -- using empty level",
+         filename);
+
+    return;
+  }
+
+  /* maximum envelope header size is 31 bytes */
+  envelope_header_len  = header[envelope_header_pos];
+  /* maximum envelope content size is 110 (156?) bytes */
+  envelope_content_len = header[envelope_content_pos];
+
+  /* maximum level title size is 40 bytes */
+  level_name_len       = MIN(header[level_name_pos],   MAX_LEVEL_NAME_LEN);
+  /* maximum level author size is 30 (51?) bytes */
+  level_author_len     = MIN(header[level_author_pos], MAX_LEVEL_AUTHOR_LEN);
+
+  envelope_size = 0;
+
+  for (i = 0; i < envelope_header_len; i++)
+    if (envelope_size < MAX_ENVELOPE_TEXT_LEN)
+      level->envelope[0].text[envelope_size++] =
+       header[envelope_header_pos + 1 + i];
+
+  if (envelope_header_len > 0 && envelope_content_len > 0)
+  {
+    if (envelope_size < MAX_ENVELOPE_TEXT_LEN)
+      level->envelope[0].text[envelope_size++] = '\n';
+    if (envelope_size < MAX_ENVELOPE_TEXT_LEN)
+      level->envelope[0].text[envelope_size++] = '\n';
+  }
+
+  for (i = 0; i < envelope_content_len; i++)
+    if (envelope_size < MAX_ENVELOPE_TEXT_LEN)
+      level->envelope[0].text[envelope_size++] =
+       header[envelope_content_pos + 1 + i];
+
+  level->envelope[0].text[envelope_size] = '\0';
+
+  level->envelope[0].xsize = MAX_ENVELOPE_XSIZE;
+  level->envelope[0].ysize = 10;
+  level->envelope[0].autowrap = TRUE;
+  level->envelope[0].centered = TRUE;
+
+  for (i = 0; i < level_name_len; i++)
+    level->name[i] = header[level_name_pos + 1 + i];
+  level->name[level_name_len] = '\0';
+
+  for (i = 0; i < level_author_len; i++)
+    level->author[i] = header[level_author_pos + 1 + i];
+  level->author[level_author_len] = '\0';
+
+  num_yamyam_contents = header[60] | (header[61] << 8);
+  level->num_yamyam_contents =
+    MIN(MAX(MIN_ELEMENT_CONTENTS, num_yamyam_contents), MAX_ELEMENT_CONTENTS);
+
+  for (i = 0; i < num_yamyam_contents; i++)
+  {
+    for (y = 0; y < 3; y++) for (x = 0; x < 3; x++)
+    {
+      unsigned short word = getDecodedWord_DC(getFile16BitBE(file), FALSE);
+#if 1
+      int element_dc = ((word & 0xff) << 8) | ((word >> 8) & 0xff);
+#else
+      int element_dc = word;
+#endif
+
+      if (i < MAX_ELEMENT_CONTENTS)
+       level->yamyam_content[i].e[x][y] = getMappedElement_DC(element_dc);
+    }
+  }
+
+  fieldx = header[6] | (header[7] << 8);
+  fieldy = header[8] | (header[9] << 8);
+  level->fieldx = MIN(MAX(MIN_LEV_FIELDX, fieldx), MAX_LEV_FIELDX);
+  level->fieldy = MIN(MAX(MIN_LEV_FIELDY, fieldy), MAX_LEV_FIELDY);
+
+  for (y = 0; y < fieldy; y++) for (x = 0; x < fieldx; x++)
+  {
+    unsigned short word = getDecodedWord_DC(getFile16BitBE(file), FALSE);
+#if 1
+    int element_dc = ((word & 0xff) << 8) | ((word >> 8) & 0xff);
+#else
+    int element_dc = word;
+#endif
+
+    if (x < MAX_LEV_FIELDX && y < MAX_LEV_FIELDY)
+      level->field[x][y] = getMappedElement_DC(element_dc);
+  }
+
+  x = MIN(MAX(0, (header[10] | (header[11] << 8)) - 1), MAX_LEV_FIELDX - 1);
+  y = MIN(MAX(0, (header[12] | (header[13] << 8)) - 1), MAX_LEV_FIELDY - 1);
+  level->field[x][y] = EL_PLAYER_1;
+
+  x = MIN(MAX(0, (header[14] | (header[15] << 8)) - 1), MAX_LEV_FIELDX - 1);
+  y = MIN(MAX(0, (header[16] | (header[17] << 8)) - 1), MAX_LEV_FIELDY - 1);
+  level->field[x][y] = EL_PLAYER_2;
+
+  level->gems_needed           = header[18] | (header[19] << 8);
+
+  level->score[SC_EMERALD]     = header[20] | (header[21] << 8);
+  level->score[SC_DIAMOND]     = header[22] | (header[23] << 8);
+  level->score[SC_PEARL]       = header[24] | (header[25] << 8);
+  level->score[SC_CRYSTAL]     = header[26] | (header[27] << 8);
+  level->score[SC_NUT]         = header[28] | (header[29] << 8);
+  level->score[SC_ROBOT]       = header[30] | (header[31] << 8);
+  level->score[SC_SPACESHIP]   = header[32] | (header[33] << 8);
+  level->score[SC_BUG]         = header[34] | (header[35] << 8);
+  level->score[SC_YAMYAM]      = header[36] | (header[37] << 8);
+  level->score[SC_DYNAMITE]    = header[38] | (header[39] << 8);
+  level->score[SC_KEY]         = header[40] | (header[41] << 8);
+  level->score[SC_TIME_BONUS]  = header[42] | (header[43] << 8);
+
+  level->time                  = header[44] | (header[45] << 8);
+
+  level->amoeba_speed          = header[46] | (header[47] << 8);
+  level->time_light            = header[48] | (header[49] << 8);
+  level->time_timegate         = header[50] | (header[51] << 8);
+  level->time_wheel            = header[52] | (header[53] << 8);
+  level->time_magic_wall       = header[54] | (header[55] << 8);
+  level->extra_time            = header[56] | (header[57] << 8);
+  level->shield_normal_time    = header[58] | (header[59] << 8);
+
+  fclose(file);
+
+  /* Diamond Caves has the same (strange) behaviour as Emerald Mine that gems
+     can slip down from flat walls, like normal walls and steel walls */
+  level->em_slippery_gems = TRUE;
+
+#if 0
+  /* Diamond Caves II levels are always surrounded by indestructible wall, but
+     not necessarily in a rectangular way -- fill with invisible steel wall */
+
+  /* !!! not always true !!! keep level and set BorderElement instead !!! */
+
+  for (y = 0; y < level->fieldy; y++) for (x = 0; x < level->fieldx; x++)
+  {
+#if 1
+    if ((x == 0 || x == level->fieldx - 1 ||
+        y == 0 || y == level->fieldy - 1) &&
+       level->field[x][y] == EL_EMPTY)
+      level->field[x][y] = EL_INVISIBLE_STEELWALL;
+#else
+    if ((x == 0 || x == level->fieldx - 1 ||
+        y == 0 || y == level->fieldy - 1) &&
+       level->field[x][y] == EL_EMPTY)
+      FloodFillLevel(x, y, EL_INVISIBLE_STEELWALL,
+                    level->field, level->fieldx, level->fieldy);
+#endif
+  }
+#endif
+}
+
+#endif
+
+
+/* ------------------------------------------------------------------------- */
+/* functions for loading generic level                                       */
+/* ------------------------------------------------------------------------- */
+
+void LoadLevelFromFileInfo(struct LevelInfo *level,
+                          struct LevelFileInfo *level_file_info)
+{
+  /* always start with reliable default values */
+  setLevelInfoToDefaults(level);
+
+  switch (level_file_info->type)
+  {
+    case LEVEL_FILE_TYPE_RND:
+      LoadLevelFromFileInfo_RND(level, level_file_info);
+      break;
+
+    case LEVEL_FILE_TYPE_EM:
+      LoadLevelFromFileInfo_EM(level, level_file_info);
+      level->game_engine_type = GAME_ENGINE_TYPE_EM;
+      break;
+
+    case LEVEL_FILE_TYPE_SP:
+      LoadLevelFromFileInfo_SP(level, level_file_info);
+#if 1
+      level->game_engine_type = GAME_ENGINE_TYPE_SP;
+#endif
+      break;
+
+    case LEVEL_FILE_TYPE_DC:
+      LoadLevelFromFileInfo_DC(level, level_file_info);
+      break;
+
+    default:
+      LoadLevelFromFileInfo_RND(level, level_file_info);
+      break;
+  }
+
+  /* if level file is invalid, restore level structure to default values */
+  if (level->no_valid_file)
+    setLevelInfoToDefaults(level);
+
+  if (level->game_engine_type == GAME_ENGINE_TYPE_UNKNOWN)
+    level->game_engine_type = GAME_ENGINE_TYPE_RND;
+
+  if (level_file_info->type != LEVEL_FILE_TYPE_RND)
+    CopyNativeLevel_Native_to_RND(level);
+}
+
+void LoadLevelFromFilename(struct LevelInfo *level, char *filename)
+{
+  static struct LevelFileInfo level_file_info;
+
+  /* always start with reliable default values */
+  setFileInfoToDefaults(&level_file_info);
+
+  level_file_info.nr = 0;                      /* unknown level number */
+  level_file_info.type = LEVEL_FILE_TYPE_RND;  /* no others supported yet */
+  level_file_info.filename = filename;
+
+  LoadLevelFromFileInfo(level, &level_file_info);
+}
+
+static void LoadLevel_InitVersion(struct LevelInfo *level, char *filename)
+{
+  int i, j;
+
+  if (leveldir_current == NULL)                /* only when dumping level */
+    return;
+
+  /* all engine modifications also valid for levels which use latest engine */
+  if (level->game_version < VERSION_IDENT(3,2,0,5))
+  {
+    /* time bonus score was given for 10 s instead of 1 s before 3.2.0-5 */
+    level->score[SC_TIME_BONUS] /= 10;
+  }
+
+#if 0
+  leveldir_current->latest_engine = TRUE;      /* !!! TEST ONLY !!! */
+#endif
+
+  if (leveldir_current->latest_engine)
+  {
+    /* ---------- use latest game engine ----------------------------------- */
+
+    /* For all levels which are forced to use the latest game engine version
+       (normally all but user contributed, private and undefined levels), set
+       the game engine version to the actual version; this allows for actual
+       corrections in the game engine to take effect for existing, converted
+       levels (from "classic" or other existing games) to make the emulation
+       of the corresponding game more accurate, while (hopefully) not breaking
+       existing levels created from other players. */
+
+    level->game_version = GAME_VERSION_ACTUAL;
+
+    /* Set special EM style gems behaviour: EM style gems slip down from
+       normal, steel and growing wall. As this is a more fundamental change,
+       it seems better to set the default behaviour to "off" (as it is more
+       natural) and make it configurable in the level editor (as a property
+       of gem style elements). Already existing converted levels (neither
+       private nor contributed levels) are changed to the new behaviour. */
+
+    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.
 
@@ -5886,7 +6328,7 @@ static void LoadLevel_InitVersion(struct LevelInfo *level, char *filename)
 
   /* try to detect and fix "Snake Bite" levels, which are broken with 3.2.0 */
   {
-    int element = EL_CUSTOM_START + 255;
+    int element = EL_CUSTOM_256;
     struct ElementInfo *ei = &element_info[element];
     struct ElementChangeInfo *change = &ei->change_page[0];
 
@@ -5905,6 +6347,68 @@ static void LoadLevel_InitVersion(struct LevelInfo *level, char *filename)
        change->target_element == EL_SOKOBAN_FIELD_PLAYER)
       change->target_element = EL_PLAYER_1;
   }
+
+#if 1
+  /* try to detect and fix "Zelda" style levels, which are broken with 3.2.5 */
+  if (level->game_version < VERSION_IDENT(3,2,5,0))
+  {
+    /* This is needed to fix a problem that was caused by a bugfix in function
+       game.c/CheckTriggeredElementChangeExt() introduced with 3.2.5 that
+       corrects the behaviour when a custom element changes to another custom
+       element with a higher element number that has change actions defined.
+       Normally, only one change per frame is allowed for custom elements.
+       Therefore, it is checked if a custom element already changed in the
+       current frame; if it did, subsequent changes are suppressed.
+       Unfortunately, this is only checked for element changes, but not for
+       change actions, which are still executed. As the function above loops
+       through all custom elements from lower to higher, an element change
+       resulting in a lower CE number won't be checked again, while a target
+       element with a higher number will also be checked, and potential change
+       actions will get executed for this CE, too (which is wrong), while
+       further changes are ignored (which is correct). As this bugfix breaks
+       Zelda II (and introduces graphical bugs to Zelda I, and also breaks a
+       few other levels like Alan Bond's "FMV"), allow the previous, incorrect
+       behaviour for existing levels and tapes that make use of this bug */
+
+    level->use_action_after_change_bug = TRUE;
+  }
+#else
+  /* !!! THIS DOES NOT FIX "Zelda I" (GRAPHICALLY) AND "Alan's FMV" LEVELS */
+  /* try to detect and fix "Zelda II" levels, which are broken with 3.2.5 */
+  {
+    int element = EL_CUSTOM_16;
+    struct ElementInfo *ei = &element_info[element];
+
+    /* This is needed to fix a problem that was caused by a bugfix in function
+       game.c/CheckTriggeredElementChangeExt() introduced with 3.2.5 that
+       corrects the behaviour when a custom element changes to another custom
+       element with a higher element number that has change actions defined.
+       Normally, only one change per frame is allowed for custom elements.
+       Therefore, it is checked if a custom element already changed in the
+       current frame; if it did, subsequent changes are suppressed.
+       Unfortunately, this is only checked for element changes, but not for
+       change actions, which are still executed. As the function above loops
+       through all custom elements from lower to higher, an element change
+       resulting in a lower CE number won't be checked again, while a target
+       element with a higher number will also be checked, and potential change
+       actions will get executed for this CE, too (which is wrong), while
+       further changes are ignored (which is correct). As this bugfix breaks
+       Zelda II (but no other levels), allow the previous, incorrect behaviour
+       for this outstanding level set to not break the game or existing tapes */
+
+    if (strncmp(leveldir_current->identifier, "zelda2", 6) == 0 ||
+       strncmp(ei->description, "scanline - row 1", 16) == 0)
+      level->use_action_after_change_bug = TRUE;
+  }
+#endif
+
+  /* not centering level after relocating player was default only in 3.2.3 */
+  if (level->game_version == VERSION_IDENT(3,2,3,0))   /* (no pre-releases) */
+    level->shifted_relocation = TRUE;
+
+  /* EM style elements always chain-exploded in R'n'D engine before 3.2.6 */
+  if (level->game_version < VERSION_IDENT(3,2,6,0))
+    level->em_explodes_by_fire = TRUE;
 }
 
 static void LoadLevel_InitElements(struct LevelInfo *level, char *filename)
@@ -6036,6 +6540,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);
+  InitElementPropertiesGfxElement();
 }
 
 static void LoadLevel_InitPlayfield(struct LevelInfo *level, char *filename)
@@ -6058,7 +6563,10 @@ static void LoadLevel_InitPlayfield(struct LevelInfo *level, char *filename)
   lev_fieldy = level->fieldy;
 
   /* determine border element for this level */
-  SetBorderElement();
+  if (level->file_info.type == LEVEL_FILE_TYPE_DC)
+    BorderElement = EL_EMPTY;  /* (in editor, SetBorderElement() is used) */
+  else
+    SetBorderElement();
 }
 
 static void LoadLevel_InitNativeEngines(struct LevelInfo *level,char *filename)
@@ -6411,7 +6919,7 @@ static void SaveLevel_CUS3(FILE *file, struct LevelInfo *level,
        WriteUnusedBytesToFile(file, 7);
 
        putFile8Bit(file, ei->use_gfx_element);
-       putFile16BitBE(file, ei->gfx_element);
+       putFile16BitBE(file, ei->gfx_element_initial);
 
        putFile8Bit(file, ei->collect_score_initial);
        putFile8Bit(file, ei->collect_count_initial);
@@ -6437,7 +6945,7 @@ static void SaveLevel_CUS3(FILE *file, struct LevelInfo *level,
        putFile16BitBE(file, ei->change->delay_random);
        putFile16BitBE(file, ei->change->delay_frames);
 
-       putFile16BitBE(file, ei->change->trigger_element);
+       putFile16BitBE(file, ei->change->initial_trigger_element);
 
        putFile8Bit(file, ei->change->explode);
        putFile8Bit(file, ei->change->use_target_content);
@@ -6490,7 +6998,7 @@ static void SaveLevel_CUS4(FILE *file, struct LevelInfo *level, int element)
   putFile8Bit(file, ei->use_last_ce_value);
 
   putFile8Bit(file, ei->use_gfx_element);
-  putFile16BitBE(file, ei->gfx_element);
+  putFile16BitBE(file, ei->gfx_element_initial);
 
   putFile8Bit(file, ei->collect_score_initial);
   putFile8Bit(file, ei->collect_count_initial);
@@ -6549,7 +7057,7 @@ static void SaveLevel_CUS4(FILE *file, struct LevelInfo *level, int element)
     putFile16BitBE(file, change->delay_random);
     putFile16BitBE(file, change->delay_frames);
 
-    putFile16BitBE(file, change->trigger_element);
+    putFile16BitBE(file, change->initial_trigger_element);
 
     putFile8Bit(file, change->explode);
     putFile8Bit(file, change->use_target_content);
@@ -6601,7 +7109,7 @@ static void SaveLevel_GRP1(FILE *file, struct LevelInfo *level, int element)
   putFile8Bit(file, group->num_elements);
 
   putFile8Bit(file, ei->use_gfx_element);
-  putFile16BitBE(file, ei->gfx_element);
+  putFile16BitBE(file, ei->gfx_element_initial);
 
   putFile8Bit(file, group->choice_mode);
 
@@ -7629,30 +8137,32 @@ void SaveScore(int nr)
 #define SETUP_TOKEN_SOUND_SIMPLE               4
 #define SETUP_TOKEN_TOONS                      5
 #define SETUP_TOKEN_SCROLL_DELAY               6
-#define SETUP_TOKEN_SOFT_SCROLLING             7
-#define SETUP_TOKEN_FADE_SCREENS               8
-#define SETUP_TOKEN_AUTORECORD                 9
-#define SETUP_TOKEN_SHOW_TITLESCREEN           10
-#define SETUP_TOKEN_QUICK_DOORS                        11
-#define SETUP_TOKEN_TEAM_MODE                  12
-#define SETUP_TOKEN_HANDICAP                   13
-#define SETUP_TOKEN_SKIP_LEVELS                        14
-#define SETUP_TOKEN_TIME_LIMIT                 15
-#define SETUP_TOKEN_FULLSCREEN                 16
-#define SETUP_TOKEN_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
+#define SETUP_TOKEN_SCROLL_DELAY_VALUE         7
+#define SETUP_TOKEN_SOFT_SCROLLING             8
+#define SETUP_TOKEN_FADE_SCREENS               9
+#define SETUP_TOKEN_AUTORECORD                 10
+#define SETUP_TOKEN_SHOW_TITLESCREEN           11
+#define SETUP_TOKEN_QUICK_DOORS                        12
+#define SETUP_TOKEN_TEAM_MODE                  13
+#define SETUP_TOKEN_HANDICAP                   14
+#define SETUP_TOKEN_SKIP_LEVELS                        15
+#define SETUP_TOKEN_TIME_LIMIT                 16
+#define SETUP_TOKEN_FULLSCREEN                 17
+#define SETUP_TOKEN_FULLSCREEN_MODE            18
+#define SETUP_TOKEN_ASK_ON_ESCAPE              19
+#define SETUP_TOKEN_ASK_ON_ESCAPE_EDITOR       20
+#define SETUP_TOKEN_QUICK_SWITCH               21
+#define SETUP_TOKEN_INPUT_ON_FOCUS             22
+#define SETUP_TOKEN_PREFER_AGA_GRAPHICS                23
+#define SETUP_TOKEN_GAME_FRAME_DELAY           24
+#define SETUP_TOKEN_GRAPHICS_SET               25
+#define SETUP_TOKEN_SOUNDS_SET                 26
+#define SETUP_TOKEN_MUSIC_SET                  27
+#define SETUP_TOKEN_OVERRIDE_LEVEL_GRAPHICS    28
+#define SETUP_TOKEN_OVERRIDE_LEVEL_SOUNDS      29
+#define SETUP_TOKEN_OVERRIDE_LEVEL_MUSIC       30
+
+#define NUM_GLOBAL_SETUP_TOKENS                        31
 
 /* editor setup */
 #define SETUP_TOKEN_EDITOR_EL_BOULDERDASH      0
@@ -7664,7 +8174,7 @@ void SaveScore(int nr)
 #define SETUP_TOKEN_EDITOR_EL_DIAMOND_CAVES    6
 #define SETUP_TOKEN_EDITOR_EL_DX_BOULDERDASH   7
 #define SETUP_TOKEN_EDITOR_EL_CHARS            8
-#define SETUP_TOKEN_EDITOR_EL_STEELCHARS       9
+#define SETUP_TOKEN_EDITOR_EL_STEEL_CHARS      9
 #define SETUP_TOKEN_EDITOR_EL_CUSTOM           10
 #define SETUP_TOKEN_EDITOR_EL_HEADLINES                11
 #define SETUP_TOKEN_EDITOR_EL_USER_DEFINED     12
@@ -7727,10 +8237,11 @@ void SaveScore(int nr)
 #define NUM_PLAYER_SETUP_TOKENS                        16
 
 /* system setup */
-#define SETUP_TOKEN_SYSTEM_SDL_AUDIODRIVER     0
-#define SETUP_TOKEN_SYSTEM_AUDIO_FRAGMENT_SIZE 1
+#define SETUP_TOKEN_SYSTEM_SDL_VIDEODRIVER     0
+#define SETUP_TOKEN_SYSTEM_SDL_AUDIODRIVER     1
+#define SETUP_TOKEN_SYSTEM_AUDIO_FRAGMENT_SIZE 2
 
-#define NUM_SYSTEM_SETUP_TOKENS                        2
+#define NUM_SYSTEM_SETUP_TOKENS                        3
 
 /* options setup */
 #define SETUP_TOKEN_OPTIONS_VERBOSE            0
@@ -7755,6 +8266,7 @@ static struct TokenInfo global_setup_tokens[] =
   { TYPE_SWITCH, &si.sound_simple,     "simple_sound_effects"          },
   { TYPE_SWITCH, &si.toons,            "toons"                         },
   { TYPE_SWITCH, &si.scroll_delay,     "scroll_delay"                  },
+  { TYPE_INTEGER,&si.scroll_delay_value,"scroll_delay_value"           },
   { TYPE_SWITCH, &si.soft_scrolling,   "soft_scrolling"                },
   { TYPE_SWITCH, &si.fade_screens,     "fade_screens"                  },
   { TYPE_SWITCH, &si.autorecord,       "automatic_tape_recording"      },
@@ -7771,12 +8283,13 @@ static struct TokenInfo global_setup_tokens[] =
   { TYPE_SWITCH, &si.quick_switch,     "quick_player_switch"           },
   { TYPE_SWITCH, &si.input_on_focus,   "input_on_focus"                },
   { TYPE_SWITCH, &si.prefer_aga_graphics, "prefer_aga_graphics"                },
+  { TYPE_INTEGER,&si.game_frame_delay, "game_frame_delay"              },
   { TYPE_STRING, &si.graphics_set,     "graphics_set"                  },
   { TYPE_STRING, &si.sounds_set,       "sounds_set"                    },
   { TYPE_STRING, &si.music_set,                "music_set"                     },
-  { TYPE_SWITCH&si.override_level_graphics, "override_level_graphics"        },
-  { TYPE_SWITCH&si.override_level_sounds,   "override_level_sounds"  },
-  { TYPE_SWITCH&si.override_level_music,    "override_level_music"   },
+  { TYPE_SWITCH3,&si.override_level_graphics, "override_level_graphics"        },
+  { TYPE_SWITCH3,&si.override_level_sounds,   "override_level_sounds"  },
+  { TYPE_SWITCH3,&si.override_level_music,    "override_level_music"   },
 };
 
 static boolean not_used = FALSE;
@@ -7802,7 +8315,7 @@ static struct TokenInfo editor_setup_tokens[] =
   { TYPE_SWITCH, &sei.el_dx_boulderdash,"editor.el_dx_boulderdash"     },
 #endif
   { TYPE_SWITCH, &sei.el_chars,                "editor.el_chars"               },
-  { TYPE_SWITCH, &sei.el_steelchars,   "editor.el_steelchars"          },
+  { TYPE_SWITCH, &sei.el_steel_chars,  "editor.el_steel_chars"         },
   { TYPE_SWITCH, &sei.el_custom,       "editor.el_custom"              },
 #if 1
   { TYPE_SWITCH, &not_used,            "editor.el_headlines"           },
@@ -7827,7 +8340,7 @@ static struct TokenInfo editor_cascade_setup_tokens[] =
   { TYPE_SWITCH, &seci.el_dc,          "editor.cascade.el_dc"          },
   { TYPE_SWITCH, &seci.el_dx,          "editor.cascade.el_dx"          },
   { TYPE_SWITCH, &seci.el_chars,       "editor.cascade.el_chars"       },
-  { TYPE_SWITCH, &seci.el_steelchars,  "editor.cascade.el_steelchars"  },
+  { TYPE_SWITCH, &seci.el_steel_chars, "editor.cascade.el_steel_chars" },
   { TYPE_SWITCH, &seci.el_ce,          "editor.cascade.el_ce"          },
   { TYPE_SWITCH, &seci.el_ge,          "editor.cascade.el_ge"          },
   { TYPE_SWITCH, &seci.el_ref,         "editor.cascade.el_ref"         },
@@ -7869,6 +8382,7 @@ static struct TokenInfo player_setup_tokens[] =
 
 static struct TokenInfo system_setup_tokens[] =
 {
+  { TYPE_STRING,  &syi.sdl_videodriver,        "system.sdl_videodriver"        },
   { TYPE_STRING,  &syi.sdl_audiodriver,        "system.sdl_audiodriver"        },
   { TYPE_INTEGER, &syi.audio_fragment_size,"system.audio_fragment_size"        },
 };
@@ -7904,9 +8418,8 @@ static void setSetupInfoToDefaults(struct SetupInfo *si)
   si->sound_music = TRUE;
   si->sound_simple = TRUE;
   si->toons = TRUE;
-  si->double_buffering = TRUE;
-  si->direct_draw = !si->double_buffering;
   si->scroll_delay = TRUE;
+  si->scroll_delay_value = STD_SCROLL_DELAY;
   si->soft_scrolling = TRUE;
   si->fade_screens = TRUE;
   si->autorecord = TRUE;
@@ -7923,25 +8436,26 @@ static void setSetupInfoToDefaults(struct SetupInfo *si)
   si->quick_switch = FALSE;
   si->input_on_focus = FALSE;
   si->prefer_aga_graphics = TRUE;
+  si->game_frame_delay = GAME_FRAME_DELAY;
 
-  si->graphics_set = getStringCopy(GFX_CLASSIC_SUBDIR);
-  si->sounds_set = getStringCopy(SND_CLASSIC_SUBDIR);
-  si->music_set = getStringCopy(MUS_CLASSIC_SUBDIR);
+  si->graphics_set = getStringCopy(GFX_DEFAULT_SUBDIR);
+  si->sounds_set = getStringCopy(SND_DEFAULT_SUBDIR);
+  si->music_set = getStringCopy(MUS_DEFAULT_SUBDIR);
   si->override_level_graphics = FALSE;
   si->override_level_sounds = FALSE;
   si->override_level_music = FALSE;
 
-  si->editor.el_boulderdash       = TRUE;
-  si->editor.el_emerald_mine      = TRUE;
-  si->editor.el_emerald_mine_club = TRUE;
-  si->editor.el_more              = TRUE;
-  si->editor.el_sokoban           = TRUE;
-  si->editor.el_supaplex          = TRUE;
-  si->editor.el_diamond_caves     = TRUE;
-  si->editor.el_dx_boulderdash    = TRUE;
-  si->editor.el_chars             = TRUE;
-  si->editor.el_steelchars        = TRUE;
-  si->editor.el_custom            = TRUE;
+  si->editor.el_boulderdash            = TRUE;
+  si->editor.el_emerald_mine           = TRUE;
+  si->editor.el_emerald_mine_club      = TRUE;
+  si->editor.el_more                   = TRUE;
+  si->editor.el_sokoban                        = TRUE;
+  si->editor.el_supaplex               = TRUE;
+  si->editor.el_diamond_caves          = TRUE;
+  si->editor.el_dx_boulderdash         = TRUE;
+  si->editor.el_chars                  = TRUE;
+  si->editor.el_steel_chars            = TRUE;
+  si->editor.el_custom                 = TRUE;
 
   si->editor.el_headlines = TRUE;
   si->editor.el_user_defined = FALSE;
@@ -7949,15 +8463,15 @@ static void setSetupInfoToDefaults(struct SetupInfo *si)
 
   si->editor.show_element_token = FALSE;
 
-  si->shortcut.save_game = DEFAULT_KEY_SAVE_GAME;
-  si->shortcut.load_game = DEFAULT_KEY_LOAD_GAME;
-  si->shortcut.toggle_pause = DEFAULT_KEY_TOGGLE_PAUSE;
+  si->shortcut.save_game       = DEFAULT_KEY_SAVE_GAME;
+  si->shortcut.load_game       = DEFAULT_KEY_LOAD_GAME;
+  si->shortcut.toggle_pause    = DEFAULT_KEY_TOGGLE_PAUSE;
 
-  si->shortcut.focus_player[0] = DEFAULT_KEY_FOCUS_PLAYER_1;
-  si->shortcut.focus_player[1] = DEFAULT_KEY_FOCUS_PLAYER_2;
-  si->shortcut.focus_player[2] = DEFAULT_KEY_FOCUS_PLAYER_3;
-  si->shortcut.focus_player[3] = DEFAULT_KEY_FOCUS_PLAYER_4;
-  si->shortcut.focus_player_all = DEFAULT_KEY_FOCUS_PLAYER_ALL;
+  si->shortcut.focus_player[0] = DEFAULT_KEY_FOCUS_PLAYER_1;
+  si->shortcut.focus_player[1] = DEFAULT_KEY_FOCUS_PLAYER_2;
+  si->shortcut.focus_player[2] = DEFAULT_KEY_FOCUS_PLAYER_3;
+  si->shortcut.focus_player[3] = DEFAULT_KEY_FOCUS_PLAYER_4;
+  si->shortcut.focus_player_all        = DEFAULT_KEY_FOCUS_PLAYER_ALL;
 
   for (i = 0; i < MAX_PLAYERS; i++)
   {
@@ -7979,10 +8493,19 @@ static void setSetupInfoToDefaults(struct SetupInfo *si)
     si->input[i].key.drop  = (i == 0 ? DEFAULT_KEY_DROP  : KSYM_UNDEFINED);
   }
 
+  si->system.sdl_videodriver = getStringCopy(ARG_DEFAULT);
   si->system.sdl_audiodriver = getStringCopy(ARG_DEFAULT);
   si->system.audio_fragment_size = DEFAULT_AUDIO_FRAGMENT_SIZE;
 
   si->options.verbose = FALSE;
+
+#if defined(CREATE_SPECIAL_EDITION_RND_JUE)
+  si->handicap = FALSE;
+  si->fullscreen = TRUE;
+  si->override_level_graphics = AUTO;
+  si->override_level_sounds = AUTO;
+  si->override_level_music = AUTO;
+#endif
 }
 
 static void setSetupInfoToDefaults_EditorCascade(struct SetupInfo *si)
@@ -7997,7 +8520,7 @@ static void setSetupInfoToDefaults_EditorCascade(struct SetupInfo *si)
   si->editor_cascade.el_dx             = TRUE;
 
   si->editor_cascade.el_chars          = FALSE;
-  si->editor_cascade.el_steelchars     = FALSE;
+  si->editor_cascade.el_steel_chars    = FALSE;
   si->editor_cascade.el_ce             = FALSE;
   si->editor_cascade.el_ge             = FALSE;
   si->editor_cascade.el_ref            = FALSE;
@@ -8100,14 +8623,23 @@ void LoadSetup()
     checkSetupFileHashIdentifier(setup_file_hash, filename,getCookie("SETUP"));
     decodeSetupFileHash(setup_file_hash);
 
-    setup.direct_draw = !setup.double_buffering;
-
     freeSetupFileHash(setup_file_hash);
 
     /* needed to work around problems with fixed length strings */
     player_name_new = get_corrected_login_name(setup.player_name);
     free(setup.player_name);
     setup.player_name = player_name_new;
+
+    /* "scroll_delay: on(3) / off(0)" was replaced by scroll delay value */
+    if (setup.scroll_delay == FALSE)
+    {
+      setup.scroll_delay_value = MIN_SCROLL_DELAY;
+      setup.scroll_delay = TRUE;                       /* now always "on" */
+    }
+
+    /* make sure that scroll delay value stays inside valid range */
+    setup.scroll_delay_value =
+      MIN(MAX(MIN_SCROLL_DELAY, setup.scroll_delay_value), MAX_SCROLL_DELAY);
   }
   else
     Error(ERR_WARN, "using default setup values");
@@ -8269,43 +8801,306 @@ void LoadCustomElementDescriptions()
   freeSetupFileHash(setup_file_hash);
 }
 
-static void LoadSpecialMenuDesignSettingsFromFilename(char *filename)
+static int getElementFromToken(char *token)
+{
+#if 1
+  char *value = getHashEntry(element_token_hash, token);
+
+  if (value != NULL)
+    return atoi(value);
+#else
+  int i;
+
+  /* !!! OPTIMIZE THIS BY USING HASH !!! */
+  for (i = 0; i < MAX_NUM_ELEMENTS; i++)
+    if (strEqual(token, element_info[i].token_name))
+      return i;
+#endif
+
+  Error(ERR_WARN, "unknown element token '%s'", token);
+
+  return EL_UNDEFINED;
+}
+
+static int get_token_parameter_value(char *token, char *value_raw)
+{
+  char *suffix;
+
+  if (token == NULL || value_raw == NULL)
+    return ARG_UNDEFINED_VALUE;
+
+  suffix = strrchr(token, '.');
+  if (suffix == NULL)
+    suffix = token;
+
+#if 1
+  if (strEqual(suffix, ".element"))
+    return getElementFromToken(value_raw);
+#endif
+
+#if 0
+  if (strncmp(suffix, ".font", 5) == 0)
+  {
+    int i;
+
+    /* !!! OPTIMIZE THIS BY USING HASH !!! */
+    for (i = 0; i < NUM_FONTS; i++)
+      if (strEqual(value_raw, font_info[i].token_name))
+       return i;
+
+    /* if font not found, use reliable default value */
+    return FONT_INITIAL_1;
+  }
+#endif
+
+  /* !!! USE CORRECT VALUE TYPE (currently works also for TYPE_BOOLEAN) !!! */
+  return get_parameter_value(value_raw, suffix, TYPE_INTEGER);
+}
+
+void InitMenuDesignSettings_Static()
+{
+#if 0
+  static SetupFileHash *image_config_hash = NULL;
+#endif
+  int i;
+
+#if 0
+  if (image_config_hash == NULL)
+  {
+    image_config_hash = newSetupFileHash();
+
+    for (i = 0; image_config[i].token != NULL; i++)
+      setHashEntry(image_config_hash,
+                  image_config[i].token,
+                  image_config[i].value);
+  }
+#endif
+
+#if 1
+  /* always start with reliable default values from static default config */
+  for (i = 0; image_config_vars[i].token != NULL; i++)
+  {
+    char *value = getHashEntry(image_config_hash, image_config_vars[i].token);
+
+    if (value != NULL)
+      *image_config_vars[i].value =
+       get_token_parameter_value(image_config_vars[i].token, value);
+  }
+
+#else
+
+  int j;
+
+  /* always start with reliable default values from static default config */
+  for (i = 0; image_config_vars[i].token != NULL; i++)
+    for (j = 0; image_config[j].token != NULL; j++)
+      if (strEqual(image_config_vars[i].token, image_config[j].token))
+       *image_config_vars[i].value =
+         get_token_parameter_value(image_config_vars[i].token,
+                                   image_config[j].value);
+#endif
+}
+
+static void InitMenuDesignSettings_SpecialPreProcessing()
 {
-  SetupFileHash *setup_file_hash;
   int i;
 
+  /* the following initializes hierarchical values from static configuration */
+
+  /* special case: initialize "ARG_DEFAULT" values in static default config */
+  /* (e.g., initialize "[titlemessage].fade_mode" from "[title].fade_mode") */
+  titlemessage_initial_default.fade_mode  = title_initial_default.fade_mode;
+  titlemessage_initial_default.fade_delay = title_initial_default.fade_delay;
+  titlemessage_initial_default.post_delay = title_initial_default.post_delay;
+  titlemessage_initial_default.auto_delay = title_initial_default.auto_delay;
+  titlemessage_default.fade_mode  = title_default.fade_mode;
+  titlemessage_default.fade_delay = title_default.fade_delay;
+  titlemessage_default.post_delay = title_default.post_delay;
+  titlemessage_default.auto_delay = title_default.auto_delay;
+
+  /* special case: initialize "ARG_DEFAULT" values in static default config */
+  /* (e.g., init "titlemessage_1.fade_mode" from "[titlemessage].fade_mode") */
+  for (i = 0; i < MAX_NUM_TITLE_MESSAGES; i++)
+  {
+    titlemessage_initial[i] = titlemessage_initial_default;
+    titlemessage[i] = titlemessage_default;
+  }
+
+  /* special case: initialize "ARG_DEFAULT" values in static default config */
+  /* (eg, init "menu.enter_screen.SCORES.xyz" from "menu.enter_screen.xyz") */
+  for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
+  {
+    menu.enter_screen[i] = menu.enter_screen[GFX_SPECIAL_ARG_DEFAULT];
+    menu.leave_screen[i] = menu.leave_screen[GFX_SPECIAL_ARG_DEFAULT];
+  }
+}
+
+static void InitMenuDesignSettings_SpecialPostProcessing()
+{
+  /* special case: initialize later added SETUP list size from LEVELS value */
+  if (menu.list_size[GAME_MODE_SETUP] == -1)
+    menu.list_size[GAME_MODE_SETUP] = menu.list_size[GAME_MODE_LEVELS];
+}
+
+static void LoadMenuDesignSettingsFromFilename(char *filename)
+{
+  static struct TitleMessageInfo tmi;
+  static struct TokenInfo titlemessage_tokens[] =
+  {
+    { TYPE_INTEGER,    &tmi.x,                 ".x"                    },
+    { TYPE_INTEGER,    &tmi.y,                 ".y"                    },
+    { TYPE_INTEGER,    &tmi.width,             ".width"                },
+    { TYPE_INTEGER,    &tmi.height,            ".height"               },
+    { TYPE_INTEGER,    &tmi.chars,             ".chars"                },
+    { TYPE_INTEGER,    &tmi.lines,             ".lines"                },
+    { TYPE_INTEGER,    &tmi.align,             ".align"                },
+    { TYPE_INTEGER,    &tmi.valign,            ".valign"               },
+    { TYPE_INTEGER,    &tmi.font,              ".font"                 },
+    { TYPE_BOOLEAN,    &tmi.autowrap,          ".autowrap"             },
+    { TYPE_BOOLEAN,    &tmi.centered,          ".centered"             },
+    { TYPE_BOOLEAN,    &tmi.parse_comments,    ".parse_comments"       },
+    { TYPE_INTEGER,    &tmi.sort_priority,     ".sort_priority"        },
+    { TYPE_INTEGER,    &tmi.fade_mode,         ".fade_mode"            },
+    { TYPE_INTEGER,    &tmi.fade_delay,        ".fade_delay"           },
+    { TYPE_INTEGER,    &tmi.post_delay,        ".post_delay"           },
+    { TYPE_INTEGER,    &tmi.auto_delay,        ".auto_delay"           },
+
+    { -1,              NULL,                   NULL                    }
+  };
+  static struct
+  {
+    struct TitleMessageInfo *array;
+    char *text;
+  }
+  titlemessage_arrays[] =
+  {
+    { titlemessage_initial,            "[titlemessage_initial]"        },
+    { titlemessage,                    "[titlemessage]"                },
+
+    { NULL,                            NULL                            }
+  };
+  SetupFileHash *setup_file_hash;
+  int i, j, k;
+
 #if 0
-  printf("LoadSpecialMenuDesignSettings from file '%s' ...\n", filename);
+  printf("LoadMenuDesignSettings from file '%s' ...\n", filename);
 #endif
 
   if ((setup_file_hash = loadSetupFileHash(filename)) == NULL)
     return;
 
+  /* the following initializes hierarchical values from dynamic configuration */
+
   /* special case: initialize with default values that may be overwritten */
+  /* (e.g., init "menu.draw_xoffset.INFO" from "menu.draw_xoffset") */
   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
   {
-    char *value_x = getHashEntry(setup_file_hash, "menu.draw_xoffset");
-    char *value_y = getHashEntry(setup_file_hash, "menu.draw_yoffset");
-    char *list_size = getHashEntry(setup_file_hash, "menu.list_size");
+    char *value_1 = getHashEntry(setup_file_hash, "menu.draw_xoffset");
+    char *value_2 = getHashEntry(setup_file_hash, "menu.draw_yoffset");
+    char *value_3 = getHashEntry(setup_file_hash, "menu.list_size");
 
-    if (value_x != NULL)
-      menu.draw_xoffset[i] = get_integer_from_string(value_x);
-    if (value_y != NULL)
-      menu.draw_yoffset[i] = get_integer_from_string(value_y);
-    if (list_size != NULL)
-      menu.list_size[i] = get_integer_from_string(list_size);
+    if (value_1 != NULL)
+      menu.draw_xoffset[i] = get_integer_from_string(value_1);
+    if (value_2 != NULL)
+      menu.draw_yoffset[i] = get_integer_from_string(value_2);
+    if (value_3 != NULL)
+      menu.list_size[i] = get_integer_from_string(value_3);
   }
 
   /* special case: initialize with default values that may be overwritten */
+  /* (eg, init "menu.draw_xoffset.INFO[XXX]" from "menu.draw_xoffset.INFO") */
   for (i = 0; i < NUM_SPECIAL_GFX_INFO_ARGS; i++)
   {
-    char *value_x = getHashEntry(setup_file_hash, "menu.draw_xoffset.INFO");
-    char *value_y = getHashEntry(setup_file_hash, "menu.draw_yoffset.INFO");
+    char *value_1 = getHashEntry(setup_file_hash, "menu.draw_xoffset.INFO");
+    char *value_2 = getHashEntry(setup_file_hash, "menu.draw_yoffset.INFO");
+
+    if (value_1 != NULL)
+      menu.draw_xoffset_info[i] = get_integer_from_string(value_1);
+    if (value_2 != NULL)
+      menu.draw_yoffset_info[i] = get_integer_from_string(value_2);
+  }
+
+  /* special case: initialize with default values that may be overwritten */
+  /* (eg, init "menu.draw_xoffset.SETUP[XXX]" from "menu.draw_xoffset.SETUP") */
+  for (i = 0; i < NUM_SPECIAL_GFX_SETUP_ARGS; i++)
+  {
+    char *value_1 = getHashEntry(setup_file_hash, "menu.draw_xoffset.SETUP");
+    char *value_2 = getHashEntry(setup_file_hash, "menu.draw_yoffset.SETUP");
+
+    if (value_1 != NULL)
+      menu.draw_xoffset_setup[i] = get_integer_from_string(value_1);
+    if (value_2 != NULL)
+      menu.draw_yoffset_setup[i] = get_integer_from_string(value_2);
+  }
+
+  /* special case: initialize with default values that may be overwritten */
+  /* (eg, init "menu.enter_screen.SCORES.xyz" from "menu.enter_screen.xyz") */
+  for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
+  {
+    char *token_1 = "menu.enter_screen.fade_mode";
+    char *token_2 = "menu.enter_screen.fade_delay";
+    char *token_3 = "menu.enter_screen.post_delay";
+    char *token_4 = "menu.leave_screen.fade_mode";
+    char *token_5 = "menu.leave_screen.fade_delay";
+    char *token_6 = "menu.leave_screen.post_delay";
+    char *value_1 = getHashEntry(setup_file_hash, token_1);
+    char *value_2 = getHashEntry(setup_file_hash, token_2);
+    char *value_3 = getHashEntry(setup_file_hash, token_3);
+    char *value_4 = getHashEntry(setup_file_hash, token_4);
+    char *value_5 = getHashEntry(setup_file_hash, token_5);
+    char *value_6 = getHashEntry(setup_file_hash, token_6);
+
+    if (value_1 != NULL)
+      menu.enter_screen[i].fade_mode = get_token_parameter_value(token_1,
+                                                                value_1);
+    if (value_2 != NULL)
+      menu.enter_screen[i].fade_delay = get_token_parameter_value(token_2,
+                                                                 value_2);
+    if (value_3 != NULL)
+      menu.enter_screen[i].post_delay = get_token_parameter_value(token_3,
+                                                                 value_3);
+    if (value_4 != NULL)
+      menu.leave_screen[i].fade_mode = get_token_parameter_value(token_4,
+                                                                value_4);
+    if (value_5 != NULL)
+      menu.leave_screen[i].fade_delay = get_token_parameter_value(token_5,
+                                                                 value_5);
+    if (value_6 != NULL)
+      menu.leave_screen[i].post_delay = get_token_parameter_value(token_6,
+                                                                 value_6);
+  }
+
+  /* special case: initialize with default values that may be overwritten */
+  /* (e.g., init "titlemessage_1.fade_mode" from "[titlemessage].fade_mode") */
+  for (i = 0; titlemessage_arrays[i].array != NULL; i++)
+  {
+    struct TitleMessageInfo *array = titlemessage_arrays[i].array;
+    char *base_token = titlemessage_arrays[i].text;
+
+    for (j = 0; titlemessage_tokens[j].type != -1; j++)
+    {
+      char *token = getStringCat2(base_token, titlemessage_tokens[j].text);
+      char *value = getHashEntry(setup_file_hash, token);
+
+      if (value != NULL)
+      {
+       int parameter_value = get_token_parameter_value(token, value);
+
+       for (k = 0; k < MAX_NUM_TITLE_MESSAGES; k++)
+       {
+         tmi = array[k];
 
-    if (value_x != NULL)
-      menu.draw_xoffset_info[i] = get_integer_from_string(value_x);
-    if (value_y != NULL)
-      menu.draw_yoffset_info[i] = get_integer_from_string(value_y);
+         if (titlemessage_tokens[j].type == TYPE_INTEGER)
+           *(boolean *)titlemessage_tokens[j].value = (boolean)parameter_value;
+         else
+           *(int     *)titlemessage_tokens[j].value = (int)parameter_value;
+
+         array[k] = tmi;
+       }
+      }
+
+      free(token);
+    }
   }
 
   /* read (and overwrite with) values that may be specified in config file */
@@ -8313,40 +9108,41 @@ static void LoadSpecialMenuDesignSettingsFromFilename(char *filename)
   {
     char *value = getHashEntry(setup_file_hash, image_config_vars[i].token);
 
-    if (value != NULL)
+    /* (ignore definitions set to "[DEFAULT]" which are already initialized) */
+    if (value != NULL && !strEqual(value, ARG_DEFAULT))
       *image_config_vars[i].value =
-       get_auto_parameter_value(image_config_vars[i].token, value);
+       get_token_parameter_value(image_config_vars[i].token, value);
   }
 
   freeSetupFileHash(setup_file_hash);
 }
 
-void LoadSpecialMenuDesignSettings()
+void LoadMenuDesignSettings()
 {
   char *filename_base = UNDEFINED_FILENAME, *filename_local;
-  int i, j;
 
-  /* always start with reliable default values from default config */
-  for (i = 0; image_config_vars[i].token != NULL; i++)
-    for (j = 0; image_config[j].token != NULL; j++)
-      if (strEqual(image_config_vars[i].token, image_config[j].token))
-       *image_config_vars[i].value =
-         get_auto_parameter_value(image_config_vars[i].token,
-                                  image_config[j].value);
+  InitMenuDesignSettings_Static();
+  InitMenuDesignSettings_SpecialPreProcessing();
 
+#if 1
+  if (!GFX_OVERRIDE_ARTWORK(ARTWORK_TYPE_GRAPHICS))
+#else
   if (!SETUP_OVERRIDE_ARTWORK(setup, ARTWORK_TYPE_GRAPHICS))
+#endif
   {
     /* first look for special settings configured in level series config */
     filename_base = getCustomArtworkLevelConfigFilename(ARTWORK_TYPE_GRAPHICS);
 
     if (fileExists(filename_base))
-      LoadSpecialMenuDesignSettingsFromFilename(filename_base);
+      LoadMenuDesignSettingsFromFilename(filename_base);
   }
 
   filename_local = getCustomArtworkConfigFilename(ARTWORK_TYPE_GRAPHICS);
 
   if (filename_local != NULL && !strEqual(filename_base, filename_local))
-    LoadSpecialMenuDesignSettingsFromFilename(filename_local);
+    LoadMenuDesignSettingsFromFilename(filename_local);
+
+  InitMenuDesignSettings_SpecialPostProcessing();
 }
 
 void LoadUserDefinedEditorElementList(int **elements, int *num_elements)
@@ -8404,19 +9200,19 @@ void LoadUserDefinedEditorElementList(int **elements, int *num_elements)
     {
       if (num_unknown_tokens == 0)
       {
-       Error(ERR_RETURN_LINE, "-");
-       Error(ERR_RETURN, "warning: unknown token(s) found in config file:");
-       Error(ERR_RETURN, "- config file: '%s'", filename);
+       Error(ERR_INFO_LINE, "-");
+       Error(ERR_INFO, "warning: unknown token(s) found in config file:");
+       Error(ERR_INFO, "- config file: '%s'", filename);
 
        num_unknown_tokens++;
       }
 
-      Error(ERR_RETURN, "- token: '%s'", list->token);
+      Error(ERR_INFO, "- token: '%s'", list->token);
     }
   }
 
   if (num_unknown_tokens > 0)
-    Error(ERR_RETURN_LINE, "-");
+    Error(ERR_INFO_LINE, "-");
 
   while (*num_elements % 4)    /* pad with empty elements, if needed */
     (*elements)[(*num_elements)++] = EL_EMPTY;
@@ -8504,7 +9300,7 @@ static struct MusicFileInfo *get_music_file_info_ext(char *basename, int music,
 
   /* ---------- music file info found ---------- */
 
-  memset(&tmp_music_file_info, 0, sizeof(struct MusicFileInfo));
+  clear_mem(&tmp_music_file_info, sizeof(struct MusicFileInfo));
 
   for (i = 0; token_to_value_ptr[i].token != NULL; i++)
   {
@@ -8717,18 +9513,18 @@ void print_unknown_token(char *filename, char *token, int token_nr)
 {
   if (token_nr == 0)
   {
-    Error(ERR_RETURN_LINE, "-");
-    Error(ERR_RETURN, "warning: unknown token(s) found in config file:");
-    Error(ERR_RETURN, "- config file: '%s'", filename);
+    Error(ERR_INFO_LINE, "-");
+    Error(ERR_INFO, "warning: unknown token(s) found in config file:");
+    Error(ERR_INFO, "- config file: '%s'", filename);
   }
 
-  Error(ERR_RETURN, "- token: '%s'", token);
+  Error(ERR_INFO, "- token: '%s'", token);
 }
 
 void print_unknown_token_end(int token_nr)
 {
   if (token_nr > 0)
-    Error(ERR_RETURN_LINE, "-");
+    Error(ERR_INFO_LINE, "-");
 }
 
 void LoadHelpAnimInfo()
@@ -8977,9 +9773,9 @@ void LoadHelpTextInfo()
 }
 
 
-/* ------------------------------------------------------------------------- *
- * convert levels
- * ------------------------------------------------------------------------- */
+/* ------------------------------------------------------------------------- */
+/* convert levels                                                            */
+/* ------------------------------------------------------------------------- */
 
 #define MAX_NUM_CONVERT_LEVELS         1000
 
@@ -9089,3 +9885,165 @@ void ConvertLevels()
 
   CloseAllAndExit(0);
 }
+
+
+/* ------------------------------------------------------------------------- */
+/* create and save images for use in level sketches (raw BMP format)         */
+/* ------------------------------------------------------------------------- */
+
+void CreateLevelSketchImages()
+{
+#if defined(TARGET_SDL)
+  Bitmap *bitmap1;
+  Bitmap *bitmap2;
+  int i;
+
+  InitElementPropertiesGfxElement();
+
+  bitmap1 = CreateBitmap(TILEX, TILEY, DEFAULT_DEPTH);
+  bitmap2 = CreateBitmap(MINI_TILEX, MINI_TILEY, DEFAULT_DEPTH);
+
+  for (i = 0; i < NUM_FILE_ELEMENTS; i++)
+  {
+    Bitmap *src_bitmap;
+    int src_x, src_y;
+    int element = getMappedElement(i);
+    int graphic = el2edimg(element);
+    char basename1[16];
+    char basename2[16];
+    char *filename1;
+    char *filename2;
+
+    sprintf(basename1, "%03d.bmp", i);
+    sprintf(basename2, "%03ds.bmp", i);
+
+    filename1 = getPath2(global.create_images_dir, basename1);
+    filename2 = getPath2(global.create_images_dir, basename2);
+
+    getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
+    BlitBitmap(src_bitmap, bitmap1, src_x, src_y, TILEX, TILEY, 0, 0);
+
+    if (SDL_SaveBMP(bitmap1->surface, filename1) != 0)
+      Error(ERR_EXIT, "cannot save level sketch image file '%s'", filename1);
+
+    getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
+    BlitBitmap(src_bitmap, bitmap2, src_x, src_y, MINI_TILEX, MINI_TILEY, 0, 0);
+
+    if (SDL_SaveBMP(bitmap2->surface, filename2) != 0)
+      Error(ERR_EXIT, "cannot save level sketch image file '%s'", filename2);
+
+    free(filename1);
+    free(filename2);
+
+    if (options.debug)
+      printf("%03d `%03d%c", i, i, (i % 10 < 9 ? ' ' : '\n'));
+  }
+
+  FreeBitmap(bitmap1);
+  FreeBitmap(bitmap2);
+
+  if (options.debug)
+    printf("\n");
+
+  Error(ERR_INFO, "%d normal and small images created", NUM_FILE_ELEMENTS);
+
+  CloseAllAndExit(0);
+#endif
+}
+
+
+/* ------------------------------------------------------------------------- */
+/* create and save images for custom and group elements (raw BMP format)     */
+/* ------------------------------------------------------------------------- */
+
+void CreateCustomElementImages()
+{
+#if defined(TARGET_SDL)
+  char *filename = "graphics.classic/RocksCE.bmp";
+  Bitmap *bitmap;
+  Bitmap *src_bitmap;
+  int dummy_graphic = IMG_CUSTOM_99;
+  int yoffset_ce = 0;
+  int yoffset_ge = (TILEY * NUM_CUSTOM_ELEMENTS / 16);
+  int src_x, src_y;
+  int i;
+
+  bitmap = CreateBitmap(TILEX * 16 * 2,
+                       TILEY * (NUM_CUSTOM_ELEMENTS + NUM_GROUP_ELEMENTS) / 16,
+                       DEFAULT_DEPTH);
+
+  getGraphicSource(dummy_graphic, 0, &src_bitmap, &src_x, &src_y);
+
+  for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
+  {
+    int x = i % 16;
+    int y = i / 16;
+    int ii = i + 1;
+    int j;
+
+    BlitBitmap(src_bitmap, bitmap, 0, 0, TILEX, TILEY,
+              TILEX * x, TILEY * y + yoffset_ce);
+
+    BlitBitmap(src_bitmap, bitmap, 0, TILEY, TILEX, TILEY,
+              TILEX * x + TILEX * 16, TILEY * y + yoffset_ce);
+
+    for (j = 2; j >= 0; j--)
+    {
+      int c = ii % 10;
+
+      BlitBitmap(src_bitmap, bitmap, TILEX + c * 7, 0, 6, 10,
+                TILEX * x + 6 + j * 7,
+                TILEY * y + 11 + yoffset_ce);
+
+      BlitBitmap(src_bitmap, bitmap, TILEX + c * 8, TILEY, 6, 10,
+                TILEX * 16 + TILEX * x + 6 + j * 8,
+                TILEY * y + 10 + yoffset_ce);
+
+      ii /= 10;
+    }
+  }
+
+  for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
+  {
+    int x = i % 16;
+    int y = i / 16;
+    int ii = i + 1;
+    int j;
+
+    BlitBitmap(src_bitmap, bitmap, 0, 0, TILEX, TILEY,
+              TILEX * x, TILEY * y + yoffset_ge);
+
+    BlitBitmap(src_bitmap, bitmap, 0, TILEY, TILEX, TILEY,
+              TILEX * x + TILEX * 16, TILEY * y + yoffset_ge);
+
+    for (j = 1; j >= 0; j--)
+    {
+      int c = ii % 10;
+
+      BlitBitmap(src_bitmap, bitmap, TILEX + c * 10, 11, 10, 10,
+                TILEX * x + 6 + j * 10,
+                TILEY * y + 11 + yoffset_ge);
+
+      BlitBitmap(src_bitmap, bitmap, TILEX + c * 8, TILEY + 12, 6, 10,
+                TILEX * 16 + TILEX * x + 10 + j * 8,
+                TILEY * y + 10 + yoffset_ge);
+
+      ii /= 10;
+    }
+  }
+
+  if (SDL_SaveBMP(bitmap->surface, filename) != 0)
+    Error(ERR_EXIT, "cannot save CE graphics file '%s'", filename);
+
+  FreeBitmap(bitmap);
+
+  CloseAllAndExit(0);
+#endif
+}
+
+#if 0
+void CreateLevelSketchImages_TEST()
+{
+  void CreateCustomElementImages()
+}
+#endif