X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Ffiles.c;h=ef7fa51f4792121c18f8290f180e698e75eacc57;hb=5e616edfe5f101927d2ff3f7a14d2c65897de3cc;hp=4ef0174af5d82563ac31646637060ea587327f72;hpb=86b0ea5594dc5a9db7ac5d71fa2b7487a4fc1f9d;p=rocksndiamonds.git diff --git a/src/files.c b/src/files.c index 4ef0174a..ef7fa51f 100644 --- a/src/files.c +++ b/src/files.c @@ -30,12 +30,17 @@ #define LEVEL_HEADER_UNUSED 13 /* unused level header bytes */ #define LEVEL_CHUNK_CNT2_SIZE 160 /* size of level CNT2 chunk */ #define LEVEL_CHUNK_CNT2_UNUSED 11 /* unused CNT2 chunk bytes */ +#define LEVEL_CHUNK_CNT3_HEADER 16 /* size of level CNT3 header */ +#define LEVEL_CHUNK_CNT3_UNUSED 10 /* unused CNT3 chunk bytes */ #define LEVEL_CPART_CUS3_SIZE 134 /* size of CUS3 chunk part */ #define LEVEL_CPART_CUS3_UNUSED 15 /* unused CUS3 bytes / part */ +#define LEVEL_CPART_CUS4_SIZE ??? /* size of CUS4 chunk part */ +#define LEVEL_CPART_CUS4_UNUSED ??? /* unused CUS4 bytes / part */ #define TAPE_HEADER_SIZE 20 /* size of tape file header */ #define TAPE_HEADER_UNUSED 3 /* unused tape header bytes */ -#define LEVEL_CHUNK_CUS3_SIZE(x) (2 + x * LEVEL_CPART_CUS3_SIZE) +#define LEVEL_CHUNK_CUS3_SIZE(x) (2 + (x) * LEVEL_CPART_CUS3_SIZE) +#define LEVEL_CHUNK_CUS4_SIZE(x) (48 + 48 + (x) * 48) /* file identifier strings */ #define LEVEL_COOKIE_TMPL "ROCKSNDIAMONDS_LEVEL_FILE_VERSION_x.x" @@ -69,6 +74,8 @@ void setElementChangeInfoToDefaults(struct ElementChangeInfo *change) change->can_change = FALSE; change->events = CE_BITMASK_DEFAULT; + change->sides = CH_SIDE_ANY; + change->target_element = EL_EMPTY_SPACE; change->delay_fixed = 0; @@ -88,8 +95,7 @@ void setElementChangeInfoToDefaults(struct ElementChangeInfo *change) for(y=0; y<3; y++) change->content[x][y] = EL_EMPTY_SPACE; - change->player_action = 0; - change->collide_action = 0; + change->direct_action = 0; change->other_action = 0; change->pre_change_function = NULL; @@ -137,9 +143,12 @@ static void setLevelInfoToDefaults(struct LevelInfo *level) strcpy(level->name, NAMELESS_LEVEL_NAME); strcpy(level->author, ANONYMOUS_NAME); - level->envelope[0] = '\0'; - level->envelope_xsize = MAX_ENVELOPE_XSIZE; - level->envelope_ysize = MAX_ENVELOPE_YSIZE; + for (i=0; i<4; i++) + { + level->envelope_text[i][0] = '\0'; + level->envelope_xsize[i] = MAX_ENVELOPE_XSIZE; + level->envelope_ysize[i] = MAX_ENVELOPE_YSIZE; + } for(i=0; iscore[i] = 10; @@ -268,15 +277,63 @@ boolean LevelFileExists(int level_nr) static int checkLevelElement(int element) { + /* map some (historic, now obsolete) elements */ + +#if 1 + switch (element) + { + case EL_PLAYER_OBSOLETE: + element = EL_PLAYER_1; + break; + + case EL_KEY_OBSOLETE: + element = EL_KEY_1; + + case EL_EM_KEY_1_FILE_OBSOLETE: + element = EL_EM_KEY_1; + break; + + case EL_EM_KEY_2_FILE_OBSOLETE: + element = EL_EM_KEY_2; + break; + + case EL_EM_KEY_3_FILE_OBSOLETE: + element = EL_EM_KEY_3; + break; + + case EL_EM_KEY_4_FILE_OBSOLETE: + element = EL_EM_KEY_4; + break; + + case EL_ENVELOPE_OBSOLETE: + element = EL_ENVELOPE_1; + break; + + case EL_SP_EMPTY: + element = EL_EMPTY; + break; + + default: + if (element >= NUM_FILE_ELEMENTS) + { + Error(ERR_WARN, "invalid level element %d", element); + + element = EL_CHAR_QUESTION; + } + break; + } +#else if (element >= NUM_FILE_ELEMENTS) { Error(ERR_WARN, "invalid level element %d", element); + element = EL_CHAR_QUESTION; } else if (element == EL_PLAYER_OBSOLETE) element = EL_PLAYER_1; else if (element == EL_KEY_OBSOLETE) element = EL_KEY_1; +#endif return element; } @@ -417,6 +474,7 @@ static int LoadLevel_CNT2(FILE *file, int chunk_size, struct LevelInfo *level) num_contents = getFile8Bit(file); content_xsize = getFile8Bit(file); content_ysize = getFile8Bit(file); + ReadUnusedBytesFromFile(file, LEVEL_CHUNK_CNT2_UNUSED); for(i=0; ienvelope_xsize[envelope_nr] = getFile8Bit(file); + level->envelope_ysize[envelope_nr] = getFile8Bit(file); + + ReadUnusedBytesFromFile(file, LEVEL_CHUNK_CNT3_UNUSED); + + chunk_size_expected = LEVEL_CHUNK_CNT3_HEADER + envelope_len; + + if (chunk_size_expected != chunk_size) + { + ReadUnusedBytesFromFile(file, chunk_size - LEVEL_CHUNK_CNT3_HEADER); + return chunk_size_expected; + } + + for(i=0; i < envelope_len; i++) + level->envelope_text[envelope_nr][i] = getFile8Bit(file); + + return chunk_size; +} + static int LoadLevel_CUS1(FILE *file, int chunk_size, struct LevelInfo *level) { int num_changed_custom_elements = getFile16BitBE(file); @@ -591,6 +684,114 @@ static int LoadLevel_CUS3(FILE *file, int chunk_size, struct LevelInfo *level) return chunk_size; } +static int LoadLevel_CUS4(FILE *file, int chunk_size, struct LevelInfo *level) +{ + struct ElementInfo *ei; + int chunk_size_expected; + int element; + int i, x, y; + + element = getFile16BitBE(file); + + if (!IS_CUSTOM_ELEMENT(element)) + { + Error(ERR_WARN, "invalid custom element number %d", element); + + element = EL_DEFAULT; /* dummy element used for artwork config */ + } + + ei = &element_info[element]; + + for(i=0; i < MAX_ELEMENT_NAME_LEN; i++) + ei->description[i] = getFile8Bit(file); + ei->description[MAX_ELEMENT_NAME_LEN] = 0; + + Properties[element][EP_BITFIELD_BASE] = getFile32BitBE(file); + ReadUnusedBytesFromFile(file, 4); /* reserved for more base properties */ + + ei->num_change_pages = getFile8Bit(file); + + /* some free bytes for future base property values and padding */ + ReadUnusedBytesFromFile(file, 5); + + chunk_size_expected = LEVEL_CHUNK_CUS4_SIZE(ei->num_change_pages); + if (chunk_size_expected != chunk_size) + { + ReadUnusedBytesFromFile(file, chunk_size - 48); + return chunk_size_expected; + } + + /* read custom property values */ + + ei->use_gfx_element = getFile8Bit(file); + ei->gfx_element = checkLevelElement(getFile16BitBE(file)); + + ei->collect_score = getFile8Bit(file); + ei->collect_count = getFile8Bit(file); + + ei->push_delay_fixed = getFile16BitBE(file); + ei->push_delay_random = getFile16BitBE(file); + ei->move_delay_fixed = getFile16BitBE(file); + ei->move_delay_random = getFile16BitBE(file); + + ei->move_pattern = getFile16BitBE(file); + ei->move_direction_initial = getFile8Bit(file); + ei->move_stepsize = getFile8Bit(file); + + ei->slippery_type = getFile8Bit(file); + + for(y=0; y<3; y++) + for(x=0; x<3; x++) + ei->content[x][y] = checkLevelElement(getFile16BitBE(file)); + + /* some free bytes for future custom property values and padding */ + ReadUnusedBytesFromFile(file, 12); + + /* read change property values */ + + setElementChangePages(ei, ei->num_change_pages); + + for (i=0; i < ei->num_change_pages; i++) + { + struct ElementChangeInfo *change = &ei->change_page[i]; + + /* always start with reliable default values */ + setElementChangeInfoToDefaults(change); + + change->events = getFile32BitBE(file); + + change->target_element = checkLevelElement(getFile16BitBE(file)); + + change->delay_fixed = getFile16BitBE(file); + change->delay_random = getFile16BitBE(file); + change->delay_frames = getFile16BitBE(file); + + change->trigger_element = checkLevelElement(getFile16BitBE(file)); + + change->explode = getFile8Bit(file); + change->use_content = getFile8Bit(file); + change->only_complete = getFile8Bit(file); + change->use_random_change = getFile8Bit(file); + + change->random = getFile8Bit(file); + change->power = getFile8Bit(file); + + for(y=0; y<3; y++) + for(x=0; x<3; x++) + change->content[x][y] = checkLevelElement(getFile16BitBE(file)); + + change->can_change = getFile8Bit(file); + + /* some free bytes for future change property values and padding */ + ReadUnusedBytesFromFile(file, 9); + } + + /* mark this custom element as modified */ + ei->modified_settings = TRUE; + + return chunk_size; +} + void LoadLevelFromFilename(struct LevelInfo *level, char *filename) { char cookie[MAX_LINE_LEN]; @@ -671,9 +872,11 @@ void LoadLevelFromFilename(struct LevelInfo *level, char *filename) { "BODY", -1, LoadLevel_BODY }, { "CONT", -1, LoadLevel_CONT }, { "CNT2", LEVEL_CHUNK_CNT2_SIZE, LoadLevel_CNT2 }, + { "CNT3", -1, LoadLevel_CNT3 }, { "CUS1", -1, LoadLevel_CUS1 }, { "CUS2", -1, LoadLevel_CUS2 }, { "CUS3", -1, LoadLevel_CUS3 }, + { "CUS4", -1, LoadLevel_CUS4 }, { NULL, 0, NULL } }; @@ -789,15 +992,15 @@ static void LoadLevel_InitElements(struct LevelInfo *level, char *filename) int i, j; /* map custom element change events that have changed in newer versions - (these following values have accidentally changed in version 3.0.1) */ + (these following values were accidentally changed in version 3.0.1) */ if (level->game_version <= VERSION_IDENT(3,0,0)) { for (i=0; i < NUM_CUSTOM_ELEMENTS; i++) { int element = EL_CUSTOM_START + i; - /* order of checking events to be mapped is important */ - for (j=CE_BY_OTHER; j >= CE_BY_PLAYER; j--) + /* order of checking and copying events to be mapped is important */ + for (j=CE_BY_OTHER_ACTION; j >= CE_BY_PLAYER; j--) { if (HAS_CHANGE_EVENT(element, j - 2)) { @@ -806,7 +1009,7 @@ static void LoadLevel_InitElements(struct LevelInfo *level, char *filename) } } - /* order of checking events to be mapped is important */ + /* order of checking and copying events to be mapped is important */ for (j=CE_OTHER_GETS_COLLECTED; j >= CE_COLLISION; j--) { if (HAS_CHANGE_EVENT(element, j - 1)) @@ -818,6 +1021,21 @@ static void LoadLevel_InitElements(struct LevelInfo *level, char *filename) } } + /* some custom element change events get mapped since version 3.0.3 */ + for (i=0; i < NUM_CUSTOM_ELEMENTS; i++) + { + int element = EL_CUSTOM_START + i; + + if (HAS_CHANGE_EVENT(element, CE_BY_PLAYER) || + HAS_CHANGE_EVENT(element, CE_BY_COLLISION)) + { + SET_CHANGE_EVENT(element, CE_BY_PLAYER, FALSE); + SET_CHANGE_EVENT(element, CE_BY_COLLISION, FALSE); + + SET_CHANGE_EVENT(element, CE_BY_DIRECT_ACTION, TRUE); + } + } + /* initialize "can_change" field for old levels with only one change page */ if (level->game_version <= VERSION_IDENT(3,0,2)) { @@ -1200,6 +1418,23 @@ static void SaveLevel_CNT2(FILE *file, struct LevelInfo *level, int element) putFile16BitBE(file, content_array[i][x][y]); } +static void SaveLevel_CNT3(FILE *file, struct LevelInfo *level, int element) +{ + int i; + int envelope_nr = element - EL_ENVELOPE_1; + int envelope_len = strlen(level->envelope_text[envelope_nr]) + 1; + + putFile16BitBE(file, element); + putFile16BitBE(file, envelope_len); + putFile8Bit(file, level->envelope_xsize[envelope_nr]); + putFile8Bit(file, level->envelope_ysize[envelope_nr]); + + WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT3_UNUSED); + + for(i=0; i < envelope_len; i++) + putFile8Bit(file, level->envelope_text[envelope_nr][i]); +} + #if 0 static void SaveLevel_CUS1(FILE *file, struct LevelInfo *level, int num_changed_custom_elements) @@ -1258,6 +1493,7 @@ static void SaveLevel_CUS2(FILE *file, struct LevelInfo *level, } #endif +#if 0 static void SaveLevel_CUS3(FILE *file, struct LevelInfo *level, int num_changed_custom_elements) { @@ -1337,12 +1573,90 @@ static void SaveLevel_CUS3(FILE *file, struct LevelInfo *level, if (check != num_changed_custom_elements) /* should not happen */ Error(ERR_WARN, "inconsistent number of custom element properties"); } +#endif + +static void SaveLevel_CUS4(FILE *file, struct LevelInfo *level, int element) +{ + struct ElementInfo *ei = &element_info[element]; + int i, x, y; + + putFile16BitBE(file, element); + + for(i=0; i < MAX_ELEMENT_NAME_LEN; i++) + putFile8Bit(file, ei->description[i]); + + putFile32BitBE(file, Properties[element][EP_BITFIELD_BASE]); + WriteUnusedBytesToFile(file, 4); /* reserved for more base properties */ + + putFile8Bit(file, ei->num_change_pages); + + /* some free bytes for future base property values and padding */ + WriteUnusedBytesToFile(file, 5); + + /* write custom property values */ + + putFile8Bit(file, ei->use_gfx_element); + putFile16BitBE(file, ei->gfx_element); + + putFile8Bit(file, ei->collect_score); + putFile8Bit(file, ei->collect_count); + + putFile16BitBE(file, ei->push_delay_fixed); + putFile16BitBE(file, ei->push_delay_random); + putFile16BitBE(file, ei->move_delay_fixed); + putFile16BitBE(file, ei->move_delay_random); + + putFile16BitBE(file, ei->move_pattern); + putFile8Bit(file, ei->move_direction_initial); + putFile8Bit(file, ei->move_stepsize); + + putFile8Bit(file, ei->slippery_type); + + for(y=0; y<3; y++) + for(x=0; x<3; x++) + putFile16BitBE(file, ei->content[x][y]); + + /* some free bytes for future custom property values and padding */ + WriteUnusedBytesToFile(file, 12); + + /* write change property values */ + + for (i=0; i < ei->num_change_pages; i++) + { + struct ElementChangeInfo *change = &ei->change_page[i]; + + putFile32BitBE(file, change->events); + + putFile16BitBE(file, change->target_element); + + putFile16BitBE(file, change->delay_fixed); + putFile16BitBE(file, change->delay_random); + putFile16BitBE(file, change->delay_frames); + + putFile16BitBE(file, change->trigger_element); + + putFile8Bit(file, change->explode); + putFile8Bit(file, change->use_content); + putFile8Bit(file, change->only_complete); + putFile8Bit(file, change->use_random_change); + + putFile8Bit(file, change->random); + putFile8Bit(file, change->power); + + for(y=0; y<3; y++) + for(x=0; x<3; x++) + putFile16BitBE(file, change->content[x][y]); + + putFile8Bit(file, change->can_change); + + /* some free bytes for future change property values and padding */ + WriteUnusedBytesToFile(file, 9); + } +} static void SaveLevelFromFilename(struct LevelInfo *level, char *filename) { int body_chunk_size; - int num_changed_custom_elements = 0; - int level_chunk_CUS3_size; int i, x, y; FILE *file; @@ -1379,12 +1693,6 @@ static void SaveLevelFromFilename(struct LevelInfo *level, char *filename) body_chunk_size = level->fieldx * level->fieldy * (level->encoding_16bit_field ? 2 : 1); - /* check for non-standard custom elements and calculate "CUS3" chunk size */ - for (i=0; i < NUM_CUSTOM_ELEMENTS; i++) - if (element_info[EL_CUSTOM_START + i].modified_settings) - num_changed_custom_elements++; - level_chunk_CUS3_size = LEVEL_CHUNK_CUS3_SIZE(num_changed_custom_elements); - putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED); putFileChunkBE(file, "CAVE", CHUNK_SIZE_NONE); @@ -1413,10 +1721,33 @@ static void SaveLevelFromFilename(struct LevelInfo *level, char *filename) SaveLevel_CNT2(file, level, EL_BD_AMOEBA); } - if (num_changed_custom_elements > 0 && !level->use_custom_template) + /* check for envelope content */ + for (i=0; i<4; i++) { - putFileChunkBE(file, "CUS3", level_chunk_CUS3_size); - SaveLevel_CUS3(file, level, num_changed_custom_elements); + if (strlen(level->envelope_text[i]) > 0) + { + int envelope_len = strlen(level->envelope_text[i]) + 1; + + putFileChunkBE(file, "CNT3", LEVEL_CHUNK_CNT3_HEADER + envelope_len); + SaveLevel_CNT3(file, level, EL_ENVELOPE_1 + i); + } + } + + /* check for non-default custom elements (unless using template level) */ + if (!level->use_custom_template) + { + for (i=0; i < NUM_CUSTOM_ELEMENTS; i++) + { + int element = EL_CUSTOM_START + i; + + if (element_info[element].modified_settings) + { + int num_change_pages = element_info[element].num_change_pages; + + putFileChunkBE(file, "CUS4", LEVEL_CHUNK_CUS4_SIZE(num_change_pages)); + SaveLevel_CUS4(file, level, element); + } + } } fclose(file); @@ -2065,9 +2396,10 @@ void SaveScore(int level_nr) #define SETUP_TOKEN_EDITOR_EL_DX_BOULDERDASH 6 #define SETUP_TOKEN_EDITOR_EL_CHARS 7 #define SETUP_TOKEN_EDITOR_EL_CUSTOM 8 -#define SETUP_TOKEN_EDITOR_EL_HEADLINES 9 +#define SETUP_TOKEN_EDITOR_EL_CUSTOM_MORE 9 +#define SETUP_TOKEN_EDITOR_EL_HEADLINES 10 -#define NUM_EDITOR_SETUP_TOKENS 10 +#define NUM_EDITOR_SETUP_TOKENS 11 /* shortcut setup */ #define SETUP_TOKEN_SHORTCUT_SAVE_GAME 0 @@ -2479,6 +2811,20 @@ void LoadCustomElementDescriptions() freeSetupFileHash(setup_file_hash); } +static int get_special_integer_from_string(char *string_raw) +{ + char *string = getStringToLower(string_raw); + int value = (strcmp(string, "none") == 0 ? 0 : + strcmp(string, "short") == 0 ? 1 : + strcmp(string, "full") == 0 ? 2 : + strcmp(string, "default") == 0 ? 0 : + strcmp(string, "curtain") == 0 ? 1 : -1); + + free(string); + + return value; +} + void LoadSpecialMenuDesignSettings() { char *filename = getCustomArtworkConfigFilename(ARTWORK_TYPE_GRAPHICS); @@ -2489,8 +2835,15 @@ void LoadSpecialMenuDesignSettings() for (i=0; image_config_vars[i].token != NULL; i++) for (j=0; image_config[j].token != NULL; j++) if (strcmp(image_config_vars[i].token, image_config[j].token) == 0) - *image_config_vars[i].value = - get_integer_from_string(image_config[j].value); + { + if (strcmp(image_config_vars[i].token, "game.envelope.anim_mode") == 0 + || strcmp(image_config_vars[i].token, "door.anim_mode") == 0) + *image_config_vars[i].value = + get_special_integer_from_string(image_config[j].value); + else + *image_config_vars[i].value = + get_integer_from_string(image_config[j].value); + } if ((setup_file_hash = loadSetupFileHash(filename)) == NULL) return; @@ -2516,7 +2869,13 @@ void LoadSpecialMenuDesignSettings() char *value = getHashEntry(setup_file_hash, image_config_vars[i].token); if (value != NULL) - *image_config_vars[i].value = get_integer_from_string(value); + { + if (strcmp(image_config_vars[i].token, "game.envelope.anim_mode") == 0 + || strcmp(image_config_vars[i].token, "door.anim_mode") == 0) + *image_config_vars[i].value = get_special_integer_from_string(value); + else + *image_config_vars[i].value = get_integer_from_string(value); + } } freeSetupFileHash(setup_file_hash);