X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Ffiles.c;h=61bd1af81bc931728934b5d0e0788ab1e611ac04;hb=d3eee47071cee093667ee49857d05d4f0142733e;hp=efbe71aa62d25a4585b83bb844becd482d7408a2;hpb=8e5671db64b55432158b1d43d7fd2e684544ebeb;p=rocksndiamonds.git diff --git a/src/files.c b/src/files.c index efbe71aa..61bd1af8 100644 --- a/src/files.c +++ b/src/files.c @@ -34,8 +34,6 @@ #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 */ @@ -74,11 +72,13 @@ 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; change->delay_random = 0; - change->delay_frames = -1; /* later set to reliable default value */ + change->delay_frames = 1; change->trigger_element = EL_EMPTY_SPACE; @@ -86,7 +86,7 @@ void setElementChangeInfoToDefaults(struct ElementChangeInfo *change) change->use_content = FALSE; change->only_complete = FALSE; change->use_random_change = FALSE; - change->random = 0; + change->random = 100; change->power = CP_NON_DESTRUCTIVE; for(x=0; x<3; x++) @@ -128,7 +128,7 @@ static void setLevelInfoToDefaults(struct LevelInfo *level) level->time_timegate = 10; level->amoeba_content = EL_DIAMOND; level->double_speed = FALSE; - level->gravity = FALSE; + level->initial_gravity = FALSE; level->em_slippery_gems = FALSE; level->use_custom_template = FALSE; @@ -141,9 +141,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; @@ -183,8 +186,8 @@ static void setLevelInfoToDefaults(struct LevelInfo *level) element_info[element].collect_score = 10; /* special default */ element_info[element].collect_count = 1; /* special default */ - element_info[element].push_delay_fixed = 2; /* special default */ - element_info[element].push_delay_random = 8; /* special default */ + element_info[element].push_delay_fixed = -1; /* initialize later */ + element_info[element].push_delay_random = -1; /* initialize later */ element_info[element].move_delay_fixed = 0; element_info[element].move_delay_random = 0; @@ -272,15 +275,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; } @@ -321,7 +372,7 @@ static int LoadLevel_HEAD(FILE *file, int chunk_size, struct LevelInfo *level) level->time_wheel = getFile8Bit(file); level->amoeba_content = checkLevelElement(getFile8Bit(file)); level->double_speed = (getFile8Bit(file) == 1 ? TRUE : FALSE); - level->gravity = (getFile8Bit(file) == 1 ? TRUE : FALSE); + level->initial_gravity = (getFile8Bit(file) == 1 ? TRUE : FALSE); level->encoding_16bit_field = (getFile8Bit(file) == 1 ? TRUE : FALSE); level->em_slippery_gems = (getFile8Bit(file) == 1 ? TRUE : FALSE); @@ -458,13 +509,20 @@ static int LoadLevel_CNT3(FILE *file, int chunk_size, struct LevelInfo *level) { int i; int element; + int envelope_nr; int envelope_len; int chunk_size_expected; element = checkLevelElement(getFile16BitBE(file)); + if (!IS_ENVELOPE(element)) + element = EL_ENVELOPE_1; + + envelope_nr = element - EL_ENVELOPE_1; + envelope_len = getFile16BitBE(file); - level->envelope_xsize = getFile8Bit(file); - level->envelope_ysize = getFile8Bit(file); + + level->envelope_xsize[envelope_nr] = getFile8Bit(file); + level->envelope_ysize[envelope_nr] = getFile8Bit(file); ReadUnusedBytesFromFile(file, LEVEL_CHUNK_CNT3_UNUSED); @@ -477,7 +535,7 @@ static int LoadLevel_CNT3(FILE *file, int chunk_size, struct LevelInfo *level) } for(i=0; i < envelope_len; i++) - level->envelope[i] = getFile8Bit(file); + level->envelope_text[envelope_nr][i] = getFile8Bit(file); return chunk_size; } @@ -689,10 +747,15 @@ static int LoadLevel_CUS4(FILE *file, int chunk_size, struct LevelInfo *level) /* 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)); @@ -717,8 +780,13 @@ static int LoadLevel_CUS4(FILE *file, int chunk_size, struct LevelInfo *level) change->can_change = getFile8Bit(file); + change->sides = getFile8Bit(file); + + if (change->sides == CH_SIDE_NONE) /* correct empty sides field */ + change->sides = CH_SIDE_ANY; + /* some free bytes for future change property values and padding */ - ReadUnusedBytesFromFile(file, 9); + ReadUnusedBytesFromFile(file, 8); } /* mark this custom element as modified */ @@ -857,8 +925,6 @@ void LoadLevelFromFilename(struct LevelInfo *level, char *filename) fclose(file); } -#if 1 - static void LoadLevel_InitVersion(struct LevelInfo *level, char *filename) { if (leveldir_current == NULL) /* only when dumping level */ @@ -927,7 +993,7 @@ 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++) @@ -983,122 +1049,36 @@ static void LoadLevel_InitElements(struct LevelInfo *level, char *filename) } } - /* initialize element properties for level editor etc. */ - InitElementPropertiesEngine(level->game_version); -} - -static void LoadLevel_InitPlayfield(struct LevelInfo *level, char *filename) -{ - int x, y; - - /* map elements that have changed in newer versions */ - for(y=0; yfieldy; y++) + /* set default push delay values (corrected since version 3.0.7) */ + if (level->game_version < VERSION_IDENT(3,0,7)) { - for(x=0; xfieldx; x++) - { - int element = level->field[x][y]; - - if (level->game_version <= VERSION_IDENT(2,2,0)) - { - /* map game font elements */ - element = (element == EL_CHAR('[') ? EL_CHAR_AUMLAUT : - element == EL_CHAR('\\') ? EL_CHAR_OUMLAUT : - element == EL_CHAR(']') ? EL_CHAR_UUMLAUT : - element == EL_CHAR('^') ? EL_CHAR_COPYRIGHT : element); - } - - if (level->game_version < VERSION_IDENT(3,0,0)) - { - /* map Supaplex gravity tube elements */ - element = (element == EL_SP_GRAVITY_PORT_LEFT ? EL_SP_PORT_LEFT : - element == EL_SP_GRAVITY_PORT_RIGHT ? EL_SP_PORT_RIGHT : - element == EL_SP_GRAVITY_PORT_UP ? EL_SP_PORT_UP : - element == EL_SP_GRAVITY_PORT_DOWN ? EL_SP_PORT_DOWN : - element); - } - - level->field[x][y] = element; - } - } - - /* copy elements to runtime playfield array */ - for(x=0; xfield[x][y]; - - /* initialize level size variables for faster access */ - lev_fieldx = level->fieldx; - lev_fieldy = level->fieldy; - - /* determine border element for this level */ - SetBorderElement(); -} - -#else - -static void LoadLevel_InitLevel(struct LevelInfo *level, char *filename) -{ - int i, j, x, y; - - if (leveldir_current == NULL) /* only when dumping level */ - return; - - /* determine correct game engine version of current level */ - if (IS_LEVELCLASS_CONTRIBUTION(leveldir_current) || - IS_LEVELCLASS_USER(leveldir_current)) - { -#if 0 - printf("\n::: This level is private or contributed: '%s'\n", filename); -#endif - - /* For user contributed and private 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). */ - - /* do some special adjustments to support older level versions */ - if (level->file_version == FILE_VERSION_1_0) - { - Error(ERR_WARN, "level file '%s'has version number 1.0", filename); - Error(ERR_WARN, "using high speed movement for player"); - - /* player was faster than monsters in (pre-)1.0 levels */ - 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)) - level->em_slippery_gems = TRUE; + game.default_push_delay_fixed = 2; + game.default_push_delay_random = 8; } else { -#if 0 - printf("\n::: ALWAYS USE LATEST ENGINE FOR THIS LEVEL: [%d] '%s'\n", - leveldir_current->sort_priority, filename); -#endif + game.default_push_delay_fixed = 8; + game.default_push_delay_random = 8; + } - /* Always use the latest version of the game engine for all but - user contributed and private levels; this allows for actual - corrections in the game engine to take effect for existing, - converted levels (from "classic" or other existing games) to - make the game emulation more accurate, while (hopefully) not - breaking existing levels created from other players. */ + /* set uninitialized push delay values of custom elements in older levels */ + for (i=0; i < NUM_CUSTOM_ELEMENTS; i++) + { + int element = EL_CUSTOM_START + i; - level->game_version = GAME_VERSION_ACTUAL; + if (element_info[element].push_delay_fixed == -1) + element_info[element].push_delay_fixed = game.default_push_delay_fixed; + if (element_info[element].push_delay_random == -1) + element_info[element].push_delay_random = game.default_push_delay_random; + } - /* Set special EM style gems behaviour: EM style gems slip down from - normal, steel and growing wall. As this is a more fundamental change, - it seems better to set the default behaviour to "off" (as it is more - natural) and make it configurable in the level editor (as a property - of gem style elements). Already existing converted levels (neither - private nor contributed levels) are changed to the new behaviour. */ + /* initialize element properties for level editor etc. */ + InitElementPropertiesEngine(level->game_version); +} - if (level->file_version < FILE_VERSION_2_0) - level->em_slippery_gems = TRUE; - } +static void LoadLevel_InitPlayfield(struct LevelInfo *level, char *filename) +{ + int x, y; /* map elements that have changed in newer versions */ for(y=0; yfieldy; y++) @@ -1130,48 +1110,6 @@ static void LoadLevel_InitLevel(struct LevelInfo *level, char *filename) } } - /* map custom element change events that have changed in newer versions - (these following values have 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--) - { - if (HAS_CHANGE_EVENT(element, j - 2)) - { - SET_CHANGE_EVENT(element, j - 2, FALSE); - SET_CHANGE_EVENT(element, j, TRUE); - } - } - - /* order of checking events to be mapped is important */ - for (j=CE_OTHER_GETS_COLLECTED; j >= CE_COLLISION; j--) - { - if (HAS_CHANGE_EVENT(element, j - 1)) - { - SET_CHANGE_EVENT(element, j - 1, FALSE); - SET_CHANGE_EVENT(element, j, TRUE); - } - } - } - } - - /* initialize "can_change" field for old levels with only one change page */ - if (level->game_version <= VERSION_IDENT(3,0,2)) - { - for (i=0; i < NUM_CUSTOM_ELEMENTS; i++) - { - int element = EL_CUSTOM_START + i; - - if (CAN_CHANGE(element)) - element_info[element].change->can_change = TRUE; - } - } - /* copy elements to runtime playfield array */ for(x=0; xgame_version); } -#endif - void LoadLevelTemplate(int level_nr) { char *filename = getLevelFilename(level_nr); @@ -1253,7 +1186,7 @@ static void SaveLevel_HEAD(FILE *file, struct LevelInfo *level) putFile8Bit(file, (level->encoding_16bit_amoeba ? EL_EMPTY : level->amoeba_content)); putFile8Bit(file, (level->double_speed ? 1 : 0)); - putFile8Bit(file, (level->gravity ? 1 : 0)); + putFile8Bit(file, (level->initial_gravity ? 1 : 0)); putFile8Bit(file, (level->encoding_16bit_field ? 1 : 0)); putFile8Bit(file, (level->em_slippery_gems ? 1 : 0)); @@ -1356,17 +1289,18 @@ static void SaveLevel_CNT2(FILE *file, struct LevelInfo *level, int element) static void SaveLevel_CNT3(FILE *file, struct LevelInfo *level, int element) { int i; - int envelope_len = strlen(level->envelope) + 1; + 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); - putFile8Bit(file, level->envelope_ysize); + 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[i]); + putFile8Bit(file, level->envelope_text[envelope_nr][i]); } #if 0 @@ -1583,8 +1517,10 @@ static void SaveLevel_CUS4(FILE *file, struct LevelInfo *level, int element) putFile8Bit(file, change->can_change); + putFile8Bit(file, change->sides); + /* some free bytes for future change property values and padding */ - WriteUnusedBytesToFile(file, 9); + WriteUnusedBytesToFile(file, 8); } } @@ -1656,12 +1592,15 @@ static void SaveLevelFromFilename(struct LevelInfo *level, char *filename) } /* check for envelope content */ - if (strlen(level->envelope) > 0) + for (i=0; i<4; i++) { - int envelope_len = strlen(level->envelope) + 1; + 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); + 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) */ @@ -1722,7 +1661,7 @@ void DumpLevel(struct LevelInfo *level) printf("\n"); printf("Amoeba Speed: %d\n", level->amoeba_speed); printf("\n"); - printf("Gravity: %s\n", (level->gravity ? "yes" : "no")); + printf("Gravity: %s\n", (level->initial_gravity ? "yes" : "no")); printf("Double Speed Movement: %s\n", (level->double_speed ? "yes" : "no")); printf("EM style slippery gems: %s\n", (level->em_slippery_gems ? "yes" : "no")); @@ -2753,7 +2692,8 @@ void LoadSpecialMenuDesignSettings() 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); + get_auto_parameter_value(image_config_vars[i].token, + image_config[j].value); if ((setup_file_hash = loadSetupFileHash(filename)) == NULL) return; @@ -2779,7 +2719,8 @@ 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); + *image_config_vars[i].value = + get_auto_parameter_value(image_config_vars[i].token, value); } freeSetupFileHash(setup_file_hash);