rnd-20030327-1-src
[rocksndiamonds.git] / src / files.c
index fac13d0133719ac331a34f39c707170296958b89..436decce8759e073aefceeb3d69aaa1fad2d8bfc 100644 (file)
@@ -90,12 +90,20 @@ static void setLevelInfoToDefaults()
        level.yam_content[i][x][y] =
          (i < STD_ELEMENT_CONTENTS ? EL_ROCK : EL_EMPTY);
 
-  Feld[0][0] = Ur[0][0] = EL_PLAYER1;
+  Feld[0][0] = Ur[0][0] = EL_PLAYER_1;
   Feld[STD_LEV_FIELDX-1][STD_LEV_FIELDY-1] =
     Ur[STD_LEV_FIELDX-1][STD_LEV_FIELDY-1] = EL_EXIT_CLOSED;
 
+  for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
+    Properties1[EL_CUSTOM_START + i] = EP_BITMASK_DEFAULT;
+
   BorderElement = EL_STEELWALL;
 
+  level.no_level_file = FALSE;
+
+  if (leveldir_current == NULL)                /* only when dumping level */
+    return;
+
   /* try to determine better author name than 'anonymous' */
   if (strcmp(leveldir_current->author, ANONYMOUS_NAME) != 0)
   {
@@ -125,8 +133,6 @@ static void setLevelInfoToDefaults()
        break;
     }
   }
-
-  level.no_level_file = FALSE;
 }
 
 static int checkLevelElement(int element)
@@ -137,9 +143,9 @@ static int checkLevelElement(int element)
     element = EL_CHAR_QUESTION;
   }
   else if (element == EL_PLAYER_OBSOLETE)
-    element = EL_PLAYER1;
+    element = EL_PLAYER_1;
   else if (element == EL_KEY_OBSOLETE)
-    element = EL_KEY1;
+    element = EL_KEY_1;
 
   return element;
 }
@@ -200,6 +206,33 @@ static int LoadLevel_AUTH(FILE *file, int chunk_size, struct LevelInfo *level)
   return chunk_size;
 }
 
+static int LoadLevel_BODY(FILE *file, int chunk_size, struct LevelInfo *level)
+{
+  int x, y;
+  int chunk_size_expected = level->fieldx * level->fieldy;
+
+  /* Note: "chunk_size" was wrong before version 2.0 when elements are
+     stored with 16-bit encoding (and should be twice as big then).
+     Even worse, playfield data was stored 16-bit when only yamyam content
+     contained 16-bit elements and vice versa. */
+
+  if (level->encoding_16bit_field && level->file_version >= FILE_VERSION_2_0)
+    chunk_size_expected *= 2;
+
+  if (chunk_size_expected != chunk_size)
+  {
+    ReadUnusedBytesFromFile(file, chunk_size);
+    return chunk_size_expected;
+  }
+
+  for(y=0; y<level->fieldy; y++)
+    for(x=0; x<level->fieldx; x++)
+      Feld[x][y] = Ur[x][y] =
+       checkLevelElement(level->encoding_16bit_field ?
+                         getFile16BitBE(file) : fgetc(file));
+  return chunk_size;
+}
+
 static int LoadLevel_CONT(FILE *file, int chunk_size, struct LevelInfo *level)
 {
   int i, x, y;
@@ -240,33 +273,6 @@ static int LoadLevel_CONT(FILE *file, int chunk_size, struct LevelInfo *level)
   return chunk_size;
 }
 
-static int LoadLevel_BODY(FILE *file, int chunk_size, struct LevelInfo *level)
-{
-  int x, y;
-  int chunk_size_expected = level->fieldx * level->fieldy;
-
-  /* Note: "chunk_size" was wrong before version 2.0 when elements are
-     stored with 16-bit encoding (and should be twice as big then).
-     Even worse, playfield data was stored 16-bit when only yamyam content
-     contained 16-bit elements and vice versa. */
-
-  if (level->encoding_16bit_field && level->file_version >= FILE_VERSION_2_0)
-    chunk_size_expected *= 2;
-
-  if (chunk_size_expected != chunk_size)
-  {
-    ReadUnusedBytesFromFile(file, chunk_size);
-    return chunk_size_expected;
-  }
-
-  for(y=0; y<level->fieldy; y++)
-    for(x=0; x<level->fieldx; x++)
-      Feld[x][y] = Ur[x][y] =
-       checkLevelElement(level->encoding_16bit_field ?
-                         getFile16BitBE(file) : fgetc(file));
-  return chunk_size;
-}
-
 static int LoadLevel_CNT2(FILE *file, int chunk_size, struct LevelInfo *level)
 {
   int i, x, y;
@@ -310,9 +316,34 @@ static int LoadLevel_CNT2(FILE *file, int chunk_size, struct LevelInfo *level)
   return chunk_size;
 }
 
