rnd-20030102-2-src
[rocksndiamonds.git] / src / files.c
index b3557c182e235d2e41127d1f95520771dbc5b1fa..fad45178abaf3bf6c61eb9567df2b2e97bdd5dc9 100644 (file)
@@ -1,7 +1,7 @@
 /***********************************************************
 * Rocks'n'Diamonds -- McDuffin Strikes Back!               *
 *----------------------------------------------------------*
-* (c) 1995-2001 Artsoft Entertainment                      *
+* (c) 1995-2002 Artsoft Entertainment                      *
 *               Holger Schemel                             *
 *               Detmolder Strasse 189                      *
 *               33604 Bielefeld                            *
@@ -30,7 +30,7 @@
 #define LEVEL_CHUNK_CNT2_SIZE  160     /* size of level CNT2 chunk   */
 #define LEVEL_CHUNK_CNT2_UNUSED        11      /* unused CNT2 chunk bytes    */
 #define TAPE_HEADER_SIZE       20      /* size of tape file header   */
-#define TAPE_HEADER_UNUSED     7       /* unused tape header bytes   */
+#define TAPE_HEADER_UNUSED     3       /* unused tape header bytes   */
 
 /* file identifier strings */
 #define LEVEL_COOKIE_TMPL      "ROCKSNDIAMONDS_LEVEL_FILE_VERSION_x.x"
@@ -58,7 +58,7 @@ static void setLevelInfoToDefaults()
 
   for(x=0; x<MAX_LEV_FIELDX; x++)
     for(y=0; y<MAX_LEV_FIELDY; y++)
-      Feld[x][y] = Ur[x][y] = EL_ERDREICH;
+      Feld[x][y] = Ur[x][y] = EL_SAND;
 
   level.time = 100;
   level.gems_needed = 0;
@@ -67,7 +67,7 @@ static void setLevelInfoToDefaults()
   level.time_wheel = 10;
   level.time_light = 10;
   level.time_timegate = 10;
-  level.amoeba_content = EL_DIAMANT;
+  level.amoeba_content = EL_DIAMOND;
   level.double_speed = FALSE;
   level.gravity = FALSE;
   level.em_slippery_gems = FALSE;
@@ -88,13 +88,13 @@ static void setLevelInfoToDefaults()
     for(x=0; x<3; x++)
       for(y=0; y<3; y++)
        level.yam_content[i][x][y] =
-         (i < STD_ELEMENT_CONTENTS ? EL_FELSBROCKEN : EL_LEERRAUM);
+         (i < STD_ELEMENT_CONTENTS ? EL_ROCK : EL_EMPTY);
 
-  Feld[0][0] = Ur[0][0] = EL_SPIELFIGUR;
+  Feld[0][0] = Ur[0][0] = EL_PLAYER1;
   Feld[STD_LEV_FIELDX-1][STD_LEV_FIELDY-1] =
-    Ur[STD_LEV_FIELDX-1][STD_LEV_FIELDY-1] = EL_AUSGANG_ZU;
+    Ur[STD_LEV_FIELDX-1][STD_LEV_FIELDY-1] = EL_EXIT_CLOSED;
 
-  BorderElement = EL_BETON;
+  BorderElement = EL_STEELWALL;
 
   /* try to determine better author name than 'anonymous' */
   if (strcmp(leveldir_current->author, ANONYMOUS_NAME) != 0)
@@ -125,22 +125,29 @@ static void setLevelInfoToDefaults()
        break;
     }
   }
+
+  level.no_level_file = FALSE;
 }
 
 static int checkLevelElement(int element)
 {
-  if (element >= EL_FIRST_RUNTIME_EL)
+  if (element >= NUM_FILE_ELEMENTS)
   {
     Error(ERR_WARN, "invalid level element %d", element);
-    element = EL_CHAR_FRAGE;
+    element = EL_CHAR_QUESTION;
   }
+  else if (element == EL_PLAYER_OBSOLETE)
+    element = EL_PLAYER1;
+  else if (element == EL_KEY_OBSOLETE)
+    element = EL_KEY1;
 
   return element;
 }
 
 static int LoadLevel_VERS(FILE *file, int chunk_size, struct LevelInfo *level)
 {
-  ReadChunk_VERS(file, &(level->file_version), &(level->game_version));
+  level->file_version = getFileVersion(file);
+  level->game_version = getFileVersion(file);
 
   return chunk_size;
 }
@@ -282,7 +289,7 @@ static int LoadLevel_CNT2(FILE *file, int chunk_size, struct LevelInfo *level)
   if (num_contents < 1 || num_contents > MAX_ELEMENT_CONTENTS)
     num_contents = STD_ELEMENT_CONTENTS;
 
