rocksndiamonds-3.3.0.0
[rocksndiamonds.git] / src / game_sp / file.c
index 26f74167920efe9d835a4d154e378fe919b37270..f841cf208ae9b43e839f5696229c23bf90672e68 100644 (file)
@@ -7,6 +7,12 @@
 /* functions for loading Supaplex level                                      */
 /* ------------------------------------------------------------------------- */
 
+void setTapeInfoToDefaults_SP()
+{
+  native_sp_level.demo.is_available = FALSE;
+  native_sp_level.demo.length = 0;
+}
+
 void setLevelInfoToDefaults_SP()
 {
   LevelInfoType *header = &native_sp_level.header;
@@ -49,8 +55,7 @@ void setLevelInfoToDefaults_SP()
   for (i = 0; i < SP_HEADER_SIZE; i++)
     native_sp_level.header_raw_bytes[i] = 0x20;
 
-  native_sp_level.demo.is_available = FALSE;
-  native_sp_level.demo.length = 0;
+  setTapeInfoToDefaults_SP();
 }
 
 void copyInternalEngineVars_SP()
@@ -107,10 +112,8 @@ void copyInternalEngineVars_SP()
   int count;
   int i, x, y;
 
-#if 1
   for (i = 0; preceding_playfield_memory[i] != NULL; i++)
     preceding_buffer_size += 8;                /* eight 16-bit integer values */
-#endif
 
   /* needed for engine snapshots */
   game_sp.preceding_buffer_size = preceding_buffer_size;
@@ -124,25 +127,15 @@ void copyInternalEngineVars_SP()
   FieldMax = (FieldWidth * FieldHeight) + HeaderSize - 1;
   LevelMax = (FieldWidth * FieldHeight) - 1;
 
-  FileMax = FieldMax + native_sp_level.demo.length;
-
-  PlayField8 = REDIM_1D(sizeof(byte), 0, FileMax + 1 - 1);
-  DisPlayField = REDIM_1D(sizeof(byte), 0, FieldMax + 1 - 1);
-#if 1
-  PlayField16 = REDIM_1D(sizeof(int), -preceding_buffer_size, FieldMax);
-#else
-  PlayField16 = REDIM_1D(sizeof(int), -FieldWidth, FieldMax);
-#endif
-
-#if 1
+  /* (add one byte for the level number stored as first byte of demo data) */
+  FileMax = FieldMax + native_sp_level.demo.length + 1;
 
 #if 0
-  /* fill preceding playfield buffer zone with (indestructible) "hardware" */
-  for (i = -FieldWidth; i < 0; i++)
-    PlayField16[i] = 0x20;
+  PlayField8 = REDIM_1D(sizeof(byte), 0, FileMax);
+  DisPlayField = REDIM_1D(sizeof(byte), 0, FieldMax);
+  PlayField16 = REDIM_1D(sizeof(int), -preceding_buffer_size, FieldMax);
 #endif
 
-#if 1
   count = 0;
   for (i = 0; preceding_playfield_memory[i] != NULL; i++)
   {
@@ -171,7 +164,6 @@ void copyInternalEngineVars_SP()
        s++;
     }
   }
-#endif
 
   count = 0;
   for (y = 0; y < native_sp_level.height; y++)
@@ -189,63 +181,25 @@ void copyInternalEngineVars_SP()
     PlayField8[i] = 0;
   }
 
