moved functions to parse GIC parameters from 'libgame' to main source tree
[rocksndiamonds.git] / src / files.c
index 7af56662cd3f50734d5fd7002a579a3d294c9305..4ac4563fee7dfd0fb9c3ab6494da719c95f56cca 100644 (file)
@@ -8171,18 +8171,19 @@ void SaveTape(int nr)
   tape.changed = FALSE;
 }
 
-static boolean SaveTapeCheckedExt(int nr, char *msg_replace, char *msg_saved)
+static boolean SaveTapeCheckedExt(int nr, char *msg_replace, char *msg_saved,
+                                 unsigned int req_state_added)
 {
   char *filename = getTapeFilename(nr);
   boolean new_tape = !fileExists(filename);
   boolean tape_saved = FALSE;
 
-  if (new_tape || Request(msg_replace, REQ_ASK))
+  if (new_tape || Request(msg_replace, REQ_ASK | req_state_added))
   {
     SaveTape(nr);
 
     if (new_tape)
-      Request(msg_saved, REQ_CONFIRM);
+      Request(msg_saved, REQ_CONFIRM | req_state_added);
 
     tape_saved = TRUE;
   }
@@ -8192,13 +8193,13 @@ static boolean SaveTapeCheckedExt(int nr, char *msg_replace, char *msg_saved)
 
 boolean SaveTapeChecked(int nr)
 {
-  return SaveTapeCheckedExt(nr, "Replace old tape?", "Tape saved!");
+  return SaveTapeCheckedExt(nr, "Replace old tape?", "Tape saved!", 0);
 }
 
 boolean SaveTapeChecked_LevelSolved(int nr)
 {
   return SaveTapeCheckedExt(nr, "Level solved! Replace old tape?",
-                               "Level solved! Tape saved!");
+                               "Level solved! Tape saved!", REQ_STAY_OPEN);
 }
 
 void DumpTape(struct TapeInfo *tape)
@@ -8350,456 +8351,749 @@ void SaveScore(int nr)
 
 #define TOKEN_STR_PLAYER_PREFIX                        "player_"
 
