rnd-20060802-1-src
[rocksndiamonds.git] / src / files.c
index 585933c32b8e9661477230b3e66ddef1b26688ef..dd841f4863e1f820297474cb89264c1f2ec363ce 100644 (file)
@@ -32,6 +32,7 @@
 #define LEVEL_CHUNK_AUTH_SIZE  MAX_LEVEL_AUTHOR_LEN
 
 #define LEVEL_CHUNK_VERS_SIZE  8       /* size of file version chunk */
+#define LEVEL_CHUNK_DATE_SIZE  4       /* size of file date chunk    */
 #define LEVEL_CHUNK_HEAD_SIZE  80      /* size of level file header  */
 #define LEVEL_CHUNK_HEAD_UNUSED        0       /* unused level header bytes  */
 #define LEVEL_CHUNK_CNT2_SIZE  160     /* size of level CNT2 chunk   */
@@ -226,8 +227,8 @@ static struct LevelFileConfigInfo chunk_config_INFO[] =
   {
     -1,                                        -1,
     -1,                                        -1,
-    NULL,                              -1,
-  },
+    NULL,                              -1
+  }
 };
 
 static struct LevelFileConfigInfo chunk_config_ELEM[] =
@@ -721,8 +722,8 @@ static struct LevelFileConfigInfo chunk_config_ELEM[] =
   {
     -1,                                        -1,
     -1,                                        -1,
-    NULL,                              -1,
-  },
+    NULL,                              -1
+  }
 };
 
 static struct LevelFileConfigInfo chunk_config_NOTE[] =
@@ -749,8 +750,8 @@ static struct LevelFileConfigInfo chunk_config_NOTE[] =
   {
     -1,                                        -1,
     -1,                                        -1,
-    NULL,                              -1,
-  },
+    NULL,                              -1
+  }
 };
 
 static struct LevelFileConfigInfo chunk_config_CUSX_base[] =
@@ -955,7 +956,7 @@ static struct LevelFileConfigInfo chunk_config_CUSX_base[] =
     -1,                                        -1,
     NULL,                              -1,
     NULL
-  },
+  }
 };
 
 static struct LevelFileConfigInfo chunk_config_CUSX_change[] =
@@ -1093,8 +1094,8 @@ static struct LevelFileConfigInfo chunk_config_CUSX_change[] =
   {
     -1,                                        -1,
     -1,                                        -1,
-    NULL,                              -1,
-  },
+    NULL,                              -1
+  }
 };
 
 static struct LevelFileConfigInfo chunk_config_GRPX[] =
@@ -1134,8 +1135,63 @@ static struct LevelFileConfigInfo chunk_config_GRPX[] =
   {
     -1,                                        -1,
     -1,                                        -1,
-    NULL,                              -1,
+    NULL,                              -1
+  }
+};
+
+static struct LevelFileConfigInfo chunk_config_CONF[] =                /* (OBSOLETE) */
+{
+  {
+    EL_PLAYER_1,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(9),
+    &li.block_snap_field,              TRUE
+  },
+  {
+    EL_PLAYER_1,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(13),
+    &li.continuous_snapping,           TRUE
+  },
+  {
+    EL_PLAYER_1,                       -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(1),
+    &li.initial_player_stepsize[0],    STEPSIZE_NORMAL
+  },
+  {
+    EL_PLAYER_1,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(10),
+    &li.use_start_element[0],          FALSE
+  },
+  {
+    EL_PLAYER_1,                       -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(1),
+    &li.start_element[0],              EL_PLAYER_1
   },
+  {
+    EL_PLAYER_1,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(11),
+    &li.use_artwork_element[0],                FALSE
+  },
+  {
+    EL_PLAYER_1,                       -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(2),
+    &li.artwork_element[0],            EL_PLAYER_1
+  },
+  {
+    EL_PLAYER_1,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(12),
+    &li.use_explosion_element[0],      FALSE
+  },
+  {
+    EL_PLAYER_1,                       -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(3),
+    &li.explosion_element[0],          EL_PLAYER_1
+  },
+
+  {
+    -1,                                        -1,
+    -1,                                        -1,
+    NULL,                              -1
+  }
 };
 
 static struct
