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