-  if (element == EL_MAMPFER)
+  if (element == EL_YAMYAM)
   {
     level->num_yam_contents = num_contents;
 
@@ -291,7 +298,7 @@ static int LoadLevel_CNT2(FILE *file, int chunk_size, struct LevelInfo *level)
        for(x=0; x<3; x++)
          level->yam_content[i][x][y] = content_array[i][x][y];
   }
-  else if (element == EL_AMOEBE_BD)
+  else if (element == EL_BD_AMOEBA)
   {
     level->amoeba_content = content_array[0][0][0];
   }
@@ -316,6 +323,8 @@ void LoadLevel(int level_nr)
 
   if (!(file = fopen(filename, MODE_READ)))
   {
+    level.no_level_file = TRUE;
+
     Error(ERR_WARN, "cannot read level '%s' - creating new level", filename);
     return;
   }
@@ -475,6 +484,12 @@ void LoadLevel(int level_nr)
   SetBorderElement();
 }
 
+static void SaveLevel_VERS(FILE *file, struct LevelInfo *level)
+{
+  putFileVersion(file, level->file_version);
+  putFileVersion(file, level->game_version);
+}
+
 static void SaveLevel_HEAD(FILE *file, struct LevelInfo *level)
 {
   int i, x, y;
@@ -494,13 +509,13 @@ static void SaveLevel_HEAD(FILE *file, struct LevelInfo *level)
   for(i=0; i<STD_ELEMENT_CONTENTS; i++)
     for(y=0; y<3; y++)
       for(x=0; x<3; x++)
-       fputc((level->encoding_16bit_yamyam ? EL_LEERRAUM :
+       fputc((level->encoding_16bit_yamyam ? EL_EMPTY :
               level->yam_content[i][x][y]),
              file);
   fputc(level->amoeba_speed, file);
   fputc(level->time_magic_wall, file);
   fputc(level->time_wheel, file);
-  fputc((level->encoding_16bit_amoeba ? EL_LEERRAUM : level->amoeba_content),
+  fputc((level->encoding_16bit_amoeba ? EL_EMPTY : level->amoeba_content),
        file);
   fputc((level->double_speed ? 1 : 0), file);
   fputc((level->gravity ? 1 : 0), file);
@@ -523,7 +538,7 @@ static void SaveLevel_CONT(FILE *file, struct LevelInfo *level)
 {
   int i, x, y;
 
-  fputc(EL_MAMPFER, file);
+  fputc(EL_YAMYAM, file);
   fputc(level->num_yam_contents, file);
   fputc(0, file);
   fputc(0, file);
@@ -556,7 +571,7 @@ static void SaveLevel_CNT2(FILE *file, struct LevelInfo *level, int element)
   int num_contents, content_xsize, content_ysize;
   int content_array[MAX_ELEMENT_CONTENTS][3][3];
 
-  if (element == EL_MAMPFER)
+  if (element == EL_YAMYAM)
   {
     num_contents = level->num_yam_contents;
     content_xsize = 3;
@@ -567,7 +582,7 @@ static void SaveLevel_CNT2(FILE *file, struct LevelInfo *level, int element)
        for(x=0; x<3; x++)
          content_array[i][x][y] = level->yam_content[i][x][y];
   }
-  else if (element == EL_AMOEBE_BD)
+  else if (element == EL_BD_AMOEBA)
   {
     num_contents = 1;
     content_xsize = 1;
@@ -576,7 +591,7 @@ static void SaveLevel_CNT2(FILE *file, struct LevelInfo *level, int element)
     for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
       for(y=0; y<3; y++)
        for(x=0; x<3; x++)
-         content_array[i][x][y] = EL_LEERRAUM;
+         content_array[i][x][y] = EL_EMPTY;
     content_array[0][0][0] = level->amoeba_content;
   }
   else
@@ -614,6 +629,8 @@ void SaveLevel(int level_nr)
     return;
   }
 
+  level.file_version = FILE_VERSION_ACTUAL;
+  level.game_version = GAME_VERSION_ACTUAL;
 
   /* check level field for 16-bit elements */
   level.encoding_16bit_field = FALSE;
@@ -642,7 +659,7 @@ void SaveLevel(int level_nr)
   putFileChunkBE(file, "CAVE", CHUNK_SIZE_NONE);
 
   putFileChunkBE(file, "VERS", FILE_VERS_CHUNK_SIZE);
-  WriteChunk_VERS(file, FILE_VERSION_ACTUAL, GAME_VERSION_ACTUAL);
+  SaveLevel_VERS(file, &level);
 
   putFileChunkBE(file, "HEAD", LEVEL_HEADER_SIZE);
   SaveLevel_HEAD(file, &level);
@@ -657,13 +674,13 @@ void SaveLevel(int level_nr)
       level.num_yam_contents != STD_ELEMENT_CONTENTS)
   {
     putFileChunkBE(file, "CNT2", LEVEL_CHUNK_CNT2_SIZE);
-    SaveLevel_CNT2(file, &level, EL_MAMPFER);
+    SaveLevel_CNT2(file, &level, EL_YAMYAM);
   }
 
   if (level.encoding_16bit_amoeba)
   {
     putFileChunkBE(file, "CNT2", LEVEL_CHUNK_CNT2_SIZE);
-    SaveLevel_CNT2(file, &level, EL_AMOEBE_BD);
+    SaveLevel_CNT2(file, &level, EL_BD_AMOEBA);
   }
 
   fclose(file);
@@ -681,8 +698,6 @@ static void setTapeInfoToDefaults()
   int i;
 
   /* always start with reliable default values (empty tape) */
-  tape.file_version = FILE_VERSION_ACTUAL;
-  tape.game_version = GAME_VERSION_ACTUAL;
   TapeErase();
 
   /* default values (also for pre-1.2 tapes) with only the first player */
@@ -704,7 +719,8 @@ static void setTapeInfoToDefaults()
 
 static int LoadTape_VERS(FILE *file, int chunk_size, struct TapeInfo *tape)
 {
-  ReadChunk_VERS(file, &(tape->file_version), &(tape->game_version));
+  tape->file_version = getFileVersion(file);
+  tape->game_version = getFileVersion(file);
 
   return chunk_size;
 }
@@ -721,8 +737,7 @@ static int LoadTape_HEAD(FILE *file, int chunk_size, struct TapeInfo *tape)
   if (tape->file_version >= FILE_VERSION_1_2)
   {
     byte store_participating_players = fgetc(file);
-
-    ReadUnusedBytesFromFile(file, TAPE_HEADER_UNUSED);
+    int engine_version;
 
     /* since version 1.2, tapes store which players participate in the tape */
     tape->num_participating_players = 0;
@@ -736,6 +751,12 @@ static int LoadTape_HEAD(FILE *file, int chunk_size, struct TapeInfo *tape)
        tape->num_participating_players++;
       }
     }
+
+    ReadUnusedBytesFromFile(file, TAPE_HEADER_UNUSED);
+
+    engine_version = getFileVersion(file);
+    if (engine_version > 0)
+      tape->engine_version = engine_version;
   }
 
   return chunk_size;
@@ -825,9 +846,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;
@@ -943,6 +963,19 @@ 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);
+  putFileVersion(file, tape->game_version);
+}
+
 static void SaveTape_HEAD(FILE *file, struct TapeInfo *tape)
 {
   int i;
@@ -959,7 +992,10 @@ static void SaveTape_HEAD(FILE *file, struct TapeInfo *tape)
 
   fputc(store_participating_players, file);
 
+  /* unused bytes not at the end here for 4-byte alignment of engine_version */
   WriteUnusedBytesToFile(file, TAPE_HEADER_UNUSED);
+
+  putFileVersion(file, tape->engine_version);
 }
 
 static void SaveTape_BODY(FILE *file, struct TapeInfo *tape)