@@ -1160,6 +1216,19 @@ filetype_id_list[] =
 /* level file functions                                                      */
 /* ========================================================================= */
 
+static struct DateInfo getCurrentDate()
+{
+  time_t epoch_seconds = time(NULL);
+  struct tm *now = localtime(&epoch_seconds);
+  struct DateInfo date;
+
+  date.year  = now->tm_year + 1900;
+  date.month = now->tm_mon  + 1;
+  date.day   = now->tm_mday;
+
+  return date;
+}
+
 static void resetEventFlags(struct ElementChangeInfo *change)
 {
   int i;
@@ -1524,6 +1593,8 @@ static void setLevelInfoToDefaults(struct LevelInfo *level)
   level->file_version = FILE_VERSION_ACTUAL;
   level->game_version = GAME_VERSION_ACTUAL;
 
+  level->creation_date = getCurrentDate();
+
 #if 1
   level->encoding_16bit_field  = TRUE;
   level->encoding_16bit_yamyam = TRUE;
@@ -1667,6 +1738,11 @@ static void setLevelInfoToDefaults(struct LevelInfo *level)
     int element = i;
     struct ElementInfo *ei = &element_info[element];
 
+    /* never initialize clipboard elements after the very first time */
+    /* (to be able to use clipboard elements between several levels) */
+    if (IS_CLIPBOARD_ELEMENT(element) && clipboard_elements_initialized)
+      continue;
+
     if (IS_ENVELOPE(element))
     {
       int envelope_nr = element - EL_ENVELOPE_1;
@@ -1689,11 +1765,6 @@ static void setLevelInfoToDefaults(struct LevelInfo *level)
     }
 #endif
 
-    /* never initialize clipboard elements after the very first time */
-    /* (to be able to use clipboard elements between several levels) */
-    if (IS_CLIPBOARD_ELEMENT(element) && clipboard_elements_initialized)
-      continue;
-
     setElementChangePages(ei, 1);
     setElementChangeInfoToDefaults(ei->change);
 
@@ -2240,6 +2311,15 @@ static int LoadLevel_VERS(FILE *file, int chunk_size, struct LevelInfo *level)
   return chunk_size;
 }
 
+static int LoadLevel_DATE(FILE *file, int chunk_size, struct LevelInfo *level)
+{
+  level->creation_date.year  = getFile16BitBE(file);
+  level->creation_date.month = getFile8Bit(file);
+  level->creation_date.day   = getFile8Bit(file);
+
+  return chunk_size;
+}
+
 static int LoadLevel_HEAD(FILE *file, int chunk_size, struct LevelInfo *level)
 {
   int initial_player_stepsize;
@@ -2502,6 +2582,11 @@ static int LoadLevel_CUS1(FILE *file, int chunk_size, struct LevelInfo *level)
 #endif
 
 #if 1
+    /* older game versions that wrote level files with CUS1 chunks used
+       different default push delay values (not yet stored in level file) */
+    element_info[element].push_delay_fixed = 2;
+    element_info[element].push_delay_random = 8;
+#else
     /* needed for older levels (see src/init.c for details) */
     element_info[element].push_delay_fixed = -1;       /* initialize later */
     element_info[element].push_delay_random = -1;      /* initialize later */
@@ -2980,6 +3065,28 @@ static int LoadLevel_INFO(FILE *file, int chunk_size, struct LevelInfo *level)
   return real_chunk_size;
 }
 
