rnd-20030614-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 /* values for key_status */
27 #define KEY_NOT_PRESSED         FALSE
28 #define KEY_RELEASED            FALSE
29 #define KEY_PRESSED             TRUE
30
31
32 static boolean cursor_inside_playfield = FALSE;
33 static boolean playfield_cursor_set = FALSE;
34 static unsigned long playfield_cursor_delay = 0;
35
36
37 /* event filter especially needed for SDL event filtering due to
38    delay problems with lots of mouse motion events when mouse button
39    not pressed (X11 can handle this with 'PointerMotionHintMask') */
40
41 int FilterMouseMotionEvents(const Event *event)
42 {
43   MotionEvent *motion;
44
45   /* non-motion events are directly passed to event handler functions */
46   if (event->type != EVENT_MOTIONNOTIFY)
47     return 1;
48
49   motion = (MotionEvent *)event;
50   cursor_inside_playfield = (motion->x >= SX && motion->x < SX + SXSIZE &&
51                              motion->y >= SY && motion->y < SY + SYSIZE);
52
53   if (game_status == GAME_MODE_PLAYING && playfield_cursor_set)
54   {
55     SetMouseCursor(CURSOR_DEFAULT);
56     playfield_cursor_set = FALSE;
57     DelayReached(&playfield_cursor_delay, 0);
58   }
59
60   /* skip mouse motion events without pressed button outside level editor */
61   if (button_status == MB_RELEASED && game_status != GAME_MODE_EDITOR &&
62       game_status != GAME_MODE_PLAYING)
63     return 0;
64   else
65     return 1;
66 }
67
68 /* this is only really needed for non-SDL targets to filter unwanted events;
69    when using SDL with properly installed event filter, this function can be
70    replaced with a simple "NextEvent()" call, but it doesn't hurt either */
71
72 static boolean NextValidEvent(Event *event)
73 {
74   while (PendingEvent())
75   {
76     NextEvent(event);
77
78     if (FilterMouseMotionEvents(event))
79       return TRUE;
80   }
81
82   return FALSE;
83 }
84
85 void EventLoop(void)
86 {
87   while(1)
88   {
89     if (PendingEvent())         /* got event */
90     {
91       Event event;
92
93       if (NextValidEvent(&event))
94       {
95         switch(event.type)
96         {
97           case EVENT_BUTTONPRESS:
98           case EVENT_BUTTONRELEASE:
99             HandleButtonEvent((ButtonEvent *) &event);
100             break;
101   
102           case EVENT_MOTIONNOTIFY:
103             HandleMotionEvent((MotionEvent *) &event);
104             break;
105   
106           case EVENT_KEYPRESS:
107           case EVENT_KEYRELEASE:
108             HandleKeyEvent((KeyEvent *) &event);
109             break;
110   
111           default:
112             HandleOtherEvents(&event);
113             break;
114         }
115       }
116     }
117     else
118     {
119       /* when playing, display a special mouse pointer inside the playfield */
120       if (game_status == GAME_MODE_PLAYING)
121       {
122         if (!playfield_cursor_set && cursor_inside_playfield &&
123             DelayReached(&playfield_cursor_delay, 1000))
124         {
125           SetMouseCursor(CURSOR_PLAYFIELD);
126           playfield_cursor_set = TRUE;
127         }
128       }
129       else if (playfield_cursor_set)
130       {
131         SetMouseCursor(CURSOR_DEFAULT);
132         playfield_cursor_set = FALSE;
133       }
134
135       HandleNoEvent();
136     }
137
138     /* don't use all CPU time when idle; the main loop while playing
139        has its own synchronization and is CPU friendly, too */
140
141     if (game_status == GAME_MODE_PLAYING)
142       HandleGameActions();
143     else
144     {
145       SyncDisplay();
146       if (!PendingEvent())      /* delay only if no pending events */
147         Delay(10);
148     }
149
150     /* refresh window contents from drawing buffer, if needed */
151     BackToFront();
152
153     if (game_status == GAME_MODE_QUIT)
154       return;
155   }
156 }
157
158 void HandleOtherEvents(Event *event)
159 {
160   switch(event->type)
161   {
162     case EVENT_EXPOSE:
163       HandleExposeEvent((ExposeEvent *) event);
164       break;
165
166     case EVENT_UNMAPNOTIFY:
167 #if 0
168       /* This causes the game to stop not only when iconified, but also
169          when on another virtual desktop, which might be not desired. */
170       SleepWhileUnmapped();
171 #endif
172       break;
173
174     case EVENT_FOCUSIN:
175     case EVENT_FOCUSOUT:
176       HandleFocusEvent((FocusChangeEvent *) event);
177       break;
178
179     case EVENT_CLIENTMESSAGE:
180       HandleClientMessageEvent((ClientMessageEvent *) event);
181       break;
182
183 #if defined(TARGET_SDL)
184     case SDL_JOYAXISMOTION:
185     case SDL_JOYBUTTONDOWN:
186     case SDL_JOYBUTTONUP:
187       HandleJoystickEvent(event);
188       break;
189 #endif
190
191     default:
192       break;
193   }
194 }
195
196 void ClearEventQueue()
197 {
198   while (PendingEvent())
199   {
200     Event event;
201
202     NextEvent(&event);
203
204     switch(event.type)
205     {
206       case EVENT_BUTTONRELEASE:
207         button_status = MB_RELEASED;
208         break;
209
210       case EVENT_KEYRELEASE:
211         key_joystick_mapping = 0;
212         break;
213
214       default:
215         HandleOtherEvents(&event);
216         break;
217     }
218   }
219 }
220
221 void ClearPlayerAction()
222 {
223   int i;
224
225   /* simulate key release events for still pressed keys */
226   key_joystick_mapping = 0;
227   for (i=0; i<MAX_PLAYERS; i++)
228     stored_player[i].action = 0;
229 }
230
231 void SleepWhileUnmapped()
232 {
233   boolean window_unmapped = TRUE;
234
235   KeyboardAutoRepeatOn();
236
237   while(window_unmapped)
238   {
239     Event event;
240
241     NextEvent(&event);
242
243     switch(event.type)
244     {
245       case EVENT_BUTTONRELEASE:
246         button_status = MB_RELEASED;
247         break;
248
249       case EVENT_KEYRELEASE:
250         key_joystick_mapping = 0;
251         break;
252
253       case EVENT_MAPNOTIFY:
254         window_unmapped = FALSE;
255         break;
256
257       case EVENT_UNMAPNOTIFY:
258         /* this is only to surely prevent the 'should not happen' case
259          * of recursively looping between 'SleepWhileUnmapped()' and
260          * 'HandleOtherEvents()' which usually calls this funtion.
261          */
262         break;
263
264       default:
265         HandleOtherEvents(&event);
266         break;
267     }
268   }
269
270   if (game_status == GAME_MODE_PLAYING)
271     KeyboardAutoRepeatOffUnlessAutoplay();
272 }
273
274 void HandleExposeEvent(ExposeEvent *event)
275 {
276 #ifndef TARGET_SDL
277   RedrawPlayfield(FALSE, event->x, event->y, event->width, event->height);
278   FlushDisplay();
279 #endif
280 }
281
282 void HandleButtonEvent(ButtonEvent *event)
283 {
284   motion_status = FALSE;
285
286   if (event->type == EVENT_BUTTONPRESS)
287     button_status = event->button;
288   else
289     button_status = MB_RELEASED;
290
291   HandleButton(event->x, event->y, button_status);
292 }
293
294 void HandleMotionEvent(MotionEvent *event)
295 {
296   if (!PointerInWindow(window))
297     return;     /* window and pointer are on different screens */
298
299 #if 1
300   if (button_status == MB_RELEASED && game_status != GAME_MODE_EDITOR)
301     return;
302 #endif
303
304   motion_status = TRUE;
305
306   HandleButton(event->x, event->y, button_status);
307 }
308
309 void HandleKeyEvent(KeyEvent *event)
310 {
311   int key_status = (event->type==EVENT_KEYPRESS ? KEY_PRESSED : KEY_RELEASED);
312   boolean with_modifiers = (game_status == GAME_MODE_PLAYING ? FALSE : TRUE);
313   Key key = GetEventKey(event, with_modifiers);
314
315   HandleKey(key, key_status);
316 }
317
318 void HandleFocusEvent(FocusChangeEvent *event)
319 {
320   static int old_joystick_status = -1;
321
322   if (event->type == EVENT_FOCUSOUT)
323   {
324     KeyboardAutoRepeatOn();
325     old_joystick_status = joystick.status;
326     joystick.status = JOYSTICK_NOT_AVAILABLE;
327
328     ClearPlayerAction();
329   }
330   else if (event->type == EVENT_FOCUSIN)
331   {
332     /* When there are two Rocks'n'Diamonds windows which overlap and
333        the player moves the pointer from one game window to the other,
334        a 'FocusOut' event is generated for the window the pointer is
335        leaving and a 'FocusIn' event is generated for the window the
336        pointer is entering. In some cases, it can happen that the
337        'FocusIn' event is handled by the one game process before the
338        'FocusOut' event by the other game process. In this case the
339        X11 environment would end up with activated keyboard auto repeat,
340        because unfortunately this is a global setting and not (which
341        would be far better) set for each X11 window individually.
342        The effect would be keyboard auto repeat while playing the game
343        (game_status == GAME_MODE_PLAYING), which is not desired.
344        To avoid this special case, we just wait 1/10 second before
345        processing the 'FocusIn' event.
346     */
347
348     if (game_status == GAME_MODE_PLAYING)
349     {
350       Delay(100);
351       KeyboardAutoRepeatOffUnlessAutoplay();
352     }
353     if (old_joystick_status != -1)
354       joystick.status = old_joystick_status;
355   }
356 }
357
358 void HandleClientMessageEvent(ClientMessageEvent *event)
359 {
360   if (CheckCloseWindowEvent(event))
361     CloseAllAndExit(0);
362 }
363
364 void HandleButton(int mx, int my, int button)
365 {
366   static int old_mx = 0, old_my = 0;
367
368   if (button < 0)
369   {
370     mx = old_mx;
371     my = old_my;
372     button = -button;
373   }
374   else
375   {
376     old_mx = mx;
377     old_my = my;
378   }
379
380   HandleGadgets(mx, my, button);
381
382   switch(game_status)
383   {
384     case GAME_MODE_MAIN:
385       HandleMainMenu(mx,my, 0,0, button);
386       break;
387
388     case GAME_MODE_PSEUDO_TYPENAME:
389       HandleTypeName(0, KSYM_Return);
390       break;
391
392     case GAME_MODE_LEVELS:
393       HandleChooseLevel(mx,my, 0,0, button);
394       break;
395
396     case GAME_MODE_SCORES:
397       HandleHallOfFame(0,0, 0,0, button);
398       break;
399
400     case GAME_MODE_EDITOR:
401       break;
402
403     case GAME_MODE_INFO:
404       HandleHelpScreen(button);
405       break;
406
407     case GAME_MODE_SETUP:
408       HandleSetupScreen(mx,my, 0,0, button);
409       break;
410
411     case GAME_MODE_PLAYING:
412 #ifdef DEBUG
413       if (button == MB_RELEASED)
414       {
415         int sx = (mx - SX) / TILEX;
416         int sy = (my - SY) / TILEY;
417
418         if (IN_VIS_FIELD(sx,sy))
419         {
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\n", x,y, Feld[x][y]);
429           printf("      Store[%d][%d] == %d\n", x,y, Store[x][y]);
430           printf("      Store2[%d][%d] == %d\n", x,y, Store2[x][y]);
431           printf("      StorePlayer[%d][%d] == %d\n", x,y, StorePlayer[x][y]);
432           printf("      MovPos[%d][%d] == %d\n", x,y, MovPos[x][y]);
433           printf("      MovDir[%d][%d] == %d\n", x,y, MovDir[x][y]);
434           printf("      MovDelay[%d][%d] == %d\n", x,y, MovDelay[x][y]);
435           printf("      ChangeDelay[%d][%d] == %d\n", x,y, ChangeDelay[x][y]);
436           printf("      GfxElement[%d][%d] == %d\n", x,y, GfxElement[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           local_player->dynamite = 1000;
798           break;
799
800
801
802 #if 0
803
804         case KSYM_z:
805           {
806             int i;
807
808             for(i=0; i<MAX_PLAYERS; i++)
809             {
810               printf("Player %d:\n", i);
811               printf("  jx == %d, jy == %d\n",
812                      stored_player[i].jx, stored_player[i].jy);
813               printf("  last_jx == %d, last_jy == %d\n",
814                      stored_player[i].last_jx, stored_player[i].last_jy);
815             }
816             printf("\n");
817           }
818
819           break;
820 #endif
821 #endif
822
823         default:
824           break;
825       }
826       break;
827     }
828     default:
829       break;
830   }
831 }
832
833 void HandleNoEvent()
834 {
835   if (button_status && game_status != GAME_MODE_PLAYING)
836   {
837     HandleButton(0, 0, -button_status);
838     return;
839   }
840
841 #if defined(PLATFORM_UNIX)
842   if (options.network)
843     HandleNetworking();
844 #endif
845
846   HandleJoystick();
847 }
848
849 static int HandleJoystickForAllPlayers()
850 {
851   int i;
852   int result = 0;
853
854   for (i=0; i<MAX_PLAYERS; i++)
855   {
856     byte joy_action = 0;
857
858     /*
859     if (!setup.input[i].use_joystick)
860       continue;
861       */
862
863     joy_action = Joystick(i);
864     result |= joy_action;
865
866     if (!setup.input[i].use_joystick)
867       continue;
868
869     stored_player[i].action = joy_action;
870   }
871
872   return result;
873 }
874
875 void HandleJoystick()
876 {
877   int joystick  = HandleJoystickForAllPlayers();
878   int keyboard  = key_joystick_mapping;
879   int joy       = (joystick | keyboard);
880   int left      = joy & JOY_LEFT;
881   int right     = joy & JOY_RIGHT;
882   int up        = joy & JOY_UP;
883   int down      = joy & JOY_DOWN;
884   int button    = joy & JOY_BUTTON;
885   int newbutton = (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED);
886   int dx        = (left ? -1    : right ? 1     : 0);
887   int dy        = (up   ? -1    : down  ? 1     : 0);
888
889   switch(game_status)
890   {
891     case GAME_MODE_MAIN:
892     case GAME_MODE_LEVELS:
893     case GAME_MODE_SETUP:
894     {
895       static unsigned long joystickmove_delay = 0;
896
897       if (joystick && !button &&
898           !DelayReached(&joystickmove_delay, GADGET_FRAME_DELAY))
899         newbutton = dx = dy = 0;
900
901       if (game_status == GAME_MODE_MAIN)
902         HandleMainMenu(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
903       else if (game_status == GAME_MODE_LEVELS)
904         HandleChooseLevel(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
905       else if (game_status == GAME_MODE_SETUP)
906         HandleSetupScreen(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
907       break;
908     }
909
910     case GAME_MODE_SCORES:
911       HandleHallOfFame(0,0, dx,dy, !newbutton);
912       break;
913
914     case GAME_MODE_INFO:
915       HandleHelpScreen(!newbutton);
916       break;
917
918     case GAME_MODE_EDITOR:
919       HandleLevelEditorIdle();
920       break;
921
922     case GAME_MODE_PLAYING:
923       if (tape.playing || keyboard)
924         newbutton = ((joy & JOY_BUTTON) != 0);
925
926       if (AllPlayersGone && newbutton)
927       {
928         CloseDoor(DOOR_CLOSE_1);
929         game_status = GAME_MODE_MAIN;
930         DrawMainMenu();
931         return;
932       }
933
934       break;
935
936     default:
937       break;
938   }
939 }