-#if 0
-  {
-    static int x = 0;
-
-    if (x == 1)
-    {
-      printf("++++++++");
-      printf("----------\n");
-      for (i = 0; i < preceding_buffer_size + FieldMax; i++)
-      {
-       int x = PlayField16[-preceding_buffer_size + i];
-
-       printf("%c%c", x & 0xff, x >> 8);
-      }
-      printf("----------\n");
-      exit(0);
-    }
-
-    x++;
-  }
-#endif
-
-#else
-
-  for (i = 0; y = 0; y < native_sp_level.height; y++)
-  {
-    for (x = 0; x < native_sp_level.width; x++)
-    {
-      PlayField8[i] = native_sp_level.playfield[x][y];
-
-      PlayField16[i] = PlayField8[i];
-      DisPlayField[i] = PlayField8[i];
-      PlayField8[i] = 0;
-
-      i++;
-    }
-  }
-
-#endif
-
   if (native_sp_level.demo.is_available)
   {
     DemoAvailable = True;
 
+#if 0
+    /* !!! NEVER USED !!! */
     PlayField8[FieldMax + 1] = native_sp_level.demo.level_nr;
 
+    /* !!! NEVER USED !!! */
     for (i = 0; i < native_sp_level.demo.length; i++)
-      PlayField8[FieldMax + i + 2] = native_sp_level.demo.data[i];
+      PlayField8[FieldMax + 2 + i] = native_sp_level.demo.data[i];
+#endif
   }
 
+#if 0
   AnimationPosTable = REDIM_1D(sizeof(int), 0, LevelMax - 2 * FieldWidth);
   AnimationSubTable = REDIM_1D(sizeof(byte), 0, LevelMax - 2 * FieldWidth);
-  TerminalState = REDIM_1D(sizeof(byte), 0, FieldMax + 1 - 1);
-
-  DemoPointer = FieldMax + 1;
-  DemoOffset = DemoPointer;
-  DemoKeyRepeatCounter = 0;
+  TerminalState = REDIM_1D(sizeof(byte), 0, FieldMax);
+#endif
 
   GravityFlag = LInfo.InitialGravity;
   FreezeZonks = LInfo.InitialFreezeZonks;
@@ -253,13 +207,7 @@ void copyInternalEngineVars_SP()
 #if 1
   /* this is set by main game tape code to native random generator directly */
 #else
-
-#if 1
-  printf("::: file.c: copyInternalEngineVars_SP(): RandomSeed = LInfo.DemoRandomSeed\n");
-#endif
-
   RandomSeed = LInfo.DemoRandomSeed;
-
 #endif
 
   LevelLoaded = True;