-// global setup
-enum
-{
-  SETUP_TOKEN_PLAYER_NAME = 0,
-  SETUP_TOKEN_SOUND,
-  SETUP_TOKEN_SOUND_LOOPS,
-  SETUP_TOKEN_SOUND_MUSIC,
-  SETUP_TOKEN_SOUND_SIMPLE,
-  SETUP_TOKEN_TOONS,
-  SETUP_TOKEN_SCROLL_DELAY,
-  SETUP_TOKEN_SCROLL_DELAY_VALUE,
-  SETUP_TOKEN_ENGINE_SNAPSHOT_MODE,
-  SETUP_TOKEN_ENGINE_SNAPSHOT_MEMORY,
-  SETUP_TOKEN_FADE_SCREENS,
-  SETUP_TOKEN_AUTORECORD,
-  SETUP_TOKEN_SHOW_TITLESCREEN,
-  SETUP_TOKEN_QUICK_DOORS,
-  SETUP_TOKEN_TEAM_MODE,
-  SETUP_TOKEN_HANDICAP,
-  SETUP_TOKEN_SKIP_LEVELS,
-  SETUP_TOKEN_INCREMENT_LEVELS,
-  SETUP_TOKEN_AUTO_PLAY_NEXT_LEVEL,
-  SETUP_TOKEN_SKIP_SCORES_AFTER_GAME,
-  SETUP_TOKEN_TIME_LIMIT,
-  SETUP_TOKEN_FULLSCREEN,
-  SETUP_TOKEN_WINDOW_SCALING_PERCENT,
-  SETUP_TOKEN_WINDOW_SCALING_QUALITY,
-  SETUP_TOKEN_SCREEN_RENDERING_MODE,
-  SETUP_TOKEN_VSYNC_MODE,
-  SETUP_TOKEN_ASK_ON_ESCAPE,
-  SETUP_TOKEN_ASK_ON_ESCAPE_EDITOR,
-  SETUP_TOKEN_ASK_ON_GAME_OVER,
-  SETUP_TOKEN_QUICK_SWITCH,
-  SETUP_TOKEN_INPUT_ON_FOCUS,
-  SETUP_TOKEN_PREFER_AGA_GRAPHICS,
-  SETUP_TOKEN_GAME_SPEED_EXTENDED,
-  SETUP_TOKEN_GAME_FRAME_DELAY,
-  SETUP_TOKEN_SP_SHOW_BORDER_ELEMENTS,
-  SETUP_TOKEN_SMALL_GAME_GRAPHICS,
-  SETUP_TOKEN_SHOW_SNAPSHOT_BUTTONS,
-  SETUP_TOKEN_GRAPHICS_SET,
-  SETUP_TOKEN_SOUNDS_SET,
-  SETUP_TOKEN_MUSIC_SET,
-  SETUP_TOKEN_OVERRIDE_LEVEL_GRAPHICS,
-  SETUP_TOKEN_OVERRIDE_LEVEL_SOUNDS,
-  SETUP_TOKEN_OVERRIDE_LEVEL_MUSIC,
-  SETUP_TOKEN_VOLUME_SIMPLE,
-  SETUP_TOKEN_VOLUME_LOOPS,
-  SETUP_TOKEN_VOLUME_MUSIC,
-  SETUP_TOKEN_NETWORK_MODE,
-  SETUP_TOKEN_NETWORK_PLAYER_NR,
-  SETUP_TOKEN_NETWORK_SERVER_HOSTNAME,
-  SETUP_TOKEN_TOUCH_CONTROL_TYPE,
-  SETUP_TOKEN_TOUCH_MOVE_DISTANCE,
-  SETUP_TOKEN_TOUCH_DROP_DISTANCE,
-  SETUP_TOKEN_TOUCH_TRANSPARENCY,
-  SETUP_TOKEN_TOUCH_DRAW_OUTLINED,
-  SETUP_TOKEN_TOUCH_DRAW_PRESSED,
-  SETUP_TOKEN_TOUCH_GRID_XSIZE_0,
-  SETUP_TOKEN_TOUCH_GRID_YSIZE_0,
-  SETUP_TOKEN_TOUCH_GRID_XSIZE_1,
-  SETUP_TOKEN_TOUCH_GRID_YSIZE_1,
-
-  NUM_GLOBAL_SETUP_TOKENS
-};
-
-// auto setup
-enum
-{
-  SETUP_TOKEN_AUTO_EDITOR_ZOOM_TILESIZE = 0,
-
-  NUM_AUTO_SETUP_TOKENS
-};
-
-// editor setup
-enum
-{
-  SETUP_TOKEN_EDITOR_EL_CLASSIC = 0,
-  SETUP_TOKEN_EDITOR_EL_CUSTOM,
-  SETUP_TOKEN_EDITOR_EL_USER_DEFINED,
-  SETUP_TOKEN_EDITOR_EL_DYNAMIC,
-  SETUP_TOKEN_EDITOR_EL_HEADLINES,
-  SETUP_TOKEN_EDITOR_SHOW_ELEMENT_TOKEN,
-
-  NUM_EDITOR_SETUP_TOKENS
-};
-
-// editor cascade setup
-enum
-{
-  SETUP_TOKEN_EDITOR_CASCADE_BD = 0,
-  SETUP_TOKEN_EDITOR_CASCADE_EM,
-  SETUP_TOKEN_EDITOR_CASCADE_EMC,
-  SETUP_TOKEN_EDITOR_CASCADE_RND,
-  SETUP_TOKEN_EDITOR_CASCADE_SB,
-  SETUP_TOKEN_EDITOR_CASCADE_SP,
-  SETUP_TOKEN_EDITOR_CASCADE_DC,
-  SETUP_TOKEN_EDITOR_CASCADE_DX,
-  SETUP_TOKEN_EDITOR_CASCADE_TEXT,
-  SETUP_TOKEN_EDITOR_CASCADE_STEELTEXT,
-  SETUP_TOKEN_EDITOR_CASCADE_CE,
-  SETUP_TOKEN_EDITOR_CASCADE_GE,
-  SETUP_TOKEN_EDITOR_CASCADE_REF,
-  SETUP_TOKEN_EDITOR_CASCADE_USER,
-  SETUP_TOKEN_EDITOR_CASCADE_DYNAMIC,
-
-  NUM_EDITOR_CASCADE_SETUP_TOKENS
-};
-
-// shortcut setup
-enum
-{
-  SETUP_TOKEN_SHORTCUT_SAVE_GAME = 0,
-  SETUP_TOKEN_SHORTCUT_LOAD_GAME,
-  SETUP_TOKEN_SHORTCUT_TOGGLE_PAUSE,
-  SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_1,
-  SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_2,
-  SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_3,
-  SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_4,
-  SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_ALL,
-  SETUP_TOKEN_SHORTCUT_TAPE_EJECT,
-  SETUP_TOKEN_SHORTCUT_TAPE_EXTRA,
-  SETUP_TOKEN_SHORTCUT_TAPE_STOP,
-  SETUP_TOKEN_SHORTCUT_TAPE_PAUSE,
-  SETUP_TOKEN_SHORTCUT_TAPE_RECORD,
-  SETUP_TOKEN_SHORTCUT_TAPE_PLAY,
-  SETUP_TOKEN_SHORTCUT_SOUND_SIMPLE,
-  SETUP_TOKEN_SHORTCUT_SOUND_LOOPS,
-  SETUP_TOKEN_SHORTCUT_SOUND_MUSIC,
-  SETUP_TOKEN_SHORTCUT_SNAP_LEFT,
-  SETUP_TOKEN_SHORTCUT_SNAP_RIGHT,
-  SETUP_TOKEN_SHORTCUT_SNAP_UP,
-  SETUP_TOKEN_SHORTCUT_SNAP_DOWN,
-
-  NUM_SHORTCUT_SETUP_TOKENS
-};
-
-// player setup
-enum
-{
-  SETUP_TOKEN_PLAYER_USE_JOYSTICK = 0,
-  SETUP_TOKEN_PLAYER_JOY_DEVICE_NAME,
-  SETUP_TOKEN_PLAYER_JOY_XLEFT,
-  SETUP_TOKEN_PLAYER_JOY_XMIDDLE,
-  SETUP_TOKEN_PLAYER_JOY_XRIGHT,
-  SETUP_TOKEN_PLAYER_JOY_YUPPER,
-  SETUP_TOKEN_PLAYER_JOY_YMIDDLE,
-  SETUP_TOKEN_PLAYER_JOY_YLOWER,
-  SETUP_TOKEN_PLAYER_JOY_SNAP,
-  SETUP_TOKEN_PLAYER_JOY_DROP,
-  SETUP_TOKEN_PLAYER_KEY_LEFT,
-  SETUP_TOKEN_PLAYER_KEY_RIGHT,
-  SETUP_TOKEN_PLAYER_KEY_UP,
-  SETUP_TOKEN_PLAYER_KEY_DOWN,
-  SETUP_TOKEN_PLAYER_KEY_SNAP,
-  SETUP_TOKEN_PLAYER_KEY_DROP,
-
-  NUM_PLAYER_SETUP_TOKENS
-};
-
-// system setup
-enum
-{
-  SETUP_TOKEN_SYSTEM_SDL_VIDEODRIVER = 0,
-  SETUP_TOKEN_SYSTEM_SDL_AUDIODRIVER,
-  SETUP_TOKEN_SYSTEM_AUDIO_FRAGMENT_SIZE,
-
-  NUM_SYSTEM_SETUP_TOKENS
-};
-
-// internal setup
-enum
-{
-  SETUP_TOKEN_INT_PROGRAM_TITLE = 0,
-  SETUP_TOKEN_INT_PROGRAM_VERSION,
-  SETUP_TOKEN_INT_PROGRAM_AUTHOR,
-  SETUP_TOKEN_INT_PROGRAM_EMAIL,
-  SETUP_TOKEN_INT_PROGRAM_WEBSITE,
-  SETUP_TOKEN_INT_PROGRAM_COPYRIGHT,
-  SETUP_TOKEN_INT_PROGRAM_COMPANY,
-  SETUP_TOKEN_INT_PROGRAM_ICON_FILE,
-  SETUP_TOKEN_INT_DEFAULT_GRAPHICS_SET,
-  SETUP_TOKEN_INT_DEFAULT_SOUNDS_SET,
-  SETUP_TOKEN_INT_DEFAULT_MUSIC_SET,
-  SETUP_TOKEN_INT_FALLBACK_GRAPHICS_FILE,
-  SETUP_TOKEN_INT_FALLBACK_SOUNDS_FILE,
-  SETUP_TOKEN_INT_FALLBACK_MUSIC_FILE,
-  SETUP_TOKEN_INT_DEFAULT_LEVEL_SERIES,
-  SETUP_TOKEN_INT_CHOOSE_FROM_TOP_LEVELDIR,
-  SETUP_TOKEN_INT_SHOW_SCALING_IN_TITLE,
-  SETUP_TOKEN_INT_DEFAULT_WINDOW_WIDTH,
-  SETUP_TOKEN_INT_DEFAULT_WINDOW_HEIGHT,
-
-  NUM_INTERNAL_SETUP_TOKENS
-};
-
-// debug setup
-enum
-{
-  SETUP_TOKEN_DEBUG_FRAME_DELAY_0 = 0,
-  SETUP_TOKEN_DEBUG_FRAME_DELAY_1,
-  SETUP_TOKEN_DEBUG_FRAME_DELAY_2,
-  SETUP_TOKEN_DEBUG_FRAME_DELAY_3,
-  SETUP_TOKEN_DEBUG_FRAME_DELAY_4,
-  SETUP_TOKEN_DEBUG_FRAME_DELAY_5,
-  SETUP_TOKEN_DEBUG_FRAME_DELAY_6,
-  SETUP_TOKEN_DEBUG_FRAME_DELAY_7,
-  SETUP_TOKEN_DEBUG_FRAME_DELAY_8,
-  SETUP_TOKEN_DEBUG_FRAME_DELAY_9,
-  SETUP_TOKEN_DEBUG_FRAME_DELAY_KEY_0,
-  SETUP_TOKEN_DEBUG_FRAME_DELAY_KEY_1,
-  SETUP_TOKEN_DEBUG_FRAME_DELAY_KEY_2,
-  SETUP_TOKEN_DEBUG_FRAME_DELAY_KEY_3,
-  SETUP_TOKEN_DEBUG_FRAME_DELAY_KEY_4,
-  SETUP_TOKEN_DEBUG_FRAME_DELAY_KEY_5,
-  SETUP_TOKEN_DEBUG_FRAME_DELAY_KEY_6,
-  SETUP_TOKEN_DEBUG_FRAME_DELAY_KEY_7,
-  SETUP_TOKEN_DEBUG_FRAME_DELAY_KEY_8,
-  SETUP_TOKEN_DEBUG_FRAME_DELAY_KEY_9,
-  SETUP_TOKEN_DEBUG_FRAME_DELAY_USE_MOD_KEY,
-  SETUP_TOKEN_DEBUG_FRAME_DELAY_GAME_ONLY,
-  SETUP_TOKEN_DEBUG_SHOW_FRAMES_PER_SECOND,
-
-  NUM_DEBUG_SETUP_TOKENS
-};
-
-// options setup
-enum
-{
-  SETUP_TOKEN_OPTIONS_VERBOSE = 0,
-
-  NUM_OPTIONS_SETUP_TOKENS
-};
-
-
-static struct SetupInfo si;
-static struct SetupAutoSetupInfo sasi;
-static struct SetupEditorInfo sei;
-static struct SetupEditorCascadeInfo seci;
-static struct SetupShortcutInfo ssi;
-static struct SetupInputInfo sii;
-static struct SetupSystemInfo syi;
-static struct SetupInternalInfo sxi;
-static struct SetupDebugInfo sdi;
-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_INTEGER,&si.scroll_delay_value,      "scroll_delay_value"     },
-  { TYPE_STRING, &si.engine_snapshot_mode,    "engine_snapshot_mode"   },
-  { TYPE_INTEGER,&si.engine_snapshot_memory,  "engine_snapshot_memory" },
-  { TYPE_SWITCH, &si.fade_screens,            "fade_screens"           },
-  { TYPE_SWITCH, &si.autorecord,              "automatic_tape_recording"},
-  { TYPE_SWITCH, &si.show_titlescreen,        "show_titlescreen"       },
-  { 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.increment_levels,        "increment_levels"       },
-  { TYPE_SWITCH, &si.auto_play_next_level,    "auto_play_next_level"   },
-  { TYPE_SWITCH, &si.skip_scores_after_game,  "skip_scores_after_game" },
-  { TYPE_SWITCH, &si.time_limit,              "time_limit"             },
-  { TYPE_SWITCH, &si.fullscreen,              "fullscreen"             },
-  { TYPE_INTEGER,&si.window_scaling_percent,  "window_scaling_percent" },
-  { TYPE_STRING, &si.window_scaling_quality,  "window_scaling_quality" },
-  { TYPE_STRING, &si.screen_rendering_mode,   "screen_rendering_mode"  },
-  { TYPE_STRING, &si.vsync_mode,              "vsync_mode"             },
-  { TYPE_SWITCH, &si.ask_on_escape,           "ask_on_escape"          },
-  { TYPE_SWITCH, &si.ask_on_escape_editor,    "ask_on_escape_editor"   },
-  { TYPE_SWITCH, &si.ask_on_game_over,        "ask_on_game_over"       },
-  { TYPE_SWITCH, &si.quick_switch,            "quick_player_switch"    },
-  { TYPE_SWITCH, &si.input_on_focus,          "input_on_focus"         },
-  { TYPE_SWITCH, &si.prefer_aga_graphics,     "prefer_aga_graphics"    },
-  { TYPE_SWITCH, &si.game_speed_extended,     "game_speed_extended"    },
-  { TYPE_INTEGER,&si.game_frame_delay,        "game_frame_delay"       },
-  { TYPE_SWITCH, &si.sp_show_border_elements, "sp_show_border_elements"        },
-  { TYPE_SWITCH, &si.small_game_graphics,     "small_game_graphics"    },
-  { TYPE_SWITCH, &si.show_snapshot_buttons,   "show_snapshot_buttons"  },
-  { TYPE_STRING, &si.graphics_set,            "graphics_set"           },
-  { TYPE_STRING, &si.sounds_set,              "sounds_set"             },
-  { TYPE_STRING, &si.music_set,               "music_set"              },
-  { TYPE_SWITCH3,&si.override_level_graphics, "override_level_graphics"        },
-  { TYPE_SWITCH3,&si.override_level_sounds,   "override_level_sounds"  },
-  { TYPE_SWITCH3,&si.override_level_music,    "override_level_music"   },
-  { TYPE_INTEGER,&si.volume_simple,           "volume_simple"          },
-  { TYPE_INTEGER,&si.volume_loops,            "volume_loops"           },
-  { TYPE_INTEGER,&si.volume_music,            "volume_music"           },
-  { TYPE_SWITCH, &si.network_mode,            "network_mode"           },
-  { TYPE_PLAYER, &si.network_player_nr,       "network_player"         },
-  { TYPE_STRING, &si.network_server_hostname, "network_server_hostname"        },
-  { TYPE_STRING, &si.touch.control_type,      "touch.control_type"     },
-  { TYPE_INTEGER,&si.touch.move_distance,     "touch.move_distance"    },
-  { TYPE_INTEGER,&si.touch.drop_distance,     "touch.drop_distance"    },
-  { TYPE_INTEGER,&si.touch.transparency,      "touch.transparency"     },
-  { TYPE_INTEGER,&si.touch.draw_outlined,     "touch.draw_outlined"    },
-  { TYPE_INTEGER,&si.touch.draw_pressed,      "touch.draw_pressed"     },
-  { TYPE_INTEGER,&si.touch.grid_xsize[0],     "touch.virtual_buttons.0.xsize" },
-  { TYPE_INTEGER,&si.touch.grid_ysize[0],     "touch.virtual_buttons.0.ysize" },
-  { TYPE_INTEGER,&si.touch.grid_xsize[1],     "touch.virtual_buttons.1.xsize" },
-  { TYPE_INTEGER,&si.touch.grid_ysize[1],     "touch.virtual_buttons.1.ysize" },
+  {
+    TYPE_STRING,
+    &setup.player_name,                                "player_name"
+  },
+  {
+    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_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.skip_scores_after_game,             "skip_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.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.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,&sasi.editor_zoom_tilesize,   "editor.zoom_tilesize"  },
+  {
+    TYPE_INTEGER,
+    &setup.auto_setup.editor_zoom_tilesize,    "editor.zoom_tilesize"
+  },
 };
 
 static struct TokenInfo editor_setup_tokens[] =
 {
-  { TYPE_SWITCH, &sei.el_classic,      "editor.el_classic"             },
-  { TYPE_SWITCH, &sei.el_custom,       "editor.el_custom"              },
-  { TYPE_SWITCH, &sei.el_user_defined, "editor.el_user_defined"        },
-  { TYPE_SWITCH, &sei.el_dynamic,      "editor.el_dynamic"             },
-  { TYPE_SWITCH, &sei.el_headlines,    "editor.el_headlines"           },
-  { TYPE_SWITCH, &sei.show_element_token,"editor.show_element_token"   },
+  {
+    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"
+  },
 };
 
 static struct TokenInfo editor_cascade_setup_tokens[] =
 {
-  { TYPE_SWITCH, &seci.el_bd,          "editor.cascade.el_bd"          },
-  { TYPE_SWITCH, &seci.el_em,          "editor.cascade.el_em"          },
-  { TYPE_SWITCH, &seci.el_emc,         "editor.cascade.el_emc"         },
-  { TYPE_SWITCH, &seci.el_rnd,         "editor.cascade.el_rnd"         },
-  { TYPE_SWITCH, &seci.el_sb,          "editor.cascade.el_sb"          },
-  { TYPE_SWITCH, &seci.el_sp,          "editor.cascade.el_sp"          },
-  { TYPE_SWITCH, &seci.el_dc,          "editor.cascade.el_dc"          },
-  { TYPE_SWITCH, &seci.el_dx,          "editor.cascade.el_dx"          },
-  { TYPE_SWITCH, &seci.el_mm,          "editor.cascade.el_mm"          },
-  { TYPE_SWITCH, &seci.el_df,          "editor.cascade.el_df"          },
-  { TYPE_SWITCH, &seci.el_chars,       "editor.cascade.el_chars"       },
-  { TYPE_SWITCH, &seci.el_steel_chars, "editor.cascade.el_steel_chars" },
-  { TYPE_SWITCH, &seci.el_ce,          "editor.cascade.el_ce"          },
-  { TYPE_SWITCH, &seci.el_ge,          "editor.cascade.el_ge"          },
-  { TYPE_SWITCH, &seci.el_ref,         "editor.cascade.el_ref"         },
-  { TYPE_SWITCH, &seci.el_user,                "editor.cascade.el_user"        },
-  { TYPE_SWITCH, &seci.el_dynamic,     "editor.cascade.el_dynamic"     },
+  {
+    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, &ssi.save_game,      "shortcut.save_game"            },
-  { TYPE_KEY_X11, &ssi.load_game,      "shortcut.load_game"            },
-  { TYPE_KEY_X11, &ssi.toggle_pause,   "shortcut.toggle_pause"         },
-  { TYPE_KEY_X11, &ssi.focus_player[0],        "shortcut.focus_player_1"       },
-  { TYPE_KEY_X11, &ssi.focus_player[1],        "shortcut.focus_player_2"       },
-  { TYPE_KEY_X11, &ssi.focus_player[2],        "shortcut.focus_player_3"       },
-  { TYPE_KEY_X11, &ssi.focus_player[3],        "shortcut.focus_player_4"       },
-  { TYPE_KEY_X11, &ssi.focus_player_all,"shortcut.focus_player_all"    },
-  { TYPE_KEY_X11, &ssi.tape_eject,     "shortcut.tape_eject"           },
-  { TYPE_KEY_X11, &ssi.tape_extra,     "shortcut.tape_extra"           },
-  { TYPE_KEY_X11, &ssi.tape_stop,      "shortcut.tape_stop"            },
-  { TYPE_KEY_X11, &ssi.tape_pause,     "shortcut.tape_pause"           },
-  { TYPE_KEY_X11, &ssi.tape_record,    "shortcut.tape_record"          },
-  { TYPE_KEY_X11, &ssi.tape_play,      "shortcut.tape_play"            },
-  { TYPE_KEY_X11, &ssi.sound_simple,   "shortcut.sound_simple"         },
-  { TYPE_KEY_X11, &ssi.sound_loops,    "shortcut.sound_loops"          },
-  { TYPE_KEY_X11, &ssi.sound_music,    "shortcut.sound_music"          },
-  { TYPE_KEY_X11, &ssi.snap_left,      "shortcut.snap_left"            },
-  { TYPE_KEY_X11, &ssi.snap_right,     "shortcut.snap_right"           },
-  { TYPE_KEY_X11, &ssi.snap_up,                "shortcut.snap_up"              },
-  { TYPE_KEY_X11, &ssi.snap_down,      "shortcut.snap_down"            },
+  {
+    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, &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"               },
+  {
+    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,  &syi.sdl_videodriver,    "system.sdl_videodriver"    },
-  { TYPE_STRING,  &syi.sdl_audiodriver,           "system.sdl_audiodriver"     },
-  { TYPE_INTEGER, &syi.audio_fragment_size,"system.audio_fragment_size"        },
+  {
+    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, &sxi.program_title,           "program_title"         },
-  { TYPE_STRING, &sxi.program_version,         "program_version"       },
-  { TYPE_STRING, &sxi.program_author,          "program_author"        },
-  { TYPE_STRING, &sxi.program_email,           "program_email"         },
-  { TYPE_STRING, &sxi.program_website,         "program_website"       },
-  { TYPE_STRING, &sxi.program_copyright,       "program_copyright"     },
-  { TYPE_STRING, &sxi.program_company,         "program_company"       },
-  { TYPE_STRING, &sxi.program_icon_file,       "program_icon_file"     },
-  { TYPE_STRING, &sxi.default_graphics_set,    "default_graphics_set"  },
-  { TYPE_STRING, &sxi.default_sounds_set,      "default_sounds_set"    },
-  { TYPE_STRING, &sxi.default_music_set,       "default_music_set"     },
-  { TYPE_STRING, &sxi.fallback_graphics_file,  "fallback_graphics_file"},
-  { TYPE_STRING, &sxi.fallback_sounds_file,    "fallback_sounds_file"  },
-  { TYPE_STRING, &sxi.fallback_music_file,     "fallback_music_file"   },
-  { TYPE_STRING, &sxi.default_level_series,    "default_level_series"  },
-  { TYPE_BOOLEAN,&sxi.choose_from_top_leveldir,        "choose_from_top_leveldir" },
-  { TYPE_BOOLEAN,&sxi.show_scaling_in_title,   "show_scaling_in_title" },
-  { TYPE_INTEGER,&sxi.default_window_width,    "default_window_width"  },
-  { TYPE_INTEGER,&sxi.default_window_height,   "default_window_height" },
+  {
+    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.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, &sdi.frame_delay[0],         "debug.frame_delay_0"   },
-  { TYPE_INTEGER, &sdi.frame_delay[1],         "debug.frame_delay_1"   },
-  { TYPE_INTEGER, &sdi.frame_delay[2],         "debug.frame_delay_2"   },
-  { TYPE_INTEGER, &sdi.frame_delay[3],         "debug.frame_delay_3"   },
-  { TYPE_INTEGER, &sdi.frame_delay[4],         "debug.frame_delay_4"   },
-  { TYPE_INTEGER, &sdi.frame_delay[5],         "debug.frame_delay_5"   },
-  { TYPE_INTEGER, &sdi.frame_delay[6],         "debug.frame_delay_6"   },
-  { TYPE_INTEGER, &sdi.frame_delay[7],         "debug.frame_delay_7"   },
-  { TYPE_INTEGER, &sdi.frame_delay[8],         "debug.frame_delay_8"   },
-  { TYPE_INTEGER, &sdi.frame_delay[9],         "debug.frame_delay_9"   },
-  { TYPE_KEY_X11, &sdi.frame_delay_key[0],     "debug.key.frame_delay_0" },
-  { TYPE_KEY_X11, &sdi.frame_delay_key[1],     "debug.key.frame_delay_1" },
-  { TYPE_KEY_X11, &sdi.frame_delay_key[2],     "debug.key.frame_delay_2" },
-  { TYPE_KEY_X11, &sdi.frame_delay_key[3],     "debug.key.frame_delay_3" },
-  { TYPE_KEY_X11, &sdi.frame_delay_key[4],     "debug.key.frame_delay_4" },
-  { TYPE_KEY_X11, &sdi.frame_delay_key[5],     "debug.key.frame_delay_5" },
-  { TYPE_KEY_X11, &sdi.frame_delay_key[6],     "debug.key.frame_delay_6" },
-  { TYPE_KEY_X11, &sdi.frame_delay_key[7],     "debug.key.frame_delay_7" },
-  { TYPE_KEY_X11, &sdi.frame_delay_key[8],     "debug.key.frame_delay_8" },
-  { TYPE_KEY_X11, &sdi.frame_delay_key[9],     "debug.key.frame_delay_9" },
-  { TYPE_BOOLEAN, &sdi.frame_delay_use_mod_key,"debug.frame_delay.use_mod_key"},
-  { TYPE_BOOLEAN, &sdi.frame_delay_game_only,  "debug.frame_delay.game_only" },
-  { TYPE_BOOLEAN, &sdi.show_frames_per_second, "debug.show_frames_per_second" },
+  {
+    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"
+  },
 };
 
 static struct TokenInfo options_setup_tokens[] =
 {
-  { TYPE_BOOLEAN, &soi.verbose,                "options.verbose"               },
+  {
+    TYPE_BOOLEAN,
+    &setup.options.verbose,                    "options.verbose"
+  },
 };
 
 static char *get_corrected_login_name(char *login_name)
@@ -9116,14 +9410,6 @@ void setHideSetupEntry(void *setup_value)
     setHashEntry(hide_setup_hash, hide_setup_token, "");
 }
 
