rnd-20030615-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             4
33 #define SETUP_MODE_GRAPHICS             5
34 #define SETUP_MODE_SOUND                6
35 #define SETUP_MODE_ARTWORK              7
36 #define SETUP_MODE_CHOOSE_GRAPHICS      8
37 #define SETUP_MODE_CHOOSE_SOUNDS        9
38 #define SETUP_MODE_CHOOSE_MUSIC         10
39
40 #define MAX_SETUP_MODES                 11
41
42 /* for input setup functions */
43 #define SETUPINPUT_SCREEN_POS_START     0
44 #define SETUPINPUT_SCREEN_POS_END       (SCR_FIELDY - 4)
45 #define SETUPINPUT_SCREEN_POS_EMPTY1    (SETUPINPUT_SCREEN_POS_START + 3)
46 #define SETUPINPUT_SCREEN_POS_EMPTY2    (SETUPINPUT_SCREEN_POS_END - 1)
47
48 /* for various menu stuff  */
49 #define MAX_MENU_ENTRIES_ON_SCREEN      (SCR_FIELDY - 2)
50 #define MENU_SCREEN_START_YPOS          2
51 #define MENU_SCREEN_VALUE_XPOS          14
52
53 /* buttons and scrollbars identifiers */
54 #define SCREEN_CTRL_ID_SCROLL_UP        0
55 #define SCREEN_CTRL_ID_SCROLL_DOWN      1
56 #define SCREEN_CTRL_ID_SCROLL_VERTICAL  2
57
58 #define NUM_SCREEN_SCROLLBUTTONS        2
59 #define NUM_SCREEN_SCROLLBARS           1
60 #define NUM_SCREEN_GADGETS              3
61
62 /* forward declarations of internal functions */
63 static void HandleScreenGadgets(struct GadgetInfo *);
64 static void HandleSetupScreen_Generic(int, int, int, int, int);
65 static void HandleSetupScreen_Input(int, int, int, int, int);
66 static void CustomizeKeyboard(int);
67 static void CalibrateJoystick(int);
68 static void execSetupArtwork(void);
69 static void HandleChooseTree(int, int, int, int, int, TreeInfo **);
70
71 static struct GadgetInfo *screen_gadget[NUM_SCREEN_GADGETS];
72 static int setup_mode = SETUP_MODE_MAIN;
73
74 #define mSX (SX + (game_status >= GAME_MODE_MAIN &&     \
75                    game_status <= GAME_MODE_SETUP ?     \
76                    menu.draw_xoffset[game_status] : menu.draw_xoffset_default))
77 #define mSY (SY + (game_status >= GAME_MODE_MAIN &&     \
78                    game_status <= GAME_MODE_SETUP ?     \
79                    menu.draw_yoffset[game_status] : menu.draw_yoffset_default))
80
81 #define NUM_MENU_ENTRIES_ON_SCREEN (menu.list_size[game_status] > 2 ?   \
82                                     menu.list_size[game_status] :       \
83                                     MAX_MENU_ENTRIES_ON_SCREEN)
84
85 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
86 #define NUM_SCROLLBAR_BITMAPS           2
87 static Bitmap *scrollbar_bitmap[NUM_SCROLLBAR_BITMAPS];
88 #endif
89
90
91 static void drawCursorExt(int xpos, int ypos, int color, int graphic)
92 {
93   static int cursor_array[SCR_FIELDY];
94
95   if (xpos == 0)
96   {
97     if (graphic != 0)
98       cursor_array[ypos] = graphic;
99     else
100       graphic = cursor_array[ypos];
101   }
102
103   if (color == FC_RED)
104     graphic = (graphic == IMG_MENU_BUTTON_LEFT  ? IMG_MENU_BUTTON_LEFT_ACTIVE :
105                graphic == IMG_MENU_BUTTON_RIGHT ? IMG_MENU_BUTTON_RIGHT_ACTIVE:
106                IMG_MENU_BUTTON_ACTIVE);
107
108   ypos += MENU_SCREEN_START_YPOS;
109
110   DrawBackground(mSX + xpos * TILEX, mSY + ypos * TILEY, TILEX, TILEY);
111   DrawGraphicThruMaskExt(drawto, mSX + xpos * TILEX, mSY + ypos * TILEY,
112                          graphic, 0);
113 }
114
115 static void initCursor(int ypos, int graphic)
116 {
117   drawCursorExt(0, ypos, FC_BLUE, graphic);
118 }
119
120 static void drawCursor(int ypos, int color)
121 {
122   drawCursorExt(0, ypos, color, 0);
123 }
124
125 static void drawCursorXY(int xpos, int ypos, int graphic)
126 {
127   drawCursorExt(xpos, ypos, -1, graphic);
128 }
129
130 static void PlaySound_Menu_Start(int sound)
131 {
132   if (sound_info[sound].loop)
133     PlaySoundLoop(sound);
134   else
135     PlaySound(sound);
136 }
137
138 static void PlaySound_Menu_Continue(int sound)
139 {
140   if (sound_info[sound].loop)
141     PlaySoundLoop(sound);
142 }
143
144 void DrawHeadline()
145 {
146   int font1_width = getFontWidth(FONT_TITLE_1);
147   int font2_width = getFontWidth(FONT_TITLE_2);
148   int x1 = SX + (SXSIZE - strlen(PROGRAM_TITLE_STRING)   * font1_width) / 2;
149   int x2 = SX + (SXSIZE - strlen(WINDOW_SUBTITLE_STRING) * font2_width) / 2;
150
151   DrawText(x1, SY + 8,  PROGRAM_TITLE_STRING,   FONT_TITLE_1);
152   DrawText(x2, SY + 46, WINDOW_SUBTITLE_STRING, FONT_TITLE_2);
153 }
154
155 static void ToggleFullscreenIfNeeded()
156 {
157   if (setup.fullscreen != video.fullscreen_enabled)
158   {
159     /* save old door content */
160     BlitBitmap(backbuffer, bitmap_db_door,
161                DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
162
163     /* toggle fullscreen */
164     ChangeVideoModeIfNeeded(setup.fullscreen);
165     setup.fullscreen = video.fullscreen_enabled;
166
167     /* redraw background to newly created backbuffer */
168     BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
169                0,0, WIN_XSIZE,WIN_YSIZE, 0,0);
170
171     /* restore old door content */
172     BlitBitmap(bitmap_db_door, backbuffer,
173                DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, DX, DY);
174
175     redraw_mask = REDRAW_ALL;
176   }
177 }
178
179 void DrawMainMenu()
180 {
181   static LevelDirTree *leveldir_last_valid = NULL;
182   char *name_text = (!options.network && setup.team_mode ? "Team:" : "Name:");
183   int font_width = getFontWidth(FONT_MENU_1);
184   int name_width = font_width * strlen("Name:");
185   int level_width = font_width * strlen("Level:");
186   int i;
187
188   UnmapAllGadgets();
189   FadeSounds();
190
191   KeyboardAutoRepeatOn();
192   ActivateJoystick();
193
194   SetDrawDeactivationMask(REDRAW_NONE);
195   SetDrawBackgroundMask(REDRAW_FIELD);
196
197   audio.sound_deactivated = FALSE;
198
199   /* needed if last screen was the playing screen, invoked from level editor */
200   if (level_editor_test_game)
201   {
202     game_status = GAME_MODE_EDITOR;
203     DrawLevelEd();
204     return;
205   }
206
207   /* needed if last screen was the editor screen */
208   UndrawSpecialEditorDoor();
209
210   /* needed if last screen was the setup screen and fullscreen state changed */
211   ToggleFullscreenIfNeeded();
212
213   /* needed if last screen (level choice) changed graphics, sounds or music */
214   ReloadCustomArtwork();
215
216 #ifdef TARGET_SDL
217   SetDrawtoField(DRAW_BACKBUFFER);
218 #endif
219
220   /* map gadgets for main menu screen */
221   MapTapeButtons();
222
223   /* leveldir_current may be invalid (level group, parent link) */
224   if (!validLevelSeries(leveldir_current))
225     leveldir_current = getFirstValidTreeInfoEntry(leveldir_last_valid);
226
227   /* store valid level series information */
228   leveldir_last_valid = leveldir_current;
229
230   /* level_nr may have been set to value over handicap with level editor */
231   if (setup.handicap && level_nr > leveldir_current->handicap_level)
232     level_nr = leveldir_current->handicap_level;
233
234   GetPlayerConfig();
235   LoadLevel(level_nr);
236
237   SetMainBackgroundImage(IMG_BACKGROUND_MAIN);
238   ClearWindow();
239
240   DrawHeadline();
241
242   DrawText(mSX + 32, mSY + 2*32, name_text, FONT_MENU_1);
243   DrawText(mSX + 32, mSY + 3*32, "Level:", FONT_MENU_1);
244   DrawText(mSX + 32, mSY + 4*32, "Hall Of Fame", FONT_MENU_1);
245   DrawText(mSX + 32, mSY + 5*32, "Level Creator", FONT_MENU_1);
246   DrawText(mSX + 32, mSY + 6*32, "Info Screen", FONT_MENU_1);
247   DrawText(mSX + 32, mSY + 7*32, "Start Game", FONT_MENU_1);
248   DrawText(mSX + 32, mSY + 8*32, "Setup", FONT_MENU_1);
249   DrawText(mSX + 32, mSY + 9*32, "Quit", FONT_MENU_1);
250
251   DrawText(mSX + 32 + name_width, mSY + 2*32, setup.player_name, FONT_INPUT_1);
252   DrawText(mSX + level_width + 5 * 32, mSY + 3*32, int2str(level_nr,3),
253            FONT_VALUE_1);
254
255   DrawMicroLevel(MICROLEV_XPOS, MICROLEV_YPOS, TRUE);
256
257   DrawTextF(mSX + 32 + level_width - 2, mSY + 3*32 + 1, FONT_TEXT_3, "%d-%d",
258             leveldir_current->first_level, leveldir_current->last_level);
259
260   if (leveldir_current->readonly)
261   {
262     DrawTextF(mSX + level_width + 9 * 32 - 2,
263               mSY + 3 * 32 + 1 - 7, FONT_TEXT_3, "READ");
264     DrawTextF(mSX + level_width + 9 * 32 - 2,
265               mSY + 3 * 32 + 1 + 7, FONT_TEXT_3, "ONLY");
266   }
267
268   for(i=0; i<8; i++)
269     initCursor(i, (i == 1 || i == 6 ? IMG_MENU_BUTTON_RIGHT :IMG_MENU_BUTTON));
270
271   drawCursorXY(level_width/32 + 4, 1, IMG_MENU_BUTTON_LEFT);
272   drawCursorXY(level_width/32 + 8, 1, IMG_MENU_BUTTON_RIGHT);
273
274   DrawText(SX + 56, SY + 326, "A Game by Artsoft Entertainment", FONT_TITLE_2);
275
276   FadeToFront();
277   InitAnimation();
278   HandleMainMenu(0,0, 0,0, MB_MENU_INITIALIZE);
279
280   TapeStop();
281   if (TAPE_IS_EMPTY(tape))
282     LoadTape(level_nr);
283   DrawCompleteVideoDisplay();
284
285   OpenDoor(DOOR_CLOSE_1 | DOOR_OPEN_2);
286
287 #if 0
288   ClearEventQueue();
289 #endif
290 }
291
292 static void gotoTopLevelDir()
293 {
294   /* move upwards to top level directory */
295   while (leveldir_current->node_parent)
296   {
297     /* write a "path" into level tree for easy navigation to last level */
298     if (leveldir_current->node_parent->node_group->cl_first == -1)
299     {
300       int num_leveldirs = numTreeInfoInGroup(leveldir_current);
301       int leveldir_pos = posTreeInfo(leveldir_current);
302       int num_page_entries;
303       int cl_first, cl_cursor;
304
305       if (num_leveldirs <= NUM_MENU_ENTRIES_ON_SCREEN)
306         num_page_entries = num_leveldirs;
307       else
308         num_page_entries = NUM_MENU_ENTRIES_ON_SCREEN;
309
310       cl_first = MAX(0, leveldir_pos - num_page_entries + 1);
311       cl_cursor = leveldir_pos - cl_first;
312
313       leveldir_current->node_parent->node_group->cl_first = cl_first;
314       leveldir_current->node_parent->node_group->cl_cursor = cl_cursor;
315     }
316
317     leveldir_current = leveldir_current->node_parent;
318   }
319 }
320
321 void HandleMainMenu(int mx, int my, int dx, int dy, int button)
322 {
323   static int choice = 0;
324   int x = 0;
325   int y = choice;
326
327   if (button == MB_MENU_INITIALIZE)
328   {
329     drawCursor(choice, FC_RED);
330     return;
331   }
332
333   if (mx || my)         /* mouse input */
334   {
335     x = (mx - mSX) / 32;
336     y = (my - mSY) / 32 - MENU_SCREEN_START_YPOS;
337   }
338   else if (dx || dy)    /* keyboard input */
339   {
340     if (dx && choice == 1)
341       x = (dx < 0 ? 10 : 14);
342     else if (dy)
343       y = choice + dy;
344   }
345
346   if (y == 1 && ((x == 10 && level_nr > leveldir_current->first_level) ||
347                  (x == 14 && level_nr < leveldir_current->last_level)) &&
348       button)
349   {
350     static unsigned long level_delay = 0;
351     int step = (button == 1 ? 1 : button == 2 ? 5 : 10);
352     int new_level_nr, old_level_nr = level_nr;
353
354     new_level_nr = level_nr + (x == 10 ? -step : +step);
355     if (new_level_nr < leveldir_current->first_level)
356       new_level_nr = leveldir_current->first_level;
357     if (new_level_nr > leveldir_current->last_level)
358       new_level_nr = leveldir_current->last_level;
359
360     if (setup.handicap && new_level_nr > leveldir_current->handicap_level)
361       new_level_nr = leveldir_current->handicap_level;
362
363     if (old_level_nr == new_level_nr ||
364         !DelayReached(&level_delay, GADGET_FRAME_DELAY))
365       goto out;
366
367     level_nr = new_level_nr;
368
369     DrawText(mSX + 11 * 32, mSY + 3 * 32, int2str(level_nr, 3), FONT_VALUE_1);
370
371     LoadLevel(level_nr);
372     DrawMicroLevel(MICROLEV_XPOS, MICROLEV_YPOS, TRUE);
373
374     TapeErase();
375     LoadTape(level_nr);
376     DrawCompleteVideoDisplay();
377
378     /* needed because DrawMicroLevel() takes some time */
379     BackToFront();
380     SyncDisplay();
381     DelayReached(&level_delay, 0);      /* reset delay counter */
382   }
383   else if (x == 0 && y >= 0 && y <= 7)
384   {
385     if (button)
386     {
387       if (y != choice)
388       {
389         drawCursor(y, FC_RED);
390         drawCursor(choice, FC_BLUE);
391         choice = y;
392       }
393     }
394     else
395     {
396       if (y == 0)
397       {
398         game_status = GAME_MODE_PSEUDO_TYPENAME;
399         HandleTypeName(strlen(setup.player_name), 0);
400       }
401       else if (y == 1)
402       {
403         if (leveldir_first)
404         {
405           game_status = GAME_MODE_LEVELS;
406           SaveLevelSetup_LastSeries();
407           SaveLevelSetup_SeriesInfo();
408
409           gotoTopLevelDir();
410
411           DrawChooseLevel();
412         }
413       }
414       else if (y == 2)
415       {
416         game_status = GAME_MODE_SCORES;
417         DrawHallOfFame(-1);
418       }
419       else if (y == 3)
420       {
421         if (leveldir_current->readonly &&
422             strcmp(setup.player_name, "Artsoft") != 0)
423           Request("This level is read only !", REQ_CONFIRM);
424         game_status = GAME_MODE_EDITOR;
425         DrawLevelEd();
426       }
427       else if (y == 4)
428       {
429         game_status = GAME_MODE_INFO;
430         DrawHelpScreen();
431       }
432       else if (y == 5)
433       {
434         if (setup.autorecord)
435           TapeStartRecording();
436
437 #if defined(PLATFORM_UNIX)
438         if (options.network)
439           SendToServer_StartPlaying();
440         else
441 #endif
442         {
443           game_status = GAME_MODE_PLAYING;
444           StopAnimation();
445           InitGame();
446         }
447       }
448       else if (y == 6)
449       {
450         game_status = GAME_MODE_SETUP;
451         setup_mode = SETUP_MODE_MAIN;
452         DrawSetupScreen();
453       }
454       else if (y == 7)
455       {
456         SaveLevelSetup_LastSeries();
457         SaveLevelSetup_SeriesInfo();
458         if (Request("Do you really want to quit ?", REQ_ASK | REQ_STAY_CLOSED))
459           game_status = GAME_MODE_QUIT;
460       }
461     }
462   }
463
464   BackToFront();
465
466   out:
467
468   if (game_status == GAME_MODE_MAIN)
469   {
470     DrawMicroLevel(MICROLEV_XPOS, MICROLEV_YPOS, FALSE);
471     DoAnimation();
472   }
473 }
474
475
476 #define MAX_HELPSCREEN_ELS      10
477 #define HA_NEXT                 -999
478 #define HA_END                  -1000
479
480 static long helpscreen_state;
481 static int helpscreen_step[MAX_HELPSCREEN_ELS];
482 static int helpscreen_frame[MAX_HELPSCREEN_ELS];
483
484 static int helpscreen_action[] =
485 {
486   IMG_PLAYER_1_MOVING_DOWN,             16,
487   IMG_PLAYER_1_MOVING_UP,               16,
488   IMG_PLAYER_1_MOVING_LEFT,             16,
489   IMG_PLAYER_1_MOVING_RIGHT,            16,
490   IMG_PLAYER_1_PUSHING_LEFT,            16,
491   IMG_PLAYER_1_PUSHING_RIGHT,           16,                     HA_NEXT,
492
493   IMG_SAND,                             -1,                     HA_NEXT,
494
495   IMG_EMPTY_SPACE,                      -1,                     HA_NEXT,
496
497   IMG_QUICKSAND_EMPTY,                  -1,                     HA_NEXT,
498
499   IMG_STEELWALL,                        -1,                     HA_NEXT,
500
501   IMG_WALL,                             -1,                     HA_NEXT,
502
503   IMG_EXPANDABLE_WALL_GROWING_LEFT,     20,
504   IMG_WALL,                             50,
505   IMG_EMPTY_SPACE,                      20,
506   IMG_EXPANDABLE_WALL_GROWING_RIGHT,    20,
507   IMG_WALL,                             50,
508   IMG_EMPTY_SPACE,                      20,
509   IMG_EXPANDABLE_WALL_GROWING_UP,       20,
510   IMG_WALL,                             50,
511   IMG_EMPTY_SPACE,                      20,
512   IMG_EXPANDABLE_WALL_GROWING_DOWN,     20,
513   IMG_WALL,                             50,
514   IMG_EMPTY_SPACE,                      20,                     HA_NEXT,
515
516   IMG_INVISIBLE_WALL,                   -1,                     HA_NEXT,
517
518   IMG_WALL_CRUMBLED,                    -1,                     HA_NEXT,
519
520   IMG_FONT_GAME_INFO,                   -1,                     HA_NEXT,
521
522   IMG_EMERALD,                          -1,                     HA_NEXT,
523
524   IMG_DIAMOND,                          -1,                     HA_NEXT,
525
526   IMG_BD_DIAMOND,                       -1,                     HA_NEXT,
527
528   IMG_EMERALD_YELLOW,                   50,
529   IMG_EMERALD_RED,                      50,
530   IMG_EMERALD_PURPLE,                   50,                     HA_NEXT,
531
532   IMG_BD_ROCK,                          -1,                     HA_NEXT,
533
534   IMG_BOMB,                             100,
535   IMG_EXPLOSION,                        16,
536   IMG_EMPTY_SPACE,                      10,                     HA_NEXT,
537
538   IMG_NUT,                              100,
539   IMG_NUT_BREAKING,                     6,
540   IMG_EMERALD,                          20,                     HA_NEXT,
541
542   IMG_WALL_EMERALD,                     100,
543   IMG_EXPLOSION,                        16,
544   IMG_EMERALD,                          20,                     HA_NEXT,
545
546   IMG_WALL_DIAMOND,                     100,
547   IMG_EXPLOSION,                        16,
548   IMG_DIAMOND,                          20,                     HA_NEXT,
549
550   IMG_WALL_BD_DIAMOND,                  100,
551   IMG_EXPLOSION,                        16,
552   IMG_BD_DIAMOND,                       20,                     HA_NEXT,
553
554   IMG_WALL_EMERALD_YELLOW,              100,
555   IMG_EXPLOSION,                        16,
556   IMG_EMERALD_YELLOW,                   20,
557   IMG_WALL_EMERALD_RED,                 100,
558   IMG_EXPLOSION,                        16,
559   IMG_EMERALD_RED,                      20,
560   IMG_WALL_EMERALD_PURPLE,              100,
561   IMG_EXPLOSION,                        16,
562   IMG_EMERALD_PURPLE,                   20,                     HA_NEXT,
563
564   IMG_ACID,                             -1,                     HA_NEXT,
565
566   IMG_KEY_1,                            50,
567   IMG_KEY_2,                            50,
568   IMG_KEY_3,                            50,
569   IMG_KEY_4,                            50,                     HA_NEXT,
570
571   IMG_GATE_1,                           50,
572   IMG_GATE_2,                           50,
573   IMG_GATE_3,                           50,
574   IMG_GATE_4,                           50,                     HA_NEXT,
575
576   IMG_GATE_1_GRAY,                      50,
577   IMG_GATE_2_GRAY,                      50,
578   IMG_GATE_3_GRAY,                      50,
579   IMG_GATE_4_GRAY,                      50,                     HA_NEXT,
580
581   IMG_DYNAMITE,                         -1,                     HA_NEXT,
582
583   IMG_DYNAMITE_ACTIVE,                  96,
584   IMG_EXPLOSION,                        16,
585   IMG_EMPTY_SPACE,                      20,                     HA_NEXT,
586
587   IMG_DYNABOMB_ACTIVE,                  100,
588   IMG_EXPLOSION,                        16,
589   IMG_EMPTY_SPACE,                      20,                     HA_NEXT,
590
591   IMG_DYNABOMB_INCREASE_NUMBER,         -1,                     HA_NEXT,
592
593   IMG_DYNABOMB_INCREASE_SIZE,           -1,                     HA_NEXT,
594
595   IMG_DYNABOMB_INCREASE_POWER,          -1,                     HA_NEXT,
596
597   IMG_SPACESHIP_RIGHT,                  16,
598   IMG_SPACESHIP_UP,                     16,
599   IMG_SPACESHIP_LEFT,                   16,
600   IMG_SPACESHIP_DOWN,                   16,                     HA_NEXT,
601
602   IMG_BUG_RIGHT,                        16,
603   IMG_BUG_UP,                           16,
604   IMG_BUG_LEFT,                         16,
605   IMG_BUG_DOWN,                         16,                     HA_NEXT,
606
607   IMG_BD_BUTTERFLY,                     -1,                     HA_NEXT,
608
609   IMG_BD_FIREFLY,                       -1,                     HA_NEXT,
610
611   IMG_PACMAN_RIGHT,                     16,
612   IMG_PACMAN_UP,                        16,
613   IMG_PACMAN_LEFT,                      16,
614   IMG_PACMAN_DOWN,                      16,                     HA_NEXT,
615
616   IMG_YAMYAM,                           -1,                     HA_NEXT,
617
618   IMG_DARK_YAMYAM,                      -1,                     HA_NEXT,
619
620   IMG_ROBOT,                            -1,                     HA_NEXT,
621
622   IMG_MOLE_MOVING_RIGHT,                16,
623   IMG_MOLE_MOVING_UP,                   16,
624   IMG_MOLE_MOVING_LEFT,                 16,
625   IMG_MOLE_MOVING_DOWN,                 16,                     HA_NEXT,
626
627   IMG_PENGUIN_MOVING_RIGHT,             16,
628   IMG_PENGUIN_MOVING_UP,                16,
629   IMG_PENGUIN_MOVING_LEFT,              16,
630   IMG_PENGUIN_MOVING_DOWN,              16,                     HA_NEXT,
631
632   IMG_PIG_MOVING_RIGHT,                 16,
633   IMG_PIG_MOVING_UP,                    16,
634   IMG_PIG_MOVING_LEFT,                  16,
635   IMG_PIG_MOVING_DOWN,                  16,                     HA_NEXT,
636
637   IMG_DRAGON_MOVING_RIGHT,              16,
638   IMG_DRAGON_MOVING_UP,                 16,
639   IMG_DRAGON_MOVING_LEFT,               16,
640   IMG_DRAGON_MOVING_DOWN,               16,                     HA_NEXT,
641
642   IMG_SATELLITE,                        -1,                     HA_NEXT,
643
644   IMG_ROBOT_WHEEL,                      50,
645   IMG_ROBOT_WHEEL_ACTIVE,               100,                    HA_NEXT,
646
647   IMG_LAMP,                             50,
648   IMG_LAMP_ACTIVE,                      50,                     HA_NEXT,
649
650   IMG_TIME_ORB_FULL,                    50,
651   IMG_TIME_ORB_EMPTY,                   50,                     HA_NEXT,
652
653   IMG_AMOEBA_DROP,                      50,
654   IMG_AMOEBA_GROWING,                   6,
655   IMG_AMOEBA_WET,                       20,                     HA_NEXT,
656
657   IMG_AMOEBA_DEAD,                      -1,                     HA_NEXT,
658
659   IMG_AMOEBA_WET,                       -1,                     HA_NEXT,
660
661   IMG_AMOEBA_WET,                       100,
662   IMG_AMOEBA_GROWING,                   6,                      HA_NEXT,
663
664   IMG_AMOEBA_FULL,                      50,
665   IMG_AMOEBA_DEAD,                      50,
666   IMG_EXPLOSION,                        16,
667   IMG_DIAMOND,                          20,                     HA_NEXT,
668
669   IMG_GAME_OF_LIFE,                     -1,                     HA_NEXT,
670
671   IMG_BIOMAZE,                          -1,                     HA_NEXT,
672
673   IMG_MAGIC_WALL_ACTIVE,                -1,                     HA_NEXT,
674
675   IMG_BD_MAGIC_WALL_ACTIVE,             -1,                     HA_NEXT,
676
677   IMG_EXIT_CLOSED,                      200,
678   IMG_EXIT_OPENING,                     16,
679   IMG_EXIT_OPEN,                        100,                    HA_NEXT,
680
681   IMG_EXIT_OPEN,                        -1,                     HA_NEXT,
682
683   IMG_SOKOBAN_OBJECT,                   -1,                     HA_NEXT,
684
685   IMG_SOKOBAN_FIELD_EMPTY,              -1,                     HA_NEXT,
686
687   IMG_SOKOBAN_FIELD_FULL,               -1,                     HA_NEXT,
688
689   IMG_SPEED_PILL,                       -1,                     HA_NEXT,
690
691   HA_END
692 };
693 static char *helpscreen_eltext[][2] =
694 {
695  {"THE HERO:",                          "(Is _this_ guy good old Rockford?)"},
696  {"Normal sand:",                       "You can dig through it"},
697  {"Empty field:",                       "You can walk through it"},
698  {"Quicksand: You cannot pass it,",     "but rocks can fall through it"},
699  {"Massive Wall:",                      "Nothing can go through it"},
700  {"Normal Wall: You can't go through",  "it, but you can bomb it away"},
701  {"Growing Wall: Grows in several di-", "rections if there is an empty field"},
702  {"Invisible Wall: Behaves like normal","wall, but is invisible"},
703  {"Old Wall: Like normal wall, but",    "some things can fall down from it"},
704  {"Letter Wall: Looks like a letter,",  "behaves like a normal wall"},
705  {"Emerald: You must collect enough of","them to finish a level"},
706  {"Diamond: Counts as 3 emeralds, but", "can be destroyed by rocks"},
707  {"Diamond (BD style): Counts like one","emerald and behaves a bit different"},
708  {"Colorful Gems:",                     "Seem to behave like Emeralds"},
709  {"Rock: Smashes several things;",      "Can be moved by the player"},
710  {"Bomb: You can move it, but be",      "careful when dropping it"},
711  {"Nut: Throw a rock on it to open it;","Each nut contains an emerald"},
712  {"Wall with an emerald inside:",       "Bomb the wall away to get it"},
713  {"Wall with a diamond inside:",        "Bomb the wall away to get it"},
714  {"Wall with BD style diamond inside:", "Bomb the wall away to get it"},
715  {"Wall with colorful gem inside:",     "Bomb the wall away to get it"},
716  {"Acid: Things that fall in are gone", "forever (including our hero)"},
717  {"Key: Opens the door that has the",   "same color (red/yellow/green/blue)"},
718  {"Door: Can be opened by the key",     "with the same color"},
719  {"Door: You have to find out the",     "right color of the key for it"},
720  {"Dynamite: Collect it and use it to", "destroy walls or kill enemies"},
721  {"Dynamite: This one explodes after",  "a few seconds"},
722  {"Dyna Bomb: Explodes in 4 directions","with variable explosion size"},
723  {"Dyna Bomb: Increases the number of", "dyna bombs available at a time"},
724  {"Dyna Bomb: Increases the size of",   "explosion of dyna bombs"},
725  {"Dyna Bomb: Increases the power of",  "explosion of dyna bombs"},
726  {"Spaceship: Moves at the left side",  "of walls; don't touch it!"},
727  {"Bug: Moves at the right side",       "of walls; don't touch it!"},
728  {"Butterfly: Moves at the right side", "of walls; don't touch it!"},
729  {"Firefly: Moves at the left side",    "of walls; don't touch it!"},
730  {"Pacman: Eats the amoeba and you,",   "if you're not careful"},
731  {"Cruncher: Eats diamonds and you,",   "if you're not careful"},
732  {"Cruncher (BD style):",               "Eats almost everything"},
733  {"Robot: Tries to kill the player",    ""},
734  {"The mole: Eats the amoeba and turns","empty space into normal sand"},
735  {"The penguin: Guide him to the exit,","but keep him away from monsters!"},
736  {"The Pig: Harmless, but eats all",    "gems it can get"},
737  {"The Dragon: Breathes fire,",         "especially to some monsters"},
738  {"Sonde: Follows you everywhere;",     "harmless, but may block your way"},
739  {"Magic Wheel: Touch it to get rid of","the robots for some seconds"},
740  {"Light Bulb: All of them must be",    "switched on to finish a level"},
741  {"Extra Time Orb: Adds some seconds",  "to the time available for the level"},
742  {"Amoeba Drop: Grows to an amoeba on", "the ground - don't touch it"},
743  {"Dead Amoeba: Does not grow, but",    "can still kill bugs and spaceships"},
744  {"Normal Amoeba: Grows through empty", "fields, sand and quicksand"},
745  {"Dropping Amoeba: This one makes",    "drops that grow to a new amoeba"},
746  {"Living Amoeba (BD style): Contains", "other element, when surrounded"},
747  {"Game Of Life: Behaves like the well","known 'Game Of Life' (2333 style)"},
748  {"Biomaze: A bit like the 'Game Of",   "Life', but builds crazy mazes"},
749  {"Magic Wall: Changes rocks, emeralds","and diamonds when they pass it"},
750  {"Magic Wall (BD style):",             "Changes rocks and BD style diamonds"},
751  {"Exit door: Opens if you have enough","emeralds to finish the level"},
752  {"Open exit door: Enter here to leave","the level and exit the actual game"},
753  {"Sokoban element: Object which must", "be pushed to an empty field"},
754  {"Sokoban element: Empty field where", "a Sokoban object can be placed on"},
755  {"Sokoban element: Field with object", "which can be pushed away"},
756  {"Speed pill: Lets the player run",    "twice as fast as normally"},
757 };
758 static int num_helpscreen_els = sizeof(helpscreen_eltext) / (2*sizeof(char *));
759
760 static char *helpscreen_music[][3] =
761 {
762   { "Alchemy",                  "Ian Boddy",            "Drive" },
763   { "The Chase",                "Propaganda",           "A Secret Wish" },
764   { "Network 23",               "Tangerine Dream",      "Exit" },
765   { "Czardasz",                 "Robert Pieculewicz",   "Czardasz" },
766   { "21st Century Common Man",  "Tangerine Dream",      "Tyger" },
767   { "Voyager",                  "The Alan Parsons Project","Pyramid" },
768   { "Twilight Painter",         "Tangerine Dream",      "Heartbreakers" }
769 };
770 static int num_helpscreen_music = 7;
771 static int helpscreen_musicpos;
772
773 #if 0
774 void OLD_DrawHelpScreenElAction(int start)
775 {
776   int i = 0, j = 0;
777   int frame, graphic;
778   int xstart = SX+16, ystart = SY+64+2*32, ystep = TILEY+4;
779
780   while(helpscreen_action[j] != HA_END)
781   {
782     if (i>=start+MAX_HELPSCREEN_ELS || i>=num_helpscreen_els)
783       break;
784     else if (i<start || helpscreen_delay[i-start])
785     {
786       if (i>=start && helpscreen_delay[i-start])
787         helpscreen_delay[i-start]--;
788
789       while(helpscreen_action[j] != HA_NEXT)
790         j++;
791       j++;
792       i++;
793       continue;
794     }
795
796     j += 3*helpscreen_step[i-start];
797     graphic = helpscreen_action[j++];
798
799     if (helpscreen_frame[i-start])
800     {
801       frame = helpscreen_action[j++] - helpscreen_frame[i-start];
802       helpscreen_frame[i-start]--;
803     }
804     else
805     {
806       frame = 0;
807       helpscreen_frame[i-start] = helpscreen_action[j++]-1;
808     }
809
810     helpscreen_delay[i-start] = helpscreen_action[j++] - 1;
811
812     if (helpscreen_action[j] == HA_NEXT)
813     {
814       if (!helpscreen_frame[i-start])
815         helpscreen_step[i-start] = 0;
816     }
817     else
818     {
819       if (!helpscreen_frame[i-start])
820         helpscreen_step[i-start]++;
821       while(helpscreen_action[j] != HA_NEXT)
822         j++;
823     }
824     j++;
825
826     DrawOldGraphicExt(drawto, xstart, ystart+(i-start)*ystep, graphic+frame);
827     i++;
828   }
829
830   for(i=2;i<16;i++)
831   {
832     MarkTileDirty(0,i);
833     MarkTileDirty(1,i);
834   }
835 }
836 #endif
837
838 void DrawHelpScreenElAction(int start)
839 {
840   int i = 0, j = 0;
841   int xstart = mSX + 16;
842   int ystart = mSY + 64 + 2 * 32;
843   int ystep = TILEY + 4;
844   int graphic;
845   int frame_count;
846   int sync_frame;
847
848   while (helpscreen_action[j] != HA_END)
849   {
850     if (i >= start + MAX_HELPSCREEN_ELS || i >= num_helpscreen_els)
851       break;
852     else if (i < start)
853     {
854       while (helpscreen_action[j] != HA_NEXT)
855         j++;
856
857       j++;
858       i++;
859
860       continue;
861     }
862
863     j += 2 * helpscreen_step[i-start];
864     graphic = helpscreen_action[j++];
865     frame_count = helpscreen_action[j++];
866     if (frame_count == -1)
867       frame_count = 1000000;
868
869     if (helpscreen_frame[i-start] == 0)
870     {
871       sync_frame = 0;
872       helpscreen_frame[i-start] = frame_count - 1;
873     }
874     else
875     {
876       sync_frame = frame_count - helpscreen_frame[i-start];
877       helpscreen_frame[i-start]--;
878     }
879
880     if (helpscreen_action[j] == HA_NEXT)
881     {
882       if (!helpscreen_frame[i-start])
883         helpscreen_step[i-start] = 0;
884     }
885     else
886     {
887       if (!helpscreen_frame[i-start])
888         helpscreen_step[i-start]++;
889       while(helpscreen_action[j] != HA_NEXT)
890         j++;
891     }
892     j++;
893
894 #if 1
895     ClearRectangleOnBackground(drawto, xstart, ystart + (i - start) * ystep,
896                                TILEX, TILEY);
897     DrawGraphicAnimationExt(drawto, xstart, ystart + (i - start) * ystep,
898                             graphic, sync_frame, USE_MASKING);
899 #else
900     frame = getGraphicAnimationFrame(graphic, sync_frame);
901
902     DrawGraphicExt(drawto, xstart, ystart + (i-start) * ystep,
903                    graphic, frame);
904 #endif
905
906     i++;
907   }
908
909   for(i=2; i<16; i++)
910   {
911     MarkTileDirty(0, i);
912     MarkTileDirty(1, i);
913   }
914
915   FrameCounter++;
916 }
917
918 void DrawHelpScreenElText(int start)
919 {
920   int i;
921   int xstart = mSX + 56, ystart = mSY + 65 + 2 * 32, ystep = TILEY + 4;
922   int ybottom = SYSIZE - 20;
923
924   SetMainBackgroundImage(IMG_BACKGROUND_INFO);
925   ClearWindow();
926   DrawHeadline();
927
928   DrawTextFCentered(100, FONT_TEXT_1, "The game elements:");
929
930   for(i=start; i < start + MAX_HELPSCREEN_ELS && i < num_helpscreen_els; i++)
931   {
932     DrawText(xstart,
933              ystart + (i - start) * ystep + (*helpscreen_eltext[i][1] ? 0 : 8),
934              helpscreen_eltext[i][0], FONT_TEXT_2);
935     DrawText(xstart, ystart + (i - start) * ystep + 16,
936              helpscreen_eltext[i][1], FONT_TEXT_2);
937   }
938
939   DrawTextFCentered(ybottom, FONT_TEXT_4,
940                     "Press any key or button for next page");
941 }
942
943 void DrawHelpScreenMusicText(int num)
944 {
945   int ystart = 150, ystep = 30;
946   int ybottom = SYSIZE - 20;
947
948   FadeSounds();
949   ClearWindow();
950   DrawHeadline();
951
952   DrawTextFCentered(100, FONT_TEXT_1, "The game background music loops:");
953
954   DrawTextFCentered(ystart + 0 * ystep, FONT_TEXT_2, "Excerpt from");
955   DrawTextFCentered(ystart + 1 * ystep, FONT_TEXT_3,
956                     "\"%s\"", helpscreen_music[num][0]);
957   DrawTextFCentered(ystart + 2 * ystep, FONT_TEXT_2, "by");
958   DrawTextFCentered(ystart + 3 * ystep, FONT_TEXT_3,
959                     "%s", helpscreen_music[num][1]);
960   DrawTextFCentered(ystart + 4 * ystep, FONT_TEXT_2, "from the album");
961   DrawTextFCentered(ystart + 5 * ystep, FONT_TEXT_3,
962                     "\"%s\"", helpscreen_music[num][2]);
963
964   DrawTextFCentered(ybottom, FONT_TEXT_4,
965                     "Press any key or button for next page");
966
967 #if 0
968   PlaySoundLoop(background_loop[num]);
969 #endif
970 }
971
972 void DrawHelpScreenCreditsText()
973 {
974   int ystart = 150, ystep = 30;
975   int ybottom = SYSIZE - 20;
976
977   FadeSounds();
978   ClearWindow();
979   DrawHeadline();
980
981   DrawTextFCentered(100, FONT_TEXT_1, "Credits:");
982   DrawTextFCentered(ystart + 0 * ystep, FONT_TEXT_2, "DOS port of the game:");
983   DrawTextFCentered(ystart + 1 * ystep, FONT_TEXT_3, "Guido Schulz");
984   DrawTextFCentered(ystart + 2 * ystep, FONT_TEXT_2, "Additional toons:");
985   DrawTextFCentered(ystart + 3 * ystep, FONT_TEXT_3, "Karl Hörnell");
986   DrawTextFCentered(ystart + 5 * ystep, FONT_TEXT_2,
987                     "...and many thanks to all contributors");
988   DrawTextFCentered(ystart + 6 * ystep, FONT_TEXT_2, "of new levels!");
989
990   DrawTextFCentered(ybottom, FONT_TEXT_4,
991                     "Press any key or button for next page");
992 }
993
994 void DrawHelpScreenContactText()
995 {
996   int ystart = 150, ystep = 30;
997   int ybottom = SYSIZE - 20;
998
999   ClearWindow();
1000   DrawHeadline();
1001
1002   DrawTextFCentered(100, FONT_TEXT_1, "Program information:");
1003
1004   DrawTextFCentered(ystart + 0 * ystep, FONT_TEXT_2,
1005                     "This game is Freeware!");
1006   DrawTextFCentered(ystart + 1 * ystep, FONT_TEXT_2,
1007                     "If you like it, send e-mail to:");
1008   DrawTextFCentered(ystart + 2 * ystep, FONT_TEXT_3,
1009                     "info@artsoft.org");
1010   DrawTextFCentered(ystart + 3 * ystep, FONT_TEXT_2,
1011                     "or SnailMail to:");
1012   DrawTextFCentered(ystart + 4 * ystep + 0, FONT_TEXT_3,
1013                     "Holger Schemel");
1014   DrawTextFCentered(ystart + 4 * ystep + 20, FONT_TEXT_3,
1015                     "Detmolder Strasse 189");
1016   DrawTextFCentered(ystart + 4 * ystep + 40, FONT_TEXT_3,
1017                     "33604 Bielefeld");
1018   DrawTextFCentered(ystart + 4 * ystep + 60, FONT_TEXT_3,
1019                     "Germany");
1020
1021   DrawTextFCentered(ystart + 7 * ystep, FONT_TEXT_2,
1022                     "If you have created new levels,");
1023   DrawTextFCentered(ystart + 8 * ystep, FONT_TEXT_2,
1024                     "send them to me to include them!");
1025   DrawTextFCentered(ystart + 9 * ystep, FONT_TEXT_2,
1026                     ":-)");
1027
1028   DrawTextFCentered(ybottom, FONT_TEXT_4,
1029                     "Press any key or button for main menu");
1030 }
1031
1032 void DrawHelpScreen()
1033 {
1034   int i;
1035
1036   UnmapAllGadgets();
1037   CloseDoor(DOOR_CLOSE_2);
1038
1039   for(i=0;i<MAX_HELPSCREEN_ELS;i++)
1040     helpscreen_step[i] = helpscreen_frame[i] = 0;
1041   helpscreen_musicpos = 0;
1042   helpscreen_state = 0;
1043
1044   DrawHelpScreenElText(0);
1045   DrawHelpScreenElAction(0);
1046
1047   FadeToFront();
1048   InitAnimation();
1049
1050 #if 0
1051   PlaySoundLoop(SND_BACKGROUND_INFO);
1052 #else
1053   PlaySound_Menu_Start(SND_BACKGROUND_INFO);
1054 #endif
1055 }
1056
1057 void HandleHelpScreen(int button)
1058 {
1059   static unsigned long hs_delay = 0;
1060   int num_helpscreen_els_pages =
1061     (num_helpscreen_els + MAX_HELPSCREEN_ELS-1) / MAX_HELPSCREEN_ELS;
1062   int button_released = !button;
1063   int i;
1064
1065   if (button_released)
1066   {
1067     if (helpscreen_state < num_helpscreen_els_pages - 1)
1068     {
1069       for(i=0;i<MAX_HELPSCREEN_ELS;i++)
1070         helpscreen_step[i] = helpscreen_frame[i] = 0;
1071       helpscreen_state++;
1072
1073       FrameCounter = 0;
1074       DrawHelpScreenElText(helpscreen_state * MAX_HELPSCREEN_ELS);
1075       DrawHelpScreenElAction(helpscreen_state * MAX_HELPSCREEN_ELS);
1076     }
1077     else if (helpscreen_state <
1078              num_helpscreen_els_pages + num_helpscreen_music - 1)
1079     {
1080       helpscreen_state++;
1081       DrawHelpScreenMusicText(helpscreen_state - num_helpscreen_els_pages);
1082     }
1083     else if (helpscreen_state ==
1084              num_helpscreen_els_pages + num_helpscreen_music - 1)
1085     {
1086       helpscreen_state++;
1087       DrawHelpScreenCreditsText();
1088     }
1089     else if (helpscreen_state ==
1090              num_helpscreen_els_pages + num_helpscreen_music)
1091     {
1092       helpscreen_state++;
1093       DrawHelpScreenContactText();
1094     }
1095     else
1096     {
1097       FadeSounds();
1098
1099       game_status = GAME_MODE_MAIN;
1100       DrawMainMenu();
1101     }
1102   }
1103   else
1104   {
1105     if (DelayReached(&hs_delay, GAME_FRAME_DELAY))
1106     {
1107       if (helpscreen_state < num_helpscreen_els_pages)
1108         DrawHelpScreenElAction(helpscreen_state * MAX_HELPSCREEN_ELS);
1109     }
1110
1111     /* !!! workaround for playing "music" that is really a sound loop (and
1112        must therefore periodically be reactivated with the current sound
1113        engine !!! */
1114 #if 0
1115     PlaySoundLoop(SND_BACKGROUND_INFO);
1116 #else
1117     PlaySound_Menu_Continue(SND_BACKGROUND_INFO);
1118 #endif
1119
1120     DoAnimation();
1121   }
1122
1123   BackToFront();
1124 }
1125
1126 void HandleTypeName(int newxpos, Key key)
1127 {
1128   static int xpos = 0, ypos = 2;
1129   int font_width = getFontWidth(FONT_INPUT_1_ACTIVE);
1130   int name_width = getFontWidth(FONT_MENU_1) * strlen("Name:");
1131   int startx = mSX + 32 + name_width;
1132   int starty = mSY + ypos * 32;
1133
1134   if (newxpos)
1135   {
1136     xpos = newxpos;
1137
1138     DrawText(startx, starty, setup.player_name, FONT_INPUT_1_ACTIVE);
1139     DrawText(startx + xpos * font_width, starty, "_", FONT_INPUT_1_ACTIVE);
1140
1141     return;
1142   }
1143
1144   if (((key >= KSYM_A && key <= KSYM_Z) ||
1145        (key >= KSYM_a && key <= KSYM_z)) && 
1146       xpos < MAX_PLAYER_NAME_LEN)
1147   {
1148     char ascii;
1149
1150     if (key >= KSYM_A && key <= KSYM_Z)
1151       ascii = 'A' + (char)(key - KSYM_A);
1152     else
1153       ascii = 'a' + (char)(key - KSYM_a);
1154
1155     setup.player_name[xpos] = ascii;
1156     setup.player_name[xpos + 1] = 0;
1157     xpos++;
1158
1159     DrawText(startx, starty, setup.player_name, FONT_INPUT_1_ACTIVE);
1160     DrawText(startx + xpos * font_width, starty, "_", FONT_INPUT_1_ACTIVE);
1161   }
1162   else if ((key == KSYM_Delete || key == KSYM_BackSpace) && xpos > 0)
1163   {
1164     xpos--;
1165     setup.player_name[xpos] = 0;
1166
1167     DrawText(startx + xpos * font_width, starty, "_ ", FONT_INPUT_1_ACTIVE);
1168   }
1169   else if (key == KSYM_Return && xpos > 0)
1170   {
1171     DrawText(startx, starty, setup.player_name, FONT_INPUT_1);
1172     DrawText(startx + xpos * font_width, starty, " ", FONT_INPUT_1_ACTIVE);
1173
1174     SaveSetup();
1175     game_status = GAME_MODE_MAIN;
1176   }
1177
1178   BackToFront();
1179 }
1180
1181 static void DrawChooseTree(TreeInfo **ti_ptr)
1182 {
1183   UnmapAllGadgets();
1184   CloseDoor(DOOR_CLOSE_2);
1185
1186   ClearWindow();
1187
1188   HandleChooseTree(0,0, 0,0, MB_MENU_INITIALIZE, ti_ptr);
1189   MapChooseTreeGadgets(*ti_ptr);
1190
1191   FadeToFront();
1192   InitAnimation();
1193 }
1194
1195 static void AdjustChooseTreeScrollbar(int id, int first_entry, TreeInfo *ti)
1196 {
1197   struct GadgetInfo *gi = screen_gadget[id];
1198   int items_max, items_visible, item_position;
1199
1200   items_max = numTreeInfoInGroup(ti);
1201   items_visible = NUM_MENU_ENTRIES_ON_SCREEN;
1202   item_position = first_entry;
1203
1204   if (item_position > items_max - items_visible)
1205     item_position = items_max - items_visible;
1206
1207   ModifyGadget(gi, GDI_SCROLLBAR_ITEMS_MAX, items_max,
1208                GDI_SCROLLBAR_ITEM_POSITION, item_position, GDI_END);
1209 }
1210
1211 static void drawChooseTreeList(int first_entry, int num_page_entries,
1212                                TreeInfo *ti)
1213 {
1214   int i;
1215   char buffer[SCR_FIELDX * 2];
1216   int max_buffer_len = (SCR_FIELDX - 2) * 2;
1217   char *title_string = NULL;
1218   int xoffset_setup = 16;
1219   int yoffset_setup = 16;
1220   int xoffset = (ti->type == TREE_TYPE_LEVEL_DIR ? 0 : xoffset_setup);
1221   int yoffset = (ti->type == TREE_TYPE_LEVEL_DIR ? 0 : yoffset_setup);
1222   int last_game_status = game_status;   /* save current game status */
1223
1224   DrawBackground(SX, SY, SXSIZE - 32, SYSIZE);
1225   redraw_mask |= REDRAW_FIELD;
1226
1227   title_string =
1228     (ti->type == TREE_TYPE_LEVEL_DIR ? "Level Directories" :
1229      ti->type == TREE_TYPE_GRAPHICS_DIR ? "Custom Graphics" :
1230      ti->type == TREE_TYPE_SOUNDS_DIR ? "Custom Sounds" :
1231      ti->type == TREE_TYPE_MUSIC_DIR ? "Custom Music" : "");
1232
1233   DrawText(SX + xoffset, SY + yoffset, title_string, FONT_TITLE_1);
1234
1235   /* force LEVELS font on artwork setup screen */
1236   game_status = GAME_MODE_LEVELS;
1237
1238   for(i=0; i<num_page_entries; i++)
1239   {
1240     TreeInfo *node, *node_first;
1241     int entry_pos = first_entry + i;
1242     int ypos = MENU_SCREEN_START_YPOS + i;
1243
1244     node_first = getTreeInfoFirstGroupEntry(ti);
1245     node = getTreeInfoFromPos(node_first, entry_pos);
1246
1247     strncpy(buffer, node->name , max_buffer_len);
1248     buffer[max_buffer_len] = '\0';
1249
1250     DrawText(mSX + 32, mSY + ypos * 32, buffer, FONT_TEXT_1 + node->color);
1251
1252     if (node->parent_link)
1253       initCursor(i, IMG_MENU_BUTTON_LEFT);
1254     else if (node->level_group)
1255       initCursor(i, IMG_MENU_BUTTON_RIGHT);
1256     else
1257       initCursor(i, IMG_MENU_BUTTON);
1258   }
1259
1260   game_status = last_game_status;       /* restore current game status */
1261 }
1262
1263 static void drawChooseTreeInfo(int entry_pos, TreeInfo *ti)
1264 {
1265   TreeInfo *node, *node_first;
1266   int x, last_redraw_mask = redraw_mask;
1267
1268   if (ti->type != TREE_TYPE_LEVEL_DIR)
1269     return;
1270
1271   node_first = getTreeInfoFirstGroupEntry(ti);
1272   node = getTreeInfoFromPos(node_first, entry_pos);
1273
1274   DrawBackground(SX + 32, SY + 32, SXSIZE - 64, 32);
1275
1276   if (node->parent_link)
1277     DrawTextFCentered(40, FONT_TITLE_2, "leave group \"%s\"",
1278                       node->class_desc);
1279   else if (node->level_group)
1280     DrawTextFCentered(40, FONT_TITLE_2, "enter group \"%s\"",
1281                       node->class_desc);
1282   else if (ti->type == TREE_TYPE_LEVEL_DIR)
1283     DrawTextFCentered(40, FONT_TITLE_2, "%3d levels (%s)",
1284                       node->levels, node->class_desc);
1285
1286   /* let BackToFront() redraw only what is needed */
1287   redraw_mask = last_redraw_mask | REDRAW_TILES;
1288   for (x=0; x<SCR_FIELDX; x++)
1289     MarkTileDirty(x, 1);
1290 }
1291
1292 static void HandleChooseTree(int mx, int my, int dx, int dy, int button,
1293                              TreeInfo **ti_ptr)
1294 {
1295   TreeInfo *ti = *ti_ptr;
1296   int x = 0;
1297   int y = ti->cl_cursor;
1298   int step = (button == 1 ? 1 : button == 2 ? 5 : 10);
1299   int num_entries = numTreeInfoInGroup(ti);
1300   int num_page_entries;
1301
1302   if (num_entries <= NUM_MENU_ENTRIES_ON_SCREEN)
1303     num_page_entries = num_entries;
1304   else
1305     num_page_entries = NUM_MENU_ENTRIES_ON_SCREEN;
1306
1307   if (button == MB_MENU_INITIALIZE)
1308   {
1309     int entry_pos = posTreeInfo(ti);
1310
1311     if (ti->cl_first == -1)
1312     {
1313       ti->cl_first = MAX(0, entry_pos - num_page_entries + 1);
1314       ti->cl_cursor =
1315         entry_pos - ti->cl_first;
1316     }
1317
1318     if (dx == 999)      /* first entry is set by scrollbar position */
1319       ti->cl_first = dy;
1320     else
1321       AdjustChooseTreeScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL,
1322                                 ti->cl_first, ti);
1323
1324     drawChooseTreeList(ti->cl_first, num_page_entries, ti);
1325     drawChooseTreeInfo(ti->cl_first + ti->cl_cursor, ti);
1326     drawCursor(ti->cl_cursor, FC_RED);
1327     return;
1328   }
1329   else if (button == MB_MENU_LEAVE)
1330   {
1331     if (ti->node_parent)
1332     {
1333       *ti_ptr = ti->node_parent;
1334       DrawChooseTree(ti_ptr);
1335     }
1336     else if (game_status == GAME_MODE_SETUP)
1337     {
1338       execSetupArtwork();
1339     }
1340     else
1341     {
1342       game_status = GAME_MODE_MAIN;
1343       DrawMainMenu();
1344     }
1345
1346     return;
1347   }
1348
1349   if (mx || my)         /* mouse input */
1350   {
1351     x = (mx - mSX) / 32;
1352     y = (my - mSY) / 32 - MENU_SCREEN_START_YPOS;
1353   }
1354   else if (dx || dy)    /* keyboard or scrollbar/scrollbutton input */
1355   {
1356     /* move cursor instead of scrolling when already at start/end of list */
1357     if (dy == -1 * SCROLL_LINE && ti->cl_first == 0)
1358       dy = -1;
1359     else if (dy == +1 * SCROLL_LINE &&
1360              ti->cl_first + num_page_entries == num_entries)
1361       dy = 1;
1362
1363     /* handle scrolling screen one line or page */
1364     if (ti->cl_cursor + dy < 0 ||
1365         ti->cl_cursor + dy > num_page_entries - 1)
1366     {
1367       if (ABS(dy) == SCROLL_PAGE)
1368         step = num_page_entries - 1;
1369
1370       if (dy < 0 && ti->cl_first > 0)
1371       {
1372         /* scroll page/line up */
1373
1374         ti->cl_first -= step;
1375         if (ti->cl_first < 0)
1376           ti->cl_first = 0;
1377
1378         drawChooseTreeList(ti->cl_first, num_page_entries, ti);
1379         drawChooseTreeInfo(ti->cl_first + ti->cl_cursor, ti);
1380         drawCursor(ti->cl_cursor, FC_RED);
1381         AdjustChooseTreeScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL,
1382                                   ti->cl_first, ti);
1383       }
1384       else if (dy > 0 && ti->cl_first + num_page_entries < num_entries)
1385       {
1386         /* scroll page/line down */
1387
1388         ti->cl_first += step;
1389         if (ti->cl_first + num_page_entries > num_entries)
1390           ti->cl_first = MAX(0, num_entries - num_page_entries);
1391
1392         drawChooseTreeList(ti->cl_first, num_page_entries, ti);
1393         drawChooseTreeInfo(ti->cl_first + ti->cl_cursor, ti);
1394         drawCursor(ti->cl_cursor, FC_RED);
1395         AdjustChooseTreeScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL,
1396                                   ti->cl_first, ti);
1397       }
1398
1399       return;
1400     }
1401
1402     /* handle moving cursor one line */
1403     y = ti->cl_cursor + dy;
1404   }
1405
1406   if (dx == 1)
1407   {
1408     TreeInfo *node_first, *node_cursor;
1409     int entry_pos = ti->cl_first + y;
1410
1411     node_first = getTreeInfoFirstGroupEntry(ti);
1412     node_cursor = getTreeInfoFromPos(node_first, entry_pos);
1413
1414     if (node_cursor->node_group)
1415     {
1416       node_cursor->cl_first = ti->cl_first;
1417       node_cursor->cl_cursor = ti->cl_cursor;
1418       *ti_ptr = node_cursor->node_group;
1419       DrawChooseTree(ti_ptr);
1420       return;
1421     }
1422   }
1423   else if (dx == -1 && ti->node_parent)
1424   {
1425     *ti_ptr = ti->node_parent;
1426     DrawChooseTree(ti_ptr);
1427     return;
1428   }
1429
1430   if (x == 0 && y >= 0 && y < num_page_entries)
1431   {
1432     if (button)
1433     {
1434       if (y != ti->cl_cursor)
1435       {
1436         drawCursor(y, FC_RED);
1437         drawCursor(ti->cl_cursor, FC_BLUE);
1438         drawChooseTreeInfo(ti->cl_first + y, ti);
1439         ti->cl_cursor = y;
1440       }
1441     }
1442     else
1443     {
1444       TreeInfo *node_first, *node_cursor;
1445       int entry_pos = ti->cl_first + y;
1446
1447       node_first = getTreeInfoFirstGroupEntry(ti);
1448       node_cursor = getTreeInfoFromPos(node_first, entry_pos);
1449
1450       if (node_cursor->node_group)
1451       {
1452         node_cursor->cl_first = ti->cl_first;
1453         node_cursor->cl_cursor = ti->cl_cursor;
1454         *ti_ptr = node_cursor->node_group;
1455         DrawChooseTree(ti_ptr);
1456       }
1457       else if (node_cursor->parent_link)
1458       {
1459         *ti_ptr = node_cursor->node_parent;
1460         DrawChooseTree(ti_ptr);
1461       }
1462       else
1463       {
1464         node_cursor->cl_first = ti->cl_first;
1465         node_cursor->cl_cursor = ti->cl_cursor;
1466         *ti_ptr = node_cursor;
1467
1468         if (ti->type == TREE_TYPE_LEVEL_DIR)
1469         {
1470           LoadLevelSetup_SeriesInfo();
1471
1472           SaveLevelSetup_LastSeries();
1473           SaveLevelSetup_SeriesInfo();
1474           TapeErase();
1475         }
1476
1477         if (game_status == GAME_MODE_SETUP)
1478         {
1479           execSetupArtwork();
1480         }
1481         else
1482         {
1483           game_status = GAME_MODE_MAIN;
1484           DrawMainMenu();
1485         }
1486       }
1487     }
1488   }
1489
1490   BackToFront();
1491
1492   if (game_status == GAME_MODE_LEVELS || game_status == GAME_MODE_SETUP)
1493     DoAnimation();
1494 }
1495
1496 void DrawChooseLevel()
1497 {
1498   SetMainBackgroundImage(IMG_BACKGROUND_LEVELS);
1499
1500   DrawChooseTree(&leveldir_current);
1501 }
1502
1503 void HandleChooseLevel(int mx, int my, int dx, int dy, int button)
1504 {
1505   HandleChooseTree(mx, my, dx, dy, button, &leveldir_current);
1506 }
1507
1508 void DrawHallOfFame(int highlight_position)
1509 {
1510   UnmapAllGadgets();
1511   FadeSounds();
1512   CloseDoor(DOOR_CLOSE_2);
1513
1514   if (highlight_position < 0) 
1515     LoadScore(level_nr);
1516
1517   FadeToFront();
1518   InitAnimation();
1519
1520   HandleHallOfFame(highlight_position,0, 0,0, MB_MENU_INITIALIZE);
1521
1522 #if 0
1523   PlaySound(SND_BACKGROUND_SCORES);
1524 #else
1525   PlaySound_Menu_Start(SND_BACKGROUND_SCORES);
1526 #endif
1527 }
1528
1529 static void drawHallOfFameList(int first_entry, int highlight_position)
1530 {
1531   int i;
1532
1533   SetMainBackgroundImage(IMG_BACKGROUND_SCORES);
1534   ClearWindow();
1535
1536   DrawText(mSX + 80, mSY + 8, "Hall Of Fame", FONT_TITLE_1);
1537   DrawTextFCentered(46, FONT_TITLE_2, "HighScores of Level %d", level_nr);
1538
1539   for(i=0; i<NUM_MENU_ENTRIES_ON_SCREEN; i++)
1540   {
1541     int entry = first_entry + i;
1542     boolean active = (entry == highlight_position);
1543     int font_nr1 = (active ? FONT_TEXT_1_ACTIVE : FONT_TEXT_1);
1544     int font_nr2 = (active ? FONT_TEXT_2_ACTIVE : FONT_TEXT_2);
1545     int font_nr3 = (active ? FONT_TEXT_3_ACTIVE : FONT_TEXT_3);
1546     int font_nr4 = (active ? FONT_TEXT_4_ACTIVE : FONT_TEXT_4);
1547     int dx1 = 3 * getFontWidth(font_nr1);
1548     int dx2 = dx1 + getFontWidth(font_nr1);
1549     int dx3 = dx2 + 25 * getFontWidth(font_nr3);
1550     int sy = mSY + 64 + i * 32;
1551
1552     DrawText(mSX, sy, int2str(entry + 1, 3), font_nr1);
1553     DrawText(mSX + dx1, sy, ".", font_nr1);
1554     DrawText(mSX + dx2, sy, ".........................", font_nr3);
1555     if (strcmp(highscore[entry].Name, EMPTY_PLAYER_NAME) != 0)
1556       DrawText(mSX + dx2, sy, highscore[entry].Name, font_nr2);
1557     DrawText(mSX + dx3, sy, int2str(highscore[entry].Score, 5), font_nr4);
1558   }
1559 }
1560
1561 void HandleHallOfFame(int mx, int my, int dx, int dy, int button)
1562 {
1563   static int first_entry = 0;
1564   static int highlight_position = 0;
1565   int step = (button == 1 ? 1 : button == 2 ? 5 : 10);
1566   int button_released = !button;
1567
1568   if (button == MB_MENU_INITIALIZE)
1569   {
1570     first_entry = 0;
1571     highlight_position = mx;
1572     drawHallOfFameList(first_entry, highlight_position);
1573     return;
1574   }
1575
1576   if (ABS(dy) == SCROLL_PAGE)           /* handle scrolling one page */
1577     step = NUM_MENU_ENTRIES_ON_SCREEN - 1;
1578
1579   if (dy < 0)
1580   {
1581     if (first_entry > 0)
1582     {
1583       first_entry -= step;
1584       if (first_entry < 0)
1585         first_entry = 0;
1586
1587       drawHallOfFameList(first_entry, highlight_position);
1588       return;
1589     }
1590   }
1591   else if (dy > 0)
1592   {
1593     if (first_entry + NUM_MENU_ENTRIES_ON_SCREEN < MAX_SCORE_ENTRIES)
1594     {
1595       first_entry += step;
1596       if (first_entry + NUM_MENU_ENTRIES_ON_SCREEN > MAX_SCORE_ENTRIES)
1597         first_entry = MAX(0, MAX_SCORE_ENTRIES - NUM_MENU_ENTRIES_ON_SCREEN);
1598
1599       drawHallOfFameList(first_entry, highlight_position);
1600       return;
1601     }
1602   }
1603
1604   if (button_released)
1605   {
1606     FadeSound(SND_BACKGROUND_SCORES);
1607     game_status = GAME_MODE_MAIN;
1608     DrawMainMenu();
1609   }
1610
1611   BackToFront();
1612
1613   if (game_status == GAME_MODE_SCORES)
1614   {
1615     DoAnimation();
1616 #if 1
1617     PlaySound_Menu_Continue(SND_BACKGROUND_SCORES);
1618 #endif
1619   }
1620 }
1621
1622
1623 /* ========================================================================= */
1624 /* setup screen functions                                                    */
1625 /* ========================================================================= */
1626
1627 static struct TokenInfo *setup_info;
1628 static int num_setup_info;
1629
1630 static char *graphics_set_name;
1631 static char *sounds_set_name;
1632 static char *music_set_name;
1633
1634 static void execSetupMain()
1635 {
1636   setup_mode = SETUP_MODE_MAIN;
1637   DrawSetupScreen();
1638 }
1639
1640 static void execSetupGame()
1641 {
1642   setup_mode = SETUP_MODE_GAME;
1643   DrawSetupScreen();
1644 }
1645
1646 static void execSetupEditor()
1647 {
1648   setup_mode = SETUP_MODE_EDITOR;
1649   DrawSetupScreen();
1650 }
1651
1652 static void execSetupGraphics()
1653 {
1654   setup_mode = SETUP_MODE_GRAPHICS;
1655   DrawSetupScreen();
1656 }
1657
1658 static void execSetupSound()
1659 {
1660   setup_mode = SETUP_MODE_SOUND;
1661   DrawSetupScreen();
1662 }
1663
1664 static void execSetupArtwork()
1665 {
1666   /* needed if last screen (setup choice) changed graphics, sounds or music */
1667   ReloadCustomArtwork();
1668
1669   setup.graphics_set = artwork.gfx_current->identifier;
1670   setup.sounds_set = artwork.snd_current->identifier;
1671   setup.music_set = artwork.mus_current->identifier;
1672
1673   /* needed for displaying artwork name instead of artwork identifier */
1674   graphics_set_name = artwork.gfx_current->name;
1675   sounds_set_name = artwork.snd_current->name;
1676   music_set_name = artwork.mus_current->name;
1677
1678   setup_mode = SETUP_MODE_ARTWORK;
1679   DrawSetupScreen();
1680 }
1681
1682 static void execSetupChooseGraphics()
1683 {
1684   setup_mode = SETUP_MODE_CHOOSE_GRAPHICS;
1685   DrawSetupScreen();
1686 }
1687
1688 static void execSetupChooseSounds()
1689 {
1690   setup_mode = SETUP_MODE_CHOOSE_SOUNDS;
1691   DrawSetupScreen();
1692 }
1693
1694 static void execSetupChooseMusic()
1695 {
1696   setup_mode = SETUP_MODE_CHOOSE_MUSIC;
1697   DrawSetupScreen();
1698 }
1699
1700 static void execSetupInput()
1701 {
1702   setup_mode = SETUP_MODE_INPUT;
1703   DrawSetupScreen();
1704 }
1705
1706 static void execSetupShortcut()
1707 {
1708   setup_mode = SETUP_MODE_SHORTCUT;
1709   DrawSetupScreen();
1710 }
1711
1712 static void execExitSetup()
1713 {
1714   game_status = GAME_MODE_MAIN;
1715   DrawMainMenu();
1716 }
1717
1718 static void execSaveAndExitSetup()
1719 {
1720   SaveSetup();
1721   execExitSetup();
1722 }
1723
1724 static struct TokenInfo setup_info_main[] =
1725 {
1726   { TYPE_ENTER_MENU,    execSetupGame,          "Game Settings"         },
1727   { TYPE_ENTER_MENU,    execSetupEditor,        "Editor Settings"       },
1728   { TYPE_ENTER_MENU,    execSetupGraphics,      "Graphics"              },
1729   { TYPE_ENTER_MENU,    execSetupSound,         "Sound & Music"         },
1730   { TYPE_ENTER_MENU,    execSetupArtwork,       "Custom Artwork"        },
1731   { TYPE_ENTER_MENU,    execSetupInput,         "Input Devices"         },
1732   { TYPE_ENTER_MENU,    execSetupShortcut,      "Key Shortcuts"         },
1733   { TYPE_EMPTY,         NULL,                   ""                      },
1734   { TYPE_LEAVE_MENU,    execExitSetup,          "Exit"                  },
1735   { TYPE_LEAVE_MENU,    execSaveAndExitSetup,   "Save and Exit"         },
1736   { 0,                  NULL,                   NULL                    }
1737 };
1738
1739 static struct TokenInfo setup_info_game[] =
1740 {
1741   { TYPE_SWITCH,        &setup.team_mode,       "Team-Mode:"            },
1742   { TYPE_SWITCH,        &setup.handicap,        "Handicap:"             },
1743   { TYPE_SWITCH,        &setup.time_limit,      "Timelimit:"            },
1744   { TYPE_SWITCH,        &setup.autorecord,      "Auto-Record:"          },
1745   { TYPE_EMPTY,         NULL,                   ""                      },
1746   { TYPE_LEAVE_MENU,    execSetupMain,          "Back"                  },
1747   { 0,                  NULL,                   NULL                    }
1748 };
1749
1750 static struct TokenInfo setup_info_editor[] =
1751 {
1752   { TYPE_STRING,        NULL,                   "Offer Special Elements:"},
1753   { TYPE_SWITCH,        &setup.editor.el_boulderdash,   "BoulderDash:"  },
1754   { TYPE_SWITCH,        &setup.editor.el_emerald_mine,  "Emerald Mine:" },
1755   { TYPE_SWITCH,        &setup.editor.el_more,          "More:"         },
1756   { TYPE_SWITCH,        &setup.editor.el_sokoban,       "Sokoban:"      },
1757   { TYPE_SWITCH,        &setup.editor.el_supaplex,      "Supaplex:"     },
1758   { TYPE_SWITCH,        &setup.editor.el_diamond_caves, "Diamd. Caves:" },
1759   { TYPE_SWITCH,        &setup.editor.el_dx_boulderdash,"DX Boulderd.:" },
1760   { TYPE_SWITCH,        &setup.editor.el_chars,         "Characters:"   },
1761   { TYPE_SWITCH,        &setup.editor.el_custom,        "Custom:"       },
1762   { TYPE_EMPTY,         NULL,                   ""                      },
1763   { TYPE_LEAVE_MENU,    execSetupMain,          "Back"                  },
1764   { 0,                  NULL,                   NULL                    }
1765 };
1766
1767 static struct TokenInfo setup_info_graphics[] =
1768 {
1769   { TYPE_SWITCH,        &setup.fullscreen,      "Fullscreen:"           },
1770   { TYPE_SWITCH,        &setup.scroll_delay,    "Scroll Delay:"         },
1771   { TYPE_SWITCH,        &setup.soft_scrolling,  "Soft Scroll.:"         },
1772 #if 0
1773   { TYPE_SWITCH,        &setup.double_buffering,"Buffered gfx:"         },
1774   { TYPE_SWITCH,        &setup.fading,          "Fading:"               },
1775 #endif
1776   { TYPE_SWITCH,        &setup.quick_doors,     "Quick Doors:"          },
1777   { TYPE_SWITCH,        &setup.toons,           "Toons:"                },
1778   { TYPE_EMPTY,         NULL,                   ""                      },
1779   { TYPE_LEAVE_MENU,    execSetupMain,          "Back"                  },
1780   { 0,                  NULL,                   NULL                    }
1781 };
1782
1783 static struct TokenInfo setup_info_sound[] =
1784 {
1785   { TYPE_SWITCH,        &setup.sound,           "Sound:",               },
1786   { TYPE_EMPTY,         NULL,                   ""                      },
1787   { TYPE_SWITCH,        &setup.sound_simple,    "Simple Sound:"         },
1788   { TYPE_SWITCH,        &setup.sound_loops,     "Sound Loops:"          },
1789   { TYPE_SWITCH,        &setup.sound_music,     "Game Music:"           },
1790   { TYPE_EMPTY,         NULL,                   ""                      },
1791   { TYPE_LEAVE_MENU,    execSetupMain,          "Back"                  },
1792   { 0,                  NULL,                   NULL                    }
1793 };
1794
1795 static struct TokenInfo setup_info_artwork[] =
1796 {
1797   { TYPE_ENTER_MENU,    execSetupChooseGraphics,"Custom Graphics"       },
1798   { TYPE_STRING,        &graphics_set_name,     ""                      },
1799   { TYPE_ENTER_MENU,    execSetupChooseSounds,  "Custom Sounds"         },
1800   { TYPE_STRING,        &sounds_set_name,       ""                      },
1801   { TYPE_ENTER_MENU,    execSetupChooseMusic,   "Custom Music"          },
1802   { TYPE_STRING,        &music_set_name,        ""                      },
1803   { TYPE_EMPTY,         NULL,                   ""                      },
1804   { TYPE_STRING,        NULL,                   "Override Level Artwork:"},
1805   { TYPE_YES_NO,        &setup.override_level_graphics, "Graphics:"     },
1806   { TYPE_YES_NO,        &setup.override_level_sounds,   "Sounds:"       },
1807   { TYPE_YES_NO,        &setup.override_level_music,    "Music:"        },
1808   { TYPE_EMPTY,         NULL,                   ""                      },
1809   { TYPE_LEAVE_MENU,    execSetupMain,          "Back"                  },
1810   { 0,                  NULL,                   NULL                    }
1811 };
1812
1813 static struct TokenInfo setup_info_shortcut[] =
1814 {
1815   { TYPE_KEYTEXT,       NULL,                   "Quick Save Game:",     },
1816   { TYPE_KEY,           &setup.shortcut.save_game,      ""              },
1817   { TYPE_KEYTEXT,       NULL,                   "Quick Load Game:",     },
1818   { TYPE_KEY,           &setup.shortcut.load_game,      ""              },
1819   { TYPE_KEYTEXT,       NULL,                   "Toggle Pause:",        },
1820   { TYPE_KEY,           &setup.shortcut.toggle_pause,   ""              },
1821   { TYPE_EMPTY,         NULL,                   ""                      },
1822   { TYPE_YES_NO,        &setup.ask_on_escape,   "Ask on Esc:"           },
1823   { TYPE_EMPTY,         NULL,                   ""                      },
1824   { TYPE_LEAVE_MENU,    execSetupMain,          "Back"                  },
1825   { 0,                  NULL,                   NULL                    }
1826 };
1827
1828 static Key getSetupKey()
1829 {
1830   Key key = KSYM_UNDEFINED;
1831   boolean got_key_event = FALSE;
1832
1833   while (!got_key_event)
1834   {
1835     if (PendingEvent())         /* got event */
1836     {
1837       Event event;
1838
1839       NextEvent(&event);
1840
1841       switch(event.type)
1842       {
1843         case EVENT_KEYPRESS:
1844           {
1845             key = GetEventKey((KeyEvent *)&event, TRUE);
1846
1847             /* press 'Escape' or 'Enter' to keep the existing key binding */
1848             if (key == KSYM_Escape || key == KSYM_Return)
1849               key = KSYM_UNDEFINED;     /* keep old value */
1850
1851             got_key_event = TRUE;
1852           }
1853           break;
1854
1855         case EVENT_KEYRELEASE:
1856           key_joystick_mapping = 0;
1857           break;
1858
1859         default:
1860           HandleOtherEvents(&event);
1861           break;
1862       }
1863     }
1864
1865     BackToFront();
1866     DoAnimation();
1867
1868     /* don't eat all CPU time */
1869     Delay(10);
1870   }
1871
1872   return key;
1873 }
1874
1875 static void drawSetupValue(int pos)
1876 {
1877   int xpos = MENU_SCREEN_VALUE_XPOS;
1878   int ypos = MENU_SCREEN_START_YPOS + pos;
1879   int font_nr = FONT_VALUE_1;
1880   char *value_string = getSetupValue(setup_info[pos].type & ~TYPE_GHOSTED,
1881                                      setup_info[pos].value);
1882
1883   if (value_string == NULL)
1884     return;
1885
1886   if (setup_info[pos].type & TYPE_KEY)
1887   {
1888     xpos = 3;
1889
1890     if (setup_info[pos].type & TYPE_QUERY)
1891     {
1892       value_string = "<press key>";
1893       font_nr = FONT_INPUT_1_ACTIVE;
1894     }
1895   }
1896   else if (setup_info[pos].type & TYPE_STRING)
1897   {
1898     int max_value_len = (SCR_FIELDX - 2) * 2;
1899
1900     xpos = 1;
1901     font_nr = FONT_VALUE_2;
1902
1903     if (strlen(value_string) > max_value_len)
1904       value_string[max_value_len] = '\0';
1905   }
1906   else if (setup_info[pos].type & TYPE_BOOLEAN_STYLE)
1907   {
1908     font_nr = (*(boolean *)(setup_info[pos].value) ? FONT_OPTION_ON :
1909                FONT_OPTION_OFF);
1910   }
1911
1912   DrawText(mSX + xpos * 32, mSY + ypos * 32,
1913            (xpos == 3 ? "              " : "   "), font_nr);
1914   DrawText(mSX + xpos * 32, mSY + ypos * 32, value_string, font_nr);
1915 }
1916
1917 static void changeSetupValue(int pos)
1918 {
1919   if (setup_info[pos].type & TYPE_BOOLEAN_STYLE)
1920   {
1921     *(boolean *)setup_info[pos].value ^= TRUE;
1922   }
1923   else if (setup_info[pos].type & TYPE_KEY)
1924   {
1925     Key key;
1926
1927     setup_info[pos].type |= TYPE_QUERY;
1928     drawSetupValue(pos);
1929     setup_info[pos].type &= ~TYPE_QUERY;
1930
1931     key = getSetupKey();
1932     if (key != KSYM_UNDEFINED)
1933       *(Key *)setup_info[pos].value = key;
1934   }
1935
1936   drawSetupValue(pos);
1937 }
1938
1939 static void DrawSetupScreen_Generic()
1940 {
1941   char *title_string = NULL;
1942   int i;
1943
1944   UnmapAllGadgets();
1945   CloseDoor(DOOR_CLOSE_2);
1946
1947   ClearWindow();
1948
1949   if (setup_mode == SETUP_MODE_MAIN)
1950   {
1951     setup_info = setup_info_main;
1952     title_string = "Setup";
1953   }
1954   else if (setup_mode == SETUP_MODE_GAME)
1955   {
1956     setup_info = setup_info_game;
1957     title_string = "Setup Game";
1958   }
1959   else if (setup_mode == SETUP_MODE_EDITOR)
1960   {
1961     setup_info = setup_info_editor;
1962     title_string = "Setup Editor";
1963   }
1964   else if (setup_mode == SETUP_MODE_GRAPHICS)
1965   {
1966     setup_info = setup_info_graphics;
1967     title_string = "Setup Graphics";
1968   }
1969   else if (setup_mode == SETUP_MODE_SOUND)
1970   {
1971     setup_info = setup_info_sound;
1972     title_string = "Setup Sound";
1973   }
1974   else if (setup_mode == SETUP_MODE_ARTWORK)
1975   {
1976     setup_info = setup_info_artwork;
1977     title_string = "Custom Artwork";
1978   }
1979   else if (setup_mode == SETUP_MODE_SHORTCUT)
1980   {
1981     setup_info = setup_info_shortcut;
1982     title_string = "Setup Shortcuts";
1983   }
1984
1985   DrawText(mSX + 16, mSY + 16, title_string, FONT_TITLE_1);
1986
1987   num_setup_info = 0;
1988   for(i=0; setup_info[i].type != 0 && i < NUM_MENU_ENTRIES_ON_SCREEN; i++)
1989   {
1990     void *value_ptr = setup_info[i].value;
1991     int ypos = MENU_SCREEN_START_YPOS + i;
1992     int font_nr = FONT_MENU_1;
1993
1994     /* set some entries to "unchangeable" according to other variables */
1995     if ((value_ptr == &setup.sound       && !audio.sound_available) ||
1996         (value_ptr == &setup.sound_loops && !audio.loops_available) ||
1997         (value_ptr == &setup.sound_music && !audio.music_available) ||
1998         (value_ptr == &setup.fullscreen  && !video.fullscreen_available))
1999       setup_info[i].type |= TYPE_GHOSTED;
2000
2001     if (setup_info[i].type & TYPE_STRING)
2002       font_nr = FONT_MENU_2;
2003
2004     DrawText(mSX + 32, mSY + ypos * 32, setup_info[i].text, font_nr);
2005
2006     if (setup_info[i].type & TYPE_ENTER_MENU)
2007       initCursor(i, IMG_MENU_BUTTON_RIGHT);
2008     else if (setup_info[i].type & TYPE_LEAVE_MENU)
2009       initCursor(i, IMG_MENU_BUTTON_LEFT);
2010     else if (setup_info[i].type & ~TYPE_SKIP_ENTRY)
2011       initCursor(i, IMG_MENU_BUTTON);
2012
2013     if (setup_info[i].type & TYPE_VALUE)
2014       drawSetupValue(i);
2015
2016     num_setup_info++;
2017   }
2018
2019   FadeToFront();
2020   InitAnimation();
2021   HandleSetupScreen_Generic(0,0,0,0,MB_MENU_INITIALIZE);
2022 }
2023
2024 void HandleSetupScreen_Generic(int mx, int my, int dx, int dy, int button)
2025 {
2026   static int choice_store[MAX_SETUP_MODES];
2027   int choice = choice_store[setup_mode];        /* always starts with 0 */
2028   int x = 0;
2029   int y = choice;
2030
2031   if (button == MB_MENU_INITIALIZE)
2032   {
2033     /* advance to first valid menu entry */
2034     while (choice < num_setup_info &&
2035            (setup_info[choice].type & TYPE_SKIP_ENTRY))
2036       choice++;
2037     choice_store[setup_mode] = choice;
2038
2039     drawCursor(choice, FC_RED);
2040     return;
2041   }
2042   else if (button == MB_MENU_LEAVE)
2043   {
2044     for (y=0; y<num_setup_info; y++)
2045     {
2046       if (setup_info[y].type & TYPE_LEAVE_MENU)
2047       {
2048         void (*menu_callback_function)(void) = setup_info[y].value;
2049
2050         menu_callback_function();
2051         break;  /* absolutely needed because function changes 'setup_info'! */
2052       }
2053     }
2054
2055     return;
2056   }
2057
2058   if (mx || my)         /* mouse input */
2059   {
2060     x = (mx - mSX) / 32;
2061     y = (my - mSY) / 32 - MENU_SCREEN_START_YPOS;
2062   }
2063   else if (dx || dy)    /* keyboard input */
2064   {
2065     if (dx)
2066     {
2067       int menu_navigation_type = (dx < 0 ? TYPE_LEAVE_MENU : TYPE_ENTER_MENU);
2068
2069       if ((setup_info[choice].type & menu_navigation_type) ||
2070           (setup_info[choice].type & TYPE_BOOLEAN_STYLE))
2071         button = MB_MENU_CHOICE;
2072     }
2073     else if (dy)
2074       y = choice + dy;
2075
2076     /* jump to next non-empty menu entry (up or down) */
2077     while (y > 0 && y < num_setup_info - 1 &&
2078            (setup_info[y].type & TYPE_SKIP_ENTRY))
2079       y += dy;
2080   }
2081
2082   if (x == 0 && y >= 0 && y < num_setup_info &&
2083       (setup_info[y].type & ~TYPE_SKIP_ENTRY))
2084   {
2085     if (button)
2086     {
2087       if (y != choice)
2088       {
2089         drawCursor(y, FC_RED);
2090         drawCursor(choice, FC_BLUE);
2091         choice = choice_store[setup_mode] = y;
2092       }
2093     }
2094     else if (!(setup_info[y].type & TYPE_GHOSTED))
2095     {
2096       if (setup_info[y].type & TYPE_ENTER_OR_LEAVE_MENU)
2097       {
2098         void (*menu_callback_function)(void) = setup_info[choice].value;
2099
2100         menu_callback_function();
2101       }
2102       else
2103       {
2104         if ((setup_info[y].type & TYPE_KEYTEXT) &&
2105             (setup_info[y + 1].type & TYPE_KEY))
2106           y++;
2107
2108         if (setup_info[y].type & TYPE_VALUE)
2109           changeSetupValue(y);
2110       }
2111     }
2112   }
2113
2114   BackToFront();
2115
2116   if (game_status == GAME_MODE_SETUP)
2117     DoAnimation();
2118 }
2119
2120 void DrawSetupScreen_Input()
2121 {
2122   ClearWindow();
2123
2124   DrawText(mSX+16, mSY+16, "Setup Input", FONT_TITLE_1);
2125
2126   initCursor(0, IMG_MENU_BUTTON);
2127   initCursor(1, IMG_MENU_BUTTON);
2128   initCursor(2, IMG_MENU_BUTTON_RIGHT);
2129   initCursor(13, IMG_MENU_BUTTON_LEFT);
2130
2131   drawCursorXY(10, 0, IMG_MENU_BUTTON_LEFT);
2132   drawCursorXY(12, 0, IMG_MENU_BUTTON_RIGHT);
2133
2134   DrawText(mSX+32, mSY+2*32, "Player:", FONT_MENU_1);
2135   DrawText(mSX+32, mSY+3*32, "Device:", FONT_MENU_1);
2136   DrawText(mSX+32, mSY+15*32, "Back",   FONT_MENU_1);
2137
2138 #if 0
2139   DeactivateJoystickForCalibration();
2140   DrawTextFCentered(SYSIZE - 20, FONT_TEXT_4,
2141                     "Joysticks deactivated on this screen");
2142 #endif
2143
2144   HandleSetupScreen_Input(0,0, 0,0, MB_MENU_INITIALIZE);
2145   FadeToFront();
2146   InitAnimation();
2147 }
2148
2149 static void setJoystickDeviceToNr(char *device_name, int device_nr)
2150 {
2151   if (device_name == NULL)
2152     return;
2153
2154   if (device_nr < 0 || device_nr >= MAX_PLAYERS)
2155     device_nr = 0;
2156
2157   if (strlen(device_name) > 1)
2158   {
2159     char c1 = device_name[strlen(device_name) - 1];
2160     char c2 = device_name[strlen(device_name) - 2];
2161
2162     if (c1 >= '0' && c1 <= '9' && !(c2 >= '0' && c2 <= '9'))
2163       device_name[strlen(device_name) - 1] = '0' + (char)(device_nr % 10);
2164   }
2165   else
2166     strncpy(device_name, getDeviceNameFromJoystickNr(device_nr),
2167             strlen(device_name));
2168 }
2169
2170 static void drawPlayerSetupInputInfo(int player_nr)
2171 {
2172   int i;
2173   static struct SetupKeyboardInfo custom_key;
2174   static struct
2175   {
2176     Key *key;
2177     char *text;
2178   } custom[] =
2179   {
2180     { &custom_key.left,  "Joystick Left"  },
2181     { &custom_key.right, "Joystick Right" },
2182     { &custom_key.up,    "Joystick Up"    },
2183     { &custom_key.down,  "Joystick Down"  },
2184     { &custom_key.snap,  "Button 1"       },
2185     { &custom_key.bomb,  "Button 2"       }
2186   };
2187   static char *joystick_name[MAX_PLAYERS] =
2188   {
2189     "Joystick1",
2190     "Joystick2",
2191     "Joystick3",
2192     "Joystick4"
2193   };
2194
2195   custom_key = setup.input[player_nr].key;
2196
2197   DrawText(mSX+11*32, mSY+2*32, int2str(player_nr +1, 1), FONT_INPUT_1_ACTIVE);
2198 #if 1
2199   DrawGraphicThruMaskExt(drawto, mSX + 8 * TILEX, mSY + 2 * TILEY,
2200                          PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0);
2201 #else
2202   DrawGraphicThruMask(8, 2, PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0);
2203 #endif
2204
2205   if (setup.input[player_nr].use_joystick)
2206   {
2207     char *device_name = setup.input[player_nr].joy.device_name;
2208
2209     DrawText(mSX+8*32, mSY+3*32,
2210              joystick_name[getJoystickNrFromDeviceName(device_name)],
2211              FONT_VALUE_1);
2212     DrawText(mSX+32, mSY+4*32, "Calibrate", FONT_MENU_1);
2213   }
2214   else
2215   {
2216     DrawText(mSX+8*32, mSY+3*32, "Keyboard ", FONT_VALUE_1);
2217     DrawText(mSX+32,   mSY+4*32, "Customize", FONT_MENU_1);
2218   }
2219
2220   DrawText(mSX+32, mSY+5*32, "Actual Settings:", FONT_MENU_1);
2221   drawCursorXY(1, 4, IMG_MENU_BUTTON_LEFT);
2222   drawCursorXY(1, 5, IMG_MENU_BUTTON_RIGHT);
2223   drawCursorXY(1, 6, IMG_MENU_BUTTON_UP);
2224   drawCursorXY(1, 7, IMG_MENU_BUTTON_DOWN);
2225   DrawText(mSX+2*32, mSY+6*32, ":", FONT_VALUE_OLD);
2226   DrawText(mSX+2*32, mSY+7*32, ":", FONT_VALUE_OLD);
2227   DrawText(mSX+2*32, mSY+8*32, ":", FONT_VALUE_OLD);
2228   DrawText(mSX+2*32, mSY+9*32, ":", FONT_VALUE_OLD);
2229   DrawText(mSX+32, mSY+10*32, "Snap Field:", FONT_VALUE_OLD);
2230   DrawText(mSX+32, mSY+12*32, "Place Bomb:", FONT_VALUE_OLD);
2231
2232   for (i=0; i<6; i++)
2233   {
2234     int ypos = 6 + i + (i > 3 ? i-3 : 0);
2235
2236     DrawText(mSX + 3*32, mSY + ypos*32,
2237              "              ", FONT_VALUE_1);
2238     DrawText(mSX + 3*32, mSY + ypos*32,
2239              (setup.input[player_nr].use_joystick ?
2240               custom[i].text :
2241               getKeyNameFromKey(*custom[i].key)), FONT_VALUE_1);
2242   }
2243 }
2244
2245 void HandleSetupScreen_Input(int mx, int my, int dx, int dy, int button)
2246 {
2247   static int choice = 0;
2248   static int player_nr = 0;
2249   int x = 0;
2250   int y = choice;
2251   int pos_start  = SETUPINPUT_SCREEN_POS_START;
2252   int pos_empty1 = SETUPINPUT_SCREEN_POS_EMPTY1;
2253   int pos_empty2 = SETUPINPUT_SCREEN_POS_EMPTY2;
2254   int pos_end    = SETUPINPUT_SCREEN_POS_END;
2255
2256   if (button == MB_MENU_INITIALIZE)
2257   {
2258     drawPlayerSetupInputInfo(player_nr);
2259     drawCursor(choice, FC_RED);
2260     return;
2261   }
2262   else if (button == MB_MENU_LEAVE)
2263   {
2264     setup_mode = SETUP_MODE_MAIN;
2265     DrawSetupScreen();
2266     InitJoysticks();
2267   }
2268
2269   if (mx || my)         /* mouse input */
2270   {
2271     x = (mx - mSX) / 32;
2272     y = (my - mSY) / 32 - MENU_SCREEN_START_YPOS;
2273   }
2274   else if (dx || dy)    /* keyboard input */
2275   {
2276     if (dx && choice == 0)
2277       x = (dx < 0 ? 10 : 12);
2278     else if ((dx && choice == 1) ||
2279              (dx == +1 && choice == 2) ||
2280              (dx == -1 && choice == pos_end))
2281       button = MB_MENU_CHOICE;
2282     else if (dy)
2283       y = choice + dy;
2284
2285     if (y >= pos_empty1 && y <= pos_empty2)
2286       y = (dy > 0 ? pos_empty2 + 1 : pos_empty1 - 1);
2287   }
2288
2289   if (y == 0 && ((x == 0 && !button) || ((x == 10 || x == 12) && button)))
2290   {
2291     static unsigned long delay = 0;
2292
2293     if (!DelayReached(&delay, GADGET_FRAME_DELAY))
2294       goto out;
2295
2296     player_nr = (player_nr + (x == 10 ? -1 : +1) + MAX_PLAYERS) % MAX_PLAYERS;
2297
2298     drawPlayerSetupInputInfo(player_nr);
2299   }
2300   else if (x == 0 && y >= pos_start && y <= pos_end &&
2301            !(y >= pos_empty1 && y <= pos_empty2))
2302   {
2303     if (button)
2304     {
2305       if (y != choice)
2306       {
2307         drawCursor(y, FC_RED);
2308         drawCursor(choice, FC_BLUE);
2309         choice = y;
2310       }
2311     }
2312     else
2313     {
2314       if (y == 1)
2315       {
2316         char *device_name = setup.input[player_nr].joy.device_name;
2317
2318         if (!setup.input[player_nr].use_joystick)
2319         {
2320           int new_device_nr = (dx >= 0 ? 0 : MAX_PLAYERS - 1);
2321
2322           setJoystickDeviceToNr(device_name, new_device_nr);
2323           setup.input[player_nr].use_joystick = TRUE;
2324         }
2325         else
2326         {
2327           int device_nr = getJoystickNrFromDeviceName(device_name);
2328           int new_device_nr = device_nr + (dx >= 0 ? +1 : -1);
2329
2330           if (new_device_nr < 0 || new_device_nr >= MAX_PLAYERS)
2331             setup.input[player_nr].use_joystick = FALSE;
2332           else
2333             setJoystickDeviceToNr(device_name, new_device_nr);
2334         }
2335
2336         drawPlayerSetupInputInfo(player_nr);
2337       }
2338       else if (y == 2)
2339       {
2340         if (setup.input[player_nr].use_joystick)
2341         {
2342           InitJoysticks();
2343           CalibrateJoystick(player_nr);
2344         }
2345         else
2346           CustomizeKeyboard(player_nr);
2347       }
2348       else if (y == pos_end)
2349       {
2350         InitJoysticks();
2351
2352         setup_mode = SETUP_MODE_MAIN;
2353         DrawSetupScreen();
2354       }
2355     }
2356   }
2357
2358   BackToFront();
2359
2360   out:
2361
2362   if (game_status == GAME_MODE_SETUP)
2363     DoAnimation();
2364 }
2365
2366 void CustomizeKeyboard(int player_nr)
2367 {
2368   int i;
2369   int step_nr;
2370   boolean finished = FALSE;
2371   static struct SetupKeyboardInfo custom_key;
2372   static struct
2373   {
2374     Key *key;
2375     char *text;
2376   } customize_step[] =
2377   {
2378     { &custom_key.left,  "Move Left"  },
2379     { &custom_key.right, "Move Right" },
2380     { &custom_key.up,    "Move Up"    },
2381     { &custom_key.down,  "Move Down"  },
2382     { &custom_key.snap,  "Snap Field" },
2383     { &custom_key.bomb,  "Place Bomb" }
2384   };
2385
2386   /* read existing key bindings from player setup */
2387   custom_key = setup.input[player_nr].key;
2388
2389   ClearWindow();
2390   DrawText(mSX + 16, mSY + 16, "Keyboard Input", FONT_TITLE_1);
2391
2392   BackToFront();
2393   InitAnimation();
2394
2395   step_nr = 0;
2396   DrawText(mSX, mSY + (2+2*step_nr)*32,
2397            customize_step[step_nr].text, FONT_INPUT_1_ACTIVE);
2398   DrawText(mSX, mSY + (2+2*step_nr+1)*32,
2399            "Key:", FONT_INPUT_1_ACTIVE);
2400   DrawText(mSX + 4*32, mSY + (2+2*step_nr+1)*32,
2401            getKeyNameFromKey(*customize_step[step_nr].key), FONT_VALUE_OLD);
2402
2403   while(!finished)
2404   {
2405     if (PendingEvent())         /* got event */
2406     {
2407       Event event;
2408
2409       NextEvent(&event);
2410
2411       switch(event.type)
2412       {
2413         case EVENT_KEYPRESS:
2414           {
2415             Key key = GetEventKey((KeyEvent *)&event, FALSE);
2416
2417             if (key == KSYM_Escape || (key == KSYM_Return && step_nr == 6))
2418             {
2419               finished = TRUE;
2420               break;
2421             }
2422
2423             /* all keys configured -- wait for "Escape" or "Return" key */
2424             if (step_nr == 6)
2425               break;
2426
2427             /* press 'Enter' to keep the existing key binding */
2428             if (key == KSYM_Return)
2429               key = *customize_step[step_nr].key;
2430
2431             /* check if key already used */
2432             for (i=0; i<step_nr; i++)
2433               if (*customize_step[i].key == key)
2434                 break;
2435             if (i < step_nr)
2436               break;
2437
2438             /* got new key binding */
2439             *customize_step[step_nr].key = key;
2440             DrawText(mSX + 4*32, mSY + (2+2*step_nr+1)*32,
2441                      "             ", FONT_VALUE_1);
2442             DrawText(mSX + 4*32, mSY + (2+2*step_nr+1)*32,
2443                      getKeyNameFromKey(key), FONT_VALUE_1);
2444             step_nr++;
2445
2446             /* un-highlight last query */
2447             DrawText(mSX, mSY+(2+2*(step_nr-1))*32,
2448                      customize_step[step_nr-1].text, FONT_MENU_1);
2449             DrawText(mSX, mSY+(2+2*(step_nr-1)+1)*32,
2450                      "Key:", FONT_MENU_1);
2451
2452             /* press 'Enter' to leave */
2453             if (step_nr == 6)
2454             {
2455               DrawText(mSX + 16, mSY + 15*32+16,
2456                        "Press Enter", FONT_TITLE_1);
2457               break;
2458             }
2459
2460             /* query next key binding */
2461             DrawText(mSX, mSY+(2+2*step_nr)*32,
2462                      customize_step[step_nr].text, FONT_INPUT_1_ACTIVE);
2463             DrawText(mSX, mSY+(2+2*step_nr+1)*32,
2464                      "Key:", FONT_INPUT_1_ACTIVE);
2465             DrawText(mSX + 4*32, mSY+(2+2*step_nr+1)*32,
2466                      getKeyNameFromKey(*customize_step[step_nr].key),
2467                      FONT_VALUE_OLD);
2468           }
2469           break;
2470
2471         case EVENT_KEYRELEASE:
2472           key_joystick_mapping = 0;
2473           break;
2474
2475         default:
2476           HandleOtherEvents(&event);
2477           break;
2478       }
2479     }
2480
2481     BackToFront();
2482     DoAnimation();
2483
2484     /* don't eat all CPU time */
2485     Delay(10);
2486   }
2487
2488   /* write new key bindings back to player setup */
2489   setup.input[player_nr].key = custom_key;
2490
2491   StopAnimation();
2492   DrawSetupScreen_Input();
2493 }
2494
2495 static boolean CalibrateJoystickMain(int player_nr)
2496 {
2497   int new_joystick_xleft = JOYSTICK_XMIDDLE;
2498   int new_joystick_xright = JOYSTICK_XMIDDLE;
2499   int new_joystick_yupper = JOYSTICK_YMIDDLE;
2500   int new_joystick_ylower = JOYSTICK_YMIDDLE;
2501   int new_joystick_xmiddle, new_joystick_ymiddle;
2502
2503   int joystick_fd = joystick.fd[player_nr];
2504   int x, y, last_x, last_y, xpos = 8, ypos = 3;
2505   boolean check[3][3];
2506   int check_remaining = 3 * 3;
2507   int joy_x, joy_y;
2508   int joy_value;
2509   int result = -1;
2510
2511   if (joystick.status == JOYSTICK_NOT_AVAILABLE)
2512     return FALSE;
2513
2514   if (joystick_fd < 0 || !setup.input[player_nr].use_joystick)
2515     return FALSE;
2516
2517   ClearWindow();
2518
2519   for(y=0; y < 3; y++)
2520   {
2521     for(x=0; x < 3; x++)
2522     {
2523       DrawGraphic(xpos + x - 1, ypos + y - 1, IMG_MENU_CALIBRATE_BLUE, 0);
2524       check[x][y] = FALSE;
2525     }
2526   }
2527
2528   DrawText(mSX,      mSY +  6 * 32, " ROTATE JOYSTICK ", FONT_TITLE_1);
2529   DrawText(mSX,      mSY +  7 * 32, "IN ALL DIRECTIONS", FONT_TITLE_1);
2530   DrawText(mSX + 16, mSY +  9 * 32, "  IF ALL BALLS  ",  FONT_TITLE_1);
2531   DrawText(mSX,      mSY + 10 * 32, "   ARE YELLOW,   ", FONT_TITLE_1);
2532   DrawText(mSX,      mSY + 11 * 32, " CENTER JOYSTICK ", FONT_TITLE_1);
2533   DrawText(mSX,      mSY + 12 * 32, "       AND       ", FONT_TITLE_1);
2534   DrawText(mSX,      mSY + 13 * 32, "PRESS ANY BUTTON!", FONT_TITLE_1);
2535
2536   joy_value = Joystick(player_nr);
2537   last_x = (joy_value & JOY_LEFT ? -1 : joy_value & JOY_RIGHT ? +1 : 0);
2538   last_y = (joy_value & JOY_UP   ? -1 : joy_value & JOY_DOWN  ? +1 : 0);
2539
2540   /* eventually uncalibrated center position (joystick could be uncentered) */
2541   if (!ReadJoystick(joystick_fd, &joy_x, &joy_y, NULL, NULL))
2542     return FALSE;
2543
2544   new_joystick_xmiddle = joy_x;
2545   new_joystick_ymiddle = joy_y;
2546
2547   DrawGraphic(xpos + last_x, ypos + last_y, IMG_MENU_CALIBRATE_RED, 0);
2548   BackToFront();
2549
2550   while(Joystick(player_nr) & JOY_BUTTON);      /* wait for released button */
2551   InitAnimation();
2552
2553   while(result < 0)
2554   {
2555     if (PendingEvent())         /* got event */
2556     {
2557       Event event;
2558
2559       NextEvent(&event);
2560
2561       switch(event.type)
2562       {
2563         case EVENT_KEYPRESS:
2564           switch(GetEventKey((KeyEvent *)&event, TRUE))
2565           {
2566             case KSYM_Return:
2567               if (check_remaining == 0)
2568                 result = 1;
2569               break;
2570
2571             case KSYM_Escape:
2572               result = 0;
2573               break;
2574
2575             default:
2576               break;
2577           }
2578           break;
2579
2580         case EVENT_KEYRELEASE:
2581           key_joystick_mapping = 0;
2582           break;
2583
2584         default:
2585           HandleOtherEvents(&event);
2586           break;
2587       }
2588     }
2589
2590     if (!ReadJoystick(joystick_fd, &joy_x, &joy_y, NULL, NULL))
2591       return FALSE;
2592
2593     new_joystick_xleft  = MIN(new_joystick_xleft,  joy_x);
2594     new_joystick_xright = MAX(new_joystick_xright, joy_x);
2595     new_joystick_yupper = MIN(new_joystick_yupper, joy_y);
2596     new_joystick_ylower = MAX(new_joystick_ylower, joy_y);
2597
2598     setup.input[player_nr].joy.xleft = new_joystick_xleft;
2599     setup.input[player_nr].joy.yupper = new_joystick_yupper;
2600     setup.input[player_nr].joy.xright = new_joystick_xright;
2601     setup.input[player_nr].joy.ylower = new_joystick_ylower;
2602     setup.input[player_nr].joy.xmiddle = new_joystick_xmiddle;
2603     setup.input[player_nr].joy.ymiddle = new_joystick_ymiddle;
2604
2605     CheckJoystickData();
2606
2607     joy_value = Joystick(player_nr);
2608
2609     if (joy_value & JOY_BUTTON && check_remaining == 0)
2610       result = 1;
2611
2612     x = (joy_value & JOY_LEFT ? -1 : joy_value & JOY_RIGHT ? +1 : 0);
2613     y = (joy_value & JOY_UP   ? -1 : joy_value & JOY_DOWN  ? +1 : 0);
2614
2615     if (x != last_x || y != last_y)
2616     {
2617       DrawGraphic(xpos + last_x, ypos + last_y, IMG_MENU_CALIBRATE_YELLOW, 0);
2618       DrawGraphic(xpos + x,      ypos + y,      IMG_MENU_CALIBRATE_RED,    0);
2619
2620       last_x = x;
2621       last_y = y;
2622
2623       if (check_remaining > 0 && !check[x+1][y+1])
2624       {
2625         check[x+1][y+1] = TRUE;
2626         check_remaining--;
2627       }
2628
2629 #if 0
2630 #ifdef DEBUG
2631       printf("LEFT / MIDDLE / RIGHT == %d / %d / %d\n",
2632              setup.input[player_nr].joy.xleft,
2633              setup.input[player_nr].joy.xmiddle,
2634              setup.input[player_nr].joy.xright);
2635       printf("UP / MIDDLE / DOWN == %d / %d / %d\n",
2636              setup.input[player_nr].joy.yupper,
2637              setup.input[player_nr].joy.ymiddle,
2638              setup.input[player_nr].joy.ylower);
2639 #endif
2640 #endif
2641
2642     }
2643
2644     BackToFront();
2645     DoAnimation();
2646
2647     /* don't eat all CPU time */
2648     Delay(10);
2649   }
2650
2651   /* calibrated center position (joystick should now be centered) */
2652   if (!ReadJoystick(joystick_fd, &joy_x, &joy_y, NULL, NULL))
2653     return FALSE;
2654
2655   new_joystick_xmiddle = joy_x;
2656   new_joystick_ymiddle = joy_y;
2657
2658   StopAnimation();
2659
2660   DrawSetupScreen_Input();
2661
2662   /* wait until the last pressed button was released */
2663   while (Joystick(player_nr) & JOY_BUTTON)
2664   {
2665     if (PendingEvent())         /* got event */
2666     {
2667       Event event;
2668
2669       NextEvent(&event);
2670       HandleOtherEvents(&event);
2671
2672       Delay(10);
2673     }
2674   }
2675
2676   return TRUE;
2677 }
2678
2679 void CalibrateJoystick(int player_nr)
2680 {
2681   if (!CalibrateJoystickMain(player_nr))
2682   {
2683     ClearWindow();
2684
2685     DrawText(mSX + 16, mSY + 6*32, "  JOYSTICK NOT  ",  FONT_TITLE_1);
2686     DrawText(mSX,      mSY + 7*32, "    AVAILABLE    ", FONT_TITLE_1);
2687     BackToFront();
2688     Delay(2000);        /* show error message for two seconds */
2689   }
2690 }
2691
2692 void DrawSetupScreen()
2693 {
2694   DeactivateJoystick();
2695
2696   SetMainBackgroundImage(IMG_BACKGROUND_SETUP);
2697
2698   if (setup_mode == SETUP_MODE_INPUT)
2699     DrawSetupScreen_Input();
2700   else if (setup_mode == SETUP_MODE_CHOOSE_GRAPHICS)
2701     DrawChooseTree(&artwork.gfx_current);
2702   else if (setup_mode == SETUP_MODE_CHOOSE_SOUNDS)
2703     DrawChooseTree(&artwork.snd_current);
2704   else if (setup_mode == SETUP_MODE_CHOOSE_MUSIC)
2705     DrawChooseTree(&artwork.mus_current);
2706   else
2707     DrawSetupScreen_Generic();
2708 }
2709
2710 void HandleSetupScreen(int mx, int my, int dx, int dy, int button)
2711 {
2712   if (setup_mode == SETUP_MODE_INPUT)
2713     HandleSetupScreen_Input(mx, my, dx, dy, button);
2714   else if (setup_mode == SETUP_MODE_CHOOSE_GRAPHICS)
2715     HandleChooseTree(mx, my, dx, dy, button, &artwork.gfx_current);
2716   else if (setup_mode == SETUP_MODE_CHOOSE_SOUNDS)
2717     HandleChooseTree(mx, my, dx, dy, button, &artwork.snd_current);
2718   else if (setup_mode == SETUP_MODE_CHOOSE_MUSIC)
2719     HandleChooseTree(mx, my, dx, dy, button, &artwork.mus_current);
2720   else
2721     HandleSetupScreen_Generic(mx, my, dx, dy, button);
2722 }
2723
2724 void HandleGameActions()
2725 {
2726   if (game_status != GAME_MODE_PLAYING)
2727     return;
2728
2729   if (local_player->LevelSolved)
2730     GameWon();
2731
2732   if (AllPlayersGone && !TAPE_IS_STOPPED(tape))
2733     TapeStop();
2734
2735   GameActions();
2736
2737   BackToFront();
2738
2739 #if 1
2740   if (tape.auto_play && !tape.playing)
2741     AutoPlayTape();     /* continue automatically playing next tape */
2742 #endif
2743 }
2744
2745 /* ---------- new screen button stuff -------------------------------------- */
2746
2747 /* graphic position and size values for buttons and scrollbars */
2748 #define SC_SCROLLBUTTON_XSIZE           TILEX
2749 #define SC_SCROLLBUTTON_YSIZE           TILEY
2750
2751 #define SC_SCROLL_VERTICAL_XSIZE        SC_SCROLLBUTTON_XSIZE
2752 #define SC_SCROLL_VERTICAL_YSIZE        ((MAX_MENU_ENTRIES_ON_SCREEN - 2) * \
2753                                          SC_SCROLLBUTTON_YSIZE)
2754 #define SC_SCROLL_UP_XPOS               (SXSIZE - SC_SCROLLBUTTON_XSIZE)
2755 #define SC_SCROLL_UP_YPOS               (2 * SC_SCROLLBUTTON_YSIZE)
2756 #define SC_SCROLL_VERTICAL_XPOS         SC_SCROLL_UP_XPOS
2757 #define SC_SCROLL_VERTICAL_YPOS         (SC_SCROLL_UP_YPOS + \
2758                                          SC_SCROLLBUTTON_YSIZE)
2759 #define SC_SCROLL_DOWN_XPOS             SC_SCROLL_UP_XPOS
2760 #define SC_SCROLL_DOWN_YPOS             (SC_SCROLL_VERTICAL_YPOS + \
2761                                          SC_SCROLL_VERTICAL_YSIZE)
2762
2763 #define SC_BORDER_SIZE                  14
2764
2765 static struct
2766 {
2767   int gfx_unpressed, gfx_pressed;
2768   int x, y;
2769   int gadget_id;
2770   char *infotext;
2771 } scrollbutton_info[NUM_SCREEN_SCROLLBUTTONS] =
2772 {
2773   {
2774     IMG_MENU_BUTTON_UP, IMG_MENU_BUTTON_UP_ACTIVE,
2775     SC_SCROLL_UP_XPOS, SC_SCROLL_UP_YPOS,
2776     SCREEN_CTRL_ID_SCROLL_UP,
2777     "scroll up"
2778   },
2779   {
2780     IMG_MENU_BUTTON_DOWN, IMG_MENU_BUTTON_DOWN_ACTIVE,
2781     SC_SCROLL_DOWN_XPOS, SC_SCROLL_DOWN_YPOS,
2782     SCREEN_CTRL_ID_SCROLL_DOWN,
2783     "scroll down"
2784   }
2785 };
2786
2787 static struct
2788 {
2789 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
2790   Bitmap **gfx_unpressed, **gfx_pressed;
2791 #else
2792   int gfx_unpressed, gfx_pressed;
2793 #endif
2794   int x, y;
2795   int width, height;
2796   int type;
2797   int gadget_id;
2798   char *infotext;
2799 } scrollbar_info[NUM_SCREEN_SCROLLBARS] =
2800 {
2801   {
2802 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
2803     &scrollbar_bitmap[0], &scrollbar_bitmap[1],
2804 #else
2805     IMG_MENU_SCROLLBAR, IMG_MENU_SCROLLBAR_ACTIVE,
2806 #endif
2807     SX + SC_SCROLL_VERTICAL_XPOS, SY + SC_SCROLL_VERTICAL_YPOS,
2808     SC_SCROLL_VERTICAL_XSIZE, SC_SCROLL_VERTICAL_YSIZE,
2809     GD_TYPE_SCROLLBAR_VERTICAL,
2810     SCREEN_CTRL_ID_SCROLL_VERTICAL,
2811     "scroll level series vertically"
2812   }
2813 };
2814
2815 static void CreateScreenScrollbuttons()
2816 {
2817   struct GadgetInfo *gi;
2818   unsigned long event_mask;
2819   int i;
2820
2821   for (i=0; i<NUM_SCREEN_SCROLLBUTTONS; i++)
2822   {
2823     Bitmap *gd_bitmap_unpressed, *gd_bitmap_pressed;
2824     int gfx_unpressed, gfx_pressed;
2825     int x, y, width, height;
2826     int gd_x1, gd_x2, gd_y1, gd_y2;
2827     int id = scrollbutton_info[i].gadget_id;
2828
2829     x = scrollbutton_info[i].x;
2830     y = scrollbutton_info[i].y;
2831
2832     event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
2833
2834     x += SX;
2835     y += SY;
2836     width = SC_SCROLLBUTTON_XSIZE;
2837     height = SC_SCROLLBUTTON_YSIZE;
2838
2839     gfx_unpressed = scrollbutton_info[i].gfx_unpressed;
2840     gfx_pressed   = scrollbutton_info[i].gfx_pressed;
2841     gd_bitmap_unpressed = graphic_info[gfx_unpressed].bitmap;
2842     gd_bitmap_pressed   = graphic_info[gfx_pressed].bitmap;
2843     gd_x1 = graphic_info[gfx_unpressed].src_x;
2844     gd_y1 = graphic_info[gfx_unpressed].src_y;
2845     gd_x2 = graphic_info[gfx_pressed].src_x;
2846     gd_y2 = graphic_info[gfx_pressed].src_y;
2847
2848     gi = CreateGadget(GDI_CUSTOM_ID, id,
2849                       GDI_CUSTOM_TYPE_ID, i,
2850                       GDI_INFO_TEXT, scrollbutton_info[i].infotext,
2851                       GDI_X, x,
2852                       GDI_Y, y,
2853                       GDI_WIDTH, width,
2854                       GDI_HEIGHT, height,
2855                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2856                       GDI_STATE, GD_BUTTON_UNPRESSED,
2857                       GDI_DESIGN_UNPRESSED, gd_bitmap_unpressed, gd_x1, gd_y1,
2858                       GDI_DESIGN_PRESSED, gd_bitmap_pressed, gd_x2, gd_y2,
2859                       GDI_EVENT_MASK, event_mask,
2860                       GDI_CALLBACK_ACTION, HandleScreenGadgets,
2861                       GDI_END);
2862
2863     if (gi == NULL)
2864       Error(ERR_EXIT, "cannot create gadget");
2865
2866     screen_gadget[id] = gi;
2867   }
2868 }
2869
2870 static void CreateScreenScrollbars()
2871 {
2872   int i;
2873
2874   for (i=0; i<NUM_SCREEN_SCROLLBARS; i++)
2875   {
2876     Bitmap *gd_bitmap_unpressed, *gd_bitmap_pressed;
2877 #if !defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
2878     int gfx_unpressed, gfx_pressed;
2879 #endif
2880     int gd_x1, gd_x2, gd_y1, gd_y2;
2881     struct GadgetInfo *gi;
2882     int items_max, items_visible, item_position;
2883     unsigned long event_mask;
2884     int num_page_entries = NUM_MENU_ENTRIES_ON_SCREEN;
2885     int id = scrollbar_info[i].gadget_id;
2886
2887     items_max = num_page_entries;
2888     items_visible = num_page_entries;
2889     item_position = 0;
2890
2891     event_mask = GD_EVENT_MOVING | GD_EVENT_OFF_BORDERS;
2892
2893 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
2894     gd_bitmap_unpressed = *scrollbar_info[i].gfx_unpressed;
2895     gd_bitmap_pressed   = *scrollbar_info[i].gfx_pressed;
2896     gd_x1 = 0;
2897     gd_y1 = 0;
2898     gd_x2 = 0;
2899     gd_y2 = 0;
2900 #else
2901     gfx_unpressed = scrollbar_info[i].gfx_unpressed;
2902     gfx_pressed   = scrollbar_info[i].gfx_pressed;
2903     gd_bitmap_unpressed = graphic_info[gfx_unpressed].bitmap;
2904     gd_bitmap_pressed   = graphic_info[gfx_pressed].bitmap;
2905     gd_x1 = graphic_info[gfx_unpressed].src_x;
2906     gd_y1 = graphic_info[gfx_unpressed].src_y;
2907     gd_x2 = graphic_info[gfx_pressed].src_x;
2908     gd_y2 = graphic_info[gfx_pressed].src_y;
2909 #endif
2910
2911     gi = CreateGadget(GDI_CUSTOM_ID, id,
2912                       GDI_CUSTOM_TYPE_ID, i,
2913                       GDI_INFO_TEXT, scrollbar_info[i].infotext,
2914                       GDI_X, scrollbar_info[i].x,
2915                       GDI_Y, scrollbar_info[i].y,
2916                       GDI_WIDTH, scrollbar_info[i].width,
2917                       GDI_HEIGHT, scrollbar_info[i].height,
2918                       GDI_TYPE, scrollbar_info[i].type,
2919                       GDI_SCROLLBAR_ITEMS_MAX, items_max,
2920                       GDI_SCROLLBAR_ITEMS_VISIBLE, items_visible,
2921                       GDI_SCROLLBAR_ITEM_POSITION, item_position,
2922                       GDI_STATE, GD_BUTTON_UNPRESSED,
2923                       GDI_DESIGN_UNPRESSED, gd_bitmap_unpressed, gd_x1, gd_y1,
2924                       GDI_DESIGN_PRESSED, gd_bitmap_pressed, gd_x2, gd_y2,
2925                       GDI_BORDER_SIZE, SC_BORDER_SIZE, SC_BORDER_SIZE,
2926                       GDI_EVENT_MASK, event_mask,
2927                       GDI_CALLBACK_ACTION, HandleScreenGadgets,
2928                       GDI_END);
2929
2930     if (gi == NULL)
2931       Error(ERR_EXIT, "cannot create gadget");
2932
2933     screen_gadget[id] = gi;
2934   }
2935 }
2936
2937 void CreateScreenGadgets()
2938 {
2939 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
2940   int i;
2941
2942   for (i=0; i < NUM_SCROLLBAR_BITMAPS; i++)
2943   {
2944     scrollbar_bitmap[i] = CreateBitmap(TILEX, TILEY, DEFAULT_DEPTH);
2945
2946     /* copy pointers to clip mask and GC */
2947     scrollbar_bitmap[i]->clip_mask =
2948       graphic_info[IMG_MENU_SCROLLBAR + i].clip_mask;
2949     scrollbar_bitmap[i]->stored_clip_gc =
2950       graphic_info[IMG_MENU_SCROLLBAR + i].clip_gc;
2951
2952     BlitBitmap(graphic_info[IMG_MENU_SCROLLBAR + i].bitmap,
2953                scrollbar_bitmap[i],
2954                graphic_info[IMG_MENU_SCROLLBAR + i].src_x,
2955                graphic_info[IMG_MENU_SCROLLBAR + i].src_y,
2956                TILEX, TILEY, 0, 0);
2957   }
2958 #endif
2959
2960   CreateScreenScrollbuttons();
2961   CreateScreenScrollbars();
2962 }
2963
2964 void FreeScreenGadgets()
2965 {
2966   int i;
2967
2968 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
2969   for (i=0; i < NUM_SCROLLBAR_BITMAPS; i++)
2970   {
2971     /* prevent freeing clip mask and GC twice */
2972     scrollbar_bitmap[i]->clip_mask = None;
2973     scrollbar_bitmap[i]->stored_clip_gc = None;
2974
2975     FreeBitmap(scrollbar_bitmap[i]);
2976   }
2977 #endif
2978
2979   for (i=0; i<NUM_SCREEN_GADGETS; i++)
2980     FreeGadget(screen_gadget[i]);
2981 }
2982
2983 void MapChooseTreeGadgets(TreeInfo *ti)
2984 {
2985   int num_entries = numTreeInfoInGroup(ti);
2986   int i;
2987
2988   if (num_entries <= NUM_MENU_ENTRIES_ON_SCREEN)
2989     return;
2990
2991   for (i=0; i<NUM_SCREEN_GADGETS; i++)
2992     MapGadget(screen_gadget[i]);
2993 }
2994
2995 void UnmapChooseTreeGadgets()
2996 {
2997   int i;
2998
2999   for (i=0; i<NUM_SCREEN_GADGETS; i++)
3000     UnmapGadget(screen_gadget[i]);
3001 }
3002
3003 static void HandleScreenGadgets(struct GadgetInfo *gi)
3004 {
3005   int id = gi->custom_id;
3006
3007   if (game_status != GAME_MODE_LEVELS && game_status != GAME_MODE_SETUP)
3008     return;
3009
3010   switch (id)
3011   {
3012     case SCREEN_CTRL_ID_SCROLL_UP:
3013       if (game_status == GAME_MODE_LEVELS)
3014         HandleChooseLevel(0,0, 0, -1 * SCROLL_LINE, MB_MENU_MARK);
3015       else if (game_status == GAME_MODE_SETUP)
3016         HandleSetupScreen(0,0, 0, -1 * SCROLL_LINE, MB_MENU_MARK);
3017       break;
3018
3019     case SCREEN_CTRL_ID_SCROLL_DOWN:
3020       if (game_status == GAME_MODE_LEVELS)
3021         HandleChooseLevel(0,0, 0, +1 * SCROLL_LINE, MB_MENU_MARK);
3022       else if (game_status == GAME_MODE_SETUP)
3023         HandleSetupScreen(0,0, 0, +1 * SCROLL_LINE, MB_MENU_MARK);
3024       break;
3025
3026     case SCREEN_CTRL_ID_SCROLL_VERTICAL:
3027       if (game_status == GAME_MODE_LEVELS)
3028         HandleChooseLevel(0,0, 999,gi->event.item_position,MB_MENU_INITIALIZE);
3029       else if (game_status == GAME_MODE_SETUP)
3030         HandleSetupScreen(0,0, 999,gi->event.item_position,MB_MENU_INITIALIZE);
3031       break;
3032
3033     default:
3034       break;
3035   }
3036 }