#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
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 + \
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(3),
+ &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),
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)
// 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));
// 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));
// ... 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;
}
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
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
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
{
Warn("wrong size (%d) of chunk '%s' in level file '%s'",
chunk_size, chunk_name, filename);
+
+ break;
}
}
}
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);
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);
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);
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] =
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);
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);
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]);
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;
}
}
- LoadLevelFromFileStream_DC(file, level, level_file_info->nr);
+ LoadLevelFromFileStream_DC(file, level);
closeFile(file);
}
{
// 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)
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);
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);
}
}
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);
}
tape.level_nr = level_nr;
tape.counter = 0;
tape.changed = FALSE;
+ tape.solved = FALSE;
tape.recording = FALSE;
tape.playing = FALSE;
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)
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
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);
}
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]");
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)
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();
// merge local scores with scores from server
MergeServerScore();
}
+
+ if (force_last_added)
+ scores.force_last_added = force_last_added;
}
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"
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[] =
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"
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.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)
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;
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;
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;
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);
// 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);
return string_has_parameter(substring, s_contained);
}
+static int get_anim_parameter_value_ce(char *s)
+{
+ char *s_ptr = s;
+ char *pattern_1 = "ce_change:custom_";
+ char *pattern_2 = ".page_";
+ int pattern_1_len = strlen(pattern_1);
+ char *matching_char = strstr(s_ptr, pattern_1);
+ int result = ANIM_EVENT_NONE;
+
+ if (matching_char == NULL)
+ return ANIM_EVENT_NONE;
+
+ result = ANIM_EVENT_CE_CHANGE;
+
+ s_ptr = matching_char + pattern_1_len;
+
+ // check for custom element number ("custom_X", "custom_XX" or "custom_XXX")
+ if (*s_ptr >= '0' && *s_ptr <= '9')
+ {
+ int gic_ce_nr = (*s_ptr++ - '0');
+
+ if (*s_ptr >= '0' && *s_ptr <= '9')
+ {
+ gic_ce_nr = 10 * gic_ce_nr + (*s_ptr++ - '0');
+
+ if (*s_ptr >= '0' && *s_ptr <= '9')
+ gic_ce_nr = 10 * gic_ce_nr + (*s_ptr++ - '0');
+ }
+
+ if (gic_ce_nr < 1 || gic_ce_nr > NUM_CUSTOM_ELEMENTS)
+ return ANIM_EVENT_NONE;
+
+ // custom element stored as 0 to 255
+ gic_ce_nr--;
+
+ result |= gic_ce_nr << ANIM_EVENT_CE_BIT;
+ }
+ else
+ {
+ // invalid custom element number specified
+
+ return ANIM_EVENT_NONE;
+ }
+
+ // check for change page number ("page_X" or "page_XX") (optional)
+ if (strPrefix(s_ptr, pattern_2))
+ {
+ s_ptr += strlen(pattern_2);
+
+ if (*s_ptr >= '0' && *s_ptr <= '9')
+ {
+ int gic_page_nr = (*s_ptr++ - '0');
+
+ if (*s_ptr >= '0' && *s_ptr <= '9')
+ gic_page_nr = 10 * gic_page_nr + (*s_ptr++ - '0');
+
+ if (gic_page_nr < 1 || gic_page_nr > MAX_CHANGE_PAGES)
+ return ANIM_EVENT_NONE;
+
+ // change page stored as 1 to 32 (0 means "all change pages")
+
+ result |= gic_page_nr << ANIM_EVENT_PAGE_BIT;
+ }
+ else
+ {
+ // invalid animation part number specified
+
+ return ANIM_EVENT_NONE;
+ }
+ }
+
+ // discard result if next character is neither delimiter nor whitespace
+ if (!(*s_ptr == ',' || *s_ptr == '\0' ||
+ *s_ptr == ' ' || *s_ptr == '\t'))
+ return ANIM_EVENT_NONE;
+
+ return result;
+}
+
static int get_anim_parameter_value(char *s)
{
int event_value[] =
int result = ANIM_EVENT_NONE;
int i;
+ result = get_anim_parameter_value_ce(s);
+
+ if (result != ANIM_EVENT_NONE)
+ return result;
+
for (i = 0; i < ARRAY_SIZE(event_value); i++)
{
matching_char = strstr(s_ptr, pattern_1[i]);
// if animation event found, add it to global animation event list
if (event_value != ANIM_EVENT_NONE)
+ {
list_pos = AddGlobalAnimEventValue(list_pos, event_value);
+ // continue with next part of the string, starting with next comma
+ s = strchr(s + 1, ',');
+ }
+
while (s != NULL)
{
// add optional "click:anim_X" or "click:anim_X.part_X" parameter
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
}
}
+static void InitMenuDesignSettings_PreviewPlayers_Ext(SetupFileHash *hash,
+ boolean initialize)
+{
+ // special case: check if network and preview player positions are redefined,
+ // to compare this later against the main menu level preview being redefined
+ struct TokenIntPtrInfo menu_config_players[] =
+ {
+ { "main.network_players.x", &menu.main.network_players.redefined },
+ { "main.network_players.y", &menu.main.network_players.redefined },
+ { "main.preview_players.x", &menu.main.preview_players.redefined },
+ { "main.preview_players.y", &menu.main.preview_players.redefined },
+ { "preview.x", &preview.redefined },
+ { "preview.y", &preview.redefined }
+ };
+ int i;
+
+ if (initialize)
+ {
+ for (i = 0; i < ARRAY_SIZE(menu_config_players); i++)
+ *menu_config_players[i].value = FALSE;
+ }
+ else
+ {
+ for (i = 0; i < ARRAY_SIZE(menu_config_players); i++)
+ if (getHashEntry(hash, menu_config_players[i].token) != NULL)
+ *menu_config_players[i].value = TRUE;
+ }
+}
+
+static void InitMenuDesignSettings_PreviewPlayers(void)
+{
+ InitMenuDesignSettings_PreviewPlayers_Ext(NULL, TRUE);
+}
+
+static void InitMenuDesignSettings_PreviewPlayers_FromHash(SetupFileHash *hash)
+{
+ InitMenuDesignSettings_PreviewPlayers_Ext(hash, FALSE);
+}
+
static void LoadMenuDesignSettingsFromFilename(char *filename)
{
static struct TitleFadingInfo tfi;
{
{ "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++)
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] },
}
}
- // special case: check if network and preview player positions are redefined,
- // to compare this later against the main menu level preview being redefined
- struct TokenIntPtrInfo menu_config_players[] =
- {
- { "main.network_players.x", &menu.main.network_players.redefined },
- { "main.network_players.y", &menu.main.network_players.redefined },
- { "main.preview_players.x", &menu.main.preview_players.redefined },
- { "main.preview_players.y", &menu.main.preview_players.redefined },
- { "preview.x", &preview.redefined },
- { "preview.y", &preview.redefined }
- };
-
- for (i = 0; i < ARRAY_SIZE(menu_config_players); i++)
- *menu_config_players[i].value = FALSE;
-
- for (i = 0; i < ARRAY_SIZE(menu_config_players); i++)
- if (getHashEntry(setup_file_hash, menu_config_players[i].token) != NULL)
- *menu_config_players[i].value = TRUE;
-
// read (and overwrite with) values that may be specified in config file
InitMenuDesignSettings_FromHash(setup_file_hash, TRUE);
+ // special case: check if network and preview player positions are redefined
+ InitMenuDesignSettings_PreviewPlayers_FromHash(setup_file_hash);
+
freeSetupFileHash(setup_file_hash);
}
InitMenuDesignSettings_Static();
InitMenuDesignSettings_SpecialPreProcessing();
+ InitMenuDesignSettings_PreviewPlayers();
if (!GFX_OVERRIDE_ARTWORK(ARTWORK_TYPE_GRAPHICS))
{
{ "artist_header", &tmp_music_file_info.artist_header },
{ "album_header", &tmp_music_file_info.album_header },
{ "year_header", &tmp_music_file_info.year_header },
+ { "played_header", &tmp_music_file_info.played_header },
{ "title", &tmp_music_file_info.title },
{ "artist", &tmp_music_file_info.artist },
{ "album", &tmp_music_file_info.album },
{ "year", &tmp_music_file_info.year },
+ { "played", &tmp_music_file_info.played },
{ NULL, NULL },
};
void LoadMusicInfo(void)
{
- char *music_directory = getCustomMusicDirectory();
+ int num_music_noconf = getMusicListSize_NoConf();
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)
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->played_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);
+ checked_free(music_file_info->played);
free(music_file_info);
new = &music_file_info;
- for (i = 0; i < num_music; i++)
+ // get (configured or unconfigured) music file info for all levels
+ for (i = leveldir_current->first_level;
+ i <= leveldir_current->last_level; i++)
{
- music = getMusicListEntry(i);
+ int music_nr;
- if (music->filename == NULL)
- continue;
+ if (levelset.music[i] != MUS_UNDEFINED)
+ {
+ // get music file info for configured level music
+ music_nr = levelset.music[i];
+ }
+ else if (num_music_noconf > 0)
+ {
+ // get music file info for unconfigured level music
+ int level_pos = i - leveldir_current->first_level;
- if (strEqual(music->filename, UNDEFINED_FILENAME))
+ music_nr = MAP_NOCONF_MUSIC(level_pos % num_music_noconf);
+ }
+ else
+ {
continue;
+ }
- // a configured file may be not recognized as music
- if (!FileIsMusic(music->filename))
+ char *basename = getMusicInfoEntryFilename(music_nr);
+
+ if (basename == NULL)
continue;
- if (!music_info_listed(music_file_info, music->filename))
+ if (!music_info_listed(music_file_info, basename))
{
- *new = get_music_file_info(music->filename, i);
+ *new = get_music_file_info(basename, music_nr);
if (*new != NULL)
new = &(*new)->next;
}
}
- if ((dir = openDirectory(music_directory)) == NULL)
- {
- Warn("cannot read music directory '%s'", music_directory);
-
- return;
- }
-
- while ((dir_entry = readDirectory(dir)) != NULL) // loop all entries
+ // get music file info for all remaining configured music files
+ for (i = 0; i < num_music; i++)
{
- 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;
+ music = getMusicListEntry(i);
- if (strEqual(basename, music->filename))
- {
- music_already_used = TRUE;
- break;
- }
- }
+ if (music->filename == NULL)
+ continue;
- if (music_already_used)
+ if (strEqual(music->filename, UNDEFINED_FILENAME))
continue;
- if (!FileIsMusic(dir_entry->filename))
+ // a configured file may be not recognized as music
+ if (!FileIsMusic(music->filename))
continue;
- if (!music_info_listed(music_file_info, basename))
+ if (!music_info_listed(music_file_info, music->filename))
{
- *new = get_music_file_info(basename, MAP_NOCONF_MUSIC(num_music_noconf));
+ *new = get_music_file_info(music->filename, i);
if (*new != NULL)
new = &(*new)->next;
}
-
- num_music_noconf++;
}
- closeDirectory(dir);
-
+ // get sound file info for all configured sound files
for (i = 0; i < num_sounds; i++)
{
sound = getSoundListEntry(i);
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++)
{
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++)
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);
}
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);