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