X-Git-Url: https://git.artsoft.org/?p=rocksndiamonds.git;a=blobdiff_plain;f=src%2Fgame_sp%2Ffile.c;h=a38c80667cff3390b9426f37c07fd7d2771f9832;hp=438e76644e9791943153c3b6a1e04d088b4fe46f;hb=3ff2e8a0b5c27b99a9920bdf5ed82bc41bf40181;hpb=7bf1759dc1f54495a7e16b32f08697b00661c32e diff --git a/src/game_sp/file.c b/src/game_sp/file.c index 438e7664..a38c8066 100644 --- a/src/game_sp/file.c +++ b/src/game_sp/file.c @@ -72,17 +72,6 @@ void copyInternalEngineVars_SP() FieldMax = (FieldWidth * FieldHeight) + HeaderSize - 1; LevelMax = (FieldWidth * FieldHeight) - 1; -#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 0 - 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 - /* initialize preceding playfield buffer */ for (i = -game_sp.preceding_buffer_size; i < 0; i++) PlayField16[i] = 0; @@ -137,38 +126,15 @@ void copyInternalEngineVars_SP() } 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 + 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); -#endif - GravityFlag = LInfo.InitialGravity; FreezeZonks = LInfo.InitialFreezeZonks; -#if 1 - /* this is set by main game tape code to native random generator directly */ -#else - RandomSeed = LInfo.DemoRandomSeed; -#endif - LevelLoaded = True; -} -#if 1 + /* random seed set by main game tape code to native random generator seed */ +} static void LoadNativeLevelFromFileStream_SP(File *file, int width, int height, boolean demo_available) @@ -300,142 +266,6 @@ static void LoadNativeLevelFromFileStream_SP(File *file, int width, int height, } } -#else - -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 = 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) */ - /* (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) */ - - ReadUnusedBytesFromFile(file, 4); /* (not used by Supaplex engine) */ - - /* initial gravity: 1 == "on", anything else (0) == "off" */ - header->InitialGravity = getFile8Bit(file); - - /* SpeedFixVersion XOR 0x20 */ - header->Version = getFile8Bit(file); - - /* level title in uppercase letters, padded with dashes ("-") (23 bytes) */ - for (i = 0; i < SP_LEVEL_NAME_LEN; i++) - header->LevelTitle[i] = getFile8Bit(file); - - /* initial "freeze zonks": 2 == "on", anything else (0, 1) == "off" */ - header->InitialFreezeZonks = getFile8Bit(file); - - /* number of infotrons needed; 0 means that Supaplex will count the total - amount of infotrons in the level and use the low byte of that number - (a multiple of 256 infotrons will result in "0 infotrons needed"!) */ - header->InfotronsNeeded = getFile8Bit(file); - - /* number of special ("gravity") port entries below (maximum 10 allowed) */ - header->SpecialPortCount = getFile8Bit(file); - - /* database of properties of up to 10 special ports (6 bytes per port) */ - for (i = 0; i < SP_MAX_SPECIAL_PORTS; i++) - { - SpecialPortType *port = &header->SpecialPort[i]; - - /* high and low byte of the location of a special port; if (x, y) are the - coordinates of a port in the field and (0, 0) is the top-left corner, - the 16 bit value here calculates as 2 * (x + (y * 60)) (this is twice - of what may be expected: Supaplex works with a game field in memory - which is 2 bytes per tile) */ - port->PortLocation = getFile16BitBE(file); /* yes, big endian */ - - /* change gravity: 1 == "turn on", anything else (0) == "turn off" */ - port->Gravity = getFile8Bit(file); - - /* "freeze zonks": 2 == "turn on", anything else (0, 1) == "turn off" */ - port->FreezeZonks = getFile8Bit(file); - - /* "freeze enemies": 1 == "turn on", anything else (0) == "turn off" */ - port->FreezeEnemies = getFile8Bit(file); - - ReadUnusedBytesFromFile(file, 1); /* (not used by Supaplex engine) */ - } - - /* SpeedByte XOR Highbyte(RandomSeed) */ - header->SpeedByte = getFile8Bit(file); - - /* CheckSum XOR SpeedByte */ - header->CheckSumByte = getFile8Bit(file); - - /* random seed used for recorded demos */ - header->DemoRandomSeed = getFile16BitLE(file); /* yes, little endian */ - - /* auto-determine number of infotrons if it was stored as "0" -- see above */ - if (header->InfotronsNeeded == 0) - { - for (x = 0; x < native_sp_level.width; x++) - for (y = 0; y < native_sp_level.height; y++) - if (native_sp_level.playfield[x][y] == fiInfotron) - header->InfotronsNeeded++; - - header->InfotronsNeeded &= 0xff; /* only use low byte -- see above */ - } - - /* 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) - { - int level_nr = getFile8Bit(file); - - level_nr &= 0x7f; /* clear highest bit */ - level_nr = (level_nr < 1 ? 1 : - level_nr > 111 ? 111 : level_nr); - - native_sp_level.demo.level_nr = level_nr; - - for (i = 0; i < SP_MAX_TAPE_LEN && !feof(file); i++) - { - native_sp_level.demo.data[i] = getFile8Bit(file); - - if (native_sp_level.demo.data[i] == 0xff) /* "end of demo" byte */ - { - i++; - - break; - } - } - - native_sp_level.demo.length = i; - native_sp_level.demo.is_available = (native_sp_level.demo.length > 0); - } -} - -#endif - -#if 1 - boolean LoadNativeLevel_SP(char *filename, int level_pos, boolean level_info_only) { @@ -644,11 +474,6 @@ 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_STD_PLAYFIELD_WIDTH > SP_MAX_PLAYFIELD_WIDTH || multipart_ypos * SP_STD_PLAYFIELD_HEIGHT > SP_MAX_PLAYFIELD_HEIGHT) { @@ -693,267 +518,6 @@ boolean LoadNativeLevel_SP(char *filename, int level_pos, return TRUE; } -#else - -boolean LoadNativeLevel_SP(char *filename, int level_pos, - boolean level_info_only) -{ - FILE *file; - int i, l, x, y; - char name_first, name_last; - struct LevelInfo_SP multipart_level; - int multipart_xpos, multipart_ypos; - boolean is_multipart_level; - boolean is_first_part; - boolean reading_multipart_level = FALSE; - boolean use_empty_level = FALSE; - LevelInfoType *header = &native_sp_level.header; - 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(); - copyInternalEngineVars_SP(); - - if (!(file = fopen(filename, MODE_READ))) - { - if (!level_info_only) - 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, file_seek_pos, SEEK_SET) != 0) - { - Error(ERR_WARN, "cannot fseek in file '%s' -- using empty level", filename); - - return FALSE; - } - - /* there exist Supaplex level package files with multi-part levels which - can be detected as follows: instead of leading and trailing dashes ('-') - to pad the level name, they have leading and trailing numbers which are - the x and y coordinations of the current part of the multi-part level; - if there are '?' characters instead of numbers on the left or right side - of the level name, the multi-part level consists of only horizontal or - vertical parts */ - - for (l = level_pos; l < SP_NUM_LEVELS_PER_PACKAGE; l++) - { - 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]; - - is_multipart_level = - ((name_first == '?' || (name_first >= '0' && name_first <= '9')) && - (name_last == '?' || (name_last >= '0' && name_last <= '9'))); - - is_first_part = - ((name_first == '?' || name_first == '1') && - (name_last == '?' || name_last == '1')); - - 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 ---------- */ - - if (!reading_multipart_level && !is_multipart_level) - { - /* the current level is simply a normal single-part level, and we are - not reading a multi-part level yet, so return the level as it is */ - - break; - } - - /* ---------- check for empty level (unused multi-part) ---------- */ - - if (!reading_multipart_level && is_multipart_level && !is_first_part) - { - /* this is a part of a multi-part level, but not the first part - (and we are not already reading parts of a multi-part level); - in this case, use an empty level instead of the single part */ - - use_empty_level = TRUE; - - break; - } - - /* ---------- check for finished multi-part level ---------- */ - - if (reading_multipart_level && - (!is_multipart_level || - !strEqualN(header->LevelTitle, multipart_level.header.LevelTitle, - SP_LEVEL_NAME_LEN))) - { - /* we are already reading parts of a multi-part level, but this level is - either not a multi-part level, or a part of a different multi-part - level; in both cases, the multi-part level seems to be complete */ - - break; - } - - /* ---------- here we have one part of a multi-part level ---------- */ - - reading_multipart_level = TRUE; - - if (is_first_part) /* start with first part of new multi-part level */ - { - /* copy level info structure from first part */ - multipart_level = native_sp_level; - - /* clear playfield of new multi-part level */ - for (x = 0; x < SP_MAX_PLAYFIELD_WIDTH; x++) - for (y = 0; y < SP_MAX_PLAYFIELD_HEIGHT; y++) - multipart_level.playfield[x][y] = fiSpace; - } - - if (name_first == '?') - name_first = '1'; - if (name_last == '?') - name_last = '1'; - - 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_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"); - - break; - } - - multipart_level.width = MAX(multipart_level.width, - multipart_xpos * SP_STD_PLAYFIELD_WIDTH); - multipart_level.height = MAX(multipart_level.height, - multipart_ypos * SP_STD_PLAYFIELD_HEIGHT); - - /* copy level part at the right position of multi-part level */ - for (x = 0; x < SP_STD_PLAYFIELD_WIDTH; x++) - { - for (y = 0; y < SP_STD_PLAYFIELD_HEIGHT; y++) - { - 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]; - } - } - } - - fclose(file); - - if (use_empty_level) - { - setLevelInfoToDefaults_SP(); - - Error(ERR_WARN, "single part of multi-part level -- using empty level"); - } - - if (reading_multipart_level) - native_sp_level = multipart_level; - - copyInternalEngineVars_SP(); - - return TRUE; -} - -#endif - void SaveNativeLevel_SP(char *filename) { LevelInfoType *header = &native_sp_level.header;