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 1
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 boolean playfield_cursor_set = FALSE;
37 static unsigned int playfield_cursor_delay = 0;
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 if (game_status == GAME_MODE_PLAYING && playfield_cursor_set)
69 SetMouseCursor(CURSOR_DEFAULT);
70 playfield_cursor_set = FALSE;
71 DelayReached(&playfield_cursor_delay, 0);
74 /* skip mouse motion events without pressed button outside level editor */
75 if (button_status == MB_RELEASED &&
76 game_status != GAME_MODE_EDITOR && game_status != GAME_MODE_PLAYING)
82 #if defined(TARGET_SDL2)
83 int FilterEvents(void *userdata, Event *event)
85 return FilterEventsExt(event);
88 int FilterEvents(const Event *event)
90 return FilterEventsExt(event);
94 /* to prevent delay problems, skip mouse motion events if the very next
95 event is also a mouse motion event (and therefore effectively only
96 handling the last of a row of mouse motion events in the event queue) */
98 boolean SkipPressedMouseMotionEvent(const Event *event)
100 /* nothing to do if the current event is not a mouse motion event */
101 if (event->type != EVENT_MOTIONNOTIFY)
104 /* only skip motion events with pressed button outside level editor */
105 if (button_status == MB_RELEASED ||
106 game_status == GAME_MODE_EDITOR || game_status == GAME_MODE_PLAYING)
113 PeekEvent(&next_event);
115 /* if next event is also a mouse motion event, skip the current one */
116 if (next_event.type == EVENT_MOTIONNOTIFY)
123 /* this is only really needed for non-SDL targets to filter unwanted events;
124 when using SDL with properly installed event filter, this function can be
125 replaced with a simple "NextEvent()" call, but it doesn't hurt either */
127 static boolean NextValidEvent(Event *event)
129 while (PendingEvent())
131 boolean handle_this_event = FALSE;
135 if (FilterEventsExt(event))
136 handle_this_event = TRUE;
138 if (SkipPressedMouseMotionEvent(event))
139 handle_this_event = FALSE;
141 if (handle_this_event)
152 if (PendingEvent()) /* got event */
156 while (NextValidEvent(&event))
160 case EVENT_BUTTONPRESS:
161 case EVENT_BUTTONRELEASE:
162 HandleButtonEvent((ButtonEvent *) &event);
165 case EVENT_MOTIONNOTIFY:
166 HandleMotionEvent((MotionEvent *) &event);
169 #if defined(TARGET_SDL2)
170 case SDL_WINDOWEVENT:
171 HandleWindowEvent((WindowEvent *) &event);
174 case EVENT_FINGERPRESS:
175 case EVENT_FINGERRELEASE:
176 case EVENT_FINGERMOTION:
177 HandleFingerEvent((FingerEvent *) &event);
180 case EVENT_TEXTINPUT:
181 HandleTextEvent((TextEvent *) &event);
184 case SDL_APP_WILLENTERBACKGROUND:
185 case SDL_APP_DIDENTERBACKGROUND:
186 case SDL_APP_WILLENTERFOREGROUND:
187 case SDL_APP_DIDENTERFOREGROUND:
188 HandlePauseResumeEvent((PauseResumeEvent *) &event);
193 case EVENT_KEYRELEASE:
194 HandleKeyEvent((KeyEvent *) &event);
198 HandleOtherEvents(&event);
205 /* when playing, display a special mouse pointer inside the playfield */
206 if (game_status == GAME_MODE_PLAYING && !tape.pausing)
208 if (!playfield_cursor_set && cursor_inside_playfield &&
209 DelayReached(&playfield_cursor_delay, 1000))
211 SetMouseCursor(CURSOR_PLAYFIELD);
212 playfield_cursor_set = TRUE;
215 else if (playfield_cursor_set)
217 SetMouseCursor(CURSOR_DEFAULT);
218 playfield_cursor_set = FALSE;
222 /* also execute after pending events have been processed before */
225 /* don't use all CPU time when idle; the main loop while playing
226 has its own synchronization and is CPU friendly, too */
228 if (game_status == GAME_MODE_PLAYING)
236 if (!PendingEvent()) /* delay only if no pending events */
240 /* refresh window contents from drawing buffer, if needed */
243 if (game_status == GAME_MODE_QUIT)
248 void HandleOtherEvents(Event *event)
253 HandleExposeEvent((ExposeEvent *) event);
256 case EVENT_UNMAPNOTIFY:
258 /* This causes the game to stop not only when iconified, but also
259 when on another virtual desktop, which might be not desired. */
260 SleepWhileUnmapped();
266 HandleFocusEvent((FocusChangeEvent *) event);
269 case EVENT_CLIENTMESSAGE:
270 HandleClientMessageEvent((ClientMessageEvent *) event);
273 #if defined(TARGET_SDL)
274 case SDL_JOYAXISMOTION:
275 case SDL_JOYBUTTONDOWN:
276 case SDL_JOYBUTTONUP:
277 HandleJoystickEvent(event);
281 HandleWindowManagerEvent(event);
290 void ClearEventQueue()
292 while (PendingEvent())
300 case EVENT_BUTTONRELEASE:
301 button_status = MB_RELEASED;
304 case EVENT_KEYRELEASE:
309 HandleOtherEvents(&event);
315 void ClearPlayerAction()
319 /* simulate key release events for still pressed keys */
320 key_joystick_mapping = 0;
321 for (i = 0; i < MAX_PLAYERS; i++)
322 stored_player[i].action = 0;
325 void SleepWhileUnmapped()
327 boolean window_unmapped = TRUE;
329 KeyboardAutoRepeatOn();
331 while (window_unmapped)
339 case EVENT_BUTTONRELEASE:
340 button_status = MB_RELEASED;
343 case EVENT_KEYRELEASE:
344 key_joystick_mapping = 0;
347 case EVENT_MAPNOTIFY:
348 window_unmapped = FALSE;
351 case EVENT_UNMAPNOTIFY:
352 /* this is only to surely prevent the 'should not happen' case
353 * of recursively looping between 'SleepWhileUnmapped()' and
354 * 'HandleOtherEvents()' which usually calls this funtion.
359 HandleOtherEvents(&event);
364 if (game_status == GAME_MODE_PLAYING)
365 KeyboardAutoRepeatOffUnlessAutoplay();
368 void HandleExposeEvent(ExposeEvent *event)
372 void HandleButtonEvent(ButtonEvent *event)
374 #if DEBUG_EVENTS_BUTTON
375 Error(ERR_DEBUG, "BUTTON EVENT: button %d %s, x/y %d/%d\n",
377 event->type == EVENT_BUTTONPRESS ? "pressed" : "released",
381 motion_status = FALSE;
383 if (event->type == EVENT_BUTTONPRESS)
384 button_status = event->button;
386 button_status = MB_RELEASED;
388 HandleButton(event->x, event->y, button_status, event->button);
391 void HandleMotionEvent(MotionEvent *event)
393 if (!PointerInWindow(window))
394 return; /* window and pointer are on different screens */
396 if (button_status == MB_RELEASED && game_status != GAME_MODE_EDITOR)
399 motion_status = TRUE;
401 #if DEBUG_EVENTS_MOTION
402 Error(ERR_DEBUG, "MOTION EVENT: button %d moved, x/y %d/%d\n",
403 button_status, event->x, event->y);
406 HandleButton(event->x, event->y, button_status, button_status);
409 #if defined(TARGET_SDL2)
411 void HandleWindowEvent(WindowEvent *event)
413 #if DEBUG_EVENTS_WINDOW
414 int subtype = event->event;
417 (subtype == SDL_WINDOWEVENT_SHOWN ? "SDL_WINDOWEVENT_SHOWN" :
418 subtype == SDL_WINDOWEVENT_HIDDEN ? "SDL_WINDOWEVENT_HIDDEN" :
419 subtype == SDL_WINDOWEVENT_EXPOSED ? "SDL_WINDOWEVENT_EXPOSED" :
420 subtype == SDL_WINDOWEVENT_MOVED ? "SDL_WINDOWEVENT_MOVED" :
421 subtype == SDL_WINDOWEVENT_SIZE_CHANGED ? "SDL_WINDOWEVENT_SIZE_CHANGED" :
422 subtype == SDL_WINDOWEVENT_RESIZED ? "SDL_WINDOWEVENT_RESIZED" :
423 subtype == SDL_WINDOWEVENT_MINIMIZED ? "SDL_WINDOWEVENT_MINIMIZED" :
424 subtype == SDL_WINDOWEVENT_MAXIMIZED ? "SDL_WINDOWEVENT_MAXIMIZED" :
425 subtype == SDL_WINDOWEVENT_RESTORED ? "SDL_WINDOWEVENT_RESTORED" :
426 subtype == SDL_WINDOWEVENT_ENTER ? "SDL_WINDOWEVENT_ENTER" :
427 subtype == SDL_WINDOWEVENT_LEAVE ? "SDL_WINDOWEVENT_LEAVE" :
428 subtype == SDL_WINDOWEVENT_FOCUS_GAINED ? "SDL_WINDOWEVENT_FOCUS_GAINED" :
429 subtype == SDL_WINDOWEVENT_FOCUS_LOST ? "SDL_WINDOWEVENT_FOCUS_LOST" :
430 subtype == SDL_WINDOWEVENT_CLOSE ? "SDL_WINDOWEVENT_CLOSE" :
433 Error(ERR_DEBUG, "WINDOW EVENT: '%s', %ld, %ld",
434 event_name, event->data1, event->data2);
437 if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED ||
438 event->event == SDL_WINDOWEVENT_RESIZED ||
439 event->event == SDL_WINDOWEVENT_EXPOSED)
442 if (event->event == SDL_WINDOWEVENT_RESIZED && !video.fullscreen_enabled)
444 int new_window_width = event->data1;
445 int new_window_height = event->data2;
447 // if window size has changed after resizing, calculate new scaling factor
448 if (new_window_width != video.window_width ||
449 new_window_height != video.window_height)
451 int new_xpercent = (100 * new_window_width / video.width);
452 int new_ypercent = (100 * new_window_height / video.height);
454 setup.window_scaling_percent = video.window_scaling_percent =
455 MIN(MAX(MIN_WINDOW_SCALING_PERCENT, MIN(new_xpercent, new_ypercent)),
456 MAX_WINDOW_SCALING_PERCENT);
458 video.window_width = new_window_width;
459 video.window_height = new_window_height;
461 if (game_status == GAME_MODE_SETUP)
462 RedrawSetupScreenAfterFullscreenToggle();
469 #define NUM_TOUCH_FINGERS 3
474 SDL_FingerID finger_id;
477 } touch_info[NUM_TOUCH_FINGERS];
479 void HandleFingerEvent(FingerEvent *event)
481 static Key motion_key_x = KSYM_UNDEFINED;
482 static Key motion_key_y = KSYM_UNDEFINED;
483 static Key button_key = KSYM_UNDEFINED;
484 static float motion_x1, motion_y1;
485 static float button_x1, button_y1;
486 static SDL_FingerID motion_id = -1;
487 static SDL_FingerID button_id = -1;
488 int move_trigger_distance_percent = 2; // percent of touchpad width/height
489 int drop_trigger_distance_percent = 5; // percent of touchpad width/height
490 float move_trigger_distance = (float)move_trigger_distance_percent / 100;
491 float drop_trigger_distance = (float)drop_trigger_distance_percent / 100;
492 float event_x = event->x;
493 float event_y = event->y;
495 #if DEBUG_EVENTS_FINGER
496 Error(ERR_DEBUG, "FINGER EVENT: finger was %s, touch ID %lld, finger ID %lld, x/y %f/%f, dx/dy %f/%f, pressure %f",
497 event->type == EVENT_FINGERPRESS ? "pressed" :
498 event->type == EVENT_FINGERRELEASE ? "released" : "moved",
502 event->dx, event->dy,
506 if (game_status != GAME_MODE_PLAYING)
509 if (strEqual(setup.touch.control_type, TOUCH_CONTROL_VIRTUAL_BUTTONS))
511 int key_status = (event->type == EVENT_FINGERRELEASE ? KEY_RELEASED :
513 Key key = (event->x < 1.0 / 3.0 ?
514 (event->y < 1.0 / 2.0 ? setup.input[0].key.snap :
515 setup.input[0].key.drop) :
516 event->x > 2.0 / 3.0 ?
517 (event->y < 1.0 / 3.0 ? setup.input[0].key.up :
518 event->y > 2.0 / 3.0 ? setup.input[0].key.down :
519 event->x < 5.0 / 6.0 ? setup.input[0].key.left :
520 setup.input[0].key.right) :
522 char *key_status_name = (key_status == KEY_RELEASED ? "KEY_RELEASED" :
526 Error(ERR_DEBUG, "::: key '%s' was '%s' [fingerId: %lld]",
527 getKeyNameFromKey(key), key_status_name, event->fingerId);
529 // check if we already know this touch event's finger id
530 for (i = 0; i < NUM_TOUCH_FINGERS; i++)
532 if (touch_info[i].touched &&
533 touch_info[i].finger_id == event->fingerId)
535 // Error(ERR_DEBUG, "MARK 1: %d", i);
541 if (i >= NUM_TOUCH_FINGERS)
543 if (key_status == KEY_PRESSED)
545 int oldest_pos = 0, oldest_counter = touch_info[0].counter;
547 // unknown finger id -- get new, empty slot, if available
548 for (i = 0; i < NUM_TOUCH_FINGERS; i++)
550 if (touch_info[i].counter < oldest_counter)
553 oldest_counter = touch_info[i].counter;
555 // Error(ERR_DEBUG, "MARK 2: %d", i);
558 if (!touch_info[i].touched)
560 // Error(ERR_DEBUG, "MARK 3: %d", i);
566 if (i >= NUM_TOUCH_FINGERS)
568 // all slots allocated -- use oldest slot
571 // Error(ERR_DEBUG, "MARK 4: %d", i);
576 // release of previously unknown key (should not happen)
578 if (key != KSYM_UNDEFINED)
580 HandleKey(key, KEY_RELEASED);
582 Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d] [1]",
583 getKeyNameFromKey(key), "KEY_RELEASED", i);
588 if (i < NUM_TOUCH_FINGERS)
590 if (key_status == KEY_PRESSED)
592 if (touch_info[i].key != key)
594 if (touch_info[i].key != KSYM_UNDEFINED)
596 HandleKey(touch_info[i].key, KEY_RELEASED);
598 Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d] [2]",
599 getKeyNameFromKey(touch_info[i].key), "KEY_RELEASED", i);
602 if (key != KSYM_UNDEFINED)
604 HandleKey(key, KEY_PRESSED);
606 Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d] [3]",
607 getKeyNameFromKey(key), "KEY_PRESSED", i);
611 touch_info[i].touched = TRUE;
612 touch_info[i].finger_id = event->fingerId;
613 touch_info[i].counter = Counter();
614 touch_info[i].key = key;
618 if (touch_info[i].key != KSYM_UNDEFINED)
620 HandleKey(touch_info[i].key, KEY_RELEASED);
622 Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d] [4]",
623 getKeyNameFromKey(touch_info[i].key), "KEY_RELEASED", i);
626 touch_info[i].touched = FALSE;
627 touch_info[i].finger_id = 0;
628 touch_info[i].counter = 0;
629 touch_info[i].key = 0;
636 // use touch direction control
638 if (event->type == EVENT_FINGERPRESS)
640 if (event_x > 1.0 / 3.0)
644 motion_id = event->fingerId;
649 motion_key_x = KSYM_UNDEFINED;
650 motion_key_y = KSYM_UNDEFINED;
652 Error(ERR_DEBUG, "---------- MOVE STARTED (WAIT) ----------");
658 button_id = event->fingerId;
663 button_key = setup.input[0].key.snap;
665 HandleKey(button_key, KEY_PRESSED);
667 Error(ERR_DEBUG, "---------- SNAP STARTED ----------");
670 else if (event->type == EVENT_FINGERRELEASE)
672 if (event->fingerId == motion_id)
676 if (motion_key_x != KSYM_UNDEFINED)
677 HandleKey(motion_key_x, KEY_RELEASED);
678 if (motion_key_y != KSYM_UNDEFINED)
679 HandleKey(motion_key_y, KEY_RELEASED);
681 motion_key_x = KSYM_UNDEFINED;
682 motion_key_y = KSYM_UNDEFINED;
684 Error(ERR_DEBUG, "---------- MOVE STOPPED ----------");
686 else if (event->fingerId == button_id)
690 if (button_key != KSYM_UNDEFINED)
691 HandleKey(button_key, KEY_RELEASED);
693 button_key = KSYM_UNDEFINED;
695 Error(ERR_DEBUG, "---------- SNAP STOPPED ----------");
698 else if (event->type == EVENT_FINGERMOTION)
700 if (event->fingerId == motion_id)
702 float distance_x = ABS(event_x - motion_x1);
703 float distance_y = ABS(event_y - motion_y1);
704 Key new_motion_key_x = (event_x < motion_x1 ? setup.input[0].key.left :
705 event_x > motion_x1 ? setup.input[0].key.right :
707 Key new_motion_key_y = (event_y < motion_y1 ? setup.input[0].key.up :
708 event_y > motion_y1 ? setup.input[0].key.down :
711 if (distance_x < move_trigger_distance / 2 ||
712 distance_x < distance_y)
713 new_motion_key_x = KSYM_UNDEFINED;
715 if (distance_y < move_trigger_distance / 2 ||
716 distance_y < distance_x)
717 new_motion_key_y = KSYM_UNDEFINED;
719 if (distance_x > move_trigger_distance ||
720 distance_y > move_trigger_distance)
722 if (new_motion_key_x != motion_key_x)
724 if (motion_key_x != KSYM_UNDEFINED)
725 HandleKey(motion_key_x, KEY_RELEASED);
726 if (new_motion_key_x != KSYM_UNDEFINED)
727 HandleKey(new_motion_key_x, KEY_PRESSED);
730 if (new_motion_key_y != motion_key_y)
732 if (motion_key_y != KSYM_UNDEFINED)
733 HandleKey(motion_key_y, KEY_RELEASED);
734 if (new_motion_key_y != KSYM_UNDEFINED)
735 HandleKey(new_motion_key_y, KEY_PRESSED);
741 motion_key_x = new_motion_key_x;
742 motion_key_y = new_motion_key_y;
744 Error(ERR_DEBUG, "---------- MOVE STARTED (MOVE) ----------");
747 else if (event->fingerId == button_id)
749 float distance_x = ABS(event_x - button_x1);
750 float distance_y = ABS(event_y - button_y1);
752 if (distance_x < drop_trigger_distance / 2 &&
753 distance_y > drop_trigger_distance)
755 if (button_key == setup.input[0].key.snap)
756 HandleKey(button_key, KEY_RELEASED);
761 button_key = setup.input[0].key.drop;
763 HandleKey(button_key, KEY_PRESSED);
765 Error(ERR_DEBUG, "---------- DROP STARTED ----------");
771 static boolean checkTextInputKeyModState()
773 // when playing, only handle raw key events and ignore text input
774 if (game_status == GAME_MODE_PLAYING)
777 return ((GetKeyModState() & KMOD_TextInput) != KMOD_None);
780 void HandleTextEvent(TextEvent *event)
782 char *text = event->text;
783 Key key = getKeyFromKeyName(text);
785 #if DEBUG_EVENTS_TEXT
786 Error(ERR_DEBUG, "TEXT EVENT: text == '%s' [%d byte(s), '%c'/%d], resulting key == %d (%s) [%04x]",
789 text[0], (int)(text[0]),
791 getKeyNameFromKey(key),
795 #if defined(PLATFORM_ANDROID)
796 if (game_status == GAME_MODE_PSEUDO_TYPENAME)
798 HandleTypeName(0, key);
804 // if (game_status != GAME_MODE_PLAYING && GetKeyModState() != KMOD_None)
806 if (game_status != GAME_MODE_PLAYING &&
807 (GetKeyModState() & KMOD_TextInput) != KMOD_None)
809 if (checkTextInputKeyModState())
811 HandleKey(key, KEY_PRESSED);
812 HandleKey(key, KEY_RELEASED);
816 void HandlePauseResumeEvent(PauseResumeEvent *event)
818 if (event->type == SDL_APP_WILLENTERBACKGROUND)
822 else if (event->type == SDL_APP_DIDENTERFOREGROUND)
830 void HandleKeyEvent(KeyEvent *event)
832 int key_status = (event->type == EVENT_KEYPRESS ? KEY_PRESSED : KEY_RELEASED);
833 boolean with_modifiers = (game_status == GAME_MODE_PLAYING ? FALSE : TRUE);
834 Key key = GetEventKey(event, with_modifiers);
835 Key keymod = (with_modifiers ? GetEventKey(event, FALSE) : key);
838 Error(ERR_DEBUG, "KEY EVENT: key was %s, keysym.scancode == %d, keysym.sym == %d, keymod = %d, GetKeyModState() = 0x%04x, resulting key == %d (%s)",
839 event->type == EVENT_KEYPRESS ? "pressed" : "released",
840 event->keysym.scancode,
845 getKeyNameFromKey(key));
848 #if defined(PLATFORM_ANDROID)
849 // always map the "back" button to the "escape" key on Android devices
850 if (key == KSYM_Back)
854 HandleKeyModState(keymod, key_status);
856 #if defined(TARGET_SDL2)
857 if (!checkTextInputKeyModState())
858 HandleKey(key, key_status);
860 HandleKey(key, key_status);
864 void HandleFocusEvent(FocusChangeEvent *event)
866 static int old_joystick_status = -1;
868 if (event->type == EVENT_FOCUSOUT)
870 KeyboardAutoRepeatOn();
871 old_joystick_status = joystick.status;
872 joystick.status = JOYSTICK_NOT_AVAILABLE;
876 else if (event->type == EVENT_FOCUSIN)
878 /* When there are two Rocks'n'Diamonds windows which overlap and
879 the player moves the pointer from one game window to the other,
880 a 'FocusOut' event is generated for the window the pointer is
881 leaving and a 'FocusIn' event is generated for the window the
882 pointer is entering. In some cases, it can happen that the
883 'FocusIn' event is handled by the one game process before the
884 'FocusOut' event by the other game process. In this case the
885 X11 environment would end up with activated keyboard auto repeat,
886 because unfortunately this is a global setting and not (which
887 would be far better) set for each X11 window individually.
888 The effect would be keyboard auto repeat while playing the game
889 (game_status == GAME_MODE_PLAYING), which is not desired.
890 To avoid this special case, we just wait 1/10 second before
891 processing the 'FocusIn' event.
894 if (game_status == GAME_MODE_PLAYING)
897 KeyboardAutoRepeatOffUnlessAutoplay();
900 if (old_joystick_status != -1)
901 joystick.status = old_joystick_status;
905 void HandleClientMessageEvent(ClientMessageEvent *event)
907 if (CheckCloseWindowEvent(event))
911 void HandleWindowManagerEvent(Event *event)
913 #if defined(TARGET_SDL)
914 SDLHandleWindowManagerEvent(event);
918 void HandleButton(int mx, int my, int button, int button_nr)
920 static int old_mx = 0, old_my = 0;
934 #if defined(PLATFORM_ANDROID)
935 if (game_status != GAME_MODE_PLAYING &&
936 HandleGadgets(mx, my, button))
938 /* do not handle this button event anymore */
939 mx = my = -32; /* force mouse event to be outside screen tiles */
942 if (HandleGadgets(mx, my, button))
944 /* do not handle this button event anymore */
945 mx = my = -32; /* force mouse event to be outside screen tiles */
949 /* do not use scroll wheel button events for anything other than gadgets */
950 if (IS_WHEEL_BUTTON(button_nr))
955 case GAME_MODE_TITLE:
956 HandleTitleScreen(mx, my, 0, 0, button);
960 HandleMainMenu(mx, my, 0, 0, button);
963 case GAME_MODE_PSEUDO_TYPENAME:
964 HandleTypeName(0, KSYM_Return);
967 case GAME_MODE_LEVELS:
968 HandleChooseLevelSet(mx, my, 0, 0, button);
971 case GAME_MODE_LEVELNR:
972 HandleChooseLevelNr(mx, my, 0, 0, button);
975 case GAME_MODE_SCORES:
976 HandleHallOfFame(0, 0, 0, 0, button);
979 case GAME_MODE_EDITOR:
980 HandleLevelEditorIdle();
984 HandleInfoScreen(mx, my, 0, 0, button);
987 case GAME_MODE_SETUP:
988 HandleSetupScreen(mx, my, 0, 0, button);
991 case GAME_MODE_PLAYING:
993 if (button == MB_PRESSED && !motion_status && IN_GFX_FIELD_PLAY(mx, my))
994 DumpTile(LEVELX((mx - SX) / TILESIZE_VAR),
995 LEVELY((my - SY) / TILESIZE_VAR));
996 // DumpTile(LEVELX((mx - SX) / TILEX), LEVELY((my - SY) / TILEY));
1005 static boolean is_string_suffix(char *string, char *suffix)
1007 int string_len = strlen(string);
1008 int suffix_len = strlen(suffix);
1010 if (suffix_len > string_len)
1013 return (strEqual(&string[string_len - suffix_len], suffix));
1016 #define MAX_CHEAT_INPUT_LEN 32
1018 static void HandleKeysSpecial(Key key)
1020 static char cheat_input[2 * MAX_CHEAT_INPUT_LEN + 1] = "";
1021 char letter = getCharFromKey(key);
1022 int cheat_input_len = strlen(cheat_input);
1028 if (cheat_input_len >= 2 * MAX_CHEAT_INPUT_LEN)
1030 for (i = 0; i < MAX_CHEAT_INPUT_LEN + 1; i++)
1031 cheat_input[i] = cheat_input[MAX_CHEAT_INPUT_LEN + i];
1033 cheat_input_len = MAX_CHEAT_INPUT_LEN;
1036 cheat_input[cheat_input_len++] = letter;
1037 cheat_input[cheat_input_len] = '\0';
1039 #if DEBUG_EVENTS_KEY
1040 Error(ERR_DEBUG, "SPECIAL KEY '%s' [%d]\n", cheat_input, cheat_input_len);
1043 if (game_status == GAME_MODE_MAIN)
1045 if (is_string_suffix(cheat_input, ":insert-solution-tape") ||
1046 is_string_suffix(cheat_input, ":ist"))
1048 InsertSolutionTape();
1050 else if (is_string_suffix(cheat_input, ":reload-graphics") ||
1051 is_string_suffix(cheat_input, ":rg"))
1053 ReloadCustomArtwork(1 << ARTWORK_TYPE_GRAPHICS);
1056 else if (is_string_suffix(cheat_input, ":reload-sounds") ||
1057 is_string_suffix(cheat_input, ":rs"))
1059 ReloadCustomArtwork(1 << ARTWORK_TYPE_SOUNDS);
1062 else if (is_string_suffix(cheat_input, ":reload-music") ||
1063 is_string_suffix(cheat_input, ":rm"))
1065 ReloadCustomArtwork(1 << ARTWORK_TYPE_MUSIC);
1068 else if (is_string_suffix(cheat_input, ":reload-artwork") ||
1069 is_string_suffix(cheat_input, ":ra"))
1071 ReloadCustomArtwork(1 << ARTWORK_TYPE_GRAPHICS |
1072 1 << ARTWORK_TYPE_SOUNDS |
1073 1 << ARTWORK_TYPE_MUSIC);
1076 else if (is_string_suffix(cheat_input, ":dump-level") ||
1077 is_string_suffix(cheat_input, ":dl"))
1081 else if (is_string_suffix(cheat_input, ":dump-tape") ||
1082 is_string_suffix(cheat_input, ":dt"))
1086 else if (is_string_suffix(cheat_input, ":fix-tape") ||
1087 is_string_suffix(cheat_input, ":ft"))
1089 /* fix single-player tapes that contain player input for more than one
1090 player (due to a bug in 3.3.1.2 and earlier versions), which results
1091 in playing levels with more than one player in multi-player mode,
1092 even though the tape was originally recorded in single-player mode */
1094 /* remove player input actions for all players but the first one */
1095 for (i = 1; i < MAX_PLAYERS; i++)
1096 tape.player_participates[i] = FALSE;
1098 tape.changed = TRUE;
1100 else if (is_string_suffix(cheat_input, ":save-native-level") ||
1101 is_string_suffix(cheat_input, ":snl"))
1103 SaveNativeLevel(&level);
1106 else if (game_status == GAME_MODE_PLAYING)
1109 if (is_string_suffix(cheat_input, ".q"))
1110 DEBUG_SetMaximumDynamite();
1113 else if (game_status == GAME_MODE_EDITOR)
1115 if (is_string_suffix(cheat_input, ":dump-brush") ||
1116 is_string_suffix(cheat_input, ":DB"))
1120 else if (is_string_suffix(cheat_input, ":DDB"))
1127 void HandleKey(Key key, int key_status)
1129 boolean anyTextGadgetActiveOrJustFinished = anyTextGadgetActive();
1130 static struct SetupKeyboardInfo ski;
1131 static struct SetupShortcutInfo ssi;
1140 { &ski.left, &ssi.snap_left, DEFAULT_KEY_LEFT, JOY_LEFT },
1141 { &ski.right, &ssi.snap_right, DEFAULT_KEY_RIGHT, JOY_RIGHT },
1142 { &ski.up, &ssi.snap_up, DEFAULT_KEY_UP, JOY_UP },
1143 { &ski.down, &ssi.snap_down, DEFAULT_KEY_DOWN, JOY_DOWN },
1144 { &ski.snap, NULL, DEFAULT_KEY_SNAP, JOY_BUTTON_SNAP },
1145 { &ski.drop, NULL, DEFAULT_KEY_DROP, JOY_BUTTON_DROP }
1150 if (game_status == GAME_MODE_PLAYING)
1152 /* only needed for single-step tape recording mode */
1153 static boolean clear_snap_button[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1154 static boolean clear_drop_button[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1155 static boolean element_snapped[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1156 static boolean element_dropped[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1159 for (pnr = 0; pnr < MAX_PLAYERS; pnr++)
1161 byte key_action = 0;
1163 if (setup.input[pnr].use_joystick)
1166 ski = setup.input[pnr].key;
1168 for (i = 0; i < NUM_PLAYER_ACTIONS; i++)
1169 if (key == *key_info[i].key_custom)
1170 key_action |= key_info[i].action;
1172 /* use combined snap+direction keys for the first player only */
1175 ssi = setup.shortcut;
1177 for (i = 0; i < NUM_DIRECTIONS; i++)
1178 if (key == *key_info[i].key_snap)
1179 key_action |= key_info[i].action | JOY_BUTTON_SNAP;
1182 /* clear delayed snap and drop actions in single step mode (see below) */
1183 if (tape.single_step)
1185 if (clear_snap_button[pnr])
1187 stored_player[pnr].action &= ~KEY_BUTTON_SNAP;
1188 clear_snap_button[pnr] = FALSE;
1191 if (clear_drop_button[pnr])
1193 stored_player[pnr].action &= ~KEY_BUTTON_DROP;
1194 clear_drop_button[pnr] = FALSE;
1198 if (key_status == KEY_PRESSED)
1199 stored_player[pnr].action |= key_action;
1201 stored_player[pnr].action &= ~key_action;
1203 if (tape.single_step && tape.recording && tape.pausing)
1205 if (key_status == KEY_PRESSED && key_action & KEY_MOTION)
1207 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1209 /* if snap key already pressed, don't snap when releasing (below) */
1210 if (stored_player[pnr].action & KEY_BUTTON_SNAP)
1211 element_snapped[pnr] = TRUE;
1213 /* if drop key already pressed, don't drop when releasing (below) */
1214 if (stored_player[pnr].action & KEY_BUTTON_DROP)
1215 element_dropped[pnr] = TRUE;
1217 else if (key_status == KEY_PRESSED && key_action & KEY_BUTTON_DROP)
1219 if (level.game_engine_type == GAME_ENGINE_TYPE_EM ||
1220 level.game_engine_type == GAME_ENGINE_TYPE_SP)
1223 if (level.game_engine_type == GAME_ENGINE_TYPE_SP &&
1224 getRedDiskReleaseFlag_SP() == 0)
1225 stored_player[pnr].action &= ~KEY_BUTTON_DROP;
1227 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1230 else if (key_status == KEY_RELEASED && key_action & KEY_BUTTON)
1232 if (key_action & KEY_BUTTON_SNAP)
1234 /* if snap key was released without moving (see above), snap now */
1235 if (!element_snapped[pnr])
1237 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1239 stored_player[pnr].action |= KEY_BUTTON_SNAP;
1241 /* clear delayed snap button on next event */
1242 clear_snap_button[pnr] = TRUE;
1245 element_snapped[pnr] = FALSE;
1248 if (key_action & KEY_BUTTON_DROP &&
1249 level.game_engine_type == GAME_ENGINE_TYPE_RND)
1251 /* if drop key was released without moving (see above), drop now */
1252 if (!element_dropped[pnr])
1254 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1256 if (level.game_engine_type != GAME_ENGINE_TYPE_SP ||
1257 getRedDiskReleaseFlag_SP() != 0)
1258 stored_player[pnr].action |= KEY_BUTTON_DROP;
1260 /* clear delayed drop button on next event */
1261 clear_drop_button[pnr] = TRUE;
1264 element_dropped[pnr] = FALSE;
1268 else if (tape.recording && tape.pausing)
1270 /* prevent key release events from un-pausing a paused game */
1271 if (key_status == KEY_PRESSED && key_action & KEY_ACTION)
1272 TapeTogglePause(TAPE_TOGGLE_MANUAL);
1278 for (i = 0; i < NUM_PLAYER_ACTIONS; i++)
1279 if (key == key_info[i].key_default)
1280 joy |= key_info[i].action;
1285 if (key_status == KEY_PRESSED)
1286 key_joystick_mapping |= joy;
1288 key_joystick_mapping &= ~joy;
1293 if (game_status != GAME_MODE_PLAYING)
1294 key_joystick_mapping = 0;
1296 if (key_status == KEY_RELEASED)
1299 if ((key == KSYM_F11 ||
1300 ((key == KSYM_Return ||
1301 key == KSYM_KP_Enter) && (GetKeyModState() & KMOD_Alt))) &&
1302 video.fullscreen_available)
1304 setup.fullscreen = !setup.fullscreen;
1306 ToggleFullscreenOrChangeWindowScalingIfNeeded();
1308 if (game_status == GAME_MODE_SETUP)
1309 RedrawSetupScreenAfterFullscreenToggle();
1314 if ((key == KSYM_minus ||
1317 ((GetKeyModState() & KMOD_Control) ||
1318 (GetKeyModState() & KMOD_Alt)) &&
1319 video.window_scaling_available &&
1320 !video.fullscreen_enabled)
1323 setup.window_scaling_percent = STD_WINDOW_SCALING_PERCENT;
1325 setup.window_scaling_percent +=
1326 (key == KSYM_minus ? -1 : +1) * STEP_WINDOW_SCALING_PERCENT;
1328 if (setup.window_scaling_percent < MIN_WINDOW_SCALING_PERCENT)
1329 setup.window_scaling_percent = MIN_WINDOW_SCALING_PERCENT;
1330 else if (setup.window_scaling_percent > MAX_WINDOW_SCALING_PERCENT)
1331 setup.window_scaling_percent = MAX_WINDOW_SCALING_PERCENT;
1333 ToggleFullscreenOrChangeWindowScalingIfNeeded();
1335 if (game_status == GAME_MODE_SETUP)
1336 RedrawSetupScreenAfterFullscreenToggle();
1341 if (game_status == GAME_MODE_PLAYING && AllPlayersGone &&
1342 (key == KSYM_Return || key == setup.shortcut.toggle_pause))
1349 if (game_status == GAME_MODE_MAIN &&
1350 (key == setup.shortcut.toggle_pause || key == KSYM_space))
1352 StartGameActions(options.network, setup.autorecord, level.random_seed);
1357 if (game_status == GAME_MODE_MAIN || game_status == GAME_MODE_PLAYING)
1359 if (key == setup.shortcut.save_game)
1361 else if (key == setup.shortcut.load_game)
1363 else if (key == setup.shortcut.toggle_pause)
1364 TapeTogglePause(TAPE_TOGGLE_MANUAL);
1366 HandleTapeButtonKeys(key);
1367 HandleSoundButtonKeys(key);
1370 if (game_status == GAME_MODE_PLAYING && !network_playing)
1372 int centered_player_nr_next = -999;
1374 if (key == setup.shortcut.focus_player_all)
1375 centered_player_nr_next = -1;
1377 for (i = 0; i < MAX_PLAYERS; i++)
1378 if (key == setup.shortcut.focus_player[i])
1379 centered_player_nr_next = i;
1381 if (centered_player_nr_next != -999)
1383 game.centered_player_nr_next = centered_player_nr_next;
1384 game.set_centered_player = TRUE;
1388 tape.centered_player_nr_next = game.centered_player_nr_next;
1389 tape.set_centered_player = TRUE;
1394 HandleKeysSpecial(key);
1396 if (HandleGadgetsKeyInput(key))
1398 if (key != KSYM_Escape) /* always allow ESC key to be handled */
1399 key = KSYM_UNDEFINED;
1402 switch (game_status)
1404 case GAME_MODE_PSEUDO_TYPENAME:
1405 HandleTypeName(0, key);
1408 case GAME_MODE_TITLE:
1409 case GAME_MODE_MAIN:
1410 case GAME_MODE_LEVELS:
1411 case GAME_MODE_LEVELNR:
1412 case GAME_MODE_SETUP:
1413 case GAME_MODE_INFO:
1414 case GAME_MODE_SCORES:
1419 if (game_status == GAME_MODE_TITLE)
1420 HandleTitleScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1421 else if (game_status == GAME_MODE_MAIN)
1422 HandleMainMenu(0, 0, 0, 0, MB_MENU_CHOICE);
1423 else if (game_status == GAME_MODE_LEVELS)
1424 HandleChooseLevelSet(0, 0, 0, 0, MB_MENU_CHOICE);
1425 else if (game_status == GAME_MODE_LEVELNR)
1426 HandleChooseLevelNr(0, 0, 0, 0, MB_MENU_CHOICE);
1427 else if (game_status == GAME_MODE_SETUP)
1428 HandleSetupScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1429 else if (game_status == GAME_MODE_INFO)
1430 HandleInfoScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1431 else if (game_status == GAME_MODE_SCORES)
1432 HandleHallOfFame(0, 0, 0, 0, MB_MENU_CHOICE);
1436 if (game_status != GAME_MODE_MAIN)
1437 FadeSkipNextFadeIn();
1439 if (game_status == GAME_MODE_TITLE)
1440 HandleTitleScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1441 else if (game_status == GAME_MODE_LEVELS)
1442 HandleChooseLevelSet(0, 0, 0, 0, MB_MENU_LEAVE);
1443 else if (game_status == GAME_MODE_LEVELNR)
1444 HandleChooseLevelNr(0, 0, 0, 0, MB_MENU_LEAVE);
1445 else if (game_status == GAME_MODE_SETUP)
1446 HandleSetupScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1447 else if (game_status == GAME_MODE_INFO)
1448 HandleInfoScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1449 else if (game_status == GAME_MODE_SCORES)
1450 HandleHallOfFame(0, 0, 0, 0, MB_MENU_LEAVE);
1454 if (game_status == GAME_MODE_LEVELS)
1455 HandleChooseLevelSet(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1456 else if (game_status == GAME_MODE_LEVELNR)
1457 HandleChooseLevelNr(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1458 else if (game_status == GAME_MODE_SETUP)
1459 HandleSetupScreen(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1460 else if (game_status == GAME_MODE_INFO)
1461 HandleInfoScreen(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1462 else if (game_status == GAME_MODE_SCORES)
1463 HandleHallOfFame(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1466 case KSYM_Page_Down:
1467 if (game_status == GAME_MODE_LEVELS)
1468 HandleChooseLevelSet(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1469 else if (game_status == GAME_MODE_LEVELNR)
1470 HandleChooseLevelNr(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1471 else if (game_status == GAME_MODE_SETUP)
1472 HandleSetupScreen(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1473 else if (game_status == GAME_MODE_INFO)
1474 HandleInfoScreen(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1475 else if (game_status == GAME_MODE_SCORES)
1476 HandleHallOfFame(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1481 GameFrameDelay = (GameFrameDelay == 500 ? GAME_FRAME_DELAY : 500);
1485 setup.sp_show_border_elements = !setup.sp_show_border_elements;
1486 printf("Supaplex border elements %s\n",
1487 setup.sp_show_border_elements ? "enabled" : "disabled");
1496 case GAME_MODE_EDITOR:
1497 if (!anyTextGadgetActiveOrJustFinished || key == KSYM_Escape)
1498 HandleLevelEditorKeyInput(key);
1501 case GAME_MODE_PLAYING:
1506 RequestQuitGame(setup.ask_on_escape);
1513 if (GameFrameDelay == 500)
1514 GameFrameDelay = GAME_FRAME_DELAY;
1516 GameFrameDelay = 500;
1519 GameFrameDelay = (key - KSYM_0) * 10;
1520 printf("Game speed == %d%% (%d ms delay between two frames)\n",
1521 GAME_FRAME_DELAY * 100 / GameFrameDelay, GameFrameDelay);
1527 options.debug = FALSE;
1528 printf("debug mode disabled\n");
1532 options.debug = TRUE;
1533 printf("debug mode enabled\n");
1539 if (!global.fps_slowdown)
1541 global.fps_slowdown = TRUE;
1542 global.fps_slowdown_factor = 2;
1543 printf("fps slowdown enabled -- display only every 2nd frame\n");
1545 else if (global.fps_slowdown_factor == 2)
1547 global.fps_slowdown_factor = 4;
1548 printf("fps slowdown enabled -- display only every 4th frame\n");
1552 global.fps_slowdown = FALSE;
1553 global.fps_slowdown_factor = 1;
1554 printf("fps slowdown disabled\n");
1560 printf("::: currently using game engine version %d\n",
1561 game.engine_version);
1572 if (key == KSYM_Escape)
1574 game_status = GAME_MODE_MAIN;
1582 void HandleNoEvent()
1584 if (button_status && game_status != GAME_MODE_PLAYING)
1586 HandleButton(0, 0, -button_status, button_status);
1593 #if defined(NETWORK_AVALIABLE)
1594 if (options.network)
1598 switch (game_status)
1600 case GAME_MODE_MAIN:
1601 DrawPreviewLevelAnimation();
1605 case GAME_MODE_LEVELS:
1606 case GAME_MODE_LEVELNR:
1607 case GAME_MODE_SETUP:
1608 case GAME_MODE_INFO:
1609 case GAME_MODE_SCORES:
1613 case GAME_MODE_EDITOR:
1614 HandleLevelEditorIdle();
1622 static int HandleJoystickForAllPlayers()
1627 for (i = 0; i < MAX_PLAYERS; i++)
1629 byte joy_action = 0;
1632 if (!setup.input[i].use_joystick)
1636 joy_action = Joystick(i);
1637 result |= joy_action;
1639 if (!setup.input[i].use_joystick)
1642 stored_player[i].action = joy_action;
1648 void HandleJoystick()
1650 int joystick = HandleJoystickForAllPlayers();
1651 int keyboard = key_joystick_mapping;
1652 int joy = (joystick | keyboard);
1653 int left = joy & JOY_LEFT;
1654 int right = joy & JOY_RIGHT;
1655 int up = joy & JOY_UP;
1656 int down = joy & JOY_DOWN;
1657 int button = joy & JOY_BUTTON;
1658 int newbutton = (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED);
1659 int dx = (left ? -1 : right ? 1 : 0);
1660 int dy = (up ? -1 : down ? 1 : 0);
1662 switch (game_status)
1664 case GAME_MODE_TITLE:
1665 case GAME_MODE_MAIN:
1666 case GAME_MODE_LEVELS:
1667 case GAME_MODE_LEVELNR:
1668 case GAME_MODE_SETUP:
1669 case GAME_MODE_INFO:
1671 static unsigned int joystickmove_delay = 0;
1673 if (joystick && !button &&
1674 !DelayReached(&joystickmove_delay, GADGET_FRAME_DELAY))
1675 newbutton = dx = dy = 0;
1677 if (game_status == GAME_MODE_TITLE)
1678 HandleTitleScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1679 else if (game_status == GAME_MODE_MAIN)
1680 HandleMainMenu(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1681 else if (game_status == GAME_MODE_LEVELS)
1682 HandleChooseLevelSet(0,0,dx,dy,newbutton?MB_MENU_CHOICE : MB_MENU_MARK);
1683 else if (game_status == GAME_MODE_LEVELNR)
1684 HandleChooseLevelNr(0,0,dx,dy,newbutton? MB_MENU_CHOICE : MB_MENU_MARK);
1685 else if (game_status == GAME_MODE_SETUP)
1686 HandleSetupScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1687 else if (game_status == GAME_MODE_INFO)
1688 HandleInfoScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1692 case GAME_MODE_SCORES:
1693 HandleHallOfFame(0, 0, dx, dy, !newbutton);
1696 case GAME_MODE_PLAYING:
1697 if (tape.playing || keyboard)
1698 newbutton = ((joy & JOY_BUTTON) != 0);
1700 if (newbutton && AllPlayersGone)