+ /* 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)
+ {
+ Error(ERR_WARN, "wrong size (%d) of chunk '%s' in tape file '%s'",
+ chunk_size, chunk_name, filename);
+ }
+ }
+ }
+ }
+
+ fclose(file);
+
+ tape.length_seconds = GetTapeLength();
+
+#if 0
+ printf("::: tape game version: %d\n", tape.game_version);
+ printf("::: tape engine version: %d\n", tape.engine_version);
+#endif
+}
+
+void LoadTape(int nr)
+{
+ char *filename = getTapeFilename(nr);
+
+ LoadTapeFromFilename(filename);
+}
+
+void LoadSolutionTape(int nr)
+{
+ char *filename = getSolutionTapeFilename(nr);
+
+ LoadTapeFromFilename(filename);
+}
+
+static void SaveTape_VERS(FILE *file, struct TapeInfo *tape)
+{
+ putFileVersion(file, tape->file_version);
+ putFileVersion(file, tape->game_version);
+}
+
+static void SaveTape_HEAD(FILE *file, struct TapeInfo *tape)
+{
+ int i;
+ byte store_participating_players = 0;
+
+ /* set bits for participating players for compact storage */
+ for (i = 0; i < MAX_PLAYERS; i++)
+ if (tape->player_participates[i])
+ store_participating_players |= (1 << i);
+
+ putFile32BitBE(file, tape->random_seed);
+ putFile32BitBE(file, tape->date);
+ putFile32BitBE(file, tape->length);
+
+ putFile8Bit(file, store_participating_players);
+
+ /* unused bytes not at the end here for 4-byte alignment of engine_version */
+ WriteUnusedBytesToFile(file, TAPE_HEADER_UNUSED);
+
+ putFileVersion(file, tape->engine_version);
+}
+
+static void SaveTape_INFO(FILE *file, struct TapeInfo *tape)
+{
+ int level_identifier_size = strlen(tape->level_identifier) + 1;
+ int i;
+
+ putFile16BitBE(file, level_identifier_size);
+
+ for (i = 0; i < level_identifier_size; i++)
+ putFile8Bit(file, tape->level_identifier[i]);
+
+ putFile16BitBE(file, tape->level_nr);
+}
+
+static void SaveTape_BODY(FILE *file, struct TapeInfo *tape)
+{
+ int i, j;
+
+ for (i = 0; i < tape->length; i++)
+ {
+ for (j = 0; j < MAX_PLAYERS; j++)
+ if (tape->player_participates[j])
+ putFile8Bit(file, tape->pos[i].action[j]);
+
+ putFile8Bit(file, tape->pos[i].delay);
+ }
+}
+
+void SaveTape(int nr)
+{
+ char *filename = getTapeFilename(nr);
+ FILE *file;
+ boolean new_tape = TRUE;
+ int num_participating_players = 0;
+ int info_chunk_size;
+ int body_chunk_size;
+ int i;
+
+ InitTapeDirectory(leveldir_current->subdir);
+
+ /* if a tape still exists, ask to overwrite it */
+ if (fileExists(filename))
+ {
+ new_tape = FALSE;
+ if (!Request("Replace old tape ?", REQ_ASK))
+ return;
+ }
+
+ if (!(file = fopen(filename, MODE_WRITE)))
+ {
+ Error(ERR_WARN, "cannot save level recording file '%s'", filename);
+ return;
+ }
+
+ tape.file_version = FILE_VERSION_ACTUAL;
+ tape.game_version = GAME_VERSION_ACTUAL;
+
+ /* count number of participating players */
+ for (i = 0; i < MAX_PLAYERS; i++)
+ if (tape.player_participates[i])
+ num_participating_players++;
+
+ info_chunk_size = 2 + (strlen(tape.level_identifier) + 1) + 2;
+ body_chunk_size = (num_participating_players + 1) * tape.length;
+
+ putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED);
+ putFileChunkBE(file, "TAPE", CHUNK_SIZE_NONE);
+
+ putFileChunkBE(file, "VERS", FILE_VERS_CHUNK_SIZE);
+ SaveTape_VERS(file, &tape);
+
+ putFileChunkBE(file, "HEAD", TAPE_HEADER_SIZE);
+ SaveTape_HEAD(file, &tape);
+
+ putFileChunkBE(file, "INFO", info_chunk_size);
+ SaveTape_INFO(file, &tape);
+
+ putFileChunkBE(file, "BODY", body_chunk_size);
+ SaveTape_BODY(file, &tape);
+
+ fclose(file);
+
+ SetFilePermissions(filename, PERMS_PRIVATE);
+
+ tape.changed = FALSE;
+
+ if (new_tape)
+ Request("Tape saved !", REQ_CONFIRM);
+}
+
+void DumpTape(struct TapeInfo *tape)
+{
+ int i, j;
+
+#if 1
+ if (tape->no_valid_file)
+ {
+ Error(ERR_WARN, "cannot dump -- no valid tape file found");
+
+ return;
+ }
+#else
+ if (TAPE_IS_EMPTY(*tape))
+ {
+ Error(ERR_WARN, "no tape available for level %d", tape->level_nr);
+
+ return;
+ }
+#endif
+
+ printf_line("-", 79);
+ printf("Tape of Level %03d (file version %08d, game version %08d)\n",
+ tape->level_nr, tape->file_version, tape->game_version);
+ printf(" (effective engine version %08d)\n",
+ tape->engine_version);
+ printf("Level series identifier: '%s'\n", tape->level_identifier);
+ printf_line("-", 79);
+
+ for (i = 0; i < tape->length; i++)
+ {
+ if (i >= MAX_TAPE_LEN)
+ break;
+
+ printf("%03d: ", i);
+
+ for (j = 0; j < MAX_PLAYERS; j++)
+ {
+ if (tape->player_participates[j])
+ {
+ int action = tape->pos[i].action[j];
+
+ printf("%d:%02x ", j, action);
+ printf("[%c%c%c%c|%c%c] - ",
+ (action & JOY_LEFT ? '<' : ' '),
+ (action & JOY_RIGHT ? '>' : ' '),
+ (action & JOY_UP ? '^' : ' '),
+ (action & JOY_DOWN ? 'v' : ' '),
+ (action & JOY_BUTTON_1 ? '1' : ' '),
+ (action & JOY_BUTTON_2 ? '2' : ' '));
+ }
+ }
+
+ printf("(%03d)\n", tape->pos[i].delay);
+ }
+
+ printf_line("-", 79);
+}
+
+
+/* ========================================================================= */
+/* score file functions */
+/* ========================================================================= */
+
+void LoadScore(int nr)
+{
+ int i;
+ char *filename = getScoreFilename(nr);
+ char cookie[MAX_LINE_LEN];
+ char line[MAX_LINE_LEN];
+ char *line_ptr;
+ FILE *file;
+
+ /* always start with reliable default values */
+ for (i = 0; i < MAX_SCORE_ENTRIES; i++)
+ {
+ strcpy(highscore[i].Name, EMPTY_PLAYER_NAME);
+ highscore[i].Score = 0;
+ }
+
+ if (!(file = fopen(filename, MODE_READ)))
+ return;
+
+ /* check file identifier */
+ fgets(cookie, MAX_LINE_LEN, file);
+ if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
+ cookie[strlen(cookie) - 1] = '\0';
+
+ if (!checkCookieString(cookie, SCORE_COOKIE))
+ {
+ Error(ERR_WARN, "unknown format of score file '%s'", filename);
+ fclose(file);
+ return;
+ }
+
+ for (i = 0; i < MAX_SCORE_ENTRIES; i++)
+ {
+ fscanf(file, "%d", &highscore[i].Score);
+ fgets(line, MAX_LINE_LEN, file);
+
+ if (line[strlen(line) - 1] == '\n')
+ line[strlen(line) - 1] = '\0';
+
+ for (line_ptr = line; *line_ptr; line_ptr++)
+ {
+ if (*line_ptr != ' ' && *line_ptr != '\t' && *line_ptr != '\0')
+ {
+ strncpy(highscore[i].Name, line_ptr, MAX_PLAYER_NAME_LEN);
+ highscore[i].Name[MAX_PLAYER_NAME_LEN] = '\0';
+ break;
+ }
+ }
+ }
+
+ fclose(file);
+}
+
+void SaveScore(int nr)
+{
+ int i;
+ char *filename = getScoreFilename(nr);
+ FILE *file;
+
+ InitScoreDirectory(leveldir_current->subdir);
+
+ if (!(file = fopen(filename, MODE_WRITE)))
+ {
+ Error(ERR_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", highscore[i].Score, highscore[i].Name);
+
+ fclose(file);
+
+ SetFilePermissions(filename, PERMS_PUBLIC);
+}
+
+
+/* ========================================================================= */
+/* setup file functions */
+/* ========================================================================= */
+
+#define TOKEN_STR_PLAYER_PREFIX "player_"
+
+/* global setup */
+#define SETUP_TOKEN_PLAYER_NAME 0
+#define SETUP_TOKEN_SOUND 1
+#define SETUP_TOKEN_SOUND_LOOPS 2
+#define SETUP_TOKEN_SOUND_MUSIC 3
+#define SETUP_TOKEN_SOUND_SIMPLE 4
+#define SETUP_TOKEN_TOONS 5
+#define SETUP_TOKEN_SCROLL_DELAY 6
+#define SETUP_TOKEN_SOFT_SCROLLING 7
+#define SETUP_TOKEN_FADING 8
+#define SETUP_TOKEN_AUTORECORD 9
+#define SETUP_TOKEN_QUICK_DOORS 10
+#define SETUP_TOKEN_TEAM_MODE 11
+#define SETUP_TOKEN_HANDICAP 12
+#define SETUP_TOKEN_SKIP_LEVELS 13
+#define SETUP_TOKEN_TIME_LIMIT 14
+#define SETUP_TOKEN_FULLSCREEN 15
+#define SETUP_TOKEN_ASK_ON_ESCAPE 16
+#define SETUP_TOKEN_GRAPHICS_SET 17
+#define SETUP_TOKEN_SOUNDS_SET 18
+#define SETUP_TOKEN_MUSIC_SET 19
+#define SETUP_TOKEN_OVERRIDE_LEVEL_GRAPHICS 20
+#define SETUP_TOKEN_OVERRIDE_LEVEL_SOUNDS 21
+#define SETUP_TOKEN_OVERRIDE_LEVEL_MUSIC 22
+
+#define NUM_GLOBAL_SETUP_TOKENS 23
+
+/* editor setup */
+#define SETUP_TOKEN_EDITOR_EL_BOULDERDASH 0
+#define SETUP_TOKEN_EDITOR_EL_EMERALD_MINE 1
+#define SETUP_TOKEN_EDITOR_EL_EMERALD_MINE_CLUB 2
+#define SETUP_TOKEN_EDITOR_EL_MORE 3
+#define SETUP_TOKEN_EDITOR_EL_SOKOBAN 4
+#define SETUP_TOKEN_EDITOR_EL_SUPAPLEX 5
+#define SETUP_TOKEN_EDITOR_EL_DIAMOND_CAVES 6
+#define SETUP_TOKEN_EDITOR_EL_DX_BOULDERDASH 7
+#define SETUP_TOKEN_EDITOR_EL_CHARS 8
+#define SETUP_TOKEN_EDITOR_EL_CUSTOM 9
+#define SETUP_TOKEN_EDITOR_EL_CUSTOM_MORE 10
+#define SETUP_TOKEN_EDITOR_EL_HEADLINES 11
+#define SETUP_TOKEN_EDITOR_EL_USER_DEFINED 12
+
+#define NUM_EDITOR_SETUP_TOKENS 13
+
+/* shortcut setup */
+#define SETUP_TOKEN_SHORTCUT_SAVE_GAME 0
+#define SETUP_TOKEN_SHORTCUT_LOAD_GAME 1
+#define SETUP_TOKEN_SHORTCUT_TOGGLE_PAUSE 2
+
+#define NUM_SHORTCUT_SETUP_TOKENS 3
+
+/* player setup */
+#define SETUP_TOKEN_PLAYER_USE_JOYSTICK 0
+#define SETUP_TOKEN_PLAYER_JOY_DEVICE_NAME 1
+#define SETUP_TOKEN_PLAYER_JOY_XLEFT 2
+#define SETUP_TOKEN_PLAYER_JOY_XMIDDLE 3
+#define SETUP_TOKEN_PLAYER_JOY_XRIGHT 4
+#define SETUP_TOKEN_PLAYER_JOY_YUPPER 5
+#define SETUP_TOKEN_PLAYER_JOY_YMIDDLE 6
+#define SETUP_TOKEN_PLAYER_JOY_YLOWER 7
+#define SETUP_TOKEN_PLAYER_JOY_SNAP 8
+#define SETUP_TOKEN_PLAYER_JOY_DROP 9
+#define SETUP_TOKEN_PLAYER_KEY_LEFT 10
+#define SETUP_TOKEN_PLAYER_KEY_RIGHT 11
+#define SETUP_TOKEN_PLAYER_KEY_UP 12
+#define SETUP_TOKEN_PLAYER_KEY_DOWN 13
+#define SETUP_TOKEN_PLAYER_KEY_SNAP 14
+#define SETUP_TOKEN_PLAYER_KEY_DROP 15
+
+#define NUM_PLAYER_SETUP_TOKENS 16
+
+/* system setup */
+#define SETUP_TOKEN_SYSTEM_SDL_AUDIODRIVER 0
+#define SETUP_TOKEN_SYSTEM_AUDIO_FRAGMENT_SIZE 1
+
+#define NUM_SYSTEM_SETUP_TOKENS 2
+
+/* options setup */
+#define SETUP_TOKEN_OPTIONS_VERBOSE 0
+
+#define NUM_OPTIONS_SETUP_TOKENS 1
+
+
+static struct SetupInfo si;
+static struct SetupEditorInfo sei;
+static struct SetupShortcutInfo ssi;
+static struct SetupInputInfo sii;
+static struct SetupSystemInfo syi;
+static struct OptionInfo soi;
+
+static struct TokenInfo global_setup_tokens[] =
+{
+ { TYPE_STRING, &si.player_name, "player_name" },
+ { TYPE_SWITCH, &si.sound, "sound" },
+ { TYPE_SWITCH, &si.sound_loops, "repeating_sound_loops" },
+ { TYPE_SWITCH, &si.sound_music, "background_music" },
+ { TYPE_SWITCH, &si.sound_simple, "simple_sound_effects" },
+ { TYPE_SWITCH, &si.toons, "toons" },
+ { TYPE_SWITCH, &si.scroll_delay, "scroll_delay" },
+ { TYPE_SWITCH, &si.soft_scrolling, "soft_scrolling" },
+ { TYPE_SWITCH, &si.fading, "screen_fading" },
+ { TYPE_SWITCH, &si.autorecord, "automatic_tape_recording" },
+ { TYPE_SWITCH, &si.quick_doors, "quick_doors" },
+ { TYPE_SWITCH, &si.team_mode, "team_mode" },
+ { TYPE_SWITCH, &si.handicap, "handicap" },
+ { TYPE_SWITCH, &si.skip_levels, "skip_levels" },
+ { TYPE_SWITCH, &si.time_limit, "time_limit" },
+ { TYPE_SWITCH, &si.fullscreen, "fullscreen" },
+ { TYPE_SWITCH, &si.ask_on_escape, "ask_on_escape" },
+ { TYPE_STRING, &si.graphics_set, "graphics_set" },
+ { TYPE_STRING, &si.sounds_set, "sounds_set" },
+ { TYPE_STRING, &si.music_set, "music_set" },
+ { TYPE_SWITCH, &si.override_level_graphics, "override_level_graphics" },
+ { TYPE_SWITCH, &si.override_level_sounds, "override_level_sounds" },
+ { TYPE_SWITCH, &si.override_level_music, "override_level_music" },
+};
+
+static struct TokenInfo editor_setup_tokens[] =
+{
+ { TYPE_SWITCH, &sei.el_boulderdash, "editor.el_boulderdash" },
+ { TYPE_SWITCH, &sei.el_emerald_mine, "editor.el_emerald_mine" },
+ { TYPE_SWITCH, &sei.el_emerald_mine_club,"editor.el_emerald_mine_club"},
+ { TYPE_SWITCH, &sei.el_more, "editor.el_more" },
+ { TYPE_SWITCH, &sei.el_sokoban, "editor.el_sokoban" },
+ { TYPE_SWITCH, &sei.el_supaplex, "editor.el_supaplex" },
+ { TYPE_SWITCH, &sei.el_diamond_caves, "editor.el_diamond_caves" },
+ { TYPE_SWITCH, &sei.el_dx_boulderdash,"editor.el_dx_boulderdash" },
+ { TYPE_SWITCH, &sei.el_chars, "editor.el_chars" },
+ { TYPE_SWITCH, &sei.el_custom, "editor.el_custom" },
+ { TYPE_SWITCH, &sei.el_custom_more, "editor.el_custom_more" },
+ { TYPE_SWITCH, &sei.el_headlines, "editor.el_headlines" },
+ { TYPE_SWITCH, &sei.el_user_defined, "editor.el_user_defined" },
+};
+
+static struct TokenInfo shortcut_setup_tokens[] =
+{
+ { TYPE_KEY_X11, &ssi.save_game, "shortcut.save_game" },
+ { TYPE_KEY_X11, &ssi.load_game, "shortcut.load_game" },
+ { TYPE_KEY_X11, &ssi.toggle_pause, "shortcut.toggle_pause" }
+};
+
+static struct TokenInfo player_setup_tokens[] =
+{
+ { TYPE_BOOLEAN, &sii.use_joystick, ".use_joystick" },
+ { TYPE_STRING, &sii.joy.device_name, ".joy.device_name" },
+ { TYPE_INTEGER, &sii.joy.xleft, ".joy.xleft" },
+ { TYPE_INTEGER, &sii.joy.xmiddle, ".joy.xmiddle" },
+ { TYPE_INTEGER, &sii.joy.xright, ".joy.xright" },
+ { TYPE_INTEGER, &sii.joy.yupper, ".joy.yupper" },
+ { TYPE_INTEGER, &sii.joy.ymiddle, ".joy.ymiddle" },
+ { TYPE_INTEGER, &sii.joy.ylower, ".joy.ylower" },
+ { TYPE_INTEGER, &sii.joy.snap, ".joy.snap_field" },
+ { TYPE_INTEGER, &sii.joy.drop, ".joy.place_bomb" },
+ { TYPE_KEY_X11, &sii.key.left, ".key.move_left" },
+ { TYPE_KEY_X11, &sii.key.right, ".key.move_right" },
+ { TYPE_KEY_X11, &sii.key.up, ".key.move_up" },
+ { TYPE_KEY_X11, &sii.key.down, ".key.move_down" },
+ { TYPE_KEY_X11, &sii.key.snap, ".key.snap_field" },
+ { TYPE_KEY_X11, &sii.key.drop, ".key.place_bomb" }
+};
+
+static struct TokenInfo system_setup_tokens[] =
+{
+ { TYPE_STRING, &syi.sdl_audiodriver, "system.sdl_audiodriver" },
+ { TYPE_INTEGER, &syi.audio_fragment_size,"system.audio_fragment_size" }
+};
+
+static struct TokenInfo options_setup_tokens[] =
+{
+ { TYPE_BOOLEAN, &soi.verbose, "options.verbose" }
+};
+
+static char *get_corrected_login_name(char *login_name)
+{
+ /* needed because player name must be a fixed length string */
+ char *login_name_new = checked_malloc(MAX_PLAYER_NAME_LEN + 1);
+
+ strncpy(login_name_new, login_name, MAX_PLAYER_NAME_LEN);
+ login_name_new[MAX_PLAYER_NAME_LEN] = '\0';
+
+ if (strlen(login_name) > MAX_PLAYER_NAME_LEN) /* name has been cut */
+ if (strchr(login_name_new, ' '))
+ *strchr(login_name_new, ' ') = '\0';
+
+ return login_name_new;
+}
+
+static void setSetupInfoToDefaults(struct SetupInfo *si)
+{
+ int i;
+
+ si->player_name = get_corrected_login_name(getLoginName());
+
+ si->sound = TRUE;
+ si->sound_loops = TRUE;
+ si->sound_music = TRUE;
+ si->sound_simple = TRUE;
+ si->toons = TRUE;
+ si->double_buffering = TRUE;
+ si->direct_draw = !si->double_buffering;
+ si->scroll_delay = TRUE;
+ si->soft_scrolling = TRUE;
+ si->fading = FALSE;
+ si->autorecord = TRUE;
+ si->quick_doors = FALSE;
+ si->team_mode = FALSE;
+ si->handicap = TRUE;
+ si->skip_levels = TRUE;
+ si->time_limit = TRUE;
+ si->fullscreen = FALSE;
+ si->ask_on_escape = TRUE;
+
+ 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->editor.el_boulderdash = 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_chars = TRUE;
+ si->editor.el_custom = TRUE;
+ si->editor.el_custom_more = FALSE;
+
+ si->editor.el_headlines = TRUE;
+ si->editor.el_user_defined = FALSE;
+
+ si->shortcut.save_game = DEFAULT_KEY_SAVE_GAME;
+ si->shortcut.load_game = DEFAULT_KEY_LOAD_GAME;
+ si->shortcut.toggle_pause = DEFAULT_KEY_TOGGLE_PAUSE;
+
+ 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_audiodriver = getStringCopy(ARG_DEFAULT);
+ si->system.audio_fragment_size = DEFAULT_AUDIO_FRAGMENT_SIZE;
+
+ si->options.verbose = FALSE;
+}
+
+static void decodeSetupFileHash(SetupFileHash *setup_file_hash)
+{
+ int i, pnr;
+
+ if (!setup_file_hash)
+ return;
+
+ /* global setup */
+ si = setup;
+ for (i = 0; i < NUM_GLOBAL_SETUP_TOKENS; i++)
+ setSetupInfo(global_setup_tokens, i,
+ getHashEntry(setup_file_hash, global_setup_tokens[i].text));
+ setup = si;
+
+ /* editor setup */
+ sei = setup.editor;
+ for (i = 0; i < NUM_EDITOR_SETUP_TOKENS; i++)
+ setSetupInfo(editor_setup_tokens, i,
+ getHashEntry(setup_file_hash,editor_setup_tokens[i].text));
+ setup.editor = sei;
+
+ /* shortcut setup */
+ ssi = setup.shortcut;
+ for (i = 0; i < NUM_SHORTCUT_SETUP_TOKENS; i++)
+ setSetupInfo(shortcut_setup_tokens, i,
+ getHashEntry(setup_file_hash,shortcut_setup_tokens[i].text));
+ setup.shortcut = ssi;
+
+ /* player setup */
+ for (pnr = 0; pnr < MAX_PLAYERS; pnr++)
+ {
+ char prefix[30];
+
+ sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
+
+ sii = setup.input[pnr];
+ for (i = 0; i < NUM_PLAYER_SETUP_TOKENS; i++)
+ {
+ char full_token[100];
+
+ sprintf(full_token, "%s%s", prefix, player_setup_tokens[i].text);
+ setSetupInfo(player_setup_tokens, i,
+ getHashEntry(setup_file_hash, full_token));
+ }
+ setup.input[pnr] = sii;
+ }
+
+ /* system setup */
+ syi = setup.system;
+ for (i = 0; i < NUM_SYSTEM_SETUP_TOKENS; i++)
+ setSetupInfo(system_setup_tokens, i,
+ getHashEntry(setup_file_hash, system_setup_tokens[i].text));
+ setup.system = syi;
+
+ /* options setup */
+ soi = setup.options;
+ for (i = 0; i < NUM_OPTIONS_SETUP_TOKENS; i++)
+ setSetupInfo(options_setup_tokens, i,
+ getHashEntry(setup_file_hash, options_setup_tokens[i].text));
+ setup.options = soi;
+}
+
+void LoadSetup()
+{
+ char *filename = getSetupFilename();
+ SetupFileHash *setup_file_hash = NULL;
+
+ /* always start with reliable default values */
+ setSetupInfoToDefaults(&setup);
+
+ setup_file_hash = loadSetupFileHash(filename);
+
+ if (setup_file_hash)
+ {
+ char *player_name_new;
+
+ checkSetupFileHashIdentifier(setup_file_hash, getCookie("SETUP"));
+ decodeSetupFileHash(setup_file_hash);
+
+ setup.direct_draw = !setup.double_buffering;
+
+ freeSetupFileHash(setup_file_hash);
+
+ /* needed to work around problems with fixed length strings */
+ player_name_new = get_corrected_login_name(setup.player_name);
+ free(setup.player_name);
+ setup.player_name = player_name_new;
+ }
+ else
+ Error(ERR_WARN, "using default setup values");
+}
+
+void SaveSetup()
+{
+ char *filename = getSetupFilename();
+ FILE *file;
+ int i, pnr;
+
+ InitUserDataDirectory();
+
+ if (!(file = fopen(filename, MODE_WRITE)))
+ {
+ Error(ERR_WARN, "cannot write setup file '%s'", filename);
+ return;