-void LoadLevel(int level_nr)
+static int LoadLevel_CUS1(FILE *file, int chunk_size, struct LevelInfo *level)
+{
+  int num_changed_custom_elements = getFile16BitBE(file);
+  int chunk_size_expected = 2 + num_changed_custom_elements * 6;
+  int i;
+
+  if (chunk_size_expected != chunk_size)
+  {
+    ReadUnusedBytesFromFile(file, chunk_size - 2);
+    return chunk_size_expected;
+  }
+
+  for (i=0; i < num_changed_custom_elements; i++)
+  {
+    int element = getFile16BitBE(file);
+    int properties = getFile32BitBE(file);
+
+    if (IS_CUSTOM_ELEMENT(element))
+      Properties1[element] = properties;
+    else
+      Error(ERR_WARN, "invalid custom element number %d", element);
+  }
+
+  return chunk_size;
+}
+
+void LoadLevelFromFilename(char *filename)
 {
-  char *filename = getLevelFilename(level_nr);
   char cookie[MAX_LINE_LEN];
   char chunk_name[CHUNK_ID_LEN + 1];
   int chunk_size;
@@ -386,9 +417,10 @@ void LoadLevel(int level_nr)
       { "VERS", FILE_VERS_CHUNK_SIZE,  LoadLevel_VERS },
       { "HEAD", LEVEL_HEADER_SIZE,     LoadLevel_HEAD },
       { "AUTH", MAX_LEVEL_AUTHOR_LEN,  LoadLevel_AUTH },
-      { "CONT", -1,                    LoadLevel_CONT },
       { "BODY", -1,                    LoadLevel_BODY },
+      { "CONT", -1,                    LoadLevel_CONT },
       { "CNT2", LEVEL_CHUNK_CNT2_SIZE, LoadLevel_CNT2 },
+      { "CUS1", -1,                    LoadLevel_CUS1 },
       {  NULL,  0,                     NULL }
     };
 
@@ -433,6 +465,9 @@ void LoadLevel(int level_nr)
 
   fclose(file);
 
+  if (leveldir_current == NULL)                /* only when dumping level */
+    return;
+
   if (IS_LEVELCLASS_CONTRIBUTION(leveldir_current) ||
       IS_LEVELCLASS_USER(leveldir_current))
   {
@@ -484,6 +519,13 @@ void LoadLevel(int level_nr)
   SetBorderElement();
 }
 
+void LoadLevel(int level_nr)
+{
+  char *filename = getLevelFilename(level_nr);
+
+  LoadLevelFromFilename(filename);
+}
+
 static void SaveLevel_VERS(FILE *file, struct LevelInfo *level)
 {
   putFileVersion(file, level->file_version);
@@ -533,6 +575,18 @@ static void SaveLevel_AUTH(FILE *file, struct LevelInfo *level)
     fputc(level->author[i], file);
 }
 
+static void SaveLevel_BODY(FILE *file, struct LevelInfo *level)
+{
+  int x, y;
+
+  for(y=0; y<level->fieldy; y++) 
+    for(x=0; x<level->fieldx; x++) 
+      if (level->encoding_16bit_field)
+       putFile16BitBE(file, Ur[x][y]);
+      else
+       fputc(Ur[x][y], file);
+}
+
 #if 0
 static void SaveLevel_CONT(FILE *file, struct LevelInfo *level)
 {
@@ -553,18 +607,6 @@ static void SaveLevel_CONT(FILE *file, struct LevelInfo *level)
 }
 #endif
 
