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