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