+ old_score_file_format = TRUE;
+ }
+
+ if (old_score_file_format)
+ {
+ // score files from versions before 4.2.4.0 without chunk structure
+ LoadScore_OLD(nr);
+ }
+ else
+ {
+ static struct
+ {
+ char *name;
+ int size;
+ int (*loader)(File *, int, struct ScoreInfo *);
+ }
+ chunk_info[] =
+ {
+ { "VERS", SCORE_CHUNK_VERS_SIZE, LoadScore_VERS },
+ { "INFO", -1, LoadScore_INFO },
+ { "NAME", -1, LoadScore_NAME },
+ { "SCOR", -1, LoadScore_SCOR },
+
+ { NULL, 0, NULL }
+ };
+
+ while (getFileChunkBE(file, chunk_name, &chunk_size))
+ {
+ int i = 0;
+
+ while (chunk_info[i].name != NULL &&
+ !strEqual(chunk_name, chunk_info[i].name))
+ i++;
+
+ if (chunk_info[i].name == NULL)
+ {
+ Warn("unknown chunk '%s' in score file '%s'",
+ chunk_name, filename);
+
+ ReadUnusedBytesFromFile(file, chunk_size);
+ }
+ else if (chunk_info[i].size != -1 &&
+ chunk_info[i].size != chunk_size)
+ {
+ Warn("wrong size (%d) of chunk '%s' in score file '%s'",
+ chunk_size, chunk_name, filename);
+
+ ReadUnusedBytesFromFile(file, chunk_size);
+ }
+ else
+ {
+ // call function to load this score chunk
+ int chunk_size_expected =
+ (chunk_info[i].loader)(file, chunk_size, &scores);
+
+ // 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
+ if (chunk_size_expected != chunk_size)
+ {
+ Warn("wrong size (%d) of chunk '%s' in score file '%s'",
+ chunk_size, chunk_name, filename);
+ }
+ }
+ }
+ }
+
+ closeFile(file);
+}
+
+#if ENABLE_HISTORIC_CHUNKS
+void SaveScore_OLD(int nr)
+{
+ int i;
+ int permissions = (program.global_scores ? PERMS_PUBLIC : PERMS_PRIVATE);
+ char *filename = getScoreFilename(nr);
+ FILE *file;
+
+ // used instead of "leveldir_current->subdir" (for network games)
+ InitScoreDirectory(levelset.identifier);
+
+ if (!(file = fopen(filename, MODE_WRITE)))
+ {
+ Warn("cannot save score for level %d", nr);
+
+ return;
+ }
+
+ fprintf(file, "%s\n\n", SCORE_COOKIE);
+
+ for (i = 0; i < MAX_SCORE_ENTRIES; i++)
+ fprintf(file, "%d %s\n", scores.entry[i].score, scores.entry[i].name);
+
+ fclose(file);
+
+ SetFilePermissions(filename, permissions);
+}
+#endif
+
+static void SaveScore_VERS(FILE *file, struct ScoreInfo *scores)
+{
+ putFileVersion(file, scores->file_version);
+ putFileVersion(file, scores->game_version);
+}
+
+static void SaveScore_INFO(FILE *file, struct ScoreInfo *scores)
+{
+ int level_identifier_size = strlen(scores->level_identifier) + 1;
+ int i;
+
+ putFile16BitBE(file, level_identifier_size);
+
+ for (i = 0; i < level_identifier_size; i++)
+ putFile8Bit(file, scores->level_identifier[i]);
+
+ putFile16BitBE(file, scores->level_nr);
+ putFile16BitBE(file, scores->num_entries);
+}
+
+static void SaveScore_NAME(FILE *file, struct ScoreInfo *scores)
+{
+ int i, j;
+
+ for (i = 0; i < scores->num_entries; i++)
+ {
+ int name_size = strlen(scores->entry[i].name);
+
+ for (j = 0; j < MAX_PLAYER_NAME_LEN; j++)
+ putFile8Bit(file, (j < name_size ? scores->entry[i].name[j] : 0));
+ }
+}
+
+static void SaveScore_SCOR(FILE *file, struct ScoreInfo *scores)
+{
+ int i;
+
+ for (i = 0; i < scores->num_entries; i++)
+ putFile16BitBE(file, scores->entry[i].score);
+}
+
+static void SaveScoreToFilename(char *filename)
+{
+ FILE *file;
+ int permissions = (program.global_scores ? PERMS_PUBLIC : PERMS_PRIVATE);
+ int info_chunk_size;
+ int name_chunk_size;
+ int scor_chunk_size;
+
+ if (!(file = fopen(filename, MODE_WRITE)))
+ {
+ Warn("cannot save score file '%s'", filename);
+
+ return;
+ }
+
+ info_chunk_size = 2 + (strlen(scores.level_identifier) + 1) + 2 + 2;
+ name_chunk_size = scores.num_entries * MAX_PLAYER_NAME_LEN;
+ scor_chunk_size = scores.num_entries * 2;
+
+ putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED);
+ putFileChunkBE(file, "SCOR", CHUNK_SIZE_NONE);
+
+ putFileChunkBE(file, "VERS", SCORE_CHUNK_VERS_SIZE);
+ SaveScore_VERS(file, &scores);
+
+ putFileChunkBE(file, "INFO", info_chunk_size);
+ SaveScore_INFO(file, &scores);
+
+ putFileChunkBE(file, "NAME", name_chunk_size);
+ SaveScore_NAME(file, &scores);
+
+ putFileChunkBE(file, "SCOR", scor_chunk_size);
+ SaveScore_SCOR(file, &scores);
+
+ fclose(file);
+
+ SetFilePermissions(filename, permissions);
+}
+
+void SaveScore(int nr)
+{
+ char *filename = getScoreFilename(nr);
+ int i;
+
+ // used instead of "leveldir_current->subdir" (for network games)
+ InitScoreDirectory(levelset.identifier);
+
+ scores.file_version = FILE_VERSION_ACTUAL;
+ scores.game_version = GAME_VERSION_ACTUAL;
+
+ strncpy(scores.level_identifier, levelset.identifier, MAX_FILENAME_LEN);
+ scores.level_identifier[MAX_FILENAME_LEN] = '\0';
+ scores.level_nr = level_nr;
+
+ for (i = 0; i < MAX_SCORE_ENTRIES; i++)
+ if (scores.entry[i].score == 0 &&
+ strEqual(scores.entry[i].name, EMPTY_PLAYER_NAME))
+ break;
+
+ scores.num_entries = i;
+
+ if (scores.num_entries == 0)
+ return;
+
+ SaveScoreToFilename(filename);
+}
+
+
+// ============================================================================
+// 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.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.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.sp_show_border_elements, "sp_show_border_elements"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.small_game_graphics, "small_game_graphics"
+ },
+ {
+ TYPE_SWITCH,
+ &setup.show_snapshot_buttons, "show_snapshot_buttons"
+ },
+ {
+ 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"
+ },
+};
+
+static struct TokenInfo auto_setup_tokens[] =
+{
+ {
+ TYPE_INTEGER,
+ &setup.auto_setup.editor_zoom_tilesize, "editor.zoom_tilesize"
+ },
+};
+
+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_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_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.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[] =