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;
935 boolean button_hold = FALSE;
950 #if defined(PLATFORM_ANDROID)
951 // !!! for now, do not handle gadgets when playing -- maybe fix this !!!
952 if (game_status != GAME_MODE_PLAYING &&
953 HandleGadgets(mx, my, button))
955 /* do not handle this button event anymore */
956 mx = my = -32; /* force mouse event to be outside screen tiles */
959 if (HandleGadgets(mx, my, button))
961 /* do not handle this button event anymore */
962 mx = my = -32; /* force mouse event to be outside screen tiles */
966 if (button_hold && game_status == GAME_MODE_PLAYING && tape.pausing)
969 /* do not use scroll wheel button events for anything other than gadgets */
970 if (IS_WHEEL_BUTTON(button_nr))
975 case GAME_MODE_TITLE:
976 HandleTitleScreen(mx, my, 0, 0, button);
980 HandleMainMenu(mx, my, 0, 0, button);
983 case GAME_MODE_PSEUDO_TYPENAME:
984 HandleTypeName(0, KSYM_Return);
987 case GAME_MODE_LEVELS:
988 HandleChooseLevelSet(mx, my, 0, 0, button);
991 case GAME_MODE_LEVELNR:
992 HandleChooseLevelNr(mx, my, 0, 0, button);
995 case GAME_MODE_SCORES:
996 HandleHallOfFame(0, 0, 0, 0, button);
999 case GAME_MODE_EDITOR:
1000 HandleLevelEditorIdle();
1003 case GAME_MODE_INFO:
1004 HandleInfoScreen(mx, my, 0, 0, button);
1007 case GAME_MODE_SETUP:
1008 HandleSetupScreen(mx, my, 0, 0, button);
1011 case GAME_MODE_PLAYING:
1013 if (button == MB_PRESSED && !motion_status && IN_GFX_FIELD_PLAY(mx, my))
1014 DumpTile(LEVELX((mx - SX) / TILESIZE_VAR),
1015 LEVELY((my - SY) / TILESIZE_VAR));
1016 // DumpTile(LEVELX((mx - SX) / TILEX), LEVELY((my - SY) / TILEY));
1025 static boolean is_string_suffix(char *string, char *suffix)
1027 int string_len = strlen(string);
1028 int suffix_len = strlen(suffix);
1030 if (suffix_len > string_len)
1033 return (strEqual(&string[string_len - suffix_len], suffix));
1036 #define MAX_CHEAT_INPUT_LEN 32
1038 static void HandleKeysSpecial(Key key)
1040 static char cheat_input[2 * MAX_CHEAT_INPUT_LEN + 1] = "";
1041 char letter = getCharFromKey(key);
1042 int cheat_input_len = strlen(cheat_input);
1048 if (cheat_input_len >= 2 * MAX_CHEAT_INPUT_LEN)
1050 for (i = 0; i < MAX_CHEAT_INPUT_LEN + 1; i++)
1051 cheat_input[i] = cheat_input[MAX_CHEAT_INPUT_LEN + i];
1053 cheat_input_len = MAX_CHEAT_INPUT_LEN;
1056 cheat_input[cheat_input_len++] = letter;
1057 cheat_input[cheat_input_len] = '\0';
1059 #if DEBUG_EVENTS_KEY
1060 Error(ERR_DEBUG, "SPECIAL KEY '%s' [%d]\n", cheat_input, cheat_input_len);
1063 if (game_status == GAME_MODE_MAIN)
1065 if (is_string_suffix(cheat_input, ":insert-solution-tape") ||
1066 is_string_suffix(cheat_input, ":ist"))
1068 InsertSolutionTape();
1070 else if (is_string_suffix(cheat_input, ":reload-graphics") ||
1071 is_string_suffix(cheat_input, ":rg"))
1073 ReloadCustomArtwork(1 << ARTWORK_TYPE_GRAPHICS);
1076 else if (is_string_suffix(cheat_input, ":reload-sounds") ||
1077 is_string_suffix(cheat_input, ":rs"))
1079 ReloadCustomArtwork(1 << ARTWORK_TYPE_SOUNDS);
1082 else if (is_string_suffix(cheat_input, ":reload-music") ||
1083 is_string_suffix(cheat_input, ":rm"))
1085 ReloadCustomArtwork(1 << ARTWORK_TYPE_MUSIC);
1088 else if (is_string_suffix(cheat_input, ":reload-artwork") ||
1089 is_string_suffix(cheat_input, ":ra"))
1091 ReloadCustomArtwork(1 << ARTWORK_TYPE_GRAPHICS |
1092 1 << ARTWORK_TYPE_SOUNDS |
1093 1 << ARTWORK_TYPE_MUSIC);
1096 else if (is_string_suffix(cheat_input, ":dump-level") ||
1097 is_string_suffix(cheat_input, ":dl"))
1101 else if (is_string_suffix(cheat_input, ":dump-tape") ||
1102 is_string_suffix(cheat_input, ":dt"))
1106 else if (is_string_suffix(cheat_input, ":fix-tape") ||
1107 is_string_suffix(cheat_input, ":ft"))
1109 /* fix single-player tapes that contain player input for more than one
1110 player (due to a bug in 3.3.1.2 and earlier versions), which results
1111 in playing levels with more than one player in multi-player mode,
1112 even though the tape was originally recorded in single-player mode */
1114 /* remove player input actions for all players but the first one */
1115 for (i = 1; i < MAX_PLAYERS; i++)
1116 tape.player_participates[i] = FALSE;
1118 tape.changed = TRUE;
1120 else if (is_string_suffix(cheat_input, ":save-native-level") ||
1121 is_string_suffix(cheat_input, ":snl"))
1123 SaveNativeLevel(&level);
1126 else if (game_status == GAME_MODE_PLAYING)
1129 if (is_string_suffix(cheat_input, ".q"))
1130 DEBUG_SetMaximumDynamite();
1133 else if (game_status == GAME_MODE_EDITOR)
1135 if (is_string_suffix(cheat_input, ":dump-brush") ||
1136 is_string_suffix(cheat_input, ":DB"))
1140 else if (is_string_suffix(cheat_input, ":DDB"))
1147 void HandleKey(Key key, int key_status)
1149 boolean anyTextGadgetActiveOrJustFinished = anyTextGadgetActive();
1150 static struct SetupKeyboardInfo ski;
1151 static struct SetupShortcutInfo ssi;
1160 { &ski.left, &ssi.snap_left, DEFAULT_KEY_LEFT, JOY_LEFT },
1161 { &ski.right, &ssi.snap_right, DEFAULT_KEY_RIGHT, JOY_RIGHT },
1162 { &ski.up, &ssi.snap_up, DEFAULT_KEY_UP, JOY_UP },
1163 { &ski.down, &ssi.snap_down, DEFAULT_KEY_DOWN, JOY_DOWN },
1164 { &ski.snap, NULL, DEFAULT_KEY_SNAP, JOY_BUTTON_SNAP },
1165 { &ski.drop, NULL, DEFAULT_KEY_DROP, JOY_BUTTON_DROP }
1170 if (game_status == GAME_MODE_PLAYING)
1172 /* only needed for single-step tape recording mode */
1173 static boolean clear_snap_button[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1174 static boolean clear_drop_button[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1175 static boolean element_snapped[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1176 static boolean element_dropped[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1179 for (pnr = 0; pnr < MAX_PLAYERS; pnr++)
1181 byte key_action = 0;
1183 if (setup.input[pnr].use_joystick)
1186 ski = setup.input[pnr].key;
1188 for (i = 0; i < NUM_PLAYER_ACTIONS; i++)
1189 if (key == *key_info[i].key_custom)
1190 key_action |= key_info[i].action;
1192 /* use combined snap+direction keys for the first player only */
1195 ssi = setup.shortcut;
1197 for (i = 0; i < NUM_DIRECTIONS; i++)
1198 if (key == *key_info[i].key_snap)
1199 key_action |= key_info[i].action | JOY_BUTTON_SNAP;
1202 /* clear delayed snap and drop actions in single step mode (see below) */
1203 if (tape.single_step)
1205 if (clear_snap_button[pnr])
1207 stored_player[pnr].action &= ~KEY_BUTTON_SNAP;
1208 clear_snap_button[pnr] = FALSE;
1211 if (clear_drop_button[pnr])
1213 stored_player[pnr].action &= ~KEY_BUTTON_DROP;
1214 clear_drop_button[pnr] = FALSE;
1218 if (key_status == KEY_PRESSED)
1219 stored_player[pnr].action |= key_action;
1221 stored_player[pnr].action &= ~key_action;
1223 if (tape.single_step && tape.recording && tape.pausing)
1225 if (key_status == KEY_PRESSED && key_action & KEY_MOTION)
1227 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1229 /* if snap key already pressed, don't snap when releasing (below) */
1230 if (stored_player[pnr].action & KEY_BUTTON_SNAP)
1231 element_snapped[pnr] = TRUE;
1233 /* if drop key already pressed, don't drop when releasing (below) */
1234 if (stored_player[pnr].action & KEY_BUTTON_DROP)
1235 element_dropped[pnr] = TRUE;
1237 else if (key_status == KEY_PRESSED && key_action & KEY_BUTTON_DROP)
1239 if (level.game_engine_type == GAME_ENGINE_TYPE_EM ||
1240 level.game_engine_type == GAME_ENGINE_TYPE_SP)
1243 if (level.game_engine_type == GAME_ENGINE_TYPE_SP &&
1244 getRedDiskReleaseFlag_SP() == 0)
1245 stored_player[pnr].action &= ~KEY_BUTTON_DROP;
1247 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1250 else if (key_status == KEY_RELEASED && key_action & KEY_BUTTON)
1252 if (key_action & KEY_BUTTON_SNAP)
1254 /* if snap key was released without moving (see above), snap now */
1255 if (!element_snapped[pnr])
1257 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1259 stored_player[pnr].action |= KEY_BUTTON_SNAP;
1261 /* clear delayed snap button on next event */
1262 clear_snap_button[pnr] = TRUE;
1265 element_snapped[pnr] = FALSE;
1268 if (key_action & KEY_BUTTON_DROP &&
1269 level.game_engine_type == GAME_ENGINE_TYPE_RND)
1271 /* if drop key was released without moving (see above), drop now */
1272 if (!element_dropped[pnr])
1274 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1276 if (level.game_engine_type != GAME_ENGINE_TYPE_SP ||
1277 getRedDiskReleaseFlag_SP() != 0)
1278 stored_player[pnr].action |= KEY_BUTTON_DROP;
1280 /* clear delayed drop button on next event */
1281 clear_drop_button[pnr] = TRUE;
1284 element_dropped[pnr] = FALSE;
1288 else if (tape.recording && tape.pausing)
1290 /* prevent key release events from un-pausing a paused game */
1291 if (key_status == KEY_PRESSED && key_action & KEY_ACTION)
1292 TapeTogglePause(TAPE_TOGGLE_MANUAL);
1298 for (i = 0; i < NUM_PLAYER_ACTIONS; i++)
1299 if (key == key_info[i].key_default)
1300 joy |= key_info[i].action;
1305 if (key_status == KEY_PRESSED)
1306 key_joystick_mapping |= joy;
1308 key_joystick_mapping &= ~joy;
1313 if (game_status != GAME_MODE_PLAYING)
1314 key_joystick_mapping = 0;
1316 if (key_status == KEY_RELEASED)
1319 if ((key == KSYM_F11 ||
1320 ((key == KSYM_Return ||
1321 key == KSYM_KP_Enter) && (GetKeyModState() & KMOD_Alt))) &&
1322 video.fullscreen_available)
1324 setup.fullscreen = !setup.fullscreen;
1326 ToggleFullscreenOrChangeWindowScalingIfNeeded();
1328 if (game_status == GAME_MODE_SETUP)
1329 RedrawSetupScreenAfterFullscreenToggle();
1334 if ((key == KSYM_minus ||
1337 ((GetKeyModState() & KMOD_Control) ||
1338 (GetKeyModState() & KMOD_Alt)) &&
1339 video.window_scaling_available &&
1340 !video.fullscreen_enabled)
1343 setup.window_scaling_percent = STD_WINDOW_SCALING_PERCENT;
1345 setup.window_scaling_percent +=
1346 (key == KSYM_minus ? -1 : +1) * STEP_WINDOW_SCALING_PERCENT;
1348 if (setup.window_scaling_percent < MIN_WINDOW_SCALING_PERCENT)
1349 setup.window_scaling_percent = MIN_WINDOW_SCALING_PERCENT;
1350 else if (setup.window_scaling_percent > MAX_WINDOW_SCALING_PERCENT)
1351 setup.window_scaling_percent = MAX_WINDOW_SCALING_PERCENT;
1353 ToggleFullscreenOrChangeWindowScalingIfNeeded();
1355 if (game_status == GAME_MODE_SETUP)
1356 RedrawSetupScreenAfterFullscreenToggle();
1361 if (game_status == GAME_MODE_PLAYING && AllPlayersGone &&
1362 (key == KSYM_Return || key == setup.shortcut.toggle_pause))
1369 if (game_status == GAME_MODE_MAIN &&
1370 (key == setup.shortcut.toggle_pause || key == KSYM_space))
1372 StartGameActions(options.network, setup.autorecord, level.random_seed);
1377 if (game_status == GAME_MODE_MAIN || game_status == GAME_MODE_PLAYING)
1379 if (key == setup.shortcut.save_game)
1381 else if (key == setup.shortcut.load_game)
1383 else if (key == setup.shortcut.toggle_pause)
1384 TapeTogglePause(TAPE_TOGGLE_MANUAL);
1386 HandleTapeButtonKeys(key);
1387 HandleSoundButtonKeys(key);
1390 if (game_status == GAME_MODE_PLAYING && !network_playing)
1392 int centered_player_nr_next = -999;
1394 if (key == setup.shortcut.focus_player_all)
1395 centered_player_nr_next = -1;
1397 for (i = 0; i < MAX_PLAYERS; i++)
1398 if (key == setup.shortcut.focus_player[i])
1399 centered_player_nr_next = i;
1401 if (centered_player_nr_next != -999)
1403 game.centered_player_nr_next = centered_player_nr_next;
1404 game.set_centered_player = TRUE;
1408 tape.centered_player_nr_next = game.centered_player_nr_next;
1409 tape.set_centered_player = TRUE;
1414 HandleKeysSpecial(key);
1416 if (HandleGadgetsKeyInput(key))
1418 if (key != KSYM_Escape) /* always allow ESC key to be handled */
1419 key = KSYM_UNDEFINED;
1422 switch (game_status)
1424 case GAME_MODE_PSEUDO_TYPENAME:
1425 HandleTypeName(0, key);
1428 case GAME_MODE_TITLE:
1429 case GAME_MODE_MAIN:
1430 case GAME_MODE_LEVELS:
1431 case GAME_MODE_LEVELNR:
1432 case GAME_MODE_SETUP:
1433 case GAME_MODE_INFO:
1434 case GAME_MODE_SCORES:
1439 if (game_status == GAME_MODE_TITLE)
1440 HandleTitleScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1441 else if (game_status == GAME_MODE_MAIN)
1442 HandleMainMenu(0, 0, 0, 0, MB_MENU_CHOICE);
1443 else if (game_status == GAME_MODE_LEVELS)
1444 HandleChooseLevelSet(0, 0, 0, 0, MB_MENU_CHOICE);
1445 else if (game_status == GAME_MODE_LEVELNR)
1446 HandleChooseLevelNr(0, 0, 0, 0, MB_MENU_CHOICE);
1447 else if (game_status == GAME_MODE_SETUP)
1448 HandleSetupScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1449 else if (game_status == GAME_MODE_INFO)
1450 HandleInfoScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1451 else if (game_status == GAME_MODE_SCORES)
1452 HandleHallOfFame(0, 0, 0, 0, MB_MENU_CHOICE);
1456 if (game_status != GAME_MODE_MAIN)
1457 FadeSkipNextFadeIn();
1459 if (game_status == GAME_MODE_TITLE)
1460 HandleTitleScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1461 else if (game_status == GAME_MODE_LEVELS)
1462 HandleChooseLevelSet(0, 0, 0, 0, MB_MENU_LEAVE);
1463 else if (game_status == GAME_MODE_LEVELNR)
1464 HandleChooseLevelNr(0, 0, 0, 0, MB_MENU_LEAVE);
1465 else if (game_status == GAME_MODE_SETUP)
1466 HandleSetupScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1467 else if (game_status == GAME_MODE_INFO)
1468 HandleInfoScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1469 else if (game_status == GAME_MODE_SCORES)
1470 HandleHallOfFame(0, 0, 0, 0, MB_MENU_LEAVE);
1474 if (game_status == GAME_MODE_LEVELS)
1475 HandleChooseLevelSet(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1476 else if (game_status == GAME_MODE_LEVELNR)
1477 HandleChooseLevelNr(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1478 else if (game_status == GAME_MODE_SETUP)
1479 HandleSetupScreen(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1480 else if (game_status == GAME_MODE_INFO)
1481 HandleInfoScreen(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1482 else if (game_status == GAME_MODE_SCORES)
1483 HandleHallOfFame(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1486 case KSYM_Page_Down:
1487 if (game_status == GAME_MODE_LEVELS)
1488 HandleChooseLevelSet(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1489 else if (game_status == GAME_MODE_LEVELNR)
1490 HandleChooseLevelNr(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1491 else if (game_status == GAME_MODE_SETUP)
1492 HandleSetupScreen(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1493 else if (game_status == GAME_MODE_INFO)
1494 HandleInfoScreen(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1495 else if (game_status == GAME_MODE_SCORES)
1496 HandleHallOfFame(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1501 GameFrameDelay = (GameFrameDelay == 500 ? GAME_FRAME_DELAY : 500);
1505 setup.sp_show_border_elements = !setup.sp_show_border_elements;
1506 printf("Supaplex border elements %s\n",
1507 setup.sp_show_border_elements ? "enabled" : "disabled");
1516 case GAME_MODE_EDITOR:
1517 if (!anyTextGadgetActiveOrJustFinished || key == KSYM_Escape)
1518 HandleLevelEditorKeyInput(key);
1521 case GAME_MODE_PLAYING:
1526 RequestQuitGame(setup.ask_on_escape);
1533 if (GameFrameDelay == 500)
1534 GameFrameDelay = GAME_FRAME_DELAY;
1536 GameFrameDelay = 500;
1539 GameFrameDelay = (key - KSYM_0) * 10;
1540 printf("Game speed == %d%% (%d ms delay between two frames)\n",
1541 GAME_FRAME_DELAY * 100 / GameFrameDelay, GameFrameDelay);
1547 options.debug = FALSE;
1548 printf("debug mode disabled\n");
1552 options.debug = TRUE;
1553 printf("debug mode enabled\n");
1559 if (!global.fps_slowdown)
1561 global.fps_slowdown = TRUE;
1562 global.fps_slowdown_factor = 2;
1563 printf("fps slowdown enabled -- display only every 2nd frame\n");
1565 else if (global.fps_slowdown_factor == 2)
1567 global.fps_slowdown_factor = 4;
1568 printf("fps slowdown enabled -- display only every 4th frame\n");
1572 global.fps_slowdown = FALSE;
1573 global.fps_slowdown_factor = 1;
1574 printf("fps slowdown disabled\n");
1580 printf("::: currently using game engine version %d\n",
1581 game.engine_version);
1592 if (key == KSYM_Escape)
1594 game_status = GAME_MODE_MAIN;
1602 void HandleNoEvent()
1604 // if (button_status && game_status != GAME_MODE_PLAYING)
1605 if (button_status && (game_status != GAME_MODE_PLAYING || tape.pausing))
1607 HandleButton(0, 0, -button_status, button_status);
1614 #if defined(NETWORK_AVALIABLE)
1615 if (options.network)
1619 switch (game_status)
1621 case GAME_MODE_MAIN:
1622 DrawPreviewLevelAnimation();
1626 case GAME_MODE_LEVELS:
1627 case GAME_MODE_LEVELNR:
1628 case GAME_MODE_SETUP:
1629 case GAME_MODE_INFO:
1630 case GAME_MODE_SCORES:
1634 case GAME_MODE_EDITOR:
1635 HandleLevelEditorIdle();
1643 static int HandleJoystickForAllPlayers()
1648 for (i = 0; i < MAX_PLAYERS; i++)
1650 byte joy_action = 0;
1653 if (!setup.input[i].use_joystick)
1657 joy_action = Joystick(i);
1658 result |= joy_action;
1660 if (!setup.input[i].use_joystick)
1663 stored_player[i].action = joy_action;
1669 void HandleJoystick()
1671 int joystick = HandleJoystickForAllPlayers();
1672 int keyboard = key_joystick_mapping;
1673 int joy = (joystick | keyboard);
1674 int left = joy & JOY_LEFT;
1675 int right = joy & JOY_RIGHT;
1676 int up = joy & JOY_UP;
1677 int down = joy & JOY_DOWN;
1678 int button = joy & JOY_BUTTON;
1679 int newbutton = (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED);
1680 int dx = (left ? -1 : right ? 1 : 0);
1681 int dy = (up ? -1 : down ? 1 : 0);
1683 switch (game_status)
1685 case GAME_MODE_TITLE:
1686 case GAME_MODE_MAIN:
1687 case GAME_MODE_LEVELS:
1688 case GAME_MODE_LEVELNR:
1689 case GAME_MODE_SETUP:
1690 case GAME_MODE_INFO:
1692 static unsigned int joystickmove_delay = 0;
1694 if (joystick && !button &&
1695 !DelayReached(&joystickmove_delay, GADGET_FRAME_DELAY))
1696 newbutton = dx = dy = 0;
1698 if (game_status == GAME_MODE_TITLE)
1699 HandleTitleScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1700 else if (game_status == GAME_MODE_MAIN)
1701 HandleMainMenu(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1702 else if (game_status == GAME_MODE_LEVELS)
1703 HandleChooseLevelSet(0,0,dx,dy,newbutton?MB_MENU_CHOICE : MB_MENU_MARK);
1704 else if (game_status == GAME_MODE_LEVELNR)
1705 HandleChooseLevelNr(0,0,dx,dy,newbutton? MB_MENU_CHOICE : MB_MENU_MARK);
1706 else if (game_status == GAME_MODE_SETUP)
1707 HandleSetupScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1708 else if (game_status == GAME_MODE_INFO)
1709 HandleInfoScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1713 case GAME_MODE_SCORES:
1714 HandleHallOfFame(0, 0, dx, dy, !newbutton);
1717 case GAME_MODE_PLAYING:
1718 if (tape.playing || keyboard)
1719 newbutton = ((joy & JOY_BUTTON) != 0);
1721 if (newbutton && AllPlayersGone)