-static void setHideSetupEntryRaw(char *token_text, void *setup_value_raw)
-{
-  // !!! DIRTY WORKAROUND; TO BE FIXED AFTER THE MM ENGINE RELEASE !!!
-  void *setup_value = setup_value_raw - (void *)&si + (void *)&setup;
-
-  setHideSetupEntry(setup_value);
-}
-
 boolean hideSetupEntry(void *setup_value)
 {
   char *hide_setup_token = getHideSetupToken(setup_value);
@@ -9144,7 +9430,7 @@ static void setSetupInfoFromTokenText(SetupFileHash *setup_file_hash,
 
   // check if this setup option should be hidden in the setup menu
   if (token_hide_value != NULL && get_boolean_from_string(token_hide_value))
-    setHideSetupEntryRaw(token_text, token_info[token_nr].value);
+    setHideSetupEntry(token_info[token_nr].value);
 }
 
 static void setSetupInfoFromTokenInfo(SetupFileHash *setup_file_hash,
@@ -9165,13 +9451,9 @@ static void decodeSetupFileHash(SetupFileHash *setup_file_hash)
   if (hide_setup_hash == NULL)
     hide_setup_hash = newSetupFileHash();
 
-  // global setup
-  si = setup;
-  for (i = 0; i < NUM_GLOBAL_SETUP_TOKENS; i++)
+  for (i = 0; i < ARRAY_SIZE(global_setup_tokens); i++)
     setSetupInfoFromTokenInfo(setup_file_hash, global_setup_tokens, i);
-  setup = si;
 
-  // virtual buttons setup
   setup.touch.grid_initialized = TRUE;
   for (i = 0; i < 2; i++)
   {
@@ -9210,27 +9492,20 @@ static void decodeSetupFileHash(SetupFileHash *setup_file_hash)
     }
   }
 
-  // editor setup
-  sei = setup.editor;
-  for (i = 0; i < NUM_EDITOR_SETUP_TOKENS; i++)
+  for (i = 0; i < ARRAY_SIZE(editor_setup_tokens); i++)
     setSetupInfoFromTokenInfo(setup_file_hash, editor_setup_tokens, i);
-  setup.editor = sei;
 
-  // shortcut setup
-  ssi = setup.shortcut;
-  for (i = 0; i < NUM_SHORTCUT_SETUP_TOKENS; i++)
+  for (i = 0; i < ARRAY_SIZE(shortcut_setup_tokens); i++)
     setSetupInfoFromTokenInfo(setup_file_hash, shortcut_setup_tokens, i);
-  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++)
+    setup_input = setup.input[pnr];
+    for (i = 0; i < ARRAY_SIZE(player_setup_tokens); i++)
     {
       char full_token[100];
 
@@ -9238,32 +9513,20 @@ static void decodeSetupFileHash(SetupFileHash *setup_file_hash)
       setSetupInfoFromTokenText(setup_file_hash, player_setup_tokens, i,
                                full_token);
     }
