rnd-19990220-1-src
[rocksndiamonds.git] / src / files.c
index c8eaa4b92e07aa7cf68a2f583bfb3001807cf454..34c53f77c97c76deb60b5cf7c1cfc0b993dc8d17 100644 (file)
@@ -26,7 +26,7 @@
 #define MAX_LINE_LEN           1000    /* maximal input line length */
 #define CHUNK_ID_LEN           4       /* IFF style chunk id length */
 #define LEVEL_HEADER_SIZE      80      /* size of level file header */
-#define LEVEL_HEADER_UNUSED    17      /* unused level header bytes */
+#define LEVEL_HEADER_UNUSED    16      /* unused level header bytes */
 #define TAPE_HEADER_SIZE       20      /* size of tape file header */
 #define TAPE_HEADER_UNUSED     7       /* unused tape header bytes */
 #define FILE_VERSION_1_0       10      /* old 1.0 file version */
                         IS_LEVELCLASS_USER(n) ? LEVELCLASS_USER : \
                         LEVELCLASS_UNDEFINED)
 
+#define LEVELCOLOR(n)  (IS_LEVELCLASS_TUTORIAL(n) ? FC_BLUE : \
+                        IS_LEVELCLASS_CLASSICS(n) ? FC_YELLOW : \
+                        IS_LEVELCLASS_CONTRIBUTION(n) ? FC_GREEN : \
+                        IS_LEVELCLASS_USER(n) ? FC_RED : FC_BLUE)
+
 static void SaveUserLevelInfo();               /* for 'InitUserLevelDir()' */
 static char *getSetupLine(char *, int);                /* for 'SaveUserLevelInfo()' */
 
@@ -270,27 +275,6 @@ static void InitUserLevelDirectory(char *level_subdir)
   }
 }
 