-static void SaveLevel_BODY(FILE *file, struct LevelInfo *level)
-{
-  int x, y;
-
-  for(y=0; y<level->fieldy; y++) 
-    for(x=0; x<level->fieldx; x++) 
-      if (level->encoding_16bit_field)
-       putFile16BitBE(file, Ur[x][y]);
-      else
-       fputc(Ur[x][y], file);
-}
-
 static void SaveLevel_CNT2(FILE *file, struct LevelInfo *level, int element)
 {
   int i, x, y;
@@ -616,11 +658,38 @@ static void SaveLevel_CNT2(FILE *file, struct LevelInfo *level, int element)
        putFile16BitBE(file, content_array[i][x][y]);
 }
 
+static void SaveLevel_CUS1(FILE *file, int num_changed_custom_elements)
+{
+  int i, check = 0;
+
+  putFile16BitBE(file, num_changed_custom_elements);
+
+  for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
+  {
+    int element = EL_CUSTOM_START + i;
+
+    if (Properties1[element] != EP_BITMASK_DEFAULT)
+    {
+      if (check < num_changed_custom_elements)
+      {
+       putFile16BitBE(file, element);
+       putFile32BitBE(file, Properties1[element]);
+      }
+
+      check++;
+    }
+  }
+
+  if (check != num_changed_custom_elements)    /* should not happen */
+    Error(ERR_WARN, "inconsistent number of custom element properties");
+}
+
 void SaveLevel(int level_nr)
 {
-  int i, x, y;
   char *filename = getLevelFilename(level_nr);
   int body_chunk_size;
+  int num_changed_custom_elements = 0;
+  int i, x, y;
   FILE *file;
 
   if (!(file = fopen(filename, MODE_WRITE)))
@@ -652,9 +721,15 @@ void SaveLevel(int level_nr)
   if (level.amoeba_content > 255)
     level.encoding_16bit_amoeba = TRUE;
 
+  /* calculate size of "BODY" chunk */
   body_chunk_size =
     level.fieldx * level.fieldy * (level.encoding_16bit_field ? 2 : 1);
 
+  /* check for non-standard custom elements and calculate "CUS1" chunk size */
+  for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
+    if (Properties1[EL_CUSTOM_START + i] != EP_BITMASK_DEFAULT)
+      num_changed_custom_elements++;
+
   putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED);
   putFileChunkBE(file, "CAVE", CHUNK_SIZE_NONE);
 
@@ -683,11 +758,46 @@ void SaveLevel(int level_nr)
     SaveLevel_CNT2(file, &level, EL_BD_AMOEBA);
   }
 
+  if (num_changed_custom_elements > 0)
+  {
+    putFileChunkBE(file, "CUS1", 2 + num_changed_custom_elements * 6);
+    SaveLevel_CUS1(file, num_changed_custom_elements);
+  }
+
   fclose(file);
 
   SetFilePermissions(filename, PERMS_PRIVATE);
 }
 
+void DumpLevel(struct LevelInfo *level)
+{
+  printf_line("-", 79);
+  printf("Level xxx (file version %06d, game version %06d)\n",
+        level->file_version, level->game_version);
+  printf_line("-", 79);
+
+  printf("Level Author: '%s'\n", level->author);
+  printf("Level Title:  '%s'\n", level->name);
+  printf("\n");
+  printf("Playfield Size: %d x %d\n", level->fieldx, level->fieldy);
+  printf("\n");
+  printf("Level Time:  %d seconds\n", level->time);
+  printf("Gems needed: %d\n", level->gems_needed);
+  printf("\n");
+  printf("Time for Magic Wall: %d seconds\n", level->time_magic_wall);
+  printf("Time for Wheel:      %d seconds\n", level->time_wheel);
+  printf("Time for Light:      %d seconds\n", level->time_light);
+  printf("Time for Timegate:   %d seconds\n", level->time_timegate);
+  printf("\n");
+  printf("Amoeba Speed: %d\n", level->amoeba_speed);
+  printf("\n");
+  printf("Gravity:                %s\n", (level->gravity ? "yes" : "no"));
+  printf("Double Speed Movement:  %s\n", (level->double_speed ? "yes" : "no"));
+  printf("EM style slippery gems: %s\n", (level->em_slippery_gems ? "yes" : "no"));
+
+  printf_line("-", 79);
+}
+
 
 /* ========================================================================= */
 /* tape file functions                                                       */
