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