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.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++)
void copyInternalEngineVars_SP()
{
- int i, x, y;
+ 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
+
+ /* needed for engine snapshots */
+ game_sp.preceding_buffer_size = preceding_buffer_size;
LInfo = native_sp_level.header;
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
+#if 0
+ /* fill preceding playfield buffer zone with (indestructible) "hardware" */
+ for (i = -FieldWidth; i < 0; i++)
+ PlayField16[i] = 0x20;
+#endif
+
+#if 1
+ count = 0;
+ for (i = 0; preceding_playfield_memory[i] != NULL; i++)
+ {
+ char *s = preceding_playfield_memory[i];
+ boolean hi_byte = FALSE; /* little endian data => start with low byte */
+
+ while (s[0] != '\0' && s[1] != '\0')
+ {
+ int hi_nibble = s[0] - (s[0] > '9' ? 'a' - 10 : '0');
+ int lo_nibble = s[1] - (s[1] > '9' ? 'a' - 10 : '0');
+ int byte = (hi_nibble << 4) | lo_nibble;
+
+ if (hi_byte)
+ byte <<= 8;
+
+ PlayField16[-preceding_buffer_size + count] |= byte;
+
+ if (hi_byte)
+ count++;
+
+ hi_byte = !hi_byte;
+
+ s += 2;
+
+ while (*s == ' ')
+ s++;
+ }
+ }
+#endif
+
count = 0;
for (y = 0; y < native_sp_level.height; y++)
for (x = 0; x < native_sp_level.width; x++)
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++)
FreezeZonks = LInfo.InitialFreezeZonks;
#if 1
- /* set by main game tape code directly */
+ /* this is set by main game tape code to native random generator directly */
#else
#if 1
LevelLoaded = True;
}
-static void LoadNativeLevelFromFileStream_SP(FILE *file, boolean demo_available)
+static void LoadNativeLevelFromFileStream_SP(FILE *file, int width, int height,
+ boolean demo_available)
{
LevelInfoType *header = &native_sp_level.header;
int i, x, y;
/* 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 = SP_PLAYFIELD_WIDTH;
- native_sp_level.height = SP_PLAYFIELD_HEIGHT;
+ native_sp_level.width = width;
+ native_sp_level.height = height;
/* read level playfield (width * height == 60 * 24 tiles == 1440 bytes) */
for (y = 0; y < native_sp_level.height; y++)
/* 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);
for (i = 0; i < SP_HEADER_SIZE; i++)
native_sp_level.header_raw_bytes[i] = fgetc(file);
- /* also load demo tape, if available */
+ /* also load demo tape, if available (only in single level files) */
if (demo_available)
{
}
}
-boolean LoadNativeLevel_SP(char *filename, int pos)
+boolean LoadNativeLevel_SP(char *filename, int level_pos)
{
FILE *file;
int i, l, x, y;
boolean reading_multipart_level = FALSE;
boolean use_empty_level = FALSE;
LevelInfoType *header = &native_sp_level.header;
- boolean demo_available = (strSuffix(filename, ".sp") ||
- strSuffix(filename, ".SP"));
+ boolean is_single_level_file = (strSuffixLower(filename, ".sp") ||
+ strSuffixLower(filename, ".mpx"));
+ boolean demo_available = is_single_level_file;
+ boolean is_mpx_file = strSuffixLower(filename, ".mpx");
+ 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 level '%s' -- using empty level", filename);
+ Error(ERR_WARN, "cannot open file '%s' -- using empty level", filename);
return FALSE;
}
+ if (is_mpx_file)
+ {
+ char mpx_chunk_name[4 + 1];
+ int mpx_version;
+ int mpx_level_count;
+ LevelDescriptor *mpx_level_desc;
+
+ getFileChunkBE(file, mpx_chunk_name, NULL);
+
+ if (!strEqual(mpx_chunk_name, "MPX "))
+ {
+ Error(ERR_WARN, "cannot find MPX ID in file '%s' -- using empty level",
+ filename);
+
+ return FALSE;
+ }
+
+ mpx_version = getFile16BitLE(file);
+
+ if (mpx_version != 1)
+ {
+ Error(ERR_WARN, "unknown MPX version in file '%s' -- using empty level",
+ filename);
+
+ return FALSE;
+ }
+
+ mpx_level_count = getFile16BitLE(file);
+
+ if (mpx_level_count < 1)
+ {
+ Error(ERR_WARN, "no MPX levels found in file '%s' -- using empty level",
+ filename);
+
+ return FALSE;
+ }
+
+ if (level_pos >= mpx_level_count)
+ {
+ Error(ERR_WARN, "MPX level not found in file '%s' -- using empty level",
+ filename);
+
+ return FALSE;
+ }
+
+ mpx_level_desc = checked_calloc(mpx_level_count * sizeof(LevelDescriptor));
+
+ for (i = 0; i < mpx_level_count; i++)
+ {
+ LevelDescriptor *ldesc = &mpx_level_desc[i];
+
+ ldesc->Width = getFile16BitLE(file);
+ ldesc->Height = getFile16BitLE(file);
+ ldesc->OffSet = getFile32BitLE(file); /* starts with 1, not with 0 */
+ ldesc->Size = getFile32BitLE(file);
+ }
+
+ level_width = mpx_level_desc[level_pos].Width;
+ level_height = mpx_level_desc[level_pos].Height;
+
+ file_seek_pos = mpx_level_desc[level_pos].OffSet - 1;
+ }
+
/* position file stream to the requested level (in case of level package) */
- if (fseek(file, pos * SP_LEVEL_SIZE, SEEK_SET) != 0)
+ if (fseek(file, file_seek_pos, SEEK_SET) != 0)
{
Error(ERR_WARN, "cannot fseek in file '%s' -- using empty level", filename);
of the level name, the multi-part level consists of only horizontal or
vertical parts */
- for (l = pos; l < SP_NUM_LEVELS_PER_PACKAGE; l++)
+ for (l = level_pos; l < SP_NUM_LEVELS_PER_PACKAGE; l++)
{
- LoadNativeLevelFromFileStream_SP(file, demo_available);
+ LoadNativeLevelFromFileStream_SP(file, level_width, level_height,
+ demo_available);
/* check if this level is a part of a bigger multi-part level */
+ if (is_single_level_file)
+ break;
+
name_first = header->LevelTitle[0];
name_last = header->LevelTitle[SP_LEVEL_NAME_LEN - 1];
((name_first == '?' || name_first == '1') &&
(name_last == '?' || name_last == '1'));
- /* correct leading multipart level meta information in level name */
- for (i = 0; i < SP_LEVEL_NAME_LEN && header->LevelTitle[i] == name_first; i++)
- header->LevelTitle[i] = '-';
-
- /* correct trailing multipart level meta information in level name */
- for (i = SP_LEVEL_NAME_LEN - 1; i >= 0 && header->LevelTitle[i] == name_last; i--)
- header->LevelTitle[i] = '-';
+ if (is_multipart_level)
+ {
+ /* correct leading multipart level meta information in level name */
+ for (i = 0;
+ i < SP_LEVEL_NAME_LEN && header->LevelTitle[i] == name_first;
+ i++)
+ header->LevelTitle[i] = '-';
+
+ /* correct trailing multipart level meta information in level name */
+ for (i = SP_LEVEL_NAME_LEN - 1;
+ i >= 0 && header->LevelTitle[i] == name_last;
+ i--)
+ header->LevelTitle[i] = '-';
+ }
/* ---------- check for normal single level ---------- */
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];