rnd-20030902-1-src
[rocksndiamonds.git] / src / files.c
index db3a432d41aa3623ee0d26ac783343663f6f25c6..4ef0174af5d82563ac31646637060ea587327f72 100644 (file)
@@ -719,6 +719,170 @@ void LoadLevelFromFilename(struct LevelInfo *level, char *filename)
   fclose(file);
 }
 
+#if 1
+
+static void LoadLevel_InitVersion(struct LevelInfo *level, char *filename)
+{
+  if (leveldir_current == NULL)                /* only when dumping level */
+    return;
+
+  /* determine correct game engine version of current level */
+  if (IS_LEVELCLASS_CONTRIBUTION(leveldir_current) ||
+      IS_LEVELCLASS_USER(leveldir_current))
+  {
+#if 0
+    printf("\n::: This level is private or contributed: '%s'\n", filename);
+#endif
+
+    /* For user contributed and private levels, use the version of
+       the game engine the levels were created for.
+       Since 2.0.1, the game engine version is now directly stored
+       in the level file (chunk "VERS"), so there is no need anymore
+       to set the game version from the file version (except for old,
+       pre-2.0 levels, where the game version is still taken from the
+       file format version used to store the level -- see above). */
+
+    /* do some special adjustments to support older level versions */
+    if (level->file_version == FILE_VERSION_1_0)
+    {
+      Error(ERR_WARN, "level file '%s'has version number 1.0", filename);
+      Error(ERR_WARN, "using high speed movement for player");
+
+      /* player was faster than monsters in (pre-)1.0 levels */
+      level->double_speed = TRUE;
+    }
+
+    /* Default behaviour for EM style gems was "slippery" only in 2.0.1 */
+    if (level->game_version == VERSION_IDENT(2,0,1))
+      level->em_slippery_gems = TRUE;
+  }
+  else
+  {
+#if 0
+    printf("\n::: ALWAYS USE LATEST ENGINE FOR THIS LEVEL: [%d] '%s'\n",
+          leveldir_current->sort_priority, filename);
+#endif
+
+    /* Always use the latest version of the game engine for all but
+       user contributed and private levels; 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 game emulation 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;
+  }
+}
+
+static void LoadLevel_InitElements(struct LevelInfo *level, char *filename)
+{
+  int i, j;
+
+  /* map custom element change events that have changed in newer versions
+     (these following values have accidentally changed in version 3.0.1) */
+  if (level->game_version <= VERSION_IDENT(3,0,0))
+  {
+    for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
+    {
+      int element = EL_CUSTOM_START + i;
+
+      /* order of checking events to be mapped is important */
+      for (j=CE_BY_OTHER; j >= CE_BY_PLAYER; j--)
+      {
+       if (HAS_CHANGE_EVENT(element, j - 2))
+       {
+         SET_CHANGE_EVENT(element, j - 2, FALSE);
+         SET_CHANGE_EVENT(element, j, TRUE);
+       }
+      }
+
+      /* order of checking events to be mapped is important */
+      for (j=CE_OTHER_GETS_COLLECTED; j >= CE_COLLISION; j--)
+      {
+       if (HAS_CHANGE_EVENT(element, j - 1))
+       {
+         SET_CHANGE_EVENT(element, j - 1, FALSE);
+         SET_CHANGE_EVENT(element, j, TRUE);
+       }
+      }
+    }
+  }
+
+  /* initialize "can_change" field for old levels with only one change page */
+  if (level->game_version <= VERSION_IDENT(3,0,2))
+  {
+    for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
+    {
+      int element = EL_CUSTOM_START + i;
+
+      if (CAN_CHANGE(element))
+       element_info[element].change->can_change = TRUE;
+    }
+  }
+
+  /* initialize element properties for level editor etc. */
+  InitElementPropertiesEngine(level->game_version);
+}
+
+static void LoadLevel_InitPlayfield(struct LevelInfo *level, char *filename)
+{
+  int x, y;
+
+  /* map elements that have changed in newer versions */
+  for(y=0; y<level->fieldy; y++)
+  {
+    for(x=0; x<level->fieldx; x++)
+    {
+      int element = level->field[x][y];
+
+      if (level->game_version <= VERSION_IDENT(2,2,0))
+      {
+       /* map game font elements */
+       element = (element == EL_CHAR('[')  ? EL_CHAR_AUMLAUT :
+                  element == EL_CHAR('\\') ? EL_CHAR_OUMLAUT :
+                  element == EL_CHAR(']')  ? EL_CHAR_UUMLAUT :
+                  element == EL_CHAR('^')  ? EL_CHAR_COPYRIGHT : element);
+      }
+
+      if (level->game_version < VERSION_IDENT(3,0,0))
+      {
+       /* map Supaplex gravity tube elements */
+       element = (element == EL_SP_GRAVITY_PORT_LEFT  ? EL_SP_PORT_LEFT  :
+                  element == EL_SP_GRAVITY_PORT_RIGHT ? EL_SP_PORT_RIGHT :
+                  element == EL_SP_GRAVITY_PORT_UP    ? EL_SP_PORT_UP    :
+                  element == EL_SP_GRAVITY_PORT_DOWN  ? EL_SP_PORT_DOWN  :
+                  element);
+      }
+
+      level->field[x][y] = element;
+    }
+  }
+
+  /* copy elements to runtime playfield array */
+  for(x=0; x<MAX_LEV_FIELDX; x++)
+    for(y=0; y<MAX_LEV_FIELDY; y++)
+      Feld[x][y] = level->field[x][y];
+
+  /* initialize level size variables for faster access */
+  lev_fieldx = level->fieldx;
+  lev_fieldy = level->fieldy;
+
+  /* determine border element for this level */
+  SetBorderElement();
+}
+
+#else
+
 static void LoadLevel_InitLevel(struct LevelInfo *level, char *filename)
 {
   int i, j, x, y;
@@ -871,12 +1035,17 @@ static void LoadLevel_InitLevel(struct LevelInfo *level, char *filename)
   InitElementPropertiesEngine(level->game_version);
 }
 
+#endif
+
 void LoadLevelTemplate(int level_nr)
 {
   char *filename = getLevelFilename(level_nr);
 
   LoadLevelFromFilename(&level_template, filename);
 
+  LoadLevel_InitVersion(&level, filename);
+  LoadLevel_InitElements(&level, filename);
+
   ActivateLevelTemplate();
 }
 
@@ -889,7 +1058,13 @@ void LoadLevel(int level_nr)
   if (level.use_custom_template)
     LoadLevelTemplate(-1);
 
+#if 1
+  LoadLevel_InitVersion(&level, filename);
+  LoadLevel_InitElements(&level, filename);
+  LoadLevel_InitPlayfield(&level, filename);
+#else
   LoadLevel_InitLevel(&level, filename);
+#endif
 }
 
 static void SaveLevel_VERS(FILE *file, struct LevelInfo *level)