-    setup.input[pnr] = sii;
+    setup.input[pnr] = setup_input;
   }
 
-  // system setup
-  syi = setup.system;
-  for (i = 0; i < NUM_SYSTEM_SETUP_TOKENS; i++)
+  for (i = 0; i < ARRAY_SIZE(system_setup_tokens); i++)
     setSetupInfoFromTokenInfo(setup_file_hash, system_setup_tokens, i);
-  setup.system = syi;
 
-  // internal setup
-  sxi = setup.internal;
-  for (i = 0; i < NUM_INTERNAL_SETUP_TOKENS; i++)
+  for (i = 0; i < ARRAY_SIZE(internal_setup_tokens); i++)
     setSetupInfoFromTokenInfo(setup_file_hash, internal_setup_tokens, i);
-  setup.internal = sxi;
 
-  // debug setup
-  sdi = setup.debug;
-  for (i = 0; i < NUM_DEBUG_SETUP_TOKENS; i++)
+  for (i = 0; i < ARRAY_SIZE(debug_setup_tokens); i++)
     setSetupInfoFromTokenInfo(setup_file_hash, debug_setup_tokens, i);
-  setup.debug = sdi;
 
-  // options setup
-  soi = setup.options;
-  for (i = 0; i < NUM_OPTIONS_SETUP_TOKENS; i++)
+  for (i = 0; i < ARRAY_SIZE(options_setup_tokens); i++)
     setSetupInfoFromTokenInfo(setup_file_hash, options_setup_tokens, i);
