X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Ffiles.c;h=889136ff675bfb83d9e5b25c28aea93c08cbcfe4;hb=c42db18f39053cf2ec85943c37a20b8caa742d09;hp=d113c6ad0f9b9733b9f9d5303e9f1336c7bdc4e4;hpb=368684d4c5e2a59cbea8c5e35171f3fe008b844f;p=rocksndiamonds.git diff --git a/src/files.c b/src/files.c index d113c6ad..889136ff 100644 --- a/src/files.c +++ b/src/files.c @@ -60,7 +60,6 @@ #define TAPE_CHUNK_VERS_SIZE 8 // size of file version chunk #define TAPE_CHUNK_HEAD_SIZE 20 // size of tape file header -#define TAPE_CHUNK_HEAD_UNUSED 1 // unused tape header bytes #define TAPE_CHUNK_SCRN_SIZE 2 // size of screen size chunk #define SCORE_CHUNK_VERS_SIZE 8 // size of file version chunk @@ -115,7 +114,7 @@ CONF_CONTENT_NUM_BYTES : 1) #define CONF_ELEMENT_BYTE_POS(i) ((i) * CONF_ELEMENT_NUM_BYTES) -#define CONF_ELEMENTS_ELEMENT(b,i) ((b[CONF_ELEMENT_BYTE_POS(i)] << 8) | \ +#define CONF_ELEMENTS_ELEMENT(b, i) ((b[CONF_ELEMENT_BYTE_POS(i)] << 8) | \ (b[CONF_ELEMENT_BYTE_POS(i) + 1])) #define CONF_CONTENT_ELEMENT_POS(c,x,y) ((c) * CONF_CONTENT_NUM_ELEMENTS + \ @@ -905,11 +904,34 @@ static struct LevelFileConfigInfo chunk_config_ELEM[] = TYPE_INTEGER, CONF_VALUE_16_BIT(1), &li.mm_time_bomb, 75 }, + { EL_MM_GRAY_BALL, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(1), &li.mm_time_ball, 75 }, + { + EL_MM_GRAY_BALL, -1, + TYPE_INTEGER, CONF_VALUE_8_BIT(1), + &li.mm_ball_choice_mode, ANIM_RANDOM + }, + { + EL_MM_GRAY_BALL, -1, + TYPE_ELEMENT_LIST, CONF_VALUE_BYTES(1), + &li.mm_ball_content, EL_EMPTY, NULL, + &li.num_mm_ball_contents, 8, MAX_MM_BALL_CONTENTS + }, + { + EL_MM_GRAY_BALL, -1, + TYPE_BOOLEAN, CONF_VALUE_8_BIT(1), + &li.rotate_mm_ball_content, TRUE + }, + { + EL_MM_GRAY_BALL, -1, + TYPE_BOOLEAN, CONF_VALUE_8_BIT(2), + &li.explode_mm_ball, FALSE + }, + { EL_MM_STEEL_BLOCK, -1, TYPE_INTEGER, CONF_VALUE_16_BIT(1), @@ -1842,6 +1864,16 @@ static void setLevelInfoToDefaults_Elements(struct LevelInfo *level) int element = i; struct ElementInfo *ei = &element_info[element]; + if (element == EL_MM_GRAY_BALL) + { + struct LevelInfo_MM *level_mm = level->native_mm_level; + int j; + + for (j = 0; j < level->num_mm_ball_contents; j++) + level->mm_ball_content[j] = + map_element_MM_to_RND(level_mm->ball_content[j]); + } + // 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) @@ -2849,7 +2881,7 @@ static int LoadLevel_CUS3(File *file, int chunk_size, struct LevelInfo *level) // bits 0 - 31 of "has_event[]" event_bits = getFile32BitBE(file); for (j = 0; j < MIN(NUM_CHANGE_EVENTS, 32); j++) - if (event_bits & (1 << j)) + if (event_bits & (1u << j)) ei->change->has_event[j] = TRUE; ei->change->target_element = getMappedElement(getFile16BitBE(file)); @@ -2985,7 +3017,7 @@ static int LoadLevel_CUS4(File *file, int chunk_size, struct LevelInfo *level) // bits 0 - 31 of "has_event[]" ... event_bits = getFile32BitBE(file); for (j = 0; j < MIN(NUM_CHANGE_EVENTS, 32); j++) - if (event_bits & (1 << j)) + if (event_bits & (1u << j)) change->has_event[j] = TRUE; change->target_element = getMappedElement(getFile16BitBE(file)); @@ -3026,7 +3058,7 @@ static int LoadLevel_CUS4(File *file, int chunk_size, struct LevelInfo *level) // ... 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))) + if (event_bits & (1u << (j - 32))) change->has_event[j] = TRUE; } @@ -3355,6 +3387,10 @@ static int LoadLevel_CUSX(File *file, int chunk_size, struct LevelInfo *level) while (!checkEndOfFile(file)) { + // level file might contain invalid change page number + if (xx_current_change_page >= ei->num_change_pages) + break; + struct ElementChangeInfo *change = &ei->change_page[xx_current_change_page]; xx_change = *change; // copy change data into temporary buffer @@ -3384,6 +3420,9 @@ static int LoadLevel_GRPX(File *file, int chunk_size, struct LevelInfo *level) struct ElementInfo *ei = &element_info[element]; struct ElementGroupInfo *group = ei->group; + if (group == NULL) + return -1; + xx_ei = *ei; // copy element data into temporary buffer xx_group = *group; // copy group data into temporary buffer @@ -3584,6 +3623,14 @@ static void LoadLevelFromFileInfo_RND(struct LevelInfo *level, int chunk_size_expected = (chunk_info[i].loader)(file, chunk_size, level); + if (chunk_size_expected < 0) + { + Warn("error reading chunk '%s' in level file '%s'", + chunk_name, filename); + + break; + } + // the size of some chunks cannot be checked before reading other // chunks first (like "HEAD" and "BODY") that contain some header // information, so check them here @@ -3591,6 +3638,8 @@ static void LoadLevelFromFileInfo_RND(struct LevelInfo *level, { Warn("wrong size (%d) of chunk '%s' in level file '%s'", chunk_size, chunk_name, filename); + + break; } } } @@ -3664,6 +3713,7 @@ static void CopyNativeLevel_RND_to_EM(struct LevelInfo *level) cav->lenses_time = level->lenses_time; cav->magnify_time = level->magnify_time; + cav->wind_time = 9999; cav->wind_direction = map_direction_RND_to_EM(level->wind_direction_initial); @@ -4113,7 +4163,7 @@ static void CopyNativeTape_SP_to_RND(struct LevelInfo *level) static void CopyNativeLevel_RND_to_MM(struct LevelInfo *level) { struct LevelInfo_MM *level_mm = level->native_mm_level; - int x, y; + int i, x, y; level_mm->fieldx = MIN(level->fieldx, MM_MAX_PLAYFIELD_WIDTH); level_mm->fieldy = MIN(level->fieldy, MM_MAX_PLAYFIELD_HEIGHT); @@ -4122,9 +4172,13 @@ static void CopyNativeLevel_RND_to_MM(struct LevelInfo *level) level_mm->kettles_needed = level->gems_needed; level_mm->auto_count_kettles = level->auto_count_gems; - level_mm->laser_red = level->mm_laser_red; - level_mm->laser_green = level->mm_laser_green; - level_mm->laser_blue = level->mm_laser_blue; + level_mm->mm_laser_red = level->mm_laser_red; + level_mm->mm_laser_green = level->mm_laser_green; + level_mm->mm_laser_blue = level->mm_laser_blue; + + level_mm->df_laser_red = level->df_laser_red; + level_mm->df_laser_green = level->df_laser_green; + level_mm->df_laser_blue = level->df_laser_blue; strcpy(level_mm->name, level->name); strcpy(level_mm->author, level->author); @@ -4141,6 +4195,15 @@ static void CopyNativeLevel_RND_to_MM(struct LevelInfo *level) level_mm->time_ball = level->mm_time_ball; level_mm->time_block = level->mm_time_block; + level_mm->num_ball_contents = level->num_mm_ball_contents; + level_mm->ball_choice_mode = level->mm_ball_choice_mode; + level_mm->rotate_ball_content = level->rotate_mm_ball_content; + level_mm->explode_ball = level->explode_mm_ball; + + for (i = 0; i < level->num_mm_ball_contents; i++) + level_mm->ball_content[i] = + map_element_RND_to_MM(level->mm_ball_content[i]); + for (x = 0; x < level->fieldx; x++) for (y = 0; y < level->fieldy; y++) Ur[x][y] = @@ -4150,7 +4213,7 @@ static void CopyNativeLevel_RND_to_MM(struct LevelInfo *level) static void CopyNativeLevel_MM_to_RND(struct LevelInfo *level) { struct LevelInfo_MM *level_mm = level->native_mm_level; - int x, y; + int i, x, y; level->fieldx = MIN(level_mm->fieldx, MAX_LEV_FIELDX); level->fieldy = MIN(level_mm->fieldy, MAX_LEV_FIELDY); @@ -4159,9 +4222,13 @@ static void CopyNativeLevel_MM_to_RND(struct LevelInfo *level) level->gems_needed = level_mm->kettles_needed; level->auto_count_gems = level_mm->auto_count_kettles; - level->mm_laser_red = level_mm->laser_red; - level->mm_laser_green = level_mm->laser_green; - level->mm_laser_blue = level_mm->laser_blue; + level->mm_laser_red = level_mm->mm_laser_red; + level->mm_laser_green = level_mm->mm_laser_green; + level->mm_laser_blue = level_mm->mm_laser_blue; + + level->df_laser_red = level_mm->df_laser_red; + level->df_laser_green = level_mm->df_laser_green; + level->df_laser_blue = level_mm->df_laser_blue; strcpy(level->name, level_mm->name); @@ -4181,6 +4248,15 @@ static void CopyNativeLevel_MM_to_RND(struct LevelInfo *level) level->mm_time_ball = level_mm->time_ball; level->mm_time_block = level_mm->time_block; + level->num_mm_ball_contents = level_mm->num_ball_contents; + level->mm_ball_choice_mode = level_mm->ball_choice_mode; + level->rotate_mm_ball_content = level_mm->rotate_ball_content; + level->explode_mm_ball = level_mm->explode_ball; + + for (i = 0; i < level->num_mm_ball_contents; i++) + level->mm_ball_content[i] = + map_element_MM_to_RND(level_mm->ball_content[i]); + for (x = 0; x < level->fieldx; x++) for (y = 0; y < level->fieldy; y++) level->field[x][y] = map_element_MM_to_RND(level_mm->field[x][y]); @@ -5662,8 +5738,7 @@ static int getMappedElement_DC(int element) return getMappedElement(element); } -static void LoadLevelFromFileStream_DC(File *file, struct LevelInfo *level, - int nr) +static void LoadLevelFromFileStream_DC(File *file, struct LevelInfo *level) { byte header[DC_LEVEL_HEADER_SIZE]; int envelope_size; @@ -5912,7 +5987,7 @@ static void LoadLevelFromFileInfo_DC(struct LevelInfo *level, } } - LoadLevelFromFileStream_DC(file, level, level_file_info->nr); + LoadLevelFromFileStream_DC(file, level); closeFile(file); } @@ -6566,6 +6641,13 @@ static void LoadLevel_InitSettings(struct LevelInfo *level) { // adjust level settings for (non-native) Sokoban-style levels LoadLevel_InitSettings_SB(level); + + // rename levels with title "nameless level" or if renaming is forced + if (leveldir_current->empty_level_name != NULL && + (strEqual(level->name, NAMELESS_LEVEL_NAME) || + leveldir_current->force_level_name)) + snprintf(level->name, MAX_LEVEL_NAME_LEN + 1, + leveldir_current->empty_level_name, level_nr); } static void LoadLevel_InitStandardElements(struct LevelInfo *level) @@ -7304,7 +7386,7 @@ static void SaveLevel_CUS4(FILE *file, struct LevelInfo *level, int element) event_bits = 0; for (j = 0; j < MIN(NUM_CHANGE_EVENTS, 32); j++) if (change->has_event[j]) - event_bits |= (1 << j); + event_bits |= (1u << j); putFile32BitBE(file, event_bits); putFile16BitBE(file, change->target_element); @@ -7344,7 +7426,7 @@ static void SaveLevel_CUS4(FILE *file, struct LevelInfo *level, int element) event_bits = 0; for (j = 32; j < NUM_CHANGE_EVENTS; j++) if (change->has_event[j]) - event_bits |= (1 << (j - 32)); + event_bits |= (1u << (j - 32)); putFile8Bit(file, event_bits); } } @@ -7791,6 +7873,28 @@ void DumpLevel(struct LevelInfo *level) Print("use step counter: %s\n", (level->use_step_counter ? "yes" : "no")); Print("rate time over score: %s\n", (level->rate_time_over_score ? "yes" : "no")); + if (options.debug) + { + int i, j; + + for (i = 0; i < NUM_ENVELOPES; i++) + { + char *text = level->envelope[i].text; + int text_len = strlen(text); + boolean has_text = FALSE; + + for (j = 0; j < text_len; j++) + if (text[j] != ' ' && text[j] != '\n') + has_text = TRUE; + + if (has_text) + { + Print("\n"); + Print("Envelope %d:\n'%s'\n", i + 1, text); + } + } + } + PrintLine("-", 79); } @@ -7841,6 +7945,7 @@ static void setTapeInfoToDefaults(void) tape.level_nr = level_nr; tape.counter = 0; tape.changed = FALSE; + tape.solved = FALSE; tape.recording = FALSE; tape.playing = FALSE; @@ -7927,8 +8032,7 @@ static int LoadTape_HEAD(File *file, int chunk_size, struct TapeInfo *tape) setTapeActionFlags(tape, getFile8Bit(file)); tape->property_bits = getFile8Bit(file); - - ReadUnusedBytesFromFile(file, TAPE_CHUNK_HEAD_UNUSED); + tape->solved = getFile8Bit(file); engine_version = getFileVersion(file); if (engine_version > 0) @@ -8333,6 +8437,13 @@ void LoadScoreTape(char *score_tape_basename, int nr) LoadTapeFromFilename(filename); } +void LoadScoreCacheTape(char *score_tape_basename, int nr) +{ + char *filename = getScoreCacheTapeFilename(score_tape_basename, nr); + + LoadTapeFromFilename(filename); +} + static boolean checkSaveTape_SCRN(struct TapeInfo *tape) { // chunk required for team mode tapes with non-default screen size @@ -8366,9 +8477,7 @@ static void SaveTape_HEAD(FILE *file, struct TapeInfo *tape) putFile8Bit(file, getTapeActionValue(tape)); putFile8Bit(file, tape->property_bits); - - // unused bytes not at the end here for 4-byte alignment of engine_version - WriteUnusedBytesToFile(file, TAPE_CHUNK_HEAD_UNUSED); + putFile8Bit(file, tape->solved); putFileVersion(file, tape->engine_version); } @@ -8550,6 +8659,10 @@ void DumpTape(struct TapeInfo *tape) tape->engine_version); Print("Level series identifier: '%s'\n", tape->level_identifier); + Print("Solution tape: %s\n", + tape->solved ? "yes" : + tape->game_version < VERSION_IDENT(4,3,2,3) ? "unknown" : "no"); + Print("Special tape properties: "); if (tape->property_bits == TAPE_PROPERTY_NONE) Print("[none]"); @@ -8675,6 +8788,13 @@ static void setScoreInfoToDefaultsExt(struct ScoreInfo *scores) scores->uploaded = FALSE; scores->tape_downloaded = FALSE; scores->force_last_added = FALSE; + + // The following values are intentionally not reset here: + // - last_level_nr + // - last_entry_nr + // - next_level_nr + // - continue_playing + // - continue_on_return } static void setScoreInfoToDefaults(void) @@ -9307,6 +9427,7 @@ void SaveServerScoreFromFile(int nr, boolean tape_saved, void LoadLocalAndServerScore(int nr, boolean download_score) { int last_added_local = scores.last_added_local; + boolean force_last_added = scores.force_last_added; // needed if only showing server scores setScoreInfoToDefaults(); @@ -9326,6 +9447,9 @@ void LoadLocalAndServerScore(int nr, boolean download_score) // merge local scores with scores from server MergeServerScore(); } + + if (force_last_added) + scores.force_last_added = force_last_added; } @@ -9394,6 +9518,10 @@ static struct TokenInfo global_setup_tokens[] = TYPE_SWITCH, &setup.autorecord, "automatic_tape_recording" }, + { + TYPE_SWITCH, + &setup.autorecord_after_replay, "autorecord_after_replay" + }, { TYPE_SWITCH, &setup.auto_pause_on_start, "auto_pause_on_start" @@ -9614,6 +9742,10 @@ static struct TokenInfo global_setup_tokens[] = TYPE_INTEGER, &setup.touch.grid_ysize[1], "touch.virtual_buttons.1.ysize" }, + { + TYPE_SWITCH, + &setup.touch.overlay_buttons, "touch.overlay_buttons" + }, }; static struct TokenInfo auto_setup_tokens[] = @@ -10043,10 +10175,18 @@ static struct TokenInfo internal_setup_tokens[] = TYPE_BOOLEAN, &setup.internal.create_user_levelset, "create_user_levelset" }, + { + TYPE_BOOLEAN, + &setup.internal.info_screens_from_main, "info_screens_from_main" + }, { TYPE_BOOLEAN, &setup.internal.menu_game, "menu_game" }, + { + TYPE_BOOLEAN, + &setup.internal.menu_engines, "menu_engines" + }, { TYPE_BOOLEAN, &setup.internal.menu_editor, "menu_editor" @@ -10083,6 +10223,58 @@ static struct TokenInfo internal_setup_tokens[] = TYPE_BOOLEAN, &setup.internal.menu_save_and_exit, "menu_save_and_exit" }, + { + TYPE_BOOLEAN, + &setup.internal.menu_shortcuts_various, "menu_shortcuts_various" + }, + { + TYPE_BOOLEAN, + &setup.internal.menu_shortcuts_focus, "menu_shortcuts_focus" + }, + { + TYPE_BOOLEAN, + &setup.internal.menu_shortcuts_tape, "menu_shortcuts_tape" + }, + { + TYPE_BOOLEAN, + &setup.internal.menu_shortcuts_sound, "menu_shortcuts_sound" + }, + { + TYPE_BOOLEAN, + &setup.internal.menu_shortcuts_snap, "menu_shortcuts_snap" + }, + { + TYPE_BOOLEAN, + &setup.internal.info_title, "info_title" + }, + { + TYPE_BOOLEAN, + &setup.internal.info_elements, "info_elements" + }, + { + TYPE_BOOLEAN, + &setup.internal.info_music, "info_music" + }, + { + TYPE_BOOLEAN, + &setup.internal.info_credits, "info_credits" + }, + { + TYPE_BOOLEAN, + &setup.internal.info_program, "info_program" + }, + { + TYPE_BOOLEAN, + &setup.internal.info_version, "info_version" + }, + { + TYPE_BOOLEAN, + &setup.internal.info_levelset, "info_levelset" + }, + { + TYPE_BOOLEAN, + &setup.internal.info_exit, "info_exit" + }, }; static struct TokenInfo debug_setup_tokens[] = @@ -10194,6 +10386,14 @@ static struct TokenInfo options_setup_tokens[] = TYPE_BOOLEAN, &setup.options.verbose, "options.verbose" }, + { + TYPE_BOOLEAN, + &setup.options.debug, "options.debug" + }, + { + TYPE_STRING, + &setup.options.debug_mode, "options.debug_mode" + }, }; static void setSetupInfoToDefaults(struct SetupInfo *si) @@ -10216,6 +10416,7 @@ static void setSetupInfoToDefaults(struct SetupInfo *si) si->engine_snapshot_memory = SNAPSHOT_MEMORY_DEFAULT; si->fade_screens = TRUE; si->autorecord = TRUE; + si->autorecord_after_replay = TRUE; si->auto_pause_on_start = FALSE; si->show_titlescreen = TRUE; si->quick_doors = FALSE; @@ -10322,6 +10523,8 @@ static void setSetupInfoToDefaults(struct SetupInfo *si) si->touch.grid_initialized = video.initialized; + si->touch.overlay_buttons = FALSE; + si->editor.el_boulderdash = TRUE; si->editor.el_emerald_mine = TRUE; si->editor.el_emerald_mine_club = TRUE; @@ -10426,6 +10629,7 @@ static void setSetupInfoToDefaults(struct SetupInfo *si) si->internal.choose_from_top_leveldir = FALSE; si->internal.show_scaling_in_title = TRUE; si->internal.create_user_levelset = TRUE; + si->internal.info_screens_from_main = FALSE; si->internal.default_window_width = WIN_XSIZE_DEFAULT; si->internal.default_window_height = WIN_YSIZE_DEFAULT; @@ -10461,9 +10665,12 @@ static void setSetupInfoToDefaults(struct SetupInfo *si) si->debug.xsn_percent = 0; si->options.verbose = FALSE; + si->options.debug = FALSE; + si->options.debug_mode = getStringCopy(ARG_UNDEFINED_STRING); #if defined(PLATFORM_ANDROID) si->fullscreen = TRUE; + si->touch.overlay_buttons = TRUE; #endif setHideSetupEntry(&setup.debug.xsn_mode); @@ -10787,6 +10994,12 @@ void LoadSetup_Default(void) // try to load setup values from default setup file filename = getDefaultSetupFilename(); + if (fileExists(filename)) + LoadSetupFromFilename(filename); + + // try to load setup values from platform setup file + filename = getPlatformSetupFilename(); + if (fileExists(filename)) LoadSetupFromFilename(filename); @@ -11897,7 +12110,7 @@ static void InitMenuDesignSettings_SpecialPostProcessing(void) vp_playfield->width = MIN(vp_playfield->width, vp_playfield->max_width); if (vp_playfield->max_height != -1) - vp_playfield->height = MIN(vp_playfield->height,vp_playfield->max_height); + vp_playfield->height = MIN(vp_playfield->height, vp_playfield->max_height); // adjust playfield position according to specified alignment @@ -12266,7 +12479,9 @@ static void LoadMenuDesignSettingsFromFilename(char *filename) { { "menu.draw_xoffset.INFO", &menu.draw_xoffset_info[i] }, { "menu.draw_yoffset.INFO", &menu.draw_yoffset_info[i] }, - { "menu.list_size.INFO", &menu.list_size_info[i] } + { "menu.list_size.INFO", &menu.list_size_info[i] }, + { "menu.list_entry_size.INFO", &menu.list_entry_size_info[i] }, + { "menu.tile_size.INFO", &menu.tile_size_info[i] } }; for (j = 0; j < ARRAY_SIZE(menu_config); j++) @@ -12306,6 +12521,7 @@ static void LoadMenuDesignSettingsFromFilename(char *filename) struct TokenIntPtrInfo menu_config[] = { { "menu.left_spacing.INFO", &menu.left_spacing_info[i] }, + { "menu.middle_spacing.INFO", &menu.middle_spacing_info[i] }, { "menu.right_spacing.INFO", &menu.right_spacing_info[i] }, { "menu.top_spacing.INFO", &menu.top_spacing_info[i] }, { "menu.bottom_spacing.INFO", &menu.bottom_spacing_info[i] }, @@ -12721,16 +12937,29 @@ static boolean sound_info_listed(struct MusicFileInfo *list, char *basename) return music_info_listed_ext(list, basename, TRUE); } +static boolean checkLevelSetHasMusic_NoConf(void) +{ + int i; + + for (i = leveldir_current->first_level; + i <= leveldir_current->last_level; i++) + if (levelset.music[level_nr] == MUS_UNDEFINED) + return TRUE; + + return FALSE; +} + void LoadMusicInfo(void) { - char *music_directory = getCustomMusicDirectory(); + char *music_directory = getCustomMusicDirectory_NoConf(); int num_music = getMusicListSize(); int num_music_noconf = 0; int num_sounds = getSoundListSize(); - Directory *dir; + Directory *dir = NULL; DirectoryEntry *dir_entry; struct FileInfo *music, *sound; struct MusicFileInfo *next, **new; + boolean read_music_from_directory = TRUE; int i; while (music_file_info != NULL) @@ -12779,14 +13008,26 @@ void LoadMusicInfo(void) } } - if ((dir = openDirectory(music_directory)) == NULL) + // if all levels have game music configured, do not read music from directory + if (!checkLevelSetHasMusic_NoConf()) + { + read_music_from_directory = FALSE; + } + else if (music_directory == NULL) + { + Warn("cannot find music directory with unconfigured music"); + + read_music_from_directory = FALSE; + } + else if ((dir = openDirectory(music_directory)) == NULL) { Warn("cannot read music directory '%s'", music_directory); - return; + read_music_from_directory = FALSE; } - while ((dir_entry = readDirectory(dir)) != NULL) // loop all entries + while (read_music_from_directory && + (dir_entry = readDirectory(dir)) != NULL) // loop all entries { char *basename = dir_entry->basename; boolean music_already_used = FALSE; @@ -12824,7 +13065,8 @@ void LoadMusicInfo(void) num_music_noconf++; } - closeDirectory(dir); + if (dir != NULL) + closeDirectory(dir); for (i = 0; i < num_sounds; i++) { @@ -13361,8 +13603,25 @@ void CreateCollectElementImages(void) int dst_width = anim_width * 2; int dst_height = anim_height * num_collect_images / 2; Bitmap *dst_bitmap = CreateBitmap(dst_width, dst_height, DEFAULT_DEPTH); - char *basename = "RocksCollect.bmp"; - char *filename = getPath2(global.create_collect_images_dir, basename); + char *basename_bmp = "RocksCollect.bmp"; + char *basename_png = "RocksCollect.png"; + char *filename_bmp = getPath2(global.create_collect_images_dir, basename_bmp); + char *filename_png = getPath2(global.create_collect_images_dir, basename_png); + int len_filename_bmp = strlen(filename_bmp); + int len_filename_png = strlen(filename_png); + int max_command_len = MAX_FILENAME_LEN + len_filename_bmp + len_filename_png; + char cmd_convert[max_command_len]; + + snprintf(cmd_convert, max_command_len, "convert \"%s\" \"%s\"", + filename_bmp, + filename_png); + + // force using RGBA surface for destination bitmap + SDL_SetColorKey(dst_bitmap->surface, SET_TRANSPARENT_PIXEL, + SDL_MapRGB(dst_bitmap->surface->format, 0x00, 0x00, 0x00)); + + dst_bitmap->surface = + SDL_ConvertSurfaceFormat(dst_bitmap->surface, SDL_PIXELFORMAT_ARGB8888, 0); for (i = 0; i < MAX_NUM_ELEMENTS; i++) { @@ -13384,6 +13643,13 @@ void CreateCollectElementImages(void) BlitBitmap(src_bitmap, tmp_bitmap, src_x, src_y, tile_size, tile_size, 0, 0); + // force using RGBA surface for temporary bitmap (using transparent black) + SDL_SetColorKey(tmp_bitmap->surface, SET_TRANSPARENT_PIXEL, + SDL_MapRGB(tmp_bitmap->surface->format, 0x00, 0x00, 0x00)); + + tmp_bitmap->surface = + SDL_ConvertSurfaceFormat(tmp_bitmap->surface, SDL_PIXELFORMAT_ARGB8888, 0); + tmp_bitmap->surface_masked = tmp_bitmap->surface; for (j = 0; j < anim_frames; j++) @@ -13404,9 +13670,9 @@ void CreateCollectElementImages(void) frame_bitmap = half_bitmap; } - BlitBitmap(frame_bitmap, dst_bitmap, 0, 0, - frame_size_final, frame_size_final, - dst_x + j * tile_size + offset, dst_y + offset); + BlitBitmapMasked(frame_bitmap, dst_bitmap, 0, 0, + frame_size_final, frame_size_final, + dst_x + j * tile_size + offset, dst_y + offset); FreeBitmap(frame_bitmap); } @@ -13418,11 +13684,18 @@ void CreateCollectElementImages(void) pos_collect_images++; } - if (SDL_SaveBMP(dst_bitmap->surface, filename) != 0) - Fail("cannot save element collecting image file '%s'", filename); + if (SDL_SaveBMP(dst_bitmap->surface, filename_bmp) != 0) + Fail("cannot save element collecting image file '%s'", filename_bmp); FreeBitmap(dst_bitmap); + Info("Converting image file from BMP to PNG ..."); + + if (system(cmd_convert) != 0) + Fail("converting image file failed"); + + unlink(filename_bmp); + Info("Done."); CloseAllAndExit(0);