rnd-20030417-3-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 == 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 != LEVELED)
62     return 0;
63   else
64     return 1;
65 }
66
67 /* this is only really needed for non-SDL targets to filter unwanted events;
68    when using SDL with properly installed event filter, this function can be
69    replaced with a simple "NextEvent()" call, but it doesn't hurt either */
70
71 static boolean NextValidEvent(Event *event)
72 {
73   while (PendingEvent())
74   {
75     NextEvent(event);
76
77     if (FilterMouseMotionEvents(event))
78       return TRUE;
79   }
80
81   return FALSE;
82 }
83
84 void EventLoop(void)
85 {
86   while(1)
87   {
88     if (PendingEvent())         /* got event */
89     {
90       Event event;
91
92       if (NextValidEvent(&event))
93       {
94         switch(event.type)
95         {
96           case EVENT_BUTTONPRESS:
97           case EVENT_BUTTONRELEASE:
98             HandleButtonEvent((ButtonEvent *) &event);
99             break;
100   
101           case EVENT_MOTIONNOTIFY:
102             HandleMotionEvent((MotionEvent *) &event);
103             break;
104   
105           case EVENT_KEYPRESS:
106           case EVENT_KEYRELEASE:
107             HandleKeyEvent((KeyEvent *) &event);
108             break;
109   
110           default:
111             HandleOtherEvents(&event);
112             break;
113         }
114       }
115     }
116     else
117     {
118       /* when playing, display a special mouse pointer inside the playfield */
119       if (game_status == PLAYING)
120       {
121         if (!playfield_cursor_set && cursor_inside_playfield &&
122             DelayReached(&playfield_cursor_delay, 1000))
123         {
124           SetMouseCursor(CURSOR_PLAYFIELD);
125           playfield_cursor_set = TRUE;
126         }
127       }
128       else if (playfield_cursor_set)
129       {
130         SetMouseCursor(CURSOR_DEFAULT);
131         playfield_cursor_set = FALSE;
132       }
133
134       HandleNoEvent();
135     }
136
137     /* don't use all CPU time when idle; the main loop while playing
138        has its own synchronization and is CPU friendly, too */
139
140     if (game_status == PLAYING)
141       HandleGameActions();
142     else
143     {
144       SyncDisplay();
145       if (!PendingEvent())      /* delay only if no pending events */
146         Delay(10);
147     }
148
149     /* refresh window contents from drawing buffer, if needed */
150     BackToFront();
151
152     if (game_status == EXITGAME)
153       return;
154   }
155 }
156
157 void HandleOtherEvents(Event *event)
158 {
159   switch(event->type)
160   {
161     case EVENT_EXPOSE:
162       HandleExposeEvent((ExposeEvent *) event);
163       break;
164
165     case EVENT_UNMAPNOTIFY:
166 #if 0
167       /* This causes the game to stop not only when iconified, but also
168          when on another virtual desktop, which might be not desired. */
169       SleepWhileUnmapped();
170 #endif
171       break;
172
173     case EVENT_FOCUSIN:
174     case EVENT_FOCUSOUT:
175       HandleFocusEvent((FocusChangeEvent *) event);
176       break;
177
178     case EVENT_CLIENTMESSAGE:
179       HandleClientMessageEvent((ClientMessageEvent *) event);
180       break;
181
182 #if defined(TARGET_SDL)
183     case SDL_JOYAXISMOTION:
184     case SDL_JOYBUTTONDOWN:
185     case SDL_JOYBUTTONUP:
186       HandleJoystickEvent(event);
187       break;
188 #endif
189
190     default:
191       break;
192   }
193 }
194
195 void ClearEventQueue()
196 {
197   while (PendingEvent())
198   {
199     Event event;
200
201     NextEvent(&event);
202
203     switch(event.type)
204     {
205       case EVENT_BUTTONRELEASE:
206         button_status = MB_RELEASED;
207         break;
208
209       case EVENT_KEYRELEASE:
210         key_joystick_mapping = 0;
211         break;
212
213       default:
214         HandleOtherEvents(&event);
215         break;
216     }
217   }
218 }
219
220 void ClearPlayerAction()
221 {
222   int i;
223
224   /* simulate key release events for still pressed keys */
225   key_joystick_mapping = 0;
226   for (i=0; i<MAX_PLAYERS; i++)
227     stored_player[i].action = 0;
228 }
229
230 void SleepWhileUnmapped()
231 {
232   boolean window_unmapped = TRUE;
233
234   KeyboardAutoRepeatOn();
235
236   while(window_unmapped)
237   {
238     Event event;
239
240     NextEvent(&event);
241
242     switch(event.type)
243     {
244       case EVENT_BUTTONRELEASE:
245         button_status = MB_RELEASED;
246         break;
247
248       case EVENT_KEYRELEASE:
249         key_joystick_mapping = 0;
250         break;
251
252       case EVENT_MAPNOTIFY:
253         window_unmapped = FALSE;
254         break;
255
256       case EVENT_UNMAPNOTIFY:
257         /* this is only to surely prevent the 'should not happen' case
258          * of recursively looping between 'SleepWhileUnmapped()' and
259          * 'HandleOtherEvents()' which usually calls this funtion.
260          */
261         break;
262
263       default:
264         HandleOtherEvents(&event);
265         break;
266     }
267   }
268
269   if (game_status == PLAYING)
270     KeyboardAutoRepeatOff();
271 }
272
273 void HandleExposeEvent(ExposeEvent *event)
274 {
275 #ifndef TARGET_SDL
276   RedrawPlayfield(FALSE, event->x, event->y, event->width, event->height);
277   FlushDisplay();
278 #endif
279 }
280
281 void HandleButtonEvent(ButtonEvent *event)
282 {
283   motion_status = FALSE;
284
285   if (event->type == EVENT_BUTTONPRESS)
286     button_status = event->button;
287   else
288     button_status = MB_RELEASED;
289
290   HandleButton(event->x, event->y, button_status);
291 }
292
293 void HandleMotionEvent(MotionEvent *event)
294 {
295   if (!PointerInWindow(window))
296     return;     /* window and pointer are on different screens */
297
298 #if 1
299   if (button_status == MB_RELEASED && game_status != LEVELED)
300     return;
301 #endif
302
303   motion_status = TRUE;
304
305   HandleButton(event->x, event->y, button_status);
306 }
307
308 void HandleKeyEvent(KeyEvent *event)
309 {
310   int key_status = (event->type==EVENT_KEYPRESS ? KEY_PRESSED : KEY_RELEASED);
311   boolean with_modifiers = (game_status == PLAYING ? FALSE : TRUE);
312   Key key = GetEventKey(event, with_modifiers);
313
314   HandleKey(key, key_status);
315 }
316
317 void HandleFocusEvent(FocusChangeEvent *event)
318 {
319   static int old_joystick_status = -1;
320
321   if (event->type == EVENT_FOCUSOUT)
322   {
323     KeyboardAutoRepeatOn();
324     old_joystick_status = joystick.status;
325     joystick.status = JOYSTICK_NOT_AVAILABLE;
326
327     ClearPlayerAction();
328   }
329   else if (event->type == EVENT_FOCUSIN)
330   {
331     /* When there are two Rocks'n'Diamonds windows which overlap and
332        the player moves the pointer from one game window to the other,
333        a 'FocusOut' event is generated for the window the pointer is
334        leaving and a 'FocusIn' event is generated for the window the
335        pointer is entering. In some cases, it can happen that the
336        'FocusIn' event is handled by the one game process before the
337        'FocusOut' event by the other game process. In this case the
338        X11 environment would end up with activated keyboard auto repeat,
339        because unfortunately this is a global setting and not (which
340        would be far better) set for each X11 window individually.
341        The effect would be keyboard auto repeat while playing the game
342        (game_status == PLAYING), which is not desired.
343        To avoid this special case, we just wait 1/10 second before
344        processing the 'FocusIn' event.
345     */
346
347     if (game_status == PLAYING)
348     {
349       Delay(100);
350       KeyboardAutoRepeatOff();
351     }
352     if (old_joystick_status != -1)
353       joystick.status = old_joystick_status;
354   }
355 }
356
357 void HandleClientMessageEvent(ClientMessageEvent *event)
358 {
359   if (CheckCloseWindowEvent(event))
360     CloseAllAndExit(0);
361 }
362
363 void HandleButton(int mx, int my, int button)
364 {
365   static int old_mx = 0, old_my = 0;
366
367   if (button < 0)
368   {
369     mx = old_mx;
370     my = old_my;
371     button = -button;
372   }
373   else
374   {
375     old_mx = mx;
376     old_my = my;
377   }
378
379   HandleGadgets(mx, my, button);
380
381   switch(game_status)
382   {
383     case MAINMENU:
384       HandleMainMenu(mx,my, 0,0, button);
385       break;
386
387     case TYPENAME:
388       HandleTypeName(0, KSYM_Return);
389       break;
390
391     case CHOOSELEVEL:
392       HandleChooseLevel(mx,my, 0,0, button);
393       break;
394
395     case HALLOFFAME:
396       HandleHallOfFame(0,0, 0,0, button);
397       break;
398
399     case LEVELED:
400       break;
401
402     case HELPSCREEN:
403       HandleHelpScreen(button);
404       break;
405
406     case SETUP:
407       HandleSetupScreen(mx,my, 0,0, button);
408       break;
409
410     case PLAYING:
411 #ifdef DEBUG
412       if (button == MB_RELEASED)
413       {
414         int sx = (mx - SX) / TILEX;
415         int sy = (my - SY) / TILEY;
416
417         if (IN_VIS_FIELD(sx,sy))
418         {
419           int x = LEVELX(sx);
420           int y = LEVELY(sy);
421
422           printf("INFO: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
423
424           if (!IN_LEV_FIELD(x, y))
425             break;
426
427           printf("      Feld[%d][%d] == %d\n", x,y, Feld[x][y]);
428           printf("      Store[%d][%d] == %d\n", x,y, Store[x][y]);
429           printf("      Store2[%d][%d] == %d\n", x,y, Store2[x][y]);
430           printf("      StorePlayer[%d][%d] == %d\n", x,y, StorePlayer[x][y]);
431           printf("      MovPos[%d][%d] == %d\n", x,y, MovPos[x][y]);
432           printf("      MovDir[%d][%d] == %d\n", x,y, MovDir[x][y]);
433           printf("      MovDelay[%d][%d] == %d\n", x,y, MovDelay[x][y]);
434           printf("      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 == 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 != 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 == PLAYING && AllPlayersGone)
556   {
557     CloseDoor(DOOR_CLOSE_1);
558     game_status = MAINMENU;
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 != MAINMENU &&
566       game_status != PLAYING &&
567       game_status != LEVELED &&
568       game_status != CHOOSELEVEL &&
569       game_status != SETUP)
570   {
571     game_status = MAINMENU;
572     DrawMainMenu();
573     return;
574   }
575
576   /* special key shortcuts */
577   if (game_status == MAINMENU || game_status == 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 == 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 TYPENAME:
602       HandleTypeName(0, key);
603       break;
604
605     case MAINMENU:
606     case CHOOSELEVEL:
607     case SETUP:
608       switch(key)
609       {
610         case KSYM_Return:
611           if (game_status == MAINMENU)
612             HandleMainMenu(0,0, 0,0, MB_MENU_CHOICE);
613           else if (game_status == CHOOSELEVEL)
614             HandleChooseLevel(0,0, 0,0, MB_MENU_CHOICE);
615           else if (game_status == SETUP)
616             HandleSetupScreen(0,0, 0,0, MB_MENU_CHOICE);
617           break;
618
619         case KSYM_Escape:
620           if (game_status == CHOOSELEVEL)
621             HandleChooseLevel(0,0, 0,0, MB_MENU_LEAVE);
622           else if (game_status == SETUP)
623             HandleSetupScreen(0,0, 0,0, MB_MENU_LEAVE);
624           break;
625
626         case KSYM_Page_Up:
627           if (game_status == CHOOSELEVEL)
628             HandleChooseLevel(0,0, 0,-SCR_FIELDY, MB_MENU_MARK);
629           else if (game_status == SETUP)
630             HandleSetupScreen(0,0, 0,-SCR_FIELDY, MB_MENU_MARK);
631           break;
632
633         case KSYM_Page_Down:
634           if (game_status == CHOOSELEVEL)
635             HandleChooseLevel(0,0, 0,SCR_FIELDY, MB_MENU_MARK);
636           else if (game_status == SETUP)
637             HandleSetupScreen(0,0, 0,SCR_FIELDY, 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 HELPSCREEN:
652       HandleHelpScreen(MB_RELEASED);
653       break;
654
655     case HALLOFFAME:
656       switch(key)
657       {
658         case KSYM_Return:
659           game_status = MAINMENU;
660           DrawMainMenu();
661           BackToFront();
662           break;
663
664         case KSYM_Page_Up:
665           HandleHallOfFame(0,0, 0,-SCR_FIELDY, MB_MENU_MARK);
666           break;
667
668         case KSYM_Page_Down:
669           HandleHallOfFame(0,0, 0,SCR_FIELDY, MB_MENU_MARK);
670           break;
671
672         default:
673           break;
674       }
675       break;
676
677     case LEVELED:
678       if (!anyTextGadgetActiveOrJustFinished || key == KSYM_Escape)
679         HandleLevelEditorKeyInput(key);
680       break;
681
682     case 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 != 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 MAINMENU:
890     case CHOOSELEVEL:
891     case 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 == MAINMENU)
900         HandleMainMenu(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
901       else if (game_status == CHOOSELEVEL)
902         HandleChooseLevel(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
903       else if (game_status == SETUP)
904         HandleSetupScreen(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
905       break;
906     }
907
908     case HALLOFFAME:
909       HandleHallOfFame(0,0, dx,dy, !newbutton);
910       break;
911
912     case HELPSCREEN:
913       HandleHelpScreen(!newbutton);
914       break;
915
916     case LEVELED:
917       HandleLevelEditorIdle();
918       break;
919
920     case 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 = MAINMENU;
928         DrawMainMenu();
929         return;
930       }
931
932       break;
933
934     default:
935       break;
936   }
937 }