+ return;
+ }
+
+ ApiAddScoreAsThread(nr, tape_saved, NULL);
+}
+
+void SaveServerScoreFromFile(int nr, boolean tape_saved,
+ char *score_tape_filename)
+{
+ if (!runtime.use_api_server)
+ return;
+
+ ApiAddScoreAsThread(nr, tape_saved, score_tape_filename);
+}
+
+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();
+
+ if (!strEqual(setup.scores_in_highscore_list, STR_SCORES_TYPE_SERVER_ONLY))
+ LoadScore(nr);
+
+ // restore last added local score entry (before merging server scores)
+ scores.last_added = scores.last_added_local = last_added_local;
+
+ if (setup.use_api_server &&
+ !strEqual(setup.scores_in_highscore_list, STR_SCORES_TYPE_LOCAL_ONLY))
+ {
+ // load server scores from cache file and trigger update from server
+ LoadServerScore(nr, download_score);
+
+ // merge local scores with scores from server
+ MergeServerScore();
+ }
+
+ if (force_last_added)
+ scores.force_last_added = force_last_added;
+}
+
+
+// ============================================================================
+// setup file functions
+// ============================================================================
+
+#define TOKEN_STR_PLAYER_PREFIX "player_"
+
+
+static struct TokenInfo global_setup_tokens[] =
+{
+ {
+ TYPE_STRING,
+ &setup.player_name, "player_name"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.multiple_users, "multiple_users"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.sound, "sound"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.sound_loops, "repeating_sound_loops"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.sound_music, "background_music"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.sound_simple, "simple_sound_effects"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.toons, "toons"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.global_animations, "global_animations"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.scroll_delay, "scroll_delay"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.forced_scroll_delay, "forced_scroll_delay"
+ },
+ {
+ TYPE_INTEGER,
+ &setup.scroll_delay_value, "scroll_delay_value"
+ },
+ {
+ TYPE_STRING,
+ &setup.engine_snapshot_mode, "engine_snapshot_mode"
+ },
+ {
+ TYPE_INTEGER,
+ &setup.engine_snapshot_memory, "engine_snapshot_memory"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.fade_screens, "fade_screens"
+ },
+ {
+ 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_SWITCH,
+ &setup.show_titlescreen, "show_titlescreen"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.quick_doors, "quick_doors"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.team_mode, "team_mode"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.handicap, "handicap"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.skip_levels, "skip_levels"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.increment_levels, "increment_levels"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.auto_play_next_level, "auto_play_next_level"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.count_score_after_game, "count_score_after_game"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.show_scores_after_game, "show_scores_after_game"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.time_limit, "time_limit"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.fullscreen, "fullscreen"
+ },
+ {
+ TYPE_INTEGER,
+ &setup.window_scaling_percent, "window_scaling_percent"
+ },
+ {
+ TYPE_STRING,
+ &setup.window_scaling_quality, "window_scaling_quality"
+ },
+ {
+ TYPE_STRING,
+ &setup.screen_rendering_mode, "screen_rendering_mode"
+ },
+ {
+ TYPE_STRING,
+ &setup.vsync_mode, "vsync_mode"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.ask_on_escape, "ask_on_escape"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.ask_on_escape_editor, "ask_on_escape_editor"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.ask_on_game_over, "ask_on_game_over"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.ask_on_quit_game, "ask_on_quit_game"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.ask_on_quit_program, "ask_on_quit_program"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.quick_switch, "quick_player_switch"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.input_on_focus, "input_on_focus"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.prefer_aga_graphics, "prefer_aga_graphics"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.prefer_lowpass_sounds, "prefer_lowpass_sounds"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.prefer_extra_panel_items, "prefer_extra_panel_items"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.game_speed_extended, "game_speed_extended"
+ },
+ {
+ TYPE_INTEGER,
+ &setup.game_frame_delay, "game_frame_delay"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.bd_skip_uncovering, "bd_skip_uncovering"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.bd_skip_hatching, "bd_skip_hatching"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.bd_scroll_delay, "bd_scroll_delay"
+ },
+ {
+ TYPE_SWITCH3,
+ &setup.bd_smooth_movements, "bd_smooth_movements"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.sp_show_border_elements, "sp_show_border_elements"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.small_game_graphics, "small_game_graphics"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.show_load_save_buttons, "show_load_save_buttons"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.show_undo_redo_buttons, "show_undo_redo_buttons"
+ },
+ {
+ TYPE_STRING,
+ &setup.scores_in_highscore_list, "scores_in_highscore_list"
+ },
+ {
+ TYPE_STRING,
+ &setup.graphics_set, "graphics_set"
+ },
+ {
+ TYPE_STRING,
+ &setup.sounds_set, "sounds_set"
+ },
+ {
+ TYPE_STRING,
+ &setup.music_set, "music_set"
+ },
+ {
+ TYPE_SWITCH3,
+ &setup.override_level_graphics, "override_level_graphics"
+ },
+ {
+ TYPE_SWITCH3,
+ &setup.override_level_sounds, "override_level_sounds"
+ },
+ {
+ TYPE_SWITCH3,
+ &setup.override_level_music, "override_level_music"
+ },
+ {
+ TYPE_INTEGER,
+ &setup.volume_simple, "volume_simple"
+ },
+ {
+ TYPE_INTEGER,
+ &setup.volume_loops, "volume_loops"
+ },
+ {
+ TYPE_INTEGER,
+ &setup.volume_music, "volume_music"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.network_mode, "network_mode"
+ },
+ {
+ TYPE_PLAYER,
+ &setup.network_player_nr, "network_player"
+ },
+ {
+ TYPE_STRING,
+ &setup.network_server_hostname, "network_server_hostname"
+ },
+ {
+ TYPE_STRING,
+ &setup.touch.control_type, "touch.control_type"
+ },
+ {
+ TYPE_INTEGER,
+ &setup.touch.move_distance, "touch.move_distance"
+ },
+ {
+ TYPE_INTEGER,
+ &setup.touch.drop_distance, "touch.drop_distance"
+ },
+ {
+ TYPE_INTEGER,
+ &setup.touch.transparency, "touch.transparency"
+ },
+ {
+ TYPE_INTEGER,
+ &setup.touch.draw_outlined, "touch.draw_outlined"
+ },
+ {
+ TYPE_INTEGER,
+ &setup.touch.draw_pressed, "touch.draw_pressed"
+ },
+ {
+ TYPE_INTEGER,
+ &setup.touch.grid_xsize[0], "touch.virtual_buttons.0.xsize"
+ },
+ {
+ TYPE_INTEGER,
+ &setup.touch.grid_ysize[0], "touch.virtual_buttons.0.ysize"
+ },
+ {
+ TYPE_INTEGER,
+ &setup.touch.grid_xsize[1], "touch.virtual_buttons.1.xsize"
+ },
+ {
+ 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_INTEGER,
+ &setup.auto_setup.editor_zoom_tilesize, "editor.zoom_tilesize"
+ },
+};
+
+static struct TokenInfo server_setup_tokens[] =
+{
+ {
+ TYPE_STRING,
+ &setup.player_uuid, "player_uuid"
+ },
+ {
+ TYPE_INTEGER,
+ &setup.player_version, "player_version"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.use_api_server, TEST_PREFIX "use_api_server"
+ },
+ {
+ TYPE_STRING,
+ &setup.api_server_hostname, TEST_PREFIX "api_server_hostname"
+ },
+ {
+ TYPE_STRING,
+ &setup.api_server_password, TEST_PREFIX "api_server_password"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.ask_for_uploading_tapes, TEST_PREFIX "ask_for_uploading_tapes"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.ask_for_remaining_tapes, TEST_PREFIX "ask_for_remaining_tapes"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.provide_uploading_tapes, TEST_PREFIX "provide_uploading_tapes"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.ask_for_using_api_server,TEST_PREFIX "ask_for_using_api_server"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.has_remaining_tapes, TEST_PREFIX "has_remaining_tapes"
+ },
+};
+
+static struct TokenInfo editor_setup_tokens[] =
+{
+ {
+ TYPE_SWITCH,
+ &setup.editor.el_classic, "editor.el_classic"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.editor.el_custom, "editor.el_custom"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.editor.el_user_defined, "editor.el_user_defined"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.editor.el_dynamic, "editor.el_dynamic"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.editor.el_headlines, "editor.el_headlines"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.editor.show_element_token, "editor.show_element_token"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.editor.show_read_only_warning, "editor.show_read_only_warning"
+ },
+};
+
+static struct TokenInfo editor_cascade_setup_tokens[] =
+{
+ {
+ TYPE_SWITCH,
+ &setup.editor_cascade.el_bd, "editor.cascade.el_bd"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.editor_cascade.el_bd_native, "editor.cascade.el_bd_native"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.editor_cascade.el_em, "editor.cascade.el_em"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.editor_cascade.el_emc, "editor.cascade.el_emc"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.editor_cascade.el_rnd, "editor.cascade.el_rnd"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.editor_cascade.el_sb, "editor.cascade.el_sb"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.editor_cascade.el_sp, "editor.cascade.el_sp"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.editor_cascade.el_dc, "editor.cascade.el_dc"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.editor_cascade.el_dx, "editor.cascade.el_dx"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.editor_cascade.el_mm, "editor.cascade.el_mm"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.editor_cascade.el_df, "editor.cascade.el_df"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.editor_cascade.el_chars, "editor.cascade.el_chars"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.editor_cascade.el_steel_chars, "editor.cascade.el_steel_chars"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.editor_cascade.el_ce, "editor.cascade.el_ce"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.editor_cascade.el_ge, "editor.cascade.el_ge"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.editor_cascade.el_es, "editor.cascade.el_es"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.editor_cascade.el_ref, "editor.cascade.el_ref"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.editor_cascade.el_user, "editor.cascade.el_user"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.editor_cascade.el_dynamic, "editor.cascade.el_dynamic"
+ },
+};
+
+static struct TokenInfo shortcut_setup_tokens[] =
+{
+ {
+ TYPE_KEY_X11,
+ &setup.shortcut.save_game, "shortcut.save_game"
+ },
+ {
+ TYPE_KEY_X11,
+ &setup.shortcut.load_game, "shortcut.load_game"
+ },
+ {
+ TYPE_KEY_X11,
+ &setup.shortcut.restart_game, "shortcut.restart_game"
+ },
+ {
+ TYPE_KEY_X11,
+ &setup.shortcut.pause_before_end, "shortcut.pause_before_end"
+ },
+ {
+ TYPE_KEY_X11,
+ &setup.shortcut.toggle_pause, "shortcut.toggle_pause"
+ },
+ {
+ TYPE_KEY_X11,
+ &setup.shortcut.focus_player[0], "shortcut.focus_player_1"
+ },
+ {
+ TYPE_KEY_X11,
+ &setup.shortcut.focus_player[1], "shortcut.focus_player_2"
+ },
+ {
+ TYPE_KEY_X11,
+ &setup.shortcut.focus_player[2], "shortcut.focus_player_3"
+ },
+ {
+ TYPE_KEY_X11,
+ &setup.shortcut.focus_player[3], "shortcut.focus_player_4"
+ },
+ {
+ TYPE_KEY_X11,
+ &setup.shortcut.focus_player_all, "shortcut.focus_player_all"
+ },
+ {
+ TYPE_KEY_X11,
+ &setup.shortcut.tape_eject, "shortcut.tape_eject"
+ },
+ {
+ TYPE_KEY_X11,
+ &setup.shortcut.tape_extra, "shortcut.tape_extra"
+ },
+ {
+ TYPE_KEY_X11,
+ &setup.shortcut.tape_stop, "shortcut.tape_stop"
+ },
+ {
+ TYPE_KEY_X11,
+ &setup.shortcut.tape_pause, "shortcut.tape_pause"
+ },
+ {
+ TYPE_KEY_X11,
+ &setup.shortcut.tape_record, "shortcut.tape_record"
+ },
+ {
+ TYPE_KEY_X11,
+ &setup.shortcut.tape_play, "shortcut.tape_play"
+ },
+ {
+ TYPE_KEY_X11,
+ &setup.shortcut.sound_simple, "shortcut.sound_simple"
+ },
+ {
+ TYPE_KEY_X11,
+ &setup.shortcut.sound_loops, "shortcut.sound_loops"
+ },
+ {
+ TYPE_KEY_X11,
+ &setup.shortcut.sound_music, "shortcut.sound_music"
+ },
+ {
+ TYPE_KEY_X11,
+ &setup.shortcut.snap_left, "shortcut.snap_left"
+ },
+ {
+ TYPE_KEY_X11,
+ &setup.shortcut.snap_right, "shortcut.snap_right"
+ },
+ {
+ TYPE_KEY_X11,
+ &setup.shortcut.snap_up, "shortcut.snap_up"
+ },
+ {
+ TYPE_KEY_X11,
+ &setup.shortcut.snap_down, "shortcut.snap_down"
+ },
+};
+
+static struct SetupInputInfo setup_input;
+static struct TokenInfo player_setup_tokens[] =
+{
+ {
+ TYPE_BOOLEAN,
+ &setup_input.use_joystick, ".use_joystick"
+ },
+ {
+ TYPE_STRING,
+ &setup_input.joy.device_name, ".joy.device_name"
+ },
+ {
+ TYPE_INTEGER,
+ &setup_input.joy.xleft, ".joy.xleft"
+ },
+ {
+ TYPE_INTEGER,
+ &setup_input.joy.xmiddle, ".joy.xmiddle"
+ },
+ {
+ TYPE_INTEGER,
+ &setup_input.joy.xright, ".joy.xright"
+ },
+ {
+ TYPE_INTEGER,
+ &setup_input.joy.yupper, ".joy.yupper"
+ },
+ {
+ TYPE_INTEGER,
+ &setup_input.joy.ymiddle, ".joy.ymiddle"
+ },
+ {
+ TYPE_INTEGER,
+ &setup_input.joy.ylower, ".joy.ylower"
+ },
+ {
+ TYPE_INTEGER,
+ &setup_input.joy.snap, ".joy.snap_field"
+ },
+ {
+ TYPE_INTEGER,
+ &setup_input.joy.drop, ".joy.place_bomb"
+ },
+ {
+ TYPE_KEY_X11,
+ &setup_input.key.left, ".key.move_left"
+ },
+ {
+ TYPE_KEY_X11,
+ &setup_input.key.right, ".key.move_right"
+ },
+ {
+ TYPE_KEY_X11,
+ &setup_input.key.up, ".key.move_up"
+ },
+ {
+ TYPE_KEY_X11,
+ &setup_input.key.down, ".key.move_down"
+ },
+ {
+ TYPE_KEY_X11,
+ &setup_input.key.snap, ".key.snap_field"
+ },
+ {
+ TYPE_KEY_X11,
+ &setup_input.key.drop, ".key.place_bomb"
+ },
+};
+
+static struct TokenInfo system_setup_tokens[] =
+{
+ {
+ TYPE_STRING,
+ &setup.system.sdl_renderdriver, "system.sdl_renderdriver"
+ },
+ {
+ TYPE_STRING,
+ &setup.system.sdl_videodriver, "system.sdl_videodriver"
+ },
+ {
+ TYPE_STRING,
+ &setup.system.sdl_audiodriver, "system.sdl_audiodriver"
+ },
+ {
+ TYPE_INTEGER,
+ &setup.system.audio_fragment_size, "system.audio_fragment_size"
+ },
+};
+
+static struct TokenInfo internal_setup_tokens[] =
+{
+ {
+ TYPE_STRING,
+ &setup.internal.program_title, "program_title"
+ },
+ {
+ TYPE_STRING,
+ &setup.internal.program_version, "program_version"
+ },
+ {
+ TYPE_STRING,
+ &setup.internal.program_author, "program_author"
+ },
+ {
+ TYPE_STRING,
+ &setup.internal.program_email, "program_email"
+ },
+ {
+ TYPE_STRING,
+ &setup.internal.program_website, "program_website"
+ },
+ {
+ TYPE_STRING,
+ &setup.internal.program_copyright, "program_copyright"
+ },
+ {
+ TYPE_STRING,
+ &setup.internal.program_company, "program_company"
+ },
+ {
+ TYPE_STRING,
+ &setup.internal.program_icon_file, "program_icon_file"
+ },
+ {
+ TYPE_STRING,
+ &setup.internal.default_graphics_set, "default_graphics_set"
+ },
+ {
+ TYPE_STRING,
+ &setup.internal.default_sounds_set, "default_sounds_set"
+ },
+ {
+ TYPE_STRING,
+ &setup.internal.default_music_set, "default_music_set"
+ },
+ {
+ TYPE_STRING,
+ &setup.internal.fallback_graphics_file, "fallback_graphics_file"
+ },
+ {
+ TYPE_STRING,
+ &setup.internal.fallback_sounds_file, "fallback_sounds_file"
+ },
+ {
+ TYPE_STRING,
+ &setup.internal.fallback_music_file, "fallback_music_file"
+ },
+ {
+ TYPE_STRING,
+ &setup.internal.default_level_series, "default_level_series"
+ },
+ {
+ TYPE_INTEGER,
+ &setup.internal.default_window_width, "default_window_width"
+ },
+ {
+ TYPE_INTEGER,
+ &setup.internal.default_window_height, "default_window_height"
+ },
+ {
+ TYPE_BOOLEAN,
+ &setup.internal.choose_from_top_leveldir, "choose_from_top_leveldir"
+ },
+ {
+ TYPE_BOOLEAN,
+ &setup.internal.show_scaling_in_title, "show_scaling_in_title"
+ },
+ {
+ 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_graphics, "menu_graphics"
+ },
+ {
+ TYPE_BOOLEAN,
+ &setup.internal.menu_sound, "menu_sound"
+ },
+ {
+ TYPE_BOOLEAN,
+ &setup.internal.menu_artwork, "menu_artwork"
+ },
+ {
+ TYPE_BOOLEAN,
+ &setup.internal.menu_input, "menu_input"
+ },
+ {
+ TYPE_BOOLEAN,
+ &setup.internal.menu_touch, "menu_touch"
+ },
+ {
+ TYPE_BOOLEAN,
+ &setup.internal.menu_shortcuts, "menu_shortcuts"
+ },
+ {
+ TYPE_BOOLEAN,
+ &setup.internal.menu_exit, "menu_exit"
+ },
+ {
+ 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[] =
+{
+ {
+ TYPE_INTEGER,
+ &setup.debug.frame_delay[0], "debug.frame_delay_0"
+ },
+ {
+ TYPE_INTEGER,
+ &setup.debug.frame_delay[1], "debug.frame_delay_1"
+ },
+ {
+ TYPE_INTEGER,
+ &setup.debug.frame_delay[2], "debug.frame_delay_2"
+ },
+ {
+ TYPE_INTEGER,
+ &setup.debug.frame_delay[3], "debug.frame_delay_3"
+ },
+ {
+ TYPE_INTEGER,
+ &setup.debug.frame_delay[4], "debug.frame_delay_4"
+ },
+ {
+ TYPE_INTEGER,
+ &setup.debug.frame_delay[5], "debug.frame_delay_5"
+ },
+ {
+ TYPE_INTEGER,
+ &setup.debug.frame_delay[6], "debug.frame_delay_6"
+ },
+ {
+ TYPE_INTEGER,
+ &setup.debug.frame_delay[7], "debug.frame_delay_7"
+ },
+ {
+ TYPE_INTEGER,
+ &setup.debug.frame_delay[8], "debug.frame_delay_8"
+ },
+ {
+ TYPE_INTEGER,
+ &setup.debug.frame_delay[9], "debug.frame_delay_9"
+ },
+ {
+ TYPE_KEY_X11,
+ &setup.debug.frame_delay_key[0], "debug.key.frame_delay_0"
+ },
+ {
+ TYPE_KEY_X11,
+ &setup.debug.frame_delay_key[1], "debug.key.frame_delay_1"
+ },
+ {
+ TYPE_KEY_X11,
+ &setup.debug.frame_delay_key[2], "debug.key.frame_delay_2"
+ },
+ {
+ TYPE_KEY_X11,
+ &setup.debug.frame_delay_key[3], "debug.key.frame_delay_3"
+ },
+ {
+ TYPE_KEY_X11,
+ &setup.debug.frame_delay_key[4], "debug.key.frame_delay_4"
+ },
+ {
+ TYPE_KEY_X11,
+ &setup.debug.frame_delay_key[5], "debug.key.frame_delay_5"
+ },
+ {
+ TYPE_KEY_X11,
+ &setup.debug.frame_delay_key[6], "debug.key.frame_delay_6"
+ },
+ {
+ TYPE_KEY_X11,
+ &setup.debug.frame_delay_key[7], "debug.key.frame_delay_7"
+ },
+ {
+ TYPE_KEY_X11,
+ &setup.debug.frame_delay_key[8], "debug.key.frame_delay_8"
+ },
+ {
+ TYPE_KEY_X11,
+ &setup.debug.frame_delay_key[9], "debug.key.frame_delay_9"
+ },
+ {
+ TYPE_BOOLEAN,
+ &setup.debug.frame_delay_use_mod_key, "debug.frame_delay.use_mod_key"},
+ {
+ TYPE_BOOLEAN,
+ &setup.debug.frame_delay_game_only, "debug.frame_delay.game_only"
+ },
+ {
+ TYPE_BOOLEAN,
+ &setup.debug.show_frames_per_second, "debug.show_frames_per_second"
+ },
+ {
+ TYPE_SWITCH3,
+ &setup.debug.xsn_mode, "debug.xsn_mode"
+ },
+ {
+ TYPE_INTEGER,
+ &setup.debug.xsn_percent, "debug.xsn_percent"
+ },
+};
+
+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)
+{
+ int i;
+
+ si->player_name = getStringCopy(getDefaultUserName(user.nr));
+
+ si->multiple_users = TRUE;
+
+ si->sound = TRUE;
+ si->sound_loops = TRUE;
+ si->sound_music = TRUE;
+ si->sound_simple = TRUE;
+ si->toons = TRUE;
+ si->global_animations = TRUE;
+ si->scroll_delay = TRUE;
+ si->forced_scroll_delay = FALSE;
+ si->scroll_delay_value = STD_SCROLL_DELAY;
+ si->engine_snapshot_mode = getStringCopy(STR_SNAPSHOT_MODE_DEFAULT);
+ 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->team_mode = FALSE;
+ si->handicap = TRUE;
+ si->skip_levels = TRUE;
+ si->increment_levels = TRUE;
+ si->auto_play_next_level = TRUE;
+ si->count_score_after_game = TRUE;
+ si->show_scores_after_game = TRUE;
+ si->time_limit = TRUE;
+ si->fullscreen = FALSE;
+ si->window_scaling_percent = STD_WINDOW_SCALING_PERCENT;
+ si->window_scaling_quality = getStringCopy(SCALING_QUALITY_DEFAULT);
+ si->screen_rendering_mode = getStringCopy(STR_SPECIAL_RENDERING_DEFAULT);
+ si->vsync_mode = getStringCopy(STR_VSYNC_MODE_DEFAULT);
+ si->ask_on_escape = TRUE;
+ si->ask_on_escape_editor = TRUE;
+ si->ask_on_game_over = TRUE;
+ si->ask_on_quit_game = TRUE;
+ si->ask_on_quit_program = TRUE;
+ si->quick_switch = FALSE;
+ si->input_on_focus = FALSE;
+ si->prefer_aga_graphics = TRUE;
+ si->prefer_lowpass_sounds = FALSE;
+ si->prefer_extra_panel_items = TRUE;
+ si->game_speed_extended = FALSE;
+ si->game_frame_delay = GAME_FRAME_DELAY;
+ si->bd_skip_uncovering = FALSE;
+ si->bd_skip_hatching = FALSE;
+ si->bd_scroll_delay = TRUE;
+ si->bd_smooth_movements = AUTO;
+ si->sp_show_border_elements = FALSE;
+ si->small_game_graphics = FALSE;
+ si->show_load_save_buttons = FALSE;
+ si->show_undo_redo_buttons = FALSE;
+ si->scores_in_highscore_list = getStringCopy(STR_SCORES_TYPE_DEFAULT);
+
+ si->graphics_set = getStringCopy(GFX_CLASSIC_SUBDIR);
+ si->sounds_set = getStringCopy(SND_CLASSIC_SUBDIR);
+ si->music_set = getStringCopy(MUS_CLASSIC_SUBDIR);
+
+ si->override_level_graphics = FALSE;
+ 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->network_mode = FALSE;
+ si->network_player_nr = 0; // first player
+ si->network_server_hostname = getStringCopy(STR_NETWORK_AUTO_DETECT);
+
+ si->touch.control_type = getStringCopy(TOUCH_CONTROL_DEFAULT);
+ si->touch.move_distance = TOUCH_MOVE_DISTANCE_DEFAULT; // percent
+ si->touch.drop_distance = TOUCH_DROP_DISTANCE_DEFAULT; // percent
+ si->touch.transparency = TOUCH_TRANSPARENCY_DEFAULT; // percent
+ si->touch.draw_outlined = TRUE;
+ si->touch.draw_pressed = TRUE;
+
+ for (i = 0; i < 2; i++)
+ {
+ char *default_grid_button[6][2] =
+ {
+ { " ", " ^^ " },
+ { " ", " ^^ " },
+ { " ", "<< >>" },
+ { " ", "<< >>" },
+ { "111222", " vv " },
+ { "111222", " vv " }
+ };
+ int grid_xsize = DEFAULT_GRID_XSIZE(i);
+ int grid_ysize = DEFAULT_GRID_YSIZE(i);
+ int min_xsize = MIN(6, grid_xsize);
+ int min_ysize = MIN(6, grid_ysize);
+ int startx = grid_xsize - min_xsize;
+ int starty = grid_ysize - min_ysize;
+ int x, y;
+
+ // virtual buttons grid can only be set to defaults if video is initialized
+ // (this will be repeated if virtual buttons are not loaded from setup file)
+ if (video.initialized)
+ {
+ si->touch.grid_xsize[i] = grid_xsize;
+ si->touch.grid_ysize[i] = grid_ysize;
+ }
+ else
+ {
+ si->touch.grid_xsize[i] = -1;
+ si->touch.grid_ysize[i] = -1;
+ }
+
+ for (x = 0; x < MAX_GRID_XSIZE; x++)
+ for (y = 0; y < MAX_GRID_YSIZE; y++)
+ si->touch.grid_button[i][x][y] = CHAR_GRID_BUTTON_NONE;
+
+ for (x = 0; x < min_xsize; x++)
+ for (y = 0; y < min_ysize; y++)
+ si->touch.grid_button[i][x][starty + y] =
+ default_grid_button[y][0][x];
+
+ for (x = 0; x < min_xsize; x++)
+ for (y = 0; y < min_ysize; y++)
+ si->touch.grid_button[i][startx + x][starty + y] =
+ default_grid_button[y][1][x];
+ }
+
+ si->touch.grid_initialized = video.initialized;
+
+ si->touch.overlay_buttons = FALSE;
+
+ si->editor.el_boulderdash = TRUE;
+ si->editor.el_boulderdash_native = TRUE;
+ si->editor.el_emerald_mine = TRUE;
+ si->editor.el_emerald_mine_club = TRUE;
+ si->editor.el_more = TRUE;
+ si->editor.el_sokoban = TRUE;
+ si->editor.el_supaplex = TRUE;
+ si->editor.el_diamond_caves = TRUE;
+ si->editor.el_dx_boulderdash = TRUE;
+
+ si->editor.el_mirror_magic = TRUE;
+ si->editor.el_deflektor = TRUE;
+
+ si->editor.el_chars = TRUE;
+ si->editor.el_steel_chars = TRUE;
+
+ si->editor.el_classic = TRUE;
+ si->editor.el_custom = TRUE;
+
+ si->editor.el_user_defined = FALSE;
+ si->editor.el_dynamic = TRUE;
+
+ si->editor.el_headlines = TRUE;
+
+ si->editor.show_element_token = FALSE;
+
+ si->editor.show_read_only_warning = TRUE;
+
+ si->editor.use_template_for_new_levels = TRUE;
+
+ si->shortcut.save_game = DEFAULT_KEY_SAVE_GAME;
+ si->shortcut.load_game = DEFAULT_KEY_LOAD_GAME;
+ si->shortcut.restart_game = DEFAULT_KEY_RESTART_GAME;
+ si->shortcut.pause_before_end = DEFAULT_KEY_PAUSE_BEFORE_END;
+ si->shortcut.toggle_pause = DEFAULT_KEY_TOGGLE_PAUSE;
+
+ si->shortcut.focus_player[0] = DEFAULT_KEY_FOCUS_PLAYER_1;
+ si->shortcut.focus_player[1] = DEFAULT_KEY_FOCUS_PLAYER_2;
+ si->shortcut.focus_player[2] = DEFAULT_KEY_FOCUS_PLAYER_3;
+ 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;
+ si->input[i].joy.device_name = getStringCopy(getDeviceNameFromJoystickNr(i));
+ si->input[i].joy.xleft = JOYSTICK_XLEFT;
+ si->input[i].joy.xmiddle = JOYSTICK_XMIDDLE;
+ si->input[i].joy.xright = JOYSTICK_XRIGHT;
+ si->input[i].joy.yupper = JOYSTICK_YUPPER;
+ si->input[i].joy.ymiddle = JOYSTICK_YMIDDLE;
+ si->input[i].joy.ylower = JOYSTICK_YLOWER;
+ si->input[i].joy.snap = (i == 0 ? JOY_BUTTON_1 : 0);
+ si->input[i].joy.drop = (i == 0 ? JOY_BUTTON_2 : 0);
+ si->input[i].key.left = (i == 0 ? DEFAULT_KEY_LEFT : KSYM_UNDEFINED);
+ si->input[i].key.right = (i == 0 ? DEFAULT_KEY_RIGHT : KSYM_UNDEFINED);
+ si->input[i].key.up = (i == 0 ? DEFAULT_KEY_UP : KSYM_UNDEFINED);
+ si->input[i].key.down = (i == 0 ? DEFAULT_KEY_DOWN : KSYM_UNDEFINED);
+ si->input[i].key.snap = (i == 0 ? DEFAULT_KEY_SNAP : KSYM_UNDEFINED);
+ si->input[i].key.drop = (i == 0 ? DEFAULT_KEY_DROP : KSYM_UNDEFINED);
+ }
+
+ si->system.sdl_renderdriver = getStringCopy(ARG_DEFAULT);
+ si->system.sdl_videodriver = getStringCopy(ARG_DEFAULT);
+ si->system.sdl_audiodriver = getStringCopy(ARG_DEFAULT);
+ si->system.audio_fragment_size = DEFAULT_AUDIO_FRAGMENT_SIZE;
+
+ si->internal.program_title = getStringCopy(PROGRAM_TITLE_STRING);
+ si->internal.program_version = getStringCopy(getProgramRealVersionString());
+ si->internal.program_author = getStringCopy(PROGRAM_AUTHOR_STRING);
+ si->internal.program_email = getStringCopy(PROGRAM_EMAIL_STRING);
+ si->internal.program_website = getStringCopy(PROGRAM_WEBSITE_STRING);
+ si->internal.program_copyright = getStringCopy(PROGRAM_COPYRIGHT_STRING);
+ si->internal.program_company = getStringCopy(PROGRAM_COMPANY_STRING);
+
+ si->internal.program_icon_file = getStringCopy(PROGRAM_ICON_FILENAME);
+
+ si->internal.default_graphics_set = getStringCopy(GFX_CLASSIC_SUBDIR);
+ si->internal.default_sounds_set = getStringCopy(SND_CLASSIC_SUBDIR);
+ si->internal.default_music_set = getStringCopy(MUS_CLASSIC_SUBDIR);
+
+ si->internal.fallback_graphics_file = getStringCopy(UNDEFINED_FILENAME);
+ si->internal.fallback_sounds_file = getStringCopy(UNDEFINED_FILENAME);
+ si->internal.fallback_music_file = getStringCopy(UNDEFINED_FILENAME);
+
+ si->internal.default_level_series = getStringCopy(UNDEFINED_LEVELSET);
+ 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.frame_delay[0] = DEFAULT_FRAME_DELAY_0;
+ si->debug.frame_delay[1] = DEFAULT_FRAME_DELAY_1;
+ si->debug.frame_delay[2] = DEFAULT_FRAME_DELAY_2;
+ si->debug.frame_delay[3] = DEFAULT_FRAME_DELAY_3;
+ si->debug.frame_delay[4] = DEFAULT_FRAME_DELAY_4;
+ si->debug.frame_delay[5] = DEFAULT_FRAME_DELAY_5;
+ si->debug.frame_delay[6] = DEFAULT_FRAME_DELAY_6;
+ si->debug.frame_delay[7] = DEFAULT_FRAME_DELAY_7;
+ si->debug.frame_delay[8] = DEFAULT_FRAME_DELAY_8;
+ si->debug.frame_delay[9] = DEFAULT_FRAME_DELAY_9;
+
+ si->debug.frame_delay_key[0] = DEFAULT_KEY_FRAME_DELAY_0;
+ si->debug.frame_delay_key[1] = DEFAULT_KEY_FRAME_DELAY_1;
+ si->debug.frame_delay_key[2] = DEFAULT_KEY_FRAME_DELAY_2;
+ si->debug.frame_delay_key[3] = DEFAULT_KEY_FRAME_DELAY_3;
+ si->debug.frame_delay_key[4] = DEFAULT_KEY_FRAME_DELAY_4;
+ si->debug.frame_delay_key[5] = DEFAULT_KEY_FRAME_DELAY_5;
+ si->debug.frame_delay_key[6] = DEFAULT_KEY_FRAME_DELAY_6;
+ si->debug.frame_delay_key[7] = DEFAULT_KEY_FRAME_DELAY_7;
+ si->debug.frame_delay_key[8] = DEFAULT_KEY_FRAME_DELAY_8;
+ si->debug.frame_delay_key[9] = DEFAULT_KEY_FRAME_DELAY_9;
+
+ si->debug.frame_delay_use_mod_key = DEFAULT_FRAME_DELAY_USE_MOD_KEY;
+ si->debug.frame_delay_game_only = DEFAULT_FRAME_DELAY_GAME_ONLY;
+
+ si->debug.show_frames_per_second = FALSE;
+
+ si->debug.xsn_mode = AUTO;
+ 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);
+}
+
+static void setSetupInfoToDefaults_AutoSetup(struct SetupInfo *si)
+{
+ si->auto_setup.editor_zoom_tilesize = MINI_TILESIZE;
+}
+
+static void setSetupInfoToDefaults_ServerSetup(struct SetupInfo *si)
+{
+ si->player_uuid = NULL; // (will be set later)
+ si->player_version = 1; // (will be set later)
+
+ si->use_api_server = TRUE;
+ si->api_server_hostname = getStringCopy(API_SERVER_HOSTNAME);
+ si->api_server_password = getStringCopy(UNDEFINED_PASSWORD);
+ si->ask_for_uploading_tapes = TRUE;
+ si->ask_for_remaining_tapes = FALSE;
+ si->provide_uploading_tapes = TRUE;
+ si->ask_for_using_api_server = TRUE;
+ si->has_remaining_tapes = FALSE;
+}
+
+static void setSetupInfoToDefaults_EditorCascade(struct SetupInfo *si)
+{
+ si->editor_cascade.el_bd = TRUE;
+ si->editor_cascade.el_bd_native = TRUE;
+ si->editor_cascade.el_em = TRUE;
+ si->editor_cascade.el_emc = TRUE;
+ si->editor_cascade.el_rnd = TRUE;
+ si->editor_cascade.el_sb = TRUE;
+ si->editor_cascade.el_sp = TRUE;
+ si->editor_cascade.el_dc = TRUE;
+ si->editor_cascade.el_dx = TRUE;
+
+ si->editor_cascade.el_mm = TRUE;
+ si->editor_cascade.el_df = TRUE;
+
+ si->editor_cascade.el_chars = FALSE;
+ si->editor_cascade.el_steel_chars = FALSE;
+ si->editor_cascade.el_ce = FALSE;
+ si->editor_cascade.el_ge = FALSE;
+ si->editor_cascade.el_es = FALSE;
+ si->editor_cascade.el_ref = FALSE;
+ si->editor_cascade.el_user = FALSE;
+ si->editor_cascade.el_dynamic = FALSE;
+}
+
+#define MAX_HIDE_SETUP_TOKEN_SIZE 20
+
+static char *getHideSetupToken(void *setup_value)
+{
+ static char hide_setup_token[MAX_HIDE_SETUP_TOKEN_SIZE];
+
+ if (setup_value != NULL)
+ snprintf(hide_setup_token, MAX_HIDE_SETUP_TOKEN_SIZE, "%p", setup_value);
+
+ return hide_setup_token;
+}
+
+void setHideSetupEntry(void *setup_value)
+{
+ char *hide_setup_token = getHideSetupToken(setup_value);
+
+ if (hide_setup_hash == NULL)
+ hide_setup_hash = newSetupFileHash();
+
+ if (setup_value != NULL)
+ setHashEntry(hide_setup_hash, hide_setup_token, "");
+}
+
+void removeHideSetupEntry(void *setup_value)
+{
+ char *hide_setup_token = getHideSetupToken(setup_value);
+
+ if (setup_value != NULL)
+ removeHashEntry(hide_setup_hash, hide_setup_token);
+}
+
+boolean hideSetupEntry(void *setup_value)
+{
+ char *hide_setup_token = getHideSetupToken(setup_value);
+
+ return (setup_value != NULL &&
+ getHashEntry(hide_setup_hash, hide_setup_token) != NULL);
+}
+
+static void setSetupInfoFromTokenText(SetupFileHash *setup_file_hash,
+ struct TokenInfo *token_info,
+ int token_nr, char *token_text)
+{
+ char *token_hide_text = getStringCat2(token_text, ".hide");
+ char *token_hide_value = getHashEntry(setup_file_hash, token_hide_text);
+
+ // set the value of this setup option in the setup option structure
+ setSetupInfo(token_info, token_nr, getHashEntry(setup_file_hash, token_text));
+
+ // check if this setup option should be hidden in the setup menu
+ if (token_hide_value != NULL && get_boolean_from_string(token_hide_value))
+ setHideSetupEntry(token_info[token_nr].value);
+
+ free(token_hide_text);
+}
+
+static void setSetupInfoFromTokenInfo(SetupFileHash *setup_file_hash,
+ struct TokenInfo *token_info,
+ int token_nr)
+{
+ setSetupInfoFromTokenText(setup_file_hash, token_info, token_nr,
+ token_info[token_nr].text);
+}
+
+static void decodeSetupFileHash_Default(SetupFileHash *setup_file_hash)
+{
+ int i, pnr;
+
+ if (!setup_file_hash)
+ return;
+
+ for (i = 0; i < ARRAY_SIZE(global_setup_tokens); i++)
+ setSetupInfoFromTokenInfo(setup_file_hash, global_setup_tokens, i);
+
+ setup.touch.grid_initialized = TRUE;
+ for (i = 0; i < 2; i++)
+ {
+ int grid_xsize = setup.touch.grid_xsize[i];
+ int grid_ysize = setup.touch.grid_ysize[i];
+ int x, y;
+
+ // if virtual buttons are not loaded from setup file, repeat initializing
+ // virtual buttons grid with default values later when video is initialized
+ if (grid_xsize == -1 ||
+ grid_ysize == -1)
+ {
+ setup.touch.grid_initialized = FALSE;
+
+ continue;
+ }
+
+ for (y = 0; y < grid_ysize; y++)
+ {
+ char token_string[MAX_LINE_LEN];
+
+ sprintf(token_string, "touch.virtual_buttons.%d.%02d", i, y);
+
+ char *value_string = getHashEntry(setup_file_hash, token_string);
+
+ if (value_string == NULL)
+ continue;
+
+ for (x = 0; x < grid_xsize; x++)
+ {
+ char c = value_string[x];
+
+ setup.touch.grid_button[i][x][y] =
+ (c == '.' ? CHAR_GRID_BUTTON_NONE : c);
+ }
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(editor_setup_tokens); i++)
+ setSetupInfoFromTokenInfo(setup_file_hash, editor_setup_tokens, i);
+
+ for (i = 0; i < ARRAY_SIZE(shortcut_setup_tokens); i++)
+ setSetupInfoFromTokenInfo(setup_file_hash, shortcut_setup_tokens, i);
+
+ for (pnr = 0; pnr < MAX_PLAYERS; pnr++)
+ {
+ char prefix[30];
+
+ sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
+
+ setup_input = setup.input[pnr];
+ for (i = 0; i < ARRAY_SIZE(player_setup_tokens); i++)
+ {
+ char full_token[100];
+
+ sprintf(full_token, "%s%s", prefix, player_setup_tokens[i].text);
+ setSetupInfoFromTokenText(setup_file_hash, player_setup_tokens, i,
+ full_token);
+ }
+ setup.input[pnr] = setup_input;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(system_setup_tokens); i++)
+ setSetupInfoFromTokenInfo(setup_file_hash, system_setup_tokens, i);
+
+ for (i = 0; i < ARRAY_SIZE(internal_setup_tokens); i++)
+ setSetupInfoFromTokenInfo(setup_file_hash, internal_setup_tokens, i);
+
+ for (i = 0; i < ARRAY_SIZE(debug_setup_tokens); i++)
+ setSetupInfoFromTokenInfo(setup_file_hash, debug_setup_tokens, i);
+
+ for (i = 0; i < ARRAY_SIZE(options_setup_tokens); i++)
+ setSetupInfoFromTokenInfo(setup_file_hash, options_setup_tokens, i);
+
+ setHideRelatedSetupEntries();
+}
+
+static void decodeSetupFileHash_AutoSetup(SetupFileHash *setup_file_hash)
+{
+ int i;
+
+ if (!setup_file_hash)
+ return;
+
+ for (i = 0; i < ARRAY_SIZE(auto_setup_tokens); i++)
+ setSetupInfo(auto_setup_tokens, i,
+ getHashEntry(setup_file_hash,
+ auto_setup_tokens[i].text));
+}
+
+static void decodeSetupFileHash_ServerSetup(SetupFileHash *setup_file_hash)
+{
+ int i;
+
+ if (!setup_file_hash)
+ return;
+
+ for (i = 0; i < ARRAY_SIZE(server_setup_tokens); i++)
+ setSetupInfo(server_setup_tokens, i,
+ getHashEntry(setup_file_hash,
+ server_setup_tokens[i].text));
+}
+
+static void decodeSetupFileHash_EditorCascade(SetupFileHash *setup_file_hash)
+{
+ int i;
+
+ if (!setup_file_hash)
+ return;
+
+ for (i = 0; i < ARRAY_SIZE(editor_cascade_setup_tokens); i++)
+ setSetupInfo(editor_cascade_setup_tokens, i,
+ getHashEntry(setup_file_hash,
+ editor_cascade_setup_tokens[i].text));
+}
+
+void LoadUserNames(void)
+{
+ int last_user_nr = user.nr;
+ int i;
+
+ if (global.user_names != NULL)
+ {
+ for (i = 0; i < MAX_PLAYER_NAMES; i++)
+ checked_free(global.user_names[i]);
+
+ checked_free(global.user_names);
+ }
+
+ global.user_names = checked_calloc(MAX_PLAYER_NAMES * sizeof(char *));
+
+ for (i = 0; i < MAX_PLAYER_NAMES; i++)
+ {
+ user.nr = i;
+
+ SetupFileHash *setup_file_hash = loadSetupFileHash(getSetupFilename());
+
+ if (setup_file_hash)
+ {
+ char *player_name = getHashEntry(setup_file_hash, "player_name");
+
+ global.user_names[i] = getFixedUserName(player_name);
+
+ freeSetupFileHash(setup_file_hash);
+ }
+
+ if (global.user_names[i] == NULL)
+ global.user_names[i] = getStringCopy(getDefaultUserName(i));
+ }
+
+ user.nr = last_user_nr;
+}
+
+void LoadSetupFromFilename(char *filename)
+{
+ SetupFileHash *setup_file_hash = loadSetupFileHash(filename);
+
+ if (setup_file_hash)
+ {
+ decodeSetupFileHash_Default(setup_file_hash);
+
+ freeSetupFileHash(setup_file_hash);
+ }
+ else
+ {
+ Debug("setup", "using default setup values");
+ }
+}
+
+static void LoadSetup_SpecialPostProcessing(void)
+{
+ char *player_name_new;
+
+ // needed to work around problems with fixed length strings
+ player_name_new = getFixedUserName(setup.player_name);
+ free(setup.player_name);
+ setup.player_name = player_name_new;
+
+ // "scroll_delay: on(3) / off(0)" was replaced by scroll delay value
+ if (setup.scroll_delay == FALSE)
+ {
+ setup.scroll_delay_value = MIN_SCROLL_DELAY;
+ setup.scroll_delay = TRUE; // now always "on"
+ }
+
+ // make sure that scroll delay value stays inside valid range
+ setup.scroll_delay_value =
+ MIN(MAX(MIN_SCROLL_DELAY, setup.scroll_delay_value), MAX_SCROLL_DELAY);
+}
+
+void LoadSetup_Default(void)
+{
+ char *filename;
+
+ // always start with reliable default values
+ setSetupInfoToDefaults(&setup);
+
+ // 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);
+
+ // try to load setup values from user setup file
+ filename = getSetupFilename();
+
+ LoadSetupFromFilename(filename);
+
+ LoadSetup_SpecialPostProcessing();
+}
+
+void LoadSetup_AutoSetup(void)
+{
+ char *filename = getPath2(getSetupDir(), AUTOSETUP_FILENAME);
+ SetupFileHash *setup_file_hash = NULL;
+
+ // always start with reliable default values
+ setSetupInfoToDefaults_AutoSetup(&setup);
+
+ setup_file_hash = loadSetupFileHash(filename);
+
+ if (setup_file_hash)
+ {
+ decodeSetupFileHash_AutoSetup(setup_file_hash);
+
+ freeSetupFileHash(setup_file_hash);
+ }
+
+ free(filename);
+}
+
+void LoadSetup_ServerSetup(void)
+{
+ char *filename = getPath2(getSetupDir(), SERVERSETUP_FILENAME);
+ SetupFileHash *setup_file_hash = NULL;
+
+ // always start with reliable default values
+ setSetupInfoToDefaults_ServerSetup(&setup);
+
+ setup_file_hash = loadSetupFileHash(filename);
+
+ if (setup_file_hash)
+ {
+ decodeSetupFileHash_ServerSetup(setup_file_hash);
+
+ freeSetupFileHash(setup_file_hash);
+ }
+
+ free(filename);
+
+ if (setup.player_uuid == NULL)
+ {
+ // player UUID does not yet exist in setup file
+ setup.player_uuid = getStringCopy(getUUID());
+ setup.player_version = 2;
+
+ SaveSetup_ServerSetup();
+ }
+}
+
+void LoadSetup_EditorCascade(void)
+{
+ char *filename = getPath2(getSetupDir(), EDITORCASCADE_FILENAME);
+ SetupFileHash *setup_file_hash = NULL;
+
+ // always start with reliable default values
+ setSetupInfoToDefaults_EditorCascade(&setup);
+
+ setup_file_hash = loadSetupFileHash(filename);
+
+ if (setup_file_hash)
+ {
+ decodeSetupFileHash_EditorCascade(setup_file_hash);
+
+ freeSetupFileHash(setup_file_hash);
+ }
+
+ free(filename);
+}
+
+void LoadSetup(void)
+{
+ LoadSetup_Default();
+ LoadSetup_AutoSetup();
+ LoadSetup_ServerSetup();
+ LoadSetup_EditorCascade();
+}
+
+static void addGameControllerMappingToHash(SetupFileHash *mappings_hash,
+ char *mapping_line)
+{
+ char mapping_guid[MAX_LINE_LEN];
+ char *mapping_start, *mapping_end;
+
+ // get GUID from game controller mapping line: copy complete line
+ strncpy(mapping_guid, mapping_line, MAX_LINE_LEN - 1);
+ mapping_guid[MAX_LINE_LEN - 1] = '\0';
+
+ // get GUID from game controller mapping line: cut after GUID part
+ mapping_start = strchr(mapping_guid, ',');
+ if (mapping_start != NULL)
+ *mapping_start = '\0';
+
+ // cut newline from game controller mapping line
+ mapping_end = strchr(mapping_line, '\n');
+ if (mapping_end != NULL)
+ *mapping_end = '\0';
+
+ // add mapping entry to game controller mappings hash
+ setHashEntry(mappings_hash, mapping_guid, mapping_line);
+}
+
+static void LoadSetup_ReadGameControllerMappings(SetupFileHash *mappings_hash,
+ char *filename)
+{
+ FILE *file;
+
+ if (!(file = fopen(filename, MODE_READ)))
+ {
+ Warn("cannot read game controller mappings file '%s'", filename);
+
+ return;
+ }
+
+ while (!feof(file))
+ {
+ char line[MAX_LINE_LEN];
+
+ if (!fgets(line, MAX_LINE_LEN, file))
+ break;
+
+ addGameControllerMappingToHash(mappings_hash, line);
+ }
+
+ fclose(file);
+}
+
+void SaveSetup_Default(void)
+{
+ char *filename = getSetupFilename();
+ FILE *file;
+ int i, pnr;
+
+ InitUserDataDirectory();
+
+ if (!(file = fopen(filename, MODE_WRITE)))
+ {
+ Warn("cannot write setup file '%s'", filename);
+
+ return;
+ }
+
+ fprintFileHeader(file, SETUP_FILENAME);
+
+ for (i = 0; i < ARRAY_SIZE(global_setup_tokens); i++)
+ {
+ // just to make things nicer :)
+ if (global_setup_tokens[i].value == &setup.multiple_users ||
+ global_setup_tokens[i].value == &setup.sound ||
+ global_setup_tokens[i].value == &setup.graphics_set ||
+ global_setup_tokens[i].value == &setup.volume_simple ||
+ global_setup_tokens[i].value == &setup.network_mode ||
+ global_setup_tokens[i].value == &setup.touch.control_type ||
+ global_setup_tokens[i].value == &setup.touch.grid_xsize[0] ||
+ global_setup_tokens[i].value == &setup.touch.grid_xsize[1])
+ fprintf(file, "\n");
+
+ fprintf(file, "%s\n", getSetupLine(global_setup_tokens, "", i));
+ }
+
+ for (i = 0; i < 2; i++)
+ {
+ int grid_xsize = setup.touch.grid_xsize[i];
+ int grid_ysize = setup.touch.grid_ysize[i];
+ int x, y;
+
+ fprintf(file, "\n");
+
+ for (y = 0; y < grid_ysize; y++)
+ {
+ char token_string[MAX_LINE_LEN];
+ char value_string[MAX_LINE_LEN];
+
+ sprintf(token_string, "touch.virtual_buttons.%d.%02d", i, y);
+
+ for (x = 0; x < grid_xsize; x++)
+ {
+ char c = setup.touch.grid_button[i][x][y];
+
+ value_string[x] = (c == CHAR_GRID_BUTTON_NONE ? '.' : c);
+ }
+
+ value_string[grid_xsize] = '\0';
+
+ fprintf(file, "%s\n", getFormattedSetupEntry(token_string, value_string));
+ }
+ }
+
+ fprintf(file, "\n");
+ for (i = 0; i < ARRAY_SIZE(editor_setup_tokens); i++)
+ fprintf(file, "%s\n", getSetupLine(editor_setup_tokens, "", i));
+
+ fprintf(file, "\n");
+ for (i = 0; i < ARRAY_SIZE(shortcut_setup_tokens); i++)
+ fprintf(file, "%s\n", getSetupLine(shortcut_setup_tokens, "", i));
+
+ for (pnr = 0; pnr < MAX_PLAYERS; pnr++)
+ {
+ char prefix[30];
+
+ sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
+ fprintf(file, "\n");
+
+ setup_input = setup.input[pnr];
+ for (i = 0; i < ARRAY_SIZE(player_setup_tokens); i++)
+ fprintf(file, "%s\n", getSetupLine(player_setup_tokens, prefix, i));
+ }
+
+ fprintf(file, "\n");
+ for (i = 0; i < ARRAY_SIZE(system_setup_tokens); i++)
+ fprintf(file, "%s\n", getSetupLine(system_setup_tokens, "", i));
+
+ // (internal setup values not saved to user setup file)
+
+ fprintf(file, "\n");
+ for (i = 0; i < ARRAY_SIZE(debug_setup_tokens); i++)
+ if (!strPrefix(debug_setup_tokens[i].text, "debug.xsn_") ||
+ setup.debug.xsn_mode != AUTO)
+ fprintf(file, "%s\n", getSetupLine(debug_setup_tokens, "", i));
+
+ fprintf(file, "\n");
+ for (i = 0; i < ARRAY_SIZE(options_setup_tokens); i++)
+ fprintf(file, "%s\n", getSetupLine(options_setup_tokens, "", i));
+
+ fclose(file);
+
+ SetFilePermissions(filename, PERMS_PRIVATE);
+}
+
+void SaveSetup_AutoSetup(void)
+{
+ char *filename = getPath2(getSetupDir(), AUTOSETUP_FILENAME);
+ FILE *file;
+ int i;
+
+ InitUserDataDirectory();
+
+ if (!(file = fopen(filename, MODE_WRITE)))
+ {
+ Warn("cannot write auto setup file '%s'", filename);
+
+ free(filename);
+
+ return;
+ }
+
+ fprintFileHeader(file, AUTOSETUP_FILENAME);
+
+ for (i = 0; i < ARRAY_SIZE(auto_setup_tokens); i++)
+ fprintf(file, "%s\n", getSetupLine(auto_setup_tokens, "", i));
+
+ fclose(file);
+
+ SetFilePermissions(filename, PERMS_PRIVATE);
+
+ free(filename);
+}
+
+void SaveSetup_ServerSetup(void)
+{
+ char *filename = getPath2(getSetupDir(), SERVERSETUP_FILENAME);
+ FILE *file;
+ int i;
+
+ InitUserDataDirectory();
+
+ if (!(file = fopen(filename, MODE_WRITE)))
+ {
+ Warn("cannot write server setup file '%s'", filename);
+
+ free(filename);
+
+ return;
+ }
+
+ fprintFileHeader(file, SERVERSETUP_FILENAME);
+
+ for (i = 0; i < ARRAY_SIZE(server_setup_tokens); i++)
+ {
+ // just to make things nicer :)
+ if (server_setup_tokens[i].value == &setup.use_api_server)
+ fprintf(file, "\n");
+
+ fprintf(file, "%s\n", getSetupLine(server_setup_tokens, "", i));
+ }
+
+ fclose(file);
+
+ SetFilePermissions(filename, PERMS_PRIVATE);
+
+ free(filename);
+}
+
+void SaveSetup_EditorCascade(void)
+{
+ char *filename = getPath2(getSetupDir(), EDITORCASCADE_FILENAME);
+ FILE *file;
+ int i;
+
+ InitUserDataDirectory();
+
+ if (!(file = fopen(filename, MODE_WRITE)))
+ {
+ Warn("cannot write editor cascade state file '%s'", filename);
+
+ free(filename);
+
+ return;
+ }
+
+ fprintFileHeader(file, EDITORCASCADE_FILENAME);
+
+ for (i = 0; i < ARRAY_SIZE(editor_cascade_setup_tokens); i++)
+ fprintf(file, "%s\n", getSetupLine(editor_cascade_setup_tokens, "", i));
+
+ fclose(file);
+
+ SetFilePermissions(filename, PERMS_PRIVATE);
+
+ free(filename);
+}
+
+void SaveSetup(void)
+{
+ SaveSetup_Default();
+ SaveSetup_AutoSetup();
+ SaveSetup_ServerSetup();
+ SaveSetup_EditorCascade();
+}
+
+static void SaveSetup_WriteGameControllerMappings(SetupFileHash *mappings_hash,
+ char *filename)
+{
+ FILE *file;
+
+ if (!(file = fopen(filename, MODE_WRITE)))
+ {
+ Warn("cannot write game controller mappings file '%s'", filename);
+
+ return;
+ }
+
+ BEGIN_HASH_ITERATION(mappings_hash, itr)
+ {
+ fprintf(file, "%s\n", HASH_ITERATION_VALUE(itr));
+ }
+ END_HASH_ITERATION(mappings_hash, itr)
+
+ fclose(file);
+}
+
+void SaveSetup_AddGameControllerMapping(char *mapping)
+{
+ char *filename = getPath2(getSetupDir(), GAMECONTROLLER_BASENAME);
+ SetupFileHash *mappings_hash = newSetupFileHash();
+
+ InitUserDataDirectory();
+
+ // load existing personal game controller mappings
+ LoadSetup_ReadGameControllerMappings(mappings_hash, filename);
+
+ // add new mapping to personal game controller mappings
+ addGameControllerMappingToHash(mappings_hash, mapping);
+
+ // save updated personal game controller mappings
+ SaveSetup_WriteGameControllerMappings(mappings_hash, filename);
+
+ freeSetupFileHash(mappings_hash);
+ free(filename);
+}
+
+void LoadCustomElementDescriptions(void)
+{
+ char *filename = getCustomArtworkConfigFilename(ARTWORK_TYPE_GRAPHICS);
+ SetupFileHash *setup_file_hash;
+ int i;
+
+ for (i = 0; i < NUM_FILE_ELEMENTS; i++)
+ {
+ if (element_info[i].custom_description != NULL)
+ {
+ free(element_info[i].custom_description);
+ element_info[i].custom_description = NULL;
+ }
+ }
+
+ if ((setup_file_hash = loadSetupFileHash(filename)) == NULL)
+ return;
+
+ for (i = 0; i < NUM_FILE_ELEMENTS; i++)
+ {
+ char *token = getStringCat2(element_info[i].token_name, ".name");
+ char *value = getHashEntry(setup_file_hash, token);
+
+ if (value != NULL)
+ element_info[i].custom_description = getStringCopy(value);
+
+ free(token);
+ }
+
+ freeSetupFileHash(setup_file_hash);
+}
+
+static int getElementFromToken(char *token)
+{
+ char *value = getHashEntry(element_token_hash, token);
+
+ if (value != NULL)
+ return atoi(value);
+
+ Warn("unknown element token '%s'", token);
+
+ return EL_UNDEFINED;
+}
+
+void FreeGlobalAnimEventInfo(void)
+{
+ struct GlobalAnimEventInfo *gaei = &global_anim_event_info;
+
+ if (gaei->event_list == NULL)
+ return;
+
+ int i;
+
+ for (i = 0; i < gaei->num_event_lists; i++)
+ {
+ checked_free(gaei->event_list[i]->event_value);
+ checked_free(gaei->event_list[i]);
+ }
+
+ checked_free(gaei->event_list);
+
+ gaei->event_list = NULL;
+ gaei->num_event_lists = 0;
+}
+
+static int AddGlobalAnimEventList(void)
+{
+ struct GlobalAnimEventInfo *gaei = &global_anim_event_info;
+ int list_pos = gaei->num_event_lists++;
+
+ gaei->event_list = checked_realloc(gaei->event_list, gaei->num_event_lists *
+ sizeof(struct GlobalAnimEventListInfo *));
+
+ gaei->event_list[list_pos] =
+ checked_calloc(sizeof(struct GlobalAnimEventListInfo));
+
+ struct GlobalAnimEventListInfo *gaeli = gaei->event_list[list_pos];
+
+ gaeli->event_value = NULL;
+ gaeli->num_event_values = 0;
+
+ return list_pos;
+}
+
+static int AddGlobalAnimEventValue(int list_pos, int event_value)
+{
+ // do not add empty global animation events
+ if (event_value == ANIM_EVENT_NONE)
+ return list_pos;
+
+ // if list position is undefined, create new list
+ if (list_pos == ANIM_EVENT_UNDEFINED)
+ list_pos = AddGlobalAnimEventList();
+
+ struct GlobalAnimEventInfo *gaei = &global_anim_event_info;
+ struct GlobalAnimEventListInfo *gaeli = gaei->event_list[list_pos];
+ int value_pos = gaeli->num_event_values++;
+
+ gaeli->event_value = checked_realloc(gaeli->event_value,
+ gaeli->num_event_values * sizeof(int *));
+
+ gaeli->event_value[value_pos] = event_value;
+
+ return list_pos;
+}
+
+int GetGlobalAnimEventValue(int list_pos, int value_pos)
+{
+ if (list_pos == ANIM_EVENT_UNDEFINED)
+ return ANIM_EVENT_NONE;
+
+ struct GlobalAnimEventInfo *gaei = &global_anim_event_info;
+ struct GlobalAnimEventListInfo *gaeli = gaei->event_list[list_pos];
+
+ return gaeli->event_value[value_pos];
+}
+
+int GetGlobalAnimEventValueCount(int list_pos)
+{
+ if (list_pos == ANIM_EVENT_UNDEFINED)
+ return 0;
+
+ struct GlobalAnimEventInfo *gaei = &global_anim_event_info;
+ struct GlobalAnimEventListInfo *gaeli = gaei->event_list[list_pos];
+
+ return gaeli->num_event_values;
+}
+
+// This function checks if a string <s> of the format "string1, string2, ..."
+// exactly contains a string <s_contained>.
+
+static boolean string_has_parameter(char *s, char *s_contained)
+{
+ char *substring;
+
+ if (s == NULL || s_contained == NULL)
+ return FALSE;
+
+ if (strlen(s_contained) > strlen(s))
+ return FALSE;
+
+ if (strncmp(s, s_contained, strlen(s_contained)) == 0)
+ {
+ char next_char = s[strlen(s_contained)];
+
+ // check if next character is delimiter or whitespace
+ if (next_char == ',' || next_char == '\0' ||
+ next_char == ' ' || next_char == '\t')
+ return TRUE;
+ }
+
+ // check if string contains another parameter string after a comma
+ substring = strchr(s, ',');
+ if (substring == NULL) // string does not contain a comma
+ return FALSE;
+
+ // advance string pointer to next character after the comma
+ substring++;
+
+ // skip potential whitespaces after the comma
+ while (*substring == ' ' || *substring == '\t')
+ substring++;
+
+ 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[] =
+ {
+ ANIM_EVENT_CLICK,
+ ANIM_EVENT_INIT,
+ ANIM_EVENT_START,
+ ANIM_EVENT_END,
+ ANIM_EVENT_POST
+ };
+ char *pattern_1[] =
+ {
+ "click:anim_",
+ "init:anim_",
+ "start:anim_",
+ "end:anim_",
+ "post:anim_"
+ };
+ char *pattern_2 = ".part_";
+ char *matching_char = NULL;
+ char *s_ptr = s;
+ int pattern_1_len = 0;
+ 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]);
+ pattern_1_len = strlen(pattern_1[i]);
+ result = event_value[i];
+
+ if (matching_char != NULL)
+ break;
+ }
+
+ if (matching_char == NULL)
+ return ANIM_EVENT_NONE;
+
+ s_ptr = matching_char + pattern_1_len;
+
+ // check for main animation number ("anim_X" or "anim_XX")
+ if (*s_ptr >= '0' && *s_ptr <= '9')
+ {
+ int gic_anim_nr = (*s_ptr++ - '0');
+
+ if (*s_ptr >= '0' && *s_ptr <= '9')
+ gic_anim_nr = 10 * gic_anim_nr + (*s_ptr++ - '0');
+
+ if (gic_anim_nr < 1 || gic_anim_nr > MAX_GLOBAL_ANIMS)
+ return ANIM_EVENT_NONE;
+
+ result |= gic_anim_nr << ANIM_EVENT_ANIM_BIT;
+ }
+ else
+ {
+ // invalid main animation number specified
+
+ return ANIM_EVENT_NONE;
+ }
+
+ // check for animation part number ("part_X" or "part_XX") (optional)
+ if (strPrefix(s_ptr, pattern_2))
+ {
+ s_ptr += strlen(pattern_2);
+
+ if (*s_ptr >= '0' && *s_ptr <= '9')
+ {
+ int gic_part_nr = (*s_ptr++ - '0');
+
+ if (*s_ptr >= '0' && *s_ptr <= '9')
+ gic_part_nr = 10 * gic_part_nr + (*s_ptr++ - '0');
+
+ if (gic_part_nr < 1 || gic_part_nr > MAX_GLOBAL_ANIM_PARTS)
+ return ANIM_EVENT_NONE;
+
+ result |= gic_part_nr << ANIM_EVENT_PART_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_values(char *s)
+{
+ int list_pos = ANIM_EVENT_UNDEFINED;
+ int event_value = ANIM_EVENT_DEFAULT;
+
+ if (string_has_parameter(s, "any"))
+ event_value |= ANIM_EVENT_ANY;
+
+ if (string_has_parameter(s, "click:self") ||
+ string_has_parameter(s, "click") ||
+ string_has_parameter(s, "self"))
+ event_value |= ANIM_EVENT_SELF;
+
+ if (string_has_parameter(s, "unclick:any"))
+ event_value |= ANIM_EVENT_UNCLICK_ANY;
+
+ // if animation event found, add it to global animation event list
+ if (event_value != ANIM_EVENT_NONE)
+ list_pos = AddGlobalAnimEventValue(list_pos, event_value);
+
+ while (s != NULL)
+ {
+ // add optional "click:anim_X" or "click:anim_X.part_X" parameter
+ event_value = get_anim_parameter_value(s);
+
+ // 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, ',');
+ }
+
+ return list_pos;
+}
+
+static int get_anim_action_parameter_value(char *token)
+{
+ // check most common default case first to massively speed things up
+ if (strEqual(token, ARG_UNDEFINED))
+ return ANIM_EVENT_ACTION_NONE;
+
+ int result = getImageIDFromToken(token);
+
+ if (result == -1)
+ {
+ char *gfx_token = getStringCat2("gfx.", token);
+
+ result = getImageIDFromToken(gfx_token);
+
+ checked_free(gfx_token);
+ }
+
+ if (result == -1)
+ {
+ Key key = getKeyFromX11KeyName(token);
+
+ if (key != KSYM_UNDEFINED)
+ result = -(int)key;
+ }
+
+ if (result == -1)
+ {
+ if (isURL(token))
+ {
+ result = get_hash_from_string(token); // unsigned int => int
+ result = ABS(result); // may be negative now
+ result += (result < MAX_IMAGE_FILES ? MAX_IMAGE_FILES : 0);
+
+ setHashEntry(anim_url_hash, int2str(result, 0), token);
+ }
+ }
+
+ if (result == -1)
+ result = ANIM_EVENT_ACTION_NONE;
+
+ return result;
+}
+
+int get_parameter_value(char *value_raw, char *suffix, int type)
+{
+ char *value = getStringToLower(value_raw);
+ int result = 0; // probably a save default value
+
+ if (strEqual(suffix, ".direction"))
+ {
+ result = (strEqual(value, "left") ? MV_LEFT :
+ strEqual(value, "right") ? MV_RIGHT :
+ strEqual(value, "up") ? MV_UP :
+ strEqual(value, "down") ? MV_DOWN : MV_NONE);
+ }
+ else if (strEqual(suffix, ".position"))
+ {
+ result = (strEqual(value, "left") ? POS_LEFT :
+ strEqual(value, "right") ? POS_RIGHT :
+ strEqual(value, "top") ? POS_TOP :
+ strEqual(value, "upper") ? POS_UPPER :
+ strEqual(value, "middle") ? POS_MIDDLE :
+ strEqual(value, "lower") ? POS_LOWER :
+ strEqual(value, "bottom") ? POS_BOTTOM :
+ strEqual(value, "any") ? POS_ANY :
+ strEqual(value, "ce") ? POS_CE :
+ strEqual(value, "ce_trigger") ? POS_CE_TRIGGER :
+ strEqual(value, "last") ? POS_LAST : POS_UNDEFINED);
+ }
+ else if (strEqual(suffix, ".align"))
+ {
+ result = (strEqual(value, "left") ? ALIGN_LEFT :
+ strEqual(value, "right") ? ALIGN_RIGHT :
+ strEqual(value, "center") ? ALIGN_CENTER :
+ strEqual(value, "middle") ? ALIGN_CENTER : ALIGN_DEFAULT);
+ }
+ else if (strEqual(suffix, ".valign"))
+ {
+ result = (strEqual(value, "top") ? VALIGN_TOP :
+ strEqual(value, "bottom") ? VALIGN_BOTTOM :
+ strEqual(value, "middle") ? VALIGN_MIDDLE :
+ strEqual(value, "center") ? VALIGN_MIDDLE : VALIGN_DEFAULT);
+ }
+ else if (strEqual(suffix, ".anim_mode"))
+ {
+ result = (string_has_parameter(value, "none") ? ANIM_NONE :
+ string_has_parameter(value, "loop") ? ANIM_LOOP :
+ string_has_parameter(value, "linear") ? ANIM_LINEAR :
+ string_has_parameter(value, "pingpong") ? ANIM_PINGPONG :
+ string_has_parameter(value, "pingpong2") ? ANIM_PINGPONG2 :
+ string_has_parameter(value, "random") ? ANIM_RANDOM :
+ string_has_parameter(value, "random_static") ? ANIM_RANDOM_STATIC :
+ string_has_parameter(value, "ce_value") ? ANIM_CE_VALUE :
+ string_has_parameter(value, "ce_score") ? ANIM_CE_SCORE :
+ string_has_parameter(value, "ce_delay") ? ANIM_CE_DELAY :
+ string_has_parameter(value, "horizontal") ? ANIM_HORIZONTAL :
+ string_has_parameter(value, "vertical") ? ANIM_VERTICAL :
+ string_has_parameter(value, "centered") ? ANIM_CENTERED :
+ string_has_parameter(value, "all") ? ANIM_ALL :
+ string_has_parameter(value, "tiled") ? ANIM_TILED :
+ string_has_parameter(value, "level_nr") ? ANIM_LEVEL_NR :
+ ANIM_DEFAULT);
+
+ if (string_has_parameter(value, "once"))
+ result |= ANIM_ONCE;
+
+ if (string_has_parameter(value, "reverse"))
+ result |= ANIM_REVERSE;
+
+ if (string_has_parameter(value, "opaque_player"))
+ result |= ANIM_OPAQUE_PLAYER;
+
+ if (string_has_parameter(value, "static_panel"))
+ result |= ANIM_STATIC_PANEL;
+ }
+ else if (strEqual(suffix, ".init_event") ||
+ strEqual(suffix, ".anim_event"))
+ {
+ result = get_anim_parameter_values(value);
+ }
+ else if (strEqual(suffix, ".init_delay_action") ||
+ strEqual(suffix, ".anim_delay_action") ||
+ strEqual(suffix, ".post_delay_action") ||
+ strEqual(suffix, ".init_event_action") ||
+ strEqual(suffix, ".anim_event_action"))
+ {
+ result = get_anim_action_parameter_value(value_raw);
+ }
+ else if (strEqual(suffix, ".class"))
+ {
+ result = (strEqual(value, ARG_UNDEFINED) ? ARG_UNDEFINED_VALUE :
+ get_hash_from_string(value));
+ }
+ else if (strEqual(suffix, ".style"))
+ {
+ result = STYLE_DEFAULT;
+
+ if (string_has_parameter(value, "accurate_borders"))
+ result |= STYLE_ACCURATE_BORDERS;
+
+ if (string_has_parameter(value, "inner_corners"))
+ result |= STYLE_INNER_CORNERS;
+
+ if (string_has_parameter(value, "reverse"))
+ result |= STYLE_REVERSE;
+
+ if (string_has_parameter(value, "leftmost_position"))
+ result |= STYLE_LEFTMOST_POSITION;
+
+ if (string_has_parameter(value, "block_clicks"))
+ result |= STYLE_BLOCK;
+
+ if (string_has_parameter(value, "passthrough_clicks"))
+ result |= STYLE_PASSTHROUGH;
+
+ if (string_has_parameter(value, "multiple_actions"))
+ result |= STYLE_MULTIPLE_ACTIONS;
+
+ if (string_has_parameter(value, "consume_ce_event"))
+ result |= STYLE_CONSUME_CE_EVENT;
+ }
+ else if (strEqual(suffix, ".fade_mode"))
+ {
+ result = (string_has_parameter(value, "none") ? FADE_MODE_NONE :
+ string_has_parameter(value, "fade") ? FADE_MODE_FADE :
+ string_has_parameter(value, "fade_in") ? FADE_MODE_FADE_IN :
+ string_has_parameter(value, "fade_out") ? FADE_MODE_FADE_OUT :
+ string_has_parameter(value, "crossfade") ? FADE_MODE_CROSSFADE :
+ string_has_parameter(value, "melt") ? FADE_MODE_MELT :
+ string_has_parameter(value, "curtain") ? FADE_MODE_CURTAIN :
+ FADE_MODE_DEFAULT);