X-Git-Url: https://git.artsoft.org/?p=rocksndiamonds.git;a=blobdiff_plain;f=src%2Fgame_sp%2Ffile.c;h=a38c80667cff3390b9426f37c07fd7d2771f9832;hp=40ffacb35738d5bef3479c718614c97cd74de874;hb=3ff2e8a0b5c27b99a9920bdf5ed82bc41bf40181;hpb=f7b79b71faf7e5fbe38df38d26d1156f3ba2f0ce diff --git a/src/game_sp/file.c b/src/game_sp/file.c index 40ffacb3..a38c8066 100644 --- a/src/game_sp/file.c +++ b/src/game_sp/file.c @@ -7,14 +7,22 @@ /* 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++) @@ -47,14 +55,13 @@ 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() { - int i, x, y; int count; + int i, x, y; LInfo = native_sp_level.header; @@ -65,29 +72,42 @@ void copyInternalEngineVars_SP() FieldMax = (FieldWidth * FieldHeight) + HeaderSize - 1; LevelMax = (FieldWidth * FieldHeight) - 1; - FileMax = FieldMax + native_sp_level.demo.length; + /* 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; game_sp.preceding_buffer[i] != NULL; 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') + { + 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; - 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 + PlayField16[-game_sp.preceding_buffer_size + count] |= byte; -#if 1 + if (hi_byte) + count++; -#if 1 - /* fill preceding playfield buffer zone with (indestructible) "hardware" */ - for (i = -FieldWidth * 2; i < -FieldWidth; i++) - PlayField16[i] = 0x20; -#endif + hi_byte = !hi_byte; -#if 0 - /* fill preceding playfield buffer zone with (indestructible) "hardware" */ - for (i = -FieldWidth; i < 0; i++) - PlayField16[i] = 0x20; -#endif + s += 2; + + while (*s == ' ') + s++; + } + } count = 0; for (y = 0; y < native_sp_level.height; y++) @@ -105,61 +125,18 @@ void copyInternalEngineVars_SP() PlayField8[i] = 0; } -#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; - PlayField8[FieldMax + 1] = native_sp_level.demo.level_nr; - - for (i = 0; i < native_sp_level.demo.length; i++) - PlayField8[FieldMax + i + 2] = native_sp_level.demo.data[i]; - } - - 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; - 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; + + /* random seed set by main game tape code to native random generator seed */ } -static void LoadNativeLevelFromFileStream_SP(FILE *file, int width, int height, +static void LoadNativeLevelFromFileStream_SP(File *file, int width, int height, boolean demo_available) { LevelInfoType *header = &native_sp_level.header; @@ -168,13 +145,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) */ @@ -201,10 +187,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++) { @@ -217,16 +199,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); @@ -247,11 +219,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) @@ -266,9 +233,9 @@ static void LoadNativeLevelFromFileStream_SP(FILE *file, int width, int height, /* read raw level header bytes (96 bytes) */ - fseek(file, -(SP_HEADER_SIZE), SEEK_CUR); /* rewind file */ + seekFile(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); + native_sp_level.header_raw_bytes[i] = getByteFromFile(file); /* also load demo tape, if available (only in single level files) */ @@ -282,7 +249,7 @@ static void LoadNativeLevelFromFileStream_SP(FILE *file, int width, int height, native_sp_level.demo.level_nr = level_nr; - for (i = 0; i < SP_MAX_TAPE_LEN && !feof(file); i++) + for (i = 0; i < SP_MAX_TAPE_LEN && !checkEndOfFile(file); i++) { native_sp_level.demo.data[i] = getFile8Bit(file); @@ -299,9 +266,10 @@ static void LoadNativeLevelFromFileStream_SP(FILE *file, int width, int height, } } -boolean LoadNativeLevel_SP(char *filename, int level_pos) +boolean LoadNativeLevel_SP(char *filename, int level_pos, + boolean level_info_only) { - FILE *file; + File *file; int i, l, x, y; char name_first, name_last; struct LevelInfo_SP multipart_level; @@ -315,17 +283,18 @@ boolean LoadNativeLevel_SP(char *filename, int level_pos) 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(); copyInternalEngineVars_SP(); - if (!(file = fopen(filename, MODE_READ))) + if (!(file = openFile(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; } @@ -394,7 +363,7 @@ boolean LoadNativeLevel_SP(char *filename, int level_pos) } /* position file stream to the requested level (in case of level package) */ - if (fseek(file, file_seek_pos, SEEK_SET) != 0) + if (seekFile(file, file_seek_pos, SEEK_SET) != 0) { Error(ERR_WARN, "cannot fseek in file '%s' -- using empty level", filename); @@ -505,13 +474,8 @@ boolean LoadNativeLevel_SP(char *filename, int level_pos) multipart_xpos = (int)(name_first - '0'); multipart_ypos = (int)(name_last - '0'); -#if 0 - printf("----------> part (%d/%d) of multi-part level '%s'\n", - 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"); @@ -519,17 +483,17 @@ boolean LoadNativeLevel_SP(char *filename, int level_pos) } 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]; @@ -537,7 +501,7 @@ boolean LoadNativeLevel_SP(char *filename, int level_pos) } } - fclose(file); + closeFile(file); if (use_empty_level) { @@ -553,3 +517,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); +}