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