@@ -1890,8 +2065,9 @@ void SaveScore(int level_nr)
 #define SETUP_TOKEN_EDITOR_EL_DX_BOULDERDASH   6
 #define SETUP_TOKEN_EDITOR_EL_CHARS            7
 #define SETUP_TOKEN_EDITOR_EL_CUSTOM           8
+#define SETUP_TOKEN_EDITOR_EL_HEADLINES                9
 
-#define NUM_EDITOR_SETUP_TOKENS                        9
+#define NUM_EDITOR_SETUP_TOKENS                        10
 
 /* shortcut setup */
 #define SETUP_TOKEN_SHORTCUT_SAVE_GAME         0
@@ -1977,6 +2153,7 @@ static struct TokenInfo editor_setup_tokens[] =
   { TYPE_SWITCH, &sei.el_chars,                "editor.el_chars"               },
   { TYPE_SWITCH, &sei.el_custom,       "editor.el_custom"              },
   { TYPE_SWITCH, &sei.el_custom_more,  "editor.el_custom_more"         },
+  { TYPE_SWITCH, &sei.el_headlines,    "editor.el_headlines"           },
 };
 
 static struct TokenInfo shortcut_setup_tokens[] =
@@ -2074,6 +2251,8 @@ static void setSetupInfoToDefaults(struct SetupInfo *si)
   si->editor.el_custom = TRUE;
   si->editor.el_custom_more = FALSE;
 
+  si->editor.el_headlines = 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;