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);
469 printf("::: RESIZED from %d, %d to %d, %d\n",
470 video.window_width, video.window_height,
471 new_window_width, new_window_height);
474 setup.window_scaling_percent = video.window_scaling_percent =
475 MIN(MAX(MIN_WINDOW_SCALING_PERCENT, MIN(new_xpercent, new_ypercent)),
476 MAX_WINDOW_SCALING_PERCENT);
478 video.window_width = new_window_width;
479 video.window_height = new_window_height;
482 printf("::: setup.window_scaling_percent set to %d\n",
483 setup.window_scaling_percent);
486 if (game_status == GAME_MODE_SETUP)
487 RedrawSetupScreenAfterFullscreenToggle();
492 // prevent slightly wrong scaling factor due to rounding differences
493 float scaling_factor = (float)setup.window_scaling_percent / 100;
494 int old_xsize = (int)(scaling_factor * video.width);
495 int old_ysize = (int)(scaling_factor * video.height);
496 int new_xsize = event->data1;
497 int new_ysize = event->data2;
499 // window size is unchanged when going from fullscreen to window mode,
500 // but reverse calculation of scaling factor might result in a scaling
501 // factor that is slightly different due to rounding differences;
502 // therefore compare old/new window size and not old/new scaling factor
503 if (old_xsize != new_xsize ||
504 old_ysize != new_ysize)
506 int new_xpercent = (100 * new_xsize / video.width);
507 int new_ypercent = (100 * new_ysize / video.height);
509 setup.window_scaling_percent = MIN(new_xpercent, new_ypercent);
511 if (setup.window_scaling_percent < MIN_WINDOW_SCALING_PERCENT)
512 setup.window_scaling_percent = MIN_WINDOW_SCALING_PERCENT;
513 else if (setup.window_scaling_percent > MAX_WINDOW_SCALING_PERCENT)
514 setup.window_scaling_percent = MAX_WINDOW_SCALING_PERCENT;
516 printf("::: setup.window_scaling_percent set to %d\n",
517 setup.window_scaling_percent);
525 #define NUM_TOUCH_FINGERS 3
530 SDL_FingerID finger_id;
533 } touch_info[NUM_TOUCH_FINGERS];
535 void HandleFingerEvent(FingerEvent *event)
537 static Key motion_key_x = KSYM_UNDEFINED;
538 static Key motion_key_y = KSYM_UNDEFINED;
539 static Key button_key = KSYM_UNDEFINED;
540 static float motion_x1, motion_y1;
541 static float button_x1, button_y1;
542 static SDL_FingerID motion_id = 0;
543 static SDL_FingerID button_id = 0;
544 int trigger_distance_percent = 1; // percent of touchpad width/height
545 float trigger_distance = (float)trigger_distance_percent / 100;
546 float event_x = event->x;
547 float event_y = event->y;
551 Error(ERR_DEBUG, "FINGER EVENT: finger was %s, touch ID %lld, finger ID %lld, x/y %f/%f, dx/dy %f/%f, pressure %f",
552 event->type == EVENT_FINGERPRESS ? "pressed" :
553 event->type == EVENT_FINGERRELEASE ? "released" : "moved",
557 event->dx, event->dy,
562 if (game_status != GAME_MODE_PLAYING)
567 int key_status = (event->type == EVENT_FINGERRELEASE ? KEY_RELEASED :
570 Key key = (event->x < 1.0 / 3.0 ?
571 (event->y < 1.0 / 2.0 ? setup.input[0].key.snap :
572 setup.input[0].key.drop) :
573 event->x > 2.0 / 3.0 ?
574 (event->y < 1.0 / 3.0 ? setup.input[0].key.up :
575 event->y > 2.0 / 3.0 ? setup.input[0].key.down :
576 event->x < 5.0 / 6.0 ? setup.input[0].key.left :
577 setup.input[0].key.right) :
580 char *key_name = (key == setup.input[0].key.snap ? "SNAP" :
581 key == setup.input[0].key.drop ? "DROP" :
582 key == setup.input[0].key.up ? "UP" :
583 key == setup.input[0].key.down ? "DOWN" :
584 key == setup.input[0].key.left ? "LEFT" :
585 key == setup.input[0].key.right ? "RIGHT" : "(unknown)");
587 char *key_status_name = (key_status == KEY_RELEASED ? "KEY_RELEASED" :
590 Key key = (event->y < 1.0 / 3.0 ? setup.input[0].key.up :
591 event->y > 2.0 / 3.0 ? setup.input[0].key.down :
592 event->x < 1.0 / 3.0 ? setup.input[0].key.left :
593 event->x > 2.0 / 3.0 ? setup.input[0].key.right :
594 setup.input[0].key.snap);
598 Error(ERR_DEBUG, "::: key '%s' was '%s' [fingerId: %lld]",
599 getKeyNameFromKey(key), key_status_name, event->fingerId);
601 // check if we already know this touch event's finger id
602 for (i = 0; i < NUM_TOUCH_FINGERS; i++)
604 if (touch_info[i].touched &&
605 touch_info[i].finger_id == event->fingerId)
607 // Error(ERR_DEBUG, "MARK 1: %d", i);
613 if (i >= NUM_TOUCH_FINGERS)
615 if (key_status == KEY_PRESSED)
617 int oldest_pos = 0, oldest_counter = touch_info[0].counter;
619 // unknown finger id -- get new, empty slot, if available
620 for (i = 0; i < NUM_TOUCH_FINGERS; i++)
622 if (touch_info[i].counter < oldest_counter)
625 oldest_counter = touch_info[i].counter;
627 // Error(ERR_DEBUG, "MARK 2: %d", i);
630 if (!touch_info[i].touched)
632 // Error(ERR_DEBUG, "MARK 3: %d", i);
638 if (i >= NUM_TOUCH_FINGERS)
640 // all slots allocated -- use oldest slot
643 // Error(ERR_DEBUG, "MARK 4: %d", i);
648 // release of previously unknown key (should not happen)
650 if (key != KSYM_UNDEFINED)
652 HandleKey(key, KEY_RELEASED);
654 Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d] [1]",
655 getKeyNameFromKey(key), "KEY_RELEASED", i);
660 if (i < NUM_TOUCH_FINGERS)
662 if (key_status == KEY_PRESSED)
664 if (touch_info[i].key != key)
666 if (touch_info[i].key != KSYM_UNDEFINED)
668 HandleKey(touch_info[i].key, KEY_RELEASED);
670 Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d] [2]",
671 getKeyNameFromKey(touch_info[i].key), "KEY_RELEASED", i);
674 if (key != KSYM_UNDEFINED)
676 HandleKey(key, KEY_PRESSED);
678 Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d] [3]",
679 getKeyNameFromKey(key), "KEY_PRESSED", i);
683 touch_info[i].touched = TRUE;
684 touch_info[i].finger_id = event->fingerId;
685 touch_info[i].counter = Counter();
686 touch_info[i].key = key;
690 if (touch_info[i].key != KSYM_UNDEFINED)
692 HandleKey(touch_info[i].key, KEY_RELEASED);
694 Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d] [4]",
695 getKeyNameFromKey(touch_info[i].key), "KEY_RELEASED", i);
698 touch_info[i].touched = FALSE;
699 touch_info[i].finger_id = 0;
700 touch_info[i].counter = 0;
701 touch_info[i].key = 0;
707 Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d]",
708 key_name, key_status_name, i);
710 Error(ERR_DEBUG, "=> key == %d, key_status == %d [%d]", key, key_status, i);
717 if (event->type == EVENT_FINGERPRESS)
719 if (event_x > 1.0 / 3.0)
723 motion_id = event->fingerId;
728 motion_key_x = KSYM_UNDEFINED;
729 motion_key_y = KSYM_UNDEFINED;
731 Error(ERR_DEBUG, "---------- MOVE STARTED (WAIT) ----------");
737 button_id = event->fingerId;
742 button_key = setup.input[0].key.snap;
744 HandleKey(button_key, KEY_PRESSED);
746 Error(ERR_DEBUG, "---------- SNAP STARTED ----------");
749 else if (event->type == EVENT_FINGERRELEASE)
751 if (event->fingerId == motion_id)
755 if (motion_key_x != KSYM_UNDEFINED)
756 HandleKey(motion_key_x, KEY_RELEASED);
757 if (motion_key_y != KSYM_UNDEFINED)
758 HandleKey(motion_key_y, KEY_RELEASED);
760 motion_key_x = KSYM_UNDEFINED;
761 motion_key_y = KSYM_UNDEFINED;
763 Error(ERR_DEBUG, "---------- MOVE STOPPED ----------");
765 else if (event->fingerId == button_id)
769 if (button_key != KSYM_UNDEFINED)
770 HandleKey(button_key, KEY_RELEASED);
772 button_key = KSYM_UNDEFINED;
774 Error(ERR_DEBUG, "---------- SNAP STOPPED ----------");
777 else if (event->type == EVENT_FINGERMOTION)
779 if (event->fingerId == motion_id)
781 float distance_x = ABS(event_x - motion_x1);
782 float distance_y = ABS(event_y - motion_y1);
783 Key new_motion_key_x = (event_x < motion_x1 ? setup.input[0].key.left :
784 event_x > motion_x1 ? setup.input[0].key.right :
786 Key new_motion_key_y = (event_y < motion_y1 ? setup.input[0].key.up :
787 event_y > motion_y1 ? setup.input[0].key.down :
790 if (distance_x < trigger_distance / 2 ||
791 distance_x < distance_y)
792 new_motion_key_x = KSYM_UNDEFINED;
794 if (distance_y < trigger_distance / 2 ||
795 distance_y < distance_x)
796 new_motion_key_y = KSYM_UNDEFINED;
798 if (distance_x > trigger_distance ||
799 distance_y > trigger_distance)
801 if (new_motion_key_x != motion_key_x)
803 if (motion_key_x != KSYM_UNDEFINED)
804 HandleKey(motion_key_x, KEY_RELEASED);
805 if (new_motion_key_x != KSYM_UNDEFINED)
806 HandleKey(new_motion_key_x, KEY_PRESSED);
809 if (new_motion_key_y != motion_key_y)
811 if (motion_key_y != KSYM_UNDEFINED)
812 HandleKey(motion_key_y, KEY_RELEASED);
813 if (new_motion_key_y != KSYM_UNDEFINED)
814 HandleKey(new_motion_key_y, KEY_PRESSED);
820 motion_key_x = new_motion_key_x;
821 motion_key_y = new_motion_key_y;
823 Error(ERR_DEBUG, "---------- MOVE STARTED (MOVE) ----------");
826 else if (event->fingerId == button_id)
828 float distance_x = ABS(event_x - button_x1);
829 float distance_y = ABS(event_y - button_y1);
831 if (distance_x < trigger_distance / 2 &&
832 distance_y > trigger_distance)
834 if (button_key == setup.input[0].key.snap)
835 HandleKey(button_key, KEY_RELEASED);
840 button_key = setup.input[0].key.drop;
842 HandleKey(button_key, KEY_PRESSED);
844 Error(ERR_DEBUG, "---------- DROP STARTED ----------");
852 void HandleFingerEvent(FingerEvent *event)
855 static int num_events = 0;
861 Error(ERR_DEBUG, "FINGER EVENT: finger was %s, touch ID %lld, finger ID %lld, x/y %f/%f, dx/dy %f/%f, pressure %f",
862 event->type == EVENT_FINGERPRESS ? "pressed" :
863 event->type == EVENT_FINGERRELEASE ? "released" : "moved",
867 event->dx, event->dy,
873 int x = (int)(event->x * video.width);
874 int y = (int)(event->y * video.height);
875 int button = MB_LEFTBUTTON;
877 Error(ERR_DEBUG, "=> screen x/y %d/%d", x, y);
881 if (++num_events >= max_events)
887 if (event->type == EVENT_FINGERPRESS ||
888 event->type == EVENT_FINGERMOTION)
889 button_status = button;
891 button_status = MB_RELEASED;
893 int max_x = SX + SXSIZE;
894 int max_y = SY + SYSIZE;
898 if (game_status == GAME_MODE_PLAYING)
900 if (game_status == GAME_MODE_PLAYING &&
904 int key_status = (event->type == EVENT_FINGERRELEASE ? KEY_RELEASED :
907 Key key = (event->y < 1.0 / 3.0 ? setup.input[0].key.up :
908 event->y > 2.0 / 3.0 ? setup.input[0].key.down :
909 event->x < 1.0 / 3.0 ? setup.input[0].key.left :
910 event->x > 2.0 / 3.0 ? setup.input[0].key.right :
911 setup.input[0].key.drop);
913 Key key = (y < max_y / 3 ? setup.input[0].key.up :
914 y > 2 * max_y / 3 ? setup.input[0].key.down :
915 x < max_x / 3 ? setup.input[0].key.left :
916 x > 2 * max_x / 3 ? setup.input[0].key.right :
917 setup.input[0].key.drop);
920 Error(ERR_DEBUG, "=> key == %d, key_status == %d", key, key_status);
922 HandleKey(key, key_status);
927 Error(ERR_DEBUG, "::: button_status == %d, button == %d\n",
928 button_status, button);
930 HandleButton(x, y, button_status, button);
938 static boolean checkTextInputKeyModState()
940 // when playing, only handle raw key events and ignore text input
941 if (game_status == GAME_MODE_PLAYING)
944 return ((GetKeyModState() & KMOD_TextInput) != KMOD_None);
947 void HandleTextEvent(TextEvent *event)
949 char *text = event->text;
950 Key key = getKeyFromKeyName(text);
953 Error(ERR_DEBUG, "TEXT EVENT: text == '%s' [%d byte(s), '%c'/%d], resulting key == %d (%s) [%04x]",
956 text[0], (int)(text[0]),
958 getKeyNameFromKey(key),
962 // if (game_status != GAME_MODE_PLAYING && GetKeyModState() != KMOD_None)
964 if (game_status != GAME_MODE_PLAYING &&
965 (GetKeyModState() & KMOD_TextInput) != KMOD_None)
967 if (checkTextInputKeyModState())
969 HandleKey(key, KEY_PRESSED);
970 HandleKey(key, KEY_RELEASED);
975 void HandleKeyEvent(KeyEvent *event)
977 int key_status = (event->type == EVENT_KEYPRESS ? KEY_PRESSED : KEY_RELEASED);
978 boolean with_modifiers = (game_status == GAME_MODE_PLAYING ? FALSE : TRUE);
979 Key key = GetEventKey(event, with_modifiers);
980 Key keymod = (with_modifiers ? GetEventKey(event, FALSE) : key);
983 Error(ERR_DEBUG, "KEY EVENT: key was %s, keysym.scancode == %d, keysym.sym == %d, keymod = %d, GetKeyModState() = 0x%04x, resulting key == %d (%s)",
984 event->type == EVENT_KEYPRESS ? "pressed" : "released",
985 event->keysym.scancode,
990 getKeyNameFromKey(key));
994 if (key == KSYM_Menu)
995 Error(ERR_DEBUG, "menu key pressed");
996 else if (key == KSYM_Back)
997 Error(ERR_DEBUG, "back key pressed");
1000 #if defined(PLATFORM_ANDROID)
1001 // always map the "back" button to the "escape" key on Android devices
1002 if (key == KSYM_Back)
1006 HandleKeyModState(keymod, key_status);
1008 #if defined(TARGET_SDL2)
1010 // if (game_status == GAME_MODE_PLAYING || GetKeyModState() == KMOD_None)
1012 if (game_status == GAME_MODE_PLAYING ||
1013 (GetKeyModState() & KMOD_TextInput) == KMOD_None)
1015 if (!checkTextInputKeyModState())
1016 HandleKey(key, key_status);
1018 HandleKey(key, key_status);
1022 void HandleFocusEvent(FocusChangeEvent *event)
1024 static int old_joystick_status = -1;
1026 if (event->type == EVENT_FOCUSOUT)
1028 KeyboardAutoRepeatOn();
1029 old_joystick_status = joystick.status;
1030 joystick.status = JOYSTICK_NOT_AVAILABLE;
1032 ClearPlayerAction();
1034 else if (event->type == EVENT_FOCUSIN)
1036 /* When there are two Rocks'n'Diamonds windows which overlap and
1037 the player moves the pointer from one game window to the other,
1038 a 'FocusOut' event is generated for the window the pointer is
1039 leaving and a 'FocusIn' event is generated for the window the
1040 pointer is entering. In some cases, it can happen that the
1041 'FocusIn' event is handled by the one game process before the
1042 'FocusOut' event by the other game process. In this case the
1043 X11 environment would end up with activated keyboard auto repeat,
1044 because unfortunately this is a global setting and not (which
1045 would be far better) set for each X11 window individually.
1046 The effect would be keyboard auto repeat while playing the game
1047 (game_status == GAME_MODE_PLAYING), which is not desired.
1048 To avoid this special case, we just wait 1/10 second before
1049 processing the 'FocusIn' event.
1052 if (game_status == GAME_MODE_PLAYING)
1055 KeyboardAutoRepeatOffUnlessAutoplay();
1058 if (old_joystick_status != -1)
1059 joystick.status = old_joystick_status;
1063 void HandleClientMessageEvent(ClientMessageEvent *event)
1065 if (CheckCloseWindowEvent(event))
1069 void HandleWindowManagerEvent(Event *event)
1071 #if defined(TARGET_SDL)
1072 SDLHandleWindowManagerEvent(event);
1076 void HandleButton(int mx, int my, int button, int button_nr)
1078 static int old_mx = 0, old_my = 0;
1092 #if defined(PLATFORM_ANDROID)
1093 if (game_status != GAME_MODE_PLAYING &&
1094 HandleGadgets(mx, my, button))
1096 /* do not handle this button event anymore */
1097 mx = my = -32; /* force mouse event to be outside screen tiles */
1100 if (HandleGadgets(mx, my, button))
1102 /* do not handle this button event anymore */
1103 mx = my = -32; /* force mouse event to be outside screen tiles */
1107 /* do not use scroll wheel button events for anything other than gadgets */
1108 if (IS_WHEEL_BUTTON(button_nr))
1112 Error(ERR_DEBUG, "::: game_status == %d", game_status);
1115 switch (game_status)
1117 case GAME_MODE_TITLE:
1118 HandleTitleScreen(mx, my, 0, 0, button);
1121 case GAME_MODE_MAIN:
1122 HandleMainMenu(mx, my, 0, 0, button);
1125 case GAME_MODE_PSEUDO_TYPENAME:
1126 HandleTypeName(0, KSYM_Return);
1129 case GAME_MODE_LEVELS:
1130 HandleChooseLevelSet(mx, my, 0, 0, button);
1133 case GAME_MODE_LEVELNR:
1134 HandleChooseLevelNr(mx, my, 0, 0, button);
1137 case GAME_MODE_SCORES:
1138 HandleHallOfFame(0, 0, 0, 0, button);
1141 case GAME_MODE_EDITOR:
1142 HandleLevelEditorIdle();
1145 case GAME_MODE_INFO:
1146 HandleInfoScreen(mx, my, 0, 0, button);
1149 case GAME_MODE_SETUP:
1150 HandleSetupScreen(mx, my, 0, 0, button);
1153 case GAME_MODE_PLAYING:
1155 if (button == MB_PRESSED && !motion_status && IN_GFX_FIELD_PLAY(mx, my))
1156 DumpTile(LEVELX((mx - SX) / TILEX), LEVELY((my - SY) / TILEY));
1165 static boolean is_string_suffix(char *string, char *suffix)
1167 int string_len = strlen(string);
1168 int suffix_len = strlen(suffix);
1170 if (suffix_len > string_len)
1173 return (strEqual(&string[string_len - suffix_len], suffix));
1176 #define MAX_CHEAT_INPUT_LEN 32
1178 static void HandleKeysSpecial(Key key)
1180 static char cheat_input[2 * MAX_CHEAT_INPUT_LEN + 1] = "";
1181 char letter = getCharFromKey(key);
1182 int cheat_input_len = strlen(cheat_input);
1188 if (cheat_input_len >= 2 * MAX_CHEAT_INPUT_LEN)
1190 for (i = 0; i < MAX_CHEAT_INPUT_LEN + 1; i++)
1191 cheat_input[i] = cheat_input[MAX_CHEAT_INPUT_LEN + i];
1193 cheat_input_len = MAX_CHEAT_INPUT_LEN;
1196 cheat_input[cheat_input_len++] = letter;
1197 cheat_input[cheat_input_len] = '\0';
1200 Error(ERR_DEBUG, "SPECIAL KEY '%s' [%d]\n", cheat_input, cheat_input_len);
1203 if (game_status == GAME_MODE_MAIN)
1205 if (is_string_suffix(cheat_input, ":insert-solution-tape") ||
1206 is_string_suffix(cheat_input, ":ist"))
1208 InsertSolutionTape();
1210 else if (is_string_suffix(cheat_input, ":reload-graphics") ||
1211 is_string_suffix(cheat_input, ":rg"))
1213 ReloadCustomArtwork(1 << ARTWORK_TYPE_GRAPHICS);
1216 else if (is_string_suffix(cheat_input, ":reload-sounds") ||
1217 is_string_suffix(cheat_input, ":rs"))
1219 ReloadCustomArtwork(1 << ARTWORK_TYPE_SOUNDS);
1222 else if (is_string_suffix(cheat_input, ":reload-music") ||
1223 is_string_suffix(cheat_input, ":rm"))
1225 ReloadCustomArtwork(1 << ARTWORK_TYPE_MUSIC);
1228 else if (is_string_suffix(cheat_input, ":reload-artwork") ||
1229 is_string_suffix(cheat_input, ":ra"))
1231 ReloadCustomArtwork(1 << ARTWORK_TYPE_GRAPHICS |
1232 1 << ARTWORK_TYPE_SOUNDS |
1233 1 << ARTWORK_TYPE_MUSIC);
1236 else if (is_string_suffix(cheat_input, ":dump-level") ||
1237 is_string_suffix(cheat_input, ":dl"))
1241 else if (is_string_suffix(cheat_input, ":dump-tape") ||
1242 is_string_suffix(cheat_input, ":dt"))
1246 else if (is_string_suffix(cheat_input, ":fix-tape") ||
1247 is_string_suffix(cheat_input, ":ft"))
1249 /* fix single-player tapes that contain player input for more than one
1250 player (due to a bug in 3.3.1.2 and earlier versions), which results
1251 in playing levels with more than one player in multi-player mode,
1252 even though the tape was originally recorded in single-player mode */
1254 /* remove player input actions for all players but the first one */
1255 for (i = 1; i < MAX_PLAYERS; i++)
1256 tape.player_participates[i] = FALSE;
1258 tape.changed = TRUE;
1260 else if (is_string_suffix(cheat_input, ":save-native-level") ||
1261 is_string_suffix(cheat_input, ":snl"))
1263 SaveNativeLevel(&level);
1266 else if (game_status == GAME_MODE_PLAYING)
1269 if (is_string_suffix(cheat_input, ".q"))
1270 DEBUG_SetMaximumDynamite();
1273 else if (game_status == GAME_MODE_EDITOR)
1275 if (is_string_suffix(cheat_input, ":dump-brush") ||
1276 is_string_suffix(cheat_input, ":DB"))
1280 else if (is_string_suffix(cheat_input, ":DDB"))
1287 void HandleKey(Key key, int key_status)
1289 boolean anyTextGadgetActiveOrJustFinished = anyTextGadgetActive();
1290 static struct SetupKeyboardInfo ski;
1291 static struct SetupShortcutInfo ssi;
1300 { &ski.left, &ssi.snap_left, DEFAULT_KEY_LEFT, JOY_LEFT },
1301 { &ski.right, &ssi.snap_right, DEFAULT_KEY_RIGHT, JOY_RIGHT },
1302 { &ski.up, &ssi.snap_up, DEFAULT_KEY_UP, JOY_UP },
1303 { &ski.down, &ssi.snap_down, DEFAULT_KEY_DOWN, JOY_DOWN },
1304 { &ski.snap, NULL, DEFAULT_KEY_SNAP, JOY_BUTTON_SNAP },
1305 { &ski.drop, NULL, DEFAULT_KEY_DROP, JOY_BUTTON_DROP }
1310 if (game_status == GAME_MODE_PLAYING)
1312 /* only needed for single-step tape recording mode */
1313 static boolean clear_snap_button[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1314 static boolean clear_drop_button[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1315 static boolean element_snapped[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1316 static boolean element_dropped[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1319 for (pnr = 0; pnr < MAX_PLAYERS; pnr++)
1321 byte key_action = 0;
1323 if (setup.input[pnr].use_joystick)
1326 ski = setup.input[pnr].key;
1328 for (i = 0; i < NUM_PLAYER_ACTIONS; i++)
1329 if (key == *key_info[i].key_custom)
1330 key_action |= key_info[i].action;
1332 /* use combined snap+direction keys for the first player only */
1335 ssi = setup.shortcut;
1337 for (i = 0; i < NUM_DIRECTIONS; i++)
1338 if (key == *key_info[i].key_snap)
1339 key_action |= key_info[i].action | JOY_BUTTON_SNAP;
1342 /* clear delayed snap and drop actions in single step mode (see below) */
1343 if (tape.single_step)
1345 if (clear_snap_button[pnr])
1347 stored_player[pnr].action &= ~KEY_BUTTON_SNAP;
1348 clear_snap_button[pnr] = FALSE;
1351 if (clear_drop_button[pnr])
1353 stored_player[pnr].action &= ~KEY_BUTTON_DROP;
1354 clear_drop_button[pnr] = FALSE;
1358 if (key_status == KEY_PRESSED)
1359 stored_player[pnr].action |= key_action;
1361 stored_player[pnr].action &= ~key_action;
1363 if (tape.single_step && tape.recording && tape.pausing)
1365 if (key_status == KEY_PRESSED && key_action & KEY_MOTION)
1367 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1369 /* if snap key already pressed, don't snap when releasing (below) */
1370 if (stored_player[pnr].action & KEY_BUTTON_SNAP)
1371 element_snapped[pnr] = TRUE;
1373 /* if drop key already pressed, don't drop when releasing (below) */
1374 if (stored_player[pnr].action & KEY_BUTTON_DROP)
1375 element_dropped[pnr] = TRUE;
1378 else if (key_status == KEY_PRESSED && key_action & KEY_BUTTON_DROP)
1380 if (level.game_engine_type == GAME_ENGINE_TYPE_EM ||
1381 level.game_engine_type == GAME_ENGINE_TYPE_SP)
1384 printf("::: drop key pressed\n");
1387 if (level.game_engine_type == GAME_ENGINE_TYPE_SP &&
1388 getRedDiskReleaseFlag_SP() == 0)
1389 stored_player[pnr].action &= ~KEY_BUTTON_DROP;
1391 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1395 else if (key_status == KEY_RELEASED && key_action & KEY_BUTTON)
1397 if (key_action & KEY_BUTTON_SNAP)
1399 /* if snap key was released without moving (see above), snap now */
1400 if (!element_snapped[pnr])
1402 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1404 stored_player[pnr].action |= KEY_BUTTON_SNAP;
1406 /* clear delayed snap button on next event */
1407 clear_snap_button[pnr] = TRUE;
1410 element_snapped[pnr] = FALSE;
1414 if (key_action & KEY_BUTTON_DROP &&
1415 level.game_engine_type == GAME_ENGINE_TYPE_RND)
1417 /* if drop key was released without moving (see above), drop now */
1418 if (!element_dropped[pnr])
1420 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1422 if (level.game_engine_type != GAME_ENGINE_TYPE_SP ||
1423 getRedDiskReleaseFlag_SP() != 0)
1424 stored_player[pnr].action |= KEY_BUTTON_DROP;
1426 /* clear delayed drop button on next event */
1427 clear_drop_button[pnr] = TRUE;
1430 element_dropped[pnr] = FALSE;
1435 else if (tape.recording && tape.pausing)
1437 /* prevent key release events from un-pausing a paused game */
1438 if (key_status == KEY_PRESSED && key_action & KEY_ACTION)
1439 TapeTogglePause(TAPE_TOGGLE_MANUAL);
1445 for (i = 0; i < NUM_PLAYER_ACTIONS; i++)
1446 if (key == key_info[i].key_default)
1447 joy |= key_info[i].action;
1452 if (key_status == KEY_PRESSED)
1453 key_joystick_mapping |= joy;
1455 key_joystick_mapping &= ~joy;
1460 if (game_status != GAME_MODE_PLAYING)
1461 key_joystick_mapping = 0;
1463 if (key_status == KEY_RELEASED)
1466 if ((key == KSYM_Return || key == KSYM_KP_Enter) &&
1467 (GetKeyModState() & KMOD_Alt) && video.fullscreen_available)
1469 setup.fullscreen = !setup.fullscreen;
1472 printf("::: %d\n", setup.window_scaling_percent);
1475 ToggleFullscreenOrChangeWindowScalingIfNeeded();
1477 if (game_status == GAME_MODE_SETUP)
1478 RedrawSetupScreenAfterFullscreenToggle();
1483 if ((key == KSYM_minus || key == KSYM_plus || key == KSYM_0) &&
1484 (GetKeyModState() & KMOD_Alt) && video.window_scaling_available &&
1485 !video.fullscreen_enabled)
1488 setup.window_scaling_percent = STD_WINDOW_SCALING_PERCENT;
1490 setup.window_scaling_percent +=
1491 (key == KSYM_minus ? -1 : +1) * STEP_WINDOW_SCALING_PERCENT;
1493 if (setup.window_scaling_percent < MIN_WINDOW_SCALING_PERCENT)
1494 setup.window_scaling_percent = MIN_WINDOW_SCALING_PERCENT;
1495 else if (setup.window_scaling_percent > MAX_WINDOW_SCALING_PERCENT)
1496 setup.window_scaling_percent = MAX_WINDOW_SCALING_PERCENT;
1498 ToggleFullscreenOrChangeWindowScalingIfNeeded();
1500 if (game_status == GAME_MODE_SETUP)
1501 RedrawSetupScreenAfterFullscreenToggle();
1507 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd &&
1508 (key == KSYM_Return || key == setup.shortcut.toggle_pause))
1510 if (game_status == GAME_MODE_PLAYING && AllPlayersGone &&
1511 (key == KSYM_Return || key == setup.shortcut.toggle_pause))
1519 if (game_status == GAME_MODE_MAIN &&
1520 (key == setup.shortcut.toggle_pause || key == KSYM_space))
1522 StartGameActions(options.network, setup.autorecord, level.random_seed);
1527 if (game_status == GAME_MODE_MAIN || game_status == GAME_MODE_PLAYING)
1529 if (key == setup.shortcut.save_game)
1531 else if (key == setup.shortcut.load_game)
1533 else if (key == setup.shortcut.toggle_pause)
1534 TapeTogglePause(TAPE_TOGGLE_MANUAL);
1536 HandleTapeButtonKeys(key);
1537 HandleSoundButtonKeys(key);
1540 if (game_status == GAME_MODE_PLAYING && !network_playing)
1542 int centered_player_nr_next = -999;
1544 if (key == setup.shortcut.focus_player_all)
1545 centered_player_nr_next = -1;
1547 for (i = 0; i < MAX_PLAYERS; i++)
1548 if (key == setup.shortcut.focus_player[i])
1549 centered_player_nr_next = i;
1551 if (centered_player_nr_next != -999)
1553 game.centered_player_nr_next = centered_player_nr_next;
1554 game.set_centered_player = TRUE;
1558 tape.centered_player_nr_next = game.centered_player_nr_next;
1559 tape.set_centered_player = TRUE;
1564 HandleKeysSpecial(key);
1566 if (HandleGadgetsKeyInput(key))
1568 if (key != KSYM_Escape) /* always allow ESC key to be handled */
1569 key = KSYM_UNDEFINED;
1572 switch (game_status)
1574 case GAME_MODE_PSEUDO_TYPENAME:
1575 HandleTypeName(0, key);
1578 case GAME_MODE_TITLE:
1579 case GAME_MODE_MAIN:
1580 case GAME_MODE_LEVELS:
1581 case GAME_MODE_LEVELNR:
1582 case GAME_MODE_SETUP:
1583 case GAME_MODE_INFO:
1584 case GAME_MODE_SCORES:
1589 if (game_status == GAME_MODE_TITLE)
1590 HandleTitleScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1591 else if (game_status == GAME_MODE_MAIN)
1592 HandleMainMenu(0, 0, 0, 0, MB_MENU_CHOICE);
1593 else if (game_status == GAME_MODE_LEVELS)
1594 HandleChooseLevelSet(0, 0, 0, 0, MB_MENU_CHOICE);
1595 else if (game_status == GAME_MODE_LEVELNR)
1596 HandleChooseLevelNr(0, 0, 0, 0, MB_MENU_CHOICE);
1597 else if (game_status == GAME_MODE_SETUP)
1598 HandleSetupScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1599 else if (game_status == GAME_MODE_INFO)
1600 HandleInfoScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1601 else if (game_status == GAME_MODE_SCORES)
1602 HandleHallOfFame(0, 0, 0, 0, MB_MENU_CHOICE);
1606 if (game_status != GAME_MODE_MAIN)
1607 FadeSkipNextFadeIn();
1609 if (game_status == GAME_MODE_TITLE)
1610 HandleTitleScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1611 else if (game_status == GAME_MODE_LEVELS)
1612 HandleChooseLevelSet(0, 0, 0, 0, MB_MENU_LEAVE);
1613 else if (game_status == GAME_MODE_LEVELNR)
1614 HandleChooseLevelNr(0, 0, 0, 0, MB_MENU_LEAVE);
1615 else if (game_status == GAME_MODE_SETUP)
1616 HandleSetupScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1617 else if (game_status == GAME_MODE_INFO)
1618 HandleInfoScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1619 else if (game_status == GAME_MODE_SCORES)
1620 HandleHallOfFame(0, 0, 0, 0, MB_MENU_LEAVE);
1624 if (game_status == GAME_MODE_LEVELS)
1625 HandleChooseLevelSet(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1626 else if (game_status == GAME_MODE_LEVELNR)
1627 HandleChooseLevelNr(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1628 else if (game_status == GAME_MODE_SETUP)
1629 HandleSetupScreen(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1630 else if (game_status == GAME_MODE_INFO)
1631 HandleInfoScreen(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1632 else if (game_status == GAME_MODE_SCORES)
1633 HandleHallOfFame(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1636 case KSYM_Page_Down:
1637 if (game_status == GAME_MODE_LEVELS)
1638 HandleChooseLevelSet(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1639 else if (game_status == GAME_MODE_LEVELNR)
1640 HandleChooseLevelNr(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1641 else if (game_status == GAME_MODE_SETUP)
1642 HandleSetupScreen(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1643 else if (game_status == GAME_MODE_INFO)
1644 HandleInfoScreen(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1645 else if (game_status == GAME_MODE_SCORES)
1646 HandleHallOfFame(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1651 GameFrameDelay = (GameFrameDelay == 500 ? GAME_FRAME_DELAY : 500);
1655 setup.sp_show_border_elements = !setup.sp_show_border_elements;
1656 printf("Supaplex border elements %s\n",
1657 setup.sp_show_border_elements ? "enabled" : "disabled");
1666 case GAME_MODE_EDITOR:
1667 if (!anyTextGadgetActiveOrJustFinished || key == KSYM_Escape)
1668 HandleLevelEditorKeyInput(key);
1671 case GAME_MODE_PLAYING:
1676 RequestQuitGame(setup.ask_on_escape);
1694 if (GameFrameDelay == 500)
1695 GameFrameDelay = GAME_FRAME_DELAY;
1697 GameFrameDelay = 500;
1700 GameFrameDelay = (key - KSYM_0) * 10;
1701 printf("Game speed == %d%% (%d ms delay between two frames)\n",
1702 GAME_FRAME_DELAY * 100 / GameFrameDelay, GameFrameDelay);
1708 options.debug = FALSE;
1709 printf("debug mode disabled\n");
1713 options.debug = TRUE;
1714 printf("debug mode enabled\n");
1720 if (!global.fps_slowdown)
1722 global.fps_slowdown = TRUE;
1723 global.fps_slowdown_factor = 2;
1724 printf("fps slowdown enabled -- display only every 2nd frame\n");
1726 else if (global.fps_slowdown_factor == 2)
1728 global.fps_slowdown_factor = 4;
1729 printf("fps slowdown enabled -- display only every 4th frame\n");
1733 global.fps_slowdown = FALSE;
1734 global.fps_slowdown_factor = 1;
1735 printf("fps slowdown disabled\n");
1742 ScrollStepSize = TILEX / 8;
1743 printf("ScrollStepSize == %d (1/8)\n", ScrollStepSize);
1747 ScrollStepSize = TILEX / 4;
1748 printf("ScrollStepSize == %d (1/4)\n", ScrollStepSize);
1752 ScrollStepSize = TILEX / 2;
1753 printf("ScrollStepSize == %d (1/2)\n", ScrollStepSize);
1757 ScrollStepSize = TILEX;
1758 printf("ScrollStepSize == %d (1/1)\n", ScrollStepSize);
1763 printf("::: currently using game engine version %d\n",
1764 game.engine_version);
1775 if (key == KSYM_Escape)
1777 game_status = GAME_MODE_MAIN;
1785 void HandleNoEvent()
1787 if (button_status && game_status != GAME_MODE_PLAYING)
1789 HandleButton(0, 0, -button_status, button_status);
1800 #if defined(NETWORK_AVALIABLE)
1801 if (options.network)
1805 switch (game_status)
1807 case GAME_MODE_MAIN:
1808 DrawPreviewLevelAnimation();
1812 case GAME_MODE_LEVELS:
1813 case GAME_MODE_LEVELNR:
1814 case GAME_MODE_SETUP:
1815 case GAME_MODE_INFO:
1816 case GAME_MODE_SCORES:
1820 case GAME_MODE_EDITOR:
1821 HandleLevelEditorIdle();
1829 static int HandleJoystickForAllPlayers()
1834 for (i = 0; i < MAX_PLAYERS; i++)
1836 byte joy_action = 0;
1839 if (!setup.input[i].use_joystick)
1843 joy_action = Joystick(i);
1844 result |= joy_action;
1846 if (!setup.input[i].use_joystick)
1849 stored_player[i].action = joy_action;
1855 void HandleJoystick()
1857 int joystick = HandleJoystickForAllPlayers();
1858 int keyboard = key_joystick_mapping;
1859 int joy = (joystick | keyboard);
1860 int left = joy & JOY_LEFT;
1861 int right = joy & JOY_RIGHT;
1862 int up = joy & JOY_UP;
1863 int down = joy & JOY_DOWN;
1864 int button = joy & JOY_BUTTON;
1865 int newbutton = (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED);
1866 int dx = (left ? -1 : right ? 1 : 0);
1867 int dy = (up ? -1 : down ? 1 : 0);
1869 switch (game_status)
1871 case GAME_MODE_TITLE:
1872 case GAME_MODE_MAIN:
1873 case GAME_MODE_LEVELS:
1874 case GAME_MODE_LEVELNR:
1875 case GAME_MODE_SETUP:
1876 case GAME_MODE_INFO:
1878 static unsigned int joystickmove_delay = 0;
1880 if (joystick && !button &&
1881 !DelayReached(&joystickmove_delay, GADGET_FRAME_DELAY))
1882 newbutton = dx = dy = 0;
1884 if (game_status == GAME_MODE_TITLE)
1885 HandleTitleScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1886 else if (game_status == GAME_MODE_MAIN)
1887 HandleMainMenu(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1888 else if (game_status == GAME_MODE_LEVELS)
1889 HandleChooseLevelSet(0,0,dx,dy,newbutton?MB_MENU_CHOICE : MB_MENU_MARK);
1890 else if (game_status == GAME_MODE_LEVELNR)
1891 HandleChooseLevelNr(0,0,dx,dy,newbutton? MB_MENU_CHOICE : MB_MENU_MARK);
1892 else if (game_status == GAME_MODE_SETUP)
1893 HandleSetupScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1894 else if (game_status == GAME_MODE_INFO)
1895 HandleInfoScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1899 case GAME_MODE_SCORES:
1900 HandleHallOfFame(0, 0, dx, dy, !newbutton);
1904 case GAME_MODE_EDITOR:
1905 HandleLevelEditorIdle();
1909 case GAME_MODE_PLAYING:
1910 if (tape.playing || keyboard)
1911 newbutton = ((joy & JOY_BUTTON) != 0);
1914 if (newbutton && local_player->LevelSolved_GameEnd)
1916 if (newbutton && AllPlayersGone)