rnd-20020420-1-src
[rocksndiamonds.git] / src / events.c
1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back!               *
3 *----------------------------------------------------------*
4 * (c) 1995-2001 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 /* event filter especially needed for SDL event filtering due to
33    delay problems with lots of mouse motion events when mouse
34    button not pressed */
35
36 int FilterMouseMotionEvents(const Event *event)
37 {
38   if (event->type != EVENT_MOTIONNOTIFY)
39     return 1;
40
41   /* get mouse motion events without pressed button only in level editor */
42   if (button_status == MB_RELEASED && game_status != LEVELED)
43     return 0;
44   else
45     return 1;
46 }
47
48 /* this is only really needed for non-SDL targets to filter unwanted events;
49    when using SDL with properly installed event filter, this function can be
50    replaced with a simple "NextEvent()" call, but it doesn't hurt either */
51
52 static boolean NextValidEvent(Event *event)
53 {
54   while (PendingEvent())
55   {
56     NextEvent(event);
57
58     if (FilterMouseMotionEvents(event))
59       return TRUE;
60   }
61
62   return FALSE;
63 }
64
65 void EventLoop(void)
66 {
67   while(1)
68   {
69     if (PendingEvent())         /* got event */
70     {
71       Event event;
72
73       if (NextValidEvent(&event))
74       {
75         switch(event.type)
76         {
77           case EVENT_BUTTONPRESS:
78           case EVENT_BUTTONRELEASE:
79             HandleButtonEvent((ButtonEvent *) &event);
80             break;
81   
82           case EVENT_MOTIONNOTIFY:
83             HandleMotionEvent((MotionEvent *) &event);
84             break;
85   
86           case EVENT_KEYPRESS:
87           case EVENT_KEYRELEASE:
88             HandleKeyEvent((KeyEvent *) &event);
89             break;
90   
91           default:
92             HandleOtherEvents(&event);
93             break;
94         }
95       }
96     }
97     else
98       HandleNoEvent();
99
100     /* don't use all CPU time when idle; the main loop while playing
101        has its own synchronization and is CPU friendly, too */
102
103     if (game_status == PLAYING)
104       HandleGameActions();
105     else
106     {
107       SyncDisplay();
108       if (!PendingEvent())      /* delay only if no pending events */
109         Delay(10);
110     }
111
112     /* refresh window contents from drawing buffer, if needed */
113     BackToFront();
114
115     if (game_status == EXITGAME)
116       return;
117   }
118 }
119
120 void HandleOtherEvents(Event *event)
121 {
122   switch(event->type)
123   {
124     case EVENT_EXPOSE:
125       HandleExposeEvent((ExposeEvent *) event);
126       break;
127
128     case EVENT_UNMAPNOTIFY:
129       SleepWhileUnmapped();
130       break;
131
132     case EVENT_FOCUSIN:
133     case EVENT_FOCUSOUT:
134       HandleFocusEvent((FocusChangeEvent *) event);
135       break;
136
137     case EVENT_CLIENTMESSAGE:
138       HandleClientMessageEvent((ClientMessageEvent *) event);
139       break;
140
141 #if defined(TARGET_SDL)
142     case SDL_JOYAXISMOTION:
143     case SDL_JOYBUTTONDOWN:
144     case SDL_JOYBUTTONUP:
145       HandleJoystickEvent(event);
146       break;
147 #endif
148
149     default:
150       break;
151   }
152 }
153
154 void ClearEventQueue()
155 {
156   while (PendingEvent())
157   {
158     Event event;
159
160     NextEvent(&event);
161
162     switch(event.type)
163     {
164       case EVENT_BUTTONRELEASE:
165         button_status = MB_RELEASED;
166         break;
167
168       case EVENT_KEYRELEASE:
169         key_joystick_mapping = 0;
170         break;
171
172       default:
173         HandleOtherEvents(&event);
174         break;
175     }
176   }
177 }
178
179 void ClearPlayerAction()
180 {
181   int i;
182
183   /* simulate key release events for still pressed keys */
184   key_joystick_mapping = 0;
185   for (i=0; i<MAX_PLAYERS; i++)
186     stored_player[i].action = 0;
187 }
188
189 void SleepWhileUnmapped()
190 {
191   boolean window_unmapped = TRUE;
192
193   KeyboardAutoRepeatOn();
194
195   while(window_unmapped)
196   {
197     Event event;
198
199     NextEvent(&event);
200
201     switch(event.type)
202     {
203       case EVENT_BUTTONRELEASE:
204         button_status = MB_RELEASED;
205         break;
206
207       case EVENT_KEYRELEASE:
208         key_joystick_mapping = 0;
209         break;
210
211       case EVENT_MAPNOTIFY:
212         window_unmapped = FALSE;
213         break;
214
215       case EVENT_UNMAPNOTIFY:
216         /* this is only to surely prevent the 'should not happen' case
217          * of recursively looping between 'SleepWhileUnmapped()' and
218          * 'HandleOtherEvents()' which usually calls this funtion.
219          */
220         break;
221
222       default:
223         HandleOtherEvents(&event);
224         break;
225     }
226   }
227
228   if (game_status == PLAYING)
229     KeyboardAutoRepeatOff();
230 }
231
232 void HandleExposeEvent(ExposeEvent *event)
233 {
234 #ifndef TARGET_SDL
235   RedrawPlayfield(FALSE, event->x, event->y, event->width, event->height);
236   FlushDisplay();
237 #endif
238 }
239
240 void HandleButtonEvent(ButtonEvent *event)
241 {
242   motion_status = FALSE;
243
244   if (event->type == EVENT_BUTTONPRESS)
245     button_status = event->button;
246   else
247     button_status = MB_RELEASED;
248
249   HandleButton(event->x, event->y, button_status);
250 }
251
252 void HandleMotionEvent(MotionEvent *event)
253 {
254   if (!PointerInWindow(window))
255     return;     /* window and pointer are on different screens */
256
257 #if 1
258   if (button_status == MB_RELEASED && game_status != LEVELED)
259     return;
260 #endif
261
262   motion_status = TRUE;
263
264   HandleButton(event->x, event->y, button_status);
265 }
266
267 void HandleKeyEvent(KeyEvent *event)
268 {
269   int key_status = (event->type==EVENT_KEYPRESS ? KEY_PRESSED : KEY_RELEASED);
270   boolean with_modifiers = (game_status == PLAYING ? FALSE : TRUE);
271   Key key = GetEventKey(event, with_modifiers);
272
273   HandleKey(key, key_status);
274 }
275
276 void HandleFocusEvent(FocusChangeEvent *event)
277 {
278   static int old_joystick_status = -1;
279
280   if (event->type == EVENT_FOCUSOUT)
281   {
282     KeyboardAutoRepeatOn();
283     old_joystick_status = joystick.status;
284     joystick.status = JOYSTICK_NOT_AVAILABLE;
285
286     ClearPlayerAction();
287   }
288   else if (event->type == EVENT_FOCUSIN)
289   {
290     /* When there are two Rocks'n'Diamonds windows which overlap and
291        the player moves the pointer from one game window to the other,
292        a 'FocusOut' event is generated for the window the pointer is
293        leaving and a 'FocusIn' event is generated for the window the
294        pointer is entering. In some cases, it can happen that the
295        'FocusIn' event is handled by the one game process before the
296        'FocusOut' event by the other game process. In this case the
297        X11 environment would end up with activated keyboard auto repeat,
298        because unfortunately this is a global setting and not (which
299        would be far better) set for each X11 window individually.
300        The effect would be keyboard auto repeat while playing the game
301        (game_status == PLAYING), which is not desired.
302        To avoid this special case, we just wait 1/10 second before
303        processing the 'FocusIn' event.
304     */
305
306     if (game_status == PLAYING)
307     {
308       Delay(100);
309       KeyboardAutoRepeatOff();
310     }
311     if (old_joystick_status != -1)
312       joystick.status = old_joystick_status;
313   }
314 }
315
316 void HandleClientMessageEvent(ClientMessageEvent *event)
317 {
318   if (CheckCloseWindowEvent(event))
319     CloseAllAndExit(0);
320 }
321
322 void HandleButton(int mx, int my, int button)
323 {
324   static int old_mx = 0, old_my = 0;
325
326   if (button < 0)
327   {
328     mx = old_mx;
329     my = old_my;
330     button = -button;
331   }
332   else
333   {
334     old_mx = mx;
335     old_my = my;
336   }
337
338   HandleGadgets(mx, my, button);
339
340   switch(game_status)
341   {
342     case MAINMENU:
343       HandleMainMenu(mx,my, 0,0, button);
344       break;
345
346     case TYPENAME:
347       HandleTypeName(0, KSYM_Return);
348       break;
349
350     case CHOOSELEVEL:
351       HandleChooseLevel(mx,my, 0,0, button);
352       break;
353
354     case HALLOFFAME:
355       HandleHallOfFame(0,0, 0,0, button);
356       break;
357
358     case LEVELED:
359       break;
360
361     case HELPSCREEN:
362       HandleHelpScreen(button);
363       break;
364
365     case SETUP:
366       HandleSetupScreen(mx,my, 0,0, button);
367       break;
368
369     case PLAYING:
370 #ifdef DEBUG
371       if (button == MB_RELEASED)
372       {
373         int sx = (mx - SX) / TILEX;
374         int sy = (my - SY) / TILEY;
375
376         if (IN_VIS_FIELD(sx,sy))
377         {
378           int x = LEVELX(sx);
379           int y = LEVELY(sy);
380
381           printf("INFO: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
382
383           if (!IN_LEV_FIELD(x, y))
384             break;
385
386           printf("      Feld[%d][%d] == %d\n", x,y, Feld[x][y]);
387           printf("      Store[%d][%d] == %d\n", x,y, Store[x][y]);
388           printf("      Store2[%d][%d] == %d\n", x,y, Store2[x][y]);
389           printf("      StorePlayer[%d][%d] == %d\n", x,y, StorePlayer[x][y]);
390           printf("      MovPos[%d][%d] == %d\n", x,y, MovPos[x][y]);
391           printf("      MovDir[%d][%d] == %d\n", x,y, MovDir[x][y]);
392           printf("      MovDelay[%d][%d] == %d\n", x,y, MovDelay[x][y]);
393           printf("\n");
394         }
395       }
396 #endif
397       break;
398
399     default:
400       break;
401   }
402 }
403
404 void HandleKey(Key key, int key_status)
405 {
406   int joy = 0;
407   boolean anyTextGadgetActiveOrJustFinished = anyTextGadgetActive();
408   static struct SetupKeyboardInfo custom_key;
409   static struct
410   {
411     Key *key_custom;
412     Key key_default;
413     byte action;
414   } key_info[] =
415   {
416     { &custom_key.left,  DEFAULT_KEY_LEFT,  JOY_LEFT     },
417     { &custom_key.right, DEFAULT_KEY_RIGHT, JOY_RIGHT    },
418     { &custom_key.up,    DEFAULT_KEY_UP,    JOY_UP       },
419     { &custom_key.down,  DEFAULT_KEY_DOWN,  JOY_DOWN     },
420     { &custom_key.snap,  DEFAULT_KEY_SNAP,  JOY_BUTTON_1 },
421     { &custom_key.bomb,  DEFAULT_KEY_BOMB,  JOY_BUTTON_2 }
422   };
423
424   if (game_status == PLAYING)
425   {
426     /* only needed for single-step tape recording mode */
427     static boolean clear_button_2[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
428     static boolean bomb_placed[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
429     int pnr;
430
431     for (pnr=0; pnr<MAX_PLAYERS; pnr++)
432     {
433       int i;
434       byte key_action = 0;
435
436       if (setup.input[pnr].use_joystick)
437         continue;
438
439       custom_key = setup.input[pnr].key;
440
441       for (i=0; i<6; i++)
442         if (key == *key_info[i].key_custom)
443           key_action |= key_info[i].action;
444
445       if (tape.single_step && clear_button_2[pnr])
446       {
447         stored_player[pnr].action &= ~KEY_BUTTON_2;
448         clear_button_2[pnr] = FALSE;
449       }
450
451       if (key_status == KEY_PRESSED)
452         stored_player[pnr].action |= key_action;
453       else
454         stored_player[pnr].action &= ~key_action;
455
456       if (tape.single_step && tape.recording && tape.pausing)
457       {
458         if (key_status == KEY_PRESSED &&
459             (key_action & (KEY_MOTION | KEY_BUTTON_1)))
460         {
461           TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
462
463           if (key_action & KEY_MOTION)
464           {
465             if (stored_player[pnr].action & KEY_BUTTON_2)
466               bomb_placed[pnr] = TRUE;
467           }
468         }
469         else if (key_status == KEY_RELEASED &&
470                  (key_action & KEY_BUTTON_2))
471         {
472           if (!bomb_placed[pnr])
473           {
474             TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
475
476             stored_player[pnr].action |= KEY_BUTTON_2;
477             clear_button_2[pnr] = TRUE;
478           }
479
480           bomb_placed[pnr] = FALSE;
481         }
482       }
483       else if (tape.recording && tape.pausing && (key_action & KEY_ACTION))
484         TapeTogglePause(TAPE_TOGGLE_MANUAL);
485     }
486   }
487   else
488   {
489     int i;
490
491     for (i=0; i<6; i++)
492       if (key == key_info[i].key_default)
493         joy |= key_info[i].action;
494   }
495
496   if (joy)
497   {
498     if (key_status == KEY_PRESSED)
499       key_joystick_mapping |= joy;
500     else
501       key_joystick_mapping &= ~joy;
502
503     HandleJoystick();
504   }
505
506   if (game_status != PLAYING)
507     key_joystick_mapping = 0;
508
509   if (key_status == KEY_RELEASED)
510     return;
511
512   if ((key == KSYM_Return || key == setup.shortcut.toggle_pause) &&
513       game_status == PLAYING && AllPlayersGone)
514   {
515     CloseDoor(DOOR_CLOSE_1);
516     game_status = MAINMENU;
517     DrawMainMenu();
518     return;
519   }
520
521   /* allow quick escape to the main menu with the Escape key */
522   if (key == KSYM_Escape &&
523       game_status != MAINMENU &&
524       game_status != PLAYING &&
525       game_status != LEVELED &&
526       game_status != CHOOSELEVEL &&
527       game_status != SETUP)
528   {
529     game_status = MAINMENU;
530     DrawMainMenu();
531     return;
532   }
533
534   /* special key shortcuts */
535   if (game_status == MAINMENU || game_status == PLAYING)
536   {
537     if (key == setup.shortcut.save_game)
538       TapeQuickSave();
539     else if (key == setup.shortcut.load_game)
540       TapeQuickLoad();
541     else if (key == setup.shortcut.toggle_pause)
542       TapeTogglePause(TAPE_TOGGLE_MANUAL);
543   }
544
545
546 #ifndef DEBUG
547
548   if (game_status == PLAYING && (tape.playing || tape.pausing))
549     return;
550
551 #endif
552
553
554
555   HandleGadgetsKeyInput(key);
556
557   switch(game_status)
558   {
559     case TYPENAME:
560       HandleTypeName(0, key);
561       break;
562
563     case MAINMENU:
564     case CHOOSELEVEL:
565     case SETUP:
566       switch(key)
567       {
568         case KSYM_Return:
569           if (game_status == MAINMENU)
570             HandleMainMenu(0,0, 0,0, MB_MENU_CHOICE);
571           else if (game_status == CHOOSELEVEL)
572             HandleChooseLevel(0,0, 0,0, MB_MENU_CHOICE);
573           else if (game_status == SETUP)
574             HandleSetupScreen(0,0, 0,0, MB_MENU_CHOICE);
575           break;
576
577         case KSYM_Escape:
578           if (game_status == CHOOSELEVEL)
579             HandleChooseLevel(0,0, 0,0, MB_MENU_LEAVE);
580           else if (game_status == SETUP)
581             HandleSetupScreen(0,0, 0,0, MB_MENU_LEAVE);
582           break;
583
584         case KSYM_Page_Up:
585           if (game_status == CHOOSELEVEL)
586             HandleChooseLevel(0,0, 0,-SCR_FIELDY, MB_MENU_MARK);
587           break;
588
589         case KSYM_Page_Down:
590           if (game_status == CHOOSELEVEL)
591             HandleChooseLevel(0,0, 0,SCR_FIELDY, MB_MENU_MARK);
592           break;
593
594 #ifdef DEBUG
595         case KSYM_t:
596           DumpTape(&tape);
597           break;
598 #endif
599
600         default:
601           break;
602       }
603       break;
604
605     case HELPSCREEN:
606       HandleHelpScreen(MB_RELEASED);
607       break;
608
609     case HALLOFFAME:
610       switch(key)
611       {
612         case KSYM_Return:
613           game_status = MAINMENU;
614           DrawMainMenu();
615           BackToFront();
616           break;
617
618         case KSYM_Page_Up:
619           HandleHallOfFame(0,0, 0,-SCR_FIELDY, MB_MENU_MARK);
620           break;
621
622         case KSYM_Page_Down:
623           HandleHallOfFame(0,0, 0,SCR_FIELDY, MB_MENU_MARK);
624           break;
625
626         default:
627           break;
628       }
629       break;
630
631     case LEVELED:
632       if (!anyTextGadgetActiveOrJustFinished || key == KSYM_Escape)
633         HandleLevelEditorKeyInput(key);
634       break;
635
636     case PLAYING:
637     {
638       switch(key)
639       {
640         case KSYM_Escape:
641           RequestQuitGame(setup.ask_on_escape);
642           break;
643
644 #ifdef DEBUG
645         case KSYM_0:
646         case KSYM_1:
647         case KSYM_2:
648         case KSYM_3:
649         case KSYM_4:
650         case KSYM_5:
651         case KSYM_6:
652         case KSYM_7:
653         case KSYM_8:
654         case KSYM_9:
655           if (key == KSYM_0)
656           {
657             if (GameFrameDelay == 500)
658               GameFrameDelay = GAME_FRAME_DELAY;
659             else
660               GameFrameDelay = 500;
661           }
662           else
663             GameFrameDelay = (key - KSYM_0) * 10;
664           printf("Game speed == %d%% (%d ms delay between two frames)\n",
665                  GAME_FRAME_DELAY * 100 / GameFrameDelay, GameFrameDelay);
666           break;
667
668         case KSYM_d:
669           if (options.debug)
670           {
671             options.debug = FALSE;
672             printf("debug mode disabled\n");
673           }
674           else
675           {
676             options.debug = TRUE;
677             printf("debug mode enabled\n");
678           }
679           break;
680
681         case KSYM_s:
682           if (!global.fps_slowdown)
683           {
684             global.fps_slowdown = TRUE;
685             global.fps_slowdown_factor = 2;
686             printf("fps slowdown enabled -- display only every 2nd frame\n");
687           }
688           else if (global.fps_slowdown_factor == 2)
689           {
690             global.fps_slowdown_factor = 4;
691             printf("fps slowdown enabled -- display only every 4th frame\n");
692           }
693           else
694           {
695             global.fps_slowdown = FALSE;
696             global.fps_slowdown_factor = 1;
697             printf("fps slowdown disabled\n");
698           }
699           break;
700
701 #if 0
702         case KSYM_a:
703           if (ScrollStepSize == TILEX/8)
704             ScrollStepSize = TILEX/4;
705           else
706             ScrollStepSize = TILEX/8;
707           printf("ScrollStepSize == %d\n", ScrollStepSize);
708           break;
709 #endif
710
711 #if 0
712         case KSYM_m:
713           if (MoveSpeed == 8)
714           {
715             MoveSpeed = 4;
716             ScrollStepSize = TILEX/4;
717           }
718           else
719           {
720             MoveSpeed = 8;
721             ScrollStepSize = TILEX/8;
722           }
723           printf("MoveSpeed == %d\n", MoveSpeed);
724           break;
725 #endif
726
727         case KSYM_f:
728           ScrollStepSize = TILEX/8;
729           printf("ScrollStepSize == %d (1/8)\n", ScrollStepSize);
730           break;
731
732         case KSYM_g:
733           ScrollStepSize = TILEX/4;
734           printf("ScrollStepSize == %d (1/4)\n", ScrollStepSize);
735           break;
736
737         case KSYM_h:
738           ScrollStepSize = TILEX/2;
739           printf("ScrollStepSize == %d (1/2)\n", ScrollStepSize);
740           break;
741
742         case KSYM_l:
743           ScrollStepSize = TILEX;
744           printf("ScrollStepSize == %d (1/1)\n", ScrollStepSize);
745           break;
746
747         case KSYM_Q:
748         case KSYM_q:
749           local_player->dynamite = 1000;
750           break;
751
752
753
754 #if 0
755
756         case KSYM_z:
757           {
758             int i;
759
760             for(i=0; i<MAX_PLAYERS; i++)
761             {
762               printf("Player %d:\n", i);
763               printf("  jx == %d, jy == %d\n",
764                      stored_player[i].jx, stored_player[i].jy);
765               printf("  last_jx == %d, last_jy == %d\n",
766                      stored_player[i].last_jx, stored_player[i].last_jy);
767             }
768             printf("\n");
769           }
770
771           break;
772 #endif
773 #endif
774
775         default:
776           break;
777       }
778       break;
779     }
780     default:
781       break;
782   }
783 }
784
785 void HandleNoEvent()
786 {
787   if (button_status && game_status != PLAYING)
788   {
789     HandleButton(0, 0, -button_status);
790     return;
791   }
792
793 #if defined(PLATFORM_UNIX)
794   if (options.network)
795     HandleNetworking();
796 #endif
797
798   HandleJoystick();
799 }
800
801 static int HandleJoystickForAllPlayers()
802 {
803   int i;
804   int result = 0;
805
806   for (i=0; i<MAX_PLAYERS; i++)
807   {
808     byte joy_action = 0;
809
810     /*
811     if (!setup.input[i].use_joystick)
812       continue;
813       */
814
815     joy_action = Joystick(i);
816     result |= joy_action;
817
818     if (!setup.input[i].use_joystick)
819       continue;
820
821     stored_player[i].action = joy_action;
822   }
823
824   return result;
825 }
826
827 void HandleJoystick()
828 {
829   int joystick  = HandleJoystickForAllPlayers();
830   int keyboard  = key_joystick_mapping;
831   int joy       = (joystick | keyboard);
832   int left      = joy & JOY_LEFT;
833   int right     = joy & JOY_RIGHT;
834   int up        = joy & JOY_UP;
835   int down      = joy & JOY_DOWN;
836   int button    = joy & JOY_BUTTON;
837   int newbutton = (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED);
838   int dx        = (left ? -1    : right ? 1     : 0);
839   int dy        = (up   ? -1    : down  ? 1     : 0);
840
841   switch(game_status)
842   {
843     case MAINMENU:
844     case CHOOSELEVEL:
845     case SETUP:
846     {
847       static unsigned long joystickmove_delay = 0;
848
849       if (joystick && !button &&
850           !DelayReached(&joystickmove_delay, GADGET_FRAME_DELAY))
851         newbutton = dx = dy = 0;
852
853       if (game_status==MAINMENU)
854         HandleMainMenu(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
855       else if (game_status==CHOOSELEVEL)
856         HandleChooseLevel(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
857       else if (game_status==SETUP)
858         HandleSetupScreen(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
859       break;
860     }
861
862     case HALLOFFAME:
863       HandleHallOfFame(0,0, dx,dy, !newbutton);
864       break;
865
866     case HELPSCREEN:
867       HandleHelpScreen(!newbutton);
868       break;
869
870     case PLAYING:
871       if (tape.playing || keyboard)
872         newbutton = ((joy & JOY_BUTTON) != 0);
873
874       if (AllPlayersGone && newbutton)
875       {
876         CloseDoor(DOOR_CLOSE_1);
877         game_status = MAINMENU;
878         DrawMainMenu();
879         return;
880       }
881
882       break;
883
884     default:
885       break;
886   }
887 }