1 // ============================================================================
2 // Rocks'n'Diamonds - McDuffin Strikes Back!
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
7 // http://www.artsoft.org/
8 // ----------------------------------------------------------------------------
10 // ============================================================================
12 #include "libgame/libgame.h"
25 #define DEBUG_EVENTS 0
27 #define DEBUG_EVENTS_BUTTON (DEBUG_EVENTS * 0)
28 #define DEBUG_EVENTS_MOTION (DEBUG_EVENTS * 0)
29 #define DEBUG_EVENTS_WINDOW (DEBUG_EVENTS * 0)
30 #define DEBUG_EVENTS_FINGER (DEBUG_EVENTS * 0)
31 #define DEBUG_EVENTS_TEXT (DEBUG_EVENTS * 1)
32 #define DEBUG_EVENTS_KEY (DEBUG_EVENTS * 1)
35 static boolean cursor_inside_playfield = FALSE;
36 static int cursor_mode_last = CURSOR_DEFAULT;
37 static unsigned int special_cursor_delay = 0;
38 static unsigned int special_cursor_delay_value = 1000;
40 /* event filter especially needed for SDL event filtering due to
41 delay problems with lots of mouse motion events when mouse button
42 not pressed (X11 can handle this with 'PointerMotionHintMask') */
44 /* event filter addition for SDL2: as SDL2 does not have a function to enable
45 or disable keyboard auto-repeat, filter repeated keyboard events instead */
47 static int FilterEventsExt(const Event *event)
51 #if defined(TARGET_SDL2)
52 /* skip repeated key press events if keyboard auto-repeat is disabled */
53 if (event->type == EVENT_KEYPRESS &&
59 /* non-motion events are directly passed to event handler functions */
60 if (event->type != EVENT_MOTIONNOTIFY)
63 motion = (MotionEvent *)event;
64 cursor_inside_playfield = (motion->x >= SX && motion->x < SX + SXSIZE &&
65 motion->y >= SY && motion->y < SY + SYSIZE);
67 /* do no reset mouse cursor before all pending events have been processed */
68 if (gfx.cursor_mode == cursor_mode_last &&
69 ((effectiveGameStatus() == GAME_MODE_TITLE &&
70 gfx.cursor_mode == CURSOR_NONE) ||
71 (game_status == GAME_MODE_PLAYING &&
72 gfx.cursor_mode == CURSOR_PLAYFIELD)))
74 SetMouseCursor(CURSOR_DEFAULT);
76 DelayReached(&special_cursor_delay, 0);
78 cursor_mode_last = CURSOR_DEFAULT;
81 /* skip mouse motion events without pressed button outside level editor */
82 if (button_status == MB_RELEASED &&
83 game_status != GAME_MODE_EDITOR && game_status != GAME_MODE_PLAYING)
89 #if defined(TARGET_SDL2)
90 int FilterEvents(void *userdata, Event *event)
92 return FilterEventsExt(event);
95 int FilterEvents(const Event *event)
97 return FilterEventsExt(event);
101 /* to prevent delay problems, skip mouse motion events if the very next
102 event is also a mouse motion event (and therefore effectively only
103 handling the last of a row of mouse motion events in the event queue) */
105 boolean SkipPressedMouseMotionEvent(const Event *event)
107 /* nothing to do if the current event is not a mouse motion event */
108 if (event->type != EVENT_MOTIONNOTIFY)
111 /* only skip motion events with pressed button outside the game */
112 if (button_status == MB_RELEASED || game_status == GAME_MODE_PLAYING)
119 PeekEvent(&next_event);
121 /* if next event is also a mouse motion event, skip the current one */
122 if (next_event.type == EVENT_MOTIONNOTIFY)
129 /* this is only really needed for non-SDL targets to filter unwanted events;
130 when using SDL with properly installed event filter, this function can be
131 replaced with a simple "NextEvent()" call, but it doesn't hurt either */
133 boolean NextValidEvent(Event *event)
135 while (PendingEvent())
137 boolean handle_this_event = FALSE;
141 if (FilterEventsExt(event))
142 handle_this_event = TRUE;
144 if (SkipPressedMouseMotionEvent(event))
145 handle_this_event = FALSE;
147 if (handle_this_event)
158 if (PendingEvent()) /* got event */
162 while (NextValidEvent(&event))
166 case EVENT_BUTTONPRESS:
167 case EVENT_BUTTONRELEASE:
168 HandleButtonEvent((ButtonEvent *) &event);
171 case EVENT_MOTIONNOTIFY:
172 HandleMotionEvent((MotionEvent *) &event);
175 #if defined(TARGET_SDL2)
176 case SDL_WINDOWEVENT:
177 HandleWindowEvent((WindowEvent *) &event);
180 case EVENT_FINGERPRESS:
181 case EVENT_FINGERRELEASE:
182 case EVENT_FINGERMOTION:
183 HandleFingerEvent((FingerEvent *) &event);
186 case EVENT_TEXTINPUT:
187 HandleTextEvent((TextEvent *) &event);
190 case SDL_APP_WILLENTERBACKGROUND:
191 case SDL_APP_DIDENTERBACKGROUND:
192 case SDL_APP_WILLENTERFOREGROUND:
193 case SDL_APP_DIDENTERFOREGROUND:
194 HandlePauseResumeEvent((PauseResumeEvent *) &event);
199 case EVENT_KEYRELEASE:
200 HandleKeyEvent((KeyEvent *) &event);
204 HandleOtherEvents(&event);
211 if (effectiveGameStatus() == GAME_MODE_TITLE)
213 /* when showing title screens, hide mouse pointer (if not moved) */
215 if (gfx.cursor_mode != CURSOR_NONE &&
216 DelayReached(&special_cursor_delay, special_cursor_delay_value))
218 SetMouseCursor(CURSOR_NONE);
221 else if (game_status == GAME_MODE_PLAYING && !tape.pausing)
223 /* when playing, display a special mouse pointer inside the playfield */
225 if (gfx.cursor_mode != CURSOR_PLAYFIELD &&
226 cursor_inside_playfield &&
227 DelayReached(&special_cursor_delay, special_cursor_delay_value))
229 SetMouseCursor(CURSOR_PLAYFIELD);
232 else if (gfx.cursor_mode != CURSOR_DEFAULT)
234 SetMouseCursor(CURSOR_DEFAULT);
237 /* this is set after all pending events have been processed */
238 cursor_mode_last = gfx.cursor_mode;
241 /* also execute after pending events have been processed before */
244 /* don't use all CPU time when idle; the main loop while playing
245 has its own synchronization and is CPU friendly, too */
247 if (game_status == GAME_MODE_PLAYING)
253 if (!PendingEvent()) /* delay only if no pending events */
257 /* refresh window contents from drawing buffer, if needed */
260 if (game_status == GAME_MODE_QUIT)
265 void HandleOtherEvents(Event *event)
270 HandleExposeEvent((ExposeEvent *) event);
273 case EVENT_UNMAPNOTIFY:
275 /* This causes the game to stop not only when iconified, but also
276 when on another virtual desktop, which might be not desired. */
277 SleepWhileUnmapped();
283 HandleFocusEvent((FocusChangeEvent *) event);
286 case EVENT_CLIENTMESSAGE:
287 HandleClientMessageEvent((ClientMessageEvent *) event);
290 #if defined(TARGET_SDL)
291 case SDL_JOYAXISMOTION:
292 case SDL_JOYBUTTONDOWN:
293 case SDL_JOYBUTTONUP:
294 HandleJoystickEvent(event);
298 HandleWindowManagerEvent(event);
307 void ClearEventQueue()
309 while (PendingEvent())
317 case EVENT_BUTTONRELEASE:
318 button_status = MB_RELEASED;
321 case EVENT_KEYRELEASE:
326 HandleOtherEvents(&event);
332 void ClearPlayerAction()
336 /* simulate key release events for still pressed keys */
337 key_joystick_mapping = 0;
338 for (i = 0; i < MAX_PLAYERS; i++)
339 stored_player[i].action = 0;
342 void SleepWhileUnmapped()
344 boolean window_unmapped = TRUE;
346 KeyboardAutoRepeatOn();
348 while (window_unmapped)
356 case EVENT_BUTTONRELEASE:
357 button_status = MB_RELEASED;
360 case EVENT_KEYRELEASE:
361 key_joystick_mapping = 0;
364 case EVENT_MAPNOTIFY:
365 window_unmapped = FALSE;
368 case EVENT_UNMAPNOTIFY:
369 /* this is only to surely prevent the 'should not happen' case
370 * of recursively looping between 'SleepWhileUnmapped()' and
371 * 'HandleOtherEvents()' which usually calls this funtion.
376 HandleOtherEvents(&event);
381 if (game_status == GAME_MODE_PLAYING)
382 KeyboardAutoRepeatOffUnlessAutoplay();
385 void HandleExposeEvent(ExposeEvent *event)
389 void HandleButtonEvent(ButtonEvent *event)
391 #if DEBUG_EVENTS_BUTTON
392 Error(ERR_DEBUG, "BUTTON EVENT: button %d %s, x/y %d/%d\n",
394 event->type == EVENT_BUTTONPRESS ? "pressed" : "released",
398 motion_status = FALSE;
400 if (event->type == EVENT_BUTTONPRESS)
401 button_status = event->button;
403 button_status = MB_RELEASED;
405 HandleButton(event->x, event->y, button_status, event->button);
408 void HandleMotionEvent(MotionEvent *event)
410 if (!PointerInWindow(window))
411 return; /* window and pointer are on different screens */
413 if (button_status == MB_RELEASED && game_status != GAME_MODE_EDITOR)
416 motion_status = TRUE;
418 #if DEBUG_EVENTS_MOTION
419 Error(ERR_DEBUG, "MOTION EVENT: button %d moved, x/y %d/%d\n",
420 button_status, event->x, event->y);
423 HandleButton(event->x, event->y, button_status, button_status);
426 #if defined(TARGET_SDL2)
428 void HandleWindowEvent(WindowEvent *event)
430 #if DEBUG_EVENTS_WINDOW
431 int subtype = event->event;
434 (subtype == SDL_WINDOWEVENT_SHOWN ? "SDL_WINDOWEVENT_SHOWN" :
435 subtype == SDL_WINDOWEVENT_HIDDEN ? "SDL_WINDOWEVENT_HIDDEN" :
436 subtype == SDL_WINDOWEVENT_EXPOSED ? "SDL_WINDOWEVENT_EXPOSED" :
437 subtype == SDL_WINDOWEVENT_MOVED ? "SDL_WINDOWEVENT_MOVED" :
438 subtype == SDL_WINDOWEVENT_SIZE_CHANGED ? "SDL_WINDOWEVENT_SIZE_CHANGED" :
439 subtype == SDL_WINDOWEVENT_RESIZED ? "SDL_WINDOWEVENT_RESIZED" :
440 subtype == SDL_WINDOWEVENT_MINIMIZED ? "SDL_WINDOWEVENT_MINIMIZED" :
441 subtype == SDL_WINDOWEVENT_MAXIMIZED ? "SDL_WINDOWEVENT_MAXIMIZED" :
442 subtype == SDL_WINDOWEVENT_RESTORED ? "SDL_WINDOWEVENT_RESTORED" :
443 subtype == SDL_WINDOWEVENT_ENTER ? "SDL_WINDOWEVENT_ENTER" :
444 subtype == SDL_WINDOWEVENT_LEAVE ? "SDL_WINDOWEVENT_LEAVE" :
445 subtype == SDL_WINDOWEVENT_FOCUS_GAINED ? "SDL_WINDOWEVENT_FOCUS_GAINED" :
446 subtype == SDL_WINDOWEVENT_FOCUS_LOST ? "SDL_WINDOWEVENT_FOCUS_LOST" :
447 subtype == SDL_WINDOWEVENT_CLOSE ? "SDL_WINDOWEVENT_CLOSE" :
450 Error(ERR_DEBUG, "WINDOW EVENT: '%s', %ld, %ld",
451 event_name, event->data1, event->data2);
454 if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED ||
455 event->event == SDL_WINDOWEVENT_RESIZED ||
456 event->event == SDL_WINDOWEVENT_EXPOSED)
459 if (event->event == SDL_WINDOWEVENT_RESIZED && !video.fullscreen_enabled)
461 int new_window_width = event->data1;
462 int new_window_height = event->data2;
464 // if window size has changed after resizing, calculate new scaling factor
465 if (new_window_width != video.window_width ||
466 new_window_height != video.window_height)
468 int new_xpercent = (100 * new_window_width / video.width);
469 int new_ypercent = (100 * new_window_height / video.height);
471 setup.window_scaling_percent = video.window_scaling_percent =
472 MIN(MAX(MIN_WINDOW_SCALING_PERCENT, MIN(new_xpercent, new_ypercent)),
473 MAX_WINDOW_SCALING_PERCENT);
475 video.window_width = new_window_width;
476 video.window_height = new_window_height;
478 if (game_status == GAME_MODE_SETUP)
479 RedrawSetupScreenAfterFullscreenToggle();
486 #define NUM_TOUCH_FINGERS 3
491 SDL_FingerID finger_id;
494 } touch_info[NUM_TOUCH_FINGERS];
496 void HandleFingerEvent(FingerEvent *event)
498 static Key motion_key_x = KSYM_UNDEFINED;
499 static Key motion_key_y = KSYM_UNDEFINED;
500 static Key button_key = KSYM_UNDEFINED;
501 static float motion_x1, motion_y1;
502 static float button_x1, button_y1;
503 static SDL_FingerID motion_id = -1;
504 static SDL_FingerID button_id = -1;
505 int move_trigger_distance_percent = 2; // percent of touchpad width/height
506 int drop_trigger_distance_percent = 5; // percent of touchpad width/height
507 float move_trigger_distance = (float)move_trigger_distance_percent / 100;
508 float drop_trigger_distance = (float)drop_trigger_distance_percent / 100;
509 float event_x = event->x;
510 float event_y = event->y;
512 #if DEBUG_EVENTS_FINGER
513 Error(ERR_DEBUG, "FINGER EVENT: finger was %s, touch ID %lld, finger ID %lld, x/y %f/%f, dx/dy %f/%f, pressure %f",
514 event->type == EVENT_FINGERPRESS ? "pressed" :
515 event->type == EVENT_FINGERRELEASE ? "released" : "moved",
519 event->dx, event->dy,
523 if (game_status != GAME_MODE_PLAYING)
526 if (strEqual(setup.touch.control_type, TOUCH_CONTROL_VIRTUAL_BUTTONS))
528 int key_status = (event->type == EVENT_FINGERRELEASE ? KEY_RELEASED :
530 Key key = (event->x < 1.0 / 3.0 ?
531 (event->y < 1.0 / 2.0 ? setup.input[0].key.snap :
532 setup.input[0].key.drop) :
533 event->x > 2.0 / 3.0 ?
534 (event->y < 1.0 / 3.0 ? setup.input[0].key.up :
535 event->y > 2.0 / 3.0 ? setup.input[0].key.down :
536 event->x < 5.0 / 6.0 ? setup.input[0].key.left :
537 setup.input[0].key.right) :
539 char *key_status_name = (key_status == KEY_RELEASED ? "KEY_RELEASED" :
543 Error(ERR_DEBUG, "::: key '%s' was '%s' [fingerId: %lld]",
544 getKeyNameFromKey(key), key_status_name, event->fingerId);
546 // check if we already know this touch event's finger id
547 for (i = 0; i < NUM_TOUCH_FINGERS; i++)
549 if (touch_info[i].touched &&
550 touch_info[i].finger_id == event->fingerId)
552 // Error(ERR_DEBUG, "MARK 1: %d", i);
558 if (i >= NUM_TOUCH_FINGERS)
560 if (key_status == KEY_PRESSED)
562 int oldest_pos = 0, oldest_counter = touch_info[0].counter;
564 // unknown finger id -- get new, empty slot, if available
565 for (i = 0; i < NUM_TOUCH_FINGERS; i++)
567 if (touch_info[i].counter < oldest_counter)
570 oldest_counter = touch_info[i].counter;
572 // Error(ERR_DEBUG, "MARK 2: %d", i);
575 if (!touch_info[i].touched)
577 // Error(ERR_DEBUG, "MARK 3: %d", i);
583 if (i >= NUM_TOUCH_FINGERS)
585 // all slots allocated -- use oldest slot
588 // Error(ERR_DEBUG, "MARK 4: %d", i);
593 // release of previously unknown key (should not happen)
595 if (key != KSYM_UNDEFINED)
597 HandleKey(key, KEY_RELEASED);
599 Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d] [1]",
600 getKeyNameFromKey(key), "KEY_RELEASED", i);
605 if (i < NUM_TOUCH_FINGERS)
607 if (key_status == KEY_PRESSED)
609 if (touch_info[i].key != key)
611 if (touch_info[i].key != KSYM_UNDEFINED)
613 HandleKey(touch_info[i].key, KEY_RELEASED);
615 Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d] [2]",
616 getKeyNameFromKey(touch_info[i].key), "KEY_RELEASED", i);
619 if (key != KSYM_UNDEFINED)
621 HandleKey(key, KEY_PRESSED);
623 Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d] [3]",
624 getKeyNameFromKey(key), "KEY_PRESSED", i);
628 touch_info[i].touched = TRUE;
629 touch_info[i].finger_id = event->fingerId;
630 touch_info[i].counter = Counter();
631 touch_info[i].key = key;
635 if (touch_info[i].key != KSYM_UNDEFINED)
637 HandleKey(touch_info[i].key, KEY_RELEASED);
639 Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d] [4]",
640 getKeyNameFromKey(touch_info[i].key), "KEY_RELEASED", i);
643 touch_info[i].touched = FALSE;
644 touch_info[i].finger_id = 0;
645 touch_info[i].counter = 0;
646 touch_info[i].key = 0;
653 // use touch direction control
655 if (event->type == EVENT_FINGERPRESS)
657 if (event_x > 1.0 / 3.0)
661 motion_id = event->fingerId;
666 motion_key_x = KSYM_UNDEFINED;
667 motion_key_y = KSYM_UNDEFINED;
669 Error(ERR_DEBUG, "---------- MOVE STARTED (WAIT) ----------");
675 button_id = event->fingerId;
680 button_key = setup.input[0].key.snap;
682 HandleKey(button_key, KEY_PRESSED);
684 Error(ERR_DEBUG, "---------- SNAP STARTED ----------");
687 else if (event->type == EVENT_FINGERRELEASE)
689 if (event->fingerId == motion_id)
693 if (motion_key_x != KSYM_UNDEFINED)
694 HandleKey(motion_key_x, KEY_RELEASED);
695 if (motion_key_y != KSYM_UNDEFINED)
696 HandleKey(motion_key_y, KEY_RELEASED);
698 motion_key_x = KSYM_UNDEFINED;
699 motion_key_y = KSYM_UNDEFINED;
701 Error(ERR_DEBUG, "---------- MOVE STOPPED ----------");
703 else if (event->fingerId == button_id)
707 if (button_key != KSYM_UNDEFINED)
708 HandleKey(button_key, KEY_RELEASED);
710 button_key = KSYM_UNDEFINED;
712 Error(ERR_DEBUG, "---------- SNAP STOPPED ----------");
715 else if (event->type == EVENT_FINGERMOTION)
717 if (event->fingerId == motion_id)
719 float distance_x = ABS(event_x - motion_x1);
720 float distance_y = ABS(event_y - motion_y1);
721 Key new_motion_key_x = (event_x < motion_x1 ? setup.input[0].key.left :
722 event_x > motion_x1 ? setup.input[0].key.right :
724 Key new_motion_key_y = (event_y < motion_y1 ? setup.input[0].key.up :
725 event_y > motion_y1 ? setup.input[0].key.down :
728 if (distance_x < move_trigger_distance / 2 ||
729 distance_x < distance_y)
730 new_motion_key_x = KSYM_UNDEFINED;
732 if (distance_y < move_trigger_distance / 2 ||
733 distance_y < distance_x)
734 new_motion_key_y = KSYM_UNDEFINED;
736 if (distance_x > move_trigger_distance ||
737 distance_y > move_trigger_distance)
739 if (new_motion_key_x != motion_key_x)
741 if (motion_key_x != KSYM_UNDEFINED)
742 HandleKey(motion_key_x, KEY_RELEASED);
743 if (new_motion_key_x != KSYM_UNDEFINED)
744 HandleKey(new_motion_key_x, KEY_PRESSED);
747 if (new_motion_key_y != motion_key_y)
749 if (motion_key_y != KSYM_UNDEFINED)
750 HandleKey(motion_key_y, KEY_RELEASED);
751 if (new_motion_key_y != KSYM_UNDEFINED)
752 HandleKey(new_motion_key_y, KEY_PRESSED);
758 motion_key_x = new_motion_key_x;
759 motion_key_y = new_motion_key_y;
761 Error(ERR_DEBUG, "---------- MOVE STARTED (MOVE) ----------");
764 else if (event->fingerId == button_id)
766 float distance_x = ABS(event_x - button_x1);
767 float distance_y = ABS(event_y - button_y1);
769 if (distance_x < drop_trigger_distance / 2 &&
770 distance_y > drop_trigger_distance)
772 if (button_key == setup.input[0].key.snap)
773 HandleKey(button_key, KEY_RELEASED);
778 button_key = setup.input[0].key.drop;
780 HandleKey(button_key, KEY_PRESSED);
782 Error(ERR_DEBUG, "---------- DROP STARTED ----------");
788 static boolean checkTextInputKeyModState()
790 // when playing, only handle raw key events and ignore text input
791 if (game_status == GAME_MODE_PLAYING)
794 return ((GetKeyModState() & KMOD_TextInput) != KMOD_None);
797 void HandleTextEvent(TextEvent *event)
799 char *text = event->text;
800 Key key = getKeyFromKeyName(text);
802 #if DEBUG_EVENTS_TEXT
803 Error(ERR_DEBUG, "TEXT EVENT: text == '%s' [%d byte(s), '%c'/%d], resulting key == %d (%s) [%04x]",
806 text[0], (int)(text[0]),
808 getKeyNameFromKey(key),
812 #if defined(PLATFORM_ANDROID)
813 if (game_status == GAME_MODE_PSEUDO_TYPENAME)
815 HandleTypeName(0, key);
821 // only handle key input with text modifier keys pressed
822 if (checkTextInputKeyModState())
824 HandleKey(key, KEY_PRESSED);
825 HandleKey(key, KEY_RELEASED);
829 void HandlePauseResumeEvent(PauseResumeEvent *event)
831 if (event->type == SDL_APP_WILLENTERBACKGROUND)
835 else if (event->type == SDL_APP_DIDENTERFOREGROUND)
843 void HandleKeyEvent(KeyEvent *event)
845 int key_status = (event->type == EVENT_KEYPRESS ? KEY_PRESSED : KEY_RELEASED);
846 boolean with_modifiers = (game_status == GAME_MODE_PLAYING ? FALSE : TRUE);
847 Key key = GetEventKey(event, with_modifiers);
848 Key keymod = (with_modifiers ? GetEventKey(event, FALSE) : key);
851 Error(ERR_DEBUG, "KEY EVENT: key was %s, keysym.scancode == %d, keysym.sym == %d, keymod = %d, GetKeyModState() = 0x%04x, resulting key == %d (%s)",
852 event->type == EVENT_KEYPRESS ? "pressed" : "released",
853 event->keysym.scancode,
858 getKeyNameFromKey(key));
861 #if defined(PLATFORM_ANDROID)
862 // always map the "back" button to the "escape" key on Android devices
863 if (key == KSYM_Back)
867 HandleKeyModState(keymod, key_status);
869 #if defined(TARGET_SDL2)
870 // only handle raw key input without text modifier keys pressed
871 if (!checkTextInputKeyModState())
872 HandleKey(key, key_status);
874 HandleKey(key, key_status);
878 void HandleFocusEvent(FocusChangeEvent *event)
880 static int old_joystick_status = -1;
882 if (event->type == EVENT_FOCUSOUT)
884 KeyboardAutoRepeatOn();
885 old_joystick_status = joystick.status;
886 joystick.status = JOYSTICK_NOT_AVAILABLE;
890 else if (event->type == EVENT_FOCUSIN)
892 /* When there are two Rocks'n'Diamonds windows which overlap and
893 the player moves the pointer from one game window to the other,
894 a 'FocusOut' event is generated for the window the pointer is
895 leaving and a 'FocusIn' event is generated for the window the
896 pointer is entering. In some cases, it can happen that the
897 'FocusIn' event is handled by the one game process before the
898 'FocusOut' event by the other game process. In this case the
899 X11 environment would end up with activated keyboard auto repeat,
900 because unfortunately this is a global setting and not (which
901 would be far better) set for each X11 window individually.
902 The effect would be keyboard auto repeat while playing the game
903 (game_status == GAME_MODE_PLAYING), which is not desired.
904 To avoid this special case, we just wait 1/10 second before
905 processing the 'FocusIn' event.
908 if (game_status == GAME_MODE_PLAYING)
911 KeyboardAutoRepeatOffUnlessAutoplay();
914 if (old_joystick_status != -1)
915 joystick.status = old_joystick_status;
919 void HandleClientMessageEvent(ClientMessageEvent *event)
921 if (CheckCloseWindowEvent(event))
925 void HandleWindowManagerEvent(Event *event)
927 #if defined(TARGET_SDL)
928 SDLHandleWindowManagerEvent(event);
932 void HandleButton(int mx, int my, int button, int button_nr)
934 static int old_mx = 0, old_my = 0;
948 #if defined(PLATFORM_ANDROID)
949 if (game_status != GAME_MODE_PLAYING &&
950 HandleGadgets(mx, my, button))
952 /* do not handle this button event anymore */
953 mx = my = -32; /* force mouse event to be outside screen tiles */
956 if (HandleGadgets(mx, my, button))
958 /* do not handle this button event anymore */
959 mx = my = -32; /* force mouse event to be outside screen tiles */
963 /* do not use scroll wheel button events for anything other than gadgets */
964 if (IS_WHEEL_BUTTON(button_nr))
969 case GAME_MODE_TITLE:
970 HandleTitleScreen(mx, my, 0, 0, button);
974 HandleMainMenu(mx, my, 0, 0, button);
977 case GAME_MODE_PSEUDO_TYPENAME:
978 HandleTypeName(0, KSYM_Return);
981 case GAME_MODE_LEVELS:
982 HandleChooseLevelSet(mx, my, 0, 0, button);
985 case GAME_MODE_LEVELNR:
986 HandleChooseLevelNr(mx, my, 0, 0, button);
989 case GAME_MODE_SCORES:
990 HandleHallOfFame(0, 0, 0, 0, button);
993 case GAME_MODE_EDITOR:
994 HandleLevelEditorIdle();
998 HandleInfoScreen(mx, my, 0, 0, button);
1001 case GAME_MODE_SETUP:
1002 HandleSetupScreen(mx, my, 0, 0, button);
1005 case GAME_MODE_PLAYING:
1007 if (button == MB_PRESSED && !motion_status && IN_GFX_FIELD_PLAY(mx, my))
1008 DumpTile(LEVELX((mx - SX) / TILESIZE_VAR),
1009 LEVELY((my - SY) / TILESIZE_VAR));
1010 // DumpTile(LEVELX((mx - SX) / TILEX), LEVELY((my - SY) / TILEY));
1019 static boolean is_string_suffix(char *string, char *suffix)
1021 int string_len = strlen(string);
1022 int suffix_len = strlen(suffix);
1024 if (suffix_len > string_len)
1027 return (strEqual(&string[string_len - suffix_len], suffix));
1030 #define MAX_CHEAT_INPUT_LEN 32
1032 static void HandleKeysSpecial(Key key)
1034 static char cheat_input[2 * MAX_CHEAT_INPUT_LEN + 1] = "";
1035 char letter = getCharFromKey(key);
1036 int cheat_input_len = strlen(cheat_input);
1042 if (cheat_input_len >= 2 * MAX_CHEAT_INPUT_LEN)
1044 for (i = 0; i < MAX_CHEAT_INPUT_LEN + 1; i++)
1045 cheat_input[i] = cheat_input[MAX_CHEAT_INPUT_LEN + i];
1047 cheat_input_len = MAX_CHEAT_INPUT_LEN;
1050 cheat_input[cheat_input_len++] = letter;
1051 cheat_input[cheat_input_len] = '\0';
1053 #if DEBUG_EVENTS_KEY
1054 Error(ERR_DEBUG, "SPECIAL KEY '%s' [%d]\n", cheat_input, cheat_input_len);
1057 if (game_status == GAME_MODE_MAIN)
1059 if (is_string_suffix(cheat_input, ":insert-solution-tape") ||
1060 is_string_suffix(cheat_input, ":ist"))
1062 InsertSolutionTape();
1064 else if (is_string_suffix(cheat_input, ":reload-graphics") ||
1065 is_string_suffix(cheat_input, ":rg"))
1067 ReloadCustomArtwork(1 << ARTWORK_TYPE_GRAPHICS);
1070 else if (is_string_suffix(cheat_input, ":reload-sounds") ||
1071 is_string_suffix(cheat_input, ":rs"))
1073 ReloadCustomArtwork(1 << ARTWORK_TYPE_SOUNDS);
1076 else if (is_string_suffix(cheat_input, ":reload-music") ||
1077 is_string_suffix(cheat_input, ":rm"))
1079 ReloadCustomArtwork(1 << ARTWORK_TYPE_MUSIC);
1082 else if (is_string_suffix(cheat_input, ":reload-artwork") ||
1083 is_string_suffix(cheat_input, ":ra"))
1085 ReloadCustomArtwork(1 << ARTWORK_TYPE_GRAPHICS |
1086 1 << ARTWORK_TYPE_SOUNDS |
1087 1 << ARTWORK_TYPE_MUSIC);
1090 else if (is_string_suffix(cheat_input, ":dump-level") ||
1091 is_string_suffix(cheat_input, ":dl"))
1095 else if (is_string_suffix(cheat_input, ":dump-tape") ||
1096 is_string_suffix(cheat_input, ":dt"))
1100 else if (is_string_suffix(cheat_input, ":fix-tape") ||
1101 is_string_suffix(cheat_input, ":ft"))
1103 /* fix single-player tapes that contain player input for more than one
1104 player (due to a bug in 3.3.1.2 and earlier versions), which results
1105 in playing levels with more than one player in multi-player mode,
1106 even though the tape was originally recorded in single-player mode */
1108 /* remove player input actions for all players but the first one */
1109 for (i = 1; i < MAX_PLAYERS; i++)
1110 tape.player_participates[i] = FALSE;
1112 tape.changed = TRUE;
1114 else if (is_string_suffix(cheat_input, ":save-native-level") ||
1115 is_string_suffix(cheat_input, ":snl"))
1117 SaveNativeLevel(&level);
1120 else if (game_status == GAME_MODE_PLAYING)
1123 if (is_string_suffix(cheat_input, ".q"))
1124 DEBUG_SetMaximumDynamite();
1127 else if (game_status == GAME_MODE_EDITOR)
1129 if (is_string_suffix(cheat_input, ":dump-brush") ||
1130 is_string_suffix(cheat_input, ":DB"))
1134 else if (is_string_suffix(cheat_input, ":DDB"))
1141 void HandleKey(Key key, int key_status)
1143 boolean anyTextGadgetActiveOrJustFinished = anyTextGadgetActive();
1144 static struct SetupKeyboardInfo ski;
1145 static struct SetupShortcutInfo ssi;
1154 { &ski.left, &ssi.snap_left, DEFAULT_KEY_LEFT, JOY_LEFT },
1155 { &ski.right, &ssi.snap_right, DEFAULT_KEY_RIGHT, JOY_RIGHT },
1156 { &ski.up, &ssi.snap_up, DEFAULT_KEY_UP, JOY_UP },
1157 { &ski.down, &ssi.snap_down, DEFAULT_KEY_DOWN, JOY_DOWN },
1158 { &ski.snap, NULL, DEFAULT_KEY_SNAP, JOY_BUTTON_SNAP },
1159 { &ski.drop, NULL, DEFAULT_KEY_DROP, JOY_BUTTON_DROP }
1164 if (game_status == GAME_MODE_PLAYING)
1166 /* only needed for single-step tape recording mode */
1167 static boolean clear_snap_button[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1168 static boolean clear_drop_button[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1169 static boolean element_snapped[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1170 static boolean element_dropped[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1173 for (pnr = 0; pnr < MAX_PLAYERS; pnr++)
1175 byte key_action = 0;
1177 if (setup.input[pnr].use_joystick)
1180 ski = setup.input[pnr].key;
1182 for (i = 0; i < NUM_PLAYER_ACTIONS; i++)
1183 if (key == *key_info[i].key_custom)
1184 key_action |= key_info[i].action;
1186 /* use combined snap+direction keys for the first player only */
1189 ssi = setup.shortcut;
1191 for (i = 0; i < NUM_DIRECTIONS; i++)
1192 if (key == *key_info[i].key_snap)
1193 key_action |= key_info[i].action | JOY_BUTTON_SNAP;
1196 /* clear delayed snap and drop actions in single step mode (see below) */
1197 if (tape.single_step)
1199 if (clear_snap_button[pnr])
1201 stored_player[pnr].action &= ~KEY_BUTTON_SNAP;
1202 clear_snap_button[pnr] = FALSE;
1205 if (clear_drop_button[pnr])
1207 stored_player[pnr].action &= ~KEY_BUTTON_DROP;
1208 clear_drop_button[pnr] = FALSE;
1212 if (key_status == KEY_PRESSED)
1213 stored_player[pnr].action |= key_action;
1215 stored_player[pnr].action &= ~key_action;
1217 if (tape.single_step && tape.recording && tape.pausing)
1219 if (key_status == KEY_PRESSED && key_action & KEY_MOTION)
1221 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1223 /* if snap key already pressed, don't snap when releasing (below) */
1224 if (stored_player[pnr].action & KEY_BUTTON_SNAP)
1225 element_snapped[pnr] = TRUE;
1227 /* if drop key already pressed, don't drop when releasing (below) */
1228 if (stored_player[pnr].action & KEY_BUTTON_DROP)
1229 element_dropped[pnr] = TRUE;
1231 else if (key_status == KEY_PRESSED && key_action & KEY_BUTTON_DROP)
1233 if (level.game_engine_type == GAME_ENGINE_TYPE_EM ||
1234 level.game_engine_type == GAME_ENGINE_TYPE_SP)
1237 if (level.game_engine_type == GAME_ENGINE_TYPE_SP &&
1238 getRedDiskReleaseFlag_SP() == 0)
1239 stored_player[pnr].action &= ~KEY_BUTTON_DROP;
1241 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1244 else if (key_status == KEY_RELEASED && key_action & KEY_BUTTON)
1246 if (key_action & KEY_BUTTON_SNAP)
1248 /* if snap key was released without moving (see above), snap now */
1249 if (!element_snapped[pnr])
1251 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1253 stored_player[pnr].action |= KEY_BUTTON_SNAP;
1255 /* clear delayed snap button on next event */
1256 clear_snap_button[pnr] = TRUE;
1259 element_snapped[pnr] = FALSE;
1262 if (key_action & KEY_BUTTON_DROP &&
1263 level.game_engine_type == GAME_ENGINE_TYPE_RND)
1265 /* if drop key was released without moving (see above), drop now */
1266 if (!element_dropped[pnr])
1268 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1270 if (level.game_engine_type != GAME_ENGINE_TYPE_SP ||
1271 getRedDiskReleaseFlag_SP() != 0)
1272 stored_player[pnr].action |= KEY_BUTTON_DROP;
1274 /* clear delayed drop button on next event */
1275 clear_drop_button[pnr] = TRUE;
1278 element_dropped[pnr] = FALSE;
1282 else if (tape.recording && tape.pausing)
1284 /* prevent key release events from un-pausing a paused game */
1285 if (key_status == KEY_PRESSED && key_action & KEY_ACTION)
1286 TapeTogglePause(TAPE_TOGGLE_MANUAL);
1292 for (i = 0; i < NUM_PLAYER_ACTIONS; i++)
1293 if (key == key_info[i].key_default)
1294 joy |= key_info[i].action;
1299 if (key_status == KEY_PRESSED)
1300 key_joystick_mapping |= joy;
1302 key_joystick_mapping &= ~joy;
1307 if (game_status != GAME_MODE_PLAYING)
1308 key_joystick_mapping = 0;
1310 if (key_status == KEY_RELEASED)
1313 if ((key == KSYM_F11 ||
1314 ((key == KSYM_Return ||
1315 key == KSYM_KP_Enter) && (GetKeyModState() & KMOD_Alt))) &&
1316 video.fullscreen_available)
1318 setup.fullscreen = !setup.fullscreen;
1320 ToggleFullscreenOrChangeWindowScalingIfNeeded();
1322 if (game_status == GAME_MODE_SETUP)
1323 RedrawSetupScreenAfterFullscreenToggle();
1328 if ((key == KSYM_minus ||
1331 ((GetKeyModState() & KMOD_Control) ||
1332 (GetKeyModState() & KMOD_Alt)) &&
1333 video.window_scaling_available &&
1334 !video.fullscreen_enabled)
1337 setup.window_scaling_percent = STD_WINDOW_SCALING_PERCENT;
1339 setup.window_scaling_percent +=
1340 (key == KSYM_minus ? -1 : +1) * STEP_WINDOW_SCALING_PERCENT;
1342 if (setup.window_scaling_percent < MIN_WINDOW_SCALING_PERCENT)
1343 setup.window_scaling_percent = MIN_WINDOW_SCALING_PERCENT;
1344 else if (setup.window_scaling_percent > MAX_WINDOW_SCALING_PERCENT)
1345 setup.window_scaling_percent = MAX_WINDOW_SCALING_PERCENT;
1347 ToggleFullscreenOrChangeWindowScalingIfNeeded();
1349 if (game_status == GAME_MODE_SETUP)
1350 RedrawSetupScreenAfterFullscreenToggle();
1355 if (game_status == GAME_MODE_PLAYING && AllPlayersGone &&
1356 (key == KSYM_Return || key == setup.shortcut.toggle_pause))
1363 if (game_status == GAME_MODE_MAIN &&
1364 (key == setup.shortcut.toggle_pause || key == KSYM_space))
1366 StartGameActions(options.network, setup.autorecord, level.random_seed);
1371 if (game_status == GAME_MODE_MAIN || game_status == GAME_MODE_PLAYING)
1373 if (key == setup.shortcut.save_game)
1375 else if (key == setup.shortcut.load_game)
1377 else if (key == setup.shortcut.toggle_pause)
1378 TapeTogglePause(TAPE_TOGGLE_MANUAL);
1380 HandleTapeButtonKeys(key);
1381 HandleSoundButtonKeys(key);
1384 if (game_status == GAME_MODE_PLAYING && !network_playing)
1386 int centered_player_nr_next = -999;
1388 if (key == setup.shortcut.focus_player_all)
1389 centered_player_nr_next = -1;
1391 for (i = 0; i < MAX_PLAYERS; i++)
1392 if (key == setup.shortcut.focus_player[i])
1393 centered_player_nr_next = i;
1395 if (centered_player_nr_next != -999)
1397 game.centered_player_nr_next = centered_player_nr_next;
1398 game.set_centered_player = TRUE;
1402 tape.centered_player_nr_next = game.centered_player_nr_next;
1403 tape.set_centered_player = TRUE;
1408 HandleKeysSpecial(key);
1410 if (HandleGadgetsKeyInput(key))
1412 if (key != KSYM_Escape) /* always allow ESC key to be handled */
1413 key = KSYM_UNDEFINED;
1416 switch (game_status)
1418 case GAME_MODE_PSEUDO_TYPENAME:
1419 HandleTypeName(0, key);
1422 case GAME_MODE_TITLE:
1423 case GAME_MODE_MAIN:
1424 case GAME_MODE_LEVELS:
1425 case GAME_MODE_LEVELNR:
1426 case GAME_MODE_SETUP:
1427 case GAME_MODE_INFO:
1428 case GAME_MODE_SCORES:
1433 if (game_status == GAME_MODE_TITLE)
1434 HandleTitleScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1435 else if (game_status == GAME_MODE_MAIN)
1436 HandleMainMenu(0, 0, 0, 0, MB_MENU_CHOICE);
1437 else if (game_status == GAME_MODE_LEVELS)
1438 HandleChooseLevelSet(0, 0, 0, 0, MB_MENU_CHOICE);
1439 else if (game_status == GAME_MODE_LEVELNR)
1440 HandleChooseLevelNr(0, 0, 0, 0, MB_MENU_CHOICE);
1441 else if (game_status == GAME_MODE_SETUP)
1442 HandleSetupScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1443 else if (game_status == GAME_MODE_INFO)
1444 HandleInfoScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1445 else if (game_status == GAME_MODE_SCORES)
1446 HandleHallOfFame(0, 0, 0, 0, MB_MENU_CHOICE);
1450 if (game_status != GAME_MODE_MAIN)
1451 FadeSkipNextFadeIn();
1453 if (game_status == GAME_MODE_TITLE)
1454 HandleTitleScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1455 else if (game_status == GAME_MODE_LEVELS)
1456 HandleChooseLevelSet(0, 0, 0, 0, MB_MENU_LEAVE);
1457 else if (game_status == GAME_MODE_LEVELNR)
1458 HandleChooseLevelNr(0, 0, 0, 0, MB_MENU_LEAVE);
1459 else if (game_status == GAME_MODE_SETUP)
1460 HandleSetupScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1461 else if (game_status == GAME_MODE_INFO)
1462 HandleInfoScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1463 else if (game_status == GAME_MODE_SCORES)
1464 HandleHallOfFame(0, 0, 0, 0, MB_MENU_LEAVE);
1468 if (game_status == GAME_MODE_LEVELS)
1469 HandleChooseLevelSet(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1470 else if (game_status == GAME_MODE_LEVELNR)
1471 HandleChooseLevelNr(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1472 else if (game_status == GAME_MODE_SETUP)
1473 HandleSetupScreen(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1474 else if (game_status == GAME_MODE_INFO)
1475 HandleInfoScreen(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1476 else if (game_status == GAME_MODE_SCORES)
1477 HandleHallOfFame(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1480 case KSYM_Page_Down:
1481 if (game_status == GAME_MODE_LEVELS)
1482 HandleChooseLevelSet(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1483 else if (game_status == GAME_MODE_LEVELNR)
1484 HandleChooseLevelNr(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1485 else if (game_status == GAME_MODE_SETUP)
1486 HandleSetupScreen(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1487 else if (game_status == GAME_MODE_INFO)
1488 HandleInfoScreen(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1489 else if (game_status == GAME_MODE_SCORES)
1490 HandleHallOfFame(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1495 GameFrameDelay = (GameFrameDelay == 500 ? GAME_FRAME_DELAY : 500);
1499 setup.sp_show_border_elements = !setup.sp_show_border_elements;
1500 printf("Supaplex border elements %s\n",
1501 setup.sp_show_border_elements ? "enabled" : "disabled");
1510 case GAME_MODE_EDITOR:
1511 if (!anyTextGadgetActiveOrJustFinished || key == KSYM_Escape)
1512 HandleLevelEditorKeyInput(key);
1515 case GAME_MODE_PLAYING:
1520 RequestQuitGame(setup.ask_on_escape);
1527 if (GameFrameDelay == 500)
1528 GameFrameDelay = GAME_FRAME_DELAY;
1530 GameFrameDelay = 500;
1533 GameFrameDelay = (key - KSYM_0) * 10;
1534 printf("Game speed == %d%% (%d ms delay between two frames)\n",
1535 GAME_FRAME_DELAY * 100 / GameFrameDelay, GameFrameDelay);
1541 options.debug = FALSE;
1542 printf("debug mode disabled\n");
1546 options.debug = TRUE;
1547 printf("debug mode enabled\n");
1553 if (!global.fps_slowdown)
1555 global.fps_slowdown = TRUE;
1556 global.fps_slowdown_factor = 2;
1557 printf("fps slowdown enabled -- display only every 2nd frame\n");
1559 else if (global.fps_slowdown_factor == 2)
1561 global.fps_slowdown_factor = 4;
1562 printf("fps slowdown enabled -- display only every 4th frame\n");
1566 global.fps_slowdown = FALSE;
1567 global.fps_slowdown_factor = 1;
1568 printf("fps slowdown disabled\n");
1574 printf("::: currently using game engine version %d\n",
1575 game.engine_version);
1586 if (key == KSYM_Escape)
1588 game_status = GAME_MODE_MAIN;
1596 void HandleNoEvent()
1598 if (button_status && game_status != GAME_MODE_PLAYING)
1600 HandleButton(0, 0, -button_status, button_status);
1607 #if defined(NETWORK_AVALIABLE)
1608 if (options.network)
1612 switch (game_status)
1614 case GAME_MODE_MAIN:
1615 DrawPreviewLevelAnimation();
1619 case GAME_MODE_LEVELS:
1620 case GAME_MODE_LEVELNR:
1621 case GAME_MODE_SETUP:
1622 case GAME_MODE_INFO:
1623 case GAME_MODE_SCORES:
1627 case GAME_MODE_EDITOR:
1628 HandleLevelEditorIdle();
1636 static int HandleJoystickForAllPlayers()
1641 for (i = 0; i < MAX_PLAYERS; i++)
1643 byte joy_action = 0;
1646 if (!setup.input[i].use_joystick)
1650 joy_action = Joystick(i);
1651 result |= joy_action;
1653 if (!setup.input[i].use_joystick)
1656 stored_player[i].action = joy_action;
1662 void HandleJoystick()
1664 int joystick = HandleJoystickForAllPlayers();
1665 int keyboard = key_joystick_mapping;
1666 int joy = (joystick | keyboard);
1667 int left = joy & JOY_LEFT;
1668 int right = joy & JOY_RIGHT;
1669 int up = joy & JOY_UP;
1670 int down = joy & JOY_DOWN;
1671 int button = joy & JOY_BUTTON;
1672 int newbutton = (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED);
1673 int dx = (left ? -1 : right ? 1 : 0);
1674 int dy = (up ? -1 : down ? 1 : 0);
1676 switch (game_status)
1678 case GAME_MODE_TITLE:
1679 case GAME_MODE_MAIN:
1680 case GAME_MODE_LEVELS:
1681 case GAME_MODE_LEVELNR:
1682 case GAME_MODE_SETUP:
1683 case GAME_MODE_INFO:
1685 static unsigned int joystickmove_delay = 0;
1687 if (joystick && !button &&
1688 !DelayReached(&joystickmove_delay, GADGET_FRAME_DELAY))
1689 newbutton = dx = dy = 0;
1691 if (game_status == GAME_MODE_TITLE)
1692 HandleTitleScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1693 else if (game_status == GAME_MODE_MAIN)
1694 HandleMainMenu(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1695 else if (game_status == GAME_MODE_LEVELS)
1696 HandleChooseLevelSet(0,0,dx,dy,newbutton?MB_MENU_CHOICE : MB_MENU_MARK);
1697 else if (game_status == GAME_MODE_LEVELNR)
1698 HandleChooseLevelNr(0,0,dx,dy,newbutton? MB_MENU_CHOICE : MB_MENU_MARK);
1699 else if (game_status == GAME_MODE_SETUP)
1700 HandleSetupScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1701 else if (game_status == GAME_MODE_INFO)
1702 HandleInfoScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1706 case GAME_MODE_SCORES:
1707 HandleHallOfFame(0, 0, dx, dy, !newbutton);
1710 case GAME_MODE_PLAYING:
1711 if (tape.playing || keyboard)
1712 newbutton = ((joy & JOY_BUTTON) != 0);
1714 if (newbutton && AllPlayersGone)