rnd-20140305-1-src
[rocksndiamonds.git] / src / screens.c
1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back!               *
3 *----------------------------------------------------------*
4 * (c) 1995-2006 Artsoft Entertainment                      *
5 *               Holger Schemel                             *
6 *               Detmolder Strasse 189                      *
7 *               33604 Bielefeld                            *
8 *               Germany                                    *
9 *               e-mail: info@artsoft.org                   *
10 *----------------------------------------------------------*
11 * screens.c                                                *
12 ***********************************************************/
13
14 #include "libgame/libgame.h"
15
16 #include "screens.h"
17 #include "events.h"
18 #include "game.h"
19 #include "tools.h"
20 #include "editor.h"
21 #include "files.h"
22 #include "tape.h"
23 #include "cartoons.h"
24 #include "network.h"
25 #include "init.h"
26 #include "config.h"
27
28 /* screens on the info screen */
29 #define INFO_MODE_MAIN                  0
30 #define INFO_MODE_TITLE                 1
31 #define INFO_MODE_ELEMENTS              2
32 #define INFO_MODE_MUSIC                 3
33 #define INFO_MODE_CREDITS               4
34 #define INFO_MODE_PROGRAM               5
35 #define INFO_MODE_VERSION               6
36 #define INFO_MODE_LEVELSET              7
37
38 #define MAX_INFO_MODES                  8
39
40 /* screens on the setup screen */
41 /* (must match GFX_SPECIAL_ARG_SETUP_* values as defined in src/main.h) */
42 /* (should also match corresponding entries in src/conf_gfx.c) */
43 #define SETUP_MODE_MAIN                 0
44 #define SETUP_MODE_GAME                 1
45 #define SETUP_MODE_EDITOR               2
46 #define SETUP_MODE_GRAPHICS             3
47 #define SETUP_MODE_SOUND                4
48 #define SETUP_MODE_ARTWORK              5
49 #define SETUP_MODE_INPUT                6
50 #define SETUP_MODE_SHORTCUTS            7
51 #define SETUP_MODE_SHORTCUTS_1          8
52 #define SETUP_MODE_SHORTCUTS_2          9
53 #define SETUP_MODE_SHORTCUTS_3          10
54 #define SETUP_MODE_SHORTCUTS_4          11
55 #define SETUP_MODE_SHORTCUTS_5          12
56
57 /* sub-screens on the setup screen (generic) */
58 #define SETUP_MODE_CHOOSE_ARTWORK       13
59 #define SETUP_MODE_CHOOSE_OTHER         14
60
61 /* sub-screens on the setup screen (specific) */
62 #define SETUP_MODE_CHOOSE_GAME_SPEED    15
63 #define SETUP_MODE_CHOOSE_SCROLL_DELAY  16
64 #define SETUP_MODE_CHOOSE_SCREEN_MODE   17
65 #define SETUP_MODE_CHOOSE_WINDOW_SIZE   18
66 #define SETUP_MODE_CHOOSE_SCALING_TYPE  19
67 #define SETUP_MODE_CHOOSE_GRAPHICS      20
68 #define SETUP_MODE_CHOOSE_SOUNDS        21
69 #define SETUP_MODE_CHOOSE_MUSIC         22
70 #define SETUP_MODE_CHOOSE_VOLUME_SIMPLE 23
71 #define SETUP_MODE_CHOOSE_VOLUME_LOOPS  24
72 #define SETUP_MODE_CHOOSE_VOLUME_MUSIC  25
73
74 #define MAX_SETUP_MODES                 26
75
76 /* for input setup functions */
77 #define SETUPINPUT_SCREEN_POS_START     0
78 #define SETUPINPUT_SCREEN_POS_END       (SCR_FIELDY - 4)
79 #define SETUPINPUT_SCREEN_POS_EMPTY1    (SETUPINPUT_SCREEN_POS_START + 3)
80 #define SETUPINPUT_SCREEN_POS_EMPTY2    (SETUPINPUT_SCREEN_POS_END - 1)
81
82 /* for various menu stuff  */
83 #define MENU_SCREEN_START_XPOS          1
84 #define MENU_SCREEN_START_YPOS          2
85 #define MENU_SCREEN_VALUE_XPOS          14
86 #define MENU_SCREEN_MAX_XPOS            (SCR_FIELDX - 1)
87 #define MENU_TITLE1_YPOS                8
88 #define MENU_TITLE2_YPOS                46
89 #define MENU_SCREEN_INFO_XSTART         16
90 #define MENU_SCREEN_INFO_YSTART1        100
91 #define MENU_SCREEN_INFO_YSTART2        128
92 #define MENU_SCREEN_INFO_YSTEP          (TILEY + 4)
93 #define MENU_SCREEN_INFO_YBOTTOM        (SYSIZE - 20)
94 #define MENU_SCREEN_INFO_YSIZE          (MENU_SCREEN_INFO_YBOTTOM -     \
95                                          MENU_SCREEN_INFO_YSTART2 -     \
96                                          TILEY / 2)
97 #define MAX_INFO_ELEMENTS_ON_SCREEN     128
98 #if 1
99 #define NUM_INFO_ELEMENTS_ON_SCREEN     MIN(MENU_SCREEN_INFO_YSIZE /    \
100                                             MENU_SCREEN_INFO_YSTEP,     \
101                                             MAX_INFO_ELEMENTS_ON_SCREEN)
102 #else
103 #define NUM_INFO_ELEMENTS_ON_SCREEN     10
104 #endif
105 #define MAX_MENU_ENTRIES_ON_SCREEN      (SCR_FIELDY - MENU_SCREEN_START_YPOS)
106 #define MAX_MENU_TEXT_LENGTH_BIG        (MENU_SCREEN_VALUE_XPOS -       \
107                                          MENU_SCREEN_START_XPOS)
108 #define MAX_MENU_TEXT_LENGTH_MEDIUM     (MAX_MENU_TEXT_LENGTH_BIG * 2)
109
110 /* buttons and scrollbars identifiers */
111 #define SCREEN_CTRL_ID_PREV_LEVEL       0
112 #define SCREEN_CTRL_ID_NEXT_LEVEL       1
113 #define SCREEN_CTRL_ID_PREV_PLAYER      2
114 #define SCREEN_CTRL_ID_NEXT_PLAYER      3
115 #define SCREEN_CTRL_ID_SCROLL_UP        4
116 #define SCREEN_CTRL_ID_SCROLL_DOWN      5
117 #define SCREEN_CTRL_ID_SCROLL_VERTICAL  6
118
119 #define NUM_SCREEN_GADGETS              7
120
121 #define NUM_SCREEN_MENUBUTTONS          4
122 #define NUM_SCREEN_SCROLLBUTTONS        2
123 #define NUM_SCREEN_SCROLLBARS           1
124
125 #define SCREEN_MASK_MAIN                (1 << 0)
126 #define SCREEN_MASK_INPUT               (1 << 1)
127
128 /* graphic position and size values for buttons and scrollbars */
129 #define SC_MENUBUTTON_XSIZE             TILEX
130 #define SC_MENUBUTTON_YSIZE             TILEY
131
132 #define SC_SCROLLBUTTON_XSIZE           TILEX
133 #define SC_SCROLLBUTTON_YSIZE           TILEY
134
135 #define SC_SCROLLBAR_XPOS               (SXSIZE - SC_SCROLLBUTTON_XSIZE)
136
137 #define SC_SCROLL_VERTICAL_XSIZE        SC_SCROLLBUTTON_XSIZE
138 #define SC_SCROLL_VERTICAL_YSIZE        ((MAX_MENU_ENTRIES_ON_SCREEN - 2) * \
139                                          SC_SCROLLBUTTON_YSIZE)
140
141 #define SC_SCROLL_UP_XPOS               SC_SCROLLBAR_XPOS
142 #define SC_SCROLL_UP_YPOS               (2 * SC_SCROLLBUTTON_YSIZE)
143
144 #define SC_SCROLL_VERTICAL_XPOS         SC_SCROLLBAR_XPOS
145 #define SC_SCROLL_VERTICAL_YPOS         (SC_SCROLL_UP_YPOS + \
146                                          SC_SCROLLBUTTON_YSIZE)
147
148 #define SC_SCROLL_DOWN_XPOS             SC_SCROLLBAR_XPOS
149 #define SC_SCROLL_DOWN_YPOS             (SC_SCROLL_VERTICAL_YPOS + \
150                                          SC_SCROLL_VERTICAL_YSIZE)
151
152 #define SC_BORDER_SIZE                  14
153
154
155 /* forward declarations of internal functions */
156 static void HandleScreenGadgets(struct GadgetInfo *);
157 static void HandleSetupScreen_Generic(int, int, int, int, int);
158 static void HandleSetupScreen_Input(int, int, int, int, int);
159 static void CustomizeKeyboard(int);
160 static void CalibrateJoystick(int);
161 static void execSetupGame(void);
162 static void execSetupGraphics(void);
163 static void execSetupSound(void);
164 static void execSetupArtwork(void);
165 static void HandleChooseTree(int, int, int, int, int, TreeInfo **);
166
167 static void DrawChooseLevelSet(void);
168 static void DrawChooseLevelNr(void);
169 static void DrawInfoScreen(void);
170 static void DrawAndFadeInInfoScreen(int);
171 static void DrawSetupScreen(void);
172
173 static void DrawInfoScreenExt(int, int);
174 static void DrawInfoScreen_NotAvailable(char *, char *);
175 static void DrawInfoScreen_HelpAnim(int, int, boolean);
176 static void DrawInfoScreen_HelpText(int, int, int, int);
177 static void HandleInfoScreen_Main(int, int, int, int, int);
178 static void HandleInfoScreen_TitleScreen(int);
179 static void HandleInfoScreen_Elements(int);
180 static void HandleInfoScreen_Music(int);
181 static void HandleInfoScreen_Credits(int);
182 static void HandleInfoScreen_Program(int);
183 static void HandleInfoScreen_Version(int);
184
185 static void MapScreenMenuGadgets(int);
186 static void MapScreenTreeGadgets(TreeInfo *);
187
188 static struct GadgetInfo *screen_gadget[NUM_SCREEN_GADGETS];
189
190 static int info_mode = INFO_MODE_MAIN;
191 static int setup_mode = SETUP_MODE_MAIN;
192
193 static TreeInfo *screen_modes = NULL;
194 static TreeInfo *screen_mode_current = NULL;
195
196 static TreeInfo *window_sizes = NULL;
197 static TreeInfo *window_size_current = NULL;
198
199 static TreeInfo *scaling_types = NULL;
200 static TreeInfo *scaling_type_current = NULL;
201
202 static TreeInfo *scroll_delays = NULL;
203 static TreeInfo *scroll_delay_current = NULL;
204
205 static TreeInfo *game_speeds = NULL;
206 static TreeInfo *game_speed_current = NULL;
207
208 static TreeInfo *volumes_simple = NULL;
209 static TreeInfo *volume_simple_current = NULL;
210
211 static TreeInfo *volumes_loops = NULL;
212 static TreeInfo *volume_loops_current = NULL;
213
214 static TreeInfo *volumes_music = NULL;
215 static TreeInfo *volume_music_current = NULL;
216
217 static TreeInfo *level_number = NULL;
218 static TreeInfo *level_number_current = NULL;
219
220 static struct
221 {
222   int value;
223   char *text;
224 } window_sizes_list[] =
225 {
226   {     50,     "50 %"                          },
227   {     80,     "80 %"                          },
228   {     90,     "90 %"                          },
229   {     100,    "100 % (Default)"               },
230   {     110,    "110 %"                         },
231   {     120,    "120 %"                         },
232   {     130,    "130 %"                         },
233   {     140,    "140 %"                         },
234   {     150,    "150 %"                         },
235   {     200,    "200 %"                         },
236   {     250,    "250 %"                         },
237   {     300,    "300 %"                         },
238
239   {     -1,     NULL                            },
240 };
241
242 static struct
243 {
244   char *value;
245   char *text;
246 } scaling_types_list[] =
247 {
248   {     SCALING_QUALITY_NEAREST, "None"         },
249   {     SCALING_QUALITY_LINEAR,  "Linear"       },
250   {     SCALING_QUALITY_BEST,    "Anisotropic"  },
251
252   {     NULL,                    NULL           },
253 };
254
255 static struct
256 {
257   int value;
258   char *text;
259 } game_speeds_list[] =
260 {
261 #if 1
262   {     30,     "Very Slow"                     },
263   {     25,     "Slow"                          },
264   {     20,     "Normal"                        },
265   {     15,     "Fast"                          },
266   {     10,     "Very Fast"                     },
267 #else
268   {     1000,   "1/1s (Extremely Slow)"         },
269   {     500,    "1/2s"                          },
270   {     200,    "1/5s"                          },
271   {     100,    "1/10s"                         },
272   {     50,     "1/20s"                         },
273   {     29,     "1/35s (Original Supaplex)"     },
274   {     25,     "1/40s"                         },
275   {     20,     "1/50s (Normal Speed)"          },
276   {     14,     "1/70s (Maximum Supaplex)"      },
277   {     10,     "1/100s"                        },
278   {     5,      "1/200s"                        },
279   {     2,      "1/500s"                        },
280   {     1,      "1/1000s (Extremely Fast)"      },
281 #endif
282
283   {     -1,     NULL                            },
284 };
285
286 static struct
287 {
288   int value;
289   char *text;
290 } scroll_delays_list[] =
291 {
292   {     0,      "0 Tiles (No Scroll Delay)"     },
293   {     1,      "1 Tile"                        },
294   {     2,      "2 Tiles"                       },
295   {     3,      "3 Tiles (Default)"             },
296   {     4,      "4 Tiles"                       },
297   {     5,      "5 Tiles"                       },
298   {     6,      "6 Tiles"                       },
299   {     7,      "7 Tiles"                       },
300   {     8,      "8 Tiles (Maximum Scroll Delay)"},
301
302   {     -1,     NULL                            },
303 };
304
305 static struct
306 {
307   int value;
308   char *text;
309 } volumes_list[] =
310 {
311   {     0,      "0 %"                           },
312   {     10,     "10 %"                          },
313   {     20,     "20 %"                          },
314   {     30,     "30 %"                          },
315   {     40,     "40 %"                          },
316   {     50,     "50 %"                          },
317   {     60,     "60 %"                          },
318   {     70,     "70 %"                          },
319   {     80,     "80 %"                          },
320   {     90,     "90 %"                          },
321   {     100,    "100 %"                         },
322
323   {     -1,     NULL                            },
324 };
325
326 #define DRAW_MODE(s)            ((s) >= GAME_MODE_MAIN &&               \
327                                  (s) <= GAME_MODE_SETUP ? (s) :         \
328                                  (s) == GAME_MODE_PSEUDO_TYPENAME ?     \
329                                  GAME_MODE_MAIN : GAME_MODE_DEFAULT)
330
331 /* (there are no draw offset definitions needed for INFO_MODE_TITLE) */
332 #define DRAW_MODE_INFO(i)       ((i) >= INFO_MODE_ELEMENTS &&           \
333                                  (i) <= INFO_MODE_LEVELSET ? (i) :      \
334                                  INFO_MODE_MAIN)
335
336 #define DRAW_MODE_SETUP(i)      ((i) >= SETUP_MODE_MAIN &&              \
337                                  (i) <= SETUP_MODE_SHORTCUTS_5 ? (i) :  \
338                                  (i) >= SETUP_MODE_CHOOSE_GRAPHICS &&   \
339                                  (i) <= SETUP_MODE_CHOOSE_MUSIC ?       \
340                                  SETUP_MODE_CHOOSE_ARTWORK :            \
341                                  SETUP_MODE_CHOOSE_OTHER)
342
343 #define DRAW_XOFFSET_INFO(i)    (DRAW_MODE_INFO(i) == INFO_MODE_MAIN ?  \
344                                  menu.draw_xoffset[GAME_MODE_INFO] :    \
345                                  menu.draw_xoffset_info[DRAW_MODE_INFO(i)])
346 #define DRAW_YOFFSET_INFO(i)    (DRAW_MODE_INFO(i) == INFO_MODE_MAIN ?  \
347                                  menu.draw_yoffset[GAME_MODE_INFO] :    \
348                                  menu.draw_yoffset_info[DRAW_MODE_INFO(i)])
349
350 #define DRAW_XOFFSET_SETUP(i)   (DRAW_MODE_SETUP(i) == SETUP_MODE_MAIN ? \
351                                  menu.draw_xoffset[GAME_MODE_SETUP] :   \
352                                  menu.draw_xoffset_setup[DRAW_MODE_SETUP(i)])
353 #define DRAW_YOFFSET_SETUP(i)   (DRAW_MODE_SETUP(i) == SETUP_MODE_MAIN ? \
354                                  menu.draw_yoffset[GAME_MODE_SETUP] :   \
355                                  menu.draw_yoffset_setup[DRAW_MODE_SETUP(i)])
356
357 #define DRAW_XOFFSET(s)         ((s) == GAME_MODE_INFO ?                \
358                                  DRAW_XOFFSET_INFO(info_mode) :         \
359                                  (s) == GAME_MODE_SETUP ?               \
360                                  DRAW_XOFFSET_SETUP(setup_mode) :       \
361                                  menu.draw_xoffset[DRAW_MODE(s)])
362 #define DRAW_YOFFSET(s)         ((s) == GAME_MODE_INFO ?                \
363                                  DRAW_YOFFSET_INFO(info_mode) :         \
364                                  (s) == GAME_MODE_SETUP ?               \
365                                  DRAW_YOFFSET_SETUP(setup_mode) :       \
366                                  menu.draw_yoffset[DRAW_MODE(s)])
367
368 #define mSX                     (SX + DRAW_XOFFSET(game_status))
369 #define mSY                     (SY + DRAW_YOFFSET(game_status))
370
371 #define NUM_MENU_ENTRIES_ON_SCREEN (menu.list_size[game_status] > 2 ?   \
372                                     menu.list_size[game_status] :       \
373                                     MAX_MENU_ENTRIES_ON_SCREEN)
374
375 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
376 #define NUM_SCROLLBAR_BITMAPS           2
377 static Bitmap *scrollbar_bitmap[NUM_SCROLLBAR_BITMAPS];
378 #endif
379
380
381 /* title display and control definitions */
382
383 #define MAX_NUM_TITLE_SCREENS   (2 * MAX_NUM_TITLE_IMAGES +             \
384                                  2 * MAX_NUM_TITLE_MESSAGES)
385
386 static int num_title_screens = 0;
387
388 struct TitleControlInfo
389 {
390   boolean is_image;
391   boolean initial;
392   int local_nr;
393   int sort_priority;
394 };
395
396 struct TitleControlInfo title_controls[MAX_NUM_TITLE_SCREENS];
397
398 /* main menu display and control definitions */
399
400 #define MAIN_CONTROL_NAME                       0
401 #define MAIN_CONTROL_LEVELS                     1
402 #define MAIN_CONTROL_SCORES                     2
403 #define MAIN_CONTROL_EDITOR                     3
404 #define MAIN_CONTROL_INFO                       4
405 #define MAIN_CONTROL_GAME                       5
406 #define MAIN_CONTROL_SETUP                      6
407 #define MAIN_CONTROL_QUIT                       7
408 #define MAIN_CONTROL_PREV_LEVEL                 8
409 #define MAIN_CONTROL_NEXT_LEVEL                 9
410 #define MAIN_CONTROL_FIRST_LEVEL                10
411 #define MAIN_CONTROL_LAST_LEVEL                 11
412 #define MAIN_CONTROL_LEVEL_NUMBER               12
413 #define MAIN_CONTROL_LEVEL_INFO_1               13
414 #define MAIN_CONTROL_LEVEL_INFO_2               14
415 #define MAIN_CONTROL_LEVEL_NAME                 15
416 #define MAIN_CONTROL_LEVEL_AUTHOR               16
417 #define MAIN_CONTROL_LEVEL_YEAR                 17
418 #define MAIN_CONTROL_LEVEL_IMPORTED_FROM        18
419 #define MAIN_CONTROL_LEVEL_IMPORTED_BY          19
420 #define MAIN_CONTROL_LEVEL_TESTED_BY            20
421 #define MAIN_CONTROL_TITLE_1                    21
422 #define MAIN_CONTROL_TITLE_2                    22
423 #define MAIN_CONTROL_TITLE_3                    23
424
425 static char str_main_text_name[10];
426 static char str_main_text_first_level[10];
427 static char str_main_text_last_level[10];
428 static char str_main_text_level_number[10];
429
430 static char *main_text_name                     = str_main_text_name;
431 static char *main_text_first_level              = str_main_text_first_level;
432 static char *main_text_last_level               = str_main_text_last_level;
433 static char *main_text_level_number             = str_main_text_level_number;
434 static char *main_text_levels                   = "Levelset";
435 static char *main_text_scores                   = "Hall Of Fame";
436 static char *main_text_editor                   = "Level Creator";
437 static char *main_text_info                     = "Info Screen";
438 static char *main_text_game                     = "Start Game";
439 static char *main_text_setup                    = "Setup";
440 static char *main_text_quit                     = "Quit";
441 static char *main_text_level_name               = level.name;
442 static char *main_text_level_author             = level.author;
443 static char *main_text_level_year               = NULL;
444 static char *main_text_level_imported_from      = NULL;
445 static char *main_text_level_imported_by        = NULL;
446 static char *main_text_level_tested_by          = NULL;
447 static char *main_text_title_1                  = PROGRAM_TITLE_STRING;
448 static char *main_text_title_2                  = PROGRAM_COPYRIGHT_STRING;
449 static char *main_text_title_3                  = PROGRAM_GAME_BY_STRING;
450
451 struct MainControlInfo
452 {
453   int nr;
454
455   struct MenuPosInfo *pos_button;
456   int button_graphic;
457
458   struct TextPosInfo *pos_text;
459   char **text;
460
461   struct TextPosInfo *pos_input;
462   char **input;
463 };
464
465 static struct MainControlInfo main_controls[] =
466 {
467   {
468     MAIN_CONTROL_NAME,
469     &menu.main.button.name,             IMG_MENU_BUTTON_NAME,
470     &menu.main.text.name,               &main_text_name,
471     &menu.main.input.name,              &setup.player_name,
472   },
473   {
474     MAIN_CONTROL_LEVELS,
475     &menu.main.button.levels,           IMG_MENU_BUTTON_LEVELS,
476     &menu.main.text.levels,             &main_text_levels,
477     NULL,                               NULL,
478   },
479   {
480     MAIN_CONTROL_SCORES,
481     &menu.main.button.scores,           IMG_MENU_BUTTON_SCORES,
482     &menu.main.text.scores,             &main_text_scores,
483     NULL,                               NULL,
484   },
485   {
486     MAIN_CONTROL_EDITOR,
487     &menu.main.button.editor,           IMG_MENU_BUTTON_EDITOR,
488     &menu.main.text.editor,             &main_text_editor,
489     NULL,                               NULL,
490   },
491   {
492     MAIN_CONTROL_INFO,
493     &menu.main.button.info,             IMG_MENU_BUTTON_INFO,
494     &menu.main.text.info,               &main_text_info,
495     NULL,                               NULL,
496   },
497   {
498     MAIN_CONTROL_GAME,
499     &menu.main.button.game,             IMG_MENU_BUTTON_GAME,
500     &menu.main.text.game,               &main_text_game,
501     NULL,                               NULL,
502   },
503   {
504     MAIN_CONTROL_SETUP,
505     &menu.main.button.setup,            IMG_MENU_BUTTON_SETUP,
506     &menu.main.text.setup,              &main_text_setup,
507     NULL,                               NULL,
508   },
509   {
510     MAIN_CONTROL_QUIT,
511     &menu.main.button.quit,             IMG_MENU_BUTTON_QUIT,
512     &menu.main.text.quit,               &main_text_quit,
513     NULL,                               NULL,
514   },
515 #if 0
516   /* (these two buttons are real gadgets) */
517   {
518     MAIN_CONTROL_PREV_LEVEL,
519     &menu.main.button.prev_level,       IMG_MENU_BUTTON_PREV_LEVEL,
520     NULL,                               NULL,
521     NULL,                               NULL,
522   },
523   {
524     MAIN_CONTROL_NEXT_LEVEL,
525     &menu.main.button.next_level,       IMG_MENU_BUTTON_NEXT_LEVEL,
526     NULL,                               NULL,
527     NULL,                               NULL,
528   },
529 #endif
530   {
531     MAIN_CONTROL_FIRST_LEVEL,
532     NULL,                               -1,
533     &menu.main.text.first_level,        &main_text_first_level,
534     NULL,                               NULL,
535   },
536   {
537     MAIN_CONTROL_LAST_LEVEL,
538     NULL,                               -1,
539     &menu.main.text.last_level,         &main_text_last_level,
540     NULL,                               NULL,
541   },
542   {
543     MAIN_CONTROL_LEVEL_NUMBER,
544     NULL,                               -1,
545     &menu.main.text.level_number,       &main_text_level_number,
546     NULL,                               NULL,
547   },
548   {
549     MAIN_CONTROL_LEVEL_INFO_1,
550     NULL,                               -1,
551     &menu.main.text.level_info_1,       NULL,
552     NULL,                               NULL,
553   },
554   {
555     MAIN_CONTROL_LEVEL_INFO_2,
556     NULL,                               -1,
557     &menu.main.text.level_info_2,       NULL,
558     NULL,                               NULL,
559   },
560   {
561     MAIN_CONTROL_LEVEL_NAME,
562     NULL,                               -1,
563     &menu.main.text.level_name,         &main_text_level_name,
564     NULL,                               NULL,
565   },
566   {
567     MAIN_CONTROL_LEVEL_AUTHOR,
568     NULL,                               -1,
569     &menu.main.text.level_author,       &main_text_level_author,
570     NULL,                               NULL,
571   },
572   {
573     MAIN_CONTROL_LEVEL_YEAR,
574     NULL,                               -1,
575     &menu.main.text.level_year,         &main_text_level_year,
576     NULL,                               NULL,
577   },
578   {
579     MAIN_CONTROL_LEVEL_IMPORTED_FROM,
580     NULL,                               -1,
581     &menu.main.text.level_imported_from, &main_text_level_imported_from,
582     NULL,                               NULL,
583   },
584   {
585     MAIN_CONTROL_LEVEL_IMPORTED_BY,
586     NULL,                               -1,
587     &menu.main.text.level_imported_by,  &main_text_level_imported_by,
588     NULL,                               NULL,
589   },
590   {
591     MAIN_CONTROL_LEVEL_TESTED_BY,
592     NULL,                               -1,
593     &menu.main.text.level_tested_by,    &main_text_level_tested_by,
594     NULL,                               NULL,
595   },
596   {
597     MAIN_CONTROL_TITLE_1,
598     NULL,                               -1,
599     &menu.main.text.title_1,            &main_text_title_1,
600     NULL,                               NULL,
601   },
602   {
603     MAIN_CONTROL_TITLE_2,
604     NULL,                               -1,
605     &menu.main.text.title_2,            &main_text_title_2,
606     NULL,                               NULL,
607   },
608   {
609     MAIN_CONTROL_TITLE_3,
610     NULL,                               -1,
611     &menu.main.text.title_3,            &main_text_title_3,
612     NULL,                               NULL,
613   },
614
615   {
616     -1,
617     NULL,                               -1,
618     NULL,                               NULL,
619     NULL,                               NULL,
620   }
621 };
622
623
624 static int getTitleScreenGraphic(int nr, boolean initial)
625 {
626   return (initial ? IMG_TITLESCREEN_INITIAL_1 : IMG_TITLESCREEN_1) + nr;
627 }
628
629 static struct TitleMessageInfo *getTitleMessageInfo(int nr, boolean initial)
630 {
631   return (initial ? &titlemessage_initial[nr] : &titlemessage[nr]);
632 }
633
634 #if 0
635 static int getTitleScreenGameMode(boolean initial)
636 {
637   return (initial ? GAME_MODE_TITLE_INITIAL : GAME_MODE_TITLE);
638 }
639 #endif
640
641 static int getTitleMessageGameMode(boolean initial)
642 {
643   return (initial ? GAME_MODE_TITLE_INITIAL : GAME_MODE_TITLE);
644 }
645
646 #if 0
647 static int getTitleScreenBackground(boolean initial)
648 {
649   return (initial ? IMG_BACKGROUND_TITLE_INITIAL : IMG_BACKGROUND_TITLE);
650 }
651 #endif
652
653 #if 0
654 static int getTitleMessageBackground(int nr, boolean initial)
655 {
656   return (initial ? IMG_BACKGROUND_TITLE_INITIAL : IMG_BACKGROUND_TITLE);
657 }
658 #endif
659
660 static int getTitleBackground(int nr, boolean initial, boolean is_image)
661 {
662   int base = (is_image ?
663               (initial ? IMG_BACKGROUND_TITLESCREEN_INITIAL_1 :
664                          IMG_BACKGROUND_TITLESCREEN_1) :
665               (initial ? IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1 :
666                          IMG_BACKGROUND_TITLEMESSAGE_1));
667   int graphic_global = (initial ? IMG_BACKGROUND_TITLE_INITIAL :
668                                   IMG_BACKGROUND_TITLE);
669   int graphic_local = base + nr;
670
671   if (graphic_info[graphic_local].bitmap != NULL)
672     return graphic_local;
673
674   if (graphic_info[graphic_global].bitmap != NULL)
675     return graphic_global;
676
677   return IMG_UNDEFINED;
678 }
679
680 static int getTitleSound(struct TitleControlInfo *tci)
681 {
682   boolean is_image = tci->is_image;
683   int initial = tci->initial;
684   int nr = tci->local_nr;
685   int mode = (initial ? GAME_MODE_TITLE_INITIAL : GAME_MODE_TITLE);
686   int base = (is_image ?
687               (initial ? SND_BACKGROUND_TITLESCREEN_INITIAL_1 :
688                          SND_BACKGROUND_TITLESCREEN_1) :
689               (initial ? SND_BACKGROUND_TITLEMESSAGE_INITIAL_1 :
690                          SND_BACKGROUND_TITLEMESSAGE_1));
691   int sound_global = menu.sound[mode];
692   int sound_local = base + nr;
693
694 #if 0
695   printf("::: %d, %d, %d: %d ['%s'], %d ['%s']\n",
696          nr, initial, is_image,
697          sound_global, getSoundListEntry(sound_global)->filename,
698          sound_local, getSoundListEntry(sound_local)->filename);
699 #endif
700
701   if (!strEqual(getSoundListEntry(sound_local)->filename, UNDEFINED_FILENAME))
702     return sound_local;
703
704   if (!strEqual(getSoundListEntry(sound_global)->filename, UNDEFINED_FILENAME))
705     return sound_global;
706
707   return SND_UNDEFINED;
708 }
709
710 static int getTitleMusic(struct TitleControlInfo *tci)
711 {
712   boolean is_image = tci->is_image;
713   int initial = tci->initial;
714   int nr = tci->local_nr;
715   int mode = (initial ? GAME_MODE_TITLE_INITIAL : GAME_MODE_TITLE);
716   int base = (is_image ?
717               (initial ? MUS_BACKGROUND_TITLESCREEN_INITIAL_1 :
718                          MUS_BACKGROUND_TITLESCREEN_1) :
719               (initial ? MUS_BACKGROUND_TITLEMESSAGE_INITIAL_1 :
720                          MUS_BACKGROUND_TITLEMESSAGE_1));
721   int music_global = menu.music[mode];
722   int music_local = base + nr;
723
724 #if 0
725   printf("::: %d, %d, %d: %d ['%s'], %d ['%s']\n",
726          nr, initial, is_image,
727          music_global, getMusicListEntry(music_global)->filename,
728          music_local, getMusicListEntry(music_local)->filename);
729 #endif
730
731   if (!strEqual(getMusicListEntry(music_local)->filename, UNDEFINED_FILENAME))
732     return music_local;
733
734   if (!strEqual(getMusicListEntry(music_global)->filename, UNDEFINED_FILENAME))
735     return music_global;
736
737   return MUS_UNDEFINED;
738 }
739
740 static struct TitleFadingInfo getTitleFading(struct TitleControlInfo *tci)
741 {
742   boolean is_image = tci->is_image;
743   int initial = tci->initial;
744   int nr = tci->local_nr;
745   struct TitleFadingInfo ti;
746
747   if (is_image)
748   {
749     int graphic = getTitleScreenGraphic(nr, initial);
750
751     /* initialize fading control values to default title config settings */
752     ti = (initial ? title_initial_default : title_default);
753
754     /* override default settings with image config settings, if defined */
755     if (graphic_info[graphic].fade_mode != FADE_MODE_DEFAULT)
756       ti.fade_mode = graphic_info[graphic].fade_mode;
757     if (graphic_info[graphic].fade_delay > -1)
758       ti.fade_delay = graphic_info[graphic].fade_delay;
759     if (graphic_info[graphic].post_delay > -1)
760       ti.post_delay = graphic_info[graphic].post_delay;
761     if (graphic_info[graphic].auto_delay > -1)
762       ti.auto_delay = graphic_info[graphic].auto_delay;
763   }
764   else
765   {
766     if (initial)
767     {
768       ti.fade_mode  = titlemessage_initial[nr].fade_mode;
769       ti.fade_delay = titlemessage_initial[nr].fade_delay;
770       ti.post_delay = titlemessage_initial[nr].post_delay;
771       ti.auto_delay = titlemessage_initial[nr].auto_delay;
772     }
773     else
774     {
775       ti.fade_mode  = titlemessage[nr].fade_mode;
776       ti.fade_delay = titlemessage[nr].fade_delay;
777       ti.post_delay = titlemessage[nr].post_delay;
778       ti.auto_delay = titlemessage[nr].auto_delay;
779     }
780   }
781
782 #if 0
783   if (ti.anim_mode == ANIM_NONE)
784     ti.fade_delay = ti.post_delay = 0;
785 #endif
786
787   return ti;
788 }
789
790 static int compareTitleControlInfo(const void *object1, const void *object2)
791 {
792   const struct TitleControlInfo *tci1 = (struct TitleControlInfo *)object1;
793   const struct TitleControlInfo *tci2 = (struct TitleControlInfo *)object2;
794   int compare_result;
795
796   if (tci1->initial != tci2->initial)
797     compare_result = (tci1->initial ? -1 : +1);
798   else if (tci1->sort_priority != tci2->sort_priority)
799     compare_result = tci1->sort_priority - tci2->sort_priority;
800   else if (tci1->is_image != tci2->is_image)
801     compare_result = (tci1->is_image ? -1 : +1);
802   else
803     compare_result = tci1->local_nr - tci2->local_nr;
804
805   return compare_result;
806 }
807
808 static void InitializeTitleControlsExt_AddTitleInfo(boolean is_image,
809                                                     boolean initial,
810                                                     int nr, int sort_priority)
811 {
812   title_controls[num_title_screens].is_image = is_image;
813   title_controls[num_title_screens].initial = initial;
814   title_controls[num_title_screens].local_nr = nr;
815   title_controls[num_title_screens].sort_priority = sort_priority;
816
817   num_title_screens++;
818 }
819
820 static void InitializeTitleControls_CheckTitleInfo(boolean initial)
821 {
822   int i;
823
824   for (i = 0; i < MAX_NUM_TITLE_IMAGES; i++)
825   {
826     int graphic = getTitleScreenGraphic(i, initial);
827     Bitmap *bitmap = graphic_info[graphic].bitmap;
828     int sort_priority = graphic_info[graphic].sort_priority;
829
830 #if 0
831     /* skip images and messages (fonts!) when using forced custom graphics */
832     if (setup.override_level_graphics && !initial)
833       continue;
834 #endif
835
836     if (bitmap != NULL)
837       InitializeTitleControlsExt_AddTitleInfo(TRUE, initial, i, sort_priority);
838   }
839
840   for (i = 0; i < MAX_NUM_TITLE_MESSAGES; i++)
841   {
842     struct TitleMessageInfo *tmi = getTitleMessageInfo(i, initial);
843     char *filename = getLevelSetTitleMessageFilename(i, initial);
844     int sort_priority = tmi->sort_priority;
845
846 #if 0
847     /* skip images and messages (fonts!) when using forced custom graphics */
848     if (setup.override_level_graphics)
849       continue;
850 #endif
851
852     if (filename != NULL)
853       InitializeTitleControlsExt_AddTitleInfo(FALSE, initial, i, sort_priority);
854   }
855 }
856
857 static void InitializeTitleControls(boolean show_title_initial)
858 {
859   num_title_screens = 0;
860
861 #if 1
862   /* 1st step: initialize title screens for game start (only when starting) */
863   if (show_title_initial)
864     InitializeTitleControls_CheckTitleInfo(TRUE);
865 #endif
866
867   /* 2nd step: initialize title screens for current level set */
868   InitializeTitleControls_CheckTitleInfo(FALSE);
869
870   /* sort title screens according to sort_priority and title number */
871   qsort(title_controls, num_title_screens, sizeof(struct TitleControlInfo),
872         compareTitleControlInfo);
873 }
874
875 static boolean visibleMenuPos(struct MenuPosInfo *pos)
876 {
877   return (pos != NULL && pos->x != -1 && pos->y != -1);
878 }
879
880 static boolean visibleTextPos(struct TextPosInfo *pos)
881 {
882   return (pos != NULL && pos->x != -1 && pos->y != -1);
883 }
884
885 static void InitializeMainControls()
886 {
887   boolean local_team_mode = (!options.network && setup.team_mode);
888   int i;
889
890   /* set main control text values to dynamically determined values */
891   sprintf(main_text_name,         "%s",   local_team_mode ? "Team:" : "Name:");
892
893   strcpy(main_text_first_level,  int2str(leveldir_current->first_level,
894                                          menu.main.text.first_level.size));
895   strcpy(main_text_last_level,   int2str(leveldir_current->last_level,
896                                          menu.main.text.last_level.size));
897   strcpy(main_text_level_number, int2str(level_nr,
898                                          menu.main.text.level_number.size));
899
900   main_text_level_year          = leveldir_current->year;
901   main_text_level_imported_from = leveldir_current->imported_from;
902   main_text_level_imported_by   = leveldir_current->imported_by;
903   main_text_level_tested_by     = leveldir_current->tested_by;
904
905   /* set main control screen positions to dynamically determined values */
906   for (i = 0; main_controls[i].nr != -1; i++)
907   {
908     struct MainControlInfo *mci = &main_controls[i];
909     int nr                         = mci->nr;
910     struct MenuPosInfo *pos_button = mci->pos_button;
911     struct TextPosInfo *pos_text   = mci->pos_text;
912     struct TextPosInfo *pos_input  = mci->pos_input;
913     char *text                     = (mci->text  ? *mci->text  : NULL);
914     char *input                    = (mci->input ? *mci->input : NULL);
915     int button_graphic             = mci->button_graphic;
916 #if 1
917     int font_text                  = (pos_text  ? pos_text->font  : -1);
918     int font_input                 = (pos_input ? pos_input->font : -1);
919 #else
920     int font_text                  = mci->font_text;
921     int font_input                 = mci->font_input;
922 #endif
923
924     int font_text_width   = (font_text  != -1 ? getFontWidth(font_text)   : 0);
925     int font_text_height  = (font_text  != -1 ? getFontHeight(font_text)  : 0);
926     int font_input_width  = (font_input != -1 ? getFontWidth(font_input)  : 0);
927     int font_input_height = (font_input != -1 ? getFontHeight(font_input) : 0);
928     int text_chars  = (text  != NULL ? strlen(text)  : 0);
929     int input_chars = (input != NULL ? strlen(input) : 0);
930
931     int button_width =
932       (button_graphic != -1 ? graphic_info[button_graphic].width  : 0);
933     int button_height =
934       (button_graphic != -1 ? graphic_info[button_graphic].height : 0);
935     int text_width   = font_text_width * text_chars;
936     int text_height  = font_text_height;
937     int input_width  = font_input_width * input_chars;
938     int input_height = font_input_height;
939
940     if (nr == MAIN_CONTROL_NAME)
941     {
942 #if 0
943       if (menu.main.input.name.x == -1)
944         menu.main.input.name.x = menu.main.text.name.x + text_width;
945       if (menu.main.input.name.y == -1)
946         menu.main.input.name.y = menu.main.text.name.y;
947 #endif
948
949 #if 1
950       menu.main.input.name.width  = input_width;
951       menu.main.input.name.height = input_height;
952 #else
953       menu.main.input.name.width  = font_input_width * MAX_PLAYER_NAME_LEN;
954       menu.main.input.name.height = font_input_height;
955 #endif
956     }
957
958     if (pos_button != NULL)             /* (x/y may be -1/-1 here) */
959     {
960       if (pos_button->width == 0)
961         pos_button->width = button_width;
962       if (pos_button->height == 0)
963         pos_button->height = button_height;
964     }
965
966     if (pos_text != NULL)               /* (x/y may be -1/-1 here) */
967     {
968 #if 1
969       /* calculate size for non-clickable text -- needed for text alignment */
970       boolean calculate_text_size = (pos_button == NULL && text != NULL);
971 #else
972       /* calculate width for non-clickable text -- needed for text alignment */
973       boolean calculate_text_width = (pos_button == NULL && text != NULL);
974 #endif
975
976       if (visibleMenuPos(pos_button))
977       {
978         if (pos_text->x == -1)
979           pos_text->x = pos_button->x + pos_button->width;
980         if (pos_text->y == -1)
981           pos_text->y = pos_button->y;
982       }
983
984 #if 1
985       if (pos_text->width == -1 || calculate_text_size)
986         pos_text->width = text_width;
987       if (pos_text->height == -1 || calculate_text_size)
988         pos_text->height = text_height;
989 #else
990       if (pos_text->width == -1 || calculate_text_width)
991         pos_text->width = text_width;
992       if (pos_text->height == -1)
993         pos_text->height = text_height;
994 #endif
995     }
996
997     if (pos_input != NULL)              /* (x/y may be -1/-1 here) */
998     {
999       if (visibleTextPos(pos_text))
1000       {
1001         if (pos_input->x == -1)
1002           pos_input->x = pos_text->x + pos_text->width;
1003         if (pos_input->y == -1)
1004           pos_input->y = pos_text->y;
1005       }
1006
1007       if (pos_input->width == -1)
1008         pos_input->width = input_width;
1009       if (pos_input->height == -1)
1010         pos_input->height = input_height;
1011     }
1012   }
1013 }
1014
1015 static void DrawCursorAndText_Main_Ext(int nr, boolean active_text,
1016                                        boolean active_input)
1017 {
1018   int i;
1019
1020   for (i = 0; main_controls[i].nr != -1; i++)
1021   {
1022     struct MainControlInfo *mci = &main_controls[i];
1023
1024     if (mci->nr == nr || nr == -1)
1025     {
1026       struct MenuPosInfo *pos_button = mci->pos_button;
1027       struct TextPosInfo *pos_text   = mci->pos_text;
1028       struct TextPosInfo *pos_input  = mci->pos_input;
1029       char *text                     = (mci->text  ? *mci->text  : NULL);
1030       char *input                    = (mci->input ? *mci->input : NULL);
1031       int button_graphic             = mci->button_graphic;
1032 #if 1
1033       int font_text                  = (pos_text  ? pos_text->font  : -1);
1034       int font_input                 = (pos_input ? pos_input->font : -1);
1035 #else
1036       int font_text                  = mci->font_text;
1037       int font_input                 = mci->font_input;
1038 #endif
1039
1040       if (active_text)
1041       {
1042         button_graphic = BUTTON_ACTIVE(button_graphic);
1043         font_text = FONT_ACTIVE(font_text);
1044       }
1045
1046       if (active_input)
1047       {
1048         font_input = FONT_ACTIVE(font_input);
1049       }
1050
1051       if (visibleMenuPos(pos_button))
1052       {
1053         struct MenuPosInfo *pos = pos_button;
1054         int x = mSX + pos->x;
1055         int y = mSY + pos->y;
1056
1057         DrawBackgroundForGraphic(x, y, pos->width, pos->height, button_graphic);
1058         DrawFixedGraphicThruMaskExt(drawto, x, y, button_graphic, 0);
1059       }
1060
1061       if (visibleTextPos(pos_text) && text != NULL)
1062       {
1063         struct TextPosInfo *pos = pos_text;
1064         int x = mSX + ALIGNED_TEXT_XPOS(pos);
1065         int y = mSY + ALIGNED_TEXT_YPOS(pos);
1066
1067 #if 1
1068         /* (check why/if this is needed) */
1069         DrawBackgroundForFont(x, y, pos->width, pos->height, font_text);
1070 #endif
1071         DrawText(x, y, text, font_text);
1072       }
1073
1074       if (visibleTextPos(pos_input) && input != NULL)
1075       {
1076         struct TextPosInfo *pos = pos_input;
1077         int x = mSX + ALIGNED_TEXT_XPOS(pos);
1078         int y = mSY + ALIGNED_TEXT_YPOS(pos);
1079
1080 #if 1
1081         /* (check why/if this is needed) */
1082         DrawBackgroundForFont(x, y, pos->width, pos->height, font_input);
1083 #endif
1084         DrawText(x, y, input, font_input);
1085       }
1086     }
1087   }
1088 }
1089
1090 static void DrawCursorAndText_Main(int nr, boolean active_text)
1091 {
1092   DrawCursorAndText_Main_Ext(nr, active_text, FALSE);
1093 }
1094
1095 #if 0
1096 static void DrawCursorAndText_Main_Input(int nr, boolean active_text)
1097 {
1098   DrawCursorAndText_Main_Ext(nr, active_text, TRUE);
1099 }
1100 #endif
1101
1102 static struct MainControlInfo *getMainControlInfo(int nr)
1103 {
1104   int i;
1105
1106   for (i = 0; main_controls[i].nr != -1; i++)
1107     if (main_controls[i].nr == nr)
1108       return &main_controls[i];
1109
1110   return NULL;
1111 }
1112
1113 static boolean insideMenuPosRect(struct MenuPosInfo *rect, int x, int y)
1114 {
1115   if (rect == NULL)
1116     return FALSE;
1117
1118   int rect_x = ALIGNED_TEXT_XPOS(rect);
1119   int rect_y = ALIGNED_TEXT_YPOS(rect);
1120
1121   return (x >= rect_x && x < rect_x + rect->width &&
1122           y >= rect_y && y < rect_y + rect->height);
1123 }
1124
1125 static boolean insideTextPosRect(struct TextPosInfo *rect, int x, int y)
1126 {
1127   if (rect == NULL)
1128     return FALSE;
1129
1130   int rect_x = ALIGNED_TEXT_XPOS(rect);
1131   int rect_y = ALIGNED_TEXT_YPOS(rect);
1132
1133 #if 0
1134   printf("::: insideTextPosRect: (%d, %d), (%d, %d) [%d, %d] (%d, %d) => %d\n",
1135          x, y, rect_x, rect_y, rect->x, rect->y, rect->width, rect->height,
1136          (x >= rect_x && x < rect_x + rect->width &&
1137           y >= rect_y && y < rect_y + rect->height));
1138 #endif
1139
1140   return (x >= rect_x && x < rect_x + rect->width &&
1141           y >= rect_y && y < rect_y + rect->height);
1142 }
1143
1144 static void drawCursorExt(int xpos, int ypos, boolean active, int graphic)
1145 {
1146 #if 1
1147   static int cursor_array[MAX_LEV_FIELDY];
1148 #else
1149   static int cursor_array[SCR_FIELDY];
1150 #endif
1151   int x = mSX + TILEX * xpos;
1152   int y = mSY + TILEY * (MENU_SCREEN_START_YPOS + ypos);
1153
1154   if (xpos == 0)
1155   {
1156     if (graphic != -1)
1157       cursor_array[ypos] = graphic;
1158     else
1159       graphic = cursor_array[ypos];
1160   }
1161
1162   if (active)
1163     graphic = BUTTON_ACTIVE(graphic);
1164
1165   DrawBackgroundForGraphic(x, y, TILEX, TILEY, graphic);
1166   DrawFixedGraphicThruMaskExt(drawto, x, y, graphic, 0);
1167 }
1168
1169 static void initCursor(int ypos, int graphic)
1170 {
1171   drawCursorExt(0, ypos, FALSE, graphic);
1172 }
1173
1174 static void drawCursor(int ypos, boolean active)
1175 {
1176   drawCursorExt(0, ypos, active, -1);
1177 }
1178
1179 static void drawCursorXY(int xpos, int ypos, int graphic)
1180 {
1181   drawCursorExt(xpos, ypos, FALSE, graphic);
1182 }
1183
1184 static void drawChooseTreeCursor(int ypos, boolean active)
1185 {
1186   int last_game_status = game_status;   /* save current game status */
1187
1188 #if 0
1189   /* force LEVELS draw offset on artwork setup screen */
1190   game_status = GAME_MODE_LEVELS;
1191 #endif
1192
1193   drawCursorExt(0, ypos, active, -1);
1194
1195   game_status = last_game_status;       /* restore current game status */
1196 }
1197
1198 void DrawHeadline()
1199 {
1200   DrawTextSCentered(MENU_TITLE1_YPOS, FONT_TITLE_1, PROGRAM_TITLE_STRING);
1201   DrawTextSCentered(MENU_TITLE2_YPOS, FONT_TITLE_2, PROGRAM_COPYRIGHT_STRING);
1202 }
1203
1204 #if 0
1205 static int getPrevlevelButtonPos()
1206 {
1207   return 10;
1208 }
1209
1210 static int getCurrentLevelTextPos()
1211 {
1212   return (getPrevlevelButtonPos() + 1);
1213 }
1214
1215 static int getNextLevelButtonPos()
1216 {
1217   return getPrevlevelButtonPos() + 3 + 1;
1218 }
1219
1220 static int getLevelRangeTextPos()
1221 {
1222   return getNextLevelButtonPos() + 1;
1223 }
1224 #endif
1225
1226 int effectiveGameStatus()
1227 {
1228   if (game_status == GAME_MODE_INFO && info_mode == INFO_MODE_TITLE)
1229     return GAME_MODE_TITLE;
1230
1231   return game_status;
1232 }
1233
1234 void DrawTitleScreenImage(int nr, boolean initial)
1235 {
1236   int graphic = getTitleScreenGraphic(nr, initial);
1237   Bitmap *bitmap = graphic_info[graphic].bitmap;
1238   int width  = graphic_info[graphic].width;
1239   int height = graphic_info[graphic].height;
1240   int src_x = graphic_info[graphic].src_x;
1241   int src_y = graphic_info[graphic].src_y;
1242   int dst_x, dst_y;
1243
1244   if (bitmap == NULL)
1245     return;
1246
1247   if (width > WIN_XSIZE)
1248   {
1249     /* image width too large for window => center image horizontally */
1250     src_x = (width - WIN_XSIZE) / 2;
1251     width = WIN_XSIZE;
1252   }
1253
1254   if (height > WIN_YSIZE)
1255   {
1256     /* image height too large for window => center image vertically */
1257     src_y = (height - WIN_YSIZE) / 2;
1258     height = WIN_YSIZE;
1259   }
1260
1261   /* always display title screens centered */
1262   dst_x = (WIN_XSIZE - width) / 2;
1263   dst_y = (WIN_YSIZE - height) / 2;
1264
1265   SetDrawBackgroundMask(REDRAW_ALL);
1266   SetWindowBackgroundImage(getTitleBackground(nr, initial, TRUE));
1267
1268   ClearRectangleOnBackground(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
1269
1270   if (DrawingOnBackground(dst_x, dst_y))
1271   {
1272     SetClipOrigin(bitmap, bitmap->stored_clip_gc, dst_x - src_x, dst_y - src_y);
1273     BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height, dst_x, dst_y);
1274   }
1275   else
1276     BlitBitmap(bitmap, drawto, src_x, src_y, width, height, dst_x, dst_y);
1277
1278   redraw_mask = REDRAW_ALL;
1279 }
1280
1281 void DrawTitleScreenMessage(int nr, boolean initial)
1282 {
1283   char *filename = getLevelSetTitleMessageFilename(nr, initial);
1284   struct TitleMessageInfo *tmi = getTitleMessageInfo(nr, initial);
1285   int last_game_status = game_status;   /* save current game status */
1286
1287   if (filename == NULL)
1288     return;
1289
1290   /* force TITLE font on title message screen */
1291   game_status = getTitleMessageGameMode(initial);
1292
1293   /* if chars set to "-1", automatically determine by text and font width */
1294   if (tmi->chars == -1)
1295     tmi->chars = tmi->width / getFontWidth(tmi->font);
1296   else
1297     tmi->width = tmi->chars * getFontWidth(tmi->font);
1298
1299   /* if lines set to "-1", automatically determine by text and font height */
1300   if (tmi->lines == -1)
1301     tmi->lines = tmi->height / getFontHeight(tmi->font);
1302   else
1303     tmi->height = tmi->lines * getFontHeight(tmi->font);
1304
1305   SetDrawBackgroundMask(REDRAW_ALL);
1306   SetWindowBackgroundImage(getTitleBackground(nr, initial, FALSE));
1307
1308   ClearRectangleOnBackground(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
1309
1310   DrawTextFile(ALIGNED_TEXT_XPOS(tmi), ALIGNED_TEXT_YPOS(tmi),
1311                filename, tmi->font, tmi->chars, -1, tmi->lines, 0, -1,
1312                tmi->autowrap, tmi->centered, tmi->parse_comments);
1313
1314   game_status = last_game_status;       /* restore current game status */
1315 }
1316
1317 void DrawTitleScreen()
1318 {
1319   KeyboardAutoRepeatOff();
1320
1321 #if 0
1322   SetMainBackgroundImage(IMG_BACKGROUND_TITLE);
1323 #endif
1324
1325   HandleTitleScreen(0, 0, 0, 0, MB_MENU_INITIALIZE);
1326
1327   StopAnimation();
1328 }
1329
1330 boolean CheckTitleScreen(boolean levelset_has_changed)
1331 {
1332   static boolean show_title_initial = TRUE;
1333   boolean show_titlescreen = FALSE;
1334
1335   /* needed to be able to skip title screen, if no image or message defined */
1336   InitializeTitleControls(show_title_initial);
1337
1338   if (setup.show_titlescreen && (show_title_initial || levelset_has_changed))
1339     show_titlescreen = TRUE;
1340
1341   /* show initial title images and messages only once at program start */
1342   show_title_initial = FALSE;
1343
1344   return (show_titlescreen && num_title_screens > 0);
1345 }
1346
1347 void DrawMainMenuExt(int fade_mask, boolean do_fading)
1348 {
1349   static LevelDirTree *leveldir_last_valid = NULL;
1350   boolean levelset_has_changed = FALSE;
1351
1352   LimitScreenUpdates(FALSE);
1353
1354   FadeSetLeaveScreen();
1355
1356   /* do not fade out here -- function may continue and fade on editor screen */
1357
1358   UnmapAllGadgets();
1359   FadeSoundsAndMusic();
1360
1361   KeyboardAutoRepeatOn();
1362   ActivateJoystick();
1363
1364   SetDrawDeactivationMask(REDRAW_NONE);
1365   SetDrawBackgroundMask(REDRAW_FIELD);
1366
1367   audio.sound_deactivated = FALSE;
1368
1369   GetPlayerConfig();
1370
1371   /* needed if last screen was the playing screen, invoked from level editor */
1372   if (level_editor_test_game)
1373   {
1374     game_status = GAME_MODE_EDITOR;
1375     DrawLevelEd();
1376
1377     return;
1378   }
1379
1380   /* needed if last screen was the setup screen and fullscreen state changed */
1381   // (moved to "execSetupGraphics()" to change fullscreen state directly)
1382   // ToggleFullscreenOrChangeWindowScalingIfNeeded();
1383
1384   /* leveldir_current may be invalid (level group, parent link) */
1385   if (!validLevelSeries(leveldir_current))
1386     leveldir_current = getFirstValidTreeInfoEntry(leveldir_last_valid);
1387
1388   if (leveldir_current != leveldir_last_valid)
1389     levelset_has_changed = TRUE;
1390
1391   /* store valid level series information */
1392   leveldir_last_valid = leveldir_current;
1393
1394   init_last = init;                     /* switch to new busy animation */
1395
1396   /* needed if last screen (level choice) changed graphics, sounds or music */
1397   ReloadCustomArtwork(0);
1398
1399   if (redraw_mask & REDRAW_ALL)
1400     fade_mask = REDRAW_ALL;
1401
1402 #if 1
1403   FadeOut(fade_mask);
1404
1405 #if 0
1406   /* needed if last screen was the editor screen */
1407   UndrawSpecialEditorDoor();
1408 #endif
1409
1410 #if 0
1411   if (fade_mask == REDRAW_FIELD)
1412     BackToFront();
1413 #endif
1414 #endif
1415
1416 #if 1
1417   /* needed if different viewport properties defined for menues */
1418   ChangeViewportPropertiesIfNeeded();
1419 #endif
1420
1421 #if 1
1422   /* needed if last screen was the editor screen */
1423   UndrawSpecialEditorDoor();
1424 #endif
1425
1426 #if defined(TARGET_SDL)
1427   SetDrawtoField(DRAW_BACKBUFFER);
1428 #endif
1429
1430   if (CheckTitleScreen(levelset_has_changed))
1431   {
1432     game_status = GAME_MODE_TITLE;
1433
1434     DrawTitleScreen();
1435
1436     return;
1437   }
1438
1439   /* level_nr may have been set to value over handicap with level editor */
1440   if (setup.handicap && level_nr > leveldir_current->handicap_level)
1441     level_nr = leveldir_current->handicap_level;
1442
1443   LoadLevel(level_nr);
1444   LoadScore(level_nr);
1445
1446   SetMainBackgroundImage(IMG_BACKGROUND_MAIN);
1447
1448 #if 1
1449   if (fade_mask == REDRAW_ALL)
1450   {
1451     // int door_state = GetDoorState();
1452
1453     RedrawBackground();
1454
1455     // OpenDoor(door_state | DOOR_NO_DELAY | DOOR_FORCE_REDRAW);
1456   }
1457 #endif
1458
1459   ClearField();
1460
1461   InitializeMainControls();
1462
1463   DrawCursorAndText_Main(-1, FALSE);
1464   DrawPreviewLevelInitial();
1465
1466   HandleMainMenu(0, 0, 0, 0, MB_MENU_INITIALIZE);
1467
1468   TapeStop();
1469   if (TAPE_IS_EMPTY(tape))
1470     LoadTape(level_nr);
1471   DrawCompleteVideoDisplay();
1472
1473   PlayMenuSound();
1474   PlayMenuMusic();
1475
1476   /* create gadgets for main menu screen */
1477   FreeScreenGadgets();
1478   CreateScreenGadgets();
1479
1480   /* map gadgets for main menu screen */
1481   MapTapeButtons();
1482   MapScreenMenuGadgets(SCREEN_MASK_MAIN);
1483
1484 #if 1
1485   if (fade_mask == REDRAW_ALL)
1486   {
1487     int door_state = GetDoorState();
1488
1489     // RedrawBackground();
1490
1491     OpenDoor(door_state | DOOR_NO_DELAY | DOOR_FORCE_REDRAW);
1492   }
1493 #endif
1494
1495   DrawMaskedBorder(REDRAW_ALL);
1496
1497   FadeIn(fade_mask);
1498   FadeSetEnterMenu();
1499
1500 #if 1
1501   /* update screen area with special editor door */
1502   redraw_mask |= REDRAW_ALL;
1503   BackToFront();
1504 #endif
1505
1506   SetMouseCursor(CURSOR_DEFAULT);
1507
1508   InitAnimation();
1509
1510   OpenDoor(DOOR_CLOSE_1 | DOOR_OPEN_2);
1511 }
1512
1513 void DrawAndFadeInMainMenu(int fade_mask)
1514 {
1515   DrawMainMenuExt(fade_mask, TRUE);
1516 }
1517
1518 void DrawMainMenu()
1519 {
1520   DrawMainMenuExt(REDRAW_ALL, FALSE);
1521 }
1522
1523 #if defined(CREATE_SPECIAL_EDITION_RND_JUE)
1524 static void gotoTopLevelDir()
1525 {
1526   /* move upwards to top level directory */
1527   while (leveldir_current->node_parent)
1528   {
1529     /* write a "path" into level tree for easy navigation to last level */
1530     if (leveldir_current->node_parent->node_group->cl_first == -1)
1531     {
1532       int num_leveldirs = numTreeInfoInGroup(leveldir_current);
1533       int leveldir_pos = posTreeInfo(leveldir_current);
1534       int num_page_entries;
1535       int cl_first, cl_cursor;
1536
1537       if (num_leveldirs <= NUM_MENU_ENTRIES_ON_SCREEN)
1538         num_page_entries = num_leveldirs;
1539       else
1540         num_page_entries = NUM_MENU_ENTRIES_ON_SCREEN;
1541
1542       cl_first = MAX(0, leveldir_pos - num_page_entries + 1);
1543       cl_cursor = leveldir_pos - cl_first;
1544
1545       leveldir_current->node_parent->node_group->cl_first = cl_first;
1546       leveldir_current->node_parent->node_group->cl_cursor = cl_cursor;
1547     }
1548
1549     leveldir_current = leveldir_current->node_parent;
1550   }
1551 }
1552 #endif
1553
1554 void HandleTitleScreen(int mx, int my, int dx, int dy, int button)
1555 {
1556   static unsigned int title_delay = 0;
1557   static int title_screen_nr = 0;
1558   static int last_sound = -1, last_music = -1;
1559   boolean return_to_main_menu = FALSE;
1560   boolean use_fading_main_menu = TRUE;
1561   struct TitleControlInfo *tci;
1562   struct TitleFadingInfo fading_default;
1563   struct TitleFadingInfo fading_last = fading;
1564   struct TitleFadingInfo fading_next;
1565   int sound, music;
1566
1567   if (button == MB_MENU_INITIALIZE)
1568   {
1569     title_delay = 0;
1570     title_screen_nr = 0;
1571     tci = &title_controls[title_screen_nr];
1572
1573     last_sound = SND_UNDEFINED;
1574     last_music = MUS_UNDEFINED;
1575
1576     if (game_status == GAME_MODE_INFO)
1577     {
1578       if (num_title_screens == 0)
1579       {
1580         DrawInfoScreen_NotAvailable("Title screen information:",
1581                                     "No title screen for this level set.");
1582
1583         return;
1584       }
1585
1586       FadeSoundsAndMusic();
1587
1588 #if 1
1589       FadeOut(REDRAW_ALL);
1590 #endif
1591     }
1592
1593     if (tci->is_image)
1594       DrawTitleScreenImage(tci->local_nr, tci->initial);
1595     else
1596       DrawTitleScreenMessage(tci->local_nr, tci->initial);
1597
1598     fading_default = (tci->initial ? title_initial_default : title_default);
1599
1600     fading = fading_next = getTitleFading(tci);
1601
1602 #if 1
1603 #if 1
1604     if (!(fading_last.fade_mode & FADE_TYPE_TRANSFORM) &&
1605         fading_next.fade_mode & FADE_TYPE_TRANSFORM)
1606     {
1607       fading.fade_mode = FADE_MODE_FADE;
1608       fading.fade_delay = fading_default.fade_delay;
1609     }
1610 #else
1611     if (fading_last.fade_mode != FADE_MODE_CROSSFADE &&
1612         fading_next.fade_mode == FADE_MODE_CROSSFADE)
1613       fading.fade_mode = FADE_MODE_FADE;
1614 #endif
1615 #endif
1616
1617 #if 1
1618     sound = getTitleSound(tci);
1619     music = getTitleMusic(tci);
1620
1621     if (sound != last_sound)
1622       PlayMenuSoundExt(sound);
1623     if (music != last_music)
1624       PlayMenuMusicExt(music);
1625
1626     last_sound = sound;
1627     last_music = music;
1628 #endif
1629
1630     SetMouseCursor(CURSOR_NONE);
1631
1632 #if 1
1633     FadeIn(REDRAW_ALL);
1634 #endif
1635
1636     fading = fading_next;
1637
1638     DelayReached(&title_delay, 0);      /* reset delay counter */
1639
1640     return;
1641   }
1642
1643 #if 1
1644   if (fading.auto_delay > 0 && DelayReached(&title_delay, fading.auto_delay))
1645     button = MB_MENU_CHOICE;
1646 #else
1647   if (fading.auto_delay > -1 && DelayReached(&title_delay, fading.auto_delay))
1648     button = MB_MENU_CHOICE;
1649 #endif
1650
1651   if (button == MB_MENU_LEAVE)
1652   {
1653     return_to_main_menu = TRUE;
1654     use_fading_main_menu = FALSE;
1655   }
1656   else if (button == MB_MENU_CHOICE)
1657   {
1658     if (game_status == GAME_MODE_INFO && num_title_screens == 0)
1659     {
1660 #if 0
1661       FadeOut(REDRAW_FIELD);
1662 #endif
1663
1664       FadeSetEnterScreen();
1665
1666       info_mode = INFO_MODE_MAIN;
1667       DrawAndFadeInInfoScreen(REDRAW_FIELD);
1668
1669       return;
1670     }
1671
1672     title_screen_nr++;
1673     tci = &title_controls[title_screen_nr];
1674
1675     if (title_screen_nr < num_title_screens)
1676     {
1677       sound = getTitleSound(tci);
1678       music = getTitleMusic(tci);
1679
1680       if (sound == SND_UNDEFINED || sound != last_sound)
1681         FadeSounds();
1682       if (music == MUS_UNDEFINED || music != last_music)
1683         FadeMusic();
1684
1685 #if 1
1686       FadeOut(REDRAW_ALL);
1687 #endif
1688
1689       if (tci->is_image)
1690         DrawTitleScreenImage(tci->local_nr, tci->initial);
1691       else
1692         DrawTitleScreenMessage(tci->local_nr, tci->initial);
1693
1694       fading_next = getTitleFading(tci);
1695
1696 #if 1
1697       sound = getTitleSound(tci);
1698       music = getTitleMusic(tci);
1699
1700       if (sound != last_sound)
1701         PlayMenuSoundExt(sound);
1702       if (music != last_music)
1703         PlayMenuMusicExt(music);
1704
1705       last_sound = sound;
1706       last_music = music;
1707 #endif
1708
1709 #if 1
1710       /* last screen already faded out, next screen has no animation */
1711       if (!(fading.fade_mode & FADE_TYPE_TRANSFORM) &&
1712           fading_next.fade_mode == FADE_MODE_NONE)
1713         fading = fading_next;
1714 #else
1715       /* last screen already faded out, next screen has no animation */
1716       if (fading.fade_mode      != FADE_MODE_CROSSFADE &&
1717           fading_next.fade_mode == FADE_MODE_NONE)
1718         fading = fading_next;
1719 #endif
1720
1721 #if 1
1722       FadeIn(REDRAW_ALL);
1723 #endif
1724
1725       fading = fading_next;
1726
1727       DelayReached(&title_delay, 0);    /* reset delay counter */
1728     }
1729     else
1730     {
1731       FadeSoundsAndMusic();
1732
1733       return_to_main_menu = TRUE;
1734     }
1735   }
1736
1737   if (return_to_main_menu)
1738   {
1739 #if 0
1740     RedrawBackground();
1741 #endif
1742
1743     SetMouseCursor(CURSOR_DEFAULT);
1744
1745     if (game_status == GAME_MODE_INFO)
1746     {
1747 #if 0
1748       OpenDoor(DOOR_CLOSE_1 | DOOR_CLOSE_2 | DOOR_NO_DELAY | DOOR_FORCE_REDRAW);
1749 #endif
1750
1751       info_mode = INFO_MODE_MAIN;
1752       DrawInfoScreenExt(REDRAW_ALL, use_fading_main_menu);
1753     }
1754     else        /* default: return to main menu */
1755     {
1756 #if 0
1757       OpenDoor(DOOR_CLOSE_1 | DOOR_OPEN_2 | DOOR_NO_DELAY | DOOR_FORCE_REDRAW);
1758 #endif
1759
1760       game_status = GAME_MODE_MAIN;
1761       DrawMainMenuExt(REDRAW_ALL, use_fading_main_menu);
1762     }
1763   }
1764 }
1765
1766 void HandleMainMenu_SelectLevel(int step, int direction)
1767 {
1768   int old_level_nr = level_nr;
1769   int new_level_nr;
1770
1771   new_level_nr = old_level_nr + step * direction;
1772   if (new_level_nr < leveldir_current->first_level)
1773     new_level_nr = leveldir_current->first_level;
1774   if (new_level_nr > leveldir_current->last_level)
1775     new_level_nr = leveldir_current->last_level;
1776
1777   if (setup.handicap && new_level_nr > leveldir_current->handicap_level)
1778   {
1779     /* skipping levels is only allowed when trying to skip single level */
1780     if (setup.skip_levels && step == 1 &&
1781         Request("Level still unsolved! Skip despite handicap?", REQ_ASK))
1782     {
1783       leveldir_current->handicap_level++;
1784       SaveLevelSetup_SeriesInfo();
1785     }
1786
1787     new_level_nr = leveldir_current->handicap_level;
1788   }
1789
1790   if (new_level_nr != old_level_nr)
1791   {
1792     struct MainControlInfo *mci= getMainControlInfo(MAIN_CONTROL_LEVEL_NUMBER);
1793
1794     PlaySound(SND_MENU_ITEM_SELECTING);
1795
1796     level_nr = new_level_nr;
1797
1798     DrawText(mSX + mci->pos_text->x, mSY + mci->pos_text->y,
1799              int2str(level_nr, menu.main.text.level_number.size),
1800              mci->pos_text->font);
1801
1802     LoadLevel(level_nr);
1803     DrawPreviewLevelInitial();
1804
1805     TapeErase();
1806     LoadTape(level_nr);
1807     DrawCompleteVideoDisplay();
1808
1809     /* needed because DrawPreviewLevelInitial() takes some time */
1810     BackToFront();
1811     SyncDisplay();
1812   }
1813 }
1814
1815 void HandleMainMenu(int mx, int my, int dx, int dy, int button)
1816 {
1817   static int choice = MAIN_CONTROL_GAME;
1818   int pos = choice;
1819   int i;
1820
1821   if (button == MB_MENU_INITIALIZE)
1822   {
1823     DrawCursorAndText_Main(choice, TRUE);
1824
1825     return;
1826   }
1827
1828   if (mx || my)         /* mouse input */
1829   {
1830     pos = -1;
1831
1832     for (i = 0; main_controls[i].nr != -1; i++)
1833     {
1834 #if 0
1835       printf("::: check click (%d, %d) for %d [%d] ...\n",
1836              mx - mSX, my - mSY, i, main_controls[i].nr);
1837 #endif
1838
1839       if (insideMenuPosRect(main_controls[i].pos_button, mx - mSX, my - mSY) ||
1840           insideTextPosRect(main_controls[i].pos_text,   mx - mSX, my - mSY) ||
1841           insideTextPosRect(main_controls[i].pos_input,  mx - mSX, my - mSY))
1842       {
1843 #if 0
1844         printf("::: inside %d\n", i);
1845 #endif
1846
1847         pos = main_controls[i].nr;
1848
1849         break;
1850       }
1851     }
1852   }
1853   else if (dx || dy)    /* keyboard input */
1854   {
1855     if (dx > 0 && (choice == MAIN_CONTROL_INFO ||
1856                    choice == MAIN_CONTROL_SETUP))
1857       button = MB_MENU_CHOICE;
1858     else if (dy)
1859       pos = choice + dy;
1860   }
1861
1862   if (pos == MAIN_CONTROL_LEVELS && dx != 0 && button)
1863   {
1864     HandleMainMenu_SelectLevel(1, dx < 0 ? -1 : +1);
1865   }
1866   else if (pos == MAIN_CONTROL_FIRST_LEVEL && !button)
1867   {
1868     HandleMainMenu_SelectLevel(MAX_LEVELS, -1);
1869   }
1870   else if (pos == MAIN_CONTROL_LAST_LEVEL && !button)
1871   {
1872     HandleMainMenu_SelectLevel(MAX_LEVELS, +1);
1873   }
1874   else if (pos == MAIN_CONTROL_LEVEL_NUMBER && !button)
1875   {
1876     game_status = GAME_MODE_LEVELNR;
1877
1878     DrawChooseLevelNr();
1879   }
1880   else if (pos >= MAIN_CONTROL_NAME && pos <= MAIN_CONTROL_QUIT)
1881   {
1882     if (button)
1883     {
1884       if (pos != choice)
1885       {
1886         PlaySound(SND_MENU_ITEM_ACTIVATING);
1887
1888         DrawCursorAndText_Main(choice, FALSE);
1889         DrawCursorAndText_Main(pos, TRUE);
1890
1891         choice = pos;
1892       }
1893     }
1894     else
1895     {
1896       PlaySound(SND_MENU_ITEM_SELECTING);
1897
1898       if (pos == MAIN_CONTROL_NAME)
1899       {
1900         game_status = GAME_MODE_PSEUDO_TYPENAME;
1901
1902         HandleTypeName(strlen(setup.player_name), 0);
1903       }
1904       else if (pos == MAIN_CONTROL_LEVELS)
1905       {
1906         if (leveldir_first)
1907         {
1908           game_status = GAME_MODE_LEVELS;
1909
1910           SaveLevelSetup_LastSeries();
1911           SaveLevelSetup_SeriesInfo();
1912
1913 #if defined(CREATE_SPECIAL_EDITION_RND_JUE)
1914           gotoTopLevelDir();
1915 #endif
1916
1917           DrawChooseLevelSet();
1918         }
1919       }
1920       else if (pos == MAIN_CONTROL_SCORES)
1921       {
1922         game_status = GAME_MODE_SCORES;
1923
1924         DrawHallOfFame(-1);
1925       }
1926       else if (pos == MAIN_CONTROL_EDITOR)
1927       {
1928         if (leveldir_current->readonly &&
1929             !strEqual(setup.player_name, "Artsoft"))
1930           Request("This level is read only!", REQ_CONFIRM);
1931
1932         CloseDoor(DOOR_CLOSE_2);
1933
1934         game_status = GAME_MODE_EDITOR;
1935
1936         FadeSetEnterScreen();
1937
1938 #if 0
1939         /* needed if different viewport properties defined for editor */
1940         ChangeViewportPropertiesIfNeeded();
1941 #endif
1942
1943         DrawLevelEd();
1944       }
1945       else if (pos == MAIN_CONTROL_INFO)
1946       {
1947         game_status = GAME_MODE_INFO;
1948         info_mode = INFO_MODE_MAIN;
1949
1950         DrawInfoScreen();
1951       }
1952       else if (pos == MAIN_CONTROL_GAME)
1953       {
1954         StartGameActions(options.network, setup.autorecord, level.random_seed);
1955       }
1956       else if (pos == MAIN_CONTROL_SETUP)
1957       {
1958         game_status = GAME_MODE_SETUP;
1959         setup_mode = SETUP_MODE_MAIN;
1960
1961         DrawSetupScreen();
1962       }
1963       else if (pos == MAIN_CONTROL_QUIT)
1964       {
1965         SaveLevelSetup_LastSeries();
1966         SaveLevelSetup_SeriesInfo();
1967
1968         if (Request("Do you really want to quit?", REQ_ASK | REQ_STAY_CLOSED))
1969           game_status = GAME_MODE_QUIT;
1970       }
1971     }
1972   }
1973
1974 #if 0
1975   if (game_status == GAME_MODE_MAIN)
1976   {
1977     DrawPreviewLevelAnimation();
1978     DoAnimation();
1979   }
1980 #endif
1981 }
1982
1983
1984 /* ========================================================================= */
1985 /* info screen functions                                                     */
1986 /* ========================================================================= */
1987
1988 static struct TokenInfo *info_info;
1989 static int num_info_info;
1990
1991 static void execInfoTitleScreen()
1992 {
1993   info_mode = INFO_MODE_TITLE;
1994
1995   DrawInfoScreen();
1996 }
1997
1998 static void execInfoElements()
1999 {
2000   info_mode = INFO_MODE_ELEMENTS;
2001
2002   DrawInfoScreen();
2003 }
2004
2005 static void execInfoMusic()
2006 {
2007   info_mode = INFO_MODE_MUSIC;
2008
2009   DrawInfoScreen();
2010 }
2011
2012 static void execInfoCredits()
2013 {
2014   info_mode = INFO_MODE_CREDITS;
2015
2016   DrawInfoScreen();
2017 }
2018
2019 static void execInfoProgram()
2020 {
2021   info_mode = INFO_MODE_PROGRAM;
2022
2023   DrawInfoScreen();
2024 }
2025
2026 static void execInfoVersion()
2027 {
2028   info_mode = INFO_MODE_VERSION;
2029
2030   DrawInfoScreen();
2031 }
2032
2033 static void execInfoLevelSet()
2034 {
2035   info_mode = INFO_MODE_LEVELSET;
2036
2037   DrawInfoScreen();
2038 }
2039
2040 static void execExitInfo()
2041 {
2042   game_status = GAME_MODE_MAIN;
2043
2044   DrawMainMenuExt(REDRAW_FIELD, FALSE);
2045 }
2046
2047 static struct TokenInfo info_info_main[] =
2048 {
2049   { TYPE_ENTER_SCREEN,  execInfoTitleScreen,    "Title Screen"          },
2050   { TYPE_ENTER_SCREEN,  execInfoElements,       "Elements Info"         },
2051   { TYPE_ENTER_SCREEN,  execInfoMusic,          "Music Info"            },
2052   { TYPE_ENTER_SCREEN,  execInfoCredits,        "Credits"               },
2053   { TYPE_ENTER_SCREEN,  execInfoProgram,        "Program Info"          },
2054   { TYPE_ENTER_SCREEN,  execInfoVersion,        "Version Info"          },
2055   { TYPE_ENTER_SCREEN,  execInfoLevelSet,       "Level Set Info"        },
2056   { TYPE_EMPTY,         NULL,                   ""                      },
2057   { TYPE_LEAVE_MENU,    execExitInfo,           "Exit"                  },
2058
2059   { 0,                  NULL,                   NULL                    }
2060 };
2061
2062 static void DrawCursorAndText_Info(int pos, boolean active)
2063 {
2064   int xpos = MENU_SCREEN_START_XPOS;
2065   int ypos = MENU_SCREEN_START_YPOS + pos;
2066   int font_nr = FONT_MENU_1;
2067
2068   if (active)
2069     font_nr = FONT_ACTIVE(font_nr);
2070
2071   DrawText(mSX + xpos * 32, mSY + ypos * 32, info_info[pos].text, font_nr);
2072
2073   if (info_info[pos].type & ~TYPE_SKIP_ENTRY)
2074     drawCursor(pos, active);
2075 }
2076
2077 static void DrawInfoScreen_Main(int fade_mask, boolean do_fading)
2078 {
2079   int i;
2080
2081   UnmapAllGadgets();
2082   CloseDoor(DOOR_CLOSE_2);
2083
2084   /* (needed after displaying title screens which disable auto repeat) */
2085   KeyboardAutoRepeatOn();
2086
2087   FadeSetLeaveScreen();
2088
2089 #if 1
2090   FadeOut(fade_mask);
2091 #endif
2092
2093 #if 1
2094   if (fade_mask == REDRAW_ALL)
2095   {
2096     RedrawBackground();
2097
2098     OpenDoor(DOOR_CLOSE_1 | DOOR_CLOSE_2 | DOOR_NO_DELAY | DOOR_FORCE_REDRAW);
2099   }
2100 #endif
2101
2102   ClearField();
2103
2104   DrawTextSCentered(mSY - SY + 16, FONT_TITLE_1, "Info Screen");
2105
2106   info_info = info_info_main;
2107   num_info_info = 0;
2108
2109 #if 1
2110   for (i = 0; info_info[i].type != 0 && i < MAX_MENU_ENTRIES_ON_SCREEN; i++)
2111 #else
2112   for (i = 0; info_info[i].type != 0 && i < NUM_MENU_ENTRIES_ON_SCREEN; i++)
2113 #endif
2114   {
2115     if (info_info[i].type & (TYPE_ENTER_MENU|TYPE_ENTER_LIST))
2116       initCursor(i, IMG_MENU_BUTTON_ENTER_MENU);
2117     else if (info_info[i].type & (TYPE_LEAVE_MENU|TYPE_LEAVE_LIST))
2118       initCursor(i, IMG_MENU_BUTTON_LEAVE_MENU);
2119     else if (info_info[i].type & ~TYPE_SKIP_ENTRY)
2120       initCursor(i, IMG_MENU_BUTTON);
2121
2122     DrawCursorAndText_Info(i, FALSE);
2123
2124     num_info_info++;
2125   }
2126
2127   HandleInfoScreen_Main(0, 0, 0, 0, MB_MENU_INITIALIZE);
2128
2129   PlayMenuSound();
2130   PlayMenuMusic();
2131
2132   DrawMaskedBorder(fade_mask);
2133
2134   FadeIn(fade_mask);
2135
2136   InitAnimation();
2137 }
2138
2139 void HandleInfoScreen_Main(int mx, int my, int dx, int dy, int button)
2140 {
2141   static int choice_store[MAX_INFO_MODES];
2142   int choice = choice_store[info_mode];         /* always starts with 0 */
2143   int x = 0;
2144   int y = choice;
2145
2146   if (button == MB_MENU_INITIALIZE)
2147   {
2148     /* advance to first valid menu entry */
2149     while (choice < num_info_info &&
2150            info_info[choice].type & TYPE_SKIP_ENTRY)
2151       choice++;
2152     choice_store[info_mode] = choice;
2153
2154     DrawCursorAndText_Info(choice, TRUE);
2155
2156     return;
2157   }
2158   else if (button == MB_MENU_LEAVE)
2159   {
2160     for (y = 0; y < num_info_info; y++)
2161     {
2162       if (info_info[y].type & TYPE_LEAVE_MENU)
2163       {
2164         void (*menu_callback_function)(void) = info_info[y].value;
2165
2166         FadeSetLeaveMenu();
2167
2168         menu_callback_function();
2169
2170         break;  /* absolutely needed because function changes 'info_info'! */
2171       }
2172     }
2173
2174     return;
2175   }
2176
2177   if (mx || my)         /* mouse input */
2178   {
2179     x = (mx - mSX) / 32;
2180     y = (my - mSY) / 32 - MENU_SCREEN_START_YPOS;
2181   }
2182   else if (dx || dy)    /* keyboard input */
2183   {
2184     if (dx)
2185     {
2186       int menu_navigation_type = (dx < 0 ? TYPE_LEAVE : TYPE_ENTER);
2187
2188       if (info_info[choice].type & menu_navigation_type ||
2189           info_info[choice].type & TYPE_ENTER_SCREEN ||
2190           info_info[choice].type & TYPE_BOOLEAN_STYLE ||
2191           info_info[choice].type & TYPE_YES_NO_AUTO)
2192         button = MB_MENU_CHOICE;
2193     }
2194     else if (dy)
2195       y = choice + dy;
2196
2197     /* jump to next non-empty menu entry (up or down) */
2198     while (y > 0 && y < num_info_info - 1 &&
2199            info_info[y].type & TYPE_SKIP_ENTRY)
2200       y += dy;
2201   }
2202
2203   if (IN_VIS_FIELD(x, y) &&
2204       y >= 0 && y < num_info_info && info_info[y].type & ~TYPE_SKIP_ENTRY)
2205   {
2206     if (button)
2207     {
2208       if (y != choice)
2209       {
2210         PlaySound(SND_MENU_ITEM_ACTIVATING);
2211
2212         DrawCursorAndText_Info(choice, FALSE);
2213         DrawCursorAndText_Info(y, TRUE);
2214
2215         choice = choice_store[info_mode] = y;
2216       }
2217     }
2218     else if (!(info_info[y].type & TYPE_GHOSTED))
2219     {
2220       PlaySound(SND_MENU_ITEM_SELECTING);
2221
2222       if (info_info[y].type & TYPE_ENTER_OR_LEAVE)
2223       {
2224         void (*menu_callback_function)(void) = info_info[choice].value;
2225
2226         FadeSetFromType(info_info[y].type);
2227
2228         menu_callback_function();
2229       }
2230     }
2231   }
2232 }
2233
2234 void DrawInfoScreen_NotAvailable(char *text_title, char *text_error)
2235 {
2236   int ystart1 = mSY - SY + 100;
2237   int ystart2 = mSY - SY + 150;
2238   int ybottom = mSY - SY + SYSIZE - 20;
2239
2240   SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_LEVELSET);
2241
2242   FadeOut(REDRAW_FIELD);
2243
2244   ClearField();
2245   DrawHeadline();
2246
2247   DrawTextSCentered(ystart1, FONT_TEXT_1, text_title);
2248   DrawTextSCentered(ystart2, FONT_TEXT_2, text_error);
2249
2250   DrawTextSCentered(ybottom, FONT_TEXT_4,
2251                     "Press any key or button for info menu");
2252
2253   FadeIn(REDRAW_FIELD);
2254 }
2255
2256 void DrawInfoScreen_HelpAnim(int start, int max_anims, boolean init)
2257 {
2258   static int infoscreen_step[MAX_INFO_ELEMENTS_ON_SCREEN];
2259   static int infoscreen_frame[MAX_INFO_ELEMENTS_ON_SCREEN];
2260   int xstart = mSX + MENU_SCREEN_INFO_XSTART;
2261   int ystart1 = mSY - SY + MENU_SCREEN_INFO_YSTART1;
2262   int ystart2 = mSY + MENU_SCREEN_INFO_YSTART2;
2263   int ybottom = mSY - SY + MENU_SCREEN_INFO_YBOTTOM;
2264   int ystep = MENU_SCREEN_INFO_YSTEP;
2265   int element, action, direction;
2266   int graphic;
2267   int delay;
2268   int sync_frame;
2269   int i, j;
2270
2271   if (init)
2272   {
2273     for (i = 0; i < NUM_INFO_ELEMENTS_ON_SCREEN; i++)
2274       infoscreen_step[i] = infoscreen_frame[i] = 0;
2275
2276     ClearField();
2277     DrawHeadline();
2278
2279     DrawTextSCentered(ystart1, FONT_TEXT_1, "The Game Elements:");
2280
2281     DrawTextSCentered(ybottom, FONT_TEXT_4,
2282                       "Press any key or button for next page");
2283
2284     FrameCounter = 0;
2285   }
2286
2287   i = j = 0;
2288   while (helpanim_info[j].element != HELPANIM_LIST_END)
2289   {
2290     if (i >= start + NUM_INFO_ELEMENTS_ON_SCREEN ||
2291         i >= max_anims)
2292       break;
2293     else if (i < start)
2294     {
2295       while (helpanim_info[j].element != HELPANIM_LIST_NEXT)
2296         j++;
2297
2298       j++;
2299       i++;
2300
2301       continue;
2302     }
2303
2304     j += infoscreen_step[i - start];
2305
2306     element = helpanim_info[j].element;
2307     action = helpanim_info[j].action;
2308     direction = helpanim_info[j].direction;
2309
2310     if (element < 0)
2311       element = EL_UNKNOWN;
2312
2313     if (action != -1 && direction != -1)
2314       graphic = el_act_dir2img(element, action, direction);
2315     else if (action != -1)
2316       graphic = el_act2img(element, action);
2317     else if (direction != -1)
2318       graphic = el_dir2img(element, direction);
2319     else
2320       graphic = el2img(element);
2321
2322     delay = helpanim_info[j++].delay;
2323
2324     if (delay == -1)
2325       delay = 1000000;
2326
2327     if (infoscreen_frame[i - start] == 0)
2328     {
2329       sync_frame = 0;
2330       infoscreen_frame[i - start] = delay - 1;
2331     }
2332     else
2333     {
2334       sync_frame = delay - infoscreen_frame[i - start];
2335       infoscreen_frame[i - start]--;
2336     }
2337
2338     if (helpanim_info[j].element == HELPANIM_LIST_NEXT)
2339     {
2340       if (!infoscreen_frame[i - start])
2341         infoscreen_step[i - start] = 0;
2342     }
2343     else
2344     {
2345       if (!infoscreen_frame[i - start])
2346         infoscreen_step[i - start]++;
2347       while (helpanim_info[j].element != HELPANIM_LIST_NEXT)
2348         j++;
2349     }
2350
2351     j++;
2352
2353     ClearRectangleOnBackground(drawto, xstart, ystart2 + (i - start) * ystep,
2354                                TILEX, TILEY);
2355     DrawFixedGraphicAnimationExt(drawto, xstart, ystart2 + (i - start) * ystep,
2356                                  graphic, sync_frame, USE_MASKING);
2357
2358     if (init)
2359       DrawInfoScreen_HelpText(element, action, direction, i - start);
2360
2361     i++;
2362   }
2363
2364   redraw_mask |= REDRAW_FIELD;
2365
2366   FrameCounter++;
2367 }
2368
2369 static char *getHelpText(int element, int action, int direction)
2370 {
2371   char token[MAX_LINE_LEN];
2372
2373   strcpy(token, element_info[element].token_name);
2374
2375   if (action != -1)
2376     strcat(token, element_action_info[action].suffix);
2377
2378   if (direction != -1)
2379     strcat(token, element_direction_info[MV_DIR_TO_BIT(direction)].suffix);
2380
2381   return getHashEntry(helptext_info, token);
2382 }
2383
2384 void DrawInfoScreen_HelpText(int element, int action, int direction, int ypos)
2385 {
2386   int font_nr = FONT_INFO_ELEMENTS;
2387   int font_width = getFontWidth(font_nr);
2388   int sx = mSX + MINI_TILEX + TILEX + MINI_TILEX;
2389   int sy = mSY + 65 + 2 * 32 + 1;
2390   int ystep = TILEY + 4;
2391   int pad_x = sx - SX;
2392   int max_chars_per_line = (SXSIZE - pad_x - MINI_TILEX) / font_width;
2393   int max_lines_per_text = 2;    
2394   char *text = NULL;
2395
2396   if (action != -1 && direction != -1)          /* element.action.direction */
2397     text = getHelpText(element, action, direction);
2398
2399   if (text == NULL && action != -1)             /* element.action */
2400     text = getHelpText(element, action, -1);
2401
2402   if (text == NULL && direction != -1)          /* element.direction */
2403     text = getHelpText(element, -1, direction);
2404
2405   if (text == NULL)                             /* base element */
2406     text = getHelpText(element, -1, -1);
2407
2408   if (text == NULL)                             /* not found */
2409     text = "No description available";
2410
2411   if (strlen(text) <= max_chars_per_line)       /* only one line of text */
2412     sy += getFontHeight(font_nr) / 2;
2413
2414   DrawTextBuffer(sx, sy + ypos * ystep, text, font_nr,
2415                  max_chars_per_line, -1, max_lines_per_text, 0, -1,
2416                  TRUE, FALSE, FALSE);
2417 }
2418
2419 void DrawInfoScreen_TitleScreen()
2420 {
2421   DrawTitleScreen();
2422 }
2423
2424 void HandleInfoScreen_TitleScreen(int button)
2425 {
2426   HandleTitleScreen(0, 0, 0, 0, button);
2427 }
2428
2429 void DrawInfoScreen_Elements()
2430 {
2431   SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_ELEMENTS);
2432
2433   FadeOut(REDRAW_FIELD);
2434
2435   LoadHelpAnimInfo();
2436   LoadHelpTextInfo();
2437
2438   HandleInfoScreen_Elements(MB_MENU_INITIALIZE);
2439
2440   FadeIn(REDRAW_FIELD);
2441
2442   InitAnimation();
2443 }
2444
2445 void HandleInfoScreen_Elements(int button)
2446 {
2447   static unsigned int info_delay = 0;
2448   static int num_anims;
2449   static int num_pages;
2450   static int page;
2451   int anims_per_page = NUM_INFO_ELEMENTS_ON_SCREEN;
2452   int i;
2453
2454   if (button == MB_MENU_INITIALIZE)
2455   {
2456     boolean new_element = TRUE;
2457
2458     num_anims = 0;
2459
2460     for (i = 0; helpanim_info[i].element != HELPANIM_LIST_END; i++)
2461     {
2462       if (helpanim_info[i].element == HELPANIM_LIST_NEXT)
2463         new_element = TRUE;
2464       else if (new_element)
2465       {
2466         num_anims++;
2467         new_element = FALSE;
2468       }
2469     }
2470
2471     num_pages = (num_anims + anims_per_page - 1) / anims_per_page;
2472     page = 0;
2473   }
2474
2475   if (button == MB_MENU_LEAVE)
2476   {
2477     PlaySound(SND_MENU_ITEM_SELECTING);
2478
2479     info_mode = INFO_MODE_MAIN;
2480     DrawInfoScreen();
2481
2482     return;
2483   }
2484   else if (button == MB_MENU_CHOICE || button == MB_MENU_INITIALIZE)
2485   {
2486     if (button != MB_MENU_INITIALIZE)
2487     {
2488       PlaySound(SND_MENU_ITEM_SELECTING);
2489
2490       page++;
2491     }
2492
2493     if (page >= num_pages)
2494     {
2495       FadeSoundsAndMusic();
2496
2497       info_mode = INFO_MODE_MAIN;
2498       DrawAndFadeInInfoScreen(REDRAW_FIELD);
2499
2500       return;
2501     }
2502
2503 #if 1
2504     if (page > 0)
2505       FadeSetNextScreen();
2506 #endif
2507
2508     if (button != MB_MENU_INITIALIZE)
2509       FadeOut(REDRAW_FIELD);
2510
2511     DrawInfoScreen_HelpAnim(page * anims_per_page, num_anims, TRUE);
2512
2513     if (button != MB_MENU_INITIALIZE)
2514       FadeIn(REDRAW_FIELD);
2515   }
2516   else
2517   {
2518     if (DelayReached(&info_delay, GameFrameDelay))
2519       if (page < num_pages)
2520         DrawInfoScreen_HelpAnim(page * anims_per_page, num_anims, FALSE);
2521
2522     PlayMenuSoundIfLoop();
2523   }
2524 }
2525
2526 void DrawInfoScreen_Music()
2527 {
2528   SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_MUSIC);
2529
2530 #if 1
2531   FadeOut(REDRAW_FIELD);
2532 #endif
2533
2534   ClearField();
2535   DrawHeadline();
2536
2537   LoadMusicInfo();
2538
2539   HandleInfoScreen_Music(MB_MENU_INITIALIZE);
2540
2541 #if 1
2542   FadeIn(REDRAW_FIELD);
2543 #endif
2544 }
2545
2546 void HandleInfoScreen_Music(int button)
2547 {
2548   static struct MusicFileInfo *list = NULL;
2549   int ystart1 = mSY - SY + 100;
2550   int ystart2 = mSY - SY + 150;
2551   int ybottom = mSY - SY + SYSIZE - 20;
2552   int dy = 30;
2553
2554   if (button == MB_MENU_INITIALIZE)
2555   {
2556     list = music_file_info;
2557
2558     if (list == NULL)
2559     {
2560       FadeSoundsAndMusic();
2561
2562       ClearField();
2563       DrawHeadline();
2564
2565       DrawTextSCentered(ystart1, FONT_TEXT_1,
2566                         "No music info for this level set.");
2567
2568       DrawTextSCentered(ybottom, FONT_TEXT_4,
2569                         "Press any key or button for info menu");
2570
2571       return;
2572     }
2573   }
2574
2575   if (button == MB_MENU_LEAVE)
2576   {
2577     PlaySound(SND_MENU_ITEM_SELECTING);
2578
2579     FadeSoundsAndMusic();
2580
2581     info_mode = INFO_MODE_MAIN;
2582     DrawInfoScreen();
2583
2584     return;
2585   }
2586   else if (button == MB_MENU_CHOICE || button == MB_MENU_INITIALIZE)
2587   {
2588     int y = 0;
2589
2590     if (button != MB_MENU_INITIALIZE)
2591     {
2592       PlaySound(SND_MENU_ITEM_SELECTING);
2593
2594       if (list != NULL)
2595         list = list->next;
2596     }
2597
2598     if (list == NULL)
2599     {
2600       FadeSoundsAndMusic();
2601
2602       info_mode = INFO_MODE_MAIN;
2603       DrawAndFadeInInfoScreen(REDRAW_FIELD);
2604
2605       return;
2606     }
2607
2608     FadeSoundsAndMusic();
2609
2610 #if 1
2611     if (list != music_file_info)
2612       FadeSetNextScreen();
2613 #endif
2614
2615     if (button != MB_MENU_INITIALIZE)
2616       FadeOut(REDRAW_FIELD);
2617
2618     ClearField();
2619     DrawHeadline();
2620
2621     if (list->is_sound)
2622     {
2623       int sound = list->music;
2624
2625       if (sound_info[sound].loop)
2626         PlaySoundLoop(sound);
2627       else
2628         PlaySound(sound);
2629
2630       DrawTextSCentered(ystart1, FONT_TEXT_1, "The Game Background Sounds:");
2631     }
2632     else
2633     {
2634       PlayMusic(list->music);
2635
2636       DrawTextSCentered(ystart1, FONT_TEXT_1, "The Game Background Music:");
2637     }
2638
2639     if (!strEqual(list->title, UNKNOWN_NAME))
2640     {
2641       if (!strEqual(list->title_header, UNKNOWN_NAME))
2642         DrawTextSCentered(ystart2 + y++ * dy, FONT_TEXT_2, list->title_header);
2643
2644       DrawTextFCentered(ystart2 + y++ * dy, FONT_TEXT_3, "\"%s\"", list->title);
2645     }
2646
2647     if (!strEqual(list->artist, UNKNOWN_NAME))
2648     {
2649       if (!strEqual(list->artist_header, UNKNOWN_NAME))
2650         DrawTextSCentered(ystart2 + y++ * dy, FONT_TEXT_2, list->artist_header);
2651       else
2652         DrawTextSCentered(ystart2 + y++ * dy, FONT_TEXT_2, "by");
2653
2654       DrawTextFCentered(ystart2 + y++ * dy, FONT_TEXT_3, "%s", list->artist);
2655     }
2656
2657     if (!strEqual(list->album, UNKNOWN_NAME))
2658     {
2659       if (!strEqual(list->album_header, UNKNOWN_NAME))
2660         DrawTextSCentered(ystart2 + y++ * dy, FONT_TEXT_2, list->album_header);
2661       else
2662         DrawTextSCentered(ystart2 + y++ * dy, FONT_TEXT_2, "from the album");
2663
2664       DrawTextFCentered(ystart2 + y++ * dy, FONT_TEXT_3, "\"%s\"", list->album);
2665     }
2666
2667     if (!strEqual(list->year, UNKNOWN_NAME))
2668     {
2669       if (!strEqual(list->year_header, UNKNOWN_NAME))
2670         DrawTextSCentered(ystart2 + y++ * dy, FONT_TEXT_2, list->year_header);
2671       else
2672         DrawTextSCentered(ystart2 + y++ * dy, FONT_TEXT_2, "from the year");
2673
2674       DrawTextFCentered(ystart2 + y++ * dy, FONT_TEXT_3, "%s", list->year);
2675     }
2676
2677     DrawTextSCentered(ybottom, FONT_TEXT_4,
2678                       "Press any key or button for next page");
2679
2680     if (button != MB_MENU_INITIALIZE)
2681       FadeIn(REDRAW_FIELD);
2682   }
2683
2684   if (list != NULL && list->is_sound && sound_info[list->music].loop)
2685     PlaySoundLoop(list->music);
2686 }
2687
2688 static void DrawInfoScreen_CreditsScreen(int screen_nr)
2689 {
2690   int ystart1 = mSY - SY + 100;
2691   int ystart2 = mSY - SY + 150;
2692   int ybottom = mSY - SY + SYSIZE - 20;
2693   int ystep = 30;
2694
2695   ClearField();
2696   DrawHeadline();
2697
2698   DrawTextSCentered(ystart1, FONT_TEXT_1, "Credits:");
2699
2700   if (screen_nr == 0)
2701   {
2702     DrawTextSCentered(ystart2 + 0 * ystep, FONT_TEXT_2,
2703                       "Special thanks to");
2704     DrawTextSCentered(ystart2 + 1 * ystep, FONT_TEXT_3,
2705                       "Peter Liepa");
2706     DrawTextSCentered(ystart2 + 2 * ystep, FONT_TEXT_2,
2707                       "for creating");
2708     DrawTextSCentered(ystart2 + 3 * ystep, FONT_TEXT_3,
2709                       "\"Boulder Dash\"");
2710     DrawTextSCentered(ystart2 + 4 * ystep, FONT_TEXT_2,
2711                       "in the year");
2712     DrawTextSCentered(ystart2 + 5 * ystep, FONT_TEXT_3,
2713                       "1984");
2714     DrawTextSCentered(ystart2 + 6 * ystep, FONT_TEXT_2,
2715                       "published by");
2716     DrawTextSCentered(ystart2 + 7 * ystep, FONT_TEXT_3,
2717                       "First Star Software");
2718   }
2719   else if (screen_nr == 1)
2720   {
2721     DrawTextSCentered(ystart2 + 0 * ystep, FONT_TEXT_2,
2722                       "Special thanks to");
2723     DrawTextSCentered(ystart2 + 1 * ystep, FONT_TEXT_3,
2724                       "Klaus Heinz & Volker Wertich");
2725     DrawTextSCentered(ystart2 + 2 * ystep, FONT_TEXT_2,
2726                       "for creating");
2727     DrawTextSCentered(ystart2 + 3 * ystep, FONT_TEXT_3,
2728                       "\"Emerald Mine\"");
2729     DrawTextSCentered(ystart2 + 4 * ystep, FONT_TEXT_2,
2730                       "in the year");
2731     DrawTextSCentered(ystart2 + 5 * ystep, FONT_TEXT_3,
2732                       "1987");
2733     DrawTextSCentered(ystart2 + 6 * ystep, FONT_TEXT_2,
2734                       "published by");
2735     DrawTextSCentered(ystart2 + 7 * ystep, FONT_TEXT_3,
2736                       "Kingsoft");
2737   }
2738   else if (screen_nr == 2)
2739   {
2740     DrawTextSCentered(ystart2 + 0 * ystep, FONT_TEXT_2,
2741                       "Special thanks to");
2742     DrawTextSCentered(ystart2 + 1 * ystep, FONT_TEXT_3,
2743                       "Michael Stopp & Philip Jespersen");
2744     DrawTextSCentered(ystart2 + 2 * ystep, FONT_TEXT_2,
2745                       "for creating");
2746     DrawTextSCentered(ystart2 + 3 * ystep, FONT_TEXT_3,
2747                       "\"Supaplex\"");
2748     DrawTextSCentered(ystart2 + 4 * ystep, FONT_TEXT_2,
2749                       "in the year");
2750     DrawTextSCentered(ystart2 + 5 * ystep, FONT_TEXT_3,
2751                       "1991");
2752     DrawTextSCentered(ystart2 + 6 * ystep, FONT_TEXT_2,
2753                       "published by");
2754     DrawTextSCentered(ystart2 + 7 * ystep, FONT_TEXT_3,
2755                       "Digital Integration");
2756   }
2757   else if (screen_nr == 3)
2758   {
2759     DrawTextSCentered(ystart2 + 0 * ystep, FONT_TEXT_2,
2760                       "Special thanks to");
2761     DrawTextSCentered(ystart2 + 1 * ystep, FONT_TEXT_3,
2762                       "Hiroyuki Imabayashi");
2763     DrawTextSCentered(ystart2 + 2 * ystep, FONT_TEXT_2,
2764                       "for creating");
2765     DrawTextSCentered(ystart2 + 3 * ystep, FONT_TEXT_3,
2766                       "\"Sokoban\"");
2767     DrawTextSCentered(ystart2 + 4 * ystep, FONT_TEXT_2,
2768                       "in the year");
2769     DrawTextSCentered(ystart2 + 5 * ystep, FONT_TEXT_3,
2770                       "1982");
2771     DrawTextSCentered(ystart2 + 6 * ystep, FONT_TEXT_2,
2772                       "published by");
2773     DrawTextSCentered(ystart2 + 7 * ystep, FONT_TEXT_3,
2774                       "Thinking Rabbit");
2775   }
2776   else if (screen_nr == 4)
2777   {
2778     DrawTextSCentered(ystart2 + 0 * ystep, FONT_TEXT_2,
2779                       "Special thanks to");
2780     DrawTextSCentered(ystart2 + 1 * ystep, FONT_TEXT_3,
2781                       "Alan Bond");
2782     DrawTextSCentered(ystart2 + 2 * ystep, FONT_TEXT_2,
2783                       "and");
2784     DrawTextSCentered(ystart2 + 3 * ystep, FONT_TEXT_3,
2785                       "Jürgen Bonhagen");
2786     DrawTextSCentered(ystart2 + 4 * ystep, FONT_TEXT_2,
2787                       "for the continuous creation");
2788     DrawTextSCentered(ystart2 + 5 * ystep, FONT_TEXT_2,
2789                       "of outstanding level sets");
2790   }
2791   else if (screen_nr == 5)
2792   {
2793     DrawTextSCentered(ystart2 + 0 * ystep, FONT_TEXT_2,
2794                       "Thanks to");
2795     DrawTextSCentered(ystart2 + 1 * ystep, FONT_TEXT_3,
2796                       "Peter Elzner");
2797     DrawTextSCentered(ystart2 + 2 * ystep, FONT_TEXT_2,
2798                       "for ideas and inspiration by");
2799     DrawTextSCentered(ystart2 + 3 * ystep, FONT_TEXT_3,
2800                       "Diamond Caves");
2801
2802     DrawTextSCentered(ystart2 + 5 * ystep, FONT_TEXT_2,
2803                       "Thanks to");
2804     DrawTextSCentered(ystart2 + 6 * ystep, FONT_TEXT_3,
2805                       "Steffest");
2806     DrawTextSCentered(ystart2 + 7 * ystep, FONT_TEXT_2,
2807                       "for ideas and inspiration by");
2808     DrawTextSCentered(ystart2 + 8 * ystep, FONT_TEXT_3,
2809                       "DX-Boulderdash");
2810   }
2811   else if (screen_nr == 6)
2812   {
2813     DrawTextSCentered(ystart2 + 0 * ystep, FONT_TEXT_2,
2814                       "Thanks to");
2815     DrawTextSCentered(ystart2 + 1 * ystep, FONT_TEXT_3,
2816                       "David Tritscher");
2817 #if 1
2818     DrawTextSCentered(ystart2 + 2 * ystep, FONT_TEXT_2,
2819                       "for the code base used for the");
2820     DrawTextSCentered(ystart2 + 3 * ystep, FONT_TEXT_2,
2821                       "native Emerald Mine engine");
2822 #else
2823     DrawTextSCentered(ystart2 + 2 * ystep, FONT_TEXT_2,
2824                       "for the new Emerald Mine engine");
2825 #endif
2826   }
2827   else if (screen_nr == 7)
2828   {
2829     DrawTextSCentered(ystart2 + 0 * ystep, FONT_TEXT_2,
2830                       "Thanks to");
2831     DrawTextSCentered(ystart2 + 1 * ystep, FONT_TEXT_3,
2832                       "Guido Schulz");
2833     DrawTextSCentered(ystart2 + 2 * ystep, FONT_TEXT_2,
2834                       "for the initial DOS port");
2835
2836     DrawTextSCentered(ystart2 + 4 * ystep, FONT_TEXT_2,
2837                       "Thanks to");
2838     DrawTextSCentered(ystart2 + 5 * ystep, FONT_TEXT_3,
2839                       "Karl Hörnell");
2840     DrawTextSCentered(ystart2 + 6 * ystep, FONT_TEXT_2,
2841                       "for some additional toons");
2842   }
2843   else if (screen_nr == 8)
2844   {
2845     DrawTextSCentered(ystart2 + 0 * ystep, FONT_TEXT_2,
2846                       "And not to forget:");
2847     DrawTextSCentered(ystart2 + 1 * ystep, FONT_TEXT_2,
2848                       "Many thanks to");
2849     DrawTextSCentered(ystart2 + 2 * ystep, FONT_TEXT_3,
2850                       "All those who contributed");
2851     DrawTextSCentered(ystart2 + 3 * ystep, FONT_TEXT_3,
2852                       "levels to this game");
2853     DrawTextSCentered(ystart2 + 4 * ystep, FONT_TEXT_3,
2854                       "since 1995");
2855   }
2856
2857   DrawTextSCentered(ybottom, FONT_TEXT_4,
2858                     "Press any key or button for next page");
2859 }
2860
2861 void DrawInfoScreen_Credits()
2862 {
2863   SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_CREDITS);
2864
2865   FadeSoundsAndMusic();
2866
2867 #if 1
2868   FadeOut(REDRAW_FIELD);
2869 #endif
2870
2871   HandleInfoScreen_Credits(MB_MENU_INITIALIZE);
2872
2873 #if 1
2874   FadeIn(REDRAW_FIELD);
2875 #endif
2876 }
2877
2878 void HandleInfoScreen_Credits(int button)
2879 {
2880   static int screen_nr = 0;
2881   int num_screens = 9;
2882
2883   if (button == MB_MENU_INITIALIZE)
2884   {
2885     screen_nr = 0;
2886
2887     // DrawInfoScreen_CreditsScreen(screen_nr);
2888   }
2889
2890   if (button == MB_MENU_LEAVE)
2891   {
2892     PlaySound(SND_MENU_ITEM_SELECTING);
2893
2894     info_mode = INFO_MODE_MAIN;
2895     DrawInfoScreen();
2896
2897     return;
2898   }
2899   else if (button == MB_MENU_CHOICE || button == MB_MENU_INITIALIZE)
2900   {
2901     if (button != MB_MENU_INITIALIZE)
2902     {
2903       PlaySound(SND_MENU_ITEM_SELECTING);
2904
2905       screen_nr++;
2906     }
2907
2908     if (screen_nr >= num_screens)
2909     {
2910       FadeSoundsAndMusic();
2911
2912       info_mode = INFO_MODE_MAIN;
2913       DrawAndFadeInInfoScreen(REDRAW_FIELD);
2914
2915       return;
2916     }
2917
2918 #if 1
2919     if (screen_nr > 0)
2920       FadeSetNextScreen();
2921 #endif
2922
2923     if (button != MB_MENU_INITIALIZE)
2924       FadeOut(REDRAW_FIELD);
2925
2926     DrawInfoScreen_CreditsScreen(screen_nr);
2927
2928     if (button != MB_MENU_INITIALIZE)
2929       FadeIn(REDRAW_FIELD);
2930   }
2931   else
2932   {
2933     PlayMenuSoundIfLoop();
2934   }
2935 }
2936
2937 void DrawInfoScreen_Program()
2938 {
2939   int ystart1 = mSY - SY + 100;
2940   int ystart2 = mSY - SY + 150;
2941   int ybottom = mSY - SY + SYSIZE - 20;
2942   int ystep = 30;
2943
2944   SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_PROGRAM);
2945
2946 #if 1
2947   FadeOut(REDRAW_FIELD);
2948 #endif
2949
2950   ClearField();
2951   DrawHeadline();
2952
2953   DrawTextSCentered(ystart1, FONT_TEXT_1, "Program Information:");
2954
2955   DrawTextSCentered(ystart2 + 0 * ystep, FONT_TEXT_2,
2956                     "This game is Freeware!");
2957   DrawTextSCentered(ystart2 + 1 * ystep, FONT_TEXT_2,
2958                     "If you like it, send e-mail to:");
2959   DrawTextSCentered(ystart2 + 2 * ystep, FONT_TEXT_3,
2960                     PROGRAM_EMAIL_STRING);
2961 #if 1
2962   DrawTextSCentered(ystart2 + 4 * ystep, FONT_TEXT_2,
2963                     "More information and levels:");
2964   DrawTextSCentered(ystart2 + 5 * ystep, FONT_TEXT_3,
2965                     PROGRAM_WEBSITE_STRING);
2966   DrawTextSCentered(ystart2 + 7 * ystep, FONT_TEXT_2,
2967                     "If you have created new levels,");
2968   DrawTextSCentered(ystart2 + 8 * ystep, FONT_TEXT_2,
2969                     "send them to me to include them!");
2970   DrawTextSCentered(ystart2 + 9 * ystep, FONT_TEXT_2,
2971                     ":-)");
2972 #else
2973   DrawTextSCentered(ystart2 + 3 * ystep, FONT_TEXT_2,
2974                     "or SnailMail to:");
2975   DrawTextSCentered(ystart2 + 4 * ystep + 0, FONT_TEXT_3,
2976                     "Holger Schemel");
2977   DrawTextSCentered(ystart2 + 4 * ystep + 20, FONT_TEXT_3,
2978                     "Detmolder Strasse 189");
2979   DrawTextSCentered(ystart2 + 4 * ystep + 40, FONT_TEXT_3,
2980                     "33604 Bielefeld");
2981   DrawTextSCentered(ystart2 + 4 * ystep + 60, FONT_TEXT_3,
2982                     "Germany");
2983   DrawTextSCentered(ystart2 + 7 * ystep, FONT_TEXT_2,
2984                     "More information and levels:");
2985   DrawTextSCentered(ystart2 + 8 * ystep, FONT_TEXT_3,
2986                     PROGRAM_WEBSITE_STRING);
2987   DrawTextSCentered(ystart2 + 9 * ystep, FONT_TEXT_2,
2988                     "If you have created new levels,");
2989   DrawTextSCentered(ystart2 + 10 * ystep, FONT_TEXT_2,
2990                     "send them to me to include them!");
2991   DrawTextSCentered(ystart2 + 11 * ystep, FONT_TEXT_2,
2992                     ":-)");
2993 #endif
2994
2995   DrawTextSCentered(ybottom, FONT_TEXT_4,
2996                     "Press any key or button for info menu");
2997
2998 #if 1
2999   FadeIn(REDRAW_FIELD);
3000 #endif
3001 }
3002
3003 void HandleInfoScreen_Program(int button)
3004 {
3005   if (button == MB_MENU_LEAVE)
3006   {
3007     PlaySound(SND_MENU_ITEM_SELECTING);
3008
3009     info_mode = INFO_MODE_MAIN;
3010     DrawInfoScreen();
3011
3012     return;
3013   }
3014   else if (button == MB_MENU_CHOICE)
3015   {
3016     PlaySound(SND_MENU_ITEM_SELECTING);
3017
3018     FadeSoundsAndMusic();
3019
3020 #if 0
3021     FadeOut(REDRAW_FIELD);
3022 #endif
3023
3024     info_mode = INFO_MODE_MAIN;
3025     DrawAndFadeInInfoScreen(REDRAW_FIELD);
3026   }
3027   else
3028   {
3029     PlayMenuSoundIfLoop();
3030   }
3031 }
3032
3033 void DrawInfoScreen_Version()
3034 {
3035   int font_header = FONT_TEXT_3;
3036   int font_text = FONT_TEXT_2;
3037   int xstep = getFontWidth(font_text);
3038   int ystep = getFontHeight(font_text);
3039   int ystart1 = mSY - SY + 100;
3040   int ystart2 = mSY - SY + 150;
3041   int ybottom = mSY - SY + SYSIZE - 20;
3042   int xstart1 = mSX - SX + 2 * xstep;
3043   int xstart2 = mSX - SX + 18 * xstep;
3044 #if defined(TARGET_SDL)
3045   int xstart3 = mSX - SX + 28 * xstep;
3046   SDL_version sdl_version_compiled;
3047   const SDL_version *sdl_version_linked;
3048   int driver_name_len = 10;
3049 #if defined(TARGET_SDL2)
3050   SDL_version sdl_version_linked_ext;
3051   const char *driver_name = NULL;
3052 #else
3053   char driver_name[driver_name_len];
3054 #endif
3055 #endif
3056
3057   SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_VERSION);
3058
3059 #if 1
3060   FadeOut(REDRAW_FIELD);
3061 #endif
3062
3063   ClearField();
3064   DrawHeadline();
3065
3066   DrawTextSCentered(ystart1, FONT_TEXT_1, "Version Information:");
3067
3068   DrawTextF(xstart1, ystart2, font_header, "Name");
3069   DrawTextF(xstart2, ystart2, font_text, PROGRAM_TITLE_STRING);
3070
3071   ystart2 += ystep;
3072   DrawTextF(xstart1, ystart2, font_header, "Version");
3073   DrawTextF(xstart2, ystart2, font_text, getProgramFullVersionString());
3074
3075   ystart2 += ystep;
3076   DrawTextF(xstart1, ystart2, font_header, "Platform");
3077   DrawTextF(xstart2, ystart2, font_text, PLATFORM_STRING);
3078
3079   ystart2 += ystep;
3080   DrawTextF(xstart1, ystart2, font_header, "Target");
3081   DrawTextF(xstart2, ystart2, font_text, TARGET_STRING);
3082
3083   ystart2 += ystep;
3084   DrawTextF(xstart1, ystart2, font_header, "Compile time");
3085   DrawTextF(xstart2, ystart2, font_text, getCompileDateString());
3086
3087 #if defined(TARGET_SDL)
3088   ystart2 += 3 * ystep;
3089   DrawTextF(xstart1, ystart2, font_header, "Library");
3090   DrawTextF(xstart2, ystart2, font_header, "compiled");
3091   DrawTextF(xstart3, ystart2, font_header, "linked");
3092
3093   SDL_VERSION(&sdl_version_compiled);
3094 #if defined(TARGET_SDL2)
3095   SDL_GetVersion(&sdl_version_linked_ext);
3096   sdl_version_linked = &sdl_version_linked_ext;
3097 #else
3098   sdl_version_linked = SDL_Linked_Version();
3099 #endif
3100
3101   ystart2 += 2 * ystep;
3102   DrawTextF(xstart1, ystart2, font_text, "SDL");
3103   DrawTextF(xstart2, ystart2, font_text, "%d.%d.%d",
3104             sdl_version_compiled.major,
3105             sdl_version_compiled.minor,
3106             sdl_version_compiled.patch);
3107   DrawTextF(xstart3, ystart2, font_text, "%d.%d.%d",
3108             sdl_version_linked->major,
3109             sdl_version_linked->minor,
3110             sdl_version_linked->patch);
3111
3112   SDL_IMAGE_VERSION(&sdl_version_compiled);
3113   sdl_version_linked = IMG_Linked_Version();
3114
3115   ystart2 += ystep;
3116   DrawTextF(xstart1, ystart2, font_text, "SDL_image");
3117   DrawTextF(xstart2, ystart2, font_text, "%d.%d.%d",
3118             sdl_version_compiled.major,
3119             sdl_version_compiled.minor,
3120             sdl_version_compiled.patch);
3121   DrawTextF(xstart3, ystart2, font_text, "%d.%d.%d",
3122             sdl_version_linked->major,
3123             sdl_version_linked->minor,
3124             sdl_version_linked->patch);
3125
3126   SDL_MIXER_VERSION(&sdl_version_compiled);
3127   sdl_version_linked = Mix_Linked_Version();
3128
3129   ystart2 += ystep;
3130   DrawTextF(xstart1, ystart2, font_text, "SDL_mixer");
3131   DrawTextF(xstart2, ystart2, font_text, "%d.%d.%d",
3132             sdl_version_compiled.major,
3133             sdl_version_compiled.minor,
3134             sdl_version_compiled.patch);
3135   DrawTextF(xstart3, ystart2, font_text, "%d.%d.%d",
3136             sdl_version_linked->major,
3137             sdl_version_linked->minor,
3138             sdl_version_linked->patch);
3139
3140   SDL_NET_VERSION(&sdl_version_compiled);
3141   sdl_version_linked = SDLNet_Linked_Version();
3142
3143   ystart2 += ystep;
3144   DrawTextF(xstart1, ystart2, font_text, "SDL_net");
3145   DrawTextF(xstart2, ystart2, font_text, "%d.%d.%d",
3146             sdl_version_compiled.major,
3147             sdl_version_compiled.minor,
3148             sdl_version_compiled.patch);
3149   DrawTextF(xstart3, ystart2, font_text, "%d.%d.%d",
3150             sdl_version_linked->major,
3151             sdl_version_linked->minor,
3152             sdl_version_linked->patch);
3153
3154   ystart2 += 3 * ystep;
3155   DrawTextF(xstart1, ystart2, font_header, "Driver");
3156   DrawTextF(xstart2, ystart2, font_header, "Requested");
3157   DrawTextF(xstart3, ystart2, font_header, "Used");
3158
3159 #if defined(TARGET_SDL2)
3160   driver_name = getStringCopyNStatic(SDL_GetVideoDriver(0), driver_name_len);
3161 #else
3162   SDL_VideoDriverName(driver_name, driver_name_len);
3163 #endif
3164
3165   ystart2 += 2 * ystep;
3166   DrawTextF(xstart1, ystart2, font_text, "SDL_VideoDriver");
3167   DrawTextF(xstart2, ystart2, font_text, "%s", setup.system.sdl_videodriver);
3168   DrawTextF(xstart3, ystart2, font_text, "%s", driver_name);
3169
3170 #if defined(TARGET_SDL2)
3171   driver_name = getStringCopyNStatic(SDL_GetAudioDriver(0), driver_name_len);
3172 #else
3173   SDL_AudioDriverName(driver_name, driver_name_len);
3174 #endif
3175
3176   ystart2 += ystep;
3177   DrawTextF(xstart1, ystart2, font_text, "SDL_AudioDriver");
3178   DrawTextF(xstart2, ystart2, font_text, "%s", setup.system.sdl_audiodriver);
3179   DrawTextF(xstart3, ystart2, font_text, "%s", driver_name);
3180 #endif
3181
3182   DrawTextSCentered(ybottom, FONT_TEXT_4,
3183                     "Press any key or button for info menu");
3184
3185 #if 1
3186   FadeIn(REDRAW_FIELD);
3187 #endif
3188 }
3189
3190 void HandleInfoScreen_Version(int button)
3191 {
3192   if (button == MB_MENU_LEAVE)
3193   {
3194     PlaySound(SND_MENU_ITEM_SELECTING);
3195
3196     info_mode = INFO_MODE_MAIN;
3197     DrawInfoScreen();
3198
3199     return;
3200   }
3201   else if (button == MB_MENU_CHOICE)
3202   {
3203     PlaySound(SND_MENU_ITEM_SELECTING);
3204
3205     FadeSoundsAndMusic();
3206
3207 #if 0
3208     FadeOut(REDRAW_FIELD);
3209 #endif
3210
3211     info_mode = INFO_MODE_MAIN;
3212     DrawAndFadeInInfoScreen(REDRAW_FIELD);
3213   }
3214   else
3215   {
3216     PlayMenuSoundIfLoop();
3217   }
3218 }
3219
3220 void DrawInfoScreen_LevelSet()
3221 {
3222   struct TitleMessageInfo *tmi = &readme;
3223   char *filename = getLevelSetInfoFilename();
3224
3225   /* if chars set to "-1", automatically determine by text and font width */
3226   if (tmi->chars == -1)
3227     tmi->chars = tmi->width / getFontWidth(tmi->font);
3228   else
3229     tmi->width = tmi->chars * getFontWidth(tmi->font);
3230
3231   /* if lines set to "-1", automatically determine by text and font height */
3232   if (tmi->lines == -1)
3233     tmi->lines = tmi->height / getFontHeight(tmi->font);
3234   else
3235     tmi->height = tmi->lines * getFontHeight(tmi->font);
3236
3237   SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_LEVELSET);
3238
3239 #if 1
3240   FadeOut(REDRAW_FIELD);
3241 #endif
3242
3243   ClearField();
3244   DrawHeadline();
3245
3246   DrawTextCentered(mSY + 100, FONT_TEXT_1, "Level Set Information:");
3247
3248   if (filename != NULL)
3249     DrawTextFile(mSX + ALIGNED_TEXT_XPOS(tmi), mSY + ALIGNED_TEXT_YPOS(tmi),
3250                  filename, tmi->font, tmi->chars, -1, tmi->lines, 0, -1,
3251                  tmi->autowrap, tmi->centered, tmi->parse_comments);
3252   else
3253     DrawTextCentered(mSY + ALIGNED_TEXT_YPOS(tmi), FONT_TEXT_2,
3254                      "No information for this level set.");
3255
3256   DrawTextCentered(mSY + SYSIZE - 20, FONT_TEXT_4,
3257                    "Press any key or button for info menu");
3258
3259 #if 1
3260   FadeIn(REDRAW_FIELD);
3261 #endif
3262 }
3263
3264 void HandleInfoScreen_LevelSet(int button)
3265 {
3266   if (button == MB_MENU_LEAVE)
3267   {
3268     PlaySound(SND_MENU_ITEM_SELECTING);
3269
3270     info_mode = INFO_MODE_MAIN;
3271     DrawInfoScreen();
3272
3273     return;
3274   }
3275   else if (button == MB_MENU_CHOICE)
3276   {
3277     PlaySound(SND_MENU_ITEM_SELECTING);
3278
3279     FadeSoundsAndMusic();
3280
3281 #if 0
3282     FadeOut(REDRAW_FIELD);
3283 #endif
3284
3285     info_mode = INFO_MODE_MAIN;
3286     DrawAndFadeInInfoScreen(REDRAW_FIELD);
3287   }
3288   else
3289   {
3290     PlayMenuSoundIfLoop();
3291   }
3292 }
3293
3294 static void DrawInfoScreenExt(int fade_mask, boolean do_fading)
3295 {
3296   SetMainBackgroundImage(IMG_BACKGROUND_INFO);
3297
3298   if (info_mode == INFO_MODE_TITLE)
3299     DrawInfoScreen_TitleScreen();
3300   else if (info_mode == INFO_MODE_ELEMENTS)
3301     DrawInfoScreen_Elements();
3302   else if (info_mode == INFO_MODE_MUSIC)
3303     DrawInfoScreen_Music();
3304   else if (info_mode == INFO_MODE_CREDITS)
3305     DrawInfoScreen_Credits();
3306   else if (info_mode == INFO_MODE_PROGRAM)
3307     DrawInfoScreen_Program();
3308   else if (info_mode == INFO_MODE_VERSION)
3309     DrawInfoScreen_Version();
3310   else if (info_mode == INFO_MODE_LEVELSET)
3311     DrawInfoScreen_LevelSet();
3312   else
3313     DrawInfoScreen_Main(fade_mask, do_fading);
3314
3315   if (info_mode != INFO_MODE_MAIN &&
3316       info_mode != INFO_MODE_TITLE &&
3317       info_mode != INFO_MODE_MUSIC)
3318   {
3319     PlayMenuSound();
3320     PlayMenuMusic();
3321   }
3322 }
3323
3324 void DrawAndFadeInInfoScreen(int fade_mask)
3325 {
3326   DrawInfoScreenExt(fade_mask, TRUE);
3327 }
3328
3329 void DrawInfoScreen()
3330 {
3331   DrawInfoScreenExt(REDRAW_FIELD, FALSE);
3332 }
3333
3334 void HandleInfoScreen(int mx, int my, int dx, int dy, int button)
3335 {
3336   if (info_mode == INFO_MODE_TITLE)
3337     HandleInfoScreen_TitleScreen(button);
3338   else if (info_mode == INFO_MODE_ELEMENTS)
3339     HandleInfoScreen_Elements(button);
3340   else if (info_mode == INFO_MODE_MUSIC)
3341     HandleInfoScreen_Music(button);
3342   else if (info_mode == INFO_MODE_CREDITS)
3343     HandleInfoScreen_Credits(button);
3344   else if (info_mode == INFO_MODE_PROGRAM)
3345     HandleInfoScreen_Program(button);
3346   else if (info_mode == INFO_MODE_VERSION)
3347     HandleInfoScreen_Version(button);
3348   else if (info_mode == INFO_MODE_LEVELSET)
3349     HandleInfoScreen_LevelSet(button);
3350   else
3351     HandleInfoScreen_Main(mx, my, dx, dy, button);
3352
3353 #if 0
3354   DoAnimation();
3355 #endif
3356 }
3357
3358
3359 /* ========================================================================= */
3360 /* type name functions                                                       */
3361 /* ========================================================================= */
3362
3363 void HandleTypeName(int newxpos, Key key)
3364 {
3365   static char last_player_name[MAX_PLAYER_NAME_LEN + 1];
3366   struct MainControlInfo *mci = getMainControlInfo(MAIN_CONTROL_NAME);
3367   struct TextPosInfo *pos = mci->pos_input;
3368   int startx = mSX + ALIGNED_TEXT_XPOS(pos);
3369   int starty = mSY + ALIGNED_TEXT_YPOS(pos);
3370   static int xpos = 0;
3371   int font_nr = pos->font;
3372   int font_active_nr = FONT_ACTIVE(font_nr);
3373   int font_width = getFontWidth(font_active_nr);
3374   char key_char = getValidConfigValueChar(getCharFromKey(key));
3375   boolean is_valid_key_char = (key_char != 0 && (key_char != ' ' || xpos > 0));
3376   boolean is_active = TRUE;
3377
3378   DrawBackgroundForFont(startx,starty, pos->width, pos->height, font_active_nr);
3379
3380   if (newxpos)
3381   {
3382     strcpy(last_player_name, setup.player_name);
3383
3384     xpos = newxpos;
3385   }
3386   else if (is_valid_key_char && xpos < MAX_PLAYER_NAME_LEN)
3387   {
3388     setup.player_name[xpos] = key_char;
3389     setup.player_name[xpos + 1] = 0;
3390
3391     xpos++;
3392   }
3393   else if ((key == KSYM_Delete || key == KSYM_BackSpace) && xpos > 0)
3394   {
3395     xpos--;
3396
3397     setup.player_name[xpos] = 0;
3398   }
3399   else if (key == KSYM_Return && xpos > 0)
3400   {
3401     SaveSetup();
3402
3403     is_active = FALSE;
3404
3405     game_status = GAME_MODE_MAIN;
3406   }
3407   else if (key == KSYM_Escape)
3408   {
3409     strcpy(setup.player_name, last_player_name);
3410
3411     is_active = FALSE;
3412
3413     game_status = GAME_MODE_MAIN;
3414   }
3415
3416   if (is_active)
3417   {
3418     pos->width = (strlen(setup.player_name) + 1) * font_width;
3419     startx = mSX + ALIGNED_TEXT_XPOS(pos);
3420
3421     DrawText(startx, starty, setup.player_name, font_active_nr);
3422     DrawText(startx + xpos * font_width, starty, "_", font_active_nr);
3423   }
3424   else
3425   {
3426     pos->width = strlen(setup.player_name) * font_width;
3427     startx = mSX + ALIGNED_TEXT_XPOS(pos);
3428
3429     DrawText(startx, starty, setup.player_name, font_nr);
3430   }
3431 }
3432
3433
3434 /* ========================================================================= */
3435 /* tree menu functions                                                       */
3436 /* ========================================================================= */
3437
3438 static void DrawChooseTree(TreeInfo **ti_ptr)
3439 {
3440   UnmapAllGadgets();
3441
3442   FreeScreenGadgets();
3443   CreateScreenGadgets();
3444
3445   CloseDoor(DOOR_CLOSE_2);
3446
3447 #if 1
3448   FadeOut(REDRAW_FIELD);
3449 #endif
3450
3451   ClearField();
3452
3453   HandleChooseTree(0, 0, 0, 0, MB_MENU_INITIALIZE, ti_ptr);
3454   MapScreenTreeGadgets(*ti_ptr);
3455
3456 #if 1
3457   FadeIn(REDRAW_FIELD);
3458 #endif
3459
3460   InitAnimation();
3461 }
3462
3463 static void AdjustChooseTreeScrollbar(int id, int first_entry, TreeInfo *ti)
3464 {
3465   struct GadgetInfo *gi = screen_gadget[id];
3466   int items_max, items_visible, item_position;
3467
3468   items_max = numTreeInfoInGroup(ti);
3469   items_visible = NUM_MENU_ENTRIES_ON_SCREEN;
3470   item_position = first_entry;
3471
3472   if (item_position > items_max - items_visible)
3473     item_position = items_max - items_visible;
3474
3475   ModifyGadget(gi, GDI_SCROLLBAR_ITEMS_MAX, items_max,
3476                GDI_SCROLLBAR_ITEMS_VISIBLE, items_visible,
3477                GDI_SCROLLBAR_ITEM_POSITION, item_position, GDI_END);
3478 }
3479
3480 static void drawChooseTreeList(int first_entry, int num_page_entries,
3481                                TreeInfo *ti)
3482 {
3483   int i;
3484   char *title_string = NULL;
3485   int yoffset_sets = MENU_TITLE1_YPOS;
3486   int yoffset_setup = 16;
3487   int yoffset = (ti->type == TREE_TYPE_LEVEL_DIR ||
3488                  ti->type == TREE_TYPE_LEVEL_NR ? yoffset_sets : yoffset_setup);
3489   int last_game_status = game_status;   /* save current game status */
3490
3491   title_string = ti->infotext;
3492
3493   DrawTextSCentered(mSY - SY + yoffset, FONT_TITLE_1, title_string);
3494
3495 #if 0
3496   /* force LEVELS font on artwork setup screen */
3497   game_status = GAME_MODE_LEVELS;
3498 #endif
3499
3500 #if 1
3501   /* clear tree list area, but not title or scrollbar */
3502   DrawBackground(mSX, mSY + MENU_SCREEN_START_YPOS * 32,
3503                  SC_SCROLLBAR_XPOS + menu.scrollbar_xoffset,
3504                  NUM_MENU_ENTRIES_ON_SCREEN * 32);
3505 #else
3506   /* clear tree list area, but not title or scrollbar */
3507   DrawBackground(mSX, mSY + MENU_SCREEN_START_YPOS * 32,
3508                  SC_SCROLLBAR_XPOS + menu.scrollbar_xoffset,
3509                  MAX_MENU_ENTRIES_ON_SCREEN * 32);
3510 #endif
3511
3512   for (i = 0; i < num_page_entries; i++)
3513   {
3514     TreeInfo *node, *node_first;
3515     int entry_pos = first_entry + i;
3516     int xpos = MENU_SCREEN_START_XPOS;
3517     int ypos = MENU_SCREEN_START_YPOS + i;
3518     int startx = mSX + xpos * 32;
3519     int starty = mSY + ypos * 32;
3520     int font_nr = FONT_TEXT_1;
3521     int font_xoffset = getFontBitmapInfo(font_nr)->draw_xoffset;
3522     int startx_text = startx + font_xoffset;
3523     int startx_scrollbar = mSX + SC_SCROLLBAR_XPOS + menu.scrollbar_xoffset;
3524     int text_size = startx_scrollbar - startx_text;
3525     int max_buffer_len = text_size / getFontWidth(font_nr);
3526     char buffer[max_buffer_len + 1];
3527
3528     node_first = getTreeInfoFirstGroupEntry(ti);
3529     node = getTreeInfoFromPos(node_first, entry_pos);
3530
3531     strncpy(buffer, node->name, max_buffer_len);
3532     buffer[max_buffer_len] = '\0';
3533
3534     DrawText(startx, starty, buffer, font_nr + node->color);
3535
3536     if (node->parent_link)
3537       initCursor(i, IMG_MENU_BUTTON_LEAVE_MENU);
3538     else if (node->level_group)
3539       initCursor(i, IMG_MENU_BUTTON_ENTER_MENU);
3540     else
3541       initCursor(i, IMG_MENU_BUTTON);
3542   }
3543
3544   game_status = last_game_status;       /* restore current game status */
3545
3546   redraw_mask |= REDRAW_FIELD;
3547 }
3548
3549 static void drawChooseTreeInfo(int entry_pos, TreeInfo *ti)
3550 {
3551   TreeInfo *node, *node_first;
3552   int x, last_redraw_mask = redraw_mask;
3553   int ypos = MENU_TITLE2_YPOS;
3554   int font_nr = FONT_TITLE_2;
3555
3556   if (ti->type == TREE_TYPE_LEVEL_NR)
3557     DrawTextFCentered(ypos, font_nr, leveldir_current->name);
3558
3559   if (ti->type != TREE_TYPE_LEVEL_DIR)
3560     return;
3561
3562   node_first = getTreeInfoFirstGroupEntry(ti);
3563   node = getTreeInfoFromPos(node_first, entry_pos);
3564
3565   DrawBackgroundForFont(SX, SY + ypos, SXSIZE, getFontHeight(font_nr), font_nr);
3566
3567 #if 1
3568   if (node->parent_link)
3569     DrawTextFCentered(ypos, font_nr, "leave \"%s\"",
3570                       node->node_parent->name);
3571   else if (node->level_group)
3572     DrawTextFCentered(ypos, font_nr, "enter \"%s\"",
3573                       node->name);
3574   else if (ti->type == TREE_TYPE_LEVEL_DIR)
3575     DrawTextFCentered(ypos, font_nr, "%3d %s (%s)",
3576                       node->levels, (node->levels > 1 ? "levels" : "level"),
3577                       node->class_desc);
3578 #else
3579   if (node->parent_link)
3580     DrawTextFCentered(ypos, font_nr, "leave group \"%s\"",
3581                       node->class_desc);
3582   else if (node->level_group)
3583     DrawTextFCentered(ypos, font_nr, "enter group \"%s\"",
3584                       node->class_desc);
3585   else if (ti->type == TREE_TYPE_LEVEL_DIR)
3586     DrawTextFCentered(ypos, font_nr, "%3d levels (%s)",
3587                       node->levels, node->class_desc);
3588 #endif
3589
3590   /* let BackToFront() redraw only what is needed */
3591   redraw_mask = last_redraw_mask | REDRAW_TILES;
3592   for (x = 0; x < SCR_FIELDX; x++)
3593     MarkTileDirty(x, 1);
3594 }
3595
3596 static void HandleChooseTree(int mx, int my, int dx, int dy, int button,
3597                              TreeInfo **ti_ptr)
3598 {
3599   TreeInfo *ti = *ti_ptr;
3600   int x = 0;
3601   int y = ti->cl_cursor;
3602   int step = (button == 1 ? 1 : button == 2 ? 5 : 10);
3603   int num_entries = numTreeInfoInGroup(ti);
3604   int num_page_entries;
3605   int last_game_status = game_status;   /* save current game status */
3606   boolean position_set_by_scrollbar = (dx == 999);
3607
3608 #if 0
3609   /* force LEVELS draw offset on choose level and artwork setup screen */
3610   game_status = GAME_MODE_LEVELS;
3611 #endif
3612
3613   if (num_entries <= NUM_MENU_ENTRIES_ON_SCREEN)
3614     num_page_entries = num_entries;
3615   else
3616     num_page_entries = NUM_MENU_ENTRIES_ON_SCREEN;
3617
3618   game_status = last_game_status;       /* restore current game status */
3619
3620   if (button == MB_MENU_INITIALIZE)
3621   {
3622     int num_entries = numTreeInfoInGroup(ti);
3623     int entry_pos = posTreeInfo(ti);
3624
3625     if (ti->cl_first == -1)
3626     {
3627       /* only on initialization */
3628       ti->cl_first = MAX(0, entry_pos - num_page_entries + 1);
3629       ti->cl_cursor = entry_pos - ti->cl_first;
3630     }
3631     else if (ti->cl_cursor >= num_page_entries ||
3632              (num_entries > num_page_entries &&
3633               num_entries - ti->cl_first < num_page_entries))
3634     {
3635       /* only after change of list size (by custom graphic configuration) */
3636       ti->cl_first = MAX(0, entry_pos - num_page_entries + 1);
3637       ti->cl_cursor = entry_pos - ti->cl_first;
3638     }
3639
3640     if (position_set_by_scrollbar)
3641       ti->cl_first = dy;
3642     else
3643       AdjustChooseTreeScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL,
3644                                 ti->cl_first, ti);
3645
3646     drawChooseTreeList(ti->cl_first, num_page_entries, ti);
3647     drawChooseTreeInfo(ti->cl_first + ti->cl_cursor, ti);
3648     drawChooseTreeCursor(ti->cl_cursor, TRUE);
3649
3650     return;
3651   }
3652   else if (button == MB_MENU_LEAVE)
3653   {
3654     FadeSetLeaveMenu();
3655
3656     PlaySound(SND_MENU_ITEM_SELECTING);
3657
3658     if (ti->node_parent)
3659     {
3660       *ti_ptr = ti->node_parent;
3661       DrawChooseTree(ti_ptr);
3662     }
3663     else if (game_status == GAME_MODE_SETUP)
3664     {
3665       if (setup_mode == SETUP_MODE_CHOOSE_GAME_SPEED ||
3666           setup_mode == SETUP_MODE_CHOOSE_SCROLL_DELAY)
3667         execSetupGame();
3668       else if (setup_mode == SETUP_MODE_CHOOSE_SCREEN_MODE ||
3669                setup_mode == SETUP_MODE_CHOOSE_WINDOW_SIZE ||
3670                setup_mode == SETUP_MODE_CHOOSE_SCALING_TYPE)
3671         execSetupGraphics();
3672       else if (setup_mode == SETUP_MODE_CHOOSE_VOLUME_SIMPLE ||
3673                setup_mode == SETUP_MODE_CHOOSE_VOLUME_LOOPS ||
3674                setup_mode == SETUP_MODE_CHOOSE_VOLUME_MUSIC)
3675         execSetupSound();
3676       else
3677         execSetupArtwork();
3678     }
3679     else
3680     {
3681       if (game_status == GAME_MODE_LEVELNR)
3682         level_nr = atoi(level_number_current->identifier);
3683
3684       game_status = GAME_MODE_MAIN;
3685
3686       DrawMainMenuExt(REDRAW_FIELD, FALSE);
3687     }
3688
3689     return;
3690   }
3691
3692   if (mx || my)         /* mouse input */
3693   {
3694     int last_game_status = game_status; /* save current game status */
3695
3696 #if 0
3697     /* force LEVELS draw offset on artwork setup screen */
3698     game_status = GAME_MODE_LEVELS;
3699 #endif
3700
3701     x = (mx - mSX) / 32;
3702     y = (my - mSY) / 32 - MENU_SCREEN_START_YPOS;
3703
3704     game_status = last_game_status;     /* restore current game status */
3705   }
3706   else if (dx || dy)    /* keyboard or scrollbar/scrollbutton input */
3707   {
3708     /* move cursor instead of scrolling when already at start/end of list */
3709     if (dy == -1 * SCROLL_LINE && ti->cl_first == 0)
3710       dy = -1;
3711     else if (dy == +1 * SCROLL_LINE &&
3712              ti->cl_first + num_page_entries == num_entries)
3713       dy = 1;
3714
3715     /* handle scrolling screen one line or page */
3716     if (ti->cl_cursor + dy < 0 ||
3717         ti->cl_cursor + dy > num_page_entries - 1)
3718     {
3719       if (ABS(dy) == SCROLL_PAGE)
3720         step = num_page_entries - 1;
3721
3722       if (dy < 0 && ti->cl_first > 0)
3723       {
3724         /* scroll page/line up */
3725
3726         ti->cl_first -= step;
3727         if (ti->cl_first < 0)
3728           ti->cl_first = 0;
3729
3730         drawChooseTreeList(ti->cl_first, num_page_entries, ti);
3731         drawChooseTreeInfo(ti->cl_first + ti->cl_cursor, ti);
3732         drawChooseTreeCursor(ti->cl_cursor, TRUE);
3733
3734         AdjustChooseTreeScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL,
3735                                   ti->cl_first, ti);
3736       }
3737       else if (dy > 0 && ti->cl_first + num_page_entries < num_entries)
3738       {
3739         /* scroll page/line down */
3740
3741         ti->cl_first += step;
3742         if (ti->cl_first + num_page_entries > num_entries)
3743           ti->cl_first = MAX(0, num_entries - num_page_entries);
3744
3745         drawChooseTreeList(ti->cl_first, num_page_entries, ti);
3746         drawChooseTreeInfo(ti->cl_first + ti->cl_cursor, ti);
3747         drawChooseTreeCursor(ti->cl_cursor, TRUE);
3748
3749         AdjustChooseTreeScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL,
3750                                   ti->cl_first, ti);
3751       }
3752
3753       return;
3754     }
3755
3756     /* handle moving cursor one line */
3757     y = ti->cl_cursor + dy;
3758   }
3759
3760   if (dx == 1)
3761   {
3762     TreeInfo *node_first, *node_cursor;
3763     int entry_pos = ti->cl_first + y;
3764
3765     node_first = getTreeInfoFirstGroupEntry(ti);
3766     node_cursor = getTreeInfoFromPos(node_first, entry_pos);
3767
3768     if (node_cursor->node_group)
3769     {
3770       FadeSetEnterMenu();
3771
3772       PlaySound(SND_MENU_ITEM_SELECTING);
3773
3774       node_cursor->cl_first = ti->cl_first;
3775       node_cursor->cl_cursor = ti->cl_cursor;
3776       *ti_ptr = node_cursor->node_group;
3777       DrawChooseTree(ti_ptr);
3778
3779       return;
3780     }
3781   }
3782   else if (dx == -1 && ti->node_parent)
3783   {
3784     FadeSetLeaveMenu();
3785
3786     PlaySound(SND_MENU_ITEM_SELECTING);
3787
3788     *ti_ptr = ti->node_parent;
3789     DrawChooseTree(ti_ptr);
3790
3791     return;
3792   }
3793
3794   if (!anyScrollbarGadgetActive() &&
3795       IN_VIS_FIELD(x, y) &&
3796       mx < screen_gadget[SCREEN_CTRL_ID_SCROLL_VERTICAL]->x &&
3797       y >= 0 && y < num_page_entries)
3798   {
3799     if (button)
3800     {
3801       if (y != ti->cl_cursor)
3802       {
3803         PlaySound(SND_MENU_ITEM_ACTIVATING);
3804
3805         drawChooseTreeCursor(ti->cl_cursor, FALSE);
3806         drawChooseTreeCursor(y, TRUE);
3807         drawChooseTreeInfo(ti->cl_first + y, ti);
3808
3809         ti->cl_cursor = y;
3810       }
3811     }
3812     else
3813     {
3814       TreeInfo *node_first, *node_cursor;
3815       int entry_pos = ti->cl_first + y;
3816
3817       PlaySound(SND_MENU_ITEM_SELECTING);
3818
3819       node_first = getTreeInfoFirstGroupEntry(ti);
3820       node_cursor = getTreeInfoFromPos(node_first, entry_pos);
3821
3822       if (node_cursor->node_group)
3823       {
3824         FadeSetEnterMenu();
3825
3826         node_cursor->cl_first = ti->cl_first;
3827         node_cursor->cl_cursor = ti->cl_cursor;
3828         *ti_ptr = node_cursor->node_group;
3829         DrawChooseTree(ti_ptr);
3830       }
3831       else if (node_cursor->parent_link)
3832       {
3833         FadeSetLeaveMenu();
3834
3835         *ti_ptr = node_cursor->node_parent;
3836         DrawChooseTree(ti_ptr);
3837       }
3838       else
3839       {
3840 #if 1
3841         FadeSetEnterMenu();
3842 #else
3843         FadeSetEnterScreen();
3844 #endif
3845
3846         node_cursor->cl_first = ti->cl_first;
3847         node_cursor->cl_cursor = ti->cl_cursor;
3848         *ti_ptr = node_cursor;
3849
3850         if (ti->type == TREE_TYPE_LEVEL_DIR)
3851         {
3852           LoadLevelSetup_SeriesInfo();
3853
3854           SaveLevelSetup_LastSeries();
3855           SaveLevelSetup_SeriesInfo();
3856           TapeErase();
3857         }
3858
3859         if (game_status == GAME_MODE_SETUP)
3860         {
3861           if (setup_mode == SETUP_MODE_CHOOSE_GAME_SPEED ||
3862               setup_mode == SETUP_MODE_CHOOSE_SCROLL_DELAY)
3863             execSetupGame();
3864           else if (setup_mode == SETUP_MODE_CHOOSE_SCREEN_MODE ||
3865                    setup_mode == SETUP_MODE_CHOOSE_WINDOW_SIZE ||
3866                    setup_mode == SETUP_MODE_CHOOSE_SCALING_TYPE)
3867             execSetupGraphics();
3868           else if (setup_mode == SETUP_MODE_CHOOSE_VOLUME_SIMPLE ||
3869                    setup_mode == SETUP_MODE_CHOOSE_VOLUME_LOOPS ||
3870                    setup_mode == SETUP_MODE_CHOOSE_VOLUME_MUSIC)
3871             execSetupSound();
3872           else
3873             execSetupArtwork();
3874         }
3875         else
3876         {
3877           if (game_status == GAME_MODE_LEVELNR)
3878             level_nr = atoi(level_number_current->identifier);
3879
3880           game_status = GAME_MODE_MAIN;
3881
3882           DrawMainMenu();
3883         }
3884       }
3885     }
3886   }
3887 }
3888
3889 void DrawChooseLevelSet()
3890 {
3891   SetMainBackgroundImage(IMG_BACKGROUND_LEVELS);
3892
3893   DrawChooseTree(&leveldir_current);
3894
3895   PlayMenuSound();
3896   PlayMenuMusic();
3897 }
3898
3899 void HandleChooseLevelSet(int mx, int my, int dx, int dy, int button)
3900 {
3901   HandleChooseTree(mx, my, dx, dy, button, &leveldir_current);
3902
3903 #if 0
3904   DoAnimation();
3905 #endif
3906 }
3907
3908 void DrawChooseLevelNr()
3909 {
3910   int i;
3911
3912   if (level_number != NULL)
3913   {
3914     freeTreeInfo(level_number);
3915
3916     level_number = NULL;
3917   }
3918
3919   for (i = leveldir_current->first_level; i <= leveldir_current->last_level;i++)
3920   {
3921     TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_LEVEL_NR);
3922     char identifier[32], name[32];
3923     int value = i;
3924
3925     /* temporarily load level info to get level name */
3926     LoadLevelInfoOnly(i);
3927
3928     ti->node_top = &level_number;
3929     ti->sort_priority = 10000 + value;
3930     ti->color = (level.no_valid_file ? FC_BLUE :
3931                  LevelStats_getSolved(i) ? FC_GREEN :
3932                  LevelStats_getPlayed(i) ? FC_YELLOW : FC_RED);
3933
3934     sprintf(identifier, "%d", value);
3935     sprintf(name, "%03d: %s", value,
3936             (level.no_valid_file ? "(no file)" : level.name));
3937
3938     setString(&ti->identifier, identifier);
3939     setString(&ti->name, name);
3940     setString(&ti->name_sorting, name);
3941
3942     pushTreeInfo(&level_number, ti);
3943   }
3944
3945   /* sort level number values to start with lowest level number */
3946   sortTreeInfo(&level_number);
3947
3948   /* set current level number to current level number */
3949   level_number_current =
3950     getTreeInfoFromIdentifier(level_number, i_to_a(level_nr));
3951
3952   /* if that also fails, set current level number to first available level */
3953   if (level_number_current == NULL)
3954     level_number_current = level_number;
3955
3956   SetMainBackgroundImage(IMG_BACKGROUND_LEVELNR);
3957
3958 #if 1
3959   DrawChooseTree(&level_number_current);
3960 #else
3961   DrawChooseTree(&leveldir_current);
3962 #endif
3963
3964   PlayMenuSound();
3965   PlayMenuMusic();
3966 }
3967
3968 void HandleChooseLevelNr(int mx, int my, int dx, int dy, int button)
3969 {
3970 #if 1
3971   HandleChooseTree(mx, my, dx, dy, button, &level_number_current);
3972 #else
3973   HandleChooseTree(mx, my, dx, dy, button, &leveldir_current);
3974 #endif
3975
3976 #if 0
3977   DoAnimation();
3978 #endif
3979 }
3980
3981 void DrawHallOfFame(int highlight_position)
3982 {
3983   UnmapAllGadgets();
3984   FadeSoundsAndMusic();
3985
3986   /* (this is needed when called from GameEnd() after winning a game) */
3987   KeyboardAutoRepeatOn();
3988   ActivateJoystick();
3989
3990   /* (this is needed when called from GameEnd() after winning a game) */
3991   SetDrawDeactivationMask(REDRAW_NONE);
3992   SetDrawBackgroundMask(REDRAW_FIELD);
3993
3994   CloseDoor(DOOR_CLOSE_2);
3995
3996   if (highlight_position < 0) 
3997     LoadScore(level_nr);
3998
3999   FadeSetEnterScreen();
4000
4001   // printf("::: %d: %d\n", game_status, menu.enter_screen[game_status]);
4002
4003 #if 1
4004   FadeOut(REDRAW_FIELD);
4005 #endif
4006
4007   InitAnimation();
4008
4009   PlayMenuSound();
4010   PlayMenuMusic();
4011
4012   HandleHallOfFame(highlight_position, 0, 0, 0, MB_MENU_INITIALIZE);
4013
4014 #if 1
4015   FadeIn(REDRAW_FIELD);
4016 #endif
4017 }
4018
4019 static void drawHallOfFameList(int first_entry, int highlight_position)
4020 {
4021   int i, j;
4022
4023   SetMainBackgroundImage(IMG_BACKGROUND_SCORES);
4024   ClearField();
4025
4026   DrawTextSCentered(MENU_TITLE1_YPOS, FONT_TITLE_1, "Hall Of Fame");
4027   DrawTextFCentered(MENU_TITLE2_YPOS, FONT_TITLE_2,
4028                     "HighScores of Level %d", level_nr);
4029
4030   for (i = 0; i < NUM_MENU_ENTRIES_ON_SCREEN; i++)
4031   {
4032     int entry = first_entry + i;
4033     boolean active = (entry == highlight_position);
4034     int font_nr1 = (active ? FONT_TEXT_1_ACTIVE : FONT_TEXT_1);
4035     int font_nr2 = (active ? FONT_TEXT_2_ACTIVE : FONT_TEXT_2);
4036     int font_nr3 = (active ? FONT_TEXT_3_ACTIVE : FONT_TEXT_3);
4037     int font_nr4 = (active ? FONT_TEXT_4_ACTIVE : FONT_TEXT_4);
4038     int dx1 = 3 * getFontWidth(font_nr1);
4039     int dx2 = dx1 + getFontWidth(font_nr1);
4040 #if 1
4041     int dx3 = SXSIZE - 5 * getFontWidth(font_nr4);
4042     int num_dots = (dx3 - dx2) / getFontWidth(font_nr3);
4043 #else
4044     int dx3 = dx2 + 25 * getFontWidth(font_nr3);
4045 #endif
4046     int sy = mSY + 64 + i * 32;
4047
4048     DrawText(mSX, sy, int2str(entry + 1, 3), font_nr1);
4049     DrawText(mSX + dx1, sy, ".", font_nr1);
4050 #if 1
4051     for (j = 0; j < num_dots; j++)
4052       DrawText(mSX + dx2 + j * getFontWidth(font_nr3), sy, ".", font_nr3);
4053 #else
4054     DrawText(mSX + dx2, sy, ".........................", font_nr3);
4055 #endif
4056
4057     if (!strEqual(highscore[entry].Name, EMPTY_PLAYER_NAME))
4058       DrawText(mSX + dx2, sy, highscore[entry].Name, font_nr2);
4059
4060     DrawText(mSX + dx3, sy, int2str(highscore[entry].Score, 5), font_nr4);
4061   }
4062
4063   redraw_mask |= REDRAW_FIELD;
4064 }
4065
4066 void HandleHallOfFame(int mx, int my, int dx, int dy, int button)
4067 {
4068   static int first_entry = 0;
4069   static int highlight_position = 0;
4070   int step = (button == 1 ? 1 : button == 2 ? 5 : 10);
4071
4072   if (button == MB_MENU_INITIALIZE)
4073   {
4074     first_entry = 0;
4075     highlight_position = mx;
4076     drawHallOfFameList(first_entry, highlight_position);
4077
4078     return;
4079   }
4080
4081   if (ABS(dy) == SCROLL_PAGE)           /* handle scrolling one page */
4082     step = NUM_MENU_ENTRIES_ON_SCREEN - 1;
4083
4084   if (dy < 0)
4085   {
4086     if (first_entry > 0)
4087     {
4088       first_entry -= step;
4089       if (first_entry < 0)
4090         first_entry = 0;
4091
4092       drawHallOfFameList(first_entry, highlight_position);
4093     }
4094   }
4095   else if (dy > 0)
4096   {
4097     if (first_entry + NUM_MENU_ENTRIES_ON_SCREEN < MAX_SCORE_ENTRIES)
4098     {
4099       first_entry += step;
4100       if (first_entry + NUM_MENU_ENTRIES_ON_SCREEN > MAX_SCORE_ENTRIES)
4101         first_entry = MAX(0, MAX_SCORE_ENTRIES - NUM_MENU_ENTRIES_ON_SCREEN);
4102
4103       drawHallOfFameList(first_entry, highlight_position);
4104     }
4105   }
4106   else if (button == MB_MENU_LEAVE)
4107   {
4108     PlaySound(SND_MENU_ITEM_SELECTING);
4109
4110     FadeSound(SND_BACKGROUND_SCORES);
4111
4112     game_status = GAME_MODE_MAIN;
4113
4114     DrawMainMenu();
4115   }
4116   else if (button == MB_MENU_CHOICE)
4117   {
4118     PlaySound(SND_MENU_ITEM_SELECTING);
4119
4120     FadeSound(SND_BACKGROUND_SCORES);
4121
4122 #if 0
4123     FadeOut(REDRAW_FIELD);
4124 #endif
4125
4126     game_status = GAME_MODE_MAIN;
4127
4128     DrawAndFadeInMainMenu(REDRAW_FIELD);
4129   }
4130
4131   if (game_status == GAME_MODE_SCORES)
4132     PlayMenuSoundIfLoop();
4133
4134 #if 0
4135   DoAnimation();
4136 #endif
4137 }
4138
4139
4140 /* ========================================================================= */
4141 /* setup screen functions                                                    */
4142 /* ========================================================================= */
4143
4144 static struct TokenInfo *setup_info;
4145 static int num_setup_info;
4146
4147 static char *screen_mode_text;
4148 static char *window_size_text;
4149 static char *scaling_type_text;
4150 static char *scroll_delay_text;
4151 static char *game_speed_text;
4152 static char *graphics_set_name;
4153 static char *sounds_set_name;
4154 static char *music_set_name;
4155 static char *volume_simple_text;
4156 static char *volume_loops_text;
4157 static char *volume_music_text;
4158
4159 static void execSetupMain()
4160 {
4161   setup_mode = SETUP_MODE_MAIN;
4162
4163   DrawSetupScreen();
4164 }
4165
4166 static void execSetupGame_setGameSpeeds()
4167 {
4168   if (game_speeds == NULL)
4169   {
4170     int i;
4171
4172     for (i = 0; game_speeds_list[i].value != -1; i++)
4173     {
4174       TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED);
4175       char identifier[32], name[32];
4176       int value = game_speeds_list[i].value;
4177       char *text = game_speeds_list[i].text;
4178
4179       ti->node_top = &game_speeds;
4180       ti->sort_priority = 10000 - value;
4181
4182       sprintf(identifier, "%d", value);
4183       sprintf(name, "%s", text);
4184
4185       setString(&ti->identifier, identifier);
4186       setString(&ti->name, name);
4187       setString(&ti->name_sorting, name);
4188       setString(&ti->infotext, "Game Speed");
4189
4190       pushTreeInfo(&game_speeds, ti);
4191     }
4192
4193     /* sort game speed values to start with slowest game speed */
4194     sortTreeInfo(&game_speeds);
4195
4196     /* set current game speed to configured game speed value */
4197     game_speed_current =
4198       getTreeInfoFromIdentifier(game_speeds, i_to_a(setup.game_frame_delay));
4199
4200     /* if that fails, set current game speed to reliable default value */
4201     if (game_speed_current == NULL)
4202       game_speed_current =
4203         getTreeInfoFromIdentifier(game_speeds, i_to_a(GAME_FRAME_DELAY));
4204
4205     /* if that also fails, set current game speed to first available speed */
4206     if (game_speed_current == NULL)
4207       game_speed_current = game_speeds;
4208   }
4209
4210   setup.game_frame_delay = atoi(game_speed_current->identifier);
4211
4212   /* needed for displaying game speed text instead of identifier */
4213   game_speed_text = game_speed_current->name;
4214 }
4215
4216 static void execSetupGame_setScrollDelays()
4217 {
4218   if (scroll_delays == NULL)
4219   {
4220     int i;
4221
4222     for (i = 0; scroll_delays_list[i].value != -1; i++)
4223     {
4224       TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED);
4225       char identifier[32], name[32];
4226       int value = scroll_delays_list[i].value;
4227       char *text = scroll_delays_list[i].text;
4228
4229       ti->node_top = &scroll_delays;
4230       ti->sort_priority = value;
4231
4232       sprintf(identifier, "%d", value);
4233       sprintf(name, "%s", text);
4234
4235       setString(&ti->identifier, identifier);
4236       setString(&ti->name, name);
4237       setString(&ti->name_sorting, name);
4238       setString(&ti->infotext, "Scaling Type");
4239
4240       pushTreeInfo(&scroll_delays, ti);
4241     }
4242
4243     /* sort scaling type values to start with lowest scaling type value */
4244     sortTreeInfo(&scroll_delays);
4245
4246     /* set current scaling type value to configured scaling type value */
4247     scroll_delay_current =
4248       getTreeInfoFromIdentifier(scroll_delays,i_to_a(setup.scroll_delay_value));
4249
4250     /* if that fails, set current scaling type to reliable default value */
4251     if (scroll_delay_current == NULL)
4252       scroll_delay_current =
4253         getTreeInfoFromIdentifier(scroll_delays, i_to_a(STD_SCROLL_DELAY));
4254
4255     /* if that also fails, set current scaling type to first available value */
4256     if (scroll_delay_current == NULL)
4257       scroll_delay_current = scroll_delays;
4258   }
4259
4260   setup.scroll_delay_value = atoi(scroll_delay_current->identifier);
4261
4262   /* needed for displaying scaling type text instead of identifier */
4263   scroll_delay_text = scroll_delay_current->name;
4264 }
4265
4266 static void execSetupGame()
4267 {
4268   execSetupGame_setGameSpeeds();
4269   execSetupGame_setScrollDelays();
4270
4271   setup_mode = SETUP_MODE_GAME;
4272
4273   DrawSetupScreen();
4274 }
4275
4276 static void execSetupChooseGameSpeed()
4277 {
4278   setup_mode = SETUP_MODE_CHOOSE_GAME_SPEED;
4279
4280   DrawSetupScreen();
4281 }
4282
4283 static void execSetupChooseScrollDelay()
4284 {
4285   setup_mode = SETUP_MODE_CHOOSE_SCROLL_DELAY;
4286
4287   DrawSetupScreen();
4288 }
4289
4290 static void execSetupEditor()
4291 {
4292   setup_mode = SETUP_MODE_EDITOR;
4293
4294   DrawSetupScreen();
4295 }
4296
4297 static void execSetupGraphics_setWindowSizes(boolean update_list)
4298 {
4299   if (window_sizes != NULL && update_list)
4300   {
4301     freeTreeInfo(window_sizes);
4302
4303     window_sizes = NULL;
4304   }
4305
4306   if (window_sizes == NULL)
4307   {
4308     boolean current_window_size_found = FALSE;
4309     int i;
4310
4311     for (i = 0; window_sizes_list[i].value != -1; i++)
4312     {
4313       TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED);
4314       char identifier[32], name[32];
4315       int value = window_sizes_list[i].value;
4316       char *text = window_sizes_list[i].text;
4317
4318       ti->node_top = &window_sizes;
4319       ti->sort_priority = value;
4320
4321       sprintf(identifier, "%d", value);
4322       sprintf(name, "%s", text);
4323
4324       setString(&ti->identifier, identifier);
4325       setString(&ti->name, name);
4326       setString(&ti->name_sorting, name);
4327       setString(&ti->infotext, "Window Scaling");
4328
4329       pushTreeInfo(&window_sizes, ti);
4330
4331       if (value == setup.window_scaling_percent)
4332         current_window_size_found = TRUE;
4333     }
4334
4335     if (!current_window_size_found)
4336     {
4337       // add entry for non-preset window scaling value
4338
4339       TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED);
4340       char identifier[32], name[32];
4341       int value = setup.window_scaling_percent;
4342
4343       ti->node_top = &window_sizes;
4344       ti->sort_priority = value;
4345
4346       sprintf(identifier, "%d", value);
4347       sprintf(name, "%d %% (Current)", value);
4348
4349       setString(&ti->identifier, identifier);
4350       setString(&ti->name, name);
4351       setString(&ti->name_sorting, name);
4352       setString(&ti->infotext, "Window Scaling");
4353
4354       pushTreeInfo(&window_sizes, ti);
4355     }
4356
4357     /* sort window size values to start with lowest window size value */
4358     sortTreeInfo(&window_sizes);
4359
4360     /* set current window size value to configured window size value */
4361     window_size_current =
4362       getTreeInfoFromIdentifier(window_sizes,
4363                                 i_to_a(setup.window_scaling_percent));
4364
4365     /* if that fails, set current window size to reliable default value */
4366     if (window_size_current == NULL)
4367       window_size_current =
4368         getTreeInfoFromIdentifier(window_sizes,
4369                                   i_to_a(STD_WINDOW_SCALING_PERCENT));
4370
4371     /* if that also fails, set current window size to first available value */
4372     if (window_size_current == NULL)
4373       window_size_current = window_sizes;
4374   }
4375
4376   setup.window_scaling_percent = atoi(window_size_current->identifier);
4377
4378   /* needed for displaying window size text instead of identifier */
4379   window_size_text = window_size_current->name;
4380 }
4381
4382 static void execSetupGraphics_setScalingTypes()
4383 {
4384   if (scaling_types == NULL)
4385   {
4386     int i;
4387
4388     for (i = 0; scaling_types_list[i].value != NULL; i++)
4389     {
4390       TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED);
4391       char identifier[32], name[32];
4392       char *value = scaling_types_list[i].value;
4393       char *text = scaling_types_list[i].text;
4394
4395       ti->node_top = &scaling_types;
4396       ti->sort_priority = i;
4397
4398       sprintf(identifier, "%s", value);
4399       sprintf(name, "%s", text);
4400
4401       setString(&ti->identifier, identifier);
4402       setString(&ti->name, name);
4403       setString(&ti->name_sorting, name);
4404       setString(&ti->infotext, "Anti-Aliasing");
4405
4406       pushTreeInfo(&scaling_types, ti);
4407     }
4408
4409     /* sort scaling type values to start with lowest scaling type value */
4410     sortTreeInfo(&scaling_types);
4411
4412     /* set current scaling type value to configured scaling type value */
4413     scaling_type_current =
4414       getTreeInfoFromIdentifier(scaling_types, setup.window_scaling_quality);
4415
4416     /* if that fails, set current scaling type to reliable default value */
4417     if (scaling_type_current == NULL)
4418       scaling_type_current =
4419         getTreeInfoFromIdentifier(scaling_types, SCALING_QUALITY_DEFAULT);
4420
4421     /* if that also fails, set current scaling type to first available value */
4422     if (scaling_type_current == NULL)
4423       scaling_type_current = scaling_types;
4424   }
4425
4426   setup.window_scaling_quality = scaling_type_current->identifier;
4427
4428   /* needed for displaying scaling type text instead of identifier */
4429   scaling_type_text = scaling_type_current->name;
4430 }
4431
4432 static void execSetupGraphics_setScreenModes()
4433 {
4434   // if (screen_modes == NULL && video.fullscreen_available)
4435   if (screen_modes == NULL && video.fullscreen_modes != NULL)
4436   {
4437     int i;
4438
4439     for (i = 0; video.fullscreen_modes[i].width != -1; i++)
4440     {
4441       TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED);
4442       char identifier[32], name[32];
4443       int x = video.fullscreen_modes[i].width;
4444       int y = video.fullscreen_modes[i].height;
4445       int xx, yy;
4446
4447       get_aspect_ratio_from_screen_mode(&video.fullscreen_modes[i], &xx, &yy);
4448
4449       ti->node_top = &screen_modes;
4450       ti->sort_priority = x * 10000 + y;
4451
4452       sprintf(identifier, "%dx%d", x, y);
4453       sprintf(name, "%d x %d [%d:%d]", x, y, xx, yy);
4454
4455       setString(&ti->identifier, identifier);
4456       setString(&ti->name, name);
4457       setString(&ti->name_sorting, name);
4458       setString(&ti->infotext, "Fullscreen Mode");
4459
4460       pushTreeInfo(&screen_modes, ti);
4461     }
4462
4463     /* sort fullscreen modes to start with lowest available screen resolution */
4464     sortTreeInfo(&screen_modes);
4465
4466     /* set current screen mode for fullscreen mode to configured setup value */
4467     screen_mode_current = getTreeInfoFromIdentifier(screen_modes,
4468                                                     setup.fullscreen_mode);
4469
4470     /* if that fails, set current screen mode to reliable default value */
4471     if (screen_mode_current == NULL)
4472       screen_mode_current = getTreeInfoFromIdentifier(screen_modes,
4473                                                       DEFAULT_FULLSCREEN_MODE);
4474
4475     /* if that also fails, set current screen mode to first available mode */
4476     if (screen_mode_current == NULL)
4477       screen_mode_current = screen_modes;
4478
4479     if (screen_mode_current == NULL)
4480       video.fullscreen_available = FALSE;
4481   }
4482
4483   // if (video.fullscreen_available)
4484   if (screen_mode_current != NULL)
4485   {
4486     setup.fullscreen_mode = screen_mode_current->identifier;
4487
4488     /* needed for displaying screen mode name instead of identifier */
4489     screen_mode_text = screen_mode_current->name;
4490   }
4491 }
4492
4493 static void execSetupGraphics()
4494 {
4495   if (setup_mode == SETUP_MODE_CHOOSE_WINDOW_SIZE)
4496   {
4497     // update "setup.window_scaling_percent" from list selection
4498     execSetupGraphics_setWindowSizes(FALSE);
4499   }
4500   else
4501   {
4502     // update list selection from "setup.window_scaling_percent"
4503     execSetupGraphics_setWindowSizes(TRUE);
4504   }
4505
4506   execSetupGraphics_setScalingTypes();
4507   execSetupGraphics_setScreenModes();
4508
4509   setup_mode = SETUP_MODE_GRAPHICS;
4510
4511   DrawSetupScreen();
4512
4513 #if defined(TARGET_SDL2)
4514   // window scaling may have changed at this point
4515   ToggleFullscreenOrChangeWindowScalingIfNeeded();
4516
4517   // window scaling quality may have changed at this point
4518   if (!strEqual(setup.window_scaling_quality, video.window_scaling_quality))
4519     SDLSetWindowScalingQuality(setup.window_scaling_quality);
4520 #endif
4521 }
4522
4523 #if !defined(PLATFORM_ANDROID)
4524 #if defined(TARGET_SDL2)
4525 static void execSetupChooseWindowSize()
4526 {
4527 #if 0
4528   if (!video.window_scaling_available)
4529     return;
4530 #endif
4531
4532   setup_mode = SETUP_MODE_CHOOSE_WINDOW_SIZE;
4533
4534   DrawSetupScreen();
4535 }
4536
4537 static void execSetupChooseScalingType()
4538 {
4539   setup_mode = SETUP_MODE_CHOOSE_SCALING_TYPE;
4540
4541   DrawSetupScreen();
4542 }
4543 #else
4544 static void execSetupChooseScreenMode()
4545 {
4546   if (!video.fullscreen_available)
4547     return;
4548
4549   setup_mode = SETUP_MODE_CHOOSE_SCREEN_MODE;
4550
4551   DrawSetupScreen();
4552 }
4553 #endif
4554 #endif
4555
4556 static void execSetupChooseVolumeSimple()
4557 {
4558   setup_mode = SETUP_MODE_CHOOSE_VOLUME_SIMPLE;
4559
4560   DrawSetupScreen();
4561 }
4562
4563 static void execSetupChooseVolumeLoops()
4564 {
4565   setup_mode = SETUP_MODE_CHOOSE_VOLUME_LOOPS;
4566
4567   DrawSetupScreen();
4568 }
4569
4570 static void execSetupChooseVolumeMusic()
4571 {
4572   setup_mode = SETUP_MODE_CHOOSE_VOLUME_MUSIC;
4573
4574   DrawSetupScreen();
4575 }
4576
4577 static void execSetupSound()
4578 {
4579 #if 1
4580   if (volumes_simple == NULL)
4581   {
4582     int i;
4583
4584     for (i = 0; volumes_list[i].value != -1; i++)
4585     {
4586       TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED);
4587       char identifier[32], name[32];
4588       int value = volumes_list[i].value;
4589       char *text = volumes_list[i].text;
4590
4591       ti->node_top = &volumes_simple;
4592       ti->sort_priority = value;
4593
4594       sprintf(identifier, "%d", value);
4595       sprintf(name, "%s", text);
4596
4597       setString(&ti->identifier, identifier);
4598       setString(&ti->name, name);
4599       setString(&ti->name_sorting, name);
4600       setString(&ti->infotext, "Sound Volume");
4601
4602       pushTreeInfo(&volumes_simple, ti);
4603     }
4604
4605     /* sort volume values to start with lowest volume value */
4606     sortTreeInfo(&volumes_simple);
4607
4608     /* set current volume value to configured volume value */
4609     volume_simple_current =
4610       getTreeInfoFromIdentifier(volumes_simple,i_to_a(setup.volume_simple));
4611
4612     /* if that fails, set current volume to reliable default value */
4613     if (volume_simple_current == NULL)
4614       volume_simple_current =
4615         getTreeInfoFromIdentifier(volumes_simple, i_to_a(100));
4616
4617     /* if that also fails, set current volume to first available value */
4618     if (volume_simple_current == NULL)
4619       volume_simple_current = volumes_simple;
4620   }
4621
4622   if (volumes_loops == NULL)
4623   {
4624     int i;
4625
4626     for (i = 0; volumes_list[i].value != -1; i++)
4627     {
4628       TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED);
4629       char identifier[32], name[32];
4630       int value = volumes_list[i].value;
4631       char *text = volumes_list[i].text;
4632
4633       ti->node_top = &volumes_loops;
4634       ti->sort_priority = value;
4635
4636       sprintf(identifier, "%d", value);
4637       sprintf(name, "%s", text);
4638
4639       setString(&ti->identifier, identifier);
4640       setString(&ti->name, name);
4641       setString(&ti->name_sorting, name);
4642       setString(&ti->infotext, "Loops Volume");
4643
4644       pushTreeInfo(&volumes_loops, ti);
4645     }
4646
4647     /* sort volume values to start with lowest volume value */
4648     sortTreeInfo(&volumes_loops);
4649
4650     /* set current volume value to configured volume value */
4651     volume_loops_current =
4652       getTreeInfoFromIdentifier(volumes_loops,i_to_a(setup.volume_loops));
4653
4654     /* if that fails, set current volume to reliable default value */
4655     if (volume_loops_current == NULL)
4656       volume_loops_current =
4657         getTreeInfoFromIdentifier(volumes_loops, i_to_a(100));
4658
4659     /* if that also fails, set current volume to first available value */
4660     if (volume_loops_current == NULL)
4661       volume_loops_current = volumes_loops;
4662   }
4663
4664   if (volumes_music == NULL)
4665   {
4666     int i;
4667
4668     for (i = 0; volumes_list[i].value != -1; i++)
4669     {
4670       TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED);
4671       char identifier[32], name[32];
4672       int value = volumes_list[i].value;
4673       char *text = volumes_list[i].text;
4674
4675       ti->node_top = &volumes_music;
4676       ti->sort_priority = value;
4677
4678       sprintf(identifier, "%d", value);
4679       sprintf(name, "%s", text);
4680
4681       setString(&ti->identifier, identifier);
4682       setString(&ti->name, name);
4683       setString(&ti->name_sorting, name);
4684       setString(&ti->infotext, "Music Volume");
4685
4686       pushTreeInfo(&volumes_music, ti);
4687     }
4688
4689     /* sort volume values to start with lowest volume value */
4690     sortTreeInfo(&volumes_music);
4691
4692     /* set current volume value to configured volume value */
4693     volume_music_current =
4694       getTreeInfoFromIdentifier(volumes_music,i_to_a(setup.volume_music));
4695
4696     /* if that fails, set current volume to reliable default value */
4697     if (volume_music_current == NULL)
4698       volume_music_current =
4699         getTreeInfoFromIdentifier(volumes_music, i_to_a(100));
4700
4701     /* if that also fails, set current volume to first available value */
4702     if (volume_music_current == NULL)
4703       volume_music_current = volumes_music;
4704   }
4705
4706   setup.volume_simple = atoi(volume_simple_current->identifier);
4707   setup.volume_loops  = atoi(volume_loops_current->identifier);
4708   setup.volume_music  = atoi(volume_music_current->identifier);
4709
4710   /* needed for displaying volume text instead of identifier */
4711   volume_simple_text = volume_simple_current->name;
4712   volume_loops_text = volume_loops_current->name;
4713   volume_music_text = volume_music_current->name;
4714 #endif
4715
4716   setup_mode = SETUP_MODE_SOUND;
4717
4718   DrawSetupScreen();
4719 }
4720
4721 static void execSetupArtwork()
4722 {
4723 #if 0
4724   printf("::: '%s', '%s', '%s'\n",
4725          artwork.gfx_current->subdir,
4726          artwork.gfx_current->fullpath,
4727          artwork.gfx_current->basepath);
4728 #endif
4729
4730   setup.graphics_set = artwork.gfx_current->identifier;
4731   setup.sounds_set = artwork.snd_current->identifier;
4732   setup.music_set = artwork.mus_current->identifier;
4733
4734   /* needed if last screen (setup choice) changed graphics, sounds or music */
4735   ReloadCustomArtwork(0);
4736
4737   /* needed for displaying artwork name instead of artwork identifier */
4738   graphics_set_name = artwork.gfx_current->name;
4739   sounds_set_name = artwork.snd_current->name;
4740   music_set_name = artwork.mus_current->name;
4741
4742   setup_mode = SETUP_MODE_ARTWORK;
4743
4744   DrawSetupScreen();
4745 }
4746
4747 static void execSetupChooseGraphics()
4748 {
4749   setup_mode = SETUP_MODE_CHOOSE_GRAPHICS;
4750
4751   DrawSetupScreen();
4752 }
4753
4754 static void execSetupChooseSounds()
4755 {
4756   setup_mode = SETUP_MODE_CHOOSE_SOUNDS;
4757
4758   DrawSetupScreen();
4759 }
4760
4761 static void execSetupChooseMusic()
4762 {
4763   setup_mode = SETUP_MODE_CHOOSE_MUSIC;
4764
4765   DrawSetupScreen();
4766 }
4767
4768 static void execSetupInput()
4769 {
4770   setup_mode = SETUP_MODE_INPUT;
4771
4772   DrawSetupScreen();
4773 }
4774
4775 static void execSetupShortcuts()
4776 {
4777   setup_mode = SETUP_MODE_SHORTCUTS;
4778
4779   DrawSetupScreen();
4780 }
4781
4782 static void execSetupShortcuts1()
4783 {
4784   setup_mode = SETUP_MODE_SHORTCUTS_1;
4785
4786   DrawSetupScreen();
4787 }
4788
4789 static void execSetupShortcuts2()
4790 {
4791   setup_mode = SETUP_MODE_SHORTCUTS_2;
4792
4793   DrawSetupScreen();
4794 }
4795
4796 static void execSetupShortcuts3()
4797 {
4798   setup_mode = SETUP_MODE_SHORTCUTS_3;
4799
4800   DrawSetupScreen();
4801 }
4802
4803 static void execSetupShortcuts4()
4804 {
4805   setup_mode = SETUP_MODE_SHORTCUTS_4;
4806
4807   DrawSetupScreen();
4808 }
4809
4810 static void execSetupShortcuts5()
4811 {
4812   setup_mode = SETUP_MODE_SHORTCUTS_5;
4813
4814   DrawSetupScreen();
4815 }
4816
4817 static void execExitSetup()
4818 {
4819   game_status = GAME_MODE_MAIN;
4820
4821   DrawMainMenuExt(REDRAW_FIELD, FALSE);
4822 }
4823
4824 static void execSaveAndExitSetup()
4825 {
4826   SaveSetup();
4827   execExitSetup();
4828 }
4829
4830 static struct TokenInfo setup_info_main[] =
4831 {
4832   { TYPE_ENTER_MENU,    execSetupGame,          "Game & Menu"           },
4833   { TYPE_ENTER_MENU,    execSetupEditor,        "Editor"                },
4834   { TYPE_ENTER_MENU,    execSetupGraphics,      "Graphics"              },
4835   { TYPE_ENTER_MENU,    execSetupSound,         "Sound & Music"         },
4836   { TYPE_ENTER_MENU,    execSetupArtwork,       "Custom Artwork"        },
4837   { TYPE_ENTER_MENU,    execSetupInput,         "Input Devices"         },
4838   { TYPE_ENTER_MENU,    execSetupShortcuts,     "Key Shortcuts"         },
4839   { TYPE_EMPTY,         NULL,                   ""                      },
4840   { TYPE_LEAVE_MENU,    execExitSetup,          "Exit"                  },
4841   { TYPE_LEAVE_MENU,    execSaveAndExitSetup,   "Save and Exit"         },
4842
4843   { 0,                  NULL,                   NULL                    }
4844 };
4845
4846 static struct TokenInfo setup_info_game[] =
4847 {
4848   { TYPE_SWITCH,        &setup.team_mode,       "Team-Mode (Multi-Player):" },
4849   { TYPE_YES_NO,        &setup.input_on_focus,  "Only Move Focussed Player:" },
4850   { TYPE_SWITCH,        &setup.handicap,        "Handicap:"             },
4851   { TYPE_SWITCH,        &setup.skip_levels,     "Skip Unsolved Levels:" },
4852   { TYPE_SWITCH,        &setup.time_limit,      "Time Limit:"           },
4853   { TYPE_SWITCH,        &setup.autorecord,      "Auto-Record Tapes:"    },
4854   { TYPE_ENTER_LIST,    execSetupChooseGameSpeed, "Game Speed:"         },
4855   { TYPE_STRING,        &game_speed_text,       ""                      },
4856 #if 1
4857   { TYPE_ENTER_LIST,    execSetupChooseScrollDelay, "Scroll Delay:"     },
4858   { TYPE_STRING,        &scroll_delay_text,     ""                      },
4859 #endif
4860   { TYPE_EMPTY,         NULL,                   ""                      },
4861   { TYPE_LEAVE_MENU,    execSetupMain,          "Back"                  },
4862
4863   { 0,                  NULL,                   NULL                    }
4864 };
4865
4866 static struct TokenInfo setup_info_editor[] =
4867 {
4868 #if 0
4869   { TYPE_SWITCH,        &setup.editor.el_boulderdash,   "Boulder Dash:" },
4870   { TYPE_SWITCH,        &setup.editor.el_emerald_mine,  "Emerald Mine:" },
4871   { TYPE_SWITCH, &setup.editor.el_emerald_mine_club,    "Emerald Mine Club:" },
4872   { TYPE_SWITCH,        &setup.editor.el_more,          "Rocks'n'Diamonds:" },
4873   { TYPE_SWITCH,        &setup.editor.el_sokoban,       "Sokoban:"      },
4874   { TYPE_SWITCH,        &setup.editor.el_supaplex,      "Supaplex:"     },
4875   { TYPE_SWITCH,        &setup.editor.el_diamond_caves, "Diamond Caves II:" },
4876   { TYPE_SWITCH,        &setup.editor.el_dx_boulderdash,"DX-Boulderdash:" },
4877 #endif
4878   { TYPE_SWITCH,        &setup.editor.el_chars,         "Text Characters:" },
4879   { TYPE_SWITCH, &setup.editor.el_steel_chars, "Text Characters (Steel):" },
4880   { TYPE_SWITCH,        &setup.editor.el_custom,  "Custom & Group Elements:" },
4881 #if 0
4882   { TYPE_SWITCH,        &setup.editor.el_headlines,     "Headlines:"    },
4883 #endif
4884   { TYPE_SWITCH, &setup.editor.el_user_defined, "User defined element list:" },
4885   { TYPE_SWITCH,        &setup.editor.el_dynamic,  "Dynamic level elements:" },
4886   { TYPE_EMPTY,         NULL,                   ""                      },
4887 #if 0
4888   { TYPE_SWITCH,        &setup.editor.el_by_game,   "Show elements by game:" },
4889   { TYPE_SWITCH,        &setup.editor.el_by_type,   "Show elements by type:" },
4890   { TYPE_EMPTY,         NULL,                   ""                      },
4891 #endif
4892   { TYPE_SWITCH, &setup.editor.show_element_token,      "Show element token:" },
4893   { TYPE_EMPTY,         NULL,                   ""                      },
4894   { TYPE_LEAVE_MENU,    execSetupMain,          "Back"                  },
4895
4896   { 0,                  NULL,                   NULL                    }
4897 };
4898
4899 static struct TokenInfo setup_info_graphics[] =
4900 {
4901 #if !defined(PLATFORM_ANDROID)
4902   { TYPE_SWITCH,        &setup.fullscreen,      "Fullscreen:"           },
4903 #if defined(TARGET_SDL2)
4904   { TYPE_ENTER_LIST,    execSetupChooseWindowSize, "Window Scaling:"    },
4905   { TYPE_STRING,        &window_size_text,      ""                      },
4906 #if 1
4907   { TYPE_ENTER_LIST,    execSetupChooseScalingType, "Anti-Aliasing:"    },
4908   { TYPE_STRING,        &scaling_type_text,     ""                      },
4909 #endif
4910 #else
4911   { TYPE_ENTER_LIST,    execSetupChooseScreenMode, "Fullscreen Mode:"   },
4912   { TYPE_STRING,        &screen_mode_text,      ""                      },
4913 #endif
4914 #endif
4915 #if 0
4916   { TYPE_SWITCH,        &setup.scroll_delay,    "Scroll Delay:"         },
4917 #endif
4918 #if 0
4919   { TYPE_ENTER_LIST,    execSetupChooseScrollDelay, "Scroll Delay Value:" },
4920   { TYPE_STRING,        &scroll_delay_text,     ""                      },
4921 #endif
4922 #if 0
4923   { TYPE_SWITCH,        &setup.soft_scrolling,  "Soft Scrolling:"       },
4924 #endif
4925   { TYPE_SWITCH,        &setup.fade_screens,    "Fade Screens:"         },
4926   { TYPE_SWITCH,        &setup.quick_switch,    "Quick Player Focus Switch:" },
4927   { TYPE_SWITCH,        &setup.quick_doors,     "Quick Menu Doors:"     },
4928   { TYPE_SWITCH,        &setup.show_titlescreen,"Show Title Screens:"   },
4929   { TYPE_SWITCH,        &setup.toons,           "Show Toons:"           },
4930   { TYPE_ECS_AGA,       &setup.prefer_aga_graphics,"EMC graphics preference:" },
4931   { TYPE_SWITCH, &setup.sp_show_border_elements,"Supaplex Border Elements:" },
4932   { TYPE_SWITCH,        &setup.small_game_graphics, "Small Game Graphics:" },
4933   { TYPE_EMPTY,         NULL,                   ""                      },
4934   { TYPE_LEAVE_MENU,    execSetupMain,          "Back"                  },
4935
4936   { 0,                  NULL,                   NULL                    }
4937 };
4938
4939 static struct TokenInfo setup_info_sound[] =
4940 {
4941   { TYPE_SWITCH,        &setup.sound_simple,    "Sound Effects (Normal):"  },
4942   { TYPE_SWITCH,        &setup.sound_loops,     "Sound Effects (Looping):" },
4943   { TYPE_SWITCH,        &setup.sound_music,     "Music:"                },
4944   { TYPE_EMPTY,         NULL,                   ""                      },
4945   { TYPE_ENTER_LIST,    execSetupChooseVolumeSimple, "Sound Volume (Normal):" },
4946   { TYPE_STRING,        &volume_simple_text,    ""                      },
4947   { TYPE_ENTER_LIST,    execSetupChooseVolumeLoops, "Sound Volume (Looping):" },
4948   { TYPE_STRING,        &volume_loops_text,     ""                      },
4949   { TYPE_ENTER_LIST,    execSetupChooseVolumeMusic, "Music Volume:"     },
4950   { TYPE_STRING,        &volume_music_text,     ""                      },
4951   { TYPE_EMPTY,         NULL,                   ""                      },
4952   { TYPE_LEAVE_MENU,    execSetupMain,          "Back"                  },
4953
4954   { 0,                  NULL,                   NULL                    }
4955 };
4956
4957 static struct TokenInfo setup_info_artwork[] =
4958 {
4959   { TYPE_ENTER_LIST,    execSetupChooseGraphics,"Custom Graphics:"      },
4960   { TYPE_STRING,        &graphics_set_name,     ""                      },
4961   { TYPE_ENTER_LIST,    execSetupChooseSounds,  "Custom Sounds:"        },
4962   { TYPE_STRING,        &sounds_set_name,       ""                      },
4963   { TYPE_ENTER_LIST,    execSetupChooseMusic,   "Custom Music:"         },
4964   { TYPE_STRING,        &music_set_name,        ""                      },
4965   { TYPE_EMPTY,         NULL,                   ""                      },
4966 #if 1
4967 #if 1
4968   { TYPE_YES_NO_AUTO,&setup.override_level_graphics,"Override Level Graphics:"},
4969   { TYPE_YES_NO_AUTO,&setup.override_level_sounds,  "Override Level Sounds:"  },
4970   { TYPE_YES_NO_AUTO,&setup.override_level_music,   "Override Level Music:"   },
4971 #else
4972   { TYPE_YES_NO, &setup.override_level_graphics,"Override Level Graphics:" },
4973   { TYPE_YES_NO, &setup.override_level_sounds,  "Override Level Sounds:"   },
4974   { TYPE_YES_NO, &setup.override_level_music,   "Override Level Music:"    },
4975   { TYPE_YES_NO, &setup.auto_override_artwork,  "Auto-Override Non-CE Sets:" },
4976 #endif
4977 #else
4978   { TYPE_STRING,        NULL,                   "Override Level Artwork:"},
4979   { TYPE_YES_NO,        &setup.override_level_graphics, "Graphics:"     },
4980   { TYPE_YES_NO,        &setup.override_level_sounds,   "Sounds:"       },
4981   { TYPE_YES_NO,        &setup.override_level_music,    "Music:"        },
4982 #endif
4983   { TYPE_EMPTY,         NULL,                   ""                      },
4984   { TYPE_LEAVE_MENU,    execSetupMain,          "Back"                  },
4985
4986   { 0,                  NULL,                   NULL                    }
4987 };
4988
4989 static struct TokenInfo setup_info_input[] =
4990 {
4991   { TYPE_SWITCH,        NULL,                   "Player:"               },
4992   { TYPE_SWITCH,        NULL,                   "Device:"               },
4993   { TYPE_ENTER_MENU,    NULL,                   ""                      },
4994   { TYPE_EMPTY,         NULL,                   ""                      },
4995   { TYPE_EMPTY,         NULL,                   ""                      },
4996   { TYPE_EMPTY,         NULL,                   ""                      },
4997   { TYPE_EMPTY,         NULL,                   ""                      },
4998   { TYPE_EMPTY,         NULL,                   ""                      },
4999   { TYPE_EMPTY,         NULL,                   ""                      },
5000   { TYPE_EMPTY,         NULL,                   ""                      },
5001   { TYPE_EMPTY,         NULL,                   ""                      },
5002   { TYPE_EMPTY,         NULL,                   ""                      },
5003   { TYPE_EMPTY,         NULL,                   ""                      },
5004   { TYPE_LEAVE_MENU,    execSetupMain,          "Back"                  },
5005
5006   { 0,                  NULL,                   NULL                    }
5007 };
5008
5009 static struct TokenInfo setup_info_shortcuts[] =
5010 {
5011   { TYPE_ENTER_MENU,    execSetupShortcuts1,    "Various Keys"          },
5012   { TYPE_ENTER_MENU,    execSetupShortcuts2,    "Player Focus"          },
5013   { TYPE_ENTER_MENU,    execSetupShortcuts3,    "Tape Buttons"          },
5014   { TYPE_ENTER_MENU,    execSetupShortcuts4,    "Sound & Music"         },
5015   { TYPE_ENTER_MENU,    execSetupShortcuts5,    "TAS Snap Keys"         },
5016   { TYPE_EMPTY,         NULL,                   ""                      },
5017   { TYPE_LEAVE_MENU,    execSetupMain,          "Back"                  },
5018
5019   { 0,                  NULL,                   NULL                    }
5020 };
5021
5022 static struct TokenInfo setup_info_shortcuts_1[] =
5023 {
5024   { TYPE_KEYTEXT,       NULL,           "Quick Save Game to Tape:",     },
5025   { TYPE_KEY,           &setup.shortcut.save_game, ""                   },
5026   { TYPE_KEYTEXT,       NULL,           "Quick Load Game from Tape:",   },
5027   { TYPE_KEY,           &setup.shortcut.load_game, ""                   },
5028   { TYPE_KEYTEXT,       NULL,           "Start Game & Toggle Pause:",   },
5029   { TYPE_KEY,           &setup.shortcut.toggle_pause, ""                },
5030   { TYPE_EMPTY,         NULL,                   ""                      },
5031   { TYPE_YES_NO,        &setup.ask_on_escape,   "Ask on 'Esc' Key:"     },
5032   { TYPE_YES_NO, &setup.ask_on_escape_editor,   "Ask on 'Esc' Key (Editor):" },
5033   { TYPE_EMPTY,         NULL,                   ""                      },
5034   { TYPE_LEAVE_MENU,    execSetupShortcuts,     "Back"                  },
5035
5036   { 0,                  NULL,                   NULL                    }
5037 };
5038
5039 static struct TokenInfo setup_info_shortcuts_2[] =
5040 {
5041   { TYPE_KEYTEXT,       NULL,           "Set Focus to Player 1:",       },
5042   { TYPE_KEY,           &setup.shortcut.focus_player[0], ""             },
5043   { TYPE_KEYTEXT,       NULL,           "Set Focus to Player 2:",       },
5044   { TYPE_KEY,           &setup.shortcut.focus_player[1], ""             },
5045   { TYPE_KEYTEXT,       NULL,           "Set Focus to Player 3:",       },
5046   { TYPE_KEY,           &setup.shortcut.focus_player[2], ""             },
5047   { TYPE_KEYTEXT,       NULL,           "Set Focus to Player 4:",       },
5048   { TYPE_KEY,           &setup.shortcut.focus_player[3], ""             },
5049   { TYPE_KEYTEXT,       NULL,           "Set Focus to All Players:",    },
5050   { TYPE_KEY,           &setup.shortcut.focus_player_all, ""            },
5051   { TYPE_EMPTY,         NULL,                   ""                      },
5052   { TYPE_LEAVE_MENU,    execSetupShortcuts,     "Back"                  },
5053
5054   { 0,                  NULL,                   NULL                    }
5055 };
5056
5057 static struct TokenInfo setup_info_shortcuts_3[] =
5058 {
5059   { TYPE_KEYTEXT,       NULL,                   "Eject Tape:",          },
5060   { TYPE_KEY,           &setup.shortcut.tape_eject, ""                  },
5061   { TYPE_KEYTEXT,       NULL,                   "Warp / Single Step:",  },
5062   { TYPE_KEY,           &setup.shortcut.tape_extra, ""                  },
5063   { TYPE_KEYTEXT,       NULL,                   "Stop Tape:",           },
5064   { TYPE_KEY,           &setup.shortcut.tape_stop, ""                   },
5065   { TYPE_KEYTEXT,       NULL,                   "Pause / Unpause Tape:",},
5066   { TYPE_KEY,           &setup.shortcut.tape_pause, ""                  },
5067   { TYPE_KEYTEXT,       NULL,                   "Record Tape:",         },
5068   { TYPE_KEY,           &setup.shortcut.tape_record, ""                 },
5069   { TYPE_KEYTEXT,       NULL,                   "Play Tape:",           },
5070   { TYPE_KEY,           &setup.shortcut.tape_play, ""                   },
5071   { TYPE_EMPTY,         NULL,                   ""                      },
5072   { TYPE_LEAVE_MENU,    execSetupShortcuts,     "Back"                  },
5073
5074   { 0,                  NULL,                   NULL                    }
5075 };
5076
5077 static struct TokenInfo setup_info_shortcuts_4[] =
5078 {
5079   { TYPE_KEYTEXT,       NULL,           "Toggle Sound Effects (Normal):", },
5080   { TYPE_KEY,           &setup.shortcut.sound_simple, ""                },
5081   { TYPE_KEYTEXT,       NULL,           "Toggle Sound Effects (Looping):", },
5082   { TYPE_KEY,           &setup.shortcut.sound_loops, ""                 },
5083   { TYPE_KEYTEXT,       NULL,           "Toggle Music:",                },
5084   { TYPE_KEY,           &setup.shortcut.sound_music, ""                 },
5085   { TYPE_EMPTY,         NULL,                   ""                      },
5086   { TYPE_LEAVE_MENU,    execSetupShortcuts,     "Back"                  },
5087
5088   { 0,                  NULL,                   NULL                    }
5089 };
5090
5091 static struct TokenInfo setup_info_shortcuts_5[] =
5092 {
5093   { TYPE_KEYTEXT,       NULL,                   "Snap Left:",           },
5094   { TYPE_KEY,           &setup.shortcut.snap_left, ""                   },
5095   { TYPE_KEYTEXT,       NULL,                   "Snap Right:",          },
5096   { TYPE_KEY,           &setup.shortcut.snap_right, ""                  },
5097   { TYPE_KEYTEXT,       NULL,                   "Snap Up:",             },
5098   { TYPE_KEY,           &setup.shortcut.snap_up, ""                     },
5099   { TYPE_KEYTEXT,       NULL,                   "Snap Down:",           },
5100   { TYPE_KEY,           &setup.shortcut.snap_down, ""                   },
5101   { TYPE_EMPTY,         NULL,                   ""                      },
5102   { TYPE_LEAVE_MENU,    execSetupShortcuts,     "Back"                  },
5103
5104   { 0,                  NULL,                   NULL                    }
5105 };
5106
5107 static Key getSetupKey()
5108 {
5109   Key key = KSYM_UNDEFINED;
5110   boolean got_key_event = FALSE;
5111
5112   while (!got_key_event)
5113   {
5114     if (PendingEvent())         /* got event */
5115     {
5116       Event event;
5117
5118       NextEvent(&event);
5119
5120       switch (event.type)
5121       {
5122         case EVENT_KEYPRESS:
5123           {
5124             key = GetEventKey((KeyEvent *)&event, TRUE);
5125
5126             /* press 'Escape' or 'Enter' to keep the existing key binding */
5127             if (key == KSYM_Escape || key == KSYM_Return)
5128               key = KSYM_UNDEFINED;     /* keep old value */
5129
5130             got_key_event = TRUE;
5131           }
5132           break;
5133
5134         case EVENT_KEYRELEASE:
5135           key_joystick_mapping = 0;
5136           break;
5137
5138         default:
5139           HandleOtherEvents(&event);
5140           break;
5141       }
5142     }
5143
5144     DoAnimation();
5145     BackToFront();
5146
5147     /* don't eat all CPU time */
5148     Delay(10);
5149   }
5150
5151   return key;
5152 }
5153
5154 static int getSetupTextFont(int type)
5155 {
5156   if (type & (TYPE_SWITCH       |
5157               TYPE_YES_NO       |
5158               TYPE_YES_NO_AUTO  |
5159               TYPE_STRING       |
5160               TYPE_ECS_AGA      |
5161               TYPE_KEYTEXT      |
5162               TYPE_ENTER_LIST))
5163     return FONT_MENU_2;
5164   else
5165     return FONT_MENU_1;
5166 }
5167
5168 static int getSetupValueFont(int type, void *value)
5169 {
5170   if (type & TYPE_KEY)
5171     return (type & TYPE_QUERY ? FONT_INPUT_1_ACTIVE : FONT_VALUE_1);
5172   else if (type & TYPE_STRING)
5173     return FONT_VALUE_2;
5174   else if (type & TYPE_ECS_AGA)
5175     return FONT_VALUE_1;
5176   else if (type & TYPE_BOOLEAN_STYLE)
5177     return (*(boolean *)value ? FONT_OPTION_ON : FONT_OPTION_OFF);
5178   else if (type & TYPE_YES_NO_AUTO)
5179     return (*(int *)value == AUTO  ? FONT_OPTION_ON :
5180             *(int *)value == FALSE ? FONT_OPTION_OFF : FONT_OPTION_ON);
5181   else
5182     return FONT_VALUE_1;
5183 }
5184
5185 static void drawSetupValue(int pos)
5186 {
5187   boolean font_draw_xoffset_modified = FALSE;
5188   int font_draw_xoffset_old = -1;
5189   int xpos = MENU_SCREEN_VALUE_XPOS;
5190   int ypos = MENU_SCREEN_START_YPOS + pos;
5191   int startx = mSX + xpos * 32;
5192   int starty = mSY + ypos * 32;
5193   int font_nr, font_width;
5194 #if 0
5195   int font_height;
5196 #endif
5197   int type = setup_info[pos].type;
5198   void *value = setup_info[pos].value;
5199   char *value_string = getSetupValue(type, value);
5200 #if 1
5201   int i;
5202 #endif
5203
5204   if (value_string == NULL)
5205     return;
5206
5207   if (type & TYPE_KEY)
5208   {
5209     xpos = MENU_SCREEN_START_XPOS;
5210
5211     if (type & TYPE_QUERY)
5212       value_string = "<press key>";
5213   }
5214   else if (type & TYPE_STRING)
5215   {
5216     int max_value_len = (SCR_FIELDX - 2) * 2;
5217
5218     xpos = MENU_SCREEN_START_XPOS;
5219
5220     if (strlen(value_string) > max_value_len)
5221       value_string[max_value_len] = '\0';
5222   }
5223   else if (type & TYPE_YES_NO_AUTO)
5224   {
5225     xpos = MENU_SCREEN_VALUE_XPOS - 1;
5226   }
5227
5228   startx = mSX + xpos * 32;
5229   starty = mSY + ypos * 32;
5230   font_nr = getSetupValueFont(type, value);
5231   font_width = getFontWidth(font_nr);
5232 #if 0
5233   font_height = getFontHeight(font_nr);
5234 #endif
5235
5236   /* downward compatibility correction for Juergen Bonhagen's menu settings */
5237   if (setup_mode != SETUP_MODE_INPUT)
5238   {
5239     int check_font_nr = FONT_OPTION_ON; /* known font that needs correction */
5240     int font1_xoffset = getFontBitmapInfo(font_nr)->draw_xoffset;
5241     int font2_xoffset = getFontBitmapInfo(check_font_nr)->draw_xoffset;
5242     int text_startx = mSX + MENU_SCREEN_START_XPOS * 32;
5243     int text_font_nr = getSetupTextFont(FONT_MENU_2);
5244     int text_font_xoffset = getFontBitmapInfo(text_font_nr)->draw_xoffset;
5245     int text_width = MAX_MENU_TEXT_LENGTH_MEDIUM * getFontWidth(text_font_nr);
5246     boolean correct_font_draw_xoffset = FALSE;
5247
5248     if (xpos == MENU_SCREEN_START_XPOS &&
5249         startx + font1_xoffset < text_startx + text_font_xoffset)
5250       correct_font_draw_xoffset = TRUE;
5251
5252     if (xpos == MENU_SCREEN_VALUE_XPOS &&
5253         startx + font2_xoffset < text_startx + text_width + text_font_xoffset)
5254       correct_font_draw_xoffset = TRUE;
5255
5256     /* check if setup value would overlap with setup text when printed */
5257     /* (this can happen for extreme/wrong values for font draw offset) */
5258     if (correct_font_draw_xoffset)
5259     {
5260       font_draw_xoffset_old = getFontBitmapInfo(font_nr)->draw_xoffset;
5261       font_draw_xoffset_modified = TRUE;
5262
5263       if (type & TYPE_KEY)
5264         getFontBitmapInfo(font_nr)->draw_xoffset += 2 * getFontWidth(font_nr);
5265       else if (!(type & TYPE_STRING))
5266         getFontBitmapInfo(font_nr)->draw_xoffset = text_font_xoffset + 20 -
5267           MAX_MENU_TEXT_LENGTH_MEDIUM * (16 - getFontWidth(text_font_nr));
5268     }
5269   }
5270
5271 #if 0
5272   DrawBackground(startx, starty, SX + SXSIZE - startx, font_height);
5273 #else
5274   for (i = 0; i <= MENU_SCREEN_MAX_XPOS - xpos; i++)
5275     DrawText(startx + i * font_width, starty, " ", font_nr);
5276 #endif
5277
5278   DrawText(startx, starty, value_string, font_nr);
5279
5280   if (font_draw_xoffset_modified)
5281     getFontBitmapInfo(font_nr)->draw_xoffset = font_draw_xoffset_old;
5282 }
5283
5284 static void changeSetupValue(int pos, int dx)
5285 {
5286   if (setup_info[pos].type & TYPE_BOOLEAN_STYLE)
5287   {
5288     *(boolean *)setup_info[pos].value ^= TRUE;
5289   }
5290   else if (setup_info[pos].type & TYPE_YES_NO_AUTO)
5291   {
5292     *(int *)setup_info[pos].value =
5293       (dx == -1 ?
5294        (*(int *)setup_info[pos].value == AUTO ? TRUE :
5295         *(int *)setup_info[pos].value == TRUE ? FALSE : AUTO) :
5296        (*(int *)setup_info[pos].value == TRUE ? AUTO :
5297         *(int *)setup_info[pos].value == AUTO ? FALSE : TRUE));
5298   }
5299   else if (setup_info[pos].type & TYPE_KEY)
5300   {
5301     Key key;
5302
5303     setup_info[pos].type |= TYPE_QUERY;
5304     drawSetupValue(pos);
5305     setup_info[pos].type &= ~TYPE_QUERY;
5306
5307     key = getSetupKey();
5308     if (key != KSYM_UNDEFINED)
5309       *(Key *)setup_info[pos].value = key;
5310   }
5311
5312   drawSetupValue(pos);
5313
5314   // fullscreen state may have changed at this point
5315   if (setup_info[pos].value == &setup.fullscreen)
5316     ToggleFullscreenOrChangeWindowScalingIfNeeded();
5317 }
5318
5319 static void DrawCursorAndText_Setup(int pos, boolean active)
5320 {
5321   int xpos = MENU_SCREEN_START_XPOS;
5322   int ypos = MENU_SCREEN_START_YPOS + pos;
5323   int font_nr = getSetupTextFont(setup_info[pos].type);
5324
5325   if (setup_info == setup_info_input)
5326     font_nr = FONT_MENU_1;
5327
5328   if (active)
5329     font_nr = FONT_ACTIVE(font_nr);
5330
5331   DrawText(mSX + xpos * 32, mSY + ypos * 32, setup_info[pos].text, font_nr);
5332
5333   if (setup_info[pos].type & ~TYPE_SKIP_ENTRY)
5334     drawCursor(pos, active);
5335 }
5336
5337 static void DrawSetupScreen_Generic()
5338 {
5339   boolean redraw_all = FALSE;
5340   char *title_string = NULL;
5341   int i;
5342
5343   UnmapAllGadgets();
5344   CloseDoor(DOOR_CLOSE_2);
5345
5346   if (redraw_mask & REDRAW_ALL)
5347     redraw_all = TRUE;
5348
5349 #if 0
5350   printf("::: %s\n", (redraw_mask & REDRAW_FIELD ? "REDRAW_FIELD" :
5351                       redraw_mask & REDRAW_ALL ? "REDRAW_ALL" :
5352                       int2str(0, redraw_mask)));
5353 #endif
5354
5355 #if 0
5356   /* !!! usually REDRAW_NONE => DOES NOT WORK (with fade) => CHECK THIS !!! */
5357   FadeOut(redraw_mask);
5358 #else
5359   FadeOut(REDRAW_FIELD);
5360 #endif
5361
5362   ClearField();
5363
5364   if (setup_mode == SETUP_MODE_MAIN)
5365   {
5366     setup_info = setup_info_main;
5367     title_string = "Setup";
5368   }
5369   else if (setup_mode == SETUP_MODE_GAME)
5370   {
5371     setup_info = setup_info_game;
5372     title_string = "Setup Game";
5373   }
5374   else if (setup_mode == SETUP_MODE_EDITOR)
5375   {
5376     setup_info = setup_info_editor;
5377     title_string = "Setup Editor";
5378   }
5379   else if (setup_mode == SETUP_MODE_GRAPHICS)
5380   {
5381     setup_info = setup_info_graphics;
5382     title_string = "Setup Graphics";
5383   }
5384   else if (setup_mode == SETUP_MODE_SOUND)
5385   {
5386     setup_info = setup_info_sound;
5387     title_string = "Setup Sound";
5388   }
5389   else if (setup_mode == SETUP_MODE_ARTWORK)
5390   {
5391     setup_info = setup_info_artwork;
5392     title_string = "Custom Artwork";
5393   }
5394   else if (setup_mode == SETUP_MODE_SHORTCUTS)
5395   {
5396     setup_info = setup_info_shortcuts;
5397     title_string = "Setup Shortcuts";
5398   }
5399   else if (setup_mode == SETUP_MODE_SHORTCUTS_1)
5400   {
5401     setup_info = setup_info_shortcuts_1;
5402     title_string = "Setup Shortcuts";
5403   }
5404   else if (setup_mode == SETUP_MODE_SHORTCUTS_2)
5405   {
5406     setup_info = setup_info_shortcuts_2;
5407     title_string = "Setup Shortcuts";
5408   }
5409   else if (setup_mode == SETUP_MODE_SHORTCUTS_3)
5410   {
5411     setup_info = setup_info_shortcuts_3;
5412     title_string = "Setup Shortcuts";
5413   }
5414   else if (setup_mode == SETUP_MODE_SHORTCUTS_4)
5415   {
5416     setup_info = setup_info_shortcuts_4;
5417     title_string = "Setup Shortcuts";
5418   }
5419   else if (setup_mode == SETUP_MODE_SHORTCUTS_5)
5420   {
5421     setup_info = setup_info_shortcuts_5;
5422     title_string = "Setup Shortcuts";
5423   }
5424
5425   DrawTextSCentered(mSY - SY + 16, FONT_TITLE_1, title_string);
5426
5427   num_setup_info = 0;
5428 #if 1
5429   for (i = 0; setup_info[i].type != 0 && i < MAX_MENU_ENTRIES_ON_SCREEN; i++)
5430 #else
5431   for (i = 0; setup_info[i].type != 0 && i < NUM_MENU_ENTRIES_ON_SCREEN; i++)
5432 #endif
5433   {
5434     void *value_ptr = setup_info[i].value;
5435
5436     /* set some entries to "unchangeable" according to other variables */
5437     if ((value_ptr == &setup.sound_simple && !audio.sound_available) ||
5438         (value_ptr == &setup.sound_loops  && !audio.loops_available) ||
5439         (value_ptr == &setup.sound_music  && !audio.music_available) ||
5440         (value_ptr == &setup.fullscreen   && !video.fullscreen_available) ||
5441         (value_ptr == &screen_mode_text   && !video.fullscreen_available) ||
5442         (value_ptr == &window_size_text   && !video.window_scaling_available) ||
5443         (value_ptr == &scaling_type_text  && !video.window_scaling_available))
5444       setup_info[i].type |= TYPE_GHOSTED;
5445
5446     if (setup_info[i].type & (TYPE_ENTER_MENU|TYPE_ENTER_LIST))
5447       initCursor(i, IMG_MENU_BUTTON_ENTER_MENU);
5448     else if (setup_info[i].type & (TYPE_LEAVE_MENU|TYPE_LEAVE_LIST))
5449       initCursor(i, IMG_MENU_BUTTON_LEAVE_MENU);
5450     else if (setup_info[i].type & ~TYPE_SKIP_ENTRY)
5451       initCursor(i, IMG_MENU_BUTTON);
5452
5453     DrawCursorAndText_Setup(i, FALSE);
5454
5455     if (setup_info[i].type & TYPE_VALUE)
5456       drawSetupValue(i);
5457
5458     num_setup_info++;
5459   }
5460
5461 #if 0
5462   DrawTextSCentered(SYSIZE - 20, FONT_TEXT_4,
5463                     "Joysticks deactivated in setup menu");
5464 #endif
5465
5466 #if 1
5467   HandleSetupScreen_Generic(0, 0, 0, 0, MB_MENU_INITIALIZE);
5468 #endif
5469
5470   if (redraw_all)
5471     redraw_mask = REDRAW_ALL;
5472
5473 #if 1
5474   FadeIn(redraw_mask);
5475 #else
5476   FadeIn(REDRAW_FIELD);
5477 #endif
5478
5479   InitAnimation();
5480 #if 0
5481   HandleSetupScreen_Generic(0, 0, 0, 0, MB_MENU_INITIALIZE);
5482 #endif
5483 }
5484
5485 void HandleSetupScreen_Generic(int mx, int my, int dx, int dy, int button)
5486 {
5487   static int choice_store[MAX_SETUP_MODES];
5488   int choice = choice_store[setup_mode];        /* always starts with 0 */
5489   int x = 0;
5490   int y = choice;
5491
5492   if (button == MB_MENU_INITIALIZE)
5493   {
5494     /* advance to first valid menu entry */
5495     while (choice < num_setup_info &&
5496            setup_info[choice].type & TYPE_SKIP_ENTRY)
5497       choice++;
5498     choice_store[setup_mode] = choice;
5499
5500     DrawCursorAndText_Setup(choice, TRUE);
5501
5502     return;
5503   }
5504   else if (button == MB_MENU_LEAVE)
5505   {
5506     PlaySound(SND_MENU_ITEM_SELECTING);
5507
5508     // for (y = 0; y < num_setup_info; y++)
5509     for (y = 0; setup_info[y].type != 0; y++)
5510     {
5511       if (setup_info[y].type & TYPE_LEAVE_MENU)
5512       {
5513         void (*menu_callback_function)(void) = setup_info[y].value;
5514
5515         FadeSetLeaveMenu();
5516
5517         menu_callback_function();
5518
5519         break;  /* absolutely needed because function changes 'setup_info'! */
5520       }
5521     }
5522
5523     return;
5524   }
5525
5526   if (mx || my)         /* mouse input */
5527   {
5528     x = (mx - mSX) / 32;
5529     y = (my - mSY) / 32 - MENU_SCREEN_START_YPOS;
5530   }
5531   else if (dx || dy)    /* keyboard input */
5532   {
5533     if (dx)
5534     {
5535       int menu_navigation_type = (dx < 0 ? TYPE_LEAVE : TYPE_ENTER);
5536
5537       if (setup_info[choice].type & menu_navigation_type ||
5538           setup_info[choice].type & TYPE_BOOLEAN_STYLE ||
5539           setup_info[choice].type & TYPE_YES_NO_AUTO)
5540         button = MB_MENU_CHOICE;
5541     }
5542     else if (dy)
5543       y = choice + dy;
5544
5545     /* jump to next non-empty menu entry (up or down) */
5546     while (y > 0 && y < num_setup_info - 1 &&
5547            setup_info[y].type & TYPE_SKIP_ENTRY)
5548       y += dy;
5549   }
5550
5551   if (IN_VIS_FIELD(x, y) && y >= 0 && y < num_setup_info)
5552   {
5553     if (button)
5554     {
5555       if (y != choice && setup_info[y].type & ~TYPE_SKIP_ENTRY)
5556       {
5557         PlaySound(SND_MENU_ITEM_ACTIVATING);
5558
5559         DrawCursorAndText_Setup(choice, FALSE);
5560         DrawCursorAndText_Setup(y, TRUE);
5561
5562         choice = choice_store[setup_mode] = y;
5563       }
5564     }
5565     else if (!(setup_info[y].type & TYPE_GHOSTED))
5566     {
5567       PlaySound(SND_MENU_ITEM_SELECTING);
5568
5569       /* when selecting key headline, execute function for key value change */
5570       if (setup_info[y].type & TYPE_KEYTEXT &&
5571           setup_info[y + 1].type & TYPE_KEY)
5572         y++;
5573
5574       /* when selecting string value, execute function for list selection */
5575       if (setup_info[y].type & TYPE_STRING && y > 0 &&
5576           setup_info[y - 1].type & TYPE_ENTER_LIST)
5577         y--;
5578
5579       if (setup_info[y].type & TYPE_ENTER_OR_LEAVE)
5580       {
5581         void (*menu_callback_function)(void) = setup_info[y].value;
5582
5583         FadeSetFromType(setup_info[y].type);
5584
5585         menu_callback_function();
5586       }
5587       else
5588       {
5589         if (setup_info[y].type & TYPE_VALUE)
5590           changeSetupValue(y, dx);
5591       }
5592     }
5593   }
5594 }
5595
5596 void DrawSetupScreen_Input()
5597 {
5598   int i;
5599
5600 #if 1
5601   FadeOut(REDRAW_FIELD);
5602 #endif
5603
5604   ClearField();
5605
5606 #if 1
5607   setup_info = setup_info_input;
5608 #endif
5609
5610   DrawTextSCentered(mSY - SY + 16, FONT_TITLE_1, "Setup Input");
5611
5612 #if 1
5613 #if 1
5614   DrawTextSCentered(SYSIZE - 20, FONT_TITLE_2,
5615                     "Joysticks deactivated on this screen");
5616 #else
5617   DrawTextSCentered(SYSIZE - 20, FONT_TEXT_4,
5618                     "Joysticks deactivated on this screen");
5619 #endif
5620 #endif
5621
5622 #if 1
5623   for (i = 0; setup_info[i].type != 0 && i < MAX_MENU_ENTRIES_ON_SCREEN; i++)
5624 #else
5625   for (i = 0; setup_info[i].type != 0 && i < NUM_MENU_ENTRIES_ON_SCREEN; i++)
5626 #endif
5627   {
5628     if (setup_info[i].type & (TYPE_ENTER_MENU|TYPE_ENTER_LIST))
5629       initCursor(i, IMG_MENU_BUTTON_ENTER_MENU);
5630     else if (setup_info[i].type & (TYPE_LEAVE_MENU|TYPE_LEAVE_LIST))
5631       initCursor(i, IMG_MENU_BUTTON_LEAVE_MENU);
5632     else if (setup_info[i].type & ~TYPE_SKIP_ENTRY)
5633       initCursor(i, IMG_MENU_BUTTON);
5634
5635     DrawCursorAndText_Setup(i, FALSE);
5636   }
5637
5638 #if 0
5639   DeactivateJoystickForCalibration();
5640 #endif
5641
5642 #if 0
5643 #if 1
5644   DrawTextSCentered(SYSIZE - 20, FONT_TITLE_2,
5645                     "Joysticks deactivated on this screen");
5646 #else
5647   DrawTextSCentered(SYSIZE - 20, FONT_TEXT_4,
5648                     "Joysticks deactivated on this screen");
5649 #endif
5650 #endif
5651
5652   /* create gadgets for setup input menu screen */
5653   FreeScreenGadgets();
5654   CreateScreenGadgets();
5655
5656   /* map gadgets for setup input menu screen */
5657   MapScreenMenuGadgets(SCREEN_MASK_INPUT);
5658
5659   HandleSetupScreen_Input(0, 0, 0, 0, MB_MENU_INITIALIZE);
5660
5661 #if 1
5662   FadeIn(REDRAW_FIELD);
5663 #endif
5664
5665   InitAnimation();
5666 }
5667
5668 static void setJoystickDeviceToNr(char *device_name, int device_nr)
5669 {
5670   if (device_name == NULL)
5671     return;
5672
5673   if (device_nr < 0 || device_nr >= MAX_PLAYERS)
5674     device_nr = 0;
5675
5676   if (strlen(device_name) > 1)
5677   {
5678     char c1 = device_name[strlen(device_name) - 1];
5679     char c2 = device_name[strlen(device_name) - 2];
5680
5681     if (c1 >= '0' && c1 <= '9' && !(c2 >= '0' && c2 <= '9'))
5682       device_name[strlen(device_name) - 1] = '0' + (char)(device_nr % 10);
5683   }
5684   else
5685     strncpy(device_name, getDeviceNameFromJoystickNr(device_nr),
5686             strlen(device_name));
5687 }
5688
5689 static void drawPlayerSetupInputInfo(int player_nr, boolean active)
5690 {
5691   int i;
5692   static struct SetupKeyboardInfo custom_key;
5693   static struct
5694   {
5695     Key *key;
5696     char *text;
5697   } custom[] =
5698   {
5699     { &custom_key.left,  "Joystick Left"  },
5700     { &custom_key.right, "Joystick Right" },
5701     { &custom_key.up,    "Joystick Up"    },
5702     { &custom_key.down,  "Joystick Down"  },
5703     { &custom_key.snap,  "Button 1"       },
5704     { &custom_key.drop,  "Button 2"       }
5705   };
5706   static char *joystick_name[MAX_PLAYERS] =
5707   {
5708     "Joystick1",
5709     "Joystick2",
5710     "Joystick3",
5711     "Joystick4"
5712   };
5713   int text_font_nr = (active ? FONT_MENU_1_ACTIVE : FONT_MENU_1);
5714
5715   InitJoysticks();
5716
5717   custom_key = setup.input[player_nr].key;
5718
5719   DrawText(mSX + 11 * 32, mSY + 2 * 32, int2str(player_nr + 1, 1),
5720            FONT_INPUT_1_ACTIVE);
5721
5722   ClearRectangleOnBackground(drawto, mSX + 8 * TILEX, mSY + 2 * TILEY,
5723                              TILEX, TILEY);
5724   DrawFixedGraphicThruMaskExt(drawto, mSX + 8 * TILEX, mSY + 2 * TILEY,
5725                               PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0);
5726
5727   if (setup.input[player_nr].use_joystick)
5728   {
5729     char *device_name = setup.input[player_nr].joy.device_name;
5730     char *text = joystick_name[getJoystickNrFromDeviceName(device_name)];
5731     int font_nr = (joystick.fd[player_nr] < 0 ? FONT_VALUE_OLD : FONT_VALUE_1);
5732
5733     DrawText(mSX + 8 * 32, mSY + 3 * 32, text, font_nr);
5734     DrawText(mSX + 32, mSY + 4 * 32, "Calibrate", text_font_nr);
5735   }
5736   else
5737   {
5738     DrawText(mSX + 8 * 32, mSY + 3 * 32, "Keyboard ", FONT_VALUE_1);
5739     DrawText(mSX + 1 * 32, mSY + 4 * 32, "Customize", text_font_nr);
5740   }
5741
5742   DrawText(mSX + 32, mSY + 5 * 32, "Actual Settings:", FONT_MENU_1);
5743
5744   drawCursorXY(1, 4, IMG_MENU_BUTTON_LEFT);
5745   drawCursorXY(1, 5, IMG_MENU_BUTTON_RIGHT);
5746   drawCursorXY(1, 6, IMG_MENU_BUTTON_UP);
5747   drawCursorXY(1, 7, IMG_MENU_BUTTON_DOWN);
5748
5749   DrawText(mSX + 2 * 32, mSY +  6 * 32, ":", FONT_VALUE_OLD);
5750   DrawText(mSX + 2 * 32, mSY +  7 * 32, ":", FONT_VALUE_OLD);
5751   DrawText(mSX + 2 * 32, mSY +  8 * 32, ":", FONT_VALUE_OLD);
5752   DrawText(mSX + 2 * 32, mSY +  9 * 32, ":", FONT_VALUE_OLD);
5753   DrawText(mSX + 1 * 32, mSY + 10 * 32, "Snap Field:", FONT_VALUE_OLD);
5754   DrawText(mSX + 1 * 32, mSY + 12 * 32, "Drop Element:", FONT_VALUE_OLD);
5755
5756   for (i = 0; i < 6; i++)
5757   {
5758     int ypos = 6 + i + (i > 3 ? i-3 : 0);
5759
5760     DrawText(mSX + 3 * 32, mSY + ypos * 32,
5761              "              ", FONT_VALUE_1);
5762     DrawText(mSX + 3 * 32, mSY + ypos * 32,
5763              (setup.input[player_nr].use_joystick ?
5764               custom[i].text :
5765               getKeyNameFromKey(*custom[i].key)), FONT_VALUE_1);
5766   }
5767 }
5768
5769 static int input_player_nr = 0;
5770
5771 void HandleSetupScreen_Input_Player(int step, int direction)
5772 {
5773   int old_player_nr = input_player_nr;
5774   int new_player_nr;
5775
5776   new_player_nr = old_player_nr + step * direction;
5777   if (new_player_nr < 0)
5778     new_player_nr = 0;
5779   if (new_player_nr > MAX_PLAYERS - 1)
5780     new_player_nr = MAX_PLAYERS - 1;
5781
5782   if (new_player_nr != old_player_nr)
5783   {
5784     input_player_nr = new_player_nr;
5785
5786     drawPlayerSetupInputInfo(input_player_nr, FALSE);
5787   }
5788 }
5789
5790 void HandleSetupScreen_Input(int mx, int my, int dx, int dy, int button)
5791 {
5792   static int choice = 0;
5793   int x = 0;
5794   int y = choice;
5795   int pos_start  = SETUPINPUT_SCREEN_POS_START;
5796   int pos_empty1 = SETUPINPUT_SCREEN_POS_EMPTY1;
5797   int pos_empty2 = SETUPINPUT_SCREEN_POS_EMPTY2;
5798   int pos_end    = SETUPINPUT_SCREEN_POS_END;
5799
5800   if (button == MB_MENU_INITIALIZE)
5801   {
5802     drawPlayerSetupInputInfo(input_player_nr, (choice == 2));
5803
5804     DrawCursorAndText_Setup(choice, TRUE);
5805
5806     return;
5807   }
5808   else if (button == MB_MENU_LEAVE)
5809   {
5810     setup_mode = SETUP_MODE_MAIN;
5811     DrawSetupScreen();
5812     InitJoysticks();
5813
5814     return;
5815   }
5816
5817   if (mx || my)         /* mouse input */
5818   {
5819     x = (mx - mSX) / 32;
5820     y = (my - mSY) / 32 - MENU_SCREEN_START_YPOS;
5821   }
5822   else if (dx || dy)    /* keyboard input */
5823   {
5824     if (dx && choice == 0)
5825       x = (dx < 0 ? 10 : 12);
5826     else if ((dx && choice == 1) ||
5827              (dx == +1 && choice == 2) ||
5828              (dx == -1 && choice == pos_end))
5829       button = MB_MENU_CHOICE;
5830     else if (dy)
5831       y = choice + dy;
5832
5833     if (y >= pos_empty1 && y <= pos_empty2)
5834       y = (dy > 0 ? pos_empty2 + 1 : pos_empty1 - 1);
5835   }
5836
5837   if (y == 0 && dx != 0 && button)
5838   {
5839     HandleSetupScreen_Input_Player(1, dx < 0 ? -1 : +1);
5840   }
5841   else if (IN_VIS_FIELD(x, y) &&
5842            y >= pos_start && y <= pos_end &&
5843            !(y >= pos_empty1 && y <= pos_empty2))
5844   {
5845     if (button)
5846     {
5847       if (y != choice)
5848       {
5849         DrawCursorAndText_Setup(choice, FALSE);
5850         DrawCursorAndText_Setup(y, TRUE);
5851
5852         drawPlayerSetupInputInfo(input_player_nr, (y == 2));
5853
5854         choice = y;
5855       }
5856     }
5857     else
5858     {
5859       if (y == 1)
5860       {
5861         char *device_name = setup.input[input_player_nr].joy.device_name;
5862
5863         if (!setup.input[input_player_nr].use_joystick)
5864         {
5865           int new_device_nr = (dx >= 0 ? 0 : MAX_PLAYERS - 1);
5866
5867           setJoystickDeviceToNr(device_name, new_device_nr);
5868           setup.input[input_player_nr].use_joystick = TRUE;
5869         }
5870         else
5871         {
5872           int device_nr = getJoystickNrFromDeviceName(device_name);
5873           int new_device_nr = device_nr + (dx >= 0 ? +1 : -1);
5874
5875           if (new_device_nr < 0 || new_device_nr >= MAX_PLAYERS)
5876             setup.input[input_player_nr].use_joystick = FALSE;
5877           else
5878             setJoystickDeviceToNr(device_name, new_device_nr);
5879         }
5880
5881         drawPlayerSetupInputInfo(input_player_nr, FALSE);
5882       }
5883       else if (y == 2)
5884       {
5885         if (setup.input[input_player_nr].use_joystick)
5886         {
5887           InitJoysticks();
5888           CalibrateJoystick(input_player_nr);
5889         }
5890         else
5891           CustomizeKeyboard(input_player_nr);
5892       }
5893       else if (y == pos_end)
5894       {
5895         InitJoysticks();
5896
5897         FadeSetLeaveMenu();
5898
5899         setup_mode = SETUP_MODE_MAIN;
5900         DrawSetupScreen();
5901       }
5902     }
5903   }
5904 }
5905
5906 void CustomizeKeyboard(int player_nr)
5907 {
5908   int i;
5909   int step_nr;
5910   boolean finished = FALSE;
5911   static struct SetupKeyboardInfo custom_key;
5912   static struct
5913   {
5914     Key *key;
5915     char *text;
5916   } customize_step[] =
5917   {
5918     { &custom_key.left,  "Move Left"    },
5919     { &custom_key.right, "Move Right"   },
5920     { &custom_key.up,    "Move Up"      },
5921     { &custom_key.down,  "Move Down"    },
5922     { &custom_key.snap,  "Snap Field"   },
5923     { &custom_key.drop,  "Drop Element" }
5924   };
5925
5926   /* read existing key bindings from player setup */
5927   custom_key = setup.input[player_nr].key;
5928
5929   FadeSetEnterMenu();
5930   FadeOut(REDRAW_FIELD);
5931
5932   ClearField();
5933
5934   DrawTextSCentered(mSY - SY + 16, FONT_TITLE_1, "Keyboard Input");
5935
5936 #if 0
5937   BackToFront();
5938   InitAnimation();
5939 #endif
5940
5941   step_nr = 0;
5942   DrawText(mSX, mSY + (2 + 2 * step_nr) * 32,
5943            customize_step[step_nr].text, FONT_INPUT_1_ACTIVE);
5944   DrawText(mSX, mSY + (2 + 2 * step_nr + 1) * 32,
5945            "Key:", FONT_INPUT_1_ACTIVE);
5946   DrawText(mSX + 4 * 32, mSY + (2 + 2 * step_nr + 1) * 32,
5947            getKeyNameFromKey(*customize_step[step_nr].key), FONT_VALUE_OLD);
5948
5949 #if 1
5950   FadeIn(REDRAW_FIELD);
5951
5952   InitAnimation();
5953 #endif
5954
5955   while (!finished)
5956   {
5957     if (PendingEvent())         /* got event */
5958     {
5959       Event event;
5960
5961       NextEvent(&event);
5962
5963       switch (event.type)
5964       {
5965         case EVENT_KEYPRESS:
5966           {
5967             Key key = GetEventKey((KeyEvent *)&event, FALSE);
5968
5969             if (key == KSYM_Escape || (key == KSYM_Return && step_nr == 6))
5970             {
5971               if (key == KSYM_Escape)
5972                 FadeSkipNextFadeIn();
5973
5974               finished = TRUE;
5975               break;
5976             }
5977
5978             /* all keys configured -- wait for "Escape" or "Return" key */
5979             if (step_nr == 6)
5980               break;
5981
5982             /* press 'Enter' to keep the existing key binding */
5983             if (key == KSYM_Return)
5984               key = *customize_step[step_nr].key;
5985
5986             /* check if key already used */
5987             for (i = 0; i < step_nr; i++)
5988               if (*customize_step[i].key == key)
5989                 break;
5990             if (i < step_nr)
5991               break;
5992
5993             /* got new key binding */
5994             *customize_step[step_nr].key = key;
5995             DrawText(mSX + 4 * 32, mSY + (2 + 2 * step_nr + 1) * 32,
5996                      "             ", FONT_VALUE_1);
5997             DrawText(mSX + 4 * 32, mSY + (2 + 2 * step_nr + 1) * 32,
5998                      getKeyNameFromKey(key), FONT_VALUE_1);
5999             step_nr++;
6000
6001             /* un-highlight last query */
6002             DrawText(mSX, mSY + (2 + 2 * (step_nr - 1)) * 32,
6003                      customize_step[step_nr - 1].text, FONT_MENU_1);
6004             DrawText(mSX, mSY + (2 + 2 * (step_nr - 1) + 1) * 32,
6005                      "Key:", FONT_MENU_1);
6006
6007             /* press 'Enter' to leave */
6008             if (step_nr == 6)
6009             {
6010               DrawText(mSX + 16, mSY + 15 * 32 + 16,
6011                        "Press Enter", FONT_TITLE_1);
6012               break;
6013             }
6014
6015             /* query next key binding */
6016             DrawText(mSX, mSY + (2 + 2 * step_nr) * 32,
6017                      customize_step[step_nr].text, FONT_INPUT_1_ACTIVE);
6018             DrawText(mSX, mSY + (2 + 2 * step_nr + 1) * 32,
6019                      "Key:", FONT_INPUT_1_ACTIVE);
6020             DrawText(mSX + 4 * 32, mSY + (2 + 2 * step_nr + 1) * 32,
6021                      getKeyNameFromKey(*customize_step[step_nr].key),
6022                      FONT_VALUE_OLD);
6023           }
6024           break;
6025
6026         case EVENT_KEYRELEASE:
6027           key_joystick_mapping = 0;
6028           break;
6029
6030         default:
6031           HandleOtherEvents(&event);
6032           break;
6033       }
6034     }
6035
6036     DoAnimation();
6037     BackToFront();
6038
6039     /* don't eat all CPU time */
6040     Delay(10);
6041   }
6042
6043   /* write new key bindings back to player setup */
6044   setup.input[player_nr].key = custom_key;
6045
6046   StopAnimation();
6047   DrawSetupScreen_Input();
6048 }
6049
6050 static boolean CalibrateJoystickMain(int player_nr)
6051 {
6052   int new_joystick_xleft = JOYSTICK_XMIDDLE;
6053   int new_joystick_xright = JOYSTICK_XMIDDLE;
6054   int new_joystick_yupper = JOYSTICK_YMIDDLE;
6055   int new_joystick_ylower = JOYSTICK_YMIDDLE;
6056   int new_joystick_xmiddle, new_joystick_ymiddle;
6057
6058   int joystick_fd = joystick.fd[player_nr];
6059   int x, y, last_x, last_y, xpos = 8, ypos = 3;
6060   boolean check[3][3];
6061   int check_remaining = 3 * 3;
6062   int joy_x, joy_y;
6063   int joy_value;
6064   int result = -1;
6065
6066   if (joystick.status == JOYSTICK_NOT_AVAILABLE)
6067     return FALSE;
6068
6069   if (joystick_fd < 0 || !setup.input[player_nr].use_joystick)
6070     return FALSE;
6071
6072   FadeSetEnterMenu();
6073   FadeOut(REDRAW_FIELD);
6074
6075   ClearField();
6076
6077   for (y = 0; y < 3; y++)
6078   {
6079     for (x = 0; x < 3; x++)
6080     {
6081       DrawFixedGraphic(xpos + x - 1, ypos + y - 1, IMG_MENU_CALIBRATE_BLUE, 0);
6082       check[x][y] = FALSE;
6083     }
6084   }
6085
6086   DrawTextSCentered(mSY - SY +  6 * 32, FONT_TITLE_1, "Rotate joystick");
6087   DrawTextSCentered(mSY - SY +  7 * 32, FONT_TITLE_1, "in all directions");
6088   DrawTextSCentered(mSY - SY +  9 * 32, FONT_TITLE_1, "if all balls");
6089   DrawTextSCentered(mSY - SY + 10 * 32, FONT_TITLE_1, "are marked,");
6090   DrawTextSCentered(mSY - SY + 11 * 32, FONT_TITLE_1, "center joystick");
6091   DrawTextSCentered(mSY - SY + 12 * 32, FONT_TITLE_1, "and");
6092   DrawTextSCentered(mSY - SY + 13 * 32, FONT_TITLE_1, "press any button!");
6093
6094   joy_value = Joystick(player_nr);
6095   last_x = (joy_value & JOY_LEFT ? -1 : joy_value & JOY_RIGHT ? +1 : 0);
6096   last_y = (joy_value & JOY_UP   ? -1 : joy_value & JOY_DOWN  ? +1 : 0);
6097
6098   /* eventually uncalibrated center position (joystick could be uncentered) */
6099   if (!ReadJoystick(joystick_fd, &joy_x, &joy_y, NULL, NULL))
6100     return FALSE;
6101
6102   new_joystick_xmiddle = joy_x;
6103   new_joystick_ymiddle = joy_y;
6104
6105   DrawFixedGraphic(xpos + last_x, ypos + last_y, IMG_MENU_CALIBRATE_RED, 0);
6106
6107   FadeIn(REDRAW_FIELD);
6108
6109   while (Joystick(player_nr) & JOY_BUTTON);     /* wait for released button */
6110   InitAnimation();
6111
6112   while (result < 0)
6113   {
6114     if (PendingEvent())         /* got event */
6115     {
6116       Event event;
6117
6118       NextEvent(&event);
6119
6120       switch (event.type)
6121       {
6122         case EVENT_KEYPRESS:
6123           switch (GetEventKey((KeyEvent *)&event, TRUE))
6124           {
6125             case KSYM_Return:
6126               if (check_remaining == 0)
6127                 result = 1;
6128               break;
6129
6130             case KSYM_Escape:
6131               FadeSkipNextFadeIn();
6132               result = 0;
6133               break;
6134
6135             default:
6136               break;
6137           }
6138           break;
6139
6140         case EVENT_KEYRELEASE:
6141           key_joystick_mapping = 0;
6142           break;
6143
6144         default:
6145           HandleOtherEvents(&event);
6146           break;
6147       }
6148     }
6149
6150     if (!ReadJoystick(joystick_fd, &joy_x, &joy_y, NULL, NULL))
6151       return FALSE;
6152
6153     new_joystick_xleft  = MIN(new_joystick_xleft,  joy_x);
6154     new_joystick_xright = MAX(new_joystick_xright, joy_x);
6155     new_joystick_yupper = MIN(new_joystick_yupper, joy_y);
6156     new_joystick_ylower = MAX(new_joystick_ylower, joy_y);
6157
6158     setup.input[player_nr].joy.xleft = new_joystick_xleft;
6159     setup.input[player_nr].joy.yupper = new_joystick_yupper;
6160     setup.input[player_nr].joy.xright = new_joystick_xright;
6161     setup.input[player_nr].joy.ylower = new_joystick_ylower;
6162     setup.input[player_nr].joy.xmiddle = new_joystick_xmiddle;
6163     setup.input[player_nr].joy.ymiddle = new_joystick_ymiddle;
6164
6165     CheckJoystickData();
6166
6167     joy_value = Joystick(player_nr);
6168
6169     if (joy_value & JOY_BUTTON && check_remaining == 0)
6170       result = 1;
6171
6172     x = (joy_value & JOY_LEFT ? -1 : joy_value & JOY_RIGHT ? +1 : 0);
6173     y = (joy_value & JOY_UP   ? -1 : joy_value & JOY_DOWN  ? +1 : 0);
6174
6175     if (x != last_x || y != last_y)
6176     {
6177       DrawFixedGraphic(xpos + last_x, ypos + last_y,
6178                        IMG_MENU_CALIBRATE_YELLOW, 0);
6179       DrawFixedGraphic(xpos + x,      ypos + y,
6180                        IMG_MENU_CALIBRATE_RED,    0);
6181
6182       last_x = x;
6183       last_y = y;
6184
6185       if (check_remaining > 0 && !check[x+1][y+1])
6186       {
6187         check[x+1][y+1] = TRUE;
6188         check_remaining--;
6189       }
6190
6191 #if 0
6192 #ifdef DEBUG
6193       printf("LEFT / MIDDLE / RIGHT == %d / %d / %d\n",
6194              setup.input[player_nr].joy.xleft,
6195              setup.input[player_nr].joy.xmiddle,
6196              setup.input[player_nr].joy.xright);
6197       printf("UP / MIDDLE / DOWN == %d / %d / %d\n",
6198              setup.input[player_nr].joy.yupper,
6199              setup.input[player_nr].joy.ymiddle,
6200              setup.input[player_nr].joy.ylower);
6201 #endif
6202 #endif
6203
6204     }
6205
6206     DoAnimation();
6207     BackToFront();
6208
6209     /* don't eat all CPU time */
6210     Delay(10);
6211   }
6212
6213   /* calibrated center position (joystick should now be centered) */
6214   if (!ReadJoystick(joystick_fd, &joy_x, &joy_y, NULL, NULL))
6215     return FALSE;
6216
6217   new_joystick_xmiddle = joy_x;
6218   new_joystick_ymiddle = joy_y;
6219
6220   StopAnimation();
6221
6222 #if 0
6223   DrawSetupScreen_Input();
6224 #endif
6225
6226   /* wait until the last pressed button was released */
6227   while (Joystick(player_nr) & JOY_BUTTON)
6228   {
6229     if (PendingEvent())         /* got event */
6230     {
6231       Event event;
6232
6233       NextEvent(&event);
6234       HandleOtherEvents(&event);
6235
6236       Delay(10);
6237     }
6238   }
6239
6240   return TRUE;
6241 }
6242
6243 void CalibrateJoystick(int player_nr)
6244 {
6245   if (!CalibrateJoystickMain(player_nr))
6246   {
6247     char *device_name = setup.input[player_nr].joy.device_name;
6248     int nr = getJoystickNrFromDeviceName(device_name) + 1;
6249     int xpos = mSX - SX;
6250     int ypos = mSY - SY;
6251
6252     ClearField();
6253
6254     DrawTextF(xpos + 16, ypos + 6 * 32, FONT_TITLE_1, "   JOYSTICK %d   ", nr);
6255     DrawTextF(xpos + 16, ypos + 7 * 32, FONT_TITLE_1, " NOT AVAILABLE! ");
6256     BackToFront();
6257
6258     Delay(2000);                /* show error message for a short time */
6259
6260     ClearEventQueue();
6261   }
6262
6263 #if 1
6264   DrawSetupScreen_Input();
6265 #endif
6266 }
6267
6268 void DrawSetupScreen()
6269 {
6270   DeactivateJoystick();
6271
6272   SetMainBackgroundImage(IMG_BACKGROUND_SETUP);
6273
6274   if (setup_mode == SETUP_MODE_INPUT)
6275     DrawSetupScreen_Input();
6276   else if (setup_mode == SETUP_MODE_CHOOSE_GAME_SPEED)
6277     DrawChooseTree(&game_speed_current);
6278   else if (setup_mode == SETUP_MODE_CHOOSE_SCROLL_DELAY)
6279     DrawChooseTree(&scroll_delay_current);
6280   else if (setup_mode == SETUP_MODE_CHOOSE_SCREEN_MODE)
6281     DrawChooseTree(&screen_mode_current);
6282   else if (setup_mode == SETUP_MODE_CHOOSE_WINDOW_SIZE)
6283     DrawChooseTree(&window_size_current);
6284   else if (setup_mode == SETUP_MODE_CHOOSE_SCALING_TYPE)
6285     DrawChooseTree(&scaling_type_current);
6286   else if (setup_mode == SETUP_MODE_CHOOSE_GRAPHICS)
6287     DrawChooseTree(&artwork.gfx_current);
6288   else if (setup_mode == SETUP_MODE_CHOOSE_SOUNDS)
6289     DrawChooseTree(&artwork.snd_current);
6290   else if (setup_mode == SETUP_MODE_CHOOSE_MUSIC)
6291     DrawChooseTree(&artwork.mus_current);
6292   else if (setup_mode == SETUP_MODE_CHOOSE_VOLUME_SIMPLE)
6293     DrawChooseTree(&volume_simple_current);
6294   else if (setup_mode == SETUP_MODE_CHOOSE_VOLUME_LOOPS)
6295     DrawChooseTree(&volume_loops_current);
6296   else if (setup_mode == SETUP_MODE_CHOOSE_VOLUME_MUSIC)
6297     DrawChooseTree(&volume_music_current);
6298   else
6299     DrawSetupScreen_Generic();
6300
6301   PlayMenuSound();
6302   PlayMenuMusic();
6303 }
6304
6305 void RedrawSetupScreenAfterFullscreenToggle()
6306 {
6307 #if 1
6308   if (setup_mode == SETUP_MODE_GRAPHICS ||
6309       setup_mode == SETUP_MODE_CHOOSE_WINDOW_SIZE)
6310   {
6311     // update list selection from "setup.window_scaling_percent"
6312     execSetupGraphics_setWindowSizes(TRUE);
6313
6314     DrawSetupScreen();
6315   }
6316 #else
6317   if (setup_mode == SETUP_MODE_GRAPHICS)
6318     DrawSetupScreen();
6319 #endif
6320 }
6321
6322 void HandleSetupScreen(int mx, int my, int dx, int dy, int button)
6323 {
6324   if (setup_mode == SETUP_MODE_INPUT)
6325     HandleSetupScreen_Input(mx, my, dx, dy, button);
6326   else if (setup_mode == SETUP_MODE_CHOOSE_GAME_SPEED)
6327     HandleChooseTree(mx, my, dx, dy, button, &game_speed_current);
6328   else if (setup_mode == SETUP_MODE_CHOOSE_SCROLL_DELAY)
6329     HandleChooseTree(mx, my, dx, dy, button, &scroll_delay_current);
6330   else if (setup_mode == SETUP_MODE_CHOOSE_SCREEN_MODE)
6331     HandleChooseTree(mx, my, dx, dy, button, &screen_mode_current);
6332   else if (setup_mode == SETUP_MODE_CHOOSE_WINDOW_SIZE)
6333     HandleChooseTree(mx, my, dx, dy, button, &window_size_current);
6334   else if (setup_mode == SETUP_MODE_CHOOSE_SCALING_TYPE)
6335     HandleChooseTree(mx, my, dx, dy, button, &scaling_type_current);
6336   else if (setup_mode == SETUP_MODE_CHOOSE_GRAPHICS)
6337     HandleChooseTree(mx, my, dx, dy, button, &artwork.gfx_current);
6338   else if (setup_mode == SETUP_MODE_CHOOSE_SOUNDS)
6339     HandleChooseTree(mx, my, dx, dy, button, &artwork.snd_current);
6340   else if (setup_mode == SETUP_MODE_CHOOSE_MUSIC)
6341     HandleChooseTree(mx, my, dx, dy, button, &artwork.mus_current);
6342   else if (setup_mode == SETUP_MODE_CHOOSE_VOLUME_SIMPLE)
6343     HandleChooseTree(mx, my, dx, dy, button, &volume_simple_current);
6344   else if (setup_mode == SETUP_MODE_CHOOSE_VOLUME_LOOPS)
6345     HandleChooseTree(mx, my, dx, dy, button, &volume_loops_current);
6346   else if (setup_mode == SETUP_MODE_CHOOSE_VOLUME_MUSIC)
6347     HandleChooseTree(mx, my, dx, dy, button, &volume_music_current);
6348   else
6349     HandleSetupScreen_Generic(mx, my, dx, dy, button);
6350
6351 #if 0
6352   DoAnimation();
6353 #endif
6354 }
6355
6356 void HandleGameActions()
6357 {
6358   if (game_status != GAME_MODE_PLAYING)
6359     return;
6360
6361   GameActions();        /* main game loop */
6362
6363   if (tape.auto_play && !tape.playing)
6364     AutoPlayTape();     /* continue automatically playing next tape */
6365 }
6366
6367
6368 /* ---------- new screen button stuff -------------------------------------- */
6369
6370 static void getScreenMenuButtonPos(int *x, int *y, int gadget_id)
6371 {
6372   switch (gadget_id)
6373   {
6374 #if 1
6375     case SCREEN_CTRL_ID_PREV_LEVEL:
6376       *x = mSX + GDI_ACTIVE_POS(menu.main.button.prev_level.x);
6377       *y = mSY + GDI_ACTIVE_POS(menu.main.button.prev_level.y);
6378       break;
6379
6380     case SCREEN_CTRL_ID_NEXT_LEVEL:
6381       *x = mSX + GDI_ACTIVE_POS(menu.main.button.next_level.x);
6382       *y = mSY + GDI_ACTIVE_POS(menu.main.button.next_level.y);
6383       break;
6384 #else
6385     case SCREEN_CTRL_ID_PREV_LEVEL:
6386       *x = mSX + TILEX * getPrevlevelButtonPos();
6387       *y = mSY + TILEY * (MENU_SCREEN_START_YPOS + 1);
6388       break;
6389
6390     case SCREEN_CTRL_ID_NEXT_LEVEL:
6391       *x = mSX + TILEX * getNextLevelButtonPos();
6392       *y = mSY + TILEY * (MENU_SCREEN_START_YPOS + 1);
6393       break;
6394 #endif
6395
6396     case SCREEN_CTRL_ID_PREV_PLAYER:
6397       *x = mSX + TILEX * 10;
6398       *y = mSY + TILEY * MENU_SCREEN_START_YPOS;
6399       break;
6400
6401     case SCREEN_CTRL_ID_NEXT_PLAYER:
6402       *x = mSX + TILEX * 12;
6403       *y = mSY + TILEY * MENU_SCREEN_START_YPOS;
6404       break;
6405
6406     default:
6407       Error(ERR_EXIT, "unknown gadget ID %d", gadget_id);
6408   }
6409 }
6410
6411 static struct
6412 {
6413   int gfx_unpressed, gfx_pressed;
6414   void (*get_gadget_position)(int *, int *, int);
6415   int gadget_id;
6416   int screen_mask;
6417   char *infotext;
6418 } menubutton_info[NUM_SCREEN_MENUBUTTONS] =
6419 {
6420   {
6421     IMG_MENU_BUTTON_PREV_LEVEL, IMG_MENU_BUTTON_PREV_LEVEL_ACTIVE,
6422     getScreenMenuButtonPos,
6423     SCREEN_CTRL_ID_PREV_LEVEL,
6424     SCREEN_MASK_MAIN,
6425     "last level"
6426   },
6427   {
6428     IMG_MENU_BUTTON_NEXT_LEVEL, IMG_MENU_BUTTON_NEXT_LEVEL_ACTIVE,
6429     getScreenMenuButtonPos,
6430     SCREEN_CTRL_ID_NEXT_LEVEL,
6431     SCREEN_MASK_MAIN,
6432     "next level"
6433   },
6434   {
6435     IMG_MENU_BUTTON_LEFT, IMG_MENU_BUTTON_LEFT_ACTIVE,
6436     getScreenMenuButtonPos,
6437     SCREEN_CTRL_ID_PREV_PLAYER,
6438     SCREEN_MASK_INPUT,
6439     "last player"
6440   },
6441   {
6442     IMG_MENU_BUTTON_RIGHT, IMG_MENU_BUTTON_RIGHT_ACTIVE,
6443     getScreenMenuButtonPos,
6444     SCREEN_CTRL_ID_NEXT_PLAYER,
6445     SCREEN_MASK_INPUT,
6446     "next player"
6447   },
6448 };
6449
6450 static struct
6451 {
6452   int gfx_unpressed, gfx_pressed;
6453   int x, y;
6454   int gadget_id;
6455   char *infotext;
6456 } scrollbutton_info[NUM_SCREEN_SCROLLBUTTONS] =
6457 {
6458   {
6459     IMG_MENU_BUTTON_UP, IMG_MENU_BUTTON_UP_ACTIVE,
6460 #if 1
6461     -1, -1,     /* these values are not constant, but can change at runtime */
6462 #else
6463     SC_SCROLL_UP_XPOS, SC_SCROLL_UP_YPOS,
6464 #endif
6465     SCREEN_CTRL_ID_SCROLL_UP,
6466     "scroll up"
6467   },
6468   {
6469     IMG_MENU_BUTTON_DOWN, IMG_MENU_BUTTON_DOWN_ACTIVE,
6470 #if 1
6471     -1, -1,     /* these values are not constant, but can change at runtime */
6472 #else
6473     SC_SCROLL_DOWN_XPOS, SC_SCROLL_DOWN_YPOS,
6474 #endif
6475     SCREEN_CTRL_ID_SCROLL_DOWN,
6476     "scroll down"
6477   }
6478 };
6479
6480 static struct
6481 {
6482 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
6483   Bitmap **gfx_unpressed, **gfx_pressed;
6484 #else
6485   int gfx_unpressed, gfx_pressed;
6486 #endif
6487   int x, y;
6488   int width, height;
6489   int type;
6490   int gadget_id;
6491   char *infotext;
6492 } scrollbar_info[NUM_SCREEN_SCROLLBARS] =
6493 {
6494   {
6495 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
6496     &scrollbar_bitmap[0], &scrollbar_bitmap[1],
6497 #else
6498     IMG_MENU_SCROLLBAR, IMG_MENU_SCROLLBAR_ACTIVE,
6499 #endif
6500 #if 1
6501     -1, -1,     /* these values are not constant, but can change at runtime */
6502     -1, -1,     /* these values are not constant, but can change at runtime */
6503 #else
6504     SC_SCROLL_VERTICAL_XPOS, SC_SCROLL_VERTICAL_YPOS,
6505     SC_SCROLL_VERTICAL_XSIZE, SC_SCROLL_VERTICAL_YSIZE,
6506 #endif
6507     GD_TYPE_SCROLLBAR_VERTICAL,
6508     SCREEN_CTRL_ID_SCROLL_VERTICAL,
6509     "scroll level series vertically"
6510   }
6511 };
6512
6513 static void CreateScreenMenubuttons()
6514 {
6515   struct GadgetInfo *gi;
6516   unsigned int event_mask;
6517   int i;
6518
6519   for (i = 0; i < NUM_SCREEN_MENUBUTTONS; i++)
6520   {
6521     Bitmap *gd_bitmap_unpressed, *gd_bitmap_pressed;
6522     int gfx_unpressed, gfx_pressed;
6523     int x, y, width, height;
6524     int gd_x1, gd_x2, gd_y1, gd_y2;
6525     int id = menubutton_info[i].gadget_id;
6526
6527     event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
6528
6529     menubutton_info[i].get_gadget_position(&x, &y, id);
6530
6531     width = SC_MENUBUTTON_XSIZE;
6532     height = SC_MENUBUTTON_YSIZE;
6533
6534     gfx_unpressed = menubutton_info[i].gfx_unpressed;
6535     gfx_pressed   = menubutton_info[i].gfx_pressed;
6536     gd_bitmap_unpressed = graphic_info[gfx_unpressed].bitmap;
6537     gd_bitmap_pressed   = graphic_info[gfx_pressed].bitmap;
6538     gd_x1 = graphic_info[gfx_unpressed].src_x;
6539     gd_y1 = graphic_info[gfx_unpressed].src_y;
6540     gd_x2 = graphic_info[gfx_pressed].src_x;
6541     gd_y2 = graphic_info[gfx_pressed].src_y;
6542
6543     gi = CreateGadget(GDI_CUSTOM_ID, id,
6544                       GDI_CUSTOM_TYPE_ID, i,
6545                       GDI_INFO_TEXT, menubutton_info[i].infotext,
6546                       GDI_X, x,
6547                       GDI_Y, y,
6548                       GDI_WIDTH, width,
6549                       GDI_HEIGHT, height,
6550                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
6551                       GDI_STATE, GD_BUTTON_UNPRESSED,
6552                       GDI_DESIGN_UNPRESSED, gd_bitmap_unpressed, gd_x1, gd_y1,
6553                       GDI_DESIGN_PRESSED, gd_bitmap_pressed, gd_x2, gd_y2,
6554                       GDI_DIRECT_DRAW, FALSE,
6555                       GDI_EVENT_MASK, event_mask,
6556                       GDI_CALLBACK_ACTION, HandleScreenGadgets,
6557                       GDI_END);
6558
6559     if (gi == NULL)
6560       Error(ERR_EXIT, "cannot create gadget");
6561
6562     screen_gadget[id] = gi;
6563   }
6564 }
6565
6566 static void CreateScreenScrollbuttons()
6567 {
6568   struct GadgetInfo *gi;
6569   unsigned int event_mask;
6570   int i;
6571
6572   /* these values are not constant, but can change at runtime */
6573   scrollbutton_info[0].x = SC_SCROLL_UP_XPOS;
6574   scrollbutton_info[0].y = SC_SCROLL_UP_YPOS;
6575   scrollbutton_info[1].x = SC_SCROLL_DOWN_XPOS;
6576   scrollbutton_info[1].y = SC_SCROLL_DOWN_YPOS;
6577
6578   for (i = 0; i < NUM_SCREEN_SCROLLBUTTONS; i++)
6579   {
6580     Bitmap *gd_bitmap_unpressed, *gd_bitmap_pressed;
6581     int gfx_unpressed, gfx_pressed;
6582     int x, y, width, height;
6583     int gd_x1, gd_x2, gd_y1, gd_y2;
6584     int id = scrollbutton_info[i].gadget_id;
6585
6586     event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
6587
6588     x = mSX + scrollbutton_info[i].x + menu.scrollbar_xoffset;
6589     y = mSY + scrollbutton_info[i].y;
6590     width = SC_SCROLLBUTTON_XSIZE;
6591     height = SC_SCROLLBUTTON_YSIZE;
6592
6593     if (id == SCREEN_CTRL_ID_SCROLL_DOWN)
6594       y = mSY + (SC_SCROLL_VERTICAL_YPOS +
6595                  (NUM_MENU_ENTRIES_ON_SCREEN - 2) * SC_SCROLLBUTTON_YSIZE);
6596
6597     gfx_unpressed = scrollbutton_info[i].gfx_unpressed;
6598     gfx_pressed   = scrollbutton_info[i].gfx_pressed;
6599     gd_bitmap_unpressed = graphic_info[gfx_unpressed].bitmap;
6600     gd_bitmap_pressed   = graphic_info[gfx_pressed].bitmap;
6601     gd_x1 = graphic_info[gfx_unpressed].src_x;
6602     gd_y1 = graphic_info[gfx_unpressed].src_y;
6603     gd_x2 = graphic_info[gfx_pressed].src_x;
6604     gd_y2 = graphic_info[gfx_pressed].src_y;
6605
6606     gi = CreateGadget(GDI_CUSTOM_ID, id,
6607                       GDI_CUSTOM_TYPE_ID, i,
6608                       GDI_INFO_TEXT, scrollbutton_info[i].infotext,
6609                       GDI_X, x,
6610                       GDI_Y, y,
6611                       GDI_WIDTH, width,
6612                       GDI_HEIGHT, height,
6613                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
6614                       GDI_STATE, GD_BUTTON_UNPRESSED,
6615                       GDI_DESIGN_UNPRESSED, gd_bitmap_unpressed, gd_x1, gd_y1,
6616                       GDI_DESIGN_PRESSED, gd_bitmap_pressed, gd_x2, gd_y2,
6617                       GDI_DIRECT_DRAW, FALSE,
6618                       GDI_EVENT_MASK, event_mask,
6619                       GDI_CALLBACK_ACTION, HandleScreenGadgets,
6620                       GDI_END);
6621
6622     if (gi == NULL)
6623       Error(ERR_EXIT, "cannot create gadget");
6624
6625     screen_gadget[id] = gi;
6626   }
6627 }
6628
6629 static void CreateScreenScrollbars()
6630 {
6631   int i;
6632
6633   /* these values are not constant, but can change at runtime */
6634   scrollbar_info[0].x = SC_SCROLL_VERTICAL_XPOS;
6635   scrollbar_info[0].y = SC_SCROLL_VERTICAL_YPOS;
6636   scrollbar_info[0].width  = SC_SCROLL_VERTICAL_XSIZE;
6637   scrollbar_info[0].height = SC_SCROLL_VERTICAL_YSIZE;
6638
6639   for (i = 0; i < NUM_SCREEN_SCROLLBARS; i++)
6640   {
6641     Bitmap *gd_bitmap_unpressed, *gd_bitmap_pressed;
6642 #if !defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
6643     int gfx_unpressed, gfx_pressed;
6644 #endif
6645     int x, y, width, height;
6646     int gd_x1, gd_x2, gd_y1, gd_y2;
6647     struct GadgetInfo *gi;
6648     int items_max, items_visible, item_position;
6649     unsigned int event_mask;
6650     int num_page_entries = NUM_MENU_ENTRIES_ON_SCREEN;
6651     int id = scrollbar_info[i].gadget_id;
6652
6653     event_mask = GD_EVENT_MOVING | GD_EVENT_OFF_BORDERS;
6654
6655     x = mSX + scrollbar_info[i].x + menu.scrollbar_xoffset;
6656     y = mSY + scrollbar_info[i].y;
6657     width  = scrollbar_info[i].width;
6658     height = scrollbar_info[i].height;
6659
6660     if (id == SCREEN_CTRL_ID_SCROLL_VERTICAL)
6661       height = (NUM_MENU_ENTRIES_ON_SCREEN - 2) * SC_SCROLLBUTTON_YSIZE;
6662
6663     items_max = num_page_entries;
6664     items_visible = num_page_entries;
6665     item_position = 0;
6666
6667 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
6668     gd_bitmap_unpressed = *scrollbar_info[i].gfx_unpressed;
6669     gd_bitmap_pressed   = *scrollbar_info[i].gfx_pressed;
6670     gd_x1 = 0;
6671     gd_y1 = 0;
6672     gd_x2 = 0;
6673     gd_y2 = 0;
6674 #else
6675     gfx_unpressed = scrollbar_info[i].gfx_unpressed;
6676     gfx_pressed   = scrollbar_info[i].gfx_pressed;
6677     gd_bitmap_unpressed = graphic_info[gfx_unpressed].bitmap;
6678     gd_bitmap_pressed   = graphic_info[gfx_pressed].bitmap;
6679     gd_x1 = graphic_info[gfx_unpressed].src_x;
6680     gd_y1 = graphic_info[gfx_unpressed].src_y;
6681     gd_x2 = graphic_info[gfx_pressed].src_x;
6682     gd_y2 = graphic_info[gfx_pressed].src_y;
6683 #endif
6684
6685     gi = CreateGadget(GDI_CUSTOM_ID, id,
6686                       GDI_CUSTOM_TYPE_ID, i,
6687                       GDI_INFO_TEXT, scrollbar_info[i].infotext,
6688                       GDI_X, x,
6689                       GDI_Y, y,
6690                       GDI_WIDTH, width,
6691                       GDI_HEIGHT, height,
6692                       GDI_TYPE, scrollbar_info[i].type,
6693                       GDI_SCROLLBAR_ITEMS_MAX, items_max,
6694                       GDI_SCROLLBAR_ITEMS_VISIBLE, items_visible,
6695                       GDI_SCROLLBAR_ITEM_POSITION, item_position,
6696 #if 1
6697                       GDI_WHEEL_AREA_X, SX,
6698                       GDI_WHEEL_AREA_Y, SY,
6699                       GDI_WHEEL_AREA_WIDTH, SXSIZE,
6700                       GDI_WHEEL_AREA_HEIGHT, SYSIZE,
6701 #else
6702                       GDI_WHEEL_AREA_X, 0,
6703                       GDI_WHEEL_AREA_Y, 0,
6704                       GDI_WHEEL_AREA_WIDTH, WIN_XSIZE,
6705                       GDI_WHEEL_AREA_HEIGHT, WIN_YSIZE,
6706 #endif
6707                       GDI_STATE, GD_BUTTON_UNPRESSED,
6708                       GDI_DESIGN_UNPRESSED, gd_bitmap_unpressed, gd_x1, gd_y1,
6709                       GDI_DESIGN_PRESSED, gd_bitmap_pressed, gd_x2, gd_y2,
6710                       GDI_BORDER_SIZE, SC_BORDER_SIZE, SC_BORDER_SIZE,
6711                       GDI_DIRECT_DRAW, FALSE,
6712                       GDI_EVENT_MASK, event_mask,
6713                       GDI_CALLBACK_ACTION, HandleScreenGadgets,
6714                       GDI_END);
6715
6716     if (gi == NULL)
6717       Error(ERR_EXIT, "cannot create gadget");
6718
6719     screen_gadget[id] = gi;
6720   }
6721 }
6722
6723 void CreateScreenGadgets()
6724 {
6725   int last_game_status = game_status;   /* save current game status */
6726
6727 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
6728   int i;
6729
6730   for (i = 0; i < NUM_SCROLLBAR_BITMAPS; i++)
6731   {
6732     scrollbar_bitmap[i] = CreateBitmap(TILEX, TILEY, DEFAULT_DEPTH);
6733
6734     /* copy pointers to clip mask and GC */
6735     scrollbar_bitmap[i]->clip_mask =
6736       graphic_info[IMG_MENU_SCROLLBAR + i].clip_mask;
6737     scrollbar_bitmap[i]->stored_clip_gc =
6738       graphic_info[IMG_MENU_SCROLLBAR + i].clip_gc;
6739
6740     BlitBitmap(graphic_info[IMG_MENU_SCROLLBAR + i].bitmap,
6741                scrollbar_bitmap[i],
6742                graphic_info[IMG_MENU_SCROLLBAR + i].src_x,
6743                graphic_info[IMG_MENU_SCROLLBAR + i].src_y,
6744                TILEX, TILEY, 0, 0);
6745   }
6746 #endif
6747
6748   CreateScreenMenubuttons();
6749
6750 #if 0
6751   /* force LEVELS draw offset for scrollbar / scrollbutton gadgets */
6752   game_status = GAME_MODE_LEVELS;
6753 #endif
6754
6755   CreateScreenScrollbuttons();
6756   CreateScreenScrollbars();
6757
6758   game_status = last_game_status;       /* restore current game status */
6759 }
6760
6761 void FreeScreenGadgets()
6762 {
6763   int i;
6764
6765 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
6766   for (i = 0; i < NUM_SCROLLBAR_BITMAPS; i++)
6767   {
6768     /* prevent freeing clip mask and GC twice */
6769     scrollbar_bitmap[i]->clip_mask = None;
6770     scrollbar_bitmap[i]->stored_clip_gc = None;
6771
6772     FreeBitmap(scrollbar_bitmap[i]);
6773   }
6774 #endif
6775
6776   for (i = 0; i < NUM_SCREEN_GADGETS; i++)
6777     FreeGadget(screen_gadget[i]);
6778 }
6779
6780 void MapScreenMenuGadgets(int screen_mask)
6781 {
6782   int i;
6783
6784   for (i = 0; i < NUM_SCREEN_MENUBUTTONS; i++)
6785     if (screen_mask & menubutton_info[i].screen_mask)
6786       MapGadget(screen_gadget[menubutton_info[i].gadget_id]);
6787 }
6788
6789 void MapScreenTreeGadgets(TreeInfo *ti)
6790 {
6791   int num_entries = numTreeInfoInGroup(ti);
6792   int i;
6793
6794   if (num_entries <= NUM_MENU_ENTRIES_ON_SCREEN)
6795     return;
6796
6797   for (i = 0; i < NUM_SCREEN_SCROLLBUTTONS; i++)
6798     MapGadget(screen_gadget[scrollbutton_info[i].gadget_id]);
6799
6800   for (i = 0; i < NUM_SCREEN_SCROLLBARS; i++)
6801     MapGadget(screen_gadget[scrollbar_info[i].gadget_id]);
6802 }
6803
6804 static void HandleScreenGadgets(struct GadgetInfo *gi)
6805 {
6806   int id = gi->custom_id;
6807   int button = gi->event.button;
6808   int step = (button == 1 ? 1 : button == 2 ? 5 : 10);
6809
6810   switch (id)
6811   {
6812     case SCREEN_CTRL_ID_PREV_LEVEL:
6813       HandleMainMenu_SelectLevel(step, -1);
6814       break;
6815
6816     case SCREEN_CTRL_ID_NEXT_LEVEL:
6817       HandleMainMenu_SelectLevel(step, +1);
6818       break;
6819
6820     case SCREEN_CTRL_ID_PREV_PLAYER:
6821       HandleSetupScreen_Input_Player(step, -1);
6822       break;
6823
6824     case SCREEN_CTRL_ID_NEXT_PLAYER:
6825       HandleSetupScreen_Input_Player(step, +1);
6826       break;
6827
6828     case SCREEN_CTRL_ID_SCROLL_UP:
6829       if (game_status == GAME_MODE_LEVELS)
6830         HandleChooseLevelSet(0,0, 0, -1 * SCROLL_LINE, MB_MENU_MARK);
6831       else if (game_status == GAME_MODE_LEVELNR)
6832         HandleChooseLevelNr(0,0, 0, -1 * SCROLL_LINE, MB_MENU_MARK);
6833       else if (game_status == GAME_MODE_SETUP)
6834         HandleSetupScreen(0,0, 0, -1 * SCROLL_LINE, MB_MENU_MARK);
6835       break;
6836
6837     case SCREEN_CTRL_ID_SCROLL_DOWN:
6838       if (game_status == GAME_MODE_LEVELS)
6839         HandleChooseLevelSet(0,0, 0, +1 * SCROLL_LINE, MB_MENU_MARK);
6840       else if (game_status == GAME_MODE_LEVELNR)
6841         HandleChooseLevelNr(0,0, 0, +1 * SCROLL_LINE, MB_MENU_MARK);
6842       else if (game_status == GAME_MODE_SETUP)
6843         HandleSetupScreen(0,0, 0, +1 * SCROLL_LINE, MB_MENU_MARK);
6844       break;
6845
6846     case SCREEN_CTRL_ID_SCROLL_VERTICAL:
6847       if (game_status == GAME_MODE_LEVELS)
6848         HandleChooseLevelSet(0,0,999,gi->event.item_position,MB_MENU_INITIALIZE);
6849       else if (game_status == GAME_MODE_LEVELNR)
6850         HandleChooseLevelNr(0,0,999,gi->event.item_position,MB_MENU_INITIALIZE);
6851       else if (game_status == GAME_MODE_SETUP)
6852         HandleSetupScreen(0,0, 999,gi->event.item_position,MB_MENU_INITIALIZE);
6853       break;
6854
6855     default:
6856       break;
6857   }
6858 }