@@ -762,6 +872,26 @@ static int LoadTape_HEAD(FILE *file, int chunk_size, struct TapeInfo *tape)
   return chunk_size;
 }
 
+static int LoadTape_INFO(FILE *file, int chunk_size, struct TapeInfo *tape)
+{
+  int level_identifier_size;
+  int i;
+
+  level_identifier_size = getFile16BitBE(file);
+
+  tape->level_identifier =
+    checked_realloc(tape->level_identifier, level_identifier_size);
+
+  for(i=0; i < level_identifier_size; i++)
+    tape->level_identifier[i] = fgetc(file);
+
+  tape->level_nr = getFile16BitBE(file);
+
+  chunk_size = 2 + level_identifier_size + 2;
+
+  return chunk_size;
+}
+
 static int LoadTape_BODY(FILE *file, int chunk_size, struct TapeInfo *tape)
 {
   int i, j;
@@ -846,9 +976,8 @@ static int LoadTape_BODY(FILE *file, int chunk_size, struct TapeInfo *tape)
   return chunk_size;
 }
 
-void LoadTape(int level_nr)
+void LoadTapeFromFilename(char *filename)
 {
-  char *filename = getTapeFilename(level_nr);
   char cookie[MAX_LINE_LEN];
   char chunk_name[CHUNK_ID_LEN + 1];
   FILE *file;
@@ -916,6 +1045,7 @@ void LoadTape(int level_nr)
     {
       { "VERS", FILE_VERS_CHUNK_SIZE,  LoadTape_VERS },
       { "HEAD", TAPE_HEADER_SIZE,      LoadTape_HEAD },
+      { "INFO", -1,                    LoadTape_INFO },
       { "BODY", -1,                    LoadTape_BODY },
       {  NULL,  0,                     NULL }
     };
@@ -964,6 +1094,13 @@ void LoadTape(int level_nr)
   tape.length_seconds = GetTapeLength();
 }
 
+void LoadTape(int level_nr)
+{
+  char *filename = getTapeFilename(level_nr);
+
+  LoadTapeFromFilename(filename);
+}
+
 static void SaveTape_VERS(FILE *file, struct TapeInfo *tape)
 {
   putFileVersion(file, tape->file_version);
@@ -992,6 +1129,19 @@ static void SaveTape_HEAD(FILE *file, struct TapeInfo *tape)
   putFileVersion(file, tape->engine_version);
 }
 
+static void SaveTape_INFO(FILE *file, struct TapeInfo *tape)
+{
+  int level_identifier_size = strlen(tape->level_identifier) + 1;
+  int i;
+
+  putFile16BitBE(file, level_identifier_size);
+
+  for(i=0; i < level_identifier_size; i++)
+    fputc(tape->level_identifier[i], file);
+
+  putFile16BitBE(file, tape->level_nr);
+}
+
 static void SaveTape_BODY(FILE *file, struct TapeInfo *tape)
 {
   int i, j;
@@ -1008,12 +1158,13 @@ static void SaveTape_BODY(FILE *file, struct TapeInfo *tape)
 
 void SaveTape(int level_nr)
 {
-  int i;
   char *filename = getTapeFilename(level_nr);
   FILE *file;
   boolean new_tape = TRUE;
   int num_participating_players = 0;
+  int info_chunk_size;
   int body_chunk_size;
+  int i;
 
   InitTapeDirectory(leveldir_current->filename);
 
@@ -1039,6 +1190,7 @@ void SaveTape(int level_nr)
     if (tape.player_participates[i])
       num_participating_players++;
 
+  info_chunk_size = 2 + (strlen(tape.level_identifier) + 1) + 2;
   body_chunk_size = (num_participating_players + 1) * tape.length;
 
   putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED);
@@ -1050,6 +1202,9 @@ void SaveTape(int level_nr)
   putFileChunkBE(file, "HEAD", TAPE_HEADER_SIZE);
   SaveTape_HEAD(file, &tape);
 
+  putFileChunkBE(file, "INFO", info_chunk_size);
+  SaveTape_INFO(file, &tape);
+
   putFileChunkBE(file, "BODY", body_chunk_size);
   SaveTape_BODY(file, &tape);
 
@@ -1073,17 +1228,19 @@ void DumpTape(struct TapeInfo *tape)
     return;
   }
 
