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