rnd-20031205-B-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("      RunnerVisit[%d][%d] == %d\n", x,y, RunnerVisit[x][y]);
442           printf("      PlayerVisit[%d][%d] == %d\n", x,y, PlayerVisit[x][y]);
443           printf("\n");
444         }
445       }
446 #endif
447       break;
448
449     default:
450       break;
451   }
452 }
453
454 void HandleKey(Key key, int key_status)
455 {
456   int joy = 0;
457   boolean anyTextGadgetActiveOrJustFinished = anyTextGadgetActive();
458   static struct SetupKeyboardInfo custom_key;
459   static struct
460   {
461     Key *key_custom;
462     Key key_default;
463     byte action;
464   } key_info[] =
465   {
466     { &custom_key.left,  DEFAULT_KEY_LEFT,  JOY_LEFT     },
467     { &custom_key.right, DEFAULT_KEY_RIGHT, JOY_RIGHT    },
468     { &custom_key.up,    DEFAULT_KEY_UP,    JOY_UP       },
469     { &custom_key.down,  DEFAULT_KEY_DOWN,  JOY_DOWN     },
470     { &custom_key.snap,  DEFAULT_KEY_SNAP,  JOY_BUTTON_1 },
471     { &custom_key.bomb,  DEFAULT_KEY_BOMB,  JOY_BUTTON_2 }
472   };
473
474   if (game_status == GAME_MODE_PLAYING)
475   {
476     /* only needed for single-step tape recording mode */
477     static boolean clear_button_2[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
478     static boolean bomb_placed[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
479     int pnr;
480
481     for (pnr = 0; pnr < MAX_PLAYERS; pnr++)
482     {
483       int i;
484       byte key_action = 0;
485
486       if (setup.input[pnr].use_joystick)
487         continue;
488
489       custom_key = setup.input[pnr].key;
490
491       for (i = 0; i < 6; i++)
492         if (key == *key_info[i].key_custom)
493           key_action |= key_info[i].action;
494
495       if (tape.single_step && clear_button_2[pnr])
496       {
497         stored_player[pnr].action &= ~KEY_BUTTON_2;
498         clear_button_2[pnr] = FALSE;
499       }
500
501       if (key_status == KEY_PRESSED)
502         stored_player[pnr].action |= key_action;
503       else
504         stored_player[pnr].action &= ~key_action;
505
506       if (tape.single_step && tape.recording && tape.pausing)
507       {
508         if (key_status == KEY_PRESSED &&
509             (key_action & (KEY_MOTION | KEY_BUTTON_1)))
510         {
511           TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
512
513           if (key_action & KEY_MOTION)
514           {
515             if (stored_player[pnr].action & KEY_BUTTON_2)
516               bomb_placed[pnr] = TRUE;
517           }
518         }
519         else if (key_status == KEY_RELEASED &&
520                  (key_action & KEY_BUTTON_2))
521         {
522           if (!bomb_placed[pnr])
523           {
524             TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
525
526             stored_player[pnr].action |= KEY_BUTTON_2;
527             clear_button_2[pnr] = TRUE;
528           }
529
530           bomb_placed[pnr] = FALSE;
531         }
532       }
533       else if (tape.recording && tape.pausing && (key_action & KEY_ACTION))
534         TapeTogglePause(TAPE_TOGGLE_MANUAL);
535     }
536   }
537   else
538   {
539     int i;
540
541     for (i = 0; i < 6; i++)
542       if (key == key_info[i].key_default)
543         joy |= key_info[i].action;
544   }
545
546   if (joy)
547   {
548     if (key_status == KEY_PRESSED)
549       key_joystick_mapping |= joy;
550     else
551       key_joystick_mapping &= ~joy;
552
553     HandleJoystick();
554   }
555
556   if (game_status != GAME_MODE_PLAYING)
557     key_joystick_mapping = 0;
558
559   if (key_status == KEY_RELEASED)
560     return;
561
562   if ((key == KSYM_Return || key == setup.shortcut.toggle_pause) &&
563       game_status == GAME_MODE_PLAYING && AllPlayersGone)
564   {
565     CloseDoor(DOOR_CLOSE_1);
566     game_status = GAME_MODE_MAIN;
567     DrawMainMenu();
568     return;
569   }
570
571   /* special key shortcuts */
572   if (game_status == GAME_MODE_MAIN || game_status == GAME_MODE_PLAYING)
573   {
574     if (key == setup.shortcut.save_game)
575       TapeQuickSave();
576     else if (key == setup.shortcut.load_game)
577       TapeQuickLoad();
578     else if (key == setup.shortcut.toggle_pause)
579       TapeTogglePause(TAPE_TOGGLE_MANUAL);
580   }
581
582   if (HandleGadgetsKeyInput(key))
583   {
584     if (key != KSYM_Escape)     /* always allow ESC key to be handled */
585       key = KSYM_UNDEFINED;
586   }
587
588   switch(game_status)
589   {
590     case GAME_MODE_PSEUDO_TYPENAME:
591       HandleTypeName(0, key);
592       break;
593
594     case GAME_MODE_MAIN:
595     case GAME_MODE_LEVELS:
596     case GAME_MODE_SETUP:
597     case GAME_MODE_INFO:
598       switch(key)
599       {
600         case KSYM_Return:
601           if (game_status == GAME_MODE_MAIN)
602             HandleMainMenu(0,0, 0,0, MB_MENU_CHOICE);
603           else if (game_status == GAME_MODE_LEVELS)
604             HandleChooseLevel(0,0, 0,0, MB_MENU_CHOICE);
605           else if (game_status == GAME_MODE_SETUP)
606             HandleSetupScreen(0,0, 0,0, MB_MENU_CHOICE);
607           else if (game_status == GAME_MODE_INFO)
608             HandleInfoScreen(0,0, 0,0, MB_MENU_CHOICE);
609           break;
610
611         case KSYM_Escape:
612           if (game_status == GAME_MODE_LEVELS)
613             HandleChooseLevel(0,0, 0,0, MB_MENU_LEAVE);
614           else if (game_status == GAME_MODE_SETUP)
615             HandleSetupScreen(0,0, 0,0, MB_MENU_LEAVE);
616           else if (game_status == GAME_MODE_INFO)
617             HandleInfoScreen(0,0, 0,0, MB_MENU_LEAVE);
618           break;
619
620         case KSYM_Page_Up:
621           if (game_status == GAME_MODE_LEVELS)
622             HandleChooseLevel(0,0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
623           else if (game_status == GAME_MODE_SETUP)
624             HandleSetupScreen(0,0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
625           else if (game_status == GAME_MODE_INFO)
626             HandleInfoScreen(0,0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
627           break;
628
629         case KSYM_Page_Down:
630           if (game_status == GAME_MODE_LEVELS)
631             HandleChooseLevel(0,0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
632           else if (game_status == GAME_MODE_SETUP)
633             HandleSetupScreen(0,0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
634           else if (game_status == GAME_MODE_INFO)
635             HandleInfoScreen(0,0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
636           break;
637
638 #ifdef DEBUG
639         case KSYM_t:
640           DumpTape(&tape);
641           break;
642 #endif
643
644         default:
645           break;
646       }
647       break;
648
649     case GAME_MODE_SCORES:
650       switch(key)
651       {
652         case KSYM_Return:
653         case KSYM_Escape:
654           game_status = GAME_MODE_MAIN;
655           DrawMainMenu();
656           break;
657
658         case KSYM_Page_Up:
659           HandleHallOfFame(0,0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
660           break;
661
662         case KSYM_Page_Down:
663           HandleHallOfFame(0,0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
664           break;
665
666         default:
667           break;
668       }
669       break;
670
671     case GAME_MODE_EDITOR:
672       if (!anyTextGadgetActiveOrJustFinished || key == KSYM_Escape)
673         HandleLevelEditorKeyInput(key);
674       break;
675
676     case GAME_MODE_PLAYING:
677     {
678       switch(key)
679       {
680         case KSYM_Escape:
681           RequestQuitGame(setup.ask_on_escape);
682           break;
683
684 #ifdef DEBUG
685         case KSYM_0:
686         case KSYM_1:
687         case KSYM_2:
688         case KSYM_3:
689         case KSYM_4:
690         case KSYM_5:
691         case KSYM_6:
692         case KSYM_7:
693         case KSYM_8:
694         case KSYM_9:
695           if (key == KSYM_0)
696           {
697             if (GameFrameDelay == 500)
698               GameFrameDelay = GAME_FRAME_DELAY;
699             else
700               GameFrameDelay = 500;
701           }
702           else
703             GameFrameDelay = (key - KSYM_0) * 10;
704           printf("Game speed == %d%% (%d ms delay between two frames)\n",
705                  GAME_FRAME_DELAY * 100 / GameFrameDelay, GameFrameDelay);
706           break;
707
708         case KSYM_d:
709           if (options.debug)
710           {
711             options.debug = FALSE;
712             printf("debug mode disabled\n");
713           }
714           else
715           {
716             options.debug = TRUE;
717             printf("debug mode enabled\n");
718           }
719           break;
720
721         case KSYM_s:
722           if (!global.fps_slowdown)
723           {
724             global.fps_slowdown = TRUE;
725             global.fps_slowdown_factor = 2;
726             printf("fps slowdown enabled -- display only every 2nd frame\n");
727           }
728           else if (global.fps_slowdown_factor == 2)
729           {
730             global.fps_slowdown_factor = 4;
731             printf("fps slowdown enabled -- display only every 4th frame\n");
732           }
733           else
734           {
735             global.fps_slowdown = FALSE;
736             global.fps_slowdown_factor = 1;
737             printf("fps slowdown disabled\n");
738           }
739           break;
740
741 #if 0
742         case KSYM_a:
743           if (ScrollStepSize == TILEX/8)
744             ScrollStepSize = TILEX/4;
745           else
746             ScrollStepSize = TILEX/8;
747           printf("ScrollStepSize == %d\n", ScrollStepSize);
748           break;
749 #endif
750
751 #if 0
752         case KSYM_m:
753           if (MoveSpeed == 8)
754           {
755             MoveSpeed = 4;
756             ScrollStepSize = TILEX/4;
757           }
758           else
759           {
760             MoveSpeed = 8;
761             ScrollStepSize = TILEX/8;
762           }
763           printf("MoveSpeed == %d\n", MoveSpeed);
764           break;
765 #endif
766
767         case KSYM_f:
768           ScrollStepSize = TILEX/8;
769           printf("ScrollStepSize == %d (1/8)\n", ScrollStepSize);
770           break;
771
772         case KSYM_g:
773           ScrollStepSize = TILEX/4;
774           printf("ScrollStepSize == %d (1/4)\n", ScrollStepSize);
775           break;
776
777         case KSYM_h:
778           ScrollStepSize = TILEX/2;
779           printf("ScrollStepSize == %d (1/2)\n", ScrollStepSize);
780           break;
781
782         case KSYM_l:
783           ScrollStepSize = TILEX;
784           printf("ScrollStepSize == %d (1/1)\n", ScrollStepSize);
785           break;
786
787         case KSYM_Q:
788         case KSYM_q:
789           {
790             int i;
791
792             for (i = 0; i < MAX_INVENTORY_SIZE; i++)
793               if (local_player->inventory_size < MAX_INVENTORY_SIZE)
794                 local_player->inventory_element[local_player->inventory_size++] =
795                   EL_DYNAMITE;
796           }
797
798           break;
799
800
801 #if 0
802
803         case KSYM_z:
804           {
805             int i;
806
807             for (i = 0; i < MAX_PLAYERS; i++)
808             {
809               printf("Player %d:\n", i);
810               printf("  jx == %d, jy == %d\n",
811                      stored_player[i].jx, stored_player[i].jy);
812               printf("  last_jx == %d, last_jy == %d\n",
813                      stored_player[i].last_jx, stored_player[i].last_jy);
814             }
815             printf("\n");
816           }
817
818           break;
819 #endif
820 #endif
821
822         default:
823           break;
824       }
825       break;
826     }
827     default:
828       if (key == KSYM_Escape)
829       {
830         game_status = GAME_MODE_MAIN;
831         DrawMainMenu();
832
833         return;
834       }
835   }
836 }
837
838 void HandleNoEvent()
839 {
840   if (button_status && game_status != GAME_MODE_PLAYING)
841   {
842     HandleButton(0, 0, -button_status);
843     return;
844   }
845
846 #if defined(PLATFORM_UNIX)
847   if (options.network)
848     HandleNetworking();
849 #endif
850
851   HandleJoystick();
852 }
853
854 static int HandleJoystickForAllPlayers()
855 {
856   int i;
857   int result = 0;
858
859   for (i = 0; i < MAX_PLAYERS; i++)
860   {
861     byte joy_action = 0;
862
863     /*
864     if (!setup.input[i].use_joystick)
865       continue;
866       */
867
868     joy_action = Joystick(i);
869     result |= joy_action;
870
871     if (!setup.input[i].use_joystick)
872       continue;
873
874     stored_player[i].action = joy_action;
875   }
876
877   return result;
878 }
879
880 void HandleJoystick()
881 {
882   int joystick  = HandleJoystickForAllPlayers();
883   int keyboard  = key_joystick_mapping;
884   int joy       = (joystick | keyboard);
885   int left      = joy & JOY_LEFT;
886   int right     = joy & JOY_RIGHT;
887   int up        = joy & JOY_UP;
888   int down      = joy & JOY_DOWN;
889   int button    = joy & JOY_BUTTON;
890   int newbutton = (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED);
891   int dx        = (left ? -1    : right ? 1     : 0);
892   int dy        = (up   ? -1    : down  ? 1     : 0);
893
894   switch(game_status)
895   {
896     case GAME_MODE_MAIN:
897     case GAME_MODE_LEVELS:
898     case GAME_MODE_SETUP:
899     case GAME_MODE_INFO:
900     {
901       static unsigned long joystickmove_delay = 0;
902
903       if (joystick && !button &&
904           !DelayReached(&joystickmove_delay, GADGET_FRAME_DELAY))
905         newbutton = dx = dy = 0;
906
907       if (game_status == GAME_MODE_MAIN)
908         HandleMainMenu(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
909       else if (game_status == GAME_MODE_LEVELS)
910         HandleChooseLevel(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
911       else if (game_status == GAME_MODE_SETUP)
912         HandleSetupScreen(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
913       else if (game_status == GAME_MODE_INFO)
914         HandleInfoScreen(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
915       break;
916     }
917
918     case GAME_MODE_SCORES:
919       HandleHallOfFame(0,0, dx,dy, !newbutton);
920       break;
921
922     case GAME_MODE_EDITOR:
923       HandleLevelEditorIdle();
924       break;
925
926     case GAME_MODE_PLAYING:
927       if (tape.playing || keyboard)
928         newbutton = ((joy & JOY_BUTTON) != 0);
929
930       if (AllPlayersGone && newbutton)
931       {
932         CloseDoor(DOOR_CLOSE_1);
933         game_status = GAME_MODE_MAIN;
934         DrawMainMenu();
935         return;
936       }
937
938       break;
939
940     default:
941       break;
942   }
943 }