-  printf("\n");
-  printf("-------------------------------------------------------------------------------\n");
-  printf("Tape of Level %d (file version %06d, game version %06d)\n",
+  printf_line("-", 79);
+  printf("Tape of Level %03d (file version %06d, game version %06d)\n",
         tape->level_nr, tape->file_version, tape->game_version);
-  printf("-------------------------------------------------------------------------------\n");
+  printf("Level series identifier: '%s'\n", tape->level_identifier);
+  printf_line("-", 79);
 
   for(i=0; i<tape->length; i++)
   {
     if (i >= MAX_TAPELEN)
       break;
 
+    printf("%03d: ", i);
+
     for(j=0; j<MAX_PLAYERS; j++)
     {
       if (tape->player_participates[j])
@@ -1104,7 +1261,7 @@ void DumpTape(struct TapeInfo *tape)
     printf("(%03d)\n", tape->pos[i].delay);
   }
 
-  printf("-------------------------------------------------------------------------------\n");
+  printf_line("-", 79);
 }
 
 
@@ -1222,40 +1379,67 @@ void SaveScore(int level_nr)
 
 #define NUM_GLOBAL_SETUP_TOKENS                        22
 
+/* editor setup */
+#define SETUP_TOKEN_EDITOR_EL_BOULDERDASH      0
+#define SETUP_TOKEN_EDITOR_EL_EMERALD_MINE     1
+#define SETUP_TOKEN_EDITOR_EL_MORE             2
+#define SETUP_TOKEN_EDITOR_EL_SOKOBAN          3
+#define SETUP_TOKEN_EDITOR_EL_SUPAPLEX         4
+#define SETUP_TOKEN_EDITOR_EL_DIAMOND_CAVES    5
+#define SETUP_TOKEN_EDITOR_EL_DX_BOULDERDASH   6
+#define SETUP_TOKEN_EDITOR_EL_CHARS            7
+#define SETUP_TOKEN_EDITOR_EL_CUSTOM           8
+
+#define NUM_EDITOR_SETUP_TOKENS                        9
+
 /* shortcut setup */
-#define SETUP_TOKEN_SAVE_GAME                  0
-#define SETUP_TOKEN_LOAD_GAME                  1
-#define SETUP_TOKEN_TOGGLE_PAUSE               2
+#define SETUP_TOKEN_SHORTCUT_SAVE_GAME         0
+#define SETUP_TOKEN_SHORTCUT_LOAD_GAME         1
+#define SETUP_TOKEN_SHORTCUT_TOGGLE_PAUSE      2
 
 #define NUM_SHORTCUT_SETUP_TOKENS              3
 
 /* player setup */
-#define SETUP_TOKEN_USE_JOYSTICK               0
-#define SETUP_TOKEN_JOY_DEVICE_NAME            1
-#define SETUP_TOKEN_JOY_XLEFT                  2
-#define SETUP_TOKEN_JOY_XMIDDLE                        3
-#define SETUP_TOKEN_JOY_XRIGHT                 4
-#define SETUP_TOKEN_JOY_YUPPER                 5
-#define SETUP_TOKEN_JOY_YMIDDLE                        6
-#define SETUP_TOKEN_JOY_YLOWER                 7
-#define SETUP_TOKEN_JOY_SNAP                   8
-#define SETUP_TOKEN_JOY_BOMB                   9
-#define SETUP_TOKEN_KEY_LEFT                   10
-#define SETUP_TOKEN_KEY_RIGHT                  11
-#define SETUP_TOKEN_KEY_UP                     12
-#define SETUP_TOKEN_KEY_DOWN                   13
-#define SETUP_TOKEN_KEY_SNAP                   14
-#define SETUP_TOKEN_KEY_BOMB                   15
+#define SETUP_TOKEN_PLAYER_USE_JOYSTICK                0
+#define SETUP_TOKEN_PLAYER_JOY_DEVICE_NAME     1
+#define SETUP_TOKEN_PLAYER_JOY_XLEFT           2
+#define SETUP_TOKEN_PLAYER_JOY_XMIDDLE         3
+#define SETUP_TOKEN_PLAYER_JOY_XRIGHT          4
+#define SETUP_TOKEN_PLAYER_JOY_YUPPER          5
+#define SETUP_TOKEN_PLAYER_JOY_YMIDDLE         6
+#define SETUP_TOKEN_PLAYER_JOY_YLOWER          7
+#define SETUP_TOKEN_PLAYER_JOY_SNAP            8
+#define SETUP_TOKEN_PLAYER_JOY_BOMB            9
+#define SETUP_TOKEN_PLAYER_KEY_LEFT            10
+#define SETUP_TOKEN_PLAYER_KEY_RIGHT           11
+#define SETUP_TOKEN_PLAYER_KEY_UP              12
+#define SETUP_TOKEN_PLAYER_KEY_DOWN            13
+#define SETUP_TOKEN_PLAYER_KEY_SNAP            14
+#define SETUP_TOKEN_PLAYER_KEY_BOMB            15
 
 #define NUM_PLAYER_SETUP_TOKENS                        16
 
+/* system setup */
+#define SETUP_TOKEN_SYSTEM_SDL_AUDIODRIVER     0
+#define SETUP_TOKEN_SYSTEM_AUDIO_FRAGMENT_SIZE 1
+
+#define NUM_SYSTEM_SETUP_TOKENS                        2
+
+/* options setup */
+#define SETUP_TOKEN_OPTIONS_VERBOSE            0
+
+#define NUM_OPTIONS_SETUP_TOKENS               1
+
+
 static struct SetupInfo si;
+static struct SetupEditorInfo sei;
 static struct SetupShortcutInfo ssi;
 static struct SetupInputInfo sii;
+static struct SetupSystemInfo syi;
+static struct OptionInfo soi;
 
 static struct TokenInfo global_setup_tokens[] =
 {
-  /* global setup */
   { TYPE_STRING, &si.player_name,      "player_name"                   },
   { TYPE_SWITCH, &si.sound,            "sound"                         },
   { TYPE_SWITCH, &si.sound_loops,      "repeating_sound_loops"         },
@@ -1280,9 +1464,21 @@ static struct TokenInfo global_setup_tokens[] =
   { TYPE_SWITCH, &si.override_level_music,    "override_level_music"   },
 };
 
+static struct TokenInfo editor_setup_tokens[] =
+{
+  { TYPE_SWITCH, &sei.el_boulderdash,  "editor.el_boulderdash"         },
+  { TYPE_SWITCH, &sei.el_emerald_mine, "editor.el_emerald_mine"        },
+  { TYPE_SWITCH, &sei.el_more,         "editor.el_more"                },
+  { TYPE_SWITCH, &sei.el_sokoban,      "editor.el_sokoban"             },
+  { TYPE_SWITCH, &sei.el_supaplex,     "editor.el_supaplex"            },
+  { TYPE_SWITCH, &sei.el_diamond_caves,        "editor.el_diamond_caves"       },
+  { TYPE_SWITCH, &sei.el_dx_boulderdash,"editor.el_dx_boulderdash"     },
+  { TYPE_SWITCH, &sei.el_chars,                "editor.el_chars"               },
+  { TYPE_SWITCH, &sei.el_custom,       "editor.el_custom"              },
+};
+
 static struct TokenInfo shortcut_setup_tokens[] =
 {
-  /* shortcut setup */
   { TYPE_KEY_X11, &ssi.save_game,      "shortcut.save_game"            },
   { TYPE_KEY_X11, &ssi.load_game,      "shortcut.load_game"            },
   { TYPE_KEY_X11, &ssi.toggle_pause,   "shortcut.toggle_pause"         }
@@ -1290,7 +1486,6 @@ static struct TokenInfo shortcut_setup_tokens[] =
 
 static struct TokenInfo player_setup_tokens[] =
 {
-  /* player setup */
   { TYPE_BOOLEAN, &sii.use_joystick,   ".use_joystick"                 },
   { TYPE_STRING,  &sii.joy.device_name,        ".joy.device_name"              },
   { TYPE_INTEGER, &sii.joy.xleft,      ".joy.xleft"                    },
@@ -1309,6 +1504,17 @@ static struct TokenInfo player_setup_tokens[] =
   { TYPE_KEY_X11, &sii.key.bomb,       ".key.place_bomb"               }
 };
 
+static struct TokenInfo system_setup_tokens[] =
+{
+  { TYPE_STRING,  &syi.sdl_audiodriver,        "system.sdl_audiodriver"        },
+  { TYPE_INTEGER, &syi.audio_fragment_size,"system.audio_fragment_size"        }
+};
+
+static struct TokenInfo options_setup_tokens[] =
+{
+  { TYPE_BOOLEAN, &soi.verbose,                "options.verbose"               }
+};
+
 static void setSetupInfoToDefaults(struct SetupInfo *si)
 {
   int i;
@@ -1340,6 +1546,16 @@ static void setSetupInfoToDefaults(struct SetupInfo *si)
   si->override_level_sounds = FALSE;
   si->override_level_music = FALSE;
 
+  si->editor.el_boulderdash = TRUE;
+  si->editor.el_emerald_mine = TRUE;
+  si->editor.el_more = TRUE;
+  si->editor.el_sokoban = TRUE;
+  si->editor.el_supaplex = TRUE;
+  si->editor.el_diamond_caves = TRUE;
+  si->editor.el_dx_boulderdash = TRUE;
+  si->editor.el_chars = TRUE;
+  si->editor.el_custom = TRUE;
+
   si->shortcut.save_game = DEFAULT_KEY_SAVE_GAME;
   si->shortcut.load_game = DEFAULT_KEY_LOAD_GAME;
   si->shortcut.toggle_pause = DEFAULT_KEY_TOGGLE_PAUSE;
@@ -1363,6 +1579,11 @@ static void setSetupInfoToDefaults(struct SetupInfo *si)
     si->input[i].key.snap  = (i == 0 ? DEFAULT_KEY_SNAP  : KSYM_UNDEFINED);
     si->input[i].key.bomb  = (i == 0 ? DEFAULT_KEY_BOMB  : KSYM_UNDEFINED);
   }
+
+  si->system.sdl_audiodriver = getStringCopy(ARG_DEFAULT);
+  si->system.audio_fragment_size = DEFAULT_AUDIO_FRAGMENT_SIZE;
+
+  si->options.verbose = FALSE;
 }
 
 static void decodeSetupFileList(struct SetupFileList *setup_file_list)
@@ -1379,6 +1600,13 @@ static void decodeSetupFileList(struct SetupFileList *setup_file_list)
                 getTokenValue(setup_file_list, global_setup_tokens[i].text));
   setup = si;
 
