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