@@ -1001,6 +1037,9 @@ void SaveTape(int level_nr)
     return;
   }
 
+  tape.file_version = FILE_VERSION_ACTUAL;
+  tape.game_version = GAME_VERSION_ACTUAL;
+
   /* count number of participating players  */
   for(i=0; i<MAX_PLAYERS; i++)
     if (tape.player_participates[i])
@@ -1012,7 +1051,7 @@ void SaveTape(int level_nr)
   putFileChunkBE(file, "TAPE", CHUNK_SIZE_NONE);
 
   putFileChunkBE(file, "VERS", FILE_VERS_CHUNK_SIZE);
-  WriteChunk_VERS(file, FILE_VERSION_ACTUAL, GAME_VERSION_ACTUAL);
+  SaveTape_VERS(file, &tape);
 
   putFileChunkBE(file, "HEAD", TAPE_HEADER_SIZE);
   SaveTape_HEAD(file, &tape);
@@ -1040,17 +1079,18 @@ 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 %d (file version %06d, game version %06d)\n",
         tape->level_nr, tape->file_version, tape->game_version);
-  printf("-------------------------------------------------------------------------------\n");
+  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])
@@ -1071,7 +1111,7 @@ void DumpTape(struct TapeInfo *tape)
     printf("(%03d)\n", tape->pos[i].delay);
   }
 
-  printf("-------------------------------------------------------------------------------\n");
+  printf_line('-', 79);
 }