changed global animations (esp. toons) to be controlled by game mode
[rocksndiamonds.git] / src / main.c
index dee69a89c61169174073848ffec7e1b8254559bc..7593e01714a4239cf1e647f29afdce5fdfac4ee8 100644 (file)
@@ -1,15 +1,13 @@
-/***********************************************************
-* Rocks'n'Diamonds -- McDuffin Strikes Back!               *
-*----------------------------------------------------------*
-* (c) 1995-2006 Artsoft Entertainment                      *
-*               Holger Schemel                             *
-*               Detmolder Strasse 189                      *
-*               33604 Bielefeld                            *
-*               Germany                                    *
-*               e-mail: info@artsoft.org                   *
-*----------------------------------------------------------*
-* main.c                                                   *
-***********************************************************/
+// ============================================================================
+// Rocks'n'Diamonds - McDuffin Strikes Back!
+// ----------------------------------------------------------------------------
+// (c) 1995-2014 by Artsoft Entertainment
+//                         Holger Schemel
+//                 info@artsoft.org
+//                 http://www.artsoft.org/
+// ----------------------------------------------------------------------------
+// main.c
+// ============================================================================
 
 #include "libgame/libgame.h"
 
 #include "init.h"
 #include "game.h"
 #include "tape.h"
+#include "tools.h"
+#include "files.h"
 #include "events.h"
 #include "config.h"
 
+Bitmap                *bitmap_db_store;
 Bitmap                *bitmap_db_cross;
 Bitmap                *bitmap_db_field;
 Bitmap                *bitmap_db_panel;
-Bitmap                *bitmap_db_door;
+Bitmap                *bitmap_db_door_1;
+Bitmap                *bitmap_db_door_2;
+Bitmap                *bitmap_db_toons;
 DrawBuffer            *fieldbuffer;
 DrawBuffer            *drawto_field;
 
 int                    game_status = -1;
+boolean                        game_status_last_screen = -1;
 boolean                        level_editor_test_game = FALSE;
 boolean                        network_playing = FALSE;
 
@@ -38,9 +42,6 @@ SDL_Thread           *server_thread;
 
 int                    key_joystick_mapping = 0;
 
