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