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