-boolean                        redraw[MAX_BUF_XSIZE][MAX_BUF_YSIZE];
-int                    redraw_x1 = 0, redraw_y1 = 0;
-
 short                  Feld[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 short                  MovPos[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 short                  MovDir[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
@@ -74,19 +75,54 @@ int                         GfxRandom[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 int                    GfxElement[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 int                    GfxAction[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 int                    GfxDir[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+int                    GfxRedraw[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+
+int                    ActiveElement[MAX_NUM_ELEMENTS];
+int                    ActiveButton[NUM_IMAGE_FILES];
+int                    ActiveFont[NUM_FONTS];
 
 int                    lev_fieldx, lev_fieldy;
 int                    scroll_x, scroll_y;
 
-int                    FX = SX, FY = SY;
+int                    WIN_XSIZE = WIN_XSIZE_DEFAULT;
+int                    WIN_YSIZE = WIN_YSIZE_DEFAULT;
+
+int                    SCR_FIELDX = SCR_FIELDX_DEFAULT;
+int                    SCR_FIELDY = SCR_FIELDY_DEFAULT;
+
+int                    REAL_SX = 6, REAL_SY = 6;
+int                    SX = 8, SY = 8;
+int                    DX = 566, DY = 60;
+int                    VX = 566, VY = 400;
+int                    EX = 566, EY = 356;
+int                    dDX, dDY;
+
+int                    FULL_SXSIZE = 2 + SXSIZE_DEFAULT + 2;
+int                    FULL_SYSIZE = 2 + SYSIZE_DEFAULT + 2;
+int                    SXSIZE = SXSIZE_DEFAULT;
+int                    SYSIZE = SYSIZE_DEFAULT;
+
+int                    FADE_SX = 6, FADE_SY = 6;
+int                    FADE_SXSIZE = 2 + SXSIZE_DEFAULT + 2;
+int                    FADE_SYSIZE = 2 + SXSIZE_DEFAULT + 2;
+
+int                    DXSIZE = 100;
+int                    DYSIZE = 280;
+int                    VXSIZE = 100;
+int                    VYSIZE = 100;
+int                    EXSIZE = 100;
+int                    EYSIZE = 144;
+int                    TILESIZE_VAR = TILESIZE;
+
+int                    FX, FY;
 int                    ScrollStepSize;
 int                    ScreenMovDir = MV_NONE, ScreenMovPos = 0;
 int                    ScreenGfxPos = 0;
 int                    BorderElement = EL_STEELWALL;
 int                    GameFrameDelay = GAME_FRAME_DELAY;
 int                    FfwdFrameDelay = FFWD_FRAME_DELAY;
-int                    BX1 = 0, BY1 = 0;
-int                    BX2 = SCR_FIELDX - 1, BY2 = SCR_FIELDY - 1;
+int                    BX1, BY1;
+int                    BX2, BY2;
 int                    SBX_Left, SBX_Right;
 int                    SBY_Upper, SBY_Lower;
 int                    ZX, ZY;
@@ -106,16 +142,41 @@ struct SetupInfo  setup;
 struct GameInfo                game;
 struct GlobalInfo      global;
 struct BorderInfo      border;
-struct TitleInfo       title;
+struct ViewportInfo    viewport;
+struct TitleFadingInfo fading;
+struct TitleFadingInfo title_initial_default;
+struct TitleFadingInfo title_default;
+struct TitleMessageInfo        titlescreen_initial_default;
+struct TitleMessageInfo        titlescreen_initial_first[MAX_NUM_TITLE_IMAGES];
+struct TitleMessageInfo        titlescreen_initial[MAX_NUM_TITLE_IMAGES];
+struct TitleMessageInfo        titlescreen_default;
+struct TitleMessageInfo        titlescreen_first[MAX_NUM_TITLE_IMAGES];
+struct TitleMessageInfo        titlescreen[MAX_NUM_TITLE_IMAGES];
+struct TitleMessageInfo        titlemessage_initial_default;
+struct TitleMessageInfo        titlemessage_initial_first[MAX_NUM_TITLE_MESSAGES];
+struct TitleMessageInfo        titlemessage_initial[MAX_NUM_TITLE_MESSAGES];
+struct TitleMessageInfo        titlemessage_default;
+struct TitleMessageInfo        titlemessage_first[MAX_NUM_TITLE_MESSAGES];
+struct TitleMessageInfo        titlemessage[MAX_NUM_TITLE_MESSAGES];
+struct TitleMessageInfo        readme;
+struct InitInfo                init, init_last;
 struct MenuInfo                menu;
 struct DoorInfo                door_1, door_2;
+struct RequestInfo     request;
 struct PreviewInfo     preview;
+struct EditorInfo      editor;
+
 struct GraphicInfo     *graphic_info = NULL;
 struct SoundInfo       *sound_info = NULL;
 struct MusicInfo       *music_info = NULL;
 struct MusicFileInfo   *music_file_info = NULL;
 struct HelpAnimInfo    *helpanim_info = NULL;
+
 SetupFileHash          *helptext_info = NULL;
+SetupFileHash         *image_config_hash = NULL;
+SetupFileHash         *element_token_hash = NULL;
+SetupFileHash         *graphic_token_hash = NULL;
+SetupFileHash         *font_token_hash = NULL;
 
 
 /* ------------------------------------------------------------------------- */
@@ -1050,37 +1111,37 @@ struct ElementNameInfo element_name_info[MAX_NUM_ELEMENTS + 1] =
   {
     "char_copyright",
     "char",
-    "letter '©'"
+    "letter '\xa9'"
   },
   {
     "char_aumlaut",
     "char",
-    "letter 'Ä'"
+    "letter '\xc4'"
   },
   {
     "char_oumlaut",
     "char",
-    "letter 'Ö'"
+    "letter '\xd6'"
   },
   {
     "char_uumlaut",
     "char",
-    "letter 'Ü'"
+    "letter '\xdc'"
   },
   {
     "char_degree",
     "char",
-    "letter '°'"
+    "letter '\xb0'"
   },
   {
     "char_trademark",
     "char",
-    "letter '®'"
+    "letter '\xae'"
   },
   {
     "char_cursor",
     "char",
-    "letter ' '"
+    "letter '\xa0'"
   },
   {
     "char_unused",
@@ -1244,23 +1305,23 @@ struct ElementNameInfo element_name_info[MAX_NUM_ELEMENTS + 1] =
   },
   {
     "sp_gravity_port_right",
-    "sp_port",
-    "gravity port (leading right)"
+    "sp_gravity_port",
+    "gravity-on/off port (leading right)"
   },
   {
     "sp_gravity_port_down",
-    "sp_port",
-    "gravity port (leading down)"
+    "sp_gravity_port",
+    "gravity-on/off port (leading down)"
   },
   {
     "sp_gravity_port_left",
-    "sp_port",
-    "gravity port (leading left)"
+    "sp_gravity_port",
+    "gravity-on/off port (leading left)"
   },
   {
     "sp_gravity_port_up",
-    "sp_port",
-    "gravity port (leading up)"
+    "sp_gravity_port",
+    "gravity-on/off port (leading up)"
   },
   {
     "sp_sniksnak",
@@ -1430,7 +1491,7 @@ struct ElementNameInfo element_name_info[MAX_NUM_ELEMENTS + 1] =
   {
     "dc_gate_white",
     "gate",
-    "white gate"
+    "white door"
   },
   {
     "dc_gate_white_gray",
@@ -3424,43 +3485,43 @@ struct ElementNameInfo element_name_info[MAX_NUM_ELEMENTS + 1] =
   },
   {
     "sp_gravity_on_port_right",
-    "sp_port",
-    "gravity on port (leading right)"
+    "sp_gravity_on_port",
+    "gravity-on port (leading right)"
   },
   {
     "sp_gravity_on_port_down",
-    "sp_port",
-    "gravity on port (leading down)"
+    "sp_gravity_on_port",
+    "gravity-on port (leading down)"
   },
   {
     "sp_gravity_on_port_left",
-    "sp_port",
-    "gravity on port (leading left)"
+    "sp_gravity_on_port",
+    "gravity-on port (leading left)"
   },
   {
     "sp_gravity_on_port_up",
-    "sp_port",
-    "gravity on port (leading up)"
+    "sp_gravity_on_port",
+    "gravity-on port (leading up)"
   },
   {
     "sp_gravity_off_port_right",
-    "sp_port",
-    "gravity off port (leading right)"
+    "sp_gravity_off_port",
+    "gravity-off port (leading right)"
   },
   {
     "sp_gravity_off_port_down",
-    "sp_port",
-    "gravity off port (leading down)"
+    "sp_gravity_off_port",
+    "gravity-off port (leading down)"
   },
   {
     "sp_gravity_off_port_left",
-    "sp_port",
-    "gravity off port (leading left)"
+    "sp_gravity_off_port",
+    "gravity-off port (leading left)"
   },
   {
     "sp_gravity_off_port_up",
-    "sp_port",
-    "gravity off port (leading up)"
+    "sp_gravity_off_port",
+    "gravity-off port (leading up)"
   },
   {
     "balloon_switch_none",
@@ -4110,37 +4171,37 @@ struct ElementNameInfo element_name_info[MAX_NUM_ELEMENTS + 1] =
   {
     "steel_char_copyright",
     "steel_char",
-    "steel letter '©'"
+    "steel letter '\xa9'"
   },
   {
     "steel_char_aumlaut",
     "steel_char",
-    "steel letter 'Ä'"
+    "steel letter '\xc4'"
   },
   {
     "steel_char_oumlaut",
     "steel_char",
-    "steel letter 'Ö'"
+    "steel letter '\xd6'"
   },
   {
     "steel_char_uumlaut",
     "steel_char",
-    "steel letter 'Ü'"
+    "steel letter '\xdc'"
   },
   {
     "steel_char_degree",
     "steel_char",
-    "steel letter '°'"
+    "steel letter '\xb0'"
   },
   {
     "steel_char_trademark",
     "steel_char",
-    "steel letter '®'"
+    "steel letter '\xae'"
   },
   {
     "steel_char_cursor",
     "steel_char",
-    "steel letter ' '"
+    "steel letter '\xa0'"
   },
   {
     "steel_char_unused",
@@ -4442,6 +4503,11 @@ struct ElementNameInfo element_name_info[MAX_NUM_ELEMENTS + 1] =
     "quicksand",
     "fast quicksand (with rock)"
   },
+  {
+    "from_level_template",
+    "from_level_template",
+    "element taken from level template"
+  },
 
   /* ----------------------------------------------------------------------- */
   /* "real" (and therefore drawable) runtime elements                        */
@@ -5063,6 +5129,46 @@ struct ElementNameInfo element_name_info[MAX_NUM_ELEMENTS + 1] =
     "sb_default",
     "-"
   },
+  {
+    "graphic_1",
+    "graphic",
+    "-"
+  },
+  {
+    "graphic_2",
+    "graphic",
+    "-"
+  },
+  {
+    "graphic_3",
+    "graphic",
+    "-"
+  },
+  {
+    "graphic_4",
+    "graphic",
+    "-"
+  },
+  {
+    "graphic_5",
+    "graphic",
+    "-"
+  },
+  {
+    "graphic_6",
+    "graphic",
+    "-"
+  },
+  {
+    "graphic_7",
+    "graphic",
+    "-"
+  },
+  {
+    "graphic_8",
+    "graphic",
+    "-"
+  },
   {
     "internal_clipboard_custom",
     "internal",
@@ -5334,6 +5440,14 @@ struct ElementActionInfo element_action_info[NUM_ACTIONS + 1 + 1] =
   { ".page[30]",               ACTION_PAGE_30,                 FALSE   },
   { ".page[31]",               ACTION_PAGE_31,                 FALSE   },
   { ".page[32]",               ACTION_PAGE_32,                 FALSE   },
+  { ".part_1",                 ACTION_PART_1,                  FALSE   },
+  { ".part_2",                 ACTION_PART_2,                  FALSE   },
+  { ".part_3",                 ACTION_PART_3,                  FALSE   },
+  { ".part_4",                 ACTION_PART_4,                  FALSE   },
+  { ".part_5",                 ACTION_PART_5,                  FALSE   },
+  { ".part_6",                 ACTION_PART_6,                  FALSE   },
+  { ".part_7",                 ACTION_PART_7,                  FALSE   },
+  { ".part_8",                 ACTION_PART_8,                  FALSE   },
   { ".other",                  ACTION_OTHER,                   FALSE   },
 
   /* empty suffix always matches -- check as last entry in InitSoundInfo() */
@@ -5344,256 +5458,49 @@ struct ElementActionInfo element_action_info[NUM_ACTIONS + 1 + 1] =
 
 struct ElementDirectionInfo element_direction_info[NUM_DIRECTIONS_FULL + 1] =
 {
-  { ".left",           MV_BIT_LEFT                     },
-  { ".right",          MV_BIT_RIGHT                    },
-  { ".up",             MV_BIT_UP                       },
-  { ".down",           MV_BIT_DOWN                     },
-  { ".upleft",         MV_BIT_UP                       },
-  { ".upright",                MV_BIT_RIGHT                    },
-  { ".downleft",       MV_BIT_LEFT                     },
-  { ".downright",      MV_BIT_DOWN                     },
+  { ".left",                   MV_BIT_LEFT                             },
+  { ".right",                  MV_BIT_RIGHT                            },
+  { ".up",                     MV_BIT_UP                               },
+  { ".down",                   MV_BIT_DOWN                             },
+  { ".upleft",                 MV_BIT_UP                               },
+  { ".upright",                        MV_BIT_RIGHT                            },
+  { ".downleft",               MV_BIT_LEFT                             },
+  { ".downright",              MV_BIT_DOWN                             },
 
-  { NULL,              0                               }
+  { NULL,                      0                                       }
 };
 
 struct SpecialSuffixInfo special_suffix_info[NUM_SPECIAL_GFX_ARGS + 1 + 1] =
 {
-  { ".[DEFAULT]",      GFX_SPECIAL_ARG_DEFAULT,        },
-  { ".TITLE",          GFX_SPECIAL_ARG_TITLE,          },
-  { ".MESSAGE",                GFX_SPECIAL_ARG_MESSAGE,        },
-  { ".MAIN",           GFX_SPECIAL_ARG_MAIN,           },
-  { ".LEVELS",         GFX_SPECIAL_ARG_LEVELS          },
-  { ".SCORES",         GFX_SPECIAL_ARG_SCORES,         },
-  { ".EDITOR",         GFX_SPECIAL_ARG_EDITOR,         },
-  { ".INFO",           GFX_SPECIAL_ARG_INFO,           },
-  { ".SETUP",          GFX_SPECIAL_ARG_SETUP,          },
-  { ".PLAYING",                GFX_SPECIAL_ARG_PLAYING,        },
-  { ".DOOR",           GFX_SPECIAL_ARG_DOOR,           },
-  { ".PREVIEW",                GFX_SPECIAL_ARG_PREVIEW,        },
-  { ".CRUMBLED",       GFX_SPECIAL_ARG_CRUMBLED,       },
+  { ".[DEFAULT]",              GFX_SPECIAL_ARG_DEFAULT,                },
+  { ".LOADING",                        GFX_SPECIAL_ARG_LOADING,                },
+  { ".TITLE_INITIAL",          GFX_SPECIAL_ARG_TITLE_INITIAL,          },
+  { ".TITLE",                  GFX_SPECIAL_ARG_TITLE,                  },
+  { ".MAIN",                   GFX_SPECIAL_ARG_MAIN,                   },
+  { ".LEVELS",                 GFX_SPECIAL_ARG_LEVELS                  },
+  { ".LEVELNR",                        GFX_SPECIAL_ARG_LEVELNR                 },
+  { ".SCORES",                 GFX_SPECIAL_ARG_SCORES,                 },
+  { ".EDITOR",                 GFX_SPECIAL_ARG_EDITOR,                 },
+  { ".INFO",                   GFX_SPECIAL_ARG_INFO,                   },
+  { ".SETUP",                  GFX_SPECIAL_ARG_SETUP,                  },
+  { ".PLAYING",                        GFX_SPECIAL_ARG_PLAYING,                },
+  { ".DOOR",                   GFX_SPECIAL_ARG_DOOR,                   },
+  { ".TAPE",                   GFX_SPECIAL_ARG_TAPE,                   },
+  { ".PANEL",                  GFX_SPECIAL_ARG_PANEL,                  },
+  { ".PREVIEW",                        GFX_SPECIAL_ARG_PREVIEW,                },
+  { ".CRUMBLED",               GFX_SPECIAL_ARG_CRUMBLED,               },
+  { ".TYPENAME",               GFX_SPECIAL_ARG_TYPENAME,               },
+  { ".MENU",                   GFX_SPECIAL_ARG_MENU,                   },
+  { ".TOONS",                  GFX_SPECIAL_ARG_TOONS,                  },
+  { ".QUIT",                   GFX_SPECIAL_ARG_QUIT,                   },
 
   /* empty suffix always matches -- check as last entry in InitMusicInfo() */
-  { "",                        GFX_SPECIAL_ARG_DEFAULT,        },
+  { "",                                GFX_SPECIAL_ARG_DEFAULT,                },
 
-  { NULL,              0,                              }
+  { NULL,                      0,                                      }
 };
 
-struct TokenIntPtrInfo image_config_vars[] =
-{
-  { "global.num_toons",                &global.num_toons                             },
-
-  { "border.draw_masked.TITLE",         &border.draw_masked[GFX_SPECIAL_ARG_TITLE]   },
-  { "border.draw_masked.MAIN",  &border.draw_masked[GFX_SPECIAL_ARG_MAIN]    },
-  { "border.draw_masked.LEVELS", &border.draw_masked[GFX_SPECIAL_ARG_LEVELS]  },
-  { "border.draw_masked.SCORES", &border.draw_masked[GFX_SPECIAL_ARG_SCORES]  },
-  { "border.draw_masked.EDITOR", &border.draw_masked[GFX_SPECIAL_ARG_EDITOR]  },
-  { "border.draw_masked.INFO",  &border.draw_masked[GFX_SPECIAL_ARG_INFO]    },
-  { "border.draw_masked.SETUP",         &border.draw_masked[GFX_SPECIAL_ARG_SETUP]   },
-  { "border.draw_masked.PLAYING",&border.draw_masked[GFX_SPECIAL_ARG_PLAYING] },
-  { "border.draw_masked.DOOR",  &border.draw_masked[GFX_SPECIAL_ARG_DOOR]    },
-
-  { "title.fade_delay",                &title.fade_delay                             },
-  { "title.post_delay",                &title.post_delay                             },
-  { "title.auto_delay",                &title.auto_delay                             },
-
-  { "menu.fade_delay",         &menu.fade_delay                              },
-  { "menu.post_delay",         &menu.post_delay                              },
-  { "menu.auto_delay",         &menu.auto_delay                              },
-
-  { "menu.draw_xoffset",       &menu.draw_xoffset[GFX_SPECIAL_ARG_DEFAULT]   },
-  { "menu.draw_yoffset",       &menu.draw_yoffset[GFX_SPECIAL_ARG_DEFAULT]   },
-  { "menu.draw_xoffset.MAIN",  &menu.draw_xoffset[GFX_SPECIAL_ARG_MAIN]      },
-  { "menu.draw_yoffset.MAIN",  &menu.draw_yoffset[GFX_SPECIAL_ARG_MAIN]      },
-  { "menu.draw_xoffset.LEVELS",        &menu.draw_xoffset[GFX_SPECIAL_ARG_LEVELS]    },
-  { "menu.draw_yoffset.LEVELS",        &menu.draw_yoffset[GFX_SPECIAL_ARG_LEVELS]    },
-  { "menu.draw_xoffset.SCORES",        &menu.draw_xoffset[GFX_SPECIAL_ARG_SCORES]    },
-  { "menu.draw_yoffset.SCORES",        &menu.draw_yoffset[GFX_SPECIAL_ARG_SCORES]    },
-  { "menu.draw_xoffset.EDITOR",        &menu.draw_xoffset[GFX_SPECIAL_ARG_EDITOR]    },
-  { "menu.draw_yoffset.EDITOR",        &menu.draw_yoffset[GFX_SPECIAL_ARG_EDITOR]    },
-  { "menu.draw_xoffset.INFO",  &menu.draw_xoffset[GFX_SPECIAL_ARG_INFO]      },
-  { "menu.draw_yoffset.INFO",  &menu.draw_yoffset[GFX_SPECIAL_ARG_INFO]      },
-  { "menu.draw_xoffset.INFO[ELEMENTS]",
-    &menu.draw_xoffset_info[GFX_SPECIAL_ARG_INFO_ELEMENTS]                   },
-  { "menu.draw_yoffset.INFO[ELEMENTS]",
-    &menu.draw_yoffset_info[GFX_SPECIAL_ARG_INFO_ELEMENTS]                   },
-  { "menu.draw_xoffset.INFO[MUSIC]",
-    &menu.draw_xoffset_info[GFX_SPECIAL_ARG_INFO_MUSIC]                              },
-  { "menu.draw_yoffset.INFO[MUSIC]",
-    &menu.draw_yoffset_info[GFX_SPECIAL_ARG_INFO_MUSIC]                              },
-  { "menu.draw_xoffset.INFO[CREDITS]",
-    &menu.draw_xoffset_info[GFX_SPECIAL_ARG_INFO_CREDITS]                    },
-  { "menu.draw_yoffset.INFO[CREDITS]",
-    &menu.draw_yoffset_info[GFX_SPECIAL_ARG_INFO_CREDITS]                    },
-  { "menu.draw_xoffset.INFO[PROGRAM]",
-    &menu.draw_xoffset_info[GFX_SPECIAL_ARG_INFO_PROGRAM]                    },
-  { "menu.draw_yoffset.INFO[PROGRAM]",
-    &menu.draw_yoffset_info[GFX_SPECIAL_ARG_INFO_PROGRAM]                    },
-  { "menu.draw_xoffset.INFO[VERSION]",
-    &menu.draw_xoffset_info[GFX_SPECIAL_ARG_INFO_VERSION]                    },
-  { "menu.draw_yoffset.INFO[VERSION]",
-    &menu.draw_yoffset_info[GFX_SPECIAL_ARG_INFO_VERSION]                    },
-  { "menu.draw_xoffset.INFO[LEVELSET]",
-    &menu.draw_xoffset_info[GFX_SPECIAL_ARG_INFO_LEVELSET]                   },
-  { "menu.draw_yoffset.INFO[LEVELSET]",
-    &menu.draw_yoffset_info[GFX_SPECIAL_ARG_INFO_LEVELSET]                   },
-  { "menu.draw_xoffset.SETUP", &menu.draw_xoffset[GFX_SPECIAL_ARG_SETUP]     },
-  { "menu.draw_yoffset.SETUP", &menu.draw_yoffset[GFX_SPECIAL_ARG_SETUP]     },
-
-  { "menu.scrollbar_xoffset",  &menu.scrollbar_xoffset                       },
-
-  { "menu.list_size",          &menu.list_size[GFX_SPECIAL_ARG_DEFAULT]      },
-  { "menu.list_size.LEVELS",   &menu.list_size[GFX_SPECIAL_ARG_LEVELS]       },
-  { "menu.list_size.SCORES",   &menu.list_size[GFX_SPECIAL_ARG_SCORES]       },
-  { "menu.list_size.INFO",     &menu.list_size[GFX_SPECIAL_ARG_INFO]         },
-
-  { "main.button.name.x",              &menu.main.button.name.x              },
-  { "main.button.name.y",              &menu.main.button.name.y              },
-  { "main.button.levels.x",            &menu.main.button.levels.x            },
-  { "main.button.levels.y",            &menu.main.button.levels.y            },
-  { "main.button.scores.x",            &menu.main.button.scores.x            },
-  { "main.button.scores.y",            &menu.main.button.scores.y            },
-  { "main.button.editor.x",            &menu.main.button.editor.x            },
-  { "main.button.editor.y",            &menu.main.button.editor.y            },
-  { "main.button.info.x",              &menu.main.button.info.x              },
-  { "main.button.info.y",              &menu.main.button.info.y              },
-  { "main.button.game.x",              &menu.main.button.game.x              },
-  { "main.button.game.y",              &menu.main.button.game.y              },
-  { "main.button.setup.x",             &menu.main.button.setup.x             },
-  { "main.button.setup.y",             &menu.main.button.setup.y             },
-  { "main.button.quit.x",              &menu.main.button.quit.x              },
-  { "main.button.quit.y",              &menu.main.button.quit.y              },
-
-  { "main.button.prev_level.x",                &menu.main.button.prev_level.x        },
-  { "main.button.prev_level.y",                &menu.main.button.prev_level.y        },
-  { "main.button.next_level.x",                &menu.main.button.next_level.x        },
-  { "main.button.next_level.y",                &menu.main.button.next_level.y        },
-
-  { "main.text.name.x",                        &menu.main.text.name.x                },
-  { "main.text.name.y",                        &menu.main.text.name.y                },
-  { "main.text.name.width",            &menu.main.text.name.width            },
-  { "main.text.name.height",           &menu.main.text.name.height           },
-  { "main.text.name.align",            &menu.main.text.name.align            },
-  { "main.text.levels.x",              &menu.main.text.levels.x              },
-  { "main.text.levels.y",              &menu.main.text.levels.y              },
-  { "main.text.levels.width",          &menu.main.text.levels.width          },
-  { "main.text.levels.height",         &menu.main.text.levels.height         },
-  { "main.text.levels.align",          &menu.main.text.levels.align          },
-  { "main.text.scores.x",              &menu.main.text.scores.x              },
-  { "main.text.scores.y",              &menu.main.text.scores.y              },
-  { "main.text.scores.width",          &menu.main.text.scores.width          },
-  { "main.text.scores.height",         &menu.main.text.scores.height         },
-  { "main.text.scores.align",          &menu.main.text.scores.align          },
-  { "main.text.editor.x",              &menu.main.text.editor.x              },
-  { "main.text.editor.y",              &menu.main.text.editor.y              },
-  { "main.text.editor.width",          &menu.main.text.editor.width          },
-  { "main.text.editor.height",         &menu.main.text.editor.height         },
-  { "main.text.editor.align",          &menu.main.text.editor.align          },
-  { "main.text.info.x",                        &menu.main.text.info.x                },
-  { "main.text.info.y",                        &menu.main.text.info.y                },
-  { "main.text.info.width",            &menu.main.text.info.width            },
-  { "main.text.info.height",           &menu.main.text.info.height           },
-  { "main.text.info.align",            &menu.main.text.info.align            },
-  { "main.text.game.x",                        &menu.main.text.game.x                },
-  { "main.text.game.y",                        &menu.main.text.game.y                },
-  { "main.text.game.width",            &menu.main.text.game.width            },
-  { "main.text.game.height",           &menu.main.text.game.height           },
-  { "main.text.game.align",            &menu.main.text.game.align            },
-  { "main.text.setup.x",               &menu.main.text.setup.x               },
-  { "main.text.setup.y",               &menu.main.text.setup.y               },
-  { "main.text.setup.width",           &menu.main.text.setup.width           },
-  { "main.text.setup.height",          &menu.main.text.setup.height          },
-  { "main.text.setup.align",           &menu.main.text.setup.align           },
-  { "main.text.quit.x",                        &menu.main.text.quit.x                },
-  { "main.text.quit.y",                        &menu.main.text.quit.y                },
-  { "main.text.quit.width",            &menu.main.text.quit.width            },
-  { "main.text.quit.height",           &menu.main.text.quit.height           },
-  { "main.text.quit.align",            &menu.main.text.quit.align            },
-
-  { "main.text.current_level.x",       &menu.main.text.current_level.x       },
-  { "main.text.current_level.y",       &menu.main.text.current_level.y       },
-  { "main.text.current_level.align",   &menu.main.text.current_level.align   },
-  { "main.text.first_level.x",         &menu.main.text.first_level.x         },
-  { "main.text.first_level.y",         &menu.main.text.first_level.y         },
-  { "main.text.first_level.align",     &menu.main.text.first_level.align     },
-  { "main.text.last_level.x",          &menu.main.text.last_level.x          },
-  { "main.text.last_level.y",          &menu.main.text.last_level.y          },
-  { "main.text.last_level.align",      &menu.main.text.last_level.align      },
-  { "main.text.level_info_1.x",                &menu.main.text.level_info_1.x        },
-  { "main.text.level_info_1.y",                &menu.main.text.level_info_1.y        },
-  { "main.text.level_info_1.align",    &menu.main.text.level_info_1.align    },
-  { "main.text.level_info_1.chars",    &menu.main.text.level_info_1.chars    },
-  { "main.text.level_info_2.x",                &menu.main.text.level_info_2.x        },
-  { "main.text.level_info_2.y",                &menu.main.text.level_info_2.y        },
-  { "main.text.level_info_2.align",    &menu.main.text.level_info_2.align    },
-  { "main.text.level_info_2.chars",    &menu.main.text.level_info_2.chars    },
-  { "main.text.title_1.x",             &menu.main.text.title_1.x             },
-  { "main.text.title_1.y",             &menu.main.text.title_1.y             },
-  { "main.text.title_1.align",         &menu.main.text.title_1.align         },
-  { "main.text.title_2.x",             &menu.main.text.title_2.x             },
-  { "main.text.title_2.y",             &menu.main.text.title_2.y             },
-  { "main.text.title_2.align",         &menu.main.text.title_2.align         },
-  { "main.text.title_3.x",             &menu.main.text.title_3.x             },
-  { "main.text.title_3.y",             &menu.main.text.title_3.y             },
-  { "main.text.title_3.align",         &menu.main.text.title_3.align         },
-
-  { "main.input.name.x",               &menu.main.input.name.x               },
-  { "main.input.name.y",               &menu.main.input.name.y               },
-  { "main.input.name.align",           &menu.main.input.name.align           },
-
-  { "preview.x",                       &preview.x                            },
-  { "preview.y",                       &preview.y                            },
-  { "preview.align",                   &preview.align                        },
-  { "preview.xsize",                   &preview.xsize                        },
-  { "preview.ysize",                   &preview.ysize                        },
-  { "preview.xoffset",                 &preview.xoffset                      },
-  { "preview.yoffset",                 &preview.yoffset                      },
-  { "preview.tile_size",               &preview.tile_size                    },
-  { "preview.step_offset",             &preview.step_offset                  },
-  { "preview.step_delay",              &preview.step_delay                   },
-  { "preview.anim_mode",               &preview.anim_mode                    },
-
-  { "door_1.width",                    &door_1.width                         },
-  { "door_1.height",                   &door_1.height                        },
-  { "door_1.step_offset",              &door_1.step_offset                   },
-  { "door_1.step_delay",               &door_1.step_delay                    },
-  { "door_1.anim_mode",                        &door_1.anim_mode                     },
-  { "door_2.width",                    &door_2.width                         },
-  { "door_2.height",                   &door_2.height                        },
-  { "door_2.step_offset",              &door_2.step_offset                   },
-  { "door_2.step_delay",               &door_2.step_delay                    },
-  { "door_2.anim_mode",                        &door_2.anim_mode                     },
-
-  { "game.panel.level.x",              &game.panel.level.x                   },
-  { "game.panel.level.y",              &game.panel.level.y                   },
-  { "game.panel.level.align",          &game.panel.level.align               },
-  { "game.panel.level.digits",         &game.panel.level.chars               },
-  { "game.panel.gems.x",               &game.panel.gems.x                    },
-  { "game.panel.gems.y",               &game.panel.gems.y                    },
-  { "game.panel.gems.align",           &game.panel.gems.align                },
-  { "game.panel.gems.digits",          &game.panel.gems.chars                },
-  { "game.panel.inventory.x",          &game.panel.inventory.x               },
-  { "game.panel.inventory.y",          &game.panel.inventory.y               },
-  { "game.panel.inventory.align",      &game.panel.inventory.align           },
-  { "game.panel.inventory.digits",     &game.panel.inventory.chars           },
-  { "game.panel.keys.x",               &game.panel.keys.x                    },
-  { "game.panel.keys.y",               &game.panel.keys.y                    },
-  { "game.panel.keys.align",           &game.panel.keys.align                },
-  { "game.panel.score.x",              &game.panel.score.x                   },
-  { "game.panel.score.y",              &game.panel.score.y                   },
-  { "game.panel.score.align",          &game.panel.score.align               },
-  { "game.panel.score.digits",         &game.panel.score.chars               },
-  { "game.panel.time.x",               &game.panel.time.x                    },
-  { "game.panel.time.y",               &game.panel.time.y                    },
-  { "game.panel.time.align",           &game.panel.time.align                },
-  { "game.panel.time.digits",          &game.panel.time.chars                },
-
-  { "[player].boring_delay_fixed",     &game.player_boring_delay_fixed       },
-  { "[player].boring_delay_random",    &game.player_boring_delay_random      },
-  { "[player].sleeping_delay_fixed",   &game.player_sleeping_delay_fixed     },
-  { "[player].sleeping_delay_random",  &game.player_sleeping_delay_random    },
-
-  { NULL,                              NULL,                                 }
-};
+#include "conf_var.c"  /* include auto-generated data structure definitions */
 
 
 /* ------------------------------------------------------------------------- */
@@ -5628,6 +5535,7 @@ struct FontInfo font_info[NUM_FONTS + 1] =
   { "font.envelope_2"          },
   { "font.envelope_3"          },
   { "font.envelope_4"          },
+  { "font.request"             },
   { "font.input_1.active"      },
   { "font.input_2.active"      },
   { "font.input_1"             },
@@ -5643,6 +5551,33 @@ struct FontInfo font_info[NUM_FONTS + 1] =
   { "font.game_info"           },
   { "font.info.elements"       },
   { "font.info.levelset"       },
+
+  { NULL                       }
+};
+
+struct GlobalAnimInfo global_anim_info[NUM_GLOBAL_ANIM_TOKENS + 1] =
+{
+  /* (real) graphic definitions used to define animation graphics */
+  { "global.anim_1.gfx",       },
+  { "global.anim_2.gfx",       },
+  { "global.anim_3.gfx",       },
+  { "global.anim_4.gfx",       },
+  { "global.anim_5.gfx",       },
+  { "global.anim_6.gfx",       },
+  { "global.anim_7.gfx",       },
+  { "global.anim_8.gfx",       },
+
+  /* (dummy) graphic definitions used to define animation controls */
+  { "global.anim_1",           },
+  { "global.anim_2",           },
+  { "global.anim_3",           },
+  { "global.anim_4",           },
+  { "global.anim_5",           },
+  { "global.anim_6",           },
+  { "global.anim_7",           },
+  { "global.anim_8",           },
+
+  { NULL                       }
 };
 
 
@@ -5664,51 +5599,143 @@ struct MusicPrefixInfo music_prefix_info[NUM_MUSIC_PREFIXES + 1] =
 
 static void print_usage()
 {
-  printf("\n"
-        "Usage: %s [OPTION]... [HOSTNAME [PORT]]\n"
-        "\n"
-        "Options:\n"
-        "  -d, --display HOSTNAME[:SCREEN]  specify X server display\n"
-        "  -b, --basepath DIRECTORY         alternative base DIRECTORY\n"
-        "  -l, --level DIRECTORY            alternative level DIRECTORY\n"
-        "  -g, --graphics DIRECTORY         alternative graphics DIRECTORY\n"
-        "  -s, --sounds DIRECTORY           alternative sounds DIRECTORY\n"
-        "  -m, --music DIRECTORY            alternative music DIRECTORY\n"
-        "  -n, --network                    network multiplayer game\n"
-        "      --serveronly                 only start network server\n"
-        "  -v, --verbose                    verbose mode\n"
-        "      --debug                      display debugging information\n"
-        "  -e, --execute COMMAND            execute batch COMMAND\n"
-        "\n"
-        "Valid commands for '--execute' option:\n"
-        "  \"print graphicsinfo.conf\"        print default graphics config\n"
-        "  \"print soundsinfo.conf\"          print default sounds config\n"
-        "  \"print musicinfo.conf\"           print default music config\n"
-        "  \"print editorsetup.conf\"         print default editor config\n"
-        "  \"print helpanim.conf\"            print default helpanim config\n"
-        "  \"print helptext.conf\"            print default helptext config\n"
-        "  \"dump level FILE\"                dump level data from FILE\n"
-        "  \"dump tape FILE\"                 dump tape data from FILE\n"
-        "  \"autoplay LEVELDIR [NR ...]\"     play level tapes for LEVELDIR\n"
-        "  \"convert LEVELDIR [NR]\"          convert levels in LEVELDIR\n"
-        "\n",
-        program.command_basename);
+  Print("\n"
+       "Usage: %s [OPTION]... [HOSTNAME [PORT]]\n"
+       "\n"
+       "Options:\n"
+       "  -d, --display HOSTNAME[:SCREEN]  specify X server display\n"
+       "  -b, --basepath DIRECTORY         alternative base DIRECTORY\n"
+       "  -l, --level DIRECTORY            alternative level DIRECTORY\n"
+       "  -g, --graphics DIRECTORY         alternative graphics DIRECTORY\n"
+       "  -s, --sounds DIRECTORY           alternative sounds DIRECTORY\n"
+       "  -m, --music DIRECTORY            alternative music DIRECTORY\n"
+       "  -n, --network                    network multiplayer game\n"
+       "      --serveronly                 only start network server\n"
+       "  -v, --verbose                    verbose mode\n"
+       "  -V, --version                    show program version\n"
+       "      --debug                      display debugging information\n"
+       "  -e, --execute COMMAND            execute batch COMMAND\n"
+       "\n"
+       "Valid commands for '--execute' option:\n"
+       "  \"print graphicsinfo.conf\"        print default graphics config\n"
+       "  \"print soundsinfo.conf\"          print default sounds config\n"
+       "  \"print musicinfo.conf\"           print default music config\n"
+       "  \"print editorsetup.conf\"         print default editor config\n"
+       "  \"print helpanim.conf\"            print default helpanim config\n"
+       "  \"print helptext.conf\"            print default helptext config\n"
+       "  \"dump level FILE\"                dump level data from FILE\n"
+       "  \"dump tape FILE\"                 dump tape data from FILE\n"
+       "  \"autotest LEVELDIR [NR ...]\"     test level tapes for LEVELDIR\n"
+       "  \"autoplay LEVELDIR [NR ...]\"     play level tapes for LEVELDIR\n"
+       "  \"autoffwd LEVELDIR [NR ...]\"     ffwd level tapes for LEVELDIR\n"
+       "  \"convert LEVELDIR [NR]\"          convert levels in LEVELDIR\n"
+       "  \"create images DIRECTORY\"        write BMP images to DIRECTORY\n"
+       "  \"create CE image DIRECTORY\"      write BMP image to DIRECTORY\n"
+       "\n",
+       program.command_basename);
 }
 
-int main(int argc, char *argv[])
+static void print_version()
 {
-  char * window_title_string = getWindowTitleString();
+  Print("%s %d.%d.%d.%d\n",
+       PROGRAM_TITLE_STRING,
+       PROGRAM_VERSION_MAJOR,
+       PROGRAM_VERSION_MINOR,
+       PROGRAM_VERSION_PATCH,
+       PROGRAM_VERSION_BUILD);
 
-  InitProgramInfo(argv[0], USERDATA_DIRECTORY, USERDATA_DIRECTORY_UNIX,
-                 PROGRAM_TITLE_STRING, window_title_string, ICON_TITLE_STRING,
-                 X11_ICON_FILENAME, X11_ICONMASK_FILENAME, SDL_ICON_FILENAME,
-                 MSDOS_POINTER_FILENAME,
-                 COOKIE_PREFIX, FILENAME_PREFIX, GAME_VERSION_ACTUAL);
+  if (options.debug)
+  {
+    SDL_version sdl_version;
+
+    SDL_VERSION(&sdl_version);
+    Print("- SDL %d.%d.%d\n",
+         sdl_version.major,
+         sdl_version.minor,
+         sdl_version.patch);
+
+    SDL_IMAGE_VERSION(&sdl_version);
+    Print("- SDL_image %d.%d.%d\n",
+         sdl_version.major,
+         sdl_version.minor,
+         sdl_version.patch);
+
+    SDL_MIXER_VERSION(&sdl_version);
+    Print("- SDL_mixer %d.%d.%d\n",
+         sdl_version.major,
+         sdl_version.minor,
+         sdl_version.patch);
+
+    SDL_NET_VERSION(&sdl_version);
+    Print("- SDL_net %d.%d.%d\n",
+         sdl_version.major,
+         sdl_version.minor,
+         sdl_version.patch);
+  }
+}
+
+static void InitProgramConfig(char *command_filename)
+{
+  char *program_title = PROGRAM_TITLE_STRING;
+  char *program_icon_file = PROGRAM_ICON_FILENAME;
+  char *config_filename = getProgramConfigFilename(command_filename);
+  char *userdata_basename = getBaseNameNoSuffix(command_filename);
+  char *userdata_subdir;
+  char *userdata_subdir_unix;
+
+  // read default program config, if existing
+  if (fileExists(config_filename))
+  {
+    // if program config file exists, derive Unix user data directory from it
+    userdata_basename = getBaseName(config_filename);
+
+    if (strSuffix(userdata_basename, ".conf"))
+      userdata_basename[strlen(userdata_basename) - 5] = '\0';
+
+    LoadSetupFromFilename(config_filename);
+  }
+
+  // set user data directory for Linux/Unix (but not Mac OS X)
+  userdata_subdir_unix = getStringCat2(".", userdata_basename);
+
+  // set program title from potentially redefined program title
+  if (setup.internal.program_title != NULL &&
+      strlen(setup.internal.program_title) > 0)
+    program_title = getStringCopy(setup.internal.program_title);
+
+  // set program icon file from potentially redefined program icon file
+  if (setup.internal.program_icon_file != NULL &&
+      strlen(setup.internal.program_icon_file) > 0)
+    program_icon_file = getStringCopy(setup.internal.program_icon_file);
+
+#if defined(PLATFORM_WIN32) || defined(PLATFORM_MACOSX)
+  userdata_subdir = program_title;
+#elif defined(PLATFORM_UNIX)
+  userdata_subdir = userdata_subdir_unix;
+#else
+  userdata_subdir = USERDATA_DIRECTORY_OTHER;
+#endif
+
+  InitProgramInfo(command_filename,
+                 config_filename,
+                 userdata_subdir,
+                 program_title,
+                 program_title,
+                 program_icon_file,
+                 COOKIE_PREFIX,
+                 GAME_VERSION_ACTUAL);
+}
+
+int main(int argc, char *argv[])
+{
+  InitProgramConfig(argv[0]);
 
+  InitWindowTitleFunction(getWindowTitleString);
+  InitExitMessageFunction(DisplayExitMessage);
   InitExitFunction(CloseAllAndExit);
   InitPlatformDependentStuff();
 
-  GetOptions(argv, print_usage);
+  GetOptions(argc, argv, print_usage, print_version);
   OpenAll();
 
   EventLoop();