@@ -274,13 +222,22 @@ static void LoadNativeLevelFromFileStream_SP(FILE *file, int width, int height,
   /* for details of the Supaplex level format, see Herman Perk's Supaplex
      documentation file "SPFIX63.DOC" from his Supaplex "SpeedFix" package */
 
-  native_sp_level.width  = width;
-  native_sp_level.height = height;
+  native_sp_level.width  = MIN(width,  SP_MAX_PLAYFIELD_WIDTH);
+  native_sp_level.height = MIN(height, SP_MAX_PLAYFIELD_HEIGHT);
 
   /* read level playfield (width * height == 60 * 24 tiles == 1440 bytes) */
-  for (y = 0; y < native_sp_level.height; y++)
-    for (x = 0; x < native_sp_level.width; x++)
-      native_sp_level.playfield[x][y] = getFile8Bit(file);
+  /* (MPX levels may have non-standard playfield size -- check max. size) */
+  for (y = 0; y < height; y++)
+  {
+    for (x = 0; x < width; x++)
+    {
+      byte element = getFile8Bit(file);
+
+      if (x < SP_MAX_PLAYFIELD_WIDTH &&
+         y < SP_MAX_PLAYFIELD_HEIGHT)
+       native_sp_level.playfield[x][y] = element;
+    }
+  }
 
   /* read level header (96 bytes) */
 
@@ -307,10 +264,6 @@ static void LoadNativeLevelFromFileStream_SP(FILE *file, int width, int height,
   /* number of special ("gravity") port entries below (maximum 10 allowed) */
   header->SpecialPortCount = getFile8Bit(file);
 
-#if 0
-  printf("::: num_special_ports == %d\n", header->SpecialPortCount);
-#endif
-
   /* database of properties of up to 10 special ports (6 bytes per port) */
   for (i = 0; i < SP_MAX_SPECIAL_PORTS; i++)
   {
@@ -323,16 +276,6 @@ static void LoadNativeLevelFromFileStream_SP(FILE *file, int width, int height,
        which is 2 bytes per tile) */
     port->PortLocation = getFile16BitBE(file);         /* yes, big endian */
 
-#if 0
-    {
-      int port_x = (port->PortLocation / 2) % SP_PLAYFIELD_WIDTH;
-      int port_y = (port->PortLocation / 2) / SP_PLAYFIELD_WIDTH;
-
-      printf("::: %d: port_location == %d => (%d, %d)\n",
-            i, port->PortLocation, port_x, port_y);
-    }
-#endif
-
     /* change gravity: 1 == "turn on", anything else (0) == "turn off" */
     port->Gravity = getFile8Bit(file);
 
@@ -353,11 +296,6 @@ static void LoadNativeLevelFromFileStream_SP(FILE *file, int width, int height,
 
   /* random seed used for recorded demos */
   header->DemoRandomSeed = getFile16BitLE(file);       /* yes, little endian */
-  // header->DemoRandomSeed = getFile16BitBE(file);    /* !!! TEST ONLY !!! */
-
-#if 0
-  printf("::: file.c: DemoRandomSeed == %d\n", header->DemoRandomSeed);
-#endif
 
   /* auto-determine number of infotrons if it was stored as "0" -- see above */
   if (header->InfotronsNeeded == 0)
@@ -659,3 +597,64 @@ boolean LoadNativeLevel_SP(char *filename, int level_pos)
 
   return TRUE;
 }
+
+void SaveNativeLevel_SP(char *filename)
+{
+  LevelInfoType *header = &native_sp_level.header;
+  FILE *file;
+  int i, x, y;
+
+  if (!(file = fopen(filename, MODE_WRITE)))
+  {
+    Error(ERR_WARN, "cannot save native level file '%s'", filename);
+
+    return;
+  }
+
+  /* write level playfield (width * height == 60 * 24 tiles == 1440 bytes) */
+  for (y = 0; y < native_sp_level.height; y++)
+    for (x = 0; x < native_sp_level.width; x++)
+      putFile8Bit(file, native_sp_level.playfield[x][y]);
+
+  /* write level header (96 bytes) */
+
+  WriteUnusedBytesToFile(file, 4);
+
+  putFile8Bit(file, header->InitialGravity);
+  putFile8Bit(file, header->Version);
+
+  for (i = 0; i < SP_LEVEL_NAME_LEN; i++)
+    putFile8Bit(file, header->LevelTitle[i]);
+
+  putFile8Bit(file, header->InitialFreezeZonks);
+  putFile8Bit(file, header->InfotronsNeeded);
+  putFile8Bit(file, header->SpecialPortCount);
+
+  for (i = 0; i < SP_MAX_SPECIAL_PORTS; i++)
+  {
+    SpecialPortType *port = &header->SpecialPort[i];
+
+    putFile16BitBE(file, port->PortLocation);
+    putFile8Bit(file, port->Gravity);
+    putFile8Bit(file, port->FreezeZonks);
+    putFile8Bit(file, port->FreezeEnemies);
+
+    WriteUnusedBytesToFile(file, 1);
+  }
+
+  putFile8Bit(file, header->SpeedByte);
+  putFile8Bit(file, header->CheckSumByte);
+  putFile16BitLE(file, header->DemoRandomSeed);
+
+  /* also save demo tape, if available */
+
+  if (native_sp_level.demo.is_available)
+  {
+    putFile8Bit(file, native_sp_level.demo.level_nr);
+
+    for (i = 0; i < native_sp_level.demo.length; i++)
+      putFile8Bit(file, native_sp_level.demo.data[i]);
+  }
+
+  fclose(file);
+}