rnd-20031202-1-src
[rocksndiamonds.git] / src / events.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 * events.c                                                 *
12 ***********************************************************/
13
14 #include "libgame/libgame.h"
15
16 #include "events.h"
17 #include "init.h"
18 #include "screens.h"
19 #include "tools.h"
20 #include "game.h"
21 #include "editor.h"
22 #include "files.h"
23 #include "tape.h"
24 #include "network.h"
25
26
27 static boolean cursor_inside_playfield = FALSE;
28 static boolean playfield_cursor_set = FALSE;
29 static unsigned long playfield_cursor_delay = 0;
30
31
32 /* event filter especially needed for SDL event filtering due to
33    delay problems with lots of mouse motion events when mouse button
34    not pressed (X11 can handle this with 'PointerMotionHintMask') */
35
36 int FilterMouseMotionEvents(const Event *event)
37 {
38   MotionEvent *motion;
39
40   /* non-motion events are directly passed to event handler functions */
41   if (event->type != EVENT_MOTIONNOTIFY)
42     return 1;
43
44   motion = (MotionEvent *)event;
45   cursor_inside_playfield = (motion->x >= SX && motion->x < SX + SXSIZE &&
46                              motion->y >= SY && motion->y < SY + SYSIZE);
47
48   if (game_status == GAME_MODE_PLAYING && playfield_cursor_set)
49   {
50     SetMouseCursor(CURSOR_DEFAULT);
51     playfield_cursor_set = FALSE;
52     DelayReached(&playfield_cursor_delay, 0);
53   }
54
55   /* skip mouse motion events without pressed button outside level editor */
56   if (button_status == MB_RELEASED && game_status != GAME_MODE_EDITOR &&
57       game_status != GAME_MODE_PLAYING)
58     return 0;
59   else
60     return 1;
61 }
62
63 /* this is only really needed for non-SDL targets to filter unwanted events;
64    when using SDL with properly installed event filter, this function can be
65    replaced with a simple "NextEvent()" call, but it doesn't hurt either */
66
67 static boolean NextValidEvent(Event *event)
68 {
69   while (PendingEvent())
70   {
71     NextEvent(event);
72
73     if (FilterMouseMotionEvents(event))
74       return TRUE;
75   }
76
77   return FALSE;
78 }
79
80 void EventLoop(void)
81 {
82   while (1)
83   {
84     if (PendingEvent())         /* got event */
85     {
86       Event event;
87
88       if (NextValidEvent(&event))
89       {
90         switch(event.type)
91         {
92           case EVENT_BUTTONPRESS:
93           case EVENT_BUTTONRELEASE:
94             HandleButtonEvent((ButtonEvent *) &event);
95             break;
96   
97           case EVENT_MOTIONNOTIFY:
98             HandleMotionEvent((MotionEvent *) &event);
99             break;
100   
101           case EVENT_KEYPRESS:
102           case EVENT_KEYRELEASE:
103             HandleKeyEvent((KeyEvent *) &event);
104             break;
105   
106           default:
107             HandleOtherEvents(&event);
108             break;
109         }
110       }
111     }
112     else
113     {
114       /* when playing, display a special mouse pointer inside the playfield */
115       if (game_status == GAME_MODE_PLAYING)
116       {
117         if (!playfield_cursor_set && cursor_inside_playfield &&
118             DelayReached(&playfield_cursor_delay, 1000))
119         {
120           SetMouseCursor(CURSOR_PLAYFIELD);
121           playfield_cursor_set = TRUE;
122         }
123       }
124       else if (playfield_cursor_set)
125       {
126         SetMouseCursor(CURSOR_DEFAULT);
127         playfield_cursor_set = FALSE;
128       }
129
130       HandleNoEvent();
131     }
132
133     /* don't use all CPU time when idle; the main loop while playing
134        has its own synchronization and is CPU friendly, too */
135
136     if (game_status == GAME_MODE_PLAYING)
137       HandleGameActions();
138     else
139     {
140       SyncDisplay();
141       if (!PendingEvent())      /* delay only if no pending events */
142         Delay(10);
143     }
144
145     /* refresh window contents from drawing buffer, if needed */
146     BackToFront();
147
148     if (game_status == GAME_MODE_QUIT)
149       return;
150   }
151 }
152
153 void HandleOtherEvents(Event *event)
154 {
155   switch(event->type)
156   {
157     case EVENT_EXPOSE:
158       HandleExposeEvent((ExposeEvent *) event);
159       break;
160
161     case EVENT_UNMAPNOTIFY:
162 #if 0
163       /* This causes the game to stop not only when iconified, but also
164          when on another virtual desktop, which might be not desired. */
165       SleepWhileUnmapped();
166 #endif
167       break;
168
169     case EVENT_FOCUSIN:
170     case EVENT_FOCUSOUT:
171       HandleFocusEvent((FocusChangeEvent *) event);
172       break;
173
174     case EVENT_CLIENTMESSAGE:
175       HandleClientMessageEvent((ClientMessageEvent *) event);
176       break;
177
178 #if defined(TARGET_SDL)
179     case SDL_JOYAXISMOTION:
180     case SDL_JOYBUTTONDOWN:
181     case SDL_JOYBUTTONUP:
182       HandleJoystickEvent(event);
183       break;
184 #endif
185
186     default:
187       break;
188   }
189 }
190
191 void ClearEventQueue()
192 {
193   while (PendingEvent())
194   {
195     Event event;
196
197     NextEvent(&event);
198
199     switch(event.type)
200     {
201       case EVENT_BUTTONRELEASE:
202         button_status = MB_RELEASED;
203         break;
204
205       case EVENT_KEYRELEASE:
206         key_joystick_mapping = 0;
207         break;
208
209       default:
210         HandleOtherEvents(&event);
211         break;
212     }
213   }
214 }
215
216 void ClearPlayerAction()
217 {
218   int i;
219
220   /* simulate key release events for still pressed keys */
221   key_joystick_mapping = 0;
222   for (i = 0; i < MAX_PLAYERS; i++)
223     stored_player[i].action = 0;
224 }
225
226 void SleepWhileUnmapped()
227 {
228   boolean window_unmapped = TRUE;
229
230   KeyboardAutoRepeatOn();
231
232   while (window_unmapped)
233   {
234     Event event;
235
236     NextEvent(&event);
237
238     switch(event.type)
239     {
240       case EVENT_BUTTONRELEASE:
241         button_status = MB_RELEASED;
242         break;
243
244       case EVENT_KEYRELEASE:
245         key_joystick_mapping = 0;
246         break;
247
248       case EVENT_MAPNOTIFY:
249         window_unmapped = FALSE;
250         break;
251
252       case EVENT_UNMAPNOTIFY:
253         /* this is only to surely prevent the 'should not happen' case
254          * of recursively looping between 'SleepWhileUnmapped()' and
255          * 'HandleOtherEvents()' which usually calls this funtion.
256          */
257         break;
258
259       default:
260         HandleOtherEvents(&event);
261         break;
262     }
263   }
264
265   if (game_status == GAME_MODE_PLAYING)
266     KeyboardAutoRepeatOffUnlessAutoplay();
267 }
268
269 void HandleExposeEvent(ExposeEvent *event)
270 {
271 #ifndef TARGET_SDL
272   RedrawPlayfield(FALSE, event->x, event->y, event->width, event->height);
273   FlushDisplay();
274 #endif
275 }
276
277 void HandleButtonEvent(ButtonEvent *event)
278 {
279   motion_status = FALSE;
280
281   if (event->type == EVENT_BUTTONPRESS)
282     button_status = event->button;
283   else
284     button_status = MB_RELEASED;
285
286   HandleButton(event->x, event->y, button_status);
287 }
288
289 void HandleMotionEvent(MotionEvent *event)
290 {
291   if (!PointerInWindow(window))
292     return;     /* window and pointer are on different screens */
293
294 #if 1
295   if (button_status == MB_RELEASED && game_status != GAME_MODE_EDITOR)
296     return;
297 #endif
298
299   motion_status = TRUE;
300
301   HandleButton(event->x, event->y, button_status);
302 }
303
304 void HandleKeyEvent(KeyEvent *event)
305 {
306   int key_status = (event->type==EVENT_KEYPRESS ? KEY_PRESSED : KEY_RELEASED);
307   boolean with_modifiers = (game_status == GAME_MODE_PLAYING ? FALSE : TRUE);
308   Key key = GetEventKey(event, with_modifiers);
309   Key keymod = (with_modifiers ? GetEventKey(event, FALSE) : key);
310
311   HandleKeyModState(keymod, key_status);
312   HandleKey(key, key_status);
313 }
314
315 void HandleFocusEvent(FocusChangeEvent *event)
316 {
317   static int old_joystick_status = -1;
318
319   if (event->type == EVENT_FOCUSOUT)
320   {
321     KeyboardAutoRepeatOn();
322     old_joystick_status = joystick.status;
323     joystick.status = JOYSTICK_NOT_AVAILABLE;
324
325     ClearPlayerAction();
326   }
327   else if (event->type == EVENT_FOCUSIN)
328   {
329     /* When there are two Rocks'n'Diamonds windows which overlap and
330        the player moves the pointer from one game window to the other,
331        a 'FocusOut' event is generated for the window the pointer is
332        leaving and a 'FocusIn' event is generated for the window the
333        pointer is entering. In some cases, it can happen that the
334        'FocusIn' event is handled by the one game process before the
335        'FocusOut' event by the other game process. In this case the
336        X11 environment would end up with activated keyboard auto repeat,
337        because unfortunately this is a global setting and not (which
338        would be far better) set for each X11 window individually.
339        The effect would be keyboard auto repeat while playing the game
340        (game_status == GAME_MODE_PLAYING), which is not desired.
341        To avoid this special case, we just wait 1/10 second before
342        processing the 'FocusIn' event.
343     */
344
345     if (game_status == GAME_MODE_PLAYING)
346     {
347       Delay(100);
348       KeyboardAutoRepeatOffUnlessAutoplay();
349     }
350     if (old_joystick_status != -1)
351       joystick.status = old_joystick_status;
352   }
353 }
354
355 void HandleClientMessageEvent(ClientMessageEvent *event)
356 {
357   if (CheckCloseWindowEvent(event))
358     CloseAllAndExit(0);
359 }
360
361 void HandleButton(int mx, int my, int button)
362 {
363   static int old_mx = 0, old_my = 0;
364
365   if (button < 0)
366   {
367     mx = old_mx;
368     my = old_my;
369     button = -button;
370   }
371   else
372   {
373     old_mx = mx;
374     old_my = my;
375   }
376
377   if (HandleGadgets(mx, my, button))
378   {
379     /* do not handle this button event anymore */
380     mx = my = -32;      /* force mouse event to be outside screen tiles */
381   }
382
383   switch(game_status)
384   {
385     case GAME_MODE_MAIN:
386       HandleMainMenu(mx,my, 0,0, button);
387       break;
388
389     case GAME_MODE_PSEUDO_TYPENAME:
390       HandleTypeName(0, KSYM_Return);
391       break;
392
393     case GAME_MODE_LEVELS:
394       HandleChooseLevel(mx,my, 0,0, button);
395       break;
396
397     case GAME_MODE_SCORES:
398       HandleHallOfFame(0,0, 0,0, button);
399       break;
400
401     case GAME_MODE_EDITOR:
402       break;
403
404     case GAME_MODE_INFO:
405       HandleInfoScreen(mx,my, 0,0, button);
406       break;
407
408     case GAME_MODE_SETUP:
409       HandleSetupScreen(mx,my, 0,0, button);
410       break;
411
412     case GAME_MODE_PLAYING:
413 #ifdef DEBUG
414       if (button == MB_RELEASED)
415       {
416         if (IN_GFX_SCREEN(mx, my))
417         {
418           int sx = (mx - SX) / TILEX;
419           int sy = (my - SY) / TILEY;
420           int x = LEVELX(sx);
421           int y = LEVELY(sy);
422
423           printf("INFO: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
424
425           if (!IN_LEV_FIELD(x, y))
426             break;
427
428           printf("      Feld[%d][%d] == %d ('%s')\n", x,y, Feld[x][y],
429                  element_info[Feld[x][y]].token_name);
430           printf("      Back[%d][%d] == %d\n", x,y, Back[x][y]);
431           printf("      Store[%d][%d] == %d\n", x,y, Store[x][y]);
432           printf("      Store2[%d][%d] == %d\n", x,y, Store2[x][y]);
433           printf("      StorePlayer[%d][%d] == %d\n", x,y, StorePlayer[x][y]);
434           printf("      MovPos[%d][%d] == %d\n", x,y, MovPos[x][y]);
435           printf("      MovDir[%d][%d] == %d\n", x,y, MovDir[x][y]);
436           printf("      MovDelay[%d][%d] == %d\n", x,y, MovDelay[x][y]);
437           printf("      ChangeDelay[%d][%d] == %d\n", x,y, ChangeDelay[x][y]);
438           printf("      GfxElement[%d][%d] == %d\n", x,y, GfxElement[x][y]);
439           printf("      GfxAction[%d][%d] == %d\n", x,y, GfxAction[x][y]);
440           printf("      GfxFrame[%d][%d] == %d\n", x,y, GfxFrame[x][y]);
441           printf("\n");
442         }
443       }
444 #endif
445       break;
446
447     default:
448       break;
449   }
450 }
451
452 void HandleKey(Key key, int key_status)
453 {
454   int joy = 0;
455   boolean anyTextGadgetActiveOrJustFinished = anyTextGadgetActive();
456   static struct SetupKeyboardInfo custom_key;
457   static struct
458   {
459     Key *key_custom;
460     Key key_default;
461     byte action;
462   } key_info[] =
463   {
464     { &custom_key.left,  DEFAULT_KEY_LEFT,  JOY_LEFT     },
465     { &custom_key.right, DEFAULT_KEY_RIGHT, JOY_RIGHT    },
466     { &custom_key.up,    DEFAULT_KEY_UP,    JOY_UP       },
467     { &custom_key.down,  DEFAULT_KEY_DOWN,  JOY_DOWN     },
468     { &custom_key.snap,  DEFAULT_KEY_SNAP,  JOY_BUTTON_1 },
469     { &custom_key.bomb,  DEFAULT_KEY_BOMB,  JOY_BUTTON_2 }
470   };
471
472   if (game_status == GAME_MODE_PLAYING)
473   {
474     /* only needed for single-step tape recording mode */
475     static boolean clear_button_2[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
476     static boolean bomb_placed[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
477     int pnr;
478
479     for (pnr = 0; pnr < MAX_PLAYERS; pnr++)
480     {
481       int i;
482       byte key_action = 0;
483
484       if (setup.input[pnr].use_joystick)
485         continue;
486
487       custom_key = setup.input[pnr].key;
488
489       for (i = 0; i < 6; i++)
490         if (key == *key_info[i].key_custom)
491           key_action |= key_info[i].action;
492
493       if (tape.single_step && clear_button_2[pnr])
494       {
495         stored_player[pnr].action &= ~KEY_BUTTON_2;
496         clear_button_2[pnr] = FALSE;
497       }
498
499       if (key_status == KEY_PRESSED)
500         stored_player[pnr].action |= key_action;
501       else
502         stored_player[pnr].action &= ~key_action;
503
504       if (tape.single_step && tape.recording && tape.pausing)
505       {
506         if (key_status == KEY_PRESSED &&
507             (key_action & (KEY_MOTION | KEY_BUTTON_1)))
508         {
509           TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
510
511           if (key_action & KEY_MOTION)
512           {
513             if (stored_player[pnr].action & KEY_BUTTON_2)
514               bomb_placed[pnr] = TRUE;
515           }
516         }
517         else if (key_status == KEY_RELEASED &&
518                  (key_action & KEY_BUTTON_2))
519         {
520           if (!bomb_placed[pnr])
521           {
522             TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
523
524             stored_player[pnr].action |= KEY_BUTTON_2;
525             clear_button_2[pnr] = TRUE;
526           }
527
528           bomb_placed[pnr] = FALSE;
529         }
530       }
531       else if (tape.recording && tape.pausing && (key_action & KEY_ACTION))
532         TapeTogglePause(TAPE_TOGGLE_MANUAL);
533     }
534   }
535   else
536   {
537     int i;
538
539     for (i = 0; i < 6; i++)
540       if (key == key_info[i].key_default)
541         joy |= key_info[i].action;
542   }
543
544   if (joy)
545   {
546     if (key_status == KEY_PRESSED)
547       key_joystick_mapping |= joy;
548     else
549       key_joystick_mapping &= ~joy;
550
551     HandleJoystick();
552   }
553
554   if (game_status != GAME_MODE_PLAYING)
555     key_joystick_mapping = 0;
556
557   if (key_status == KEY_RELEASED)
558     return;
559
560   if ((key == KSYM_Return || key == setup.shortcut.toggle_pause) &&
561       game_status == GAME_MODE_PLAYING && AllPlayersGone)
562   {
563     CloseDoor(DOOR_CLOSE_1);
564     game_status = GAME_MODE_MAIN;
565     DrawMainMenu();
566     return;
567   }
568
569   /* special key shortcuts */
570   if (game_status == GAME_MODE_MAIN || game_status == GAME_MODE_PLAYING)
571   {
572     if (key == setup.shortcut.save_game)
573       TapeQuickSave();
574     else if (key == setup.shortcut.load_game)
575       TapeQuickLoad();
576     else if (key == setup.shortcut.toggle_pause)
577       TapeTogglePause(TAPE_TOGGLE_MANUAL);
578   }
579
580   if (HandleGadgetsKeyInput(key))
581   {
582     if (key != KSYM_Escape)     /* always allow ESC key to be handled */
583       key = KSYM_UNDEFINED;
584   }
585
586   switch(game_status)
587   {
588     case GAME_MODE_PSEUDO_TYPENAME:
589       HandleTypeName(0, key);
590       break;
591
592     case GAME_MODE_MAIN:
593     case GAME_MODE_LEVELS:
594     case GAME_MODE_SETUP:
595     case GAME_MODE_INFO:
596       switch(key)
597       {
598         case KSYM_Return:
599           if (game_status == GAME_MODE_MAIN)
600             HandleMainMenu(0,0, 0,0, MB_MENU_CHOICE);
601           else if (game_status == GAME_MODE_LEVELS)
602             HandleChooseLevel(0,0, 0,0, MB_MENU_CHOICE);
603           else if (game_status == GAME_MODE_SETUP)
604             HandleSetupScreen(0,0, 0,0, MB_MENU_CHOICE);
605           else if (game_status == GAME_MODE_INFO)
606             HandleInfoScreen(0,0, 0,0, MB_MENU_CHOICE);
607           break;
608
609         case KSYM_Escape:
610           if (game_status == GAME_MODE_LEVELS)
611             HandleChooseLevel(0,0, 0,0, MB_MENU_LEAVE);
612           else if (game_status == GAME_MODE_SETUP)
613             HandleSetupScreen(0,0, 0,0, MB_MENU_LEAVE);
614           else if (game_status == GAME_MODE_INFO)
615             HandleInfoScreen(0,0, 0,0, MB_MENU_LEAVE);
616           break;
617
618         case KSYM_Page_Up:
619           if (game_status == GAME_MODE_LEVELS)
620             HandleChooseLevel(0,0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
621           else if (game_status == GAME_MODE_SETUP)
622             HandleSetupScreen(0,0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
623           else if (game_status == GAME_MODE_INFO)
624             HandleInfoScreen(0,0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
625           break;
626
627         case KSYM_Page_Down:
628           if (game_status == GAME_MODE_LEVELS)
629             HandleChooseLevel(0,0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
630           else if (game_status == GAME_MODE_SETUP)
631             HandleSetupScreen(0,0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
632           else if (game_status == GAME_MODE_INFO)
633             HandleInfoScreen(0,0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
634           break;
635
636 #ifdef DEBUG
637         case KSYM_t:
638           DumpTape(&tape);
639           break;
640 #endif
641
642         default:
643           break;
644       }
645       break;
646
647     case GAME_MODE_SCORES:
648       switch(key)
649       {
650         case KSYM_Return:
651         case KSYM_Escape:
652           game_status = GAME_MODE_MAIN;
653           DrawMainMenu();
654           break;
655
656         case KSYM_Page_Up:
657           HandleHallOfFame(0,0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
658           break;
659
660         case KSYM_Page_Down:
661           HandleHallOfFame(0,0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
662           break;
663
664         default:
665           break;
666       }
667       break;
668
669     case GAME_MODE_EDITOR:
670       if (!anyTextGadgetActiveOrJustFinished || key == KSYM_Escape)
671         HandleLevelEditorKeyInput(key);
672       break;
673
674     case GAME_MODE_PLAYING:
675     {
676       switch(key)
677       {
678         case KSYM_Escape:
679           RequestQuitGame(setup.ask_on_escape);
680           break;
681
682 #ifdef DEBUG
683         case KSYM_0:
684         case KSYM_1:
685         case KSYM_2:
686         case KSYM_3:
687         case KSYM_4:
688         case KSYM_5:
689         case KSYM_6:
690         case KSYM_7:
691         case KSYM_8:
692         case KSYM_9:
693           if (key == KSYM_0)
694           {
695             if (GameFrameDelay == 500)
696               GameFrameDelay = GAME_FRAME_DELAY;
697             else
698               GameFrameDelay = 500;
699           }
700           else
701             GameFrameDelay = (key - KSYM_0) * 10;
702           printf("Game speed == %d%% (%d ms delay between two frames)\n",
703                  GAME_FRAME_DELAY * 100 / GameFrameDelay, GameFrameDelay);
704           break;
705
706         case KSYM_d:
707           if (options.debug)
708           {
709             options.debug = FALSE;
710             printf("debug mode disabled\n");
711           }
712           else
713           {
714             options.debug = TRUE;
715             printf("debug mode enabled\n");
716           }
717           break;
718
719         case KSYM_s:
720           if (!global.fps_slowdown)
721           {
722             global.fps_slowdown = TRUE;
723             global.fps_slowdown_factor = 2;
724             printf("fps slowdown enabled -- display only every 2nd frame\n");
725           }
726           else if (global.fps_slowdown_factor == 2)
727           {
728             global.fps_slowdown_factor = 4;
729             printf("fps slowdown enabled -- display only every 4th frame\n");
730           }
731           else
732           {
733             global.fps_slowdown = FALSE;
734             global.fps_slowdown_factor = 1;
735             printf("fps slowdown disabled\n");
736           }
737           break;
738
739 #if 0
740         case KSYM_a:
741           if (ScrollStepSize == TILEX/8)
742             ScrollStepSize = TILEX/4;
743           else
744             ScrollStepSize = TILEX/8;
745           printf("ScrollStepSize == %d\n", ScrollStepSize);
746           break;
747 #endif
748
749 #if 0
750         case KSYM_m:
751           if (MoveSpeed == 8)
752           {
753             MoveSpeed = 4;
754             ScrollStepSize = TILEX/4;
755           }
756           else
757           {
758             MoveSpeed = 8;
759             ScrollStepSize = TILEX/8;
760           }
761           printf("MoveSpeed == %d\n", MoveSpeed);
762           break;
763 #endif
764
765         case KSYM_f:
766           ScrollStepSize = TILEX/8;
767           printf("ScrollStepSize == %d (1/8)\n", ScrollStepSize);
768           break;
769
770         case KSYM_g:
771           ScrollStepSize = TILEX/4;
772           printf("ScrollStepSize == %d (1/4)\n", ScrollStepSize);
773           break;
774
775         case KSYM_h:
776           ScrollStepSize = TILEX/2;
777           printf("ScrollStepSize == %d (1/2)\n", ScrollStepSize);
778           break;
779
780         case KSYM_l:
781           ScrollStepSize = TILEX;
782           printf("ScrollStepSize == %d (1/1)\n", ScrollStepSize);
783           break;
784
785         case KSYM_Q:
786         case KSYM_q:
787           {
788             int i;
789
790             for (i = 0; i < MAX_INVENTORY_SIZE; i++)
791               if (local_player->inventory_size < MAX_INVENTORY_SIZE)
792                 local_player->inventory_element[local_player->inventory_size++] =
793                   EL_DYNAMITE;
794           }
795
796           break;
797
798
799 #if 0
800
801         case KSYM_z:
802           {
803             int i;
804
805             for (i = 0; i < MAX_PLAYERS; i++)
806             {
807               printf("Player %d:\n", i);
808               printf("  jx == %d, jy == %d\n",
809                      stored_player[i].jx, stored_player[i].jy);
810               printf("  last_jx == %d, last_jy == %d\n",
811                      stored_player[i].last_jx, stored_player[i].last_jy);
812             }
813             printf("\n");
814           }
815
816           break;
817 #endif
818 #endif
819
820         default:
821           break;
822       }
823       break;
824     }
825     default:
826       if (key == KSYM_Escape)
827       {
828         game_status = GAME_MODE_MAIN;
829         DrawMainMenu();
830
831         return;
832       }
833   }
834 }
835
836 void HandleNoEvent()
837 {
838   if (button_status && game_status != GAME_MODE_PLAYING)
839   {
840     HandleButton(0, 0, -button_status);
841     return;
842   }
843
844 #if defined(PLATFORM_UNIX)
845   if (options.network)
846     HandleNetworking();
847 #endif
848
849   HandleJoystick();
850 }
851
852 static int HandleJoystickForAllPlayers()
853 {
854   int i;
855   int result = 0;
856
857   for (i = 0; i < MAX_PLAYERS; i++)
858   {
859     byte joy_action = 0;
860
861     /*
862     if (!setup.input[i].use_joystick)
863       continue;
864       */
865
866     joy_action = Joystick(i);
867     result |= joy_action;
868
869     if (!setup.input[i].use_joystick)
870       continue;
871
872     stored_player[i].action = joy_action;
873   }
874
875   return result;
876 }
877
878 void HandleJoystick()
879 {
880   int joystick  = HandleJoystickForAllPlayers();
881   int keyboard  = key_joystick_mapping;
882   int joy       = (joystick | keyboard);
883   int left      = joy & JOY_LEFT;
884   int right     = joy & JOY_RIGHT;
885   int up        = joy & JOY_UP;
886   int down      = joy & JOY_DOWN;
887   int button    = joy & JOY_BUTTON;
888   int newbutton = (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED);
889   int dx        = (left ? -1    : right ? 1     : 0);
890   int dy        = (up   ? -1    : down  ? 1     : 0);
891
892   switch(game_status)
893   {
894     case GAME_MODE_MAIN:
895     case GAME_MODE_LEVELS:
896     case GAME_MODE_SETUP:
897     case GAME_MODE_INFO:
898     {
899       static unsigned long joystickmove_delay = 0;
900
901       if (joystick && !button &&
902           !DelayReached(&joystickmove_delay, GADGET_FRAME_DELAY))
903         newbutton = dx = dy = 0;
904
905       if (game_status == GAME_MODE_MAIN)
906         HandleMainMenu(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
907       else if (game_status == GAME_MODE_LEVELS)
908         HandleChooseLevel(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
909       else if (game_status == GAME_MODE_SETUP)
910         HandleSetupScreen(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
911       else if (game_status == GAME_MODE_INFO)
912         HandleInfoScreen(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
913       break;
914     }
915
916     case GAME_MODE_SCORES:
917       HandleHallOfFame(0,0, dx,dy, !newbutton);
918       break;
919
920     case GAME_MODE_EDITOR:
921       HandleLevelEditorIdle();
922       break;
923
924     case GAME_MODE_PLAYING:
925       if (tape.playing || keyboard)
926         newbutton = ((joy & JOY_BUTTON) != 0);
927
928       if (AllPlayersGone && newbutton)
929       {
930         CloseDoor(DOOR_CLOSE_1);
931         game_status = GAME_MODE_MAIN;
932         DrawMainMenu();
933         return;
934       }
935
936       break;
937
938     default:
939       break;
940   }
941 }