X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Fgame_sp%2Ffile.c;h=bc828c0ee47fdd08fea0e353294379c6aa079c43;hb=3d7779514ea1fa0a79312ec8e98f08e5b1096fcb;hp=4e7b6bc06ca93b35a32acca6c66ba53b1f4ab9f3;hpb=0b8567c8bcbe637936fa01d253de81254fa4fb3e;p=rocksndiamonds.git diff --git a/src/game_sp/file.c b/src/game_sp/file.c index 4e7b6bc0..bc828c0e 100644 --- a/src/game_sp/file.c +++ b/src/game_sp/file.c @@ -43,13 +43,67 @@ void setLevelInfoToDefaults_SP() port->FreezeEnemies = 0; } + /* set raw header bytes (used for subsequent buffer zone) to "hardware" */ + 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; } void copyInternalEngineVars_SP() { + char *preceding_playfield_memory[] = + { + "95 89 95 89 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", // |¬.¬.¬.¬.¬.Y.Y.Y.| + "59 8f 59 8f 59 8f 59 8f 59 8f 00 00 70 13 00 00", // |Y.Y.Y.Y.Y...p...| + "00 00 e8 17 00 00 00 00 00 00 69 38 00 00 00 00", // |..è.......i8....| + "00 00 00 00 00 00 00 00 00 00 00 00 d0 86 00 00", // |............Ð...| + "b2 34 00 00 00 00 00 00 00 00 8f 8b 1d 34 00 00", // |²4...........4..| + "00 00 00 00 00 00 00 00 23 39 09 09 00 0c 00 08", // |........#9......| + "00 58 00 00 00 00 00 25 77 06 7f 00 00 00 01 00", // |.X.....%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 00 00 00 00 ec 06 26", // |.............ì.&| + "05 00 00 00 00 00 00 01 00 00 00 00 31 32 33 34", // |............1234| + "35 36 37 38 39 30 2d 00 08 00 51 57 45 52 54 59", // |567890-...QWERTY| + "55 49 4f 50 00 00 0a 00 41 53 44 46 47 48 4a 4b", // |UIOP....ASDFGHJK| + "4c 00 00 00 00 00 5a 58 43 56 42 4e 4d 00 00 00", // |L.....ZXCVBNM...| + "00 00 00 20 00 00 00 00 00 00 00 00 00 00 00 00", // |... ............| + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................| + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................| + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................| + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // |................| + "00 00 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", // |..............1.| + "14 00 39 00 1f 00 14 00 18 00 ff ff 01 00 01 4c", // |..9.......ÿÿ...L| + "45 56 45 4c 53 2e 44 41 54 00 00 00 00 00 00 00", // |EVELS.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", // |................| + "00 00 00 00", // |.... | + + NULL + }; int i, x, y; + int count; LInfo = native_sp_level.header; @@ -64,9 +118,45 @@ void copyInternalEngineVars_SP() PlayField8 = REDIM_1D(sizeof(byte), 0, FileMax + 1 - 1); DisPlayField = REDIM_1D(sizeof(byte), 0, FieldMax + 1 - 1); +#if 0 PlayField16 = REDIM_1D(sizeof(int), -FieldWidth, FieldMax); +#else + PlayField16 = REDIM_1D(sizeof(int), -FieldWidth * 2, FieldMax); +#endif + +#if 1 + +#if 1 + /* fill preceding playfield buffer zone with (indestructible) "hardware" */ + for (i = -FieldWidth * 2; i < -FieldWidth; i++) + PlayField16[i] = 0x20; +#endif + +#if 0 + /* fill preceding playfield buffer zone with (indestructible) "hardware" */ + for (i = -FieldWidth; i < 0; i++) + PlayField16[i] = 0x20; +#endif + + count = 0; + for (y = 0; y < native_sp_level.height; y++) + for (x = 0; x < native_sp_level.width; x++) + PlayField8[count++] = native_sp_level.playfield[x][y]; + + /* add raw header bytes to subsequent playfield buffer zone */ + for (i = 0; i < SP_HEADER_SIZE; i++) + PlayField8[count++] = native_sp_level.header_raw_bytes[i]; + + for (i = 0; i < count; i++) + { + PlayField16[i] = PlayField8[i]; + DisPlayField[i] = PlayField8[i]; + PlayField8[i] = 0; + } + +#else - for (i = 0, y = 0; y < native_sp_level.height; y++) + for (i = 0; y = 0; y < native_sp_level.height; y++) { for (x = 0; x < native_sp_level.width; x++) { @@ -80,6 +170,8 @@ void copyInternalEngineVars_SP() } } +#endif + if (native_sp_level.demo.is_available) { DemoAvailable = True; @@ -101,12 +193,23 @@ void copyInternalEngineVars_SP() 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; } -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; @@ -114,8 +217,8 @@ static void LoadNativeLevelFromFileStream_SP(FILE *file, boolean demo_available) /* 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++) @@ -193,6 +296,7 @@ static void LoadNativeLevelFromFileStream_SP(FILE *file, boolean demo_available) /* 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); @@ -209,7 +313,13 @@ static void LoadNativeLevelFromFileStream_SP(FILE *file, boolean demo_available) header->InfotronsNeeded &= 0xff; /* only use low byte -- see above */ } - /* also load demo tape, if available */ + /* read raw level header bytes (96 bytes) */ + + fseek(file, -(SP_HEADER_SIZE), SEEK_CUR); /* rewind file */ + for (i = 0; i < SP_HEADER_SIZE; i++) + native_sp_level.header_raw_bytes[i] = fgetc(file); + + /* also load demo tape, if available (only in single level files) */ if (demo_available) { @@ -238,7 +348,7 @@ static void LoadNativeLevelFromFileStream_SP(FILE *file, boolean demo_available) } } -boolean LoadNativeLevel_SP(char *filename, int pos) +boolean LoadNativeLevel_SP(char *filename, int level_pos) { FILE *file; int i, l, x, y; @@ -250,8 +360,13 @@ boolean LoadNativeLevel_SP(char *filename, int pos) 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_LEVEL_SIZE; + int level_width = SP_PLAYFIELD_WIDTH; + int level_height = SP_PLAYFIELD_HEIGHT; /* always start with reliable default values */ setLevelInfoToDefaults_SP(); @@ -259,13 +374,76 @@ boolean LoadNativeLevel_SP(char *filename, int pos) 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); @@ -280,12 +458,16 @@ boolean LoadNativeLevel_SP(char *filename, int pos) 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]; @@ -297,13 +479,20 @@ boolean LoadNativeLevel_SP(char *filename, int pos) ((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 ---------- */