-  setup.options = soi;
 
   setHideRelatedSetupEntries();
 }
@@ -9275,13 +9538,10 @@ static void decodeSetupFileHash_AutoSetup(SetupFileHash *setup_file_hash)
   if (!setup_file_hash)
     return;
 
-  // auto setup
-  sasi = setup.auto_setup;
-  for (i = 0; i < NUM_AUTO_SETUP_TOKENS; i++)
+  for (i = 0; i < ARRAY_SIZE(auto_setup_tokens); i++)
     setSetupInfo(auto_setup_tokens, i,
                 getHashEntry(setup_file_hash,
                              auto_setup_tokens[i].text));
-  setup.auto_setup = sasi;
 }
 
 static void decodeSetupFileHash_EditorCascade(SetupFileHash *setup_file_hash)
@@ -9291,13 +9551,10 @@ static void decodeSetupFileHash_EditorCascade(SetupFileHash *setup_file_hash)
   if (!setup_file_hash)
     return;
 
-  // editor cascade setup
-  seci = setup.editor_cascade;
-  for (i = 0; i < NUM_EDITOR_CASCADE_SETUP_TOKENS; i++)
+  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));
-  setup.editor_cascade = seci;
 }
 
 void LoadSetupFromFilename(char *filename)
@@ -9463,24 +9720,21 @@ void SaveSetup(void)
 
   fprintFileHeader(file, SETUP_FILENAME);
 
-  // global setup
-  si = setup;
-  for (i = 0; i < NUM_GLOBAL_SETUP_TOKENS; i++)
+  for (i = 0; i < ARRAY_SIZE(global_setup_tokens); i++)
   {
     // just to make things nicer :)
-    if (i == SETUP_TOKEN_PLAYER_NAME + 1 ||
-       i == SETUP_TOKEN_GRAPHICS_SET ||
-       i == SETUP_TOKEN_VOLUME_SIMPLE ||
-       i == SETUP_TOKEN_NETWORK_MODE ||
-       i == SETUP_TOKEN_TOUCH_CONTROL_TYPE ||
-       i == SETUP_TOKEN_TOUCH_GRID_XSIZE_0 ||
-       i == SETUP_TOKEN_TOUCH_GRID_XSIZE_1)
+    if (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));
   }
 
-  // virtual buttons setup
   for (i = 0; i < 2; i++)
   {
     int grid_xsize = setup.touch.grid_xsize[i];
@@ -9509,19 +9763,14 @@ void SaveSetup(void)
     }
   }
 
-  // editor setup
-  sei = setup.editor;
   fprintf(file, "\n");
-  for (i = 0; i < NUM_EDITOR_SETUP_TOKENS; i++)
+  for (i = 0; i < ARRAY_SIZE(editor_setup_tokens); i++)
     fprintf(file, "%s\n", getSetupLine(editor_setup_tokens, "", i));
 
-  // shortcut setup
-  ssi = setup.shortcut;
   fprintf(file, "\n");
-  for (i = 0; i < NUM_SHORTCUT_SETUP_TOKENS; i++)
+  for (i = 0; i < ARRAY_SIZE(shortcut_setup_tokens); i++)
     fprintf(file, "%s\n", getSetupLine(shortcut_setup_tokens, "", i));
 
-  // player setup
   for (pnr = 0; pnr < MAX_PLAYERS; pnr++)
   {
     char prefix[30];
@@ -9529,30 +9778,23 @@ void SaveSetup(void)
     sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
     fprintf(file, "\n");
 
-    sii = setup.input[pnr];
-    for (i = 0; i < NUM_PLAYER_SETUP_TOKENS; i++)
+    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));
   }
 
