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