X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Ffiles.c;h=7237f57722a570efe9f36d227846ae8b24400abf;hb=7ecf99096c7c23909ada034e05d971464f66552f;hp=124b1db04b05c7b8fce2925962392718e6f9f7bb;hpb=123c5a87fa9cf6d9759ed7911d3544f05afdd11c;p=rocksndiamonds.git diff --git a/src/files.c b/src/files.c index 124b1db0..7237f577 100644 --- a/src/files.c +++ b/src/files.c @@ -1596,11 +1596,203 @@ void setElementChangeInfoToDefaults(struct ElementChangeInfo *change) change->post_change_function = NULL; } -static void setLevelInfoToDefaults(struct LevelInfo *level) +#if 1 + +static void setLevelInfoToDefaults_Level(struct LevelInfo *level) +{ + int i, x, y; + + li = *level; /* copy level data into temporary buffer */ + setConfigToDefaultsFromConfigList(chunk_config_INFO); + *level = li; /* copy temporary buffer back to level data */ + + setLevelInfoToDefaults_EM(); + setLevelInfoToDefaults_SP(); + + level->native_em_level = &native_em_level; + level->native_sp_level = &native_sp_level; + + level->file_version = FILE_VERSION_ACTUAL; + level->game_version = GAME_VERSION_ACTUAL; + + level->creation_date = getCurrentDate(); + + level->encoding_16bit_field = TRUE; + level->encoding_16bit_yamyam = TRUE; + level->encoding_16bit_amoeba = TRUE; + + for (x = 0; x < MAX_LEV_FIELDX; x++) + for (y = 0; y < MAX_LEV_FIELDY; y++) + level->field[x][y] = EL_SAND; + + for (i = 0; i < MAX_LEVEL_NAME_LEN; i++) + level->name[i] = '\0'; + for (i = 0; i < MAX_LEVEL_AUTHOR_LEN; i++) + level->author[i] = '\0'; + + strcpy(level->name, NAMELESS_LEVEL_NAME); + strcpy(level->author, ANONYMOUS_NAME); + + level->field[0][0] = EL_PLAYER_1; + level->field[STD_LEV_FIELDX - 1][STD_LEV_FIELDY - 1] = EL_EXIT_CLOSED; + + BorderElement = EL_STEELWALL; + + /* set all bug compatibility flags to "false" => do not emulate this bug */ + level->use_action_after_change_bug = FALSE; + + if (leveldir_current) + { + /* try to determine better author name than 'anonymous' */ + if (!strEqual(leveldir_current->author, ANONYMOUS_NAME)) + { + strncpy(level->author, leveldir_current->author, MAX_LEVEL_AUTHOR_LEN); + level->author[MAX_LEVEL_AUTHOR_LEN] = '\0'; + } + else + { + switch (LEVELCLASS(leveldir_current)) + { + case LEVELCLASS_TUTORIAL: + strcpy(level->author, PROGRAM_AUTHOR_STRING); + break; + + case LEVELCLASS_CONTRIB: + strncpy(level->author, leveldir_current->name, MAX_LEVEL_AUTHOR_LEN); + level->author[MAX_LEVEL_AUTHOR_LEN] = '\0'; + break; + + case LEVELCLASS_PRIVATE: + strncpy(level->author, getRealName(), MAX_LEVEL_AUTHOR_LEN); + level->author[MAX_LEVEL_AUTHOR_LEN] = '\0'; + break; + + default: + /* keep default value */ + break; + } + } + } +} + +static void setLevelInfoToDefaults_Elements(struct LevelInfo *level) +{ + static boolean clipboard_elements_initialized = FALSE; + int i; + + InitElementPropertiesStatic(); + + li = *level; /* copy level data into temporary buffer */ + setConfigToDefaultsFromConfigList(chunk_config_ELEM); + *level = li; /* copy temporary buffer back to level data */ + + for (i = 0; i < MAX_NUM_ELEMENTS; i++) + { + int element = i; + struct ElementInfo *ei = &element_info[element]; + + /* never initialize clipboard elements after the very first time */ + /* (to be able to use clipboard elements between several levels) */ + if (IS_CLIPBOARD_ELEMENT(element) && clipboard_elements_initialized) + continue; + + if (IS_ENVELOPE(element)) + { + int envelope_nr = element - EL_ENVELOPE_1; + + setConfigToDefaultsFromConfigList(chunk_config_NOTE); + + level->envelope[envelope_nr] = xx_envelope; + } + + if (IS_CUSTOM_ELEMENT(element) || + IS_GROUP_ELEMENT(element) || + IS_INTERNAL_ELEMENT(element)) + { + xx_ei = *ei; /* copy element data into temporary buffer */ + + setConfigToDefaultsFromConfigList(chunk_config_CUSX_base); + + *ei = xx_ei; + } + + setElementChangePages(ei, 1); + setElementChangeInfoToDefaults(ei->change); + + if (IS_CUSTOM_ELEMENT(element) || + IS_GROUP_ELEMENT(element) || + IS_INTERNAL_ELEMENT(element)) + { + setElementDescriptionToDefault(ei); + + ei->modified_settings = FALSE; + } + + if (IS_CUSTOM_ELEMENT(element) || + IS_INTERNAL_ELEMENT(element)) + { + /* internal values used in level editor */ + + ei->access_type = 0; + ei->access_layer = 0; + ei->access_protected = 0; + ei->walk_to_action = 0; + ei->smash_targets = 0; + ei->deadliness = 0; + + ei->can_explode_by_fire = FALSE; + ei->can_explode_smashed = FALSE; + ei->can_explode_impact = FALSE; + + ei->current_change_page = 0; + } + + if (IS_GROUP_ELEMENT(element) || + IS_INTERNAL_ELEMENT(element)) + { + struct ElementGroupInfo *group; + + /* initialize memory for list of elements in group */ + if (ei->group == NULL) + ei->group = checked_malloc(sizeof(struct ElementGroupInfo)); + + group = ei->group; + + xx_group = *group; /* copy group data into temporary buffer */ + + setConfigToDefaultsFromConfigList(chunk_config_GRPX); + + *group = xx_group; + } + } + + clipboard_elements_initialized = TRUE; +} + +static void setLevelInfoToDefaults(struct LevelInfo *level, + boolean level_info_only) +{ + setLevelInfoToDefaults_Level(level); + + if (!level_info_only) + setLevelInfoToDefaults_Elements(level); + + level->no_valid_file = FALSE; + + level->changed = FALSE; +} + +#else + +static void setLevelInfoToDefaults(struct LevelInfo *level, + boolean level_info_only) { static boolean clipboard_elements_initialized = FALSE; int i, x, y; + if (level_info_only) + return; + InitElementPropertiesStatic(); li = *level; /* copy level data into temporary buffer */ @@ -1731,40 +1923,42 @@ static void setLevelInfoToDefaults(struct LevelInfo *level) /* set all bug compatibility flags to "false" => do not emulate this bug */ level->use_action_after_change_bug = FALSE; - if (leveldir_current == NULL) /* only when dumping level */ - return; - - /* try to determine better author name than 'anonymous' */ - if (!strEqual(leveldir_current->author, ANONYMOUS_NAME)) + if (leveldir_current) { - strncpy(level->author, leveldir_current->author, MAX_LEVEL_AUTHOR_LEN); - level->author[MAX_LEVEL_AUTHOR_LEN] = '\0'; - } - else - { - switch (LEVELCLASS(leveldir_current)) + /* try to determine better author name than 'anonymous' */ + if (!strEqual(leveldir_current->author, ANONYMOUS_NAME)) { - case LEVELCLASS_TUTORIAL: - strcpy(level->author, PROGRAM_AUTHOR_STRING); - break; - - case LEVELCLASS_CONTRIB: - strncpy(level->author, leveldir_current->name, MAX_LEVEL_AUTHOR_LEN); - level->author[MAX_LEVEL_AUTHOR_LEN] = '\0'; - break; - - case LEVELCLASS_PRIVATE: - strncpy(level->author, getRealName(), MAX_LEVEL_AUTHOR_LEN); - level->author[MAX_LEVEL_AUTHOR_LEN] = '\0'; - break; - - default: - /* keep default value */ - break; + strncpy(level->author, leveldir_current->author, MAX_LEVEL_AUTHOR_LEN); + level->author[MAX_LEVEL_AUTHOR_LEN] = '\0'; + } + else + { + switch (LEVELCLASS(leveldir_current)) + { + case LEVELCLASS_TUTORIAL: + strcpy(level->author, PROGRAM_AUTHOR_STRING); + break; + + case LEVELCLASS_CONTRIB: + strncpy(level->author, leveldir_current->name, MAX_LEVEL_AUTHOR_LEN); + level->author[MAX_LEVEL_AUTHOR_LEN] = '\0'; + break; + + case LEVELCLASS_PRIVATE: + strncpy(level->author, getRealName(), MAX_LEVEL_AUTHOR_LEN); + level->author[MAX_LEVEL_AUTHOR_LEN] = '\0'; + break; + + default: + /* keep default value */ + break; + } } } } +#endif + static void setFileInfoToDefaults(struct LevelFileInfo *level_file_info) { level_file_info->nr = 0; @@ -1896,6 +2090,48 @@ static char *getSingleLevelBasename(int nr) return getSingleLevelBasenameExt(nr, LEVELFILE_EXTENSION); } +#if 1 + +static char *getPackedLevelBasename(int type) +{ + static char basename[MAX_FILENAME_LEN]; + char *directory = getCurrentLevelDir(); + Directory *dir; + DirectoryEntry *dir_entry; + + strcpy(basename, UNDEFINED_FILENAME); /* default: undefined file */ + + if ((dir = openDirectory(directory)) == NULL) + { + Error(ERR_WARN, "cannot read current level directory '%s'", directory); + + return basename; + } + + while ((dir_entry = readDirectory(dir)) != NULL) /* loop all entries */ + { + char *entry_basename = dir_entry->basename; + int entry_type = getFileTypeFromBasename(entry_basename); + + if (entry_type != LEVEL_FILE_TYPE_UNKNOWN) /* found valid level package */ + { + if (type == LEVEL_FILE_TYPE_UNKNOWN || + type == entry_type) + { + strcpy(basename, entry_basename); + + break; + } + } + } + + closeDirectory(dir); + + return basename; +} + +#else + static char *getPackedLevelBasename(int type) { static char basename[MAX_FILENAME_LEN]; @@ -1934,6 +2170,8 @@ static char *getPackedLevelBasename(int type) return basename; } +#endif + static char *getSingleLevelFilename(int nr) { return getLevelFilenameFromBasename(getSingleLevelBasename(nr)); @@ -2390,13 +2628,21 @@ static int LoadLevel_CNT2(FILE *file, int chunk_size, struct LevelInfo *level) { int i, x, y; int element; - int num_contents, content_xsize, content_ysize; + int num_contents; +#if 0 + int content_xsize, content_ysize; +#endif int content_array[MAX_ELEMENT_CONTENTS][3][3]; element = getMappedElement(getFile16BitBE(file)); num_contents = getFile8Bit(file); +#if 1 + getFile8Bit(file); /* content x size (unused) */ + getFile8Bit(file); /* content y size (unused) */ +#else content_xsize = getFile8Bit(file); content_ysize = getFile8Bit(file); +#endif ReadUnusedBytesFromFile(file, LEVEL_CHUNK_CNT2_UNUSED); @@ -3120,7 +3366,8 @@ static int LoadLevel_GRPX(FILE *file, int chunk_size, struct LevelInfo *level) } static void LoadLevelFromFileInfo_RND(struct LevelInfo *level, - struct LevelFileInfo *level_file_info) + struct LevelFileInfo *level_file_info, + boolean level_info_only) { char *filename = level_file_info->filename; char cookie[MAX_LINE_LEN]; @@ -3133,7 +3380,8 @@ static void LoadLevelFromFileInfo_RND(struct LevelInfo *level, level->no_valid_file = TRUE; #if 1 - Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename); + if (!level_info_only) + Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename); #else if (level != &level_template) Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename); @@ -3160,7 +3408,8 @@ static void LoadLevelFromFileInfo_RND(struct LevelInfo *level, else /* check for pre-2.0 file format with cookie string */ { strcpy(cookie, chunk_name); - fgets(&cookie[4], MAX_LINE_LEN - 4, file); + if (fgets(&cookie[4], MAX_LINE_LEN - 4, file) == NULL) + cookie[4] = '\0'; if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n') cookie[strlen(cookie) - 1] = '\0'; @@ -4091,7 +4340,8 @@ static void LoadLevelFromFileStream_SP(FILE *file, struct LevelInfo *level, } static void LoadLevelFromFileInfo_SP(struct LevelInfo *level, - struct LevelFileInfo *level_file_info) + struct LevelFileInfo *level_file_info, + boolean level_info_only) { char *filename = level_file_info->filename; FILE *file; @@ -4109,7 +4359,8 @@ static void LoadLevelFromFileInfo_SP(struct LevelInfo *level, { level->no_valid_file = TRUE; - Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename); + if (!level_info_only) + Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename); return; } @@ -4282,25 +4533,8 @@ void CopyNativeLevel_RND_to_SP(struct LevelInfo *level) level_sp->height = level->fieldy; for (x = 0; x < level->fieldx; x++) - { for (y = 0; y < level->fieldy; y++) - { - int element_old = level->field[x][y]; - int element_new; - - if (element_old >= EL_SP_START && - element_old <= EL_SP_END) - element_new = element_old - EL_SP_START; - else if (element_old == EL_EMPTY_SPACE) - element_new = 0x00; - else if (element_old == EL_INVISIBLE_WALL) - element_new = 0x28; - else - element_new = 0x20; /* map unknown elements to yellow "hardware" */ - - level_sp->playfield[x][y] = element_new; - } - } + level_sp->playfield[x][y] = map_element_RND_to_SP(level->field[x][y]); header->InitialGravity = (level->initial_player_gravity[0] ? 1 : 0); @@ -4387,20 +4621,12 @@ void CopyNativeLevel_SP_to_RND(struct LevelInfo *level) for (y = 0; y < level->fieldy; y++) { int element_old = level_sp->playfield[x][y]; - int element_new; + int element_new = getMappedElement(map_element_SP_to_RND(element_old)); - if (element_old <= 0x27) - element_new = getMappedElement(EL_SP_START + element_old); - else if (element_old == 0x28) - element_new = EL_INVISIBLE_WALL; - else - { + if (element_new == EL_UNKNOWN) Error(ERR_WARN, "invalid element %d at position %d, %d", element_old, x, y); - element_new = EL_UNKNOWN; - } - level->field[x][y] = element_new; } } @@ -6211,7 +6437,8 @@ static void LoadLevelFromFileStream_DC(FILE *file, struct LevelInfo *level, } static void LoadLevelFromFileInfo_DC(struct LevelInfo *level, - struct LevelFileInfo *level_file_info) + struct LevelFileInfo *level_file_info, + boolean level_info_only) { char *filename = level_file_info->filename; FILE *file; @@ -6223,7 +6450,8 @@ static void LoadLevelFromFileInfo_DC(struct LevelInfo *level, { level->no_valid_file = TRUE; - Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename); + if (!level_info_only) + Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename); return; } @@ -6233,7 +6461,8 @@ static void LoadLevelFromFileInfo_DC(struct LevelInfo *level, if (level_file_info->packed) { /* read "magic bytes" from start of file */ - fgets(magic_bytes, num_magic_bytes + 1, file); + if (fgets(magic_bytes, num_magic_bytes + 1, file) == NULL) + magic_bytes[0] = '\0'; /* check "magic bytes" for correct file format */ if (!strPrefix(magic_bytes, "DC2")) @@ -6326,7 +6555,8 @@ static void LoadLevelFromFileInfo_DC(struct LevelInfo *level, { level->no_valid_file = TRUE; - Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename); + if (!level_info_only) + Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename); return; } @@ -6560,7 +6790,8 @@ int getMappedElement_SB(int element_ascii, boolean use_ces) } static void LoadLevelFromFileInfo_SB(struct LevelInfo *level, - struct LevelFileInfo *level_file_info) + struct LevelFileInfo *level_file_info, + boolean level_info_only) { char *filename = level_file_info->filename; char line[MAX_LINE_LEN], line_raw[MAX_LINE_LEN], previous_line[MAX_LINE_LEN]; @@ -6576,7 +6807,7 @@ static void LoadLevelFromFileInfo_SB(struct LevelInfo *level, boolean load_xsb_to_ces = check_special_flags("load_xsb_to_ces"); int file_level_nr = 0; int line_nr = 0; - int x, y; + int x = 0, y = 0; /* initialized to make compilers happy */ #if 0 printf("::: looking for level number %d [%d]\n", @@ -6590,7 +6821,8 @@ static void LoadLevelFromFileInfo_SB(struct LevelInfo *level, { level->no_valid_file = TRUE; - Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename); + if (!level_info_only) + Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename); return; } @@ -6867,14 +7099,16 @@ static void LoadLevelFromFileInfo_SB(struct LevelInfo *level, /* ------------------------------------------------------------------------- */ static void LoadLevelFromFileInfo_EM(struct LevelInfo *level, - struct LevelFileInfo *level_file_info) + struct LevelFileInfo *level_file_info, + boolean level_info_only) { - if (!LoadNativeLevel_EM(level_file_info->filename)) + if (!LoadNativeLevel_EM(level_file_info->filename, level_info_only)) level->no_valid_file = TRUE; } static void LoadLevelFromFileInfo_SP(struct LevelInfo *level, - struct LevelFileInfo *level_file_info) + struct LevelFileInfo *level_file_info, + boolean level_info_only) { int pos = 0; @@ -6882,7 +7116,7 @@ static void LoadLevelFromFileInfo_SP(struct LevelInfo *level, if (level_file_info->packed) pos = level_file_info->nr - leveldir_current->first_level; - if (!LoadNativeLevel_SP(level_file_info->filename, pos)) + if (!LoadNativeLevel_SP(level_file_info->filename, pos, level_info_only)) level->no_valid_file = TRUE; } @@ -6921,44 +7155,49 @@ void SaveNativeLevel(struct LevelInfo *level) /* functions for loading generic level */ /* ------------------------------------------------------------------------- */ -void LoadLevelFromFileInfo(struct LevelInfo *level, - struct LevelFileInfo *level_file_info) +static void LoadLevelFromFileInfo(struct LevelInfo *level, + struct LevelFileInfo *level_file_info, + boolean level_info_only) { /* always start with reliable default values */ - setLevelInfoToDefaults(level); + setLevelInfoToDefaults(level, level_info_only); switch (level_file_info->type) { case LEVEL_FILE_TYPE_RND: - LoadLevelFromFileInfo_RND(level, level_file_info); + LoadLevelFromFileInfo_RND(level, level_file_info, level_info_only); break; case LEVEL_FILE_TYPE_EM: - LoadLevelFromFileInfo_EM(level, level_file_info); + LoadLevelFromFileInfo_EM(level, level_file_info, level_info_only); level->game_engine_type = GAME_ENGINE_TYPE_EM; break; case LEVEL_FILE_TYPE_SP: - LoadLevelFromFileInfo_SP(level, level_file_info); + LoadLevelFromFileInfo_SP(level, level_file_info, level_info_only); level->game_engine_type = GAME_ENGINE_TYPE_SP; break; case LEVEL_FILE_TYPE_DC: - LoadLevelFromFileInfo_DC(level, level_file_info); + LoadLevelFromFileInfo_DC(level, level_file_info, level_info_only); break; case LEVEL_FILE_TYPE_SB: - LoadLevelFromFileInfo_SB(level, level_file_info); + LoadLevelFromFileInfo_SB(level, level_file_info, level_info_only); break; default: - LoadLevelFromFileInfo_RND(level, level_file_info); + LoadLevelFromFileInfo_RND(level, level_file_info, level_info_only); break; } /* if level file is invalid, restore level structure to default values */ if (level->no_valid_file) - setLevelInfoToDefaults(level); + { + setLevelInfoToDefaults(level, level_info_only); + + level->no_valid_file = TRUE; /* but keep "no valid file" flag */ + } if (level->game_engine_type == GAME_ENGINE_TYPE_UNKNOWN) level->game_engine_type = GAME_ENGINE_TYPE_RND; @@ -6978,7 +7217,7 @@ void LoadLevelFromFilename(struct LevelInfo *level, char *filename) level_file_info.type = LEVEL_FILE_TYPE_RND; /* no others supported yet */ level_file_info.filename = filename; - LoadLevelFromFileInfo(level, &level_file_info); + LoadLevelFromFileInfo(level, &level_file_info, FALSE); } static void LoadLevel_InitVersion(struct LevelInfo *level, char *filename) @@ -7366,7 +7605,7 @@ void LoadLevelTemplate(int nr) setLevelFileInfo(&level_template.file_info, nr); filename = level_template.file_info.filename; - LoadLevelFromFileInfo(&level_template, &level_template.file_info); + LoadLevelFromFileInfo(&level_template, &level_template.file_info, FALSE); LoadLevel_InitVersion(&level_template, filename); LoadLevel_InitElements(&level_template, filename); @@ -7381,7 +7620,7 @@ void LoadLevel(int nr) setLevelFileInfo(&level.file_info, nr); filename = level.file_info.filename; - LoadLevelFromFileInfo(&level, &level.file_info); + LoadLevelFromFileInfo(&level, &level.file_info, FALSE); if (level.use_custom_template) LoadLevelTemplate(-1); @@ -7393,6 +7632,20 @@ void LoadLevel(int nr) LoadLevel_InitNativeEngines(&level, filename); } +void LoadLevelInfoOnly(int nr) +{ +#if 0 + char *filename; +#endif + + setLevelFileInfo(&level.file_info, nr); +#if 0 + filename = level.file_info.filename; +#endif + + LoadLevelFromFileInfo(&level, &level.file_info, TRUE); +} + static int SaveLevel_VERS(FILE *file, struct LevelInfo *level) { int chunk_size = 0; @@ -8477,6 +8730,79 @@ static int LoadTape_BODY(FILE *file, int chunk_size, struct TapeInfo *tape) return chunk_size; } +void LoadTape_SokobanSolution(char *filename) +{ + FILE *file; + int move_delay = TILESIZE / level.initial_player_stepsize[0]; + + if (!(file = fopen(filename, MODE_READ))) + { + tape.no_valid_file = TRUE; + + return; + } + + while (!feof(file)) + { + unsigned char c = fgetc(file); + + if (feof(file)) + break; + + switch (c) + { + case 'u': + case 'U': + tape.pos[tape.length].action[0] = MV_UP; + tape.pos[tape.length].delay = move_delay + (c < 'a' ? 2 : 0); + tape.length++; + break; + + case 'd': + case 'D': + tape.pos[tape.length].action[0] = MV_DOWN; + tape.pos[tape.length].delay = move_delay + (c < 'a' ? 2 : 0); + tape.length++; + break; + + case 'l': + case 'L': + tape.pos[tape.length].action[0] = MV_LEFT; + tape.pos[tape.length].delay = move_delay + (c < 'a' ? 2 : 0); + tape.length++; + break; + + case 'r': + case 'R': + tape.pos[tape.length].action[0] = MV_RIGHT; + tape.pos[tape.length].delay = move_delay + (c < 'a' ? 2 : 0); + tape.length++; + break; + + case '\n': + case '\r': + case '\t': + case ' ': + /* ignore white-space characters */ + break; + + default: + tape.no_valid_file = TRUE; + + Error(ERR_WARN, "unsupported Sokoban solution file '%s' ['%d']", filename, c); + + break; + } + } + + fclose(file); + + if (tape.no_valid_file) + return; + + tape.length_seconds = GetTapeLength(); +} + void LoadTapeFromFilename(char *filename) { char cookie[MAX_LINE_LEN]; @@ -8487,6 +8813,13 @@ void LoadTapeFromFilename(char *filename) /* always start with reliable default values */ setTapeInfoToDefaults(); + if (strSuffix(filename, ".sln")) + { + LoadTape_SokobanSolution(filename); + + return; + } + if (!(file = fopen(filename, MODE_READ))) { tape.no_valid_file = TRUE; @@ -8512,7 +8845,8 @@ void LoadTapeFromFilename(char *filename) else /* check for pre-2.0 file format with cookie string */ { strcpy(cookie, chunk_name); - fgets(&cookie[4], MAX_LINE_LEN - 4, file); + if (fgets(&cookie[4], MAX_LINE_LEN - 4, file) == NULL) + cookie[4] = '\0'; if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n') cookie[strlen(cookie) - 1] = '\0'; @@ -8531,6 +8865,7 @@ void LoadTapeFromFilename(char *filename) Error(ERR_WARN, "unsupported version of tape file '%s'", filename); fclose(file); + return; } @@ -8854,7 +9189,8 @@ void LoadScore(int nr) return; /* check file identifier */ - fgets(cookie, MAX_LINE_LEN, file); + if (fgets(cookie, MAX_LINE_LEN, file) == NULL) + cookie[0] = '\0'; if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n') cookie[strlen(cookie) - 1] = '\0'; @@ -8867,10 +9203,12 @@ void LoadScore(int nr) for (i = 0; i < MAX_SCORE_ENTRIES; i++) { - fscanf(file, "%d", &highscore[i].Score); - fgets(line, MAX_LINE_LEN, file); + if (fscanf(file, "%d", &highscore[i].Score) == EOF) + Error(ERR_WARN, "fscanf() failed; %s", strerror(errno)); + if (fgets(line, MAX_LINE_LEN, file) == NULL) + line[0] = '\0'; - if (line[strlen(line) - 1] == '\n') + if (strlen(line) > 0 && line[strlen(line) - 1] == '\n') line[strlen(line) - 1] = '\0'; for (line_ptr = line; *line_ptr; line_ptr++) @@ -8945,14 +9283,18 @@ void SaveScore(int nr) #define SETUP_TOKEN_PREFER_AGA_GRAPHICS 23 #define SETUP_TOKEN_GAME_FRAME_DELAY 24 #define SETUP_TOKEN_SP_SHOW_BORDER_ELEMENTS 25 -#define SETUP_TOKEN_GRAPHICS_SET 26 -#define SETUP_TOKEN_SOUNDS_SET 27 -#define SETUP_TOKEN_MUSIC_SET 28 -#define SETUP_TOKEN_OVERRIDE_LEVEL_GRAPHICS 29 -#define SETUP_TOKEN_OVERRIDE_LEVEL_SOUNDS 30 -#define SETUP_TOKEN_OVERRIDE_LEVEL_MUSIC 31 - -#define NUM_GLOBAL_SETUP_TOKENS 32 +#define SETUP_TOKEN_SMALL_GAME_GRAPHICS 26 +#define SETUP_TOKEN_GRAPHICS_SET 27 +#define SETUP_TOKEN_SOUNDS_SET 28 +#define SETUP_TOKEN_MUSIC_SET 29 +#define SETUP_TOKEN_OVERRIDE_LEVEL_GRAPHICS 30 +#define SETUP_TOKEN_OVERRIDE_LEVEL_SOUNDS 31 +#define SETUP_TOKEN_OVERRIDE_LEVEL_MUSIC 32 +#define SETUP_TOKEN_VOLUME_SIMPLE 33 +#define SETUP_TOKEN_VOLUME_LOOPS 34 +#define SETUP_TOKEN_VOLUME_MUSIC 35 + +#define NUM_GLOBAL_SETUP_TOKENS 36 /* editor setup */ #define SETUP_TOKEN_EDITOR_EL_BOULDERDASH 0 @@ -9003,8 +9345,21 @@ void SaveScore(int nr) #define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_3 5 #define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_4 6 #define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_ALL 7 - -#define NUM_SHORTCUT_SETUP_TOKENS 8 +#define SETUP_TOKEN_SHORTCUT_TAPE_EJECT 8 +#define SETUP_TOKEN_SHORTCUT_TAPE_EXTRA 9 +#define SETUP_TOKEN_SHORTCUT_TAPE_STOP 10 +#define SETUP_TOKEN_SHORTCUT_TAPE_PAUSE 11 +#define SETUP_TOKEN_SHORTCUT_TAPE_RECORD 12 +#define SETUP_TOKEN_SHORTCUT_TAPE_PLAY 13 +#define SETUP_TOKEN_SHORTCUT_SOUND_SIMPLE 14 +#define SETUP_TOKEN_SHORTCUT_SOUND_LOOPS 15 +#define SETUP_TOKEN_SHORTCUT_SOUND_MUSIC 16 +#define SETUP_TOKEN_SHORTCUT_SNAP_LEFT 17 +#define SETUP_TOKEN_SHORTCUT_SNAP_RIGHT 18 +#define SETUP_TOKEN_SHORTCUT_SNAP_UP 19 +#define SETUP_TOKEN_SHORTCUT_SNAP_DOWN 20 + +#define NUM_SHORTCUT_SETUP_TOKENS 21 /* player setup */ #define SETUP_TOKEN_PLAYER_USE_JOYSTICK 0 @@ -9075,12 +9430,16 @@ static struct TokenInfo global_setup_tokens[] = { TYPE_SWITCH, &si.prefer_aga_graphics, "prefer_aga_graphics" }, { TYPE_INTEGER,&si.game_frame_delay, "game_frame_delay" }, { TYPE_SWITCH, &si.sp_show_border_elements, "sp_show_border_elements" }, + { TYPE_SWITCH, &si.small_game_graphics, "small_game_graphics" }, { TYPE_STRING, &si.graphics_set, "graphics_set" }, { TYPE_STRING, &si.sounds_set, "sounds_set" }, { TYPE_STRING, &si.music_set, "music_set" }, { TYPE_SWITCH3,&si.override_level_graphics, "override_level_graphics" }, { TYPE_SWITCH3,&si.override_level_sounds, "override_level_sounds" }, { TYPE_SWITCH3,&si.override_level_music, "override_level_music" }, + { TYPE_INTEGER,&si.volume_simple, "volume_simple" }, + { TYPE_INTEGER,&si.volume_loops, "volume_loops" }, + { TYPE_INTEGER,&si.volume_music, "volume_music" }, }; static boolean not_used = FALSE; @@ -9149,6 +9508,19 @@ static struct TokenInfo shortcut_setup_tokens[] = { TYPE_KEY_X11, &ssi.focus_player[2], "shortcut.focus_player_3" }, { TYPE_KEY_X11, &ssi.focus_player[3], "shortcut.focus_player_4" }, { TYPE_KEY_X11, &ssi.focus_player_all,"shortcut.focus_player_all" }, + { TYPE_KEY_X11, &ssi.tape_eject, "shortcut.tape_eject" }, + { TYPE_KEY_X11, &ssi.tape_extra, "shortcut.tape_extra" }, + { TYPE_KEY_X11, &ssi.tape_stop, "shortcut.tape_stop" }, + { TYPE_KEY_X11, &ssi.tape_pause, "shortcut.tape_pause" }, + { TYPE_KEY_X11, &ssi.tape_record, "shortcut.tape_record" }, + { TYPE_KEY_X11, &ssi.tape_play, "shortcut.tape_play" }, + { TYPE_KEY_X11, &ssi.sound_simple, "shortcut.sound_simple" }, + { TYPE_KEY_X11, &ssi.sound_loops, "shortcut.sound_loops" }, + { TYPE_KEY_X11, &ssi.sound_music, "shortcut.sound_music" }, + { TYPE_KEY_X11, &ssi.snap_left, "shortcut.snap_left" }, + { TYPE_KEY_X11, &ssi.snap_right, "shortcut.snap_right" }, + { TYPE_KEY_X11, &ssi.snap_up, "shortcut.snap_up" }, + { TYPE_KEY_X11, &ssi.snap_down, "shortcut.snap_down" }, }; static struct TokenInfo player_setup_tokens[] = @@ -9229,6 +9601,7 @@ static void setSetupInfoToDefaults(struct SetupInfo *si) si->prefer_aga_graphics = TRUE; si->game_frame_delay = GAME_FRAME_DELAY; si->sp_show_border_elements = FALSE; + si->small_game_graphics = FALSE; si->graphics_set = getStringCopy(GFX_DEFAULT_SUBDIR); si->sounds_set = getStringCopy(SND_DEFAULT_SUBDIR); @@ -9237,6 +9610,10 @@ static void setSetupInfoToDefaults(struct SetupInfo *si) si->override_level_sounds = FALSE; si->override_level_music = FALSE; + si->volume_simple = 100; /* percent */ + si->volume_loops = 100; /* percent */ + si->volume_music = 100; /* percent */ + si->editor.el_boulderdash = TRUE; si->editor.el_emerald_mine = TRUE; si->editor.el_emerald_mine_club = TRUE; @@ -9265,6 +9642,22 @@ static void setSetupInfoToDefaults(struct SetupInfo *si) si->shortcut.focus_player[3] = DEFAULT_KEY_FOCUS_PLAYER_4; si->shortcut.focus_player_all = DEFAULT_KEY_FOCUS_PLAYER_ALL; + si->shortcut.tape_eject = DEFAULT_KEY_TAPE_EJECT; + si->shortcut.tape_extra = DEFAULT_KEY_TAPE_EXTRA; + si->shortcut.tape_stop = DEFAULT_KEY_TAPE_STOP; + si->shortcut.tape_pause = DEFAULT_KEY_TAPE_PAUSE; + si->shortcut.tape_record = DEFAULT_KEY_TAPE_RECORD; + si->shortcut.tape_play = DEFAULT_KEY_TAPE_PLAY; + + si->shortcut.sound_simple = DEFAULT_KEY_SOUND_SIMPLE; + si->shortcut.sound_loops = DEFAULT_KEY_SOUND_LOOPS; + si->shortcut.sound_music = DEFAULT_KEY_SOUND_MUSIC; + + si->shortcut.snap_left = DEFAULT_KEY_SNAP_LEFT; + si->shortcut.snap_right = DEFAULT_KEY_SNAP_RIGHT; + si->shortcut.snap_up = DEFAULT_KEY_SNAP_UP; + si->shortcut.snap_down = DEFAULT_KEY_SNAP_DOWN; + for (i = 0; i < MAX_PLAYERS; i++) { si->input[i].use_joystick = FALSE; @@ -9292,6 +9685,7 @@ static void setSetupInfoToDefaults(struct SetupInfo *si) si->options.verbose = FALSE; #if defined(CREATE_SPECIAL_EDITION_RND_JUE) + si->toons = FALSE; si->handicap = FALSE; si->fullscreen = TRUE; si->override_level_graphics = AUTO; @@ -9482,7 +9876,8 @@ void SaveSetup() { /* just to make things nicer :) */ if (i == SETUP_TOKEN_PLAYER_NAME + 1 || - i == SETUP_TOKEN_GRAPHICS_SET) + i == SETUP_TOKEN_GRAPHICS_SET || + i == SETUP_TOKEN_VOLUME_SIMPLE) fprintf(file, "\n"); fprintf(file, "%s\n", getSetupLine(global_setup_tokens, "", i)); @@ -9725,6 +10120,16 @@ static void InitMenuDesignSettings_SpecialPreProcessing() menu.enter_screen[i] = menu.enter_screen[GFX_SPECIAL_ARG_DEFAULT]; menu.leave_screen[i] = menu.leave_screen[GFX_SPECIAL_ARG_DEFAULT]; } + + /* special case: initialize "ARG_DEFAULT" values in static default config */ + /* (eg, init "viewport.door_1.MAIN.xyz" from "viewport.door_1.xyz") */ + for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++) + { + viewport.playfield[i] = viewport.playfield[GFX_SPECIAL_ARG_DEFAULT]; + viewport.door_1[i] = viewport.door_1[GFX_SPECIAL_ARG_DEFAULT]; + if (i != GFX_SPECIAL_ARG_EDITOR) /* editor value already initialized */ + viewport.door_2[i] = viewport.door_2[GFX_SPECIAL_ARG_DEFAULT]; + } } static void InitMenuDesignSettings_SpecialPostProcessing() @@ -9862,6 +10267,50 @@ static void LoadMenuDesignSettingsFromFilename(char *filename) value_6); } + /* special case: initialize with default values that may be overwritten */ + /* (eg, init "viewport.door_1.MAIN.xyz" from "viewport.door_1.xyz") */ + for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++) + { + char *token_1 = "viewport.playfield.x"; + char *token_2 = "viewport.playfield.y"; + char *token_3 = "viewport.playfield.width"; + char *token_4 = "viewport.playfield.height"; + char *token_5 = "viewport.playfield.border_size"; + char *token_6 = "viewport.door_1.x"; + char *token_7 = "viewport.door_1.y"; + char *token_8 = "viewport.door_2.x"; + char *token_9 = "viewport.door_2.y"; + char *value_1 = getHashEntry(setup_file_hash, token_1); + char *value_2 = getHashEntry(setup_file_hash, token_2); + char *value_3 = getHashEntry(setup_file_hash, token_3); + char *value_4 = getHashEntry(setup_file_hash, token_4); + char *value_5 = getHashEntry(setup_file_hash, token_5); + char *value_6 = getHashEntry(setup_file_hash, token_6); + char *value_7 = getHashEntry(setup_file_hash, token_7); + char *value_8 = getHashEntry(setup_file_hash, token_8); + char *value_9 = getHashEntry(setup_file_hash, token_9); + + if (value_1 != NULL) + viewport.playfield[i].x = get_token_parameter_value(token_1, value_1); + if (value_2 != NULL) + viewport.playfield[i].y = get_token_parameter_value(token_2, value_2); + if (value_3 != NULL) + viewport.playfield[i].width = get_token_parameter_value(token_3, value_3); + if (value_4 != NULL) + viewport.playfield[i].height = get_token_parameter_value(token_4,value_4); + if (value_5 != NULL) + viewport.playfield[i].border_size = get_token_parameter_value(token_5, + value_5); + if (value_6 != NULL) + viewport.door_1[i].x = get_token_parameter_value(token_6, value_6); + if (value_7 != NULL) + viewport.door_1[i].y = get_token_parameter_value(token_7, value_7); + if (value_8 != NULL) + viewport.door_2[i].x = get_token_parameter_value(token_8, value_8); + if (value_9 != NULL) + viewport.door_2[i].y = get_token_parameter_value(token_9, value_9); + } + /* special case: initialize with default values that may be overwritten */ /* (e.g., init "titlemessage_1.fade_mode" from "[titlemessage].fade_mode") */ for (i = 0; titlemessage_arrays[i].array != NULL; i++) @@ -10142,6 +10591,160 @@ static boolean sound_info_listed(struct MusicFileInfo *list, char *basename) return music_info_listed_ext(list, basename, TRUE); } +#if 1 + +void LoadMusicInfo() +{ + char *music_directory = getCustomMusicDirectory(); + int num_music = getMusicListSize(); + int num_music_noconf = 0; + int num_sounds = getSoundListSize(); + Directory *dir; + DirectoryEntry *dir_entry; + struct FileInfo *music, *sound; + struct MusicFileInfo *next, **new; + int i; + + while (music_file_info != NULL) + { + next = music_file_info->next; + + checked_free(music_file_info->basename); + + checked_free(music_file_info->title_header); + checked_free(music_file_info->artist_header); + checked_free(music_file_info->album_header); + checked_free(music_file_info->year_header); + + checked_free(music_file_info->title); + checked_free(music_file_info->artist); + checked_free(music_file_info->album); + checked_free(music_file_info->year); + + free(music_file_info); + + music_file_info = next; + } + + new = &music_file_info; + + for (i = 0; i < num_music; i++) + { + music = getMusicListEntry(i); + + if (music->filename == NULL) + continue; + + if (strEqual(music->filename, UNDEFINED_FILENAME)) + continue; + + /* a configured file may be not recognized as music */ + if (!FileIsMusic(music->filename)) + continue; + +#if 0 + printf("::: -> '%s' (configured)\n", music->filename); +#endif + + if (!music_info_listed(music_file_info, music->filename)) + { + *new = get_music_file_info(music->filename, i); +#if 0 + if (*new != NULL) + printf(":1: adding '%s' ['%s'] ...\n", (*new)->title, music->filename); +#endif + if (*new != NULL) + new = &(*new)->next; + } + } + + if ((dir = openDirectory(music_directory)) == NULL) + { + Error(ERR_WARN, "cannot read music directory '%s'", music_directory); + return; + } + + while ((dir_entry = readDirectory(dir)) != NULL) /* loop all entries */ + { + char *basename = dir_entry->basename; + boolean music_already_used = FALSE; + int i; + + /* skip all music files that are configured in music config file */ + for (i = 0; i < num_music; i++) + { + music = getMusicListEntry(i); + + if (music->filename == NULL) + continue; + + if (strEqual(basename, music->filename)) + { + music_already_used = TRUE; + break; + } + } + + if (music_already_used) + continue; + + if (!FileIsMusic(basename)) + continue; + +#if 0 + printf("::: -> '%s' (found in directory)\n", basename); +#endif + + if (!music_info_listed(music_file_info, basename)) + { + *new = get_music_file_info(basename, MAP_NOCONF_MUSIC(num_music_noconf)); +#if 0 + if (*new != NULL) + printf(":2: adding '%s' ['%s'] ...\n", (*new)->title, basename); +#endif + if (*new != NULL) + new = &(*new)->next; + } + + num_music_noconf++; + } + + closeDirectory(dir); + + for (i = 0; i < num_sounds; i++) + { + sound = getSoundListEntry(i); + + if (sound->filename == NULL) + continue; + + if (strEqual(sound->filename, UNDEFINED_FILENAME)) + continue; + + /* a configured file may be not recognized as sound */ + if (!FileIsSound(sound->filename)) + continue; + +#if 0 + printf("::: -> '%s' (configured)\n", sound->filename); +#endif + + if (!sound_info_listed(music_file_info, sound->filename)) + { + *new = get_sound_file_info(sound->filename, i); + if (*new != NULL) + new = &(*new)->next; + } + } + +#if 0 + for (next = music_file_info; next != NULL; next = next->next) + printf("::: title == '%s'\n", next->title); +#endif +} + +#else + void LoadMusicInfo() { char *music_directory = getCustomMusicDirectory(); @@ -10198,6 +10801,10 @@ void LoadMusicInfo() if (!music_info_listed(music_file_info, music->filename)) { *new = get_music_file_info(music->filename, i); +#if 0 + if (*new != NULL) + printf(":1: adding '%s' ['%s'] ...\n", (*new)->title, music->filename); +#endif if (*new != NULL) new = &(*new)->next; } @@ -10243,6 +10850,10 @@ void LoadMusicInfo() if (!music_info_listed(music_file_info, basename)) { *new = get_music_file_info(basename, MAP_NOCONF_MUSIC(num_music_noconf)); +#if 0 + if (*new != NULL) + printf(":2: adding '%s' ['%s'] ...\n", (*new)->title, basename); +#endif if (*new != NULL) new = &(*new)->next; } @@ -10284,6 +10895,8 @@ void LoadMusicInfo() #endif } +#endif + void add_helpanim_entry(int element, int action, int direction, int delay, int *num_list_entries) { @@ -10712,8 +11325,9 @@ void CreateLevelSketchImages() filename1 = getPath2(global.create_images_dir, basename1); filename2 = getPath2(global.create_images_dir, basename2); - getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y); - BlitBitmap(src_bitmap, bitmap1, src_x, src_y, TILEX, TILEY, 0, 0); + getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y); + BlitBitmap(src_bitmap, bitmap1, src_x, src_y, TILEX, TILEY, + 0, 0); if (SDL_SaveBMP(bitmap1->surface, filename1) != 0) Error(ERR_EXIT, "cannot save level sketch image file '%s'", filename1); @@ -10764,7 +11378,7 @@ void CreateCustomElementImages() TILEY * (NUM_CUSTOM_ELEMENTS + NUM_GROUP_ELEMENTS) / 16, DEFAULT_DEPTH); - getGraphicSource(dummy_graphic, 0, &src_bitmap, &src_x, &src_y); + getFixedGraphicSource(dummy_graphic, 0, &src_bitmap, &src_x, &src_y); for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) { @@ -10776,18 +11390,22 @@ void CreateCustomElementImages() BlitBitmap(src_bitmap, bitmap, 0, 0, TILEX, TILEY, TILEX * x, TILEY * y + yoffset_ce); - BlitBitmap(src_bitmap, bitmap, 0, TILEY, TILEX, TILEY, - TILEX * x + TILEX * 16, TILEY * y + yoffset_ce); + BlitBitmap(src_bitmap, bitmap, 0, TILEY, + TILEX, TILEY, + TILEX * x + TILEX * 16, + TILEY * y + yoffset_ce); for (j = 2; j >= 0; j--) { int c = ii % 10; - BlitBitmap(src_bitmap, bitmap, TILEX + c * 7, 0, 6, 10, + BlitBitmap(src_bitmap, bitmap, + TILEX + c * 7, 0, 6, 10, TILEX * x + 6 + j * 7, TILEY * y + 11 + yoffset_ce); - BlitBitmap(src_bitmap, bitmap, TILEX + c * 8, TILEY, 6, 10, + BlitBitmap(src_bitmap, bitmap, + TILEX + c * 8, TILEY, 6, 10, TILEX * 16 + TILEX * x + 6 + j * 8, TILEY * y + 10 + yoffset_ce); @@ -10805,8 +11423,10 @@ void CreateCustomElementImages() BlitBitmap(src_bitmap, bitmap, 0, 0, TILEX, TILEY, TILEX * x, TILEY * y + yoffset_ge); - BlitBitmap(src_bitmap, bitmap, 0, TILEY, TILEX, TILEY, - TILEX * x + TILEX * 16, TILEY * y + yoffset_ge); + BlitBitmap(src_bitmap, bitmap, 0, TILEY, + TILEX, TILEY, + TILEX * x + TILEX * 16, + TILEY * y + yoffset_ge); for (j = 1; j >= 0; j--) { @@ -10816,7 +11436,8 @@ void CreateCustomElementImages() TILEX * x + 6 + j * 10, TILEY * y + 11 + yoffset_ge); - BlitBitmap(src_bitmap, bitmap, TILEX + c * 8, TILEY + 12, 6, 10, + BlitBitmap(src_bitmap, bitmap, + TILEX + c * 8, TILEY + 12, 6, 10, TILEX * 16 + TILEX * x + 10 + j * 8, TILEY * y + 10 + yoffset_ge);