+  /* editor setup */
+  sei = setup.editor;
+  for (i=0; i<NUM_EDITOR_SETUP_TOKENS; i++)
+    setSetupInfo(editor_setup_tokens, i,
+                getTokenValue(setup_file_list,editor_setup_tokens[i].text));
+  setup.editor = sei;
+
   /* shortcut setup */
   ssi = setup.shortcut;
   for (i=0; i<NUM_SHORTCUT_SETUP_TOKENS; i++)
@@ -1404,6 +1632,20 @@ static void decodeSetupFileList(struct SetupFileList *setup_file_list)
     }
     setup.input[pnr] = sii;
   }
+
+  /* system setup */
+  syi = setup.system;
+  for (i=0; i<NUM_SYSTEM_SETUP_TOKENS; i++)
+    setSetupInfo(system_setup_tokens, i,
+                getTokenValue(setup_file_list, system_setup_tokens[i].text));
+  setup.system = syi;
+
+  /* options setup */
+  soi = setup.options;
+  for (i=0; i<NUM_OPTIONS_SETUP_TOKENS; i++)
+    setSetupInfo(options_setup_tokens, i,
+                getTokenValue(setup_file_list, options_setup_tokens[i].text));
+  setup.options = soi;
 }
 
 void LoadSetup()
@@ -1463,13 +1705,20 @@ void SaveSetup()
   si = setup;
   for (i=0; i<NUM_GLOBAL_SETUP_TOKENS; i++)
   {
-    fprintf(file, "%s\n", getSetupLine(global_setup_tokens, "", i));
-
     /* just to make things nicer :) */
-    if (i == SETUP_TOKEN_PLAYER_NAME || i == SETUP_TOKEN_GRAPHICS_SET - 1)
+    if (i == SETUP_TOKEN_PLAYER_NAME + 1 ||
+       i == SETUP_TOKEN_GRAPHICS_SET)
       fprintf(file, "\n");
+
+    fprintf(file, "%s\n", getSetupLine(global_setup_tokens, "", i));
   }
 