-static void getFileChunk(FILE *file, char *chunk_buffer, int *chunk_length)
-{
-  fgets(chunk_buffer, CHUNK_ID_LEN + 1, file);
-
-  *chunk_length =
-    (fgetc(file) << 24) |
-    (fgetc(file) << 16) |
-    (fgetc(file) <<  8)  |
-    (fgetc(file) <<  0);
-}
-
-static void putFileChunk(FILE *file, char *chunk_name, int chunk_length)
-{
-  fputs(chunk_name, file);
-
-  fputc((chunk_length >> 24) & 0xff, file);
-  fputc((chunk_length >> 16) & 0xff, file);
-  fputc((chunk_length >>  8) & 0xff, file);
-  fputc((chunk_length >>  0) & 0xff, file);
-}
-
 static void setLevelInfoToDefaults()
 {
   int i, x, y;
@@ -303,12 +287,13 @@ static void setLevelInfoToDefaults()
       Feld[x][y] = Ur[x][y] = EL_ERDREICH;
 
   level.time = 100;
-  level.edelsteine = 0;
-  level.tempo_amoebe = 10;
-  level.dauer_sieb = 10;
-  level.dauer_ablenk = 10;
-  level.amoebe_inhalt = EL_DIAMANT;
+  level.gems_needed = 0;
+  level.amoeba_speed = 10;
+  level.time_magic_wall = 10;
+  level.time_wheel = 10;
+  level.amoeba_content = EL_DIAMANT;
   level.double_speed = FALSE;
+  level.gravity = FALSE;
 
   for(i=0; i<MAX_LEVEL_NAME_LEN; i++)
     level.name[i] = '\0';
@@ -321,11 +306,11 @@ static void setLevelInfoToDefaults()
   for(i=0; i<LEVEL_SCORE_ELEMENTS; i++)
     level.score[i] = 10;
 
-  MampferMax = 4;
-  for(i=0; i<8; i++)
+  level.num_yam_contents = STD_ELEMENT_CONTENTS;
+  for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
     for(x=0; x<3; x++)
       for(y=0; y<3; y++)
-       level.mampfer_inhalt[i][x][y] = EL_FELSBROCKEN;
+       level.yam_content[i][x][y] = EL_FELSBROCKEN;
 
   Feld[0][0] = Ur[0][0] = EL_SPIELFIGUR;
   Feld[STD_LEV_FIELDX-1][STD_LEV_FIELDY-1] =
@@ -400,7 +385,7 @@ void LoadLevel(int level_nr)
   /* read chunk "HEAD" */
   if (file_version >= FILE_VERSION_1_2)
   {
-    getFileChunk(file, chunk, &chunk_length);
+    getFileChunk(file, chunk, &chunk_length, BYTE_ORDER_BIG_ENDIAN);
     if (strcmp(chunk, "HEAD") || chunk_length != LEVEL_HEADER_SIZE)
     {
       Error(ERR_WARN, "wrong 'HEAD' chunk of level file '%s'", filename);
@@ -412,36 +397,37 @@ void LoadLevel(int level_nr)
   lev_fieldx = level.fieldx = fgetc(file);
   lev_fieldy = level.fieldy = fgetc(file);
 
-  level.time           = (fgetc(file)<<8) | fgetc(file);
-  level.edelsteine     = (fgetc(file)<<8) | fgetc(file);
+  level.time        = getFile16BitInteger(file, BYTE_ORDER_BIG_ENDIAN);
+  level.gems_needed = getFile16BitInteger(file, BYTE_ORDER_BIG_ENDIAN);
 
   for(i=0; i<MAX_LEVEL_NAME_LEN; i++)
-    level.name[i]      = fgetc(file);
+    level.name[i] = fgetc(file);
   level.name[MAX_LEVEL_NAME_LEN] = 0;
 
   for(i=0; i<LEVEL_SCORE_ELEMENTS; i++)
-    level.score[i]     = fgetc(file);
+    level.score[i] = fgetc(file);
 
-  MampferMax = 4;
-  for(i=0; i<8; i++)
+  level.num_yam_contents = STD_ELEMENT_CONTENTS;
+  for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
   {
     for(y=0; y<3; y++)
     {
       for(x=0; x<3; x++)
       {
-       if (i < 4)
-         level.mampfer_inhalt[i][x][y] = fgetc(file);
+       if (i < STD_ELEMENT_CONTENTS)
+         level.yam_content[i][x][y] = fgetc(file);
        else
-         level.mampfer_inhalt[i][x][y] = EL_LEERRAUM;
+         level.yam_content[i][x][y] = EL_LEERRAUM;
       }
     }
   }
 
-  level.tempo_amoebe   = fgetc(file);
-  level.dauer_sieb     = fgetc(file);
-  level.dauer_ablenk   = fgetc(file);
-  level.amoebe_inhalt  = fgetc(file);
+  level.amoeba_speed   = fgetc(file);
+  level.time_magic_wall        = fgetc(file);
+  level.time_wheel     = fgetc(file);
+  level.amoeba_content = fgetc(file);
   level.double_speed   = (fgetc(file) == 1 ? TRUE : FALSE);
+  level.gravity                = (fgetc(file) == 1 ? TRUE : FALSE);
 
   for(i=0; i<LEVEL_HEADER_UNUSED; i++) /* skip unused header bytes */
     fgetc(file);
@@ -449,7 +435,7 @@ void LoadLevel(int level_nr)
   /* read chunk "BODY" */
   if (file_version >= FILE_VERSION_1_2)
   {
-    getFileChunk(file, chunk, &chunk_length);
+    getFileChunk(file, chunk, &chunk_length, BYTE_ORDER_BIG_ENDIAN);
 
     /* look for optional author chunk */
     if (strcmp(chunk, "AUTH") == 0 && chunk_length == MAX_LEVEL_AUTHOR_LEN)
@@ -458,23 +444,24 @@ void LoadLevel(int level_nr)
        level.author[i] = fgetc(file);
       level.author[MAX_LEVEL_NAME_LEN] = 0;
 
-      getFileChunk(file, chunk, &chunk_length);
+      getFileChunk(file, chunk, &chunk_length, BYTE_ORDER_BIG_ENDIAN);
     }
 
     /* look for optional content chunk */
-    if (strcmp(chunk, "CONT") == 0 && chunk_length == 4 + 8 * 3 * 3)
+    if (strcmp(chunk, "CONT") == 0 &&
+       chunk_length == 4 + MAX_ELEMENT_CONTENTS * 3 * 3)
     {
       fgetc(file);
-      MampferMax = fgetc(file);
+      level.num_yam_contents = fgetc(file);
       fgetc(file);
       fgetc(file);
 
-      for(i=0; i<8; i++)
+      for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
        for(y=0; y<3; y++)
          for(x=0; x<3; x++)
-           level.mampfer_inhalt[i][x][y] = fgetc(file);
+           level.yam_content[i][x][y] = fgetc(file);
 
-      getFileChunk(file, chunk, &chunk_length);
+      getFileChunk(file, chunk, &chunk_length, BYTE_ORDER_BIG_ENDIAN);
     }
 
     /* next check body chunk identifier and chunk length */
@@ -506,6 +493,9 @@ void LoadLevel(int level_nr)
     Error(ERR_WARN, "using high speed movement for player");
     level.double_speed = TRUE;
   }
+
+  /* determine border element for this level */
+  SetBorderElement();
 }
 
 void SaveLevel(int level_nr)
@@ -523,50 +513,51 @@ void SaveLevel(int level_nr)
   fputs(LEVEL_COOKIE, file);           /* file identifier */
   fputc('\n', file);
 
-  putFileChunk(file, "HEAD", LEVEL_HEADER_SIZE);
+  putFileChunk(file, "HEAD", LEVEL_HEADER_SIZE, BYTE_ORDER_BIG_ENDIAN);
 
   fputc(level.fieldx, file);
   fputc(level.fieldy, file);
-  fputc(level.time / 256, file);
-  fputc(level.time % 256, file);
-  fputc(level.edelsteine / 256, file);
-  fputc(level.edelsteine % 256, file);
+
+  putFile16BitInteger(file, level.time, BYTE_ORDER_BIG_ENDIAN);
+  putFile16BitInteger(file, level.gems_needed, BYTE_ORDER_BIG_ENDIAN);
 
   for(i=0; i<MAX_LEVEL_NAME_LEN; i++)
     fputc(level.name[i], file);
   for(i=0; i<LEVEL_SCORE_ELEMENTS; i++)
     fputc(level.score[i], file);
-  for(i=0; i<4; i++)
+  for(i=0; i<STD_ELEMENT_CONTENTS; i++)
     for(y=0; y<3; y++)
       for(x=0; x<3; x++)
-       fputc(level.mampfer_inhalt[i][x][y], file);
-  fputc(level.tempo_amoebe, file);
-  fputc(level.dauer_sieb, file);
-  fputc(level.dauer_ablenk, file);
-  fputc(level.amoebe_inhalt, file);
+       fputc(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.amoeba_content, file);
   fputc((level.double_speed ? 1 : 0), file);
+  fputc((level.gravity ? 1 : 0), file);
 
   for(i=0; i<LEVEL_HEADER_UNUSED; i++) /* set unused header bytes to zero */
     fputc(0, file);
 
-  putFileChunk(file, "AUTH", MAX_LEVEL_AUTHOR_LEN);
+  putFileChunk(file, "AUTH", MAX_LEVEL_AUTHOR_LEN, BYTE_ORDER_BIG_ENDIAN);
 
   for(i=0; i<MAX_LEVEL_AUTHOR_LEN; i++)
     fputc(level.author[i], file);
 
-  putFileChunk(file, "CONT", 4 + 8 * 3 * 3);
+  putFileChunk(file, "CONT", 4 + MAX_ELEMENT_CONTENTS * 3 * 3,
+              BYTE_ORDER_BIG_ENDIAN);
 
   fputc(EL_MAMPFER, file);
-  fputc(MampferMax, file);
+  fputc(level.num_yam_contents, file);
   fputc(0, file);
   fputc(0, file);
 
-  for(i=0; i<8; i++)
+  for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
     for(y=0; y<3; y++)
       for(x=0; x<3; x++)
-       fputc(level.mampfer_inhalt[i][x][y], file);
+       fputc(level.yam_content[i][x][y], file);
 
-  putFileChunk(file, "BODY", lev_fieldx * lev_fieldy);
+  putFileChunk(file, "BODY", lev_fieldx * lev_fieldy, BYTE_ORDER_BIG_ENDIAN);
 
   for(y=0; y<lev_fieldy; y++) 
     for(x=0; x<lev_fieldx; x++) 
@@ -619,11 +610,7 @@ void LoadTape(int level_nr)
   /* read chunk "HEAD" */
   if (file_version >= FILE_VERSION_1_2)
   {
-    /* first check header chunk identifier and chunk length */
-    fgets(chunk, CHUNK_ID_LEN + 1, file);
-    chunk_length =
-      (fgetc(file)<<24) | (fgetc(file)<<16) | (fgetc(file)<<8) | fgetc(file);
-
+    getFileChunk(file, chunk, &chunk_length, BYTE_ORDER_BIG_ENDIAN);
     if (strcmp(chunk, "HEAD") || chunk_length != TAPE_HEADER_SIZE)
     {
       Error(ERR_WARN, "wrong 'HEAD' chunk of tape file '%s'", filename);
@@ -632,12 +619,9 @@ void LoadTape(int level_nr)
     }
   }
 
-  tape.random_seed =
-    (fgetc(file)<<24) | (fgetc(file)<<16) | (fgetc(file)<<8) | fgetc(file);
-  tape.date =
-    (fgetc(file)<<24) | (fgetc(file)<<16) | (fgetc(file)<<8) | fgetc(file);
-  tape.length =
-    (fgetc(file)<<24) | (fgetc(file)<<16) | (fgetc(file)<<8) | fgetc(file);
+  tape.random_seed = getFile32BitInteger(file, BYTE_ORDER_BIG_ENDIAN);
+  tape.date        = getFile32BitInteger(file, BYTE_ORDER_BIG_ENDIAN);
+  tape.length      = getFile32BitInteger(file, BYTE_ORDER_BIG_ENDIAN);
 
   /* read header fields that are new since version 1.2 */
   if (file_version >= FILE_VERSION_1_2)
@@ -672,10 +656,7 @@ void LoadTape(int level_nr)
   /* read chunk "BODY" */
   if (file_version >= FILE_VERSION_1_2)
   {
-    /* next check body chunk identifier and chunk length */
-    fgets(chunk, CHUNK_ID_LEN + 1, file);
-    chunk_length =
-      (fgetc(file)<<24) | (fgetc(file)<<16) | (fgetc(file)<<8) | fgetc(file);
+    getFileChunk(file, chunk, &chunk_length, BYTE_ORDER_BIG_ENDIAN);
     if (strcmp(chunk, "BODY") ||
        chunk_length != (num_participating_players + 1) * tape.length)
     {
@@ -748,7 +729,6 @@ void SaveTape(int level_nr)
   boolean new_tape = TRUE;
   byte store_participating_players;
   int num_participating_players;
-  int chunk_length;
 
   InitTapeDirectory(leveldir[leveldir_nr].filename);
 
@@ -781,42 +761,19 @@ void SaveTape(int level_nr)
   fputs(TAPE_COOKIE, file);            /* file identifier */
   fputc('\n', file);
 
-  fputs("HEAD", file);                 /* chunk identifier for file header */
-
-  chunk_length = TAPE_HEADER_SIZE;
+  putFileChunk(file, "HEAD", TAPE_HEADER_SIZE, BYTE_ORDER_BIG_ENDIAN);
 
-  fputc((chunk_length >>  24) & 0xff, file);
-  fputc((chunk_length >>  16) & 0xff, file);
-  fputc((chunk_length >>   8) & 0xff, file);
-  fputc((chunk_length >>   0) & 0xff, file);
-
-  fputc((tape.random_seed >> 24) & 0xff, file);
-  fputc((tape.random_seed >> 16) & 0xff, file);
-  fputc((tape.random_seed >>  8) & 0xff, file);
-  fputc((tape.random_seed >>  0) & 0xff, file);
-
-  fputc((tape.date >>  24) & 0xff, file);
-  fputc((tape.date >>  16) & 0xff, file);
-  fputc((tape.date >>   8) & 0xff, file);
-  fputc((tape.date >>   0) & 0xff, file);
-
-  fputc((tape.length >>  24) & 0xff, file);
-  fputc((tape.length >>  16) & 0xff, file);
-  fputc((tape.length >>   8) & 0xff, file);
-  fputc((tape.length >>   0) & 0xff, file);
+  putFile32BitInteger(file, tape.random_seed, BYTE_ORDER_BIG_ENDIAN);
+  putFile32BitInteger(file, tape.date, BYTE_ORDER_BIG_ENDIAN);
+  putFile32BitInteger(file, tape.length, BYTE_ORDER_BIG_ENDIAN);
 
   fputc(store_participating_players, file);
 
   for(i=0; i<TAPE_HEADER_UNUSED; i++)  /* set unused header bytes to zero */
     fputc(0, file);
 
-  fputs("BODY", file);                 /* chunk identifier for file body */
-  chunk_length = (num_participating_players + 1) * tape.length;
-
-  fputc((chunk_length >>  24) & 0xff, file);
-  fputc((chunk_length >>  16) & 0xff, file);
-  fputc((chunk_length >>   8) & 0xff, file);
-  fputc((chunk_length >>   0) & 0xff, file);
+  putFileChunk(file, "BODY", (num_participating_players + 1) * tape.length,
+              BYTE_ORDER_BIG_ENDIAN);
 
   for(i=0; i<tape.length; i++)
   {
@@ -1198,7 +1155,7 @@ static struct SetupFileList *loadSetupFileList(char *filename)
     /* cut trailing comment or whitespace from input line */
     for (line_ptr = line; *line_ptr; line_ptr++)
     {
-      if (*line_ptr == '#' || *line_ptr == '\n')
+      if (*line_ptr == '#' || *line_ptr == '\n' || *line_ptr == '\r')
       {
        *line_ptr = '\0';
        break;
@@ -1516,6 +1473,7 @@ static int LoadLevelInfoFromLevelDir(char *level_directory, int start_entry)
        leveldir[current_entry].levels - 1;
       leveldir[current_entry].user_defined =
        (level_directory == options.level_directory ? FALSE : TRUE);
+      leveldir[current_entry].color = LEVELCOLOR(current_entry);
 
       freeSetupFileList(setup_file_list);
       current_entry++;