1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2006 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
14 #include "libgame/libgame.h"
27 #define DEBUG_EVENTS 0
30 static boolean cursor_inside_playfield = FALSE;
31 static boolean playfield_cursor_set = FALSE;
32 static unsigned int playfield_cursor_delay = 0;
35 /* event filter especially needed for SDL event filtering due to
36 delay problems with lots of mouse motion events when mouse button
37 not pressed (X11 can handle this with 'PointerMotionHintMask') */
39 /* event filter addition for SDL2: as SDL2 does not have a function to enable
40 or disable keyboard auto-repeat, filter repeated keyboard events instead */
42 static int FilterEventsExt(const Event *event)
46 #if defined(TARGET_SDL2)
47 /* skip repeated key press events if keyboard auto-repeat is disabled */
48 if (event->type == EVENT_KEYPRESS &&
54 /* non-motion events are directly passed to event handler functions */
55 if (event->type != EVENT_MOTIONNOTIFY)
58 motion = (MotionEvent *)event;
59 cursor_inside_playfield = (motion->x >= SX && motion->x < SX + SXSIZE &&
60 motion->y >= SY && motion->y < SY + SYSIZE);
62 if (game_status == GAME_MODE_PLAYING && playfield_cursor_set)
64 SetMouseCursor(CURSOR_DEFAULT);
65 playfield_cursor_set = FALSE;
66 DelayReached(&playfield_cursor_delay, 0);
69 /* skip mouse motion events without pressed button outside level editor */
70 if (button_status == MB_RELEASED &&
71 game_status != GAME_MODE_EDITOR && game_status != GAME_MODE_PLAYING)
77 #if defined(TARGET_SDL2)
78 int FilterEvents(void *userdata, Event *event)
80 return FilterEventsExt(event);
83 int FilterEvents(const Event *event)
85 return FilterEventsExt(event);
89 /* to prevent delay problems, skip mouse motion events if the very next
90 event is also a mouse motion event (and therefore effectively only
91 handling the last of a row of mouse motion events in the event queue) */
93 boolean SkipPressedMouseMotionEvent(const Event *event)
95 /* nothing to do if the current event is not a mouse motion event */
96 if (event->type != EVENT_MOTIONNOTIFY)
99 /* only skip motion events with pressed button outside level editor */
100 if (button_status == MB_RELEASED ||
101 game_status == GAME_MODE_EDITOR || game_status == GAME_MODE_PLAYING)
108 PeekEvent(&next_event);
110 /* if next event is also a mouse motion event, skip the current one */
111 if (next_event.type == EVENT_MOTIONNOTIFY)
118 /* this is only really needed for non-SDL targets to filter unwanted events;
119 when using SDL with properly installed event filter, this function can be
120 replaced with a simple "NextEvent()" call, but it doesn't hurt either */
122 static boolean NextValidEvent(Event *event)
124 while (PendingEvent())
126 boolean handle_this_event = FALSE;
130 if (FilterEventsExt(event))
131 handle_this_event = TRUE;
133 if (SkipPressedMouseMotionEvent(event))
134 handle_this_event = FALSE;
136 if (handle_this_event)
147 if (PendingEvent()) /* got event */
151 while (NextValidEvent(&event))
155 case EVENT_BUTTONPRESS:
156 case EVENT_BUTTONRELEASE:
157 HandleButtonEvent((ButtonEvent *) &event);
160 case EVENT_MOTIONNOTIFY:
161 HandleMotionEvent((MotionEvent *) &event);
164 #if defined(TARGET_SDL2)
165 case SDL_WINDOWEVENT:
166 HandleWindowEvent((WindowEvent *) &event);
169 case EVENT_FINGERPRESS:
170 case EVENT_FINGERRELEASE:
171 case EVENT_FINGERMOTION:
172 HandleFingerEvent((FingerEvent *) &event);
175 case EVENT_TEXTINPUT:
176 HandleTextEvent((TextEvent *) &event);
181 case EVENT_KEYRELEASE:
182 HandleKeyEvent((KeyEvent *) &event);
186 HandleOtherEvents(&event);
193 /* when playing, display a special mouse pointer inside the playfield */
194 if (game_status == GAME_MODE_PLAYING && !tape.pausing)
196 if (!playfield_cursor_set && cursor_inside_playfield &&
197 DelayReached(&playfield_cursor_delay, 1000))
199 SetMouseCursor(CURSOR_PLAYFIELD);
200 playfield_cursor_set = TRUE;
203 else if (playfield_cursor_set)
205 SetMouseCursor(CURSOR_DEFAULT);
206 playfield_cursor_set = FALSE;
218 /* don't use all CPU time when idle; the main loop while playing
219 has its own synchronization and is CPU friendly, too */
221 if (game_status == GAME_MODE_PLAYING)
228 if (!PendingEvent()) /* delay only if no pending events */
232 /* refresh window contents from drawing buffer, if needed */
235 if (game_status == GAME_MODE_QUIT)
240 void HandleOtherEvents(Event *event)
245 HandleExposeEvent((ExposeEvent *) event);
248 case EVENT_UNMAPNOTIFY:
250 /* This causes the game to stop not only when iconified, but also
251 when on another virtual desktop, which might be not desired. */
252 SleepWhileUnmapped();
258 HandleFocusEvent((FocusChangeEvent *) event);
261 case EVENT_CLIENTMESSAGE:
262 HandleClientMessageEvent((ClientMessageEvent *) event);
265 #if defined(TARGET_SDL)
266 case SDL_JOYAXISMOTION:
267 case SDL_JOYBUTTONDOWN:
268 case SDL_JOYBUTTONUP:
269 HandleJoystickEvent(event);
273 HandleWindowManagerEvent(event);
282 void ClearEventQueue()
284 while (PendingEvent())
292 case EVENT_BUTTONRELEASE:
293 button_status = MB_RELEASED;
296 case EVENT_KEYRELEASE:
300 key_joystick_mapping = 0;
305 HandleOtherEvents(&event);
311 void ClearPlayerAction()
315 /* simulate key release events for still pressed keys */
316 key_joystick_mapping = 0;
317 for (i = 0; i < MAX_PLAYERS; i++)
318 stored_player[i].action = 0;
321 void SleepWhileUnmapped()
323 boolean window_unmapped = TRUE;
325 KeyboardAutoRepeatOn();
327 while (window_unmapped)
335 case EVENT_BUTTONRELEASE:
336 button_status = MB_RELEASED;
339 case EVENT_KEYRELEASE:
340 key_joystick_mapping = 0;
343 case EVENT_MAPNOTIFY:
344 window_unmapped = FALSE;
347 case EVENT_UNMAPNOTIFY:
348 /* this is only to surely prevent the 'should not happen' case
349 * of recursively looping between 'SleepWhileUnmapped()' and
350 * 'HandleOtherEvents()' which usually calls this funtion.
355 HandleOtherEvents(&event);
360 if (game_status == GAME_MODE_PLAYING)
361 KeyboardAutoRepeatOffUnlessAutoplay();
364 void HandleExposeEvent(ExposeEvent *event)
366 #if !defined(TARGET_SDL)
367 RedrawPlayfield(FALSE, event->x, event->y, event->width, event->height);
372 void HandleButtonEvent(ButtonEvent *event)
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;
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)
410 void HandleWindowEvent(WindowEvent *event)
413 int subtype = event->event;
416 (subtype == SDL_WINDOWEVENT_SHOWN ? "SDL_WINDOWEVENT_SHOWN" :
417 subtype == SDL_WINDOWEVENT_HIDDEN ? "SDL_WINDOWEVENT_HIDDEN" :
418 subtype == SDL_WINDOWEVENT_EXPOSED ? "SDL_WINDOWEVENT_EXPOSED" :
419 subtype == SDL_WINDOWEVENT_MOVED ? "SDL_WINDOWEVENT_MOVED" :
420 subtype == SDL_WINDOWEVENT_SIZE_CHANGED ? "SDL_WINDOWEVENT_SIZE_CHANGED" :
421 subtype == SDL_WINDOWEVENT_RESIZED ? "SDL_WINDOWEVENT_RESIZED" :
422 subtype == SDL_WINDOWEVENT_MINIMIZED ? "SDL_WINDOWEVENT_MINIMIZED" :
423 subtype == SDL_WINDOWEVENT_MAXIMIZED ? "SDL_WINDOWEVENT_MAXIMIZED" :
424 subtype == SDL_WINDOWEVENT_RESTORED ? "SDL_WINDOWEVENT_RESTORED" :
425 subtype == SDL_WINDOWEVENT_ENTER ? "SDL_WINDOWEVENT_ENTER" :
426 subtype == SDL_WINDOWEVENT_LEAVE ? "SDL_WINDOWEVENT_LEAVE" :
427 subtype == SDL_WINDOWEVENT_FOCUS_GAINED ? "SDL_WINDOWEVENT_FOCUS_GAINED" :
428 subtype == SDL_WINDOWEVENT_FOCUS_LOST ? "SDL_WINDOWEVENT_FOCUS_LOST" :
429 subtype == SDL_WINDOWEVENT_CLOSE ? "SDL_WINDOWEVENT_CLOSE" :
432 Error(ERR_DEBUG, "WINDOW EVENT: '%s', %ld, %ld",
433 event_name, event->data1, event->data2);
436 if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED ||
437 event->event == SDL_WINDOWEVENT_RESIZED ||
438 event->event == SDL_WINDOWEVENT_EXPOSED)
442 if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED)
444 // if game started in fullscreen mode, window will also get fullscreen size
445 if (!video.fullscreen_enabled && video.fullscreen_initial)
447 SDLSetWindowScaling(setup.window_scaling_percent);
449 // only do this correction once
450 video.fullscreen_initial = FALSE;
455 if (event->event == SDL_WINDOWEVENT_RESIZED && !video.fullscreen_enabled)
458 int new_window_width = event->data1;
459 int new_window_height = event->data2;
461 // if window size has changed after resizing, calculate new scaling factor
462 if (new_window_width != video.window_width ||
463 new_window_height != video.window_height)
465 int new_xpercent = (100 * new_window_width / video.width);
466 int new_ypercent = (100 * new_window_height / video.height);
468 printf("::: RESIZED from %d, %d to %d, %d\n",
469 video.window_width, video.window_height,
470 new_window_width, new_window_height);
472 setup.window_scaling_percent = video.window_scaling_percent =
473 MIN(MAX(MIN_WINDOW_SCALING_PERCENT, MIN(new_xpercent, new_ypercent)),
474 MAX_WINDOW_SCALING_PERCENT);
476 video.window_width = new_window_width;
477 video.window_height = new_window_height;
479 printf("::: setup.window_scaling_percent set to %d\n",
480 setup.window_scaling_percent);
482 if (game_status == GAME_MODE_SETUP)
483 RedrawSetupScreenAfterFullscreenToggle();
486 // prevent slightly wrong scaling factor due to rounding differences
487 float scaling_factor = (float)setup.window_scaling_percent / 100;
488 int old_xsize = (int)(scaling_factor * video.width);
489 int old_ysize = (int)(scaling_factor * video.height);
490 int new_xsize = event->data1;
491 int new_ysize = event->data2;
493 // window size is unchanged when going from fullscreen to window mode,
494 // but reverse calculation of scaling factor might result in a scaling
495 // factor that is slightly different due to rounding differences;
496 // therefore compare old/new window size and not old/new scaling factor
497 if (old_xsize != new_xsize ||
498 old_ysize != new_ysize)
500 int new_xpercent = (100 * new_xsize / video.width);
501 int new_ypercent = (100 * new_ysize / video.height);
503 setup.window_scaling_percent = MIN(new_xpercent, new_ypercent);
505 if (setup.window_scaling_percent < MIN_WINDOW_SCALING_PERCENT)
506 setup.window_scaling_percent = MIN_WINDOW_SCALING_PERCENT;
507 else if (setup.window_scaling_percent > MAX_WINDOW_SCALING_PERCENT)
508 setup.window_scaling_percent = MAX_WINDOW_SCALING_PERCENT;
510 printf("::: setup.window_scaling_percent set to %d\n",
511 setup.window_scaling_percent);
519 #define NUM_TOUCH_FINGERS 3
524 SDL_FingerID finger_id;
527 } touch_info[NUM_TOUCH_FINGERS];
529 void HandleFingerEvent(FingerEvent *event)
531 static Key motion_key_x = KSYM_UNDEFINED;
532 static Key motion_key_y = KSYM_UNDEFINED;
533 static Key button_key = KSYM_UNDEFINED;
534 static float motion_x1, motion_y1;
535 static float button_x1, button_y1;
536 static SDL_FingerID motion_id = 0;
537 static SDL_FingerID button_id = 0;
538 int trigger_distance_percent = 1; // percent of touchpad width/height
539 float trigger_distance = (float)trigger_distance_percent / 100;
540 float event_x = event->x;
541 float event_y = event->y;
545 Error(ERR_DEBUG, "FINGER EVENT: finger was %s, touch ID %lld, finger ID %lld, x/y %f/%f, dx/dy %f/%f, pressure %f",
546 event->type == EVENT_FINGERPRESS ? "pressed" :
547 event->type == EVENT_FINGERRELEASE ? "released" : "moved",
551 event->dx, event->dy,
556 if (game_status != GAME_MODE_PLAYING)
561 int key_status = (event->type == EVENT_FINGERRELEASE ? KEY_RELEASED :
564 Key key = (event->x < 1.0 / 3.0 ?
565 (event->y < 1.0 / 2.0 ? setup.input[0].key.snap :
566 setup.input[0].key.drop) :
567 event->x > 2.0 / 3.0 ?
568 (event->y < 1.0 / 3.0 ? setup.input[0].key.up :
569 event->y > 2.0 / 3.0 ? setup.input[0].key.down :
570 event->x < 5.0 / 6.0 ? setup.input[0].key.left :
571 setup.input[0].key.right) :
574 char *key_name = (key == setup.input[0].key.snap ? "SNAP" :
575 key == setup.input[0].key.drop ? "DROP" :
576 key == setup.input[0].key.up ? "UP" :
577 key == setup.input[0].key.down ? "DOWN" :
578 key == setup.input[0].key.left ? "LEFT" :
579 key == setup.input[0].key.right ? "RIGHT" : "(unknown)");
581 char *key_status_name = (key_status == KEY_RELEASED ? "KEY_RELEASED" :
584 Key key = (event->y < 1.0 / 3.0 ? setup.input[0].key.up :
585 event->y > 2.0 / 3.0 ? setup.input[0].key.down :
586 event->x < 1.0 / 3.0 ? setup.input[0].key.left :
587 event->x > 2.0 / 3.0 ? setup.input[0].key.right :
588 setup.input[0].key.snap);
592 Error(ERR_DEBUG, "::: key '%s' was '%s' [fingerId: %lld]",
593 getKeyNameFromKey(key), key_status_name, event->fingerId);
595 // check if we already know this touch event's finger id
596 for (i = 0; i < NUM_TOUCH_FINGERS; i++)
598 if (touch_info[i].touched &&
599 touch_info[i].finger_id == event->fingerId)
601 // Error(ERR_DEBUG, "MARK 1: %d", i);
607 if (i >= NUM_TOUCH_FINGERS)
609 if (key_status == KEY_PRESSED)
611 int oldest_pos = 0, oldest_counter = touch_info[0].counter;
613 // unknown finger id -- get new, empty slot, if available
614 for (i = 0; i < NUM_TOUCH_FINGERS; i++)
616 if (touch_info[i].counter < oldest_counter)
619 oldest_counter = touch_info[i].counter;
621 // Error(ERR_DEBUG, "MARK 2: %d", i);
624 if (!touch_info[i].touched)
626 // Error(ERR_DEBUG, "MARK 3: %d", i);
632 if (i >= NUM_TOUCH_FINGERS)
634 // all slots allocated -- use oldest slot
637 // Error(ERR_DEBUG, "MARK 4: %d", i);
642 // release of previously unknown key (should not happen)
644 if (key != KSYM_UNDEFINED)
646 HandleKey(key, KEY_RELEASED);
648 Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d] [1]",
649 getKeyNameFromKey(key), "KEY_RELEASED", i);
654 if (i < NUM_TOUCH_FINGERS)
656 if (key_status == KEY_PRESSED)
658 if (touch_info[i].key != key)
660 if (touch_info[i].key != KSYM_UNDEFINED)
662 HandleKey(touch_info[i].key, KEY_RELEASED);
664 Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d] [2]",
665 getKeyNameFromKey(touch_info[i].key), "KEY_RELEASED", i);
668 if (key != KSYM_UNDEFINED)
670 HandleKey(key, KEY_PRESSED);
672 Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d] [3]",
673 getKeyNameFromKey(key), "KEY_PRESSED", i);
677 touch_info[i].touched = TRUE;
678 touch_info[i].finger_id = event->fingerId;
679 touch_info[i].counter = Counter();
680 touch_info[i].key = key;
684 if (touch_info[i].key != KSYM_UNDEFINED)
686 HandleKey(touch_info[i].key, KEY_RELEASED);
688 Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d] [4]",
689 getKeyNameFromKey(touch_info[i].key), "KEY_RELEASED", i);
692 touch_info[i].touched = FALSE;
693 touch_info[i].finger_id = 0;
694 touch_info[i].counter = 0;
695 touch_info[i].key = 0;
701 Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d]",
702 key_name, key_status_name, i);
704 Error(ERR_DEBUG, "=> key == %d, key_status == %d [%d]", key, key_status, i);
711 if (event->type == EVENT_FINGERPRESS)
713 if (event_x > 1.0 / 3.0)
717 motion_id = event->fingerId;
722 motion_key_x = KSYM_UNDEFINED;
723 motion_key_y = KSYM_UNDEFINED;
725 Error(ERR_DEBUG, "---------- MOVE STARTED (WAIT) ----------");
731 button_id = event->fingerId;
736 button_key = setup.input[0].key.snap;
738 HandleKey(button_key, KEY_PRESSED);
740 Error(ERR_DEBUG, "---------- SNAP STARTED ----------");
743 else if (event->type == EVENT_FINGERRELEASE)
745 if (event->fingerId == motion_id)
749 if (motion_key_x != KSYM_UNDEFINED)
750 HandleKey(motion_key_x, KEY_RELEASED);
751 if (motion_key_y != KSYM_UNDEFINED)
752 HandleKey(motion_key_y, KEY_RELEASED);
754 motion_key_x = KSYM_UNDEFINED;
755 motion_key_y = KSYM_UNDEFINED;
757 Error(ERR_DEBUG, "---------- MOVE STOPPED ----------");
759 else if (event->fingerId == button_id)
763 if (button_key != KSYM_UNDEFINED)
764 HandleKey(button_key, KEY_RELEASED);
766 button_key = KSYM_UNDEFINED;
768 Error(ERR_DEBUG, "---------- SNAP STOPPED ----------");
771 else if (event->type == EVENT_FINGERMOTION)
773 if (event->fingerId == motion_id)
775 float distance_x = ABS(event_x - motion_x1);
776 float distance_y = ABS(event_y - motion_y1);
777 Key new_motion_key_x = (event_x < motion_x1 ? setup.input[0].key.left :
778 event_x > motion_x1 ? setup.input[0].key.right :
780 Key new_motion_key_y = (event_y < motion_y1 ? setup.input[0].key.up :
781 event_y > motion_y1 ? setup.input[0].key.down :
784 if (distance_x < trigger_distance / 2 ||
785 distance_x < distance_y)
786 new_motion_key_x = KSYM_UNDEFINED;
788 if (distance_y < trigger_distance / 2 ||
789 distance_y < distance_x)
790 new_motion_key_y = KSYM_UNDEFINED;
792 if (distance_x > trigger_distance ||
793 distance_y > trigger_distance)
795 if (new_motion_key_x != motion_key_x)
797 if (motion_key_x != KSYM_UNDEFINED)
798 HandleKey(motion_key_x, KEY_RELEASED);
799 if (new_motion_key_x != KSYM_UNDEFINED)
800 HandleKey(new_motion_key_x, KEY_PRESSED);
803 if (new_motion_key_y != motion_key_y)
805 if (motion_key_y != KSYM_UNDEFINED)
806 HandleKey(motion_key_y, KEY_RELEASED);
807 if (new_motion_key_y != KSYM_UNDEFINED)
808 HandleKey(new_motion_key_y, KEY_PRESSED);
814 motion_key_x = new_motion_key_x;
815 motion_key_y = new_motion_key_y;
817 Error(ERR_DEBUG, "---------- MOVE STARTED (MOVE) ----------");
820 else if (event->fingerId == button_id)
822 float distance_x = ABS(event_x - button_x1);
823 float distance_y = ABS(event_y - button_y1);
825 if (distance_x < trigger_distance / 2 &&
826 distance_y > trigger_distance)
828 if (button_key == setup.input[0].key.snap)
829 HandleKey(button_key, KEY_RELEASED);
834 button_key = setup.input[0].key.drop;
836 HandleKey(button_key, KEY_PRESSED);
838 Error(ERR_DEBUG, "---------- DROP STARTED ----------");
846 void HandleFingerEvent(FingerEvent *event)
849 static int num_events = 0;
855 Error(ERR_DEBUG, "FINGER EVENT: finger was %s, touch ID %lld, finger ID %lld, x/y %f/%f, dx/dy %f/%f, pressure %f",
856 event->type == EVENT_FINGERPRESS ? "pressed" :
857 event->type == EVENT_FINGERRELEASE ? "released" : "moved",
861 event->dx, event->dy,
867 int x = (int)(event->x * video.width);
868 int y = (int)(event->y * video.height);
869 int button = MB_LEFTBUTTON;
871 Error(ERR_DEBUG, "=> screen x/y %d/%d", x, y);
875 if (++num_events >= max_events)
881 if (event->type == EVENT_FINGERPRESS ||
882 event->type == EVENT_FINGERMOTION)
883 button_status = button;
885 button_status = MB_RELEASED;
887 int max_x = SX + SXSIZE;
888 int max_y = SY + SYSIZE;
892 if (game_status == GAME_MODE_PLAYING)
894 if (game_status == GAME_MODE_PLAYING &&
898 int key_status = (event->type == EVENT_FINGERRELEASE ? KEY_RELEASED :
901 Key key = (event->y < 1.0 / 3.0 ? setup.input[0].key.up :
902 event->y > 2.0 / 3.0 ? setup.input[0].key.down :
903 event->x < 1.0 / 3.0 ? setup.input[0].key.left :
904 event->x > 2.0 / 3.0 ? setup.input[0].key.right :
905 setup.input[0].key.drop);
907 Key key = (y < max_y / 3 ? setup.input[0].key.up :
908 y > 2 * max_y / 3 ? setup.input[0].key.down :
909 x < max_x / 3 ? setup.input[0].key.left :
910 x > 2 * max_x / 3 ? setup.input[0].key.right :
911 setup.input[0].key.drop);
914 Error(ERR_DEBUG, "=> key == %d, key_status == %d", key, key_status);
916 HandleKey(key, key_status);
921 Error(ERR_DEBUG, "::: button_status == %d, button == %d\n",
922 button_status, button);
924 HandleButton(x, y, button_status, button);
932 static boolean checkTextInputKeyModState()
934 // when playing, only handle raw key events and ignore text input
935 if (game_status == GAME_MODE_PLAYING)
938 return ((GetKeyModState() & KMOD_TextInput) != KMOD_None);
941 void HandleTextEvent(TextEvent *event)
943 char *text = event->text;
944 Key key = getKeyFromKeyName(text);
947 Error(ERR_DEBUG, "TEXT EVENT: text == '%s' [%d byte(s), '%c'/%d], resulting key == %d (%s) [%04x]",
950 text[0], (int)(text[0]),
952 getKeyNameFromKey(key),
956 // if (game_status != GAME_MODE_PLAYING && GetKeyModState() != KMOD_None)
958 if (game_status != GAME_MODE_PLAYING &&
959 (GetKeyModState() & KMOD_TextInput) != KMOD_None)
961 if (checkTextInputKeyModState())
963 HandleKey(key, KEY_PRESSED);
964 HandleKey(key, KEY_RELEASED);
969 void HandleKeyEvent(KeyEvent *event)
971 int key_status = (event->type == EVENT_KEYPRESS ? KEY_PRESSED : KEY_RELEASED);
972 boolean with_modifiers = (game_status == GAME_MODE_PLAYING ? FALSE : TRUE);
973 Key key = GetEventKey(event, with_modifiers);
974 Key keymod = (with_modifiers ? GetEventKey(event, FALSE) : key);
977 Error(ERR_DEBUG, "KEY EVENT: key was %s, keysym.scancode == %d, keysym.sym == %d, keymod = %d, GetKeyModState() = 0x%04x, resulting key == %d (%s)",
978 event->type == EVENT_KEYPRESS ? "pressed" : "released",
979 event->keysym.scancode,
984 getKeyNameFromKey(key));
988 if (key == KSYM_Menu)
989 Error(ERR_DEBUG, "menu key pressed");
990 else if (key == KSYM_Back)
991 Error(ERR_DEBUG, "back key pressed");
994 #if defined(PLATFORM_ANDROID)
995 // always map the "back" button to the "escape" key on Android devices
996 if (key == KSYM_Back)
1000 HandleKeyModState(keymod, key_status);
1002 #if defined(TARGET_SDL2)
1004 // if (game_status == GAME_MODE_PLAYING || GetKeyModState() == KMOD_None)
1006 if (game_status == GAME_MODE_PLAYING ||
1007 (GetKeyModState() & KMOD_TextInput) == KMOD_None)
1009 if (!checkTextInputKeyModState())
1010 HandleKey(key, key_status);
1012 HandleKey(key, key_status);
1016 void HandleFocusEvent(FocusChangeEvent *event)
1018 static int old_joystick_status = -1;
1020 if (event->type == EVENT_FOCUSOUT)
1022 KeyboardAutoRepeatOn();
1023 old_joystick_status = joystick.status;
1024 joystick.status = JOYSTICK_NOT_AVAILABLE;
1026 ClearPlayerAction();
1028 else if (event->type == EVENT_FOCUSIN)
1030 /* When there are two Rocks'n'Diamonds windows which overlap and
1031 the player moves the pointer from one game window to the other,
1032 a 'FocusOut' event is generated for the window the pointer is
1033 leaving and a 'FocusIn' event is generated for the window the
1034 pointer is entering. In some cases, it can happen that the
1035 'FocusIn' event is handled by the one game process before the
1036 'FocusOut' event by the other game process. In this case the
1037 X11 environment would end up with activated keyboard auto repeat,
1038 because unfortunately this is a global setting and not (which
1039 would be far better) set for each X11 window individually.
1040 The effect would be keyboard auto repeat while playing the game
1041 (game_status == GAME_MODE_PLAYING), which is not desired.
1042 To avoid this special case, we just wait 1/10 second before
1043 processing the 'FocusIn' event.
1046 if (game_status == GAME_MODE_PLAYING)
1049 KeyboardAutoRepeatOffUnlessAutoplay();
1052 if (old_joystick_status != -1)
1053 joystick.status = old_joystick_status;
1057 void HandleClientMessageEvent(ClientMessageEvent *event)
1059 if (CheckCloseWindowEvent(event))
1063 void HandleWindowManagerEvent(Event *event)
1065 #if defined(TARGET_SDL)
1066 SDLHandleWindowManagerEvent(event);
1070 void HandleButton(int mx, int my, int button, int button_nr)
1072 static int old_mx = 0, old_my = 0;
1086 #if defined(PLATFORM_ANDROID)
1087 if (game_status != GAME_MODE_PLAYING &&
1088 HandleGadgets(mx, my, button))
1090 /* do not handle this button event anymore */
1091 mx = my = -32; /* force mouse event to be outside screen tiles */
1094 if (HandleGadgets(mx, my, button))
1096 /* do not handle this button event anymore */
1097 mx = my = -32; /* force mouse event to be outside screen tiles */
1101 /* do not use scroll wheel button events for anything other than gadgets */
1102 if (IS_WHEEL_BUTTON(button_nr))
1106 Error(ERR_DEBUG, "::: game_status == %d", game_status);
1109 switch (game_status)
1111 case GAME_MODE_TITLE:
1112 HandleTitleScreen(mx, my, 0, 0, button);
1115 case GAME_MODE_MAIN:
1116 HandleMainMenu(mx, my, 0, 0, button);
1119 case GAME_MODE_PSEUDO_TYPENAME:
1120 HandleTypeName(0, KSYM_Return);
1123 case GAME_MODE_LEVELS:
1124 HandleChooseLevelSet(mx, my, 0, 0, button);
1127 case GAME_MODE_LEVELNR:
1128 HandleChooseLevelNr(mx, my, 0, 0, button);
1131 case GAME_MODE_SCORES:
1132 HandleHallOfFame(0, 0, 0, 0, button);
1135 case GAME_MODE_EDITOR:
1136 HandleLevelEditorIdle();
1139 case GAME_MODE_INFO:
1140 HandleInfoScreen(mx, my, 0, 0, button);
1143 case GAME_MODE_SETUP:
1144 HandleSetupScreen(mx, my, 0, 0, button);
1147 case GAME_MODE_PLAYING:
1149 if (button == MB_PRESSED && !motion_status && IN_GFX_FIELD(mx, my))
1150 DumpTile(LEVELX((mx - SX) / TILEX), LEVELY((my - SY) / TILEY));
1159 static boolean is_string_suffix(char *string, char *suffix)
1161 int string_len = strlen(string);
1162 int suffix_len = strlen(suffix);
1164 if (suffix_len > string_len)
1167 return (strEqual(&string[string_len - suffix_len], suffix));
1170 #define MAX_CHEAT_INPUT_LEN 32
1172 static void HandleKeysSpecial(Key key)
1174 static char cheat_input[2 * MAX_CHEAT_INPUT_LEN + 1] = "";
1175 char letter = getCharFromKey(key);
1176 int cheat_input_len = strlen(cheat_input);
1182 if (cheat_input_len >= 2 * MAX_CHEAT_INPUT_LEN)
1184 for (i = 0; i < MAX_CHEAT_INPUT_LEN + 1; i++)
1185 cheat_input[i] = cheat_input[MAX_CHEAT_INPUT_LEN + i];
1187 cheat_input_len = MAX_CHEAT_INPUT_LEN;
1190 cheat_input[cheat_input_len++] = letter;
1191 cheat_input[cheat_input_len] = '\0';
1194 Error(ERR_DEBUG, "SPECIAL KEY '%s' [%d]\n", cheat_input, cheat_input_len);
1197 if (game_status == GAME_MODE_MAIN)
1199 if (is_string_suffix(cheat_input, ":insert-solution-tape") ||
1200 is_string_suffix(cheat_input, ":ist"))
1202 InsertSolutionTape();
1204 else if (is_string_suffix(cheat_input, ":reload-graphics") ||
1205 is_string_suffix(cheat_input, ":rg"))
1207 ReloadCustomArtwork(1 << ARTWORK_TYPE_GRAPHICS);
1210 else if (is_string_suffix(cheat_input, ":reload-sounds") ||
1211 is_string_suffix(cheat_input, ":rs"))
1213 ReloadCustomArtwork(1 << ARTWORK_TYPE_SOUNDS);
1216 else if (is_string_suffix(cheat_input, ":reload-music") ||
1217 is_string_suffix(cheat_input, ":rm"))
1219 ReloadCustomArtwork(1 << ARTWORK_TYPE_MUSIC);
1222 else if (is_string_suffix(cheat_input, ":reload-artwork") ||
1223 is_string_suffix(cheat_input, ":ra"))
1225 ReloadCustomArtwork(1 << ARTWORK_TYPE_GRAPHICS |
1226 1 << ARTWORK_TYPE_SOUNDS |
1227 1 << ARTWORK_TYPE_MUSIC);
1230 else if (is_string_suffix(cheat_input, ":dump-level") ||
1231 is_string_suffix(cheat_input, ":dl"))
1235 else if (is_string_suffix(cheat_input, ":dump-tape") ||
1236 is_string_suffix(cheat_input, ":dt"))
1240 else if (is_string_suffix(cheat_input, ":fix-tape") ||
1241 is_string_suffix(cheat_input, ":ft"))
1243 /* fix single-player tapes that contain player input for more than one
1244 player (due to a bug in 3.3.1.2 and earlier versions), which results
1245 in playing levels with more than one player in multi-player mode,
1246 even though the tape was originally recorded in single-player mode */
1248 /* remove player input actions for all players but the first one */
1249 for (i = 1; i < MAX_PLAYERS; i++)
1250 tape.player_participates[i] = FALSE;
1252 tape.changed = TRUE;
1254 else if (is_string_suffix(cheat_input, ":save-native-level") ||
1255 is_string_suffix(cheat_input, ":snl"))
1257 SaveNativeLevel(&level);
1260 else if (game_status == GAME_MODE_PLAYING)
1263 if (is_string_suffix(cheat_input, ".q"))
1264 DEBUG_SetMaximumDynamite();
1267 else if (game_status == GAME_MODE_EDITOR)
1269 if (is_string_suffix(cheat_input, ":dump-brush") ||
1270 is_string_suffix(cheat_input, ":DB"))
1274 else if (is_string_suffix(cheat_input, ":DDB"))
1281 void HandleKey(Key key, int key_status)
1283 boolean anyTextGadgetActiveOrJustFinished = anyTextGadgetActive();
1284 static struct SetupKeyboardInfo ski;
1285 static struct SetupShortcutInfo ssi;
1294 { &ski.left, &ssi.snap_left, DEFAULT_KEY_LEFT, JOY_LEFT },
1295 { &ski.right, &ssi.snap_right, DEFAULT_KEY_RIGHT, JOY_RIGHT },
1296 { &ski.up, &ssi.snap_up, DEFAULT_KEY_UP, JOY_UP },
1297 { &ski.down, &ssi.snap_down, DEFAULT_KEY_DOWN, JOY_DOWN },
1298 { &ski.snap, NULL, DEFAULT_KEY_SNAP, JOY_BUTTON_SNAP },
1299 { &ski.drop, NULL, DEFAULT_KEY_DROP, JOY_BUTTON_DROP }
1304 if (game_status == GAME_MODE_PLAYING)
1306 /* only needed for single-step tape recording mode */
1307 static boolean clear_snap_button[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1308 static boolean clear_drop_button[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1309 static boolean element_snapped[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1310 static boolean element_dropped[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1313 for (pnr = 0; pnr < MAX_PLAYERS; pnr++)
1315 byte key_action = 0;
1317 if (setup.input[pnr].use_joystick)
1320 ski = setup.input[pnr].key;
1322 for (i = 0; i < NUM_PLAYER_ACTIONS; i++)
1323 if (key == *key_info[i].key_custom)
1324 key_action |= key_info[i].action;
1326 /* use combined snap+direction keys for the first player only */
1329 ssi = setup.shortcut;
1331 for (i = 0; i < NUM_DIRECTIONS; i++)
1332 if (key == *key_info[i].key_snap)
1333 key_action |= key_info[i].action | JOY_BUTTON_SNAP;
1336 /* clear delayed snap and drop actions in single step mode (see below) */
1337 if (tape.single_step)
1339 if (clear_snap_button[pnr])
1341 stored_player[pnr].action &= ~KEY_BUTTON_SNAP;
1342 clear_snap_button[pnr] = FALSE;
1345 if (clear_drop_button[pnr])
1347 stored_player[pnr].action &= ~KEY_BUTTON_DROP;
1348 clear_drop_button[pnr] = FALSE;
1352 if (key_status == KEY_PRESSED)
1353 stored_player[pnr].action |= key_action;
1355 stored_player[pnr].action &= ~key_action;
1357 if (tape.single_step && tape.recording && tape.pausing)
1359 if (key_status == KEY_PRESSED && key_action & KEY_MOTION)
1361 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1363 /* if snap key already pressed, don't snap when releasing (below) */
1364 if (stored_player[pnr].action & KEY_BUTTON_SNAP)
1365 element_snapped[pnr] = TRUE;
1367 /* if drop key already pressed, don't drop when releasing (below) */
1368 if (stored_player[pnr].action & KEY_BUTTON_DROP)
1369 element_dropped[pnr] = TRUE;
1372 else if (key_status == KEY_PRESSED && key_action & KEY_BUTTON_DROP)
1374 if (level.game_engine_type == GAME_ENGINE_TYPE_EM ||
1375 level.game_engine_type == GAME_ENGINE_TYPE_SP)
1378 printf("::: drop key pressed\n");
1381 if (level.game_engine_type == GAME_ENGINE_TYPE_SP &&
1382 getRedDiskReleaseFlag_SP() == 0)
1383 stored_player[pnr].action &= ~KEY_BUTTON_DROP;
1385 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1389 else if (key_status == KEY_RELEASED && key_action & KEY_BUTTON)
1391 if (key_action & KEY_BUTTON_SNAP)
1393 /* if snap key was released without moving (see above), snap now */
1394 if (!element_snapped[pnr])
1396 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1398 stored_player[pnr].action |= KEY_BUTTON_SNAP;
1400 /* clear delayed snap button on next event */
1401 clear_snap_button[pnr] = TRUE;
1404 element_snapped[pnr] = FALSE;
1408 if (key_action & KEY_BUTTON_DROP &&
1409 level.game_engine_type == GAME_ENGINE_TYPE_RND)
1411 /* if drop key was released without moving (see above), drop now */
1412 if (!element_dropped[pnr])
1414 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1416 if (level.game_engine_type != GAME_ENGINE_TYPE_SP ||
1417 getRedDiskReleaseFlag_SP() != 0)
1418 stored_player[pnr].action |= KEY_BUTTON_DROP;
1420 /* clear delayed drop button on next event */
1421 clear_drop_button[pnr] = TRUE;
1424 element_dropped[pnr] = FALSE;
1429 else if (tape.recording && tape.pausing)
1431 /* prevent key release events from un-pausing a paused game */
1432 if (key_status == KEY_PRESSED && key_action & KEY_ACTION)
1433 TapeTogglePause(TAPE_TOGGLE_MANUAL);
1439 for (i = 0; i < NUM_PLAYER_ACTIONS; i++)
1440 if (key == key_info[i].key_default)
1441 joy |= key_info[i].action;
1446 if (key_status == KEY_PRESSED)
1447 key_joystick_mapping |= joy;
1449 key_joystick_mapping &= ~joy;
1454 if (game_status != GAME_MODE_PLAYING)
1455 key_joystick_mapping = 0;
1457 if (key_status == KEY_RELEASED)
1460 if ((key == KSYM_Return || key == KSYM_KP_Enter) &&
1461 (GetKeyModState() & KMOD_Alt) && video.fullscreen_available)
1463 setup.fullscreen = !setup.fullscreen;
1466 printf("::: %d\n", setup.window_scaling_percent);
1469 ToggleFullscreenOrChangeWindowScalingIfNeeded();
1471 if (game_status == GAME_MODE_SETUP)
1472 RedrawSetupScreenAfterFullscreenToggle();
1477 if ((key == KSYM_minus || key == KSYM_plus || key == KSYM_0) &&
1478 (GetKeyModState() & KMOD_Alt) && video.window_scaling_available &&
1479 !video.fullscreen_enabled)
1482 setup.window_scaling_percent = STD_WINDOW_SCALING_PERCENT;
1484 setup.window_scaling_percent +=
1485 (key == KSYM_minus ? -1 : +1) * STEP_WINDOW_SCALING_PERCENT;
1487 if (setup.window_scaling_percent < MIN_WINDOW_SCALING_PERCENT)
1488 setup.window_scaling_percent = MIN_WINDOW_SCALING_PERCENT;
1489 else if (setup.window_scaling_percent > MAX_WINDOW_SCALING_PERCENT)
1490 setup.window_scaling_percent = MAX_WINDOW_SCALING_PERCENT;
1492 ToggleFullscreenOrChangeWindowScalingIfNeeded();
1494 if (game_status == GAME_MODE_SETUP)
1495 RedrawSetupScreenAfterFullscreenToggle();
1501 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd &&
1502 (key == KSYM_Return || key == setup.shortcut.toggle_pause))
1504 if (game_status == GAME_MODE_PLAYING && AllPlayersGone &&
1505 (key == KSYM_Return || key == setup.shortcut.toggle_pause))
1513 if (game_status == GAME_MODE_MAIN &&
1514 (key == setup.shortcut.toggle_pause || key == KSYM_space))
1516 StartGameActions(options.network, setup.autorecord, level.random_seed);
1521 if (game_status == GAME_MODE_MAIN || game_status == GAME_MODE_PLAYING)
1523 if (key == setup.shortcut.save_game)
1525 else if (key == setup.shortcut.load_game)
1527 else if (key == setup.shortcut.toggle_pause)
1528 TapeTogglePause(TAPE_TOGGLE_MANUAL);
1530 HandleTapeButtonKeys(key);
1531 HandleSoundButtonKeys(key);
1534 if (game_status == GAME_MODE_PLAYING && !network_playing)
1536 int centered_player_nr_next = -999;
1538 if (key == setup.shortcut.focus_player_all)
1539 centered_player_nr_next = -1;
1541 for (i = 0; i < MAX_PLAYERS; i++)
1542 if (key == setup.shortcut.focus_player[i])
1543 centered_player_nr_next = i;
1545 if (centered_player_nr_next != -999)
1547 game.centered_player_nr_next = centered_player_nr_next;
1548 game.set_centered_player = TRUE;
1552 tape.centered_player_nr_next = game.centered_player_nr_next;
1553 tape.set_centered_player = TRUE;
1558 HandleKeysSpecial(key);
1560 if (HandleGadgetsKeyInput(key))
1562 if (key != KSYM_Escape) /* always allow ESC key to be handled */
1563 key = KSYM_UNDEFINED;
1566 switch (game_status)
1568 case GAME_MODE_PSEUDO_TYPENAME:
1569 HandleTypeName(0, key);
1572 case GAME_MODE_TITLE:
1573 case GAME_MODE_MAIN:
1574 case GAME_MODE_LEVELS:
1575 case GAME_MODE_LEVELNR:
1576 case GAME_MODE_SETUP:
1577 case GAME_MODE_INFO:
1578 case GAME_MODE_SCORES:
1583 if (game_status == GAME_MODE_TITLE)
1584 HandleTitleScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1585 else if (game_status == GAME_MODE_MAIN)
1586 HandleMainMenu(0, 0, 0, 0, MB_MENU_CHOICE);
1587 else if (game_status == GAME_MODE_LEVELS)
1588 HandleChooseLevelSet(0, 0, 0, 0, MB_MENU_CHOICE);
1589 else if (game_status == GAME_MODE_LEVELNR)
1590 HandleChooseLevelNr(0, 0, 0, 0, MB_MENU_CHOICE);
1591 else if (game_status == GAME_MODE_SETUP)
1592 HandleSetupScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1593 else if (game_status == GAME_MODE_INFO)
1594 HandleInfoScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1595 else if (game_status == GAME_MODE_SCORES)
1596 HandleHallOfFame(0, 0, 0, 0, MB_MENU_CHOICE);
1600 if (game_status != GAME_MODE_MAIN)
1601 FadeSkipNextFadeIn();
1603 if (game_status == GAME_MODE_TITLE)
1604 HandleTitleScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1605 else if (game_status == GAME_MODE_LEVELS)
1606 HandleChooseLevelSet(0, 0, 0, 0, MB_MENU_LEAVE);
1607 else if (game_status == GAME_MODE_LEVELNR)
1608 HandleChooseLevelNr(0, 0, 0, 0, MB_MENU_LEAVE);
1609 else if (game_status == GAME_MODE_SETUP)
1610 HandleSetupScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1611 else if (game_status == GAME_MODE_INFO)
1612 HandleInfoScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1613 else if (game_status == GAME_MODE_SCORES)
1614 HandleHallOfFame(0, 0, 0, 0, MB_MENU_LEAVE);
1618 if (game_status == GAME_MODE_LEVELS)
1619 HandleChooseLevelSet(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1620 else if (game_status == GAME_MODE_LEVELNR)
1621 HandleChooseLevelNr(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1622 else if (game_status == GAME_MODE_SETUP)
1623 HandleSetupScreen(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1624 else if (game_status == GAME_MODE_INFO)
1625 HandleInfoScreen(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1626 else if (game_status == GAME_MODE_SCORES)
1627 HandleHallOfFame(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1630 case KSYM_Page_Down:
1631 if (game_status == GAME_MODE_LEVELS)
1632 HandleChooseLevelSet(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1633 else if (game_status == GAME_MODE_LEVELNR)
1634 HandleChooseLevelNr(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1635 else if (game_status == GAME_MODE_SETUP)
1636 HandleSetupScreen(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1637 else if (game_status == GAME_MODE_INFO)
1638 HandleInfoScreen(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1639 else if (game_status == GAME_MODE_SCORES)
1640 HandleHallOfFame(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1645 GameFrameDelay = (GameFrameDelay == 500 ? GAME_FRAME_DELAY : 500);
1649 setup.sp_show_border_elements = !setup.sp_show_border_elements;
1650 printf("Supaplex border elements %s\n",
1651 setup.sp_show_border_elements ? "enabled" : "disabled");
1660 case GAME_MODE_EDITOR:
1661 if (!anyTextGadgetActiveOrJustFinished || key == KSYM_Escape)
1662 HandleLevelEditorKeyInput(key);
1665 case GAME_MODE_PLAYING:
1670 RequestQuitGame(setup.ask_on_escape);
1688 if (GameFrameDelay == 500)
1689 GameFrameDelay = GAME_FRAME_DELAY;
1691 GameFrameDelay = 500;
1694 GameFrameDelay = (key - KSYM_0) * 10;
1695 printf("Game speed == %d%% (%d ms delay between two frames)\n",
1696 GAME_FRAME_DELAY * 100 / GameFrameDelay, GameFrameDelay);
1702 options.debug = FALSE;
1703 printf("debug mode disabled\n");
1707 options.debug = TRUE;
1708 printf("debug mode enabled\n");
1714 if (!global.fps_slowdown)
1716 global.fps_slowdown = TRUE;
1717 global.fps_slowdown_factor = 2;
1718 printf("fps slowdown enabled -- display only every 2nd frame\n");
1720 else if (global.fps_slowdown_factor == 2)
1722 global.fps_slowdown_factor = 4;
1723 printf("fps slowdown enabled -- display only every 4th frame\n");
1727 global.fps_slowdown = FALSE;
1728 global.fps_slowdown_factor = 1;
1729 printf("fps slowdown disabled\n");
1736 ScrollStepSize = TILEX / 8;
1737 printf("ScrollStepSize == %d (1/8)\n", ScrollStepSize);
1741 ScrollStepSize = TILEX / 4;
1742 printf("ScrollStepSize == %d (1/4)\n", ScrollStepSize);
1746 ScrollStepSize = TILEX / 2;
1747 printf("ScrollStepSize == %d (1/2)\n", ScrollStepSize);
1751 ScrollStepSize = TILEX;
1752 printf("ScrollStepSize == %d (1/1)\n", ScrollStepSize);
1757 printf("::: currently using game engine version %d\n",
1758 game.engine_version);
1769 if (key == KSYM_Escape)
1771 game_status = GAME_MODE_MAIN;
1779 void HandleNoEvent()
1781 if (button_status && game_status != GAME_MODE_PLAYING)
1783 HandleButton(0, 0, -button_status, button_status);
1794 #if defined(NETWORK_AVALIABLE)
1795 if (options.network)
1799 switch (game_status)
1801 case GAME_MODE_MAIN:
1802 DrawPreviewLevelAnimation();
1806 case GAME_MODE_LEVELS:
1807 case GAME_MODE_LEVELNR:
1808 case GAME_MODE_SETUP:
1809 case GAME_MODE_INFO:
1810 case GAME_MODE_SCORES:
1814 case GAME_MODE_EDITOR:
1815 HandleLevelEditorIdle();
1823 static int HandleJoystickForAllPlayers()
1828 for (i = 0; i < MAX_PLAYERS; i++)
1830 byte joy_action = 0;
1833 if (!setup.input[i].use_joystick)
1837 joy_action = Joystick(i);
1838 result |= joy_action;
1840 if (!setup.input[i].use_joystick)
1843 stored_player[i].action = joy_action;
1849 void HandleJoystick()
1851 int joystick = HandleJoystickForAllPlayers();
1852 int keyboard = key_joystick_mapping;
1853 int joy = (joystick | keyboard);
1854 int left = joy & JOY_LEFT;
1855 int right = joy & JOY_RIGHT;
1856 int up = joy & JOY_UP;
1857 int down = joy & JOY_DOWN;
1858 int button = joy & JOY_BUTTON;
1859 int newbutton = (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED);
1860 int dx = (left ? -1 : right ? 1 : 0);
1861 int dy = (up ? -1 : down ? 1 : 0);
1863 switch (game_status)
1865 case GAME_MODE_TITLE:
1866 case GAME_MODE_MAIN:
1867 case GAME_MODE_LEVELS:
1868 case GAME_MODE_LEVELNR:
1869 case GAME_MODE_SETUP:
1870 case GAME_MODE_INFO:
1872 static unsigned int joystickmove_delay = 0;
1874 if (joystick && !button &&
1875 !DelayReached(&joystickmove_delay, GADGET_FRAME_DELAY))
1876 newbutton = dx = dy = 0;
1878 if (game_status == GAME_MODE_TITLE)
1879 HandleTitleScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1880 else if (game_status == GAME_MODE_MAIN)
1881 HandleMainMenu(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1882 else if (game_status == GAME_MODE_LEVELS)
1883 HandleChooseLevelSet(0,0,dx,dy,newbutton?MB_MENU_CHOICE : MB_MENU_MARK);
1884 else if (game_status == GAME_MODE_LEVELNR)
1885 HandleChooseLevelNr(0,0,dx,dy,newbutton? MB_MENU_CHOICE : MB_MENU_MARK);
1886 else if (game_status == GAME_MODE_SETUP)
1887 HandleSetupScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1888 else if (game_status == GAME_MODE_INFO)
1889 HandleInfoScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1893 case GAME_MODE_SCORES:
1894 HandleHallOfFame(0, 0, dx, dy, !newbutton);
1898 case GAME_MODE_EDITOR:
1899 HandleLevelEditorIdle();
1903 case GAME_MODE_PLAYING:
1904 if (tape.playing || keyboard)
1905 newbutton = ((joy & JOY_BUTTON) != 0);
1908 if (newbutton && local_player->LevelSolved_GameEnd)
1910 if (newbutton && AllPlayersGone)