+  /* editor setup */
+  sei = setup.editor;
+  fprintf(file, "\n");
+  for (i=0; i<NUM_EDITOR_SETUP_TOKENS; i++)
+    fprintf(file, "%s\n", getSetupLine(editor_setup_tokens, "", i));
+
   /* shortcut setup */
   ssi = setup.shortcut;
   fprintf(file, "\n");
@@ -1489,7 +1738,100 @@ void SaveSetup()
       fprintf(file, "%s\n", getSetupLine(player_setup_tokens, prefix, i));
   }
 
+  /* system setup */
+  syi = setup.system;
+  fprintf(file, "\n");
+  for (i=0; i<NUM_SYSTEM_SETUP_TOKENS; i++)
+    fprintf(file, "%s\n", getSetupLine(system_setup_tokens, "", i));
+
+  /* options setup */
+  soi = setup.options;
+  fprintf(file, "\n");
+  for (i=0; i<NUM_OPTIONS_SETUP_TOKENS; i++)
+    fprintf(file, "%s\n", getSetupLine(options_setup_tokens, "", i));
+
   fclose(file);
 
   SetFilePermissions(filename, PERMS_PRIVATE);
 }
+
+void LoadCustomElementDescriptions()
+{
+  char *filename = getCustomArtworkConfigFilename(ARTWORK_TYPE_GRAPHICS);
+  struct SetupFileList *setup_file_list;
+  int i;
+
+  for (i=0; i<NUM_FILE_ELEMENTS; i++)
+  {
+    if (element_info[i].custom_description != NULL)
+    {
+      free(element_info[i].custom_description);
+      element_info[i].custom_description = NULL;
+    }
+  }
+
+  if ((setup_file_list = loadSetupFileList(filename)) == NULL)
+    return;
+
+  for (i=0; i<NUM_FILE_ELEMENTS; i++)
+  {
+    char *token = getStringCat2(element_info[i].token_name, ".name");
+    char *value = getTokenValue(setup_file_list, token);
+
+    if (value != NULL)
+      element_info[i].custom_description = getStringCopy(value);
+
+    free(token);
+  }
+
+  freeSetupFileList(setup_file_list);
+}
+
+void LoadSpecialMenuDesignSettings()
+{
+  char *filename = getCustomArtworkConfigFilename(ARTWORK_TYPE_GRAPHICS);
+  struct SetupFileList *setup_file_list;
+  char *value;
+
+  /* !!! CHANGE THIS !!! (redundant initialization) !!! */
+  global.num_toons = 20;
+  global.menu_draw_xoffset = 0;
+  global.menu_draw_yoffset = 0;
+  global.menu_draw_xoffset_MAIN = 0;
+  global.menu_draw_yoffset_MAIN = 0;
+  global.door_step_offset = 2;
+  global.door_step_delay = 10;
+
+  if ((setup_file_list = loadSetupFileList(filename)) == NULL)
+    return;
+
+  value = getTokenValue(setup_file_list, "global.num_toons");
+  if (value != NULL)
+    global.num_toons = get_integer_from_string(value);
+
+  value = getTokenValue(setup_file_list, "menu.draw_xoffset");
+  if (value != NULL)
+    global.menu_draw_xoffset = get_integer_from_string(value);
+
+  value = getTokenValue(setup_file_list, "menu.draw_yoffset");
+  if (value != NULL)
+    global.menu_draw_yoffset = get_integer_from_string(value);
+
+  value = getTokenValue(setup_file_list, "menu.draw_xoffset.MAIN");
+  if (value != NULL)
+    global.menu_draw_xoffset_MAIN = get_integer_from_string(value);
+
+  value = getTokenValue(setup_file_list, "menu.draw_yoffset.MAIN");
+  if (value != NULL)
+    global.menu_draw_yoffset_MAIN = get_integer_from_string(value);
+
+  value = getTokenValue(setup_file_list, "door.step_offset");
+  if (value != NULL)
+    global.door_step_offset = get_integer_from_string(value);
+
+  value = getTokenValue(setup_file_list, "door.step_delay");
+  if (value != NULL)
+    global.door_step_delay = get_integer_from_string(value);
+
+  freeSetupFileList(setup_file_list);
+}