+static int LoadLevel_CONF(FILE *file, int chunk_size, struct LevelInfo *level)
+{
+  int real_chunk_size = 0;
+
+  li = *level;         /* copy level data into temporary buffer */
+
+  while (!feof(file))
+  {
+    int element = getMappedElement(getFile16BitBE(file));
+
+    real_chunk_size += 2;
+    real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_CONF,
+                                           element, element);
+    if (real_chunk_size >= chunk_size)
+      break;
+  }
+
+  *level = li;         /* copy temporary buffer back to level data */
+
+  return real_chunk_size;
+}
+
 static int LoadLevel_ELEM(FILE *file, int chunk_size, struct LevelInfo *level)
 {
   int real_chunk_size = 0;
@@ -3314,6 +3421,7 @@ static void LoadLevelFromFileInfo_RND(struct LevelInfo *level,
     chunk_info[] =
     {
       { "VERS", LEVEL_CHUNK_VERS_SIZE, LoadLevel_VERS },
+      { "DATE", LEVEL_CHUNK_DATE_SIZE, LoadLevel_DATE },
       { "HEAD", LEVEL_CHUNK_HEAD_SIZE, LoadLevel_HEAD },
       { "NAME", LEVEL_CHUNK_NAME_SIZE, LoadLevel_NAME },
       { "AUTH", LEVEL_CHUNK_AUTH_SIZE, LoadLevel_AUTH },
@@ -3327,6 +3435,7 @@ static void LoadLevelFromFileInfo_RND(struct LevelInfo *level,
       { "CUS3", -1,                    LoadLevel_CUS3 },
       { "CUS4", -1,                    LoadLevel_CUS4 },
       { "GRP1", -1,                    LoadLevel_GRP1 },
+      { "CONF", -1,                    LoadLevel_CONF },
       { "ELEM", -1,                    LoadLevel_ELEM },
       { "NOTE", -1,                    LoadLevel_NOTE },
       { "CUSX", -1,                    LoadLevel_CUSX },
@@ -4904,6 +5013,7 @@ static void LoadLevel_InitElements(struct LevelInfo *level, char *filename)
 
   /* initialize element properties for level editor etc. */
   InitElementPropertiesEngine(level->game_version);
+  InitElementPropertiesAfterLoading(level->game_version);
 }
 
 static void LoadLevel_InitPlayfield(struct LevelInfo *level, char *filename)
@@ -4988,6 +5098,17 @@ static int SaveLevel_VERS(FILE *file, struct LevelInfo *level)
   return chunk_size;
 }
 
+static int SaveLevel_DATE(FILE *file, struct LevelInfo *level)
+{
+  int chunk_size = 0;
+
+  chunk_size += putFile16BitBE(file, level->creation_date.year);
+  chunk_size += putFile8Bit(file,    level->creation_date.month);
+  chunk_size += putFile8Bit(file,    level->creation_date.day);
+
+  return chunk_size;
+}
+
 #if 0
 static void SaveLevel_HEAD(FILE *file, struct LevelInfo *level)
 {
@@ -5884,6 +6005,8 @@ static void SaveLevelFromFilename(struct LevelInfo *level, char *filename)
   level->file_version = FILE_VERSION_ACTUAL;
   level->game_version = GAME_VERSION_ACTUAL;
 
+  level->creation_date = getCurrentDate();
+
 #if 0
   /* check level field for 16-bit elements */
   level->encoding_16bit_field = FALSE;
@@ -5923,6 +6046,10 @@ static void SaveLevelFromFilename(struct LevelInfo *level, char *filename)
   putFileChunkBE(file, "VERS", chunk_size);
   SaveLevel_VERS(file, level);
 
+  chunk_size = SaveLevel_DATE(NULL, level);
+  putFileChunkBE(file, "DATE", chunk_size);
+  SaveLevel_DATE(file, level);
+
 #if 0
   putFileChunkBE(file, "HEAD", LEVEL_CHUNK_HEAD_SIZE);
   SaveLevel_HEAD(file, level);
@@ -6004,23 +6131,19 @@ static void SaveLevelFromFilename(struct LevelInfo *level, char *filename)
 #endif
 
   chunk_size = SaveLevel_ELEM(NULL, level);
-
-  /* check if non-default element settings need to be saved */
-  if (chunk_size > LEVEL_CHUNK_ELEM_UNCHANGED)
+  if (chunk_size > LEVEL_CHUNK_ELEM_UNCHANGED)         /* save if changed */
   {
     putFileChunkBE(file, "ELEM", chunk_size);
     SaveLevel_ELEM(file, level);
   }
 
 #if 1
-  for (i = 0; i < 4; i++)
+  for (i = 0; i < NUM_ENVELOPES; i++)
   {
     int element = EL_ENVELOPE_1 + i;
 
     chunk_size = SaveLevel_NOTE(NULL, level, element);
-
-    /* check if non-default element settings need to be saved */
-    if (chunk_size > LEVEL_CHUNK_NOTE_UNCHANGED)
+    if (chunk_size > LEVEL_CHUNK_NOTE_UNCHANGED)       /* save if changed */
     {
       putFileChunkBE(file, "NOTE", chunk_size);
       SaveLevel_NOTE(file, level, element);
@@ -6037,9 +6160,7 @@ static void SaveLevelFromFilename(struct LevelInfo *level, char *filename)
       int element = EL_CUSTOM_START + i;
 
       chunk_size = SaveLevel_CUSX(NULL, level, element);
-
-      /* check if non-default element settings need to be saved */
-      if (chunk_size > LEVEL_CHUNK_CUSX_UNCHANGED)
+      if (chunk_size > LEVEL_CHUNK_CUSX_UNCHANGED)     /* save if changed */
       {
        putFileChunkBE(file, "CUSX", chunk_size);
        SaveLevel_CUSX(file, level, element);
@@ -6051,9 +6172,7 @@ static void SaveLevelFromFilename(struct LevelInfo *level, char *filename)
       int element = EL_GROUP_START + i;
 
       chunk_size = SaveLevel_GRPX(NULL, level, element);
-
-      /* check if non-default element settings need to be saved */
-      if (chunk_size > LEVEL_CHUNK_GRPX_UNCHANGED)
+      if (chunk_size > LEVEL_CHUNK_GRPX_UNCHANGED)     /* save if changed */
       {
        putFileChunkBE(file, "GRPX", chunk_size);
        SaveLevel_GRPX(file, level, element);
@@ -6435,6 +6554,7 @@ void LoadTapeFromFilename(char *filename)
   tape.length_seconds = GetTapeLength();
 
 #if 0
+  printf("::: tape file version: %d\n", tape.file_version);
   printf("::: tape game version: %d\n", tape.game_version);
   printf("::: tape engine version: %d\n", tape.engine_version);
 #endif
@@ -6733,19 +6853,20 @@ void SaveScore(int nr)
 #define SETUP_TOKEN_SKIP_LEVELS                        14
 #define SETUP_TOKEN_TIME_LIMIT                 15
 #define SETUP_TOKEN_FULLSCREEN                 16
-#define SETUP_TOKEN_ASK_ON_ESCAPE              17
-#define SETUP_TOKEN_ASK_ON_ESCAPE_EDITOR       18
-#define SETUP_TOKEN_QUICK_SWITCH               19
-#define SETUP_TOKEN_INPUT_ON_FOCUS             20
-#define SETUP_TOKEN_PREFER_AGA_GRAPHICS                21
-#define SETUP_TOKEN_GRAPHICS_SET               22
-#define SETUP_TOKEN_SOUNDS_SET                 23
-#define SETUP_TOKEN_MUSIC_SET                  24
-#define SETUP_TOKEN_OVERRIDE_LEVEL_GRAPHICS    25
-#define SETUP_TOKEN_OVERRIDE_LEVEL_SOUNDS      26
-#define SETUP_TOKEN_OVERRIDE_LEVEL_MUSIC       27
-
-#define NUM_GLOBAL_SETUP_TOKENS                        28
+#define SETUP_TOKEN_FULLSCREEN_MODE            17
+#define SETUP_TOKEN_ASK_ON_ESCAPE              18
+#define SETUP_TOKEN_ASK_ON_ESCAPE_EDITOR       19
+#define SETUP_TOKEN_QUICK_SWITCH               20
+#define SETUP_TOKEN_INPUT_ON_FOCUS             21
+#define SETUP_TOKEN_PREFER_AGA_GRAPHICS                22
+#define SETUP_TOKEN_GRAPHICS_SET               23
+#define SETUP_TOKEN_SOUNDS_SET                 24
+#define SETUP_TOKEN_MUSIC_SET                  25
+#define SETUP_TOKEN_OVERRIDE_LEVEL_GRAPHICS    26
+#define SETUP_TOKEN_OVERRIDE_LEVEL_SOUNDS      27
+#define SETUP_TOKEN_OVERRIDE_LEVEL_MUSIC       28
+
+#define NUM_GLOBAL_SETUP_TOKENS                        29
 
 /* editor setup */
 #define SETUP_TOKEN_EDITOR_EL_BOULDERDASH      0
@@ -6761,9 +6882,11 @@ void SaveScore(int nr)
 #define SETUP_TOKEN_EDITOR_EL_HEADLINES                10
 #define SETUP_TOKEN_EDITOR_EL_USER_DEFINED     11
 #define SETUP_TOKEN_EDITOR_EL_DYNAMIC          12
-#define SETUP_TOKEN_EDITOR_SHOW_ELEMENT_TOKEN  13
+#define SETUP_TOKEN_EDITOR_EL_BY_GAME          13
+#define SETUP_TOKEN_EDITOR_EL_BY_TYPE          14
+#define SETUP_TOKEN_EDITOR_SHOW_ELEMENT_TOKEN  15
 
-#define NUM_EDITOR_SETUP_TOKENS                        14
+#define NUM_EDITOR_SETUP_TOKENS                        16
 
 /* editor cascade setup */
 #define SETUP_TOKEN_EDITOR_CASCADE_BD          0
@@ -6777,8 +6900,8 @@ void SaveScore(int nr)
 #define SETUP_TOKEN_EDITOR_CASCADE_TEXT                8
 #define SETUP_TOKEN_EDITOR_CASCADE_CE          9
 #define SETUP_TOKEN_EDITOR_CASCADE_GE          10
-#define SETUP_TOKEN_EDITOR_CASCADE_USER                11
-#define SETUP_TOKEN_EDITOR_CASCADE_GENERIC     12
+#define SETUP_TOKEN_EDITOR_CASCADE_REF         11
+#define SETUP_TOKEN_EDITOR_CASCADE_USER                12
 #define SETUP_TOKEN_EDITOR_CASCADE_DYNAMIC     13
 
 #define NUM_EDITOR_CASCADE_SETUP_TOKENS                14
@@ -6854,6 +6977,7 @@ static struct TokenInfo global_setup_tokens[] =
   { TYPE_SWITCH, &si.skip_levels,      "skip_levels"                   },
   { TYPE_SWITCH, &si.time_limit,       "time_limit"                    },
   { TYPE_SWITCH, &si.fullscreen,       "fullscreen"                    },
+  { TYPE_SWITCH, &si.fullscreen_mode,  "fullscreen_mode"               },
   { TYPE_SWITCH, &si.ask_on_escape,    "ask_on_escape"                 },
   { TYPE_SWITCH, &si.ask_on_escape_editor, "ask_on_escape_editor"      },
   { TYPE_SWITCH, &si.quick_switch,     "quick_player_switch"           },
@@ -6867,8 +6991,19 @@ static struct TokenInfo global_setup_tokens[] =
   { TYPE_SWITCH, &si.override_level_music,    "override_level_music"   },
 };
 
+static boolean not_used = FALSE;
 static struct TokenInfo editor_setup_tokens[] =
 {
+#if 1
+  { TYPE_SWITCH, &not_used,            "editor.el_boulderdash"         },
+  { TYPE_SWITCH, &not_used,            "editor.el_emerald_mine"        },
+  { TYPE_SWITCH, &not_used,            "editor.el_emerald_mine_club"   },
+  { TYPE_SWITCH, &not_used,            "editor.el_more"                },
+  { TYPE_SWITCH, &not_used,            "editor.el_sokoban"             },
+  { TYPE_SWITCH, &not_used,            "editor.el_supaplex"            },
+  { TYPE_SWITCH, &not_used,            "editor.el_diamond_caves"       },
+  { TYPE_SWITCH, &not_used,            "editor.el_dx_boulderdash"      },
+#else
   { TYPE_SWITCH, &sei.el_boulderdash,  "editor.el_boulderdash"         },
   { TYPE_SWITCH, &sei.el_emerald_mine, "editor.el_emerald_mine"        },
   { TYPE_SWITCH, &sei.el_emerald_mine_club,"editor.el_emerald_mine_club"},
@@ -6877,11 +7012,18 @@ static struct TokenInfo editor_setup_tokens[] =
   { TYPE_SWITCH, &sei.el_supaplex,     "editor.el_supaplex"            },
   { TYPE_SWITCH, &sei.el_diamond_caves,        "editor.el_diamond_caves"       },
   { TYPE_SWITCH, &sei.el_dx_boulderdash,"editor.el_dx_boulderdash"     },
+#endif
   { TYPE_SWITCH, &sei.el_chars,                "editor.el_chars"               },
   { TYPE_SWITCH, &sei.el_custom,       "editor.el_custom"              },
+#if 1
+  { TYPE_SWITCH, &not_used,            "editor.el_headlines"           },
+#else
   { TYPE_SWITCH, &sei.el_headlines,    "editor.el_headlines"           },
+#endif
   { TYPE_SWITCH, &sei.el_user_defined, "editor.el_user_defined"        },
   { TYPE_SWITCH, &sei.el_dynamic,      "editor.el_dynamic"             },
+  { TYPE_SWITCH, &sei.el_by_game,      "editor.el_by_game"             },
+  { TYPE_SWITCH, &sei.el_by_type,      "editor.el_by_type"             },
   { TYPE_SWITCH, &sei.show_element_token,"editor.show_element_token"   },
 };
 
@@ -6898,6 +7040,7 @@ static struct TokenInfo editor_cascade_setup_tokens[] =
   { TYPE_SWITCH, &seci.el_chars,       "editor.cascade.el_chars"       },
   { TYPE_SWITCH, &seci.el_ce,          "editor.cascade.el_ce"          },
   { TYPE_SWITCH, &seci.el_ge,          "editor.cascade.el_ge"          },
+  { TYPE_SWITCH, &seci.el_ref,         "editor.cascade.el_ref"         },
   { TYPE_SWITCH, &seci.el_user,                "editor.cascade.el_user"        },
   { TYPE_SWITCH, &seci.el_dynamic,     "editor.cascade.el_dynamic"     },
 };
@@ -6984,6 +7127,7 @@ static void setSetupInfoToDefaults(struct SetupInfo *si)
   si->skip_levels = TRUE;
   si->time_limit = TRUE;
   si->fullscreen = FALSE;
+  si->fullscreen_mode = getStringCopy(DEFAULT_FULLSCREEN_MODE);
   si->ask_on_escape = TRUE;
   si->ask_on_escape_editor = TRUE;
   si->quick_switch = FALSE;
@@ -7064,6 +7208,7 @@ static void setSetupInfoToDefaults_EditorCascade(struct SetupInfo *si)
   si->editor_cascade.el_chars  = FALSE;
   si->editor_cascade.el_ce     = FALSE;
   si->editor_cascade.el_ge     = FALSE;
+  si->editor_cascade.el_ref    = FALSE;
   si->editor_cascade.el_user   = FALSE;
   si->editor_cascade.el_dynamic        = FALSE;
 }
@@ -7290,7 +7435,7 @@ void SaveSetup_EditorCascade()
 
   seci = setup.editor_cascade;
   fprintf(file, "\n");
-  for (i = 0; i < NUM_EDITOR_SETUP_TOKENS; i++)
+  for (i = 0; i < NUM_EDITOR_CASCADE_SETUP_TOKENS; i++)
     fprintf(file, "%s\n", getSetupLine(editor_cascade_setup_tokens, "", i));
 
   fclose(file);