-  // system setup
-  syi = setup.system;
   fprintf(file, "\n");
-  for (i = 0; i < NUM_SYSTEM_SETUP_TOKENS; i++)
+  for (i = 0; i < ARRAY_SIZE(system_setup_tokens); i++)
     fprintf(file, "%s\n", getSetupLine(system_setup_tokens, "", i));
 
-  // internal setup
   // (internal setup values not saved to user setup file)
 
-  // debug setup
-  sdi = setup.debug;
   fprintf(file, "\n");
-  for (i = 0; i < NUM_DEBUG_SETUP_TOKENS; i++)
+  for (i = 0; i < ARRAY_SIZE(debug_setup_tokens); i++)
     fprintf(file, "%s\n", getSetupLine(debug_setup_tokens, "", i));
 
-  // options setup
-  soi = setup.options;
   fprintf(file, "\n");
-  for (i = 0; i < NUM_OPTIONS_SETUP_TOKENS; i++)
+  for (i = 0; i < ARRAY_SIZE(options_setup_tokens); i++)
     fprintf(file, "%s\n", getSetupLine(options_setup_tokens, "", i));
 
   fclose(file);
@@ -9577,8 +9819,7 @@ void SaveSetup_AutoSetup(void)
 
   fprintFileHeader(file, AUTOSETUP_FILENAME);
 
-  sasi = setup.auto_setup;
-  for (i = 0; i < NUM_AUTO_SETUP_TOKENS; i++)
+  for (i = 0; i < ARRAY_SIZE(auto_setup_tokens); i++)
     fprintf(file, "%s\n", getSetupLine(auto_setup_tokens, "", i));
 
   fclose(file);
@@ -9605,8 +9846,7 @@ void SaveSetup_EditorCascade(void)
 
   fprintFileHeader(file, EDITORCASCADE_FILENAME);
 
-  seci = setup.editor_cascade;
-  for (i = 0; i < NUM_EDITOR_CASCADE_SETUP_TOKENS; i++)
+  for (i = 0; i < ARRAY_SIZE(editor_cascade_setup_tokens); i++)
     fprintf(file, "%s\n", getSetupLine(editor_cascade_setup_tokens, "", i));
 
   fclose(file);
@@ -9701,6 +9941,273 @@ static int getElementFromToken(char *token)
   return EL_UNDEFINED;
 }
 
+// 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
+    return (next_char == ',' || next_char == '\0' ||
+           next_char == ' ' || next_char == '\t' ? TRUE : FALSE);
+  }
+
+  // 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(char *s)
+{
+  char *pattern_1 = "click:anim_";
+  char *pattern_2 = ".part_";
+  char *matching_char = NULL;
+  char *s_ptr = s;
+  int result = ANIM_EVENT_NONE;
+
+  matching_char = strstr(s_ptr, pattern_1);
+  if (matching_char == NULL)
+    return ANIM_EVENT_NONE;
+
+  s_ptr = matching_char + strlen(pattern_1);
+
+  // 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_action_parameter_value(char *token)
+{
+  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)
+    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, "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, "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 :
+             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 = ANIM_EVENT_DEFAULT;
+
+    if (string_has_parameter(value, "any"))
+      result |= ANIM_EVENT_ANY;
+
+    if (string_has_parameter(value, "click"))
+      result |= ANIM_EVENT_SELF;
+
+    // add optional "click:anim_X" or "click:anim_X.part_X" parameter
+    result |= get_anim_parameter_value(value);
+  }
+  else if (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_key(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, "passthrough_clicks"))
+      result |= STYLE_PASSTHROUGH;
+
+    if (string_has_parameter(value, "multiple_actions"))
+      result |= STYLE_MULTIPLE_ACTIONS;
+  }
+  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, "crossfade")  ? FADE_MODE_CROSSFADE :
+             string_has_parameter(value, "melt")       ? FADE_MODE_MELT :
+             string_has_parameter(value, "curtain")    ? FADE_MODE_CURTAIN :
+             FADE_MODE_DEFAULT);
+  }
+  else if (strPrefix(suffix, ".font"))         // (may also be ".font_xyz")
+  {
+    result = gfx.get_font_from_token_function(value);
+  }
+  else         // generic parameter of type integer or boolean
+  {
+    result = (strEqual(value, ARG_UNDEFINED) ? ARG_UNDEFINED_VALUE :
+             type == TYPE_INTEGER ? get_integer_from_string(value) :
+             type == TYPE_BOOLEAN ? get_boolean_from_string(value) :
+             ARG_UNDEFINED_VALUE);
+  }
+
+  free(value);
+
+  return result;
+}
+
 static int get_token_parameter_value(char *token, char *value_raw)
 {
   char *suffix;
@@ -9842,7 +10349,7 @@ static void InitMenuDesignSettings_SpecialPostProcessing(void)
 
     { NULL,                    NULL                    }
   };
-  int i;
+  int i, j;
 
   // special case: initialize later added SETUP list size from LEVELS value
   if (menu.list_size[GAME_MODE_SETUP] == -1)
@@ -9853,6 +10360,237 @@ static void InitMenuDesignSettings_SpecialPostProcessing(void)
     if ((*game_buttons_xy[i].dst).x == -1 &&
        (*game_buttons_xy[i].dst).y == -1)
       *game_buttons_xy[i].dst = *game_buttons_xy[i].src;
