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