X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Ffiles.c;h=743624677e149c4aff94d472caa46c9f76568233;hb=68f0ce90185b6ea19cad62bc6328326bda538951;hp=7ab17f2c5ed4d3d38050f74305db6936f2c2b98c;hpb=4add6d49e770bbdcd7dc4176fdec56d6dad16bb2;p=rocksndiamonds.git diff --git a/src/files.c b/src/files.c index 7ab17f2c..74362467 100644 --- a/src/files.c +++ b/src/files.c @@ -40,52 +40,52 @@ #define TAPE_HEADER_SIZE 20 /* size of tape file header */ #define TAPE_HEADER_UNUSED 3 /* unused tape header bytes */ -#define LEVEL_CHUNK_CNT3_SIZE(x) (LEVEL_CHUNK_CNT3_HEADER + (x)) -#define LEVEL_CHUNK_CUS3_SIZE(x) (2 + (x) * LEVEL_CPART_CUS3_SIZE) -#define LEVEL_CHUNK_CUS4_SIZE(x) (96 + (x) * 48) +#define LEVEL_CHUNK_CNT3_SIZE(x) (LEVEL_CHUNK_CNT3_HEADER + (x)) +#define LEVEL_CHUNK_CUS3_SIZE(x) (2 + (x) * LEVEL_CPART_CUS3_SIZE) +#define LEVEL_CHUNK_CUS4_SIZE(x) (96 + (x) * 48) /* file identifier strings */ -#define LEVEL_COOKIE_TMPL "ROCKSNDIAMONDS_LEVEL_FILE_VERSION_x.x" -#define TAPE_COOKIE_TMPL "ROCKSNDIAMONDS_TAPE_FILE_VERSION_x.x" -#define SCORE_COOKIE "ROCKSNDIAMONDS_SCORE_FILE_VERSION_1.2" +#define LEVEL_COOKIE_TMPL "ROCKSNDIAMONDS_LEVEL_FILE_VERSION_x.x" +#define TAPE_COOKIE_TMPL "ROCKSNDIAMONDS_TAPE_FILE_VERSION_x.x" +#define SCORE_COOKIE "ROCKSNDIAMONDS_SCORE_FILE_VERSION_1.2" /* values for "CONF" chunk */ -#define CONF_MASK_1_BYTE 0x00 -#define CONF_MASK_2_BYTE 0x40 -#define CONF_MASK_4_BYTE 0x80 -#define CONF_MASK_MULTI_BYTES 0xc0 +#define CONF_MASK_1_BYTE 0x00 +#define CONF_MASK_2_BYTE 0x40 +#define CONF_MASK_4_BYTE 0x80 +#define CONF_MASK_MULTI_BYTES 0xc0 -#define CONF_MASK_BYTES 0xc0 -#define CONF_MASK_TOKEN 0x3f +#define CONF_MASK_BYTES 0xc0 +#define CONF_MASK_TOKEN 0x3f -#define CONF_LAST_ENTRY (CONF_MASK_1_BYTE | 0) +#define CONF_LAST_ENTRY (CONF_MASK_1_BYTE | 0) -#define CONF_VALUE_INTEGER_1 (CONF_MASK_1_BYTE | 1) -#define CONF_VALUE_INTEGER_2 (CONF_MASK_1_BYTE | 2) -#define CONF_VALUE_INTEGER_3 (CONF_MASK_1_BYTE | 3) -#define CONF_VALUE_INTEGER_4 (CONF_MASK_1_BYTE | 4) -#define CONF_VALUE_BOOLEAN_1 (CONF_MASK_1_BYTE | 5) -#define CONF_VALUE_BOOLEAN_2 (CONF_MASK_1_BYTE | 6) -#define CONF_VALUE_BOOLEAN_3 (CONF_MASK_1_BYTE | 7) -#define CONF_VALUE_BOOLEAN_4 (CONF_MASK_1_BYTE | 8) +#define CONF_VALUE_INTEGER_1 (CONF_MASK_1_BYTE | 1) +#define CONF_VALUE_INTEGER_2 (CONF_MASK_1_BYTE | 2) +#define CONF_VALUE_INTEGER_3 (CONF_MASK_1_BYTE | 3) +#define CONF_VALUE_INTEGER_4 (CONF_MASK_1_BYTE | 4) +#define CONF_VALUE_BOOLEAN_1 (CONF_MASK_1_BYTE | 5) +#define CONF_VALUE_BOOLEAN_2 (CONF_MASK_1_BYTE | 6) +#define CONF_VALUE_BOOLEAN_3 (CONF_MASK_1_BYTE | 7) +#define CONF_VALUE_BOOLEAN_4 (CONF_MASK_1_BYTE | 8) -#define CONF_VALUE_ELEMENT_1 (CONF_MASK_2_BYTE | 1) -#define CONF_VALUE_ELEMENT_2 (CONF_MASK_2_BYTE | 2) -#define CONF_VALUE_ELEMENT_3 (CONF_MASK_2_BYTE | 3) -#define CONF_VALUE_ELEMENT_4 (CONF_MASK_2_BYTE | 4) +#define CONF_VALUE_ELEMENT_1 (CONF_MASK_2_BYTE | 1) +#define CONF_VALUE_ELEMENT_2 (CONF_MASK_2_BYTE | 2) +#define CONF_VALUE_ELEMENT_3 (CONF_MASK_2_BYTE | 3) +#define CONF_VALUE_ELEMENT_4 (CONF_MASK_2_BYTE | 4) -#define CONF_VALUE_CONTENT_1 (CONF_MASK_MULTI_BYTES | 1) -#define CONF_VALUE_CONTENT_8 (CONF_MASK_MULTI_BYTES | 2) +#define CONF_VALUE_CONTENT_1 (CONF_MASK_MULTI_BYTES | 1) +#define CONF_VALUE_CONTENT_8 (CONF_MASK_MULTI_BYTES | 2) -#define CONF_VALUE_INTEGER(x) ((x) >= CONF_VALUE_INTEGER_1 && \ - (x) <= CONF_VALUE_INTEGER_4) +#define CONF_VALUE_INTEGER(x) ((x) >= CONF_VALUE_INTEGER_1 && \ + (x) <= CONF_VALUE_INTEGER_4) -#define CONF_VALUE_BOOLEAN(x) ((x) >= CONF_VALUE_BOOLEAN_1 && \ - (x) <= CONF_VALUE_BOOLEAN_4) +#define CONF_VALUE_BOOLEAN(x) ((x) >= CONF_VALUE_BOOLEAN_1 && \ + (x) <= CONF_VALUE_BOOLEAN_4) -#define CONF_VALUE_NUM_BYTES(x) ((x) == CONF_MASK_1_BYTE ? 1 : \ - (x) == CONF_MASK_2_BYTE ? 2 : \ - (x) == CONF_MASK_4_BYTE ? 4 : 0) +#define CONF_VALUE_NUM_BYTES(x) ((x) == CONF_MASK_1_BYTE ? 1 : \ + (x) == CONF_MASK_2_BYTE ? 2 : \ + (x) == CONF_MASK_4_BYTE ? 4 : 0) #define CONF_CONTENT_NUM_ELEMENTS (3 * 3) #define CONF_CONTENT_NUM_BYTES (CONF_CONTENT_NUM_ELEMENTS * 2) @@ -115,10 +115,6 @@ static struct EL_EMC_ANDROID, CONF_VALUE_INTEGER_2, &li.android_clone_time, 10 }, - { - EL_EMC_MAGIC_BALL, CONF_VALUE_INTEGER_1, - &li.ball_time, 10 - }, { EL_EMC_LENSES, CONF_VALUE_INTEGER_1, &li.lenses_score, 10 @@ -195,10 +191,72 @@ static struct EL_EXTRA_TIME, CONF_VALUE_INTEGER_1, &li.extra_time, 10 }, + { + EL_EXTRA_TIME, CONF_VALUE_INTEGER_2, + &li.extra_time_score, 10 + }, { EL_TIME_ORB_FULL, CONF_VALUE_INTEGER_1, &li.time_orb_time, 10 }, + { + EL_TIME_ORB_FULL, CONF_VALUE_BOOLEAN_1, + &li.use_time_orb_bug, FALSE + }, + { + EL_PLAYER_1, CONF_VALUE_BOOLEAN_1, + &li.block_snap_field, TRUE + }, + { + EL_PLAYER_1, CONF_VALUE_BOOLEAN_2, + &li.use_start_element[0], FALSE + }, + { + EL_PLAYER_2, CONF_VALUE_BOOLEAN_2, + &li.use_start_element[1], FALSE + }, + { + EL_PLAYER_3, CONF_VALUE_BOOLEAN_2, + &li.use_start_element[2], FALSE + }, + { + EL_PLAYER_4, CONF_VALUE_BOOLEAN_2, + &li.use_start_element[3], FALSE + }, + { + EL_EMC_MAGIC_BALL, CONF_VALUE_INTEGER_1, + &li.ball_time, 10 + }, + { + EL_EMC_MAGIC_BALL, CONF_VALUE_INTEGER_2, + &li.num_ball_contents, 8 + }, + { + EL_EMC_MAGIC_BALL, CONF_VALUE_BOOLEAN_1, + &li.ball_random, FALSE + }, + { + EL_EMC_MAGIC_BALL, CONF_VALUE_BOOLEAN_2, + &li.ball_state_initial, FALSE + }, + + /* ---------- 2-byte values ---------------------------------------------- */ + { + EL_PLAYER_1, CONF_VALUE_ELEMENT_1, + &li.start_element[0], EL_PLAYER_1 + }, + { + EL_PLAYER_2, CONF_VALUE_ELEMENT_1, + &li.start_element[1], EL_PLAYER_2 + }, + { + EL_PLAYER_3, CONF_VALUE_ELEMENT_1, + &li.start_element[2], EL_PLAYER_3 + }, + { + EL_PLAYER_4, CONF_VALUE_ELEMENT_1, + &li.start_element[3], EL_PLAYER_4 + }, /* ---------- multi-byte values ------------------------------------------ */ { @@ -300,7 +358,7 @@ void setElementChangeInfoToDefaults(struct ElementChangeInfo *change) change->delay_fixed = 0; change->delay_random = 0; - change->delay_frames = 1; + change->delay_frames = FRAMES_PER_SECOND; change->trigger_element = EL_EMPTY_SPACE; @@ -385,6 +443,8 @@ static void setLevelInfoToDefaults(struct LevelInfo *level) level->can_pass_to_walkable = FALSE; level->grow_into_diggable = TRUE; + level->block_snap_field = TRUE; + level->block_last_field = FALSE; /* EM does not block by default */ level->sp_block_last_field = TRUE; /* SP blocks the last field */ @@ -392,6 +452,8 @@ static void setLevelInfoToDefaults(struct LevelInfo *level) level->dont_collide_with_bits = ~0; /* always deadly when colliding */ level->use_spring_bug = FALSE; + level->use_time_orb_bug = FALSE; + level->use_step_counter = FALSE; /* values for the new EMC elements */ @@ -405,10 +467,8 @@ static void setLevelInfoToDefaults(struct LevelInfo *level) level->magnify_time = 10; level->slurp_score = 10; level->wind_direction_initial = MV_NONE; -#endif level->ball_random = FALSE; level->ball_state_initial = FALSE; -#if 0 for (i = 0; i < MAX_ELEMENT_CONTENTS; i++) for (x = 0; x < 3; x++) for (y = 0; y < 3; y++) @@ -435,7 +495,7 @@ static void setLevelInfoToDefaults(struct LevelInfo *level) } for (i = 0; i < LEVEL_SCORE_ELEMENTS; i++) - level->score[i] = 10; + level->score[i] = (i == SC_TIME_BONUS ? 1 : 10); level->num_yamyam_contents = STD_ELEMENT_CONTENTS; for (i = 0; i < MAX_ELEMENT_CONTENTS; i++) @@ -1406,8 +1466,9 @@ static int LoadLevel_CUS4(FILE *file, int chunk_size, struct LevelInfo *level) /* always start with reliable default values */ setElementChangeInfoToDefaults(change); + /* bits 0 - 31 of "has_event[]" ... */ event_bits = getFile32BitBE(file); - for (j = 0; j < NUM_CHANGE_EVENTS; j++) + for (j = 0; j < MIN(NUM_CHANGE_EVENTS, 32); j++) if (event_bits & (1 << j)) change->has_event[j] = TRUE; @@ -1446,8 +1507,11 @@ static int LoadLevel_CUS4(FILE *file, int chunk_size, struct LevelInfo *level) change->action_mode = getFile8Bit(file); change->action_arg = getFile16BitBE(file); - /* some free bytes for future change property values and padding */ - ReadUnusedBytesFromFile(file, 1); + /* ... bits 32 - 39 of "has_event[]" (not nice, but downward compatible) */ + event_bits = getFile8Bit(file); + for (j = 32; j < NUM_CHANGE_EVENTS; j++) + if (event_bits & (1 << (j - 32))) + change->has_event[j] = TRUE; } /* mark this custom element as modified */ @@ -2205,6 +2269,7 @@ void CopyNativeLevel_RND_to_EM(struct LevelInfo *level) lev->ball_random = level->ball_random; lev->ball_state_initial = level->ball_state_initial; lev->ball_time = level->ball_time; + lev->num_ball_arrays = level->num_ball_contents; lev->lenses_score = level->lenses_score; lev->magnify_score = level->magnify_score; @@ -2212,7 +2277,11 @@ void CopyNativeLevel_RND_to_EM(struct LevelInfo *level) lev->lenses_time = level->lenses_time; lev->magnify_time = level->magnify_time; - lev->wind_direction_initial = level->wind_direction_initial; + + lev->wind_direction_initial = + map_direction_RND_to_EM(level->wind_direction_initial); + lev->wind_cnt_initial = (level->wind_direction_initial != MV_NONE ? + lev->wind_time : 0); for (i = 0; i < MAX_ELEMENT_CONTENTS; i++) for (j = 0; j < 8; j++) @@ -2318,6 +2387,7 @@ void CopyNativeLevel_EM_to_RND(struct LevelInfo *level) level->ball_random = lev->ball_random; level->ball_state_initial = lev->ball_state_initial; level->ball_time = lev->ball_time; + level->num_ball_contents = lev->num_ball_arrays; level->lenses_score = lev->lenses_score; level->magnify_score = lev->magnify_score; @@ -2325,7 +2395,9 @@ void CopyNativeLevel_EM_to_RND(struct LevelInfo *level) level->lenses_time = lev->lenses_time; level->magnify_time = lev->magnify_time; - level->wind_direction_initial = lev->wind_direction_initial; + + level->wind_direction_initial = + map_direction_EM_to_RND(lev->wind_direction_initial); for (i = 0; i < MAX_ELEMENT_CONTENTS; i++) for (j = 0; j < 8; j++) @@ -2777,73 +2849,10 @@ static void LoadLevel_InitVersion(struct LevelInfo *level, char *filename) if (leveldir_current == NULL) /* only when dumping level */ return; -#if 0 - printf("::: sort_priority: %d\n", leveldir_current->sort_priority); -#endif - - /* determine correct game engine version of current level */ - if (!leveldir_current->latest_engine) + if (leveldir_current->latest_engine) { - /* For all levels which are not forced to use the latest game engine - version (normally user contributed, private and undefined levels), - use the version of the game engine the levels were created for. - - Since 2.0.1, the game engine version is now directly stored - in the level file (chunk "VERS"), so there is no need anymore - to set the game version from the file version (except for old, - pre-2.0 levels, where the game version is still taken from the - file format version used to store the level -- see above). */ - - /* player was faster than enemies in 1.0.0 and before */ - if (level->file_version == FILE_VERSION_1_0) - level->double_speed = TRUE; - - /* default behaviour for EM style gems was "slippery" only in 2.0.1 */ - if (level->game_version == VERSION_IDENT(2,0,1,0)) - level->em_slippery_gems = TRUE; - - /* springs could be pushed over pits before (pre-release version) 2.2.0 */ - if (level->game_version < VERSION_IDENT(2,2,0,0)) - level->use_spring_bug = TRUE; - - /* only few elements were able to actively move into acid before 3.1.0 */ - /* trigger settings did not exist before 3.1.0; set to default "any" */ - if (level->game_version < VERSION_IDENT(3,1,0,0)) - { - int i, j; + /* ---------- use latest game engine ----------------------------------- */ - /* correct "can move into acid" settings (all zero in old levels) */ - - level->can_move_into_acid_bits = 0; /* nothing can move into acid */ - level->dont_collide_with_bits = 0; /* nothing is deadly when colliding */ - - setMoveIntoAcidProperty(level, EL_ROBOT, TRUE); - setMoveIntoAcidProperty(level, EL_SATELLITE, TRUE); - setMoveIntoAcidProperty(level, EL_PENGUIN, TRUE); - setMoveIntoAcidProperty(level, EL_BALLOON, TRUE); - - for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) - SET_PROPERTY(EL_CUSTOM_START + i, EP_CAN_MOVE_INTO_ACID, TRUE); - - /* correct trigger settings (stored as zero == "none" in old levels) */ - - for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) - { - int element = EL_CUSTOM_START + i; - struct ElementInfo *ei = &element_info[element]; - - for (j = 0; j < ei->num_change_pages; j++) - { - struct ElementChangeInfo *change = &ei->change_page[j]; - - change->trigger_player = CH_PLAYER_ANY; - change->trigger_page = CH_PAGE_ANY; - } - } - } - } - else /* always use the latest game engine version */ - { /* For all levels which are forced to use the latest game engine version (normally all but user contributed, private and undefined levels), set the game engine version to the actual version; this allows for actual @@ -2863,6 +2872,83 @@ static void LoadLevel_InitVersion(struct LevelInfo *level, char *filename) if (level->file_version < FILE_VERSION_2_0) level->em_slippery_gems = TRUE; + + return; + } + + /* ---------- use game engine the level was created with ----------------- */ + + /* For all levels which are not forced to use the latest game engine + version (normally user contributed, private and undefined levels), + use the version of the game engine the levels were created for. + + Since 2.0.1, the game engine version is now directly stored + in the level file (chunk "VERS"), so there is no need anymore + to set the game version from the file version (except for old, + pre-2.0 levels, where the game version is still taken from the + file format version used to store the level -- see above). */ + + /* player was faster than enemies in 1.0.0 and before */ + if (level->file_version == FILE_VERSION_1_0) + level->double_speed = TRUE; + + /* default behaviour for EM style gems was "slippery" only in 2.0.1 */ + if (level->game_version == VERSION_IDENT(2,0,1,0)) + level->em_slippery_gems = TRUE; + + /* springs could be pushed over pits before (pre-release version) 2.2.0 */ + if (level->game_version < VERSION_IDENT(2,2,0,0)) + level->use_spring_bug = TRUE; + + if (level->game_version < VERSION_IDENT(3,2,0,5)) + { + /* time orb caused limited time in endless time levels before 3.2.0-5 */ + level->use_time_orb_bug = TRUE; + + /* default behaviour for snapping was "no snap delay" before 3.2.0-5 */ + level->block_snap_field = FALSE; + + /* extra time score was same value as time left score before 3.2.0-5 */ + level->extra_time_score = level->score[SC_TIME_BONUS]; + + /* time bonus score was given for 10 s instead of 1 s before 3.2.0-5 */ + level->score[SC_TIME_BONUS] /= 10; + } + + /* only few elements were able to actively move into acid before 3.1.0 */ + /* trigger settings did not exist before 3.1.0; set to default "any" */ + if (level->game_version < VERSION_IDENT(3,1,0,0)) + { + int i, j; + + /* correct "can move into acid" settings (all zero in old levels) */ + + level->can_move_into_acid_bits = 0; /* nothing can move into acid */ + level->dont_collide_with_bits = 0; /* nothing is deadly when colliding */ + + setMoveIntoAcidProperty(level, EL_ROBOT, TRUE); + setMoveIntoAcidProperty(level, EL_SATELLITE, TRUE); + setMoveIntoAcidProperty(level, EL_PENGUIN, TRUE); + setMoveIntoAcidProperty(level, EL_BALLOON, TRUE); + + for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) + SET_PROPERTY(EL_CUSTOM_START + i, EP_CAN_MOVE_INTO_ACID, TRUE); + + /* correct trigger settings (stored as zero == "none" in old levels) */ + + for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) + { + int element = EL_CUSTOM_START + i; + struct ElementInfo *ei = &element_info[element]; + + for (j = 0; j < ei->num_change_pages; j++) + { + struct ElementChangeInfo *change = &ei->change_page[j]; + + change->trigger_player = CH_PLAYER_ANY; + change->trigger_page = CH_PAGE_ANY; + } + } } } @@ -3432,12 +3518,13 @@ static void SaveLevel_CUS4(FILE *file, struct LevelInfo *level, int element) for (i = 0; i < ei->num_change_pages; i++) { struct ElementChangeInfo *change = &ei->change_page[i]; - unsigned long event_bits = 0; + unsigned long event_bits; - for (j = 0; j < NUM_CHANGE_EVENTS; j++) + /* bits 0 - 31 of "has_event[]" ... */ + event_bits = 0; + for (j = 0; j < MIN(NUM_CHANGE_EVENTS, 32); j++) if (change->has_event[j]) event_bits |= (1 << j); - putFile32BitBE(file, event_bits); putFile16BitBE(file, change->target_element); @@ -3473,8 +3560,12 @@ static void SaveLevel_CUS4(FILE *file, struct LevelInfo *level, int element) putFile8Bit(file, change->action_mode); putFile16BitBE(file, change->action_arg); - /* some free bytes for future change property values and padding */ - WriteUnusedBytesToFile(file, 1); + /* ... bits 32 - 39 of "has_event[]" (not nice, but downward compatible) */ + event_bits = 0; + for (j = 32; j < NUM_CHANGE_EVENTS; j++) + if (change->has_event[j]) + event_bits |= (1 << (j - 32)); + putFile8Bit(file, event_bits); } }