+
+  // --------------------------------------------------------------------------
+  // dynamic viewports (including playfield margins, borders and alignments)
+  // --------------------------------------------------------------------------
+
+  // dynamic viewports currently only supported for landscape mode
+  int display_width  = MAX(video.display_width, video.display_height);
+  int display_height = MIN(video.display_width, video.display_height);
+
+  for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
+  {
+    struct RectWithBorder *vp_window    = &viewport.window[i];
+    struct RectWithBorder *vp_playfield = &viewport.playfield[i];
+    struct RectWithBorder *vp_door_1    = &viewport.door_1[i];
+    struct RectWithBorder *vp_door_2    = &viewport.door_2[i];
+    boolean dynamic_window_width     = (vp_window->min_width     != -1);
+    boolean dynamic_window_height    = (vp_window->min_height    != -1);
+    boolean dynamic_playfield_width  = (vp_playfield->min_width  != -1);
+    boolean dynamic_playfield_height = (vp_playfield->min_height != -1);
+
+    // adjust window size if min/max width/height is specified
+
+    if (vp_window->min_width != -1)
+    {
+      int window_width = display_width;
+
+      // when using static window height, use aspect ratio of display
+      if (vp_window->min_height == -1)
+       window_width = vp_window->height * display_width / display_height;
+
+      vp_window->width = MAX(vp_window->min_width, window_width);
+    }
+
+    if (vp_window->min_height != -1)
+    {
+      int window_height = display_height;
+
+      // when using static window width, use aspect ratio of display
+      if (vp_window->min_width == -1)
+       window_height = vp_window->width * display_height / display_width;
+
+      vp_window->height = MAX(vp_window->min_height, window_height);
+    }
+
+    if (vp_window->max_width != -1)
+      vp_window->width = MIN(vp_window->width, vp_window->max_width);
+
+    if (vp_window->max_height != -1)
+      vp_window->height = MIN(vp_window->height, vp_window->max_height);
+
+    int playfield_width  = vp_window->width;
+    int playfield_height = vp_window->height;
+
+    // adjust playfield size and position according to specified margins
+
+    playfield_width  -= vp_playfield->margin_left;
+    playfield_width  -= vp_playfield->margin_right;
+
+    playfield_height -= vp_playfield->margin_top;
+    playfield_height -= vp_playfield->margin_bottom;
+
+    // adjust playfield size if min/max width/height is specified
+
+    if (vp_playfield->min_width != -1)
+      vp_playfield->width = MAX(vp_playfield->min_width, playfield_width);
+
+    if (vp_playfield->min_height != -1)
+      vp_playfield->height = MAX(vp_playfield->min_height, playfield_height);
+
+    if (vp_playfield->max_width != -1)
+      vp_playfield->width = MIN(vp_playfield->width, vp_playfield->max_width);
+
+    if (vp_playfield->max_height != -1)
+      vp_playfield->height = MIN(vp_playfield->height,vp_playfield->max_height);
+
+    // adjust playfield position according to specified alignment
+
+    if (vp_playfield->align == ALIGN_LEFT || vp_playfield->x > 0)
+      vp_playfield->x = ALIGNED_VP_XPOS(vp_playfield);
+    else if (vp_playfield->align == ALIGN_CENTER)
+      vp_playfield->x = playfield_width / 2 - vp_playfield->width / 2;
+    else if (vp_playfield->align == ALIGN_RIGHT)
+      vp_playfield->x += playfield_width - vp_playfield->width;
+
+    if (vp_playfield->valign == VALIGN_TOP || vp_playfield->y > 0)
+      vp_playfield->y = ALIGNED_VP_YPOS(vp_playfield);
+    else if (vp_playfield->valign == VALIGN_MIDDLE)
+      vp_playfield->y = playfield_height / 2 - vp_playfield->height / 2;
+    else if (vp_playfield->valign == VALIGN_BOTTOM)
+      vp_playfield->y += playfield_height - vp_playfield->height;
+
+    vp_playfield->x += vp_playfield->margin_left;
+    vp_playfield->y += vp_playfield->margin_top;
+
+    // adjust individual playfield borders if only default border is specified
+
+    if (vp_playfield->border_left == -1)
+      vp_playfield->border_left = vp_playfield->border_size;
+    if (vp_playfield->border_right == -1)
+      vp_playfield->border_right = vp_playfield->border_size;
+    if (vp_playfield->border_top == -1)
+      vp_playfield->border_top = vp_playfield->border_size;
+    if (vp_playfield->border_bottom == -1)
+      vp_playfield->border_bottom = vp_playfield->border_size;
+
+    // set dynamic playfield borders if borders are specified as undefined
+    // (but only if window size was dynamic and playfield size was static)
+
+    if (dynamic_window_width && !dynamic_playfield_width)
+    {
+      if (vp_playfield->border_left == -1)
+      {
+       vp_playfield->border_left = (vp_playfield->x -
+                                    vp_playfield->margin_left);
+       vp_playfield->x     -= vp_playfield->border_left;
+       vp_playfield->width += vp_playfield->border_left;
+      }
+
+      if (vp_playfield->border_right == -1)
+      {
+       vp_playfield->border_right = (vp_window->width -
+                                     vp_playfield->x -
+                                     vp_playfield->width -
+                                     vp_playfield->margin_right);
+       vp_playfield->width += vp_playfield->border_right;
+      }
+    }
+
+    if (dynamic_window_height && !dynamic_playfield_height)
+    {
+      if (vp_playfield->border_top == -1)
+      {
+       vp_playfield->border_top = (vp_playfield->y -
+                                   vp_playfield->margin_top);
+       vp_playfield->y      -= vp_playfield->border_top;
+       vp_playfield->height += vp_playfield->border_top;
+      }
+
+      if (vp_playfield->border_bottom == -1)
+      {
+       vp_playfield->border_bottom = (vp_window->height -
+                                      vp_playfield->y -
+                                      vp_playfield->height -
+                                      vp_playfield->margin_bottom);
+       vp_playfield->height += vp_playfield->border_bottom;
+      }
+    }
+
+    // adjust playfield size to be a multiple of a defined alignment tile size
+
+    int align_size = vp_playfield->align_size;
+    int playfield_xtiles = vp_playfield->width  / align_size;
+    int playfield_ytiles = vp_playfield->height / align_size;
+    int playfield_width_corrected  = playfield_xtiles * align_size;
+    int playfield_height_corrected = playfield_ytiles * align_size;
+    boolean is_playfield_mode = (i == GFX_SPECIAL_ARG_PLAYING ||
+                                i == GFX_SPECIAL_ARG_EDITOR);
+
+    if (is_playfield_mode &&
+       dynamic_playfield_width &&
+       vp_playfield->width != playfield_width_corrected)
+    {
+      int playfield_xdiff = vp_playfield->width - playfield_width_corrected;
+
+      vp_playfield->width = playfield_width_corrected;
+
+      if (vp_playfield->align == ALIGN_LEFT)
+      {
+       vp_playfield->border_left += playfield_xdiff;
+      }
+      else if (vp_playfield->align == ALIGN_RIGHT)
+      {
+       vp_playfield->border_right += playfield_xdiff;
+      }
+      else if (vp_playfield->align == ALIGN_CENTER)
+      {
+       int border_left_diff  = playfield_xdiff / 2;
+       int border_right_diff = playfield_xdiff - border_left_diff;
+
+       vp_playfield->border_left  += border_left_diff;
+       vp_playfield->border_right += border_right_diff;
+      }
+    }
+
+    if (is_playfield_mode &&
+       dynamic_playfield_height &&
+       vp_playfield->height != playfield_height_corrected)
+    {
+      int playfield_ydiff = vp_playfield->height - playfield_height_corrected;
+
+      vp_playfield->height = playfield_height_corrected;
+
+      if (vp_playfield->valign == VALIGN_TOP)
+      {
+       vp_playfield->border_top += playfield_ydiff;
+      }
+      else if (vp_playfield->align == VALIGN_BOTTOM)
+      {
+       vp_playfield->border_right += playfield_ydiff;
+      }
+      else if (vp_playfield->align == VALIGN_MIDDLE)
+      {
+       int border_top_diff    = playfield_ydiff / 2;
+       int border_bottom_diff = playfield_ydiff - border_top_diff;
+
+       vp_playfield->border_top    += border_top_diff;
+       vp_playfield->border_bottom += border_bottom_diff;
+      }
+    }
+
+    // adjust door positions according to specified alignment
+
+    for (j = 0; j < 2; j++)
+    {
+      struct RectWithBorder *vp_door = (j == 0 ? vp_door_1 : vp_door_2);
+
+      if (vp_door->align == ALIGN_LEFT || vp_door->x > 0)
+       vp_door->x = ALIGNED_VP_XPOS(vp_door);
+      else if (vp_door->align == ALIGN_CENTER)
+       vp_door->x = vp_window->width / 2 - vp_door->width / 2;
+      else if (vp_door->align == ALIGN_RIGHT)
+       vp_door->x += vp_window->width - vp_door->width;
+
+      if (vp_door->valign == VALIGN_TOP || vp_door->y > 0)
+       vp_door->y = ALIGNED_VP_YPOS(vp_door);
+      else if (vp_door->valign == VALIGN_MIDDLE)
+       vp_door->y = vp_window->height / 2 - vp_door->height / 2;
+      else if (vp_door->valign == VALIGN_BOTTOM)
+       vp_door->y += vp_window->height - vp_door->height;
+    }
+  }
 }
 
 static void InitMenuDesignSettings_SpecialPostProcessing_AfterGraphics(void)
@@ -9894,6 +10632,40 @@ static void InitMenuDesignSettings_SpecialPostProcessing_AfterGraphics(void)
       *editor_buttons_xy[i].dst = *editor_buttons_xy[i].src;
     }
   }
+
+  // adjust editor palette rows and columns if specified to be dynamic
+
+  if (editor.palette.cols == -1)
+  {
+    int vp_width = viewport.playfield[GFX_SPECIAL_ARG_EDITOR].width;
+    int bt_width = graphic_info[IMG_EDITOR_PALETTE_BUTTON].width;
+    int sc_width = graphic_info[IMG_EDITOR_PALETTE_SCROLLBAR].width;
+
+    editor.palette.cols = (vp_width - sc_width) / bt_width;
+
+    if (editor.palette.x == -1)
+    {
+      int palette_width = editor.palette.cols * bt_width + sc_width;
+
+      editor.palette.x = (vp_width - palette_width) / 2;
+    }
+  }
+
+  if (editor.palette.rows == -1)
+  {
+    int vp_height = viewport.playfield[GFX_SPECIAL_ARG_EDITOR].height;
+    int bt_height = graphic_info[IMG_EDITOR_PALETTE_BUTTON].height;
+    int tx_height = getFontHeight(FONT_TEXT_2);
+
+    editor.palette.rows = (vp_height - tx_height) / bt_height;
+
+    if (editor.palette.y == -1)
+    {
+      int palette_height = editor.palette.rows * bt_height + tx_height;
+
+      editor.palette.y = (vp_height - palette_height) / 2;
+    }
+  }
 }
 
 static void LoadMenuDesignSettingsFromFilename(char *filename)
@@ -10140,7 +10912,22 @@ static void LoadMenuDesignSettingsFromFilename(char *filename)
         { ".y",                        &vp_struct[j].struct_ptr->y             },
         { ".width",            &vp_struct[j].struct_ptr->width         },
         { ".height",           &vp_struct[j].struct_ptr->height        },
-        { ".border_size",      &vp_struct[j].struct_ptr->border_size   }
+        { ".min_width",                &vp_struct[j].struct_ptr->min_width     },
+        { ".min_height",       &vp_struct[j].struct_ptr->min_height    },
+        { ".max_width",                &vp_struct[j].struct_ptr->max_width     },
+        { ".max_height",       &vp_struct[j].struct_ptr->max_height    },
+        { ".margin_left",      &vp_struct[j].struct_ptr->margin_left   },
+        { ".margin_right",     &vp_struct[j].struct_ptr->margin_right  },
+        { ".margin_top",       &vp_struct[j].struct_ptr->margin_top    },
+        { ".margin_bottom",    &vp_struct[j].struct_ptr->margin_bottom },
+        { ".border_left",      &vp_struct[j].struct_ptr->border_left   },
+        { ".border_right",     &vp_struct[j].struct_ptr->border_right  },
+        { ".border_top",       &vp_struct[j].struct_ptr->border_top    },
+        { ".border_bottom",    &vp_struct[j].struct_ptr->border_bottom },
+        { ".border_size",      &vp_struct[j].struct_ptr->border_size   },
+        { ".align_size",       &vp_struct[j].struct_ptr->align_size    },
+        { ".align",            &vp_struct[j].struct_ptr->align         },
+        { ".valign",           &vp_struct[j].struct_ptr->valign        }
       };
 
       for (k = 0; k < ARRAY_SIZE(vp_config); k++)
@@ -10217,6 +11004,25 @@ static void LoadMenuDesignSettingsFromFilename(char *filename)
     }
   }
 
+  // special case: check if network and preview player positions are redefined,
+  // to compare this later against the main menu level preview being redefined
+  struct TokenIntPtrInfo menu_config_players[] =
+  {
+    { "main.network_players.x",        &menu.main.network_players.redefined    },
+    { "main.network_players.y",        &menu.main.network_players.redefined    },
+    { "main.preview_players.x",        &menu.main.preview_players.redefined    },
+    { "main.preview_players.y",        &menu.main.preview_players.redefined    },
+    { "preview.x",             &preview.redefined                      },
+    { "preview.y",             &preview.redefined                      }
+  };
+
+  for (i = 0; i < ARRAY_SIZE(menu_config_players); i++)
+    *menu_config_players[i].value = FALSE;
+
+  for (i = 0; i < ARRAY_SIZE(menu_config_players); i++)
+    if (getHashEntry(setup_file_hash, menu_config_players[i].token) != NULL)
+      *menu_config_players[i].value = TRUE;
+
   // read (and overwrite with) values that may be specified in config file
   for (i = 0; image_config_vars[i].token != NULL; i++)
   {
@@ -10996,30 +11802,26 @@ void CreateLevelSketchImages(void)
 
   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
   {
-    Bitmap *src_bitmap;
-    int src_x, src_y;
     int element = getMappedElement(i);
-    int graphic = el2edimg(element);
     char basename1[16];
     char basename2[16];
     char *filename1;
     char *filename2;
 
-    sprintf(basename1, "%03d.bmp", i);
-    sprintf(basename2, "%03ds.bmp", i);
+    sprintf(basename1, "%04d.bmp", i);
+    sprintf(basename2, "%04ds.bmp", i);
 
     filename1 = getPath2(global.create_images_dir, basename1);
     filename2 = getPath2(global.create_images_dir, basename2);
 
-    getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
-    BlitBitmap(src_bitmap, bitmap1, src_x, src_y, TILEX, TILEY,
-              0, 0);
+    DrawSizedElement(0, 0, element, TILESIZE);
+    BlitBitmap(drawto, bitmap1, SX, SY, TILEX, TILEY, 0, 0);
 
     if (SDL_SaveBMP(bitmap1->surface, filename1) != 0)
       Error(ERR_EXIT, "cannot save level sketch image file '%s'", filename1);
 
-    getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
-    BlitBitmap(src_bitmap, bitmap2, src_x, src_y, MINI_TILEX, MINI_TILEY, 0, 0);
+    DrawSizedElement(0, 0, element, MINI_TILESIZE);
+    BlitBitmap(drawto, bitmap2, SX, SY, MINI_TILEX, MINI_TILEY, 0, 0);
 
     if (SDL_SaveBMP(bitmap2->surface, filename2) != 0)
       Error(ERR_EXIT, "cannot save level sketch image file '%s'", filename2);
@@ -11027,15 +11829,26 @@ void CreateLevelSketchImages(void)
     free(filename1);
     free(filename2);
 
+    // create corresponding SQL statements (for normal and small images)
+    if (i < 1000)
+    {
+      printf("insert into phpbb_words values (NULL, '`%03d', '<IMG class=\"levelsketch\" src=\"/I/%04d.png\"/>');\n", i, i);
+      printf("insert into phpbb_words values (NULL, '¸%03d', '<IMG class=\"levelsketch\" src=\"/I/%04ds.png\"/>');\n", i, i);
+    }
+
+    printf("insert into phpbb_words values (NULL, '`%04d', '<IMG class=\"levelsketch\" src=\"/I/%04d.png\"/>');\n", i, i);
+    printf("insert into phpbb_words values (NULL, '¸%04d', '<IMG class=\"levelsketch\" src=\"/I/%04ds.png\"/>');\n", i, i);
+
+    // optional: create content for forum level sketch demonstration post
     if (options.debug)
-      printf("%03d `%03d%c", i, i, (i % 10 < 9 ? ' ' : '\n'));
+      fprintf(stderr, "%03d `%03d%c", i, i, (i % 10 < 9 ? ' ' : '\n'));
   }
 
   FreeBitmap(bitmap1);
   FreeBitmap(bitmap2);
 
   if (options.debug)
-    printf("\n");
+    fprintf(stderr, "\n");
 
   Error(ERR_INFO, "%d normal and small images created", NUM_FILE_ELEMENTS);
 
@@ -11059,7 +11872,7 @@ void CreateCustomElementImages(char *directory)
   int yoffset_ge = (TILEY * NUM_CUSTOM_ELEMENTS / 16);
   int i;
 
-  SDLInitVideoDisplay();
+  InitVideoDefaults();
 
   ReCreateBitmap(&backbuffer, video.width, video.height);