+ request->hostname = API_SERVER_HOSTNAME;
+ request->port = API_SERVER_PORT;
+ request->method = API_SERVER_METHOD;
+ request->uri = API_SERVER_URI_GET;
+
+ snprintf(request->body, MAX_HTTP_BODY_SIZE,
+ "{\n"
+ " \"levelset_identifier\": \"%s\",\n"
+ " \"level_nr\": \"%d\",\n"
+ " \"rate_time_over_score\": \"%d\"\n"
+ "}\n",
+ levelset.identifier, nr, level.rate_time_over_score);
+
+ if (!DoHttpRequest(request, response))
+ {
+ Error("HTTP request failed: %s", GetHttpError());
+
+ return;
+ }
+
+ if (!HTTP_SUCCESS(response->status_code))
+ {
+ Error("server failed to handle request: %d %s",
+ response->status_code,
+ response->status_text);
+
+ return;
+ }
+
+ if (response->body_size == 0)
+ {
+ // no scores available for this level
+
+ return;
+ }
+
+ ConvertHttpResponseBodyToClientEncoding(response);
+
+ char *filename = getScoreCacheFilename(nr);
+ FILE *file;
+ int i;
+
+ // used instead of "leveldir_current->subdir" (for network games)
+ InitScoreCacheDirectory(levelset.identifier);
+
+ if (!(file = fopen(filename, MODE_WRITE)))
+ {
+ Warn("cannot save score cache file '%s'", filename);
+
+ return;
+ }
+
+ for (i = 0; i < response->body_size; i++)
+ fputc(response->body[i], file);
+
+ fclose(file);
+
+ SetFilePermissions(filename, PERMS_PRIVATE);
+
+ server_scores.updated = TRUE;
+}
+
+static void DownloadServerScoreToCache(int nr)
+{
+ struct HttpRequest *request = checked_calloc(sizeof(struct HttpRequest));
+ struct HttpResponse *response = checked_calloc(sizeof(struct HttpResponse));
+
+ DownloadServerScoreToCacheExt(request, response, nr);
+
+ checked_free(request);
+ checked_free(response);
+}
+
+static int DownloadServerScoreToCacheThread(void *data)
+{
+ DownloadServerScoreToCache(*(int *)data);
+
+ return 0;
+}
+
+static void DownloadServerScoreToCacheAsThread(int nr)
+{
+ ExecuteAsThread(DownloadServerScoreToCacheThread,
+ "DownloadServerScoreToCache", nr,
+ "download scores from server");
+}
+
+static void LoadServerScoreFromCache(int nr)
+{
+ struct ScoreEntry score_entry;
+ struct
+ {
+ void *value;
+ boolean is_string;
+ int string_size;
+ }
+ score_mapping[] =
+ {
+ { &score_entry.score, FALSE, 0 },
+ { &score_entry.time, FALSE, 0 },
+ { score_entry.name, TRUE, MAX_PLAYER_NAME_LEN },
+ { score_entry.tape_basename, TRUE, MAX_FILENAME_LEN },
+
+ { NULL, FALSE, 0 }
+ };
+ char *filename = getScoreCacheFilename(nr);
+ SetupFileHash *score_hash = loadSetupFileHash(filename);
+ int i, j;
+
+ server_scores.num_entries = 0;
+
+ if (score_hash == NULL)
+ return;
+
+ for (i = 0; i < MAX_SCORE_ENTRIES; i++)
+ {
+ score_entry = server_scores.entry[i];
+
+ for (j = 0; score_mapping[j].value != NULL; j++)
+ {
+ char token[10];
+
+ sprintf(token, "%02d.%d", i, j);
+
+ char *value = getHashEntry(score_hash, token);
+
+ if (value == NULL)
+ continue;
+
+ if (score_mapping[j].is_string)
+ {
+ char *score_value = (char *)score_mapping[j].value;
+ int value_size = score_mapping[j].string_size;
+
+ strncpy(score_value, value, value_size);
+ score_value[value_size] = '\0';
+ }
+ else
+ {
+ int *score_value = (int *)score_mapping[j].value;
+
+ *score_value = atoi(value);
+ }
+
+ server_scores.num_entries = i + 1;
+ }
+
+ server_scores.entry[i] = score_entry;
+ }
+
+ freeSetupFileHash(score_hash);
+}
+
+void LoadServerScore(int nr, boolean download_score)
+{
+ // always start with reliable default values
+ setServerScoreInfoToDefaults();
+
+ // 1st step: load server scores from cache file (which may not exist)
+ // (this should prevent reading it while the thread is writing to it)
+ LoadServerScoreFromCache(nr);
+
+ if (download_score)
+ {
+ // 2nd step: download server scores from score server to cache file
+ // (as thread, as it might time out if the server is not reachable)
+ DownloadServerScoreToCacheAsThread(nr);
+ }
+
+ // merge local scores with scores from server
+ MergeServerScore();
+}
+
+static char *get_file_base64(char *filename)
+{
+ struct stat file_status;
+
+ if (stat(filename, &file_status) != 0)
+ {
+ Error("cannot stat file '%s'\n", filename);
+
+ return NULL;
+ }
+
+ int buffer_size = file_status.st_size;
+ byte *buffer = checked_malloc(buffer_size);
+ FILE *file;
+ int i;
+
+ if (!(file = fopen(filename, MODE_READ)))
+ {
+ Error("cannot open file '%s'\n", filename);
+
+ checked_free(buffer);
+
+ return NULL;
+ }
+
+ for (i = 0; i < buffer_size; i++)
+ {
+ int c = fgetc(file);
+
+ if (c == EOF)
+ {
+ Error("cannot read from input file '%s'\n", filename);
+
+ fclose(file);
+ checked_free(buffer);
+
+ return NULL;
+ }
+
+ buffer[i] = (byte)c;
+ }
+
+ fclose(file);
+
+ int buffer_encoded_size = base64_encoded_size(buffer_size);
+ char *buffer_encoded = checked_malloc(buffer_encoded_size);
+
+ base64_encode(buffer_encoded, buffer, buffer_size);
+
+ checked_free(buffer);
+
+ return buffer_encoded;
+}
+
+static void UploadScoreToServerExt(struct HttpRequest *request,
+ struct HttpResponse *response,
+ int nr)
+{
+ struct ScoreEntry *score_entry = &scores.entry[scores.last_added];
+
+ request->hostname = API_SERVER_HOSTNAME;
+ request->port = API_SERVER_PORT;
+ request->method = API_SERVER_METHOD;
+ request->uri = API_SERVER_URI_ADD;
+
+ char *tape_filename = getScoreTapeFilename(score_entry->tape_basename, nr);
+ char *tape_base64 = get_file_base64(tape_filename);
+
+ if (tape_base64 == NULL)
+ {
+ Error("loading and base64 encoding score tape file failed");
+
+ return;
+ }
+
+ snprintf(request->body, MAX_HTTP_BODY_SIZE,
+ "{\n"
+ " \"game_version\": \"%s\",\n"
+ " \"levelset_identifier\": \"%s\",\n"
+ " \"levelset_name\": \"%s\",\n"
+ " \"levelset_author\": \"%s\",\n"
+ " \"levelset_num_levels\": \"%d\",\n"
+ " \"levelset_first_level\": \"%d\",\n"
+ " \"level_nr\": \"%d\",\n"
+ " \"player_name\": \"%s\",\n"
+ " \"score\": \"%d\",\n"
+ " \"time\": \"%d\",\n"
+ " \"tape_basename\": \"%s\",\n"
+ " \"tape\": \"%s\"\n"
+ "}\n",
+ getProgramRealVersionString(),
+ leveldir_current->identifier,
+ leveldir_current->name,
+ leveldir_current->author,
+ leveldir_current->levels,
+ leveldir_current->first_level,
+ level_nr,
+ score_entry->name,
+ score_entry->score,
+ score_entry->time,
+ score_entry->tape_basename,
+ tape_base64);
+
+ checked_free(tape_base64);
+
+ ConvertHttpRequestBodyToServerEncoding(request);
+
+ if (!DoHttpRequest(request, response))
+ {
+ Error("HTTP request failed: %s", GetHttpError());
+
+ return;
+ }
+
+ if (!HTTP_SUCCESS(response->status_code))
+ {
+ Error("server failed to handle request: %d %s",
+ response->status_code,
+ response->status_text);
+
+ return;
+ }
+}
+
+static void UploadScoreToServer(int nr)
+{
+ struct HttpRequest *request = checked_calloc(sizeof(struct HttpRequest));
+ struct HttpResponse *response = checked_calloc(sizeof(struct HttpResponse));
+
+ UploadScoreToServerExt(request, response, nr);
+
+ checked_free(request);
+ checked_free(response);
+}
+
+static int UploadScoreToServerThread(void *data)
+{
+ UploadScoreToServer(*(int *)data);
+
+ return 0;
+}
+
+static void UploadScoreToServerAsThread(int nr)
+{
+ ExecuteAsThread(UploadScoreToServerThread,
+ "UploadScoreToServer", nr,
+ "upload score to server");
+}
+
+void SaveServerScore(int nr)
+{
+ UploadScoreToServerAsThread(nr);
+}
+
+void LoadLocalAndServerScore(int nr, boolean download_score)
+{
+ int last_added_local = scores.last_added_local;
+
+ LoadScore(nr);
+
+ // restore last added local score entry (before merging server scores)
+ scores.last_added = scores.last_added_local = last_added_local;
+
+ LoadServerScore(nr, download_score);
+
+ MergeServerScore();
+}
+
+
+// ============================================================================
+// 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[] =
+{
+ {
+ 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.menu_game, "menu_game"
+ },
+ {
+ 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"
+ },
+};
+
+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"
+ },