/* 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;
char *empty_title = "-------- EMPTY --------";
int i, x, y;
- native_sp_level.width = SP_PLAYFIELD_WIDTH;
- native_sp_level.height = SP_PLAYFIELD_HEIGHT;
+ native_sp_level.game_sp = &game_sp;
+
+ native_sp_level.width = SP_STD_PLAYFIELD_WIDTH;
+ native_sp_level.height = SP_STD_PLAYFIELD_HEIGHT;
for (x = 0; x < native_sp_level.width; x++)
for (y = 0; y < native_sp_level.height; y++)
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()
{
- char *preceding_playfield_memory[] =
- {
- "95 89 95 89 95 89 3b 8a 3b 8a 3b 8a 3b 8a 3b 8a", // |......;.;.;.;.;.|
- "3b 8a 3b 8a 3b 8a e8 8a e8 8a e8 8a e8 8a e8 8a", // |;.;.;.è.è.è.è.è.|
- "e8 8a e8 8a e8 8a b1 8b b1 8b b1 8b b1 8b b1 8b", // |è.è.è.±.±.±.±.±.|
- "b1 8b b1 8b b1 8b 85 8c 85 8c 85 8c 85 8c 85 8c", // |±.±.±...........|
- "85 8c 85 8c 85 8c 5b 8d 5b 8d 5b 8d 5b 8d 5b 8d", // |......[.[.[.[.[.|
- "5b 8d 5b 8d 5b 8d 06 8e 06 8e 06 8e 06 8e 06 8e", // |[.[.[...........|
- "06 8e 06 8e 06 8e ac 8e ac 8e ac 8e ac 8e ac 8e", // |......¬.¬.¬.¬.¬.|
- "ac 8e ac 8e ac 8e 59 8f 59 8f 59 8f 59 8f 59 8f", // |¬.¬.¬.Y.Y.Y.Y.Y.|
- "59 8f 59 8f 59 8f 00 00 70 13 00 00 00 00 e8 17", // |Y.Y.Y...p.....è.|
- "00 00 00 00 00 00 69 38 00 00 00 00 00 00 00 00", // |......i8........|
- "00 00 00 00 00 00 00 00 d0 86 00 00 b2 34 00 00", // |........Ð...²4..|
- "00 00 00 00 00 00 8f 8b 1d 34 00 00 00 00 00 00", // |.........4......|
- "00 00 00 00 23 39 09 09 00 0c 00 08 00 58 00 00", // |....#9.......X..|
- "00 00 00 25 77 06 7f 00 00 00 01 00 00 00 00 00", // |...%w...........|
- "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................|
- "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................|
- "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................|
- "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................|
- "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................|
- "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................|
- "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................|
- "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................|
- "00 00 00 00 00 00 00 00 00 ec 06 26 05 00 00 00", // |.........ì.&....|
- "00 00 00 01 00 00 00 00 31 32 33 34 35 36 37 38", // |........12345678|
- "39 30 2d 00 08 00 51 57 45 52 54 59 55 49 4f 50", // |90-...QWERTYUIOP|
- "00 00 0a 00 41 53 44 46 47 48 4a 4b 4c 00 00 00", // |....ASDFGHJKL...|
- "00 00 5a 58 43 56 42 4e 4d 00 00 00 00 00 00 20", // |..ZXCVBNM...... |
- "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................|
- "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................|
- "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................|
- "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................|
- "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................|
- "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................|
- "00 00 00 00 00 00 2e 00 1e 00 31 00 14 00 39 00", // |..........1...9.|
- "1f 00 14 00 18 00 ff ff 01 00 01 4c 45 56 45 4c", // |......ÿÿ...LEVEL|
- "53 2e 44 41 54 00 00 00 00 00 00 00 00 00 00 00", // |S.DAT...........|
- "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................|
- "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................|
- "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................|
- "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................|
- "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................|
- "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................|
- "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................|
-
- NULL
- };
- int preceding_buffer_size = 0;
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
-
LInfo = native_sp_level.header;
FieldWidth = native_sp_level.width;
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);
+#if 0
+ /* (add one byte for the level number stored as first byte of demo data) */
+ FileMax = FieldMax + native_sp_level.demo.length + 1;
#endif
-#if 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), -game_sp.preceding_buffer_size, FieldMax);
#endif
-#if 1
+ /* initialize preceding playfield buffer */
+ for (i = -game_sp.preceding_buffer_size; i < 0; i++)
+ PlayField16[i] = 0;
+
+ /* initialize preceding playfield buffer */
+ for (i = -SP_MAX_PLAYFIELD_WIDTH; i < 0; i++)
+ PlayField8[i] = 0;
+
count = 0;
- for (i = 0; preceding_playfield_memory[i] != NULL; i++)
+ for (i = 0; game_sp.preceding_buffer[i] != NULL; i++)
{
- char *s = preceding_playfield_memory[i];
+ char *s = game_sp.preceding_buffer[i];
boolean hi_byte = FALSE; /* little endian data => start with low byte */
while (s[0] != '\0' && s[1] != '\0')
if (hi_byte)
byte <<= 8;
- PlayField16[-preceding_buffer_size + count] |= byte;
+ PlayField16[-game_sp.preceding_buffer_size + count] |= byte;
if (hi_byte)
count++;
s++;
}
}
-#endif
count = 0;
for (y = 0; y < native_sp_level.height; y++)
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;
#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;
/* 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) */
/* 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++)
{
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);
/* 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)
}
}
-boolean LoadNativeLevel_SP(char *filename, int level_pos)
+boolean LoadNativeLevel_SP(char *filename, int level_pos,
+ boolean level_info_only)
{
FILE *file;
int i, l, x, y;
strSuffixLower(filename, ".mpx"));
boolean demo_available = is_single_level_file;
boolean is_mpx_file = strSuffixLower(filename, ".mpx");
- int file_seek_pos = level_pos * SP_LEVEL_SIZE;
- int level_width = SP_PLAYFIELD_WIDTH;
- int level_height = SP_PLAYFIELD_HEIGHT;
+ int file_seek_pos = level_pos * SP_STD_LEVEL_SIZE;
+ int level_width = SP_STD_PLAYFIELD_WIDTH;
+ int level_height = SP_STD_PLAYFIELD_HEIGHT;
/* always start with reliable default values */
setLevelInfoToDefaults_SP();
if (!(file = fopen(filename, MODE_READ)))
{
- Error(ERR_WARN, "cannot open file '%s' -- using empty level", filename);
+ if (!level_info_only)
+ Error(ERR_WARN, "cannot open file '%s' -- using empty level", filename);
return FALSE;
}
multipart_xpos, multipart_ypos, multipart_level.header.LevelTitle);
#endif
- if (multipart_xpos * SP_PLAYFIELD_WIDTH > SP_MAX_PLAYFIELD_WIDTH ||
- multipart_ypos * SP_PLAYFIELD_HEIGHT > SP_MAX_PLAYFIELD_HEIGHT)
+ if (multipart_xpos * SP_STD_PLAYFIELD_WIDTH > SP_MAX_PLAYFIELD_WIDTH ||
+ multipart_ypos * SP_STD_PLAYFIELD_HEIGHT > SP_MAX_PLAYFIELD_HEIGHT)
{
Error(ERR_WARN, "multi-part level is too big -- ignoring part of it");
}
multipart_level.width = MAX(multipart_level.width,
- multipart_xpos * SP_PLAYFIELD_WIDTH);
+ multipart_xpos * SP_STD_PLAYFIELD_WIDTH);
multipart_level.height = MAX(multipart_level.height,
- multipart_ypos * SP_PLAYFIELD_HEIGHT);
+ multipart_ypos * SP_STD_PLAYFIELD_HEIGHT);
/* copy level part at the right position of multi-part level */
- for (x = 0; x < SP_PLAYFIELD_WIDTH; x++)
+ for (x = 0; x < SP_STD_PLAYFIELD_WIDTH; x++)
{
- for (y = 0; y < SP_PLAYFIELD_HEIGHT; y++)
+ for (y = 0; y < SP_STD_PLAYFIELD_HEIGHT; y++)
{
- int start_x = (multipart_xpos - 1) * SP_PLAYFIELD_WIDTH;
- int start_y = (multipart_ypos - 1) * SP_PLAYFIELD_HEIGHT;
+ int start_x = (multipart_xpos - 1) * SP_STD_PLAYFIELD_WIDTH;
+ int start_y = (multipart_ypos - 1) * SP_STD_PLAYFIELD_HEIGHT;
multipart_level.playfield[start_x + x][start_y + y] =
native_sp_level.playfield[x][y];
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);
+}