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_SCREEN(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, ":save-native-level") ||
1241 is_string_suffix(cheat_input, ":snl"))
1243 SaveNativeLevel(&level);
1246 else if (game_status == GAME_MODE_PLAYING)
1249 if (is_string_suffix(cheat_input, ".q"))
1250 DEBUG_SetMaximumDynamite();
1253 else if (game_status == GAME_MODE_EDITOR)
1255 if (is_string_suffix(cheat_input, ":dump-brush") ||
1256 is_string_suffix(cheat_input, ":DB"))
1260 else if (is_string_suffix(cheat_input, ":DDB"))
1267 void HandleKey(Key key, int key_status)
1269 boolean anyTextGadgetActiveOrJustFinished = anyTextGadgetActive();
1270 static struct SetupKeyboardInfo ski;
1271 static struct SetupShortcutInfo ssi;
1280 { &ski.left, &ssi.snap_left, DEFAULT_KEY_LEFT, JOY_LEFT },
1281 { &ski.right, &ssi.snap_right, DEFAULT_KEY_RIGHT, JOY_RIGHT },
1282 { &ski.up, &ssi.snap_up, DEFAULT_KEY_UP, JOY_UP },
1283 { &ski.down, &ssi.snap_down, DEFAULT_KEY_DOWN, JOY_DOWN },
1284 { &ski.snap, NULL, DEFAULT_KEY_SNAP, JOY_BUTTON_SNAP },
1285 { &ski.drop, NULL, DEFAULT_KEY_DROP, JOY_BUTTON_DROP }
1290 if (game_status == GAME_MODE_PLAYING)
1292 /* only needed for single-step tape recording mode */
1293 static boolean clear_snap_button[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1294 static boolean clear_drop_button[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1295 static boolean element_snapped[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1296 static boolean element_dropped[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1299 for (pnr = 0; pnr < MAX_PLAYERS; pnr++)
1301 byte key_action = 0;
1303 if (setup.input[pnr].use_joystick)
1306 ski = setup.input[pnr].key;
1308 for (i = 0; i < NUM_PLAYER_ACTIONS; i++)
1309 if (key == *key_info[i].key_custom)
1310 key_action |= key_info[i].action;
1312 /* use combined snap+direction keys for the first player only */
1315 ssi = setup.shortcut;
1317 for (i = 0; i < NUM_DIRECTIONS; i++)
1318 if (key == *key_info[i].key_snap)
1319 key_action |= key_info[i].action | JOY_BUTTON_SNAP;
1322 /* clear delayed snap and drop actions in single step mode (see below) */
1323 if (tape.single_step)
1325 if (clear_snap_button[pnr])
1327 stored_player[pnr].action &= ~KEY_BUTTON_SNAP;
1328 clear_snap_button[pnr] = FALSE;
1331 if (clear_drop_button[pnr])
1333 stored_player[pnr].action &= ~KEY_BUTTON_DROP;
1334 clear_drop_button[pnr] = FALSE;
1338 if (key_status == KEY_PRESSED)
1339 stored_player[pnr].action |= key_action;
1341 stored_player[pnr].action &= ~key_action;
1343 if (tape.single_step && tape.recording && tape.pausing)
1345 if (key_status == KEY_PRESSED && key_action & KEY_MOTION)
1347 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1349 /* if snap key already pressed, don't snap when releasing (below) */
1350 if (stored_player[pnr].action & KEY_BUTTON_SNAP)
1351 element_snapped[pnr] = TRUE;
1353 /* if drop key already pressed, don't drop when releasing (below) */
1354 if (stored_player[pnr].action & KEY_BUTTON_DROP)
1355 element_dropped[pnr] = TRUE;
1358 else if (key_status == KEY_PRESSED && key_action & KEY_BUTTON_DROP)
1360 if (level.game_engine_type == GAME_ENGINE_TYPE_EM ||
1361 level.game_engine_type == GAME_ENGINE_TYPE_SP)
1364 printf("::: drop key pressed\n");
1367 if (level.game_engine_type == GAME_ENGINE_TYPE_SP &&
1368 getRedDiskReleaseFlag_SP() == 0)
1369 stored_player[pnr].action &= ~KEY_BUTTON_DROP;
1371 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1375 else if (key_status == KEY_RELEASED && key_action & KEY_BUTTON)
1377 if (key_action & KEY_BUTTON_SNAP)
1379 /* if snap key was released without moving (see above), snap now */
1380 if (!element_snapped[pnr])
1382 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1384 stored_player[pnr].action |= KEY_BUTTON_SNAP;
1386 /* clear delayed snap button on next event */
1387 clear_snap_button[pnr] = TRUE;
1390 element_snapped[pnr] = FALSE;
1394 if (key_action & KEY_BUTTON_DROP &&
1395 level.game_engine_type == GAME_ENGINE_TYPE_RND)
1397 /* if drop key was released without moving (see above), drop now */
1398 if (!element_dropped[pnr])
1400 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1402 if (level.game_engine_type != GAME_ENGINE_TYPE_SP ||
1403 getRedDiskReleaseFlag_SP() != 0)
1404 stored_player[pnr].action |= KEY_BUTTON_DROP;
1406 /* clear delayed drop button on next event */
1407 clear_drop_button[pnr] = TRUE;
1410 element_dropped[pnr] = FALSE;
1415 else if (tape.recording && tape.pausing)
1417 /* prevent key release events from un-pausing a paused game */
1418 if (key_status == KEY_PRESSED && key_action & KEY_ACTION)
1419 TapeTogglePause(TAPE_TOGGLE_MANUAL);
1425 for (i = 0; i < NUM_PLAYER_ACTIONS; i++)
1426 if (key == key_info[i].key_default)
1427 joy |= key_info[i].action;
1432 if (key_status == KEY_PRESSED)
1433 key_joystick_mapping |= joy;
1435 key_joystick_mapping &= ~joy;
1440 if (game_status != GAME_MODE_PLAYING)
1441 key_joystick_mapping = 0;
1443 if (key_status == KEY_RELEASED)
1446 if ((key == KSYM_Return || key == KSYM_KP_Enter) &&
1447 (GetKeyModState() & KMOD_Alt) && video.fullscreen_available)
1449 setup.fullscreen = !setup.fullscreen;
1452 printf("::: %d\n", setup.window_scaling_percent);
1455 ToggleFullscreenOrChangeWindowScalingIfNeeded();
1457 if (game_status == GAME_MODE_SETUP)
1458 RedrawSetupScreenAfterFullscreenToggle();
1463 if ((key == KSYM_minus || key == KSYM_plus || key == KSYM_0) &&
1464 (GetKeyModState() & KMOD_Alt) && video.window_scaling_available &&
1465 !video.fullscreen_enabled)
1468 setup.window_scaling_percent = STD_WINDOW_SCALING_PERCENT;
1470 setup.window_scaling_percent +=
1471 (key == KSYM_minus ? -1 : +1) * STEP_WINDOW_SCALING_PERCENT;
1473 if (setup.window_scaling_percent < MIN_WINDOW_SCALING_PERCENT)
1474 setup.window_scaling_percent = MIN_WINDOW_SCALING_PERCENT;
1475 else if (setup.window_scaling_percent > MAX_WINDOW_SCALING_PERCENT)
1476 setup.window_scaling_percent = MAX_WINDOW_SCALING_PERCENT;
1478 ToggleFullscreenOrChangeWindowScalingIfNeeded();
1480 if (game_status == GAME_MODE_SETUP)
1481 RedrawSetupScreenAfterFullscreenToggle();
1487 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd &&
1488 (key == KSYM_Return || key == setup.shortcut.toggle_pause))
1490 if (game_status == GAME_MODE_PLAYING && AllPlayersGone &&
1491 (key == KSYM_Return || key == setup.shortcut.toggle_pause))
1499 if (game_status == GAME_MODE_MAIN &&
1500 (key == setup.shortcut.toggle_pause || key == KSYM_space))
1502 StartGameActions(options.network, setup.autorecord, level.random_seed);
1507 if (game_status == GAME_MODE_MAIN || game_status == GAME_MODE_PLAYING)
1509 if (key == setup.shortcut.save_game)
1511 else if (key == setup.shortcut.load_game)
1513 else if (key == setup.shortcut.toggle_pause)
1514 TapeTogglePause(TAPE_TOGGLE_MANUAL);
1516 HandleTapeButtonKeys(key);
1517 HandleSoundButtonKeys(key);
1520 if (game_status == GAME_MODE_PLAYING && !network_playing)
1522 int centered_player_nr_next = -999;
1524 if (key == setup.shortcut.focus_player_all)
1525 centered_player_nr_next = -1;
1527 for (i = 0; i < MAX_PLAYERS; i++)
1528 if (key == setup.shortcut.focus_player[i])
1529 centered_player_nr_next = i;
1531 if (centered_player_nr_next != -999)
1533 game.centered_player_nr_next = centered_player_nr_next;
1534 game.set_centered_player = TRUE;
1538 tape.centered_player_nr_next = game.centered_player_nr_next;
1539 tape.set_centered_player = TRUE;
1544 HandleKeysSpecial(key);
1546 if (HandleGadgetsKeyInput(key))
1548 if (key != KSYM_Escape) /* always allow ESC key to be handled */
1549 key = KSYM_UNDEFINED;
1552 switch (game_status)
1554 case GAME_MODE_PSEUDO_TYPENAME:
1555 HandleTypeName(0, key);
1558 case GAME_MODE_TITLE:
1559 case GAME_MODE_MAIN:
1560 case GAME_MODE_LEVELS:
1561 case GAME_MODE_LEVELNR:
1562 case GAME_MODE_SETUP:
1563 case GAME_MODE_INFO:
1564 case GAME_MODE_SCORES:
1569 if (game_status == GAME_MODE_TITLE)
1570 HandleTitleScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1571 else if (game_status == GAME_MODE_MAIN)
1572 HandleMainMenu(0, 0, 0, 0, MB_MENU_CHOICE);
1573 else if (game_status == GAME_MODE_LEVELS)
1574 HandleChooseLevelSet(0, 0, 0, 0, MB_MENU_CHOICE);
1575 else if (game_status == GAME_MODE_LEVELNR)
1576 HandleChooseLevelNr(0, 0, 0, 0, MB_MENU_CHOICE);
1577 else if (game_status == GAME_MODE_SETUP)
1578 HandleSetupScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1579 else if (game_status == GAME_MODE_INFO)
1580 HandleInfoScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1581 else if (game_status == GAME_MODE_SCORES)
1582 HandleHallOfFame(0, 0, 0, 0, MB_MENU_CHOICE);
1586 if (game_status != GAME_MODE_MAIN)
1587 FadeSkipNextFadeIn();
1589 if (game_status == GAME_MODE_TITLE)
1590 HandleTitleScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1591 else if (game_status == GAME_MODE_LEVELS)
1592 HandleChooseLevelSet(0, 0, 0, 0, MB_MENU_LEAVE);
1593 else if (game_status == GAME_MODE_LEVELNR)
1594 HandleChooseLevelNr(0, 0, 0, 0, MB_MENU_LEAVE);
1595 else if (game_status == GAME_MODE_SETUP)
1596 HandleSetupScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1597 else if (game_status == GAME_MODE_INFO)
1598 HandleInfoScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1599 else if (game_status == GAME_MODE_SCORES)
1600 HandleHallOfFame(0, 0, 0, 0, MB_MENU_LEAVE);
1604 if (game_status == GAME_MODE_LEVELS)
1605 HandleChooseLevelSet(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1606 else if (game_status == GAME_MODE_LEVELNR)
1607 HandleChooseLevelNr(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1608 else if (game_status == GAME_MODE_SETUP)
1609 HandleSetupScreen(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1610 else if (game_status == GAME_MODE_INFO)
1611 HandleInfoScreen(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1612 else if (game_status == GAME_MODE_SCORES)
1613 HandleHallOfFame(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1616 case KSYM_Page_Down:
1617 if (game_status == GAME_MODE_LEVELS)
1618 HandleChooseLevelSet(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1619 else if (game_status == GAME_MODE_LEVELNR)
1620 HandleChooseLevelNr(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1621 else if (game_status == GAME_MODE_SETUP)
1622 HandleSetupScreen(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1623 else if (game_status == GAME_MODE_INFO)
1624 HandleInfoScreen(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1625 else if (game_status == GAME_MODE_SCORES)
1626 HandleHallOfFame(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1631 GameFrameDelay = (GameFrameDelay == 500 ? GAME_FRAME_DELAY : 500);
1635 setup.sp_show_border_elements = !setup.sp_show_border_elements;
1636 printf("Supaplex border elements %s\n",
1637 setup.sp_show_border_elements ? "enabled" : "disabled");
1646 case GAME_MODE_EDITOR:
1647 if (!anyTextGadgetActiveOrJustFinished || key == KSYM_Escape)
1648 HandleLevelEditorKeyInput(key);
1651 case GAME_MODE_PLAYING:
1656 RequestQuitGame(setup.ask_on_escape);
1674 if (GameFrameDelay == 500)
1675 GameFrameDelay = GAME_FRAME_DELAY;
1677 GameFrameDelay = 500;
1680 GameFrameDelay = (key - KSYM_0) * 10;
1681 printf("Game speed == %d%% (%d ms delay between two frames)\n",
1682 GAME_FRAME_DELAY * 100 / GameFrameDelay, GameFrameDelay);
1688 options.debug = FALSE;
1689 printf("debug mode disabled\n");
1693 options.debug = TRUE;
1694 printf("debug mode enabled\n");
1699 if (!global.fps_slowdown)
1701 global.fps_slowdown = TRUE;
1702 global.fps_slowdown_factor = 2;
1703 printf("fps slowdown enabled -- display only every 2nd frame\n");
1705 else if (global.fps_slowdown_factor == 2)
1707 global.fps_slowdown_factor = 4;
1708 printf("fps slowdown enabled -- display only every 4th frame\n");
1712 global.fps_slowdown = FALSE;
1713 global.fps_slowdown_factor = 1;
1714 printf("fps slowdown disabled\n");
1719 ScrollStepSize = TILEX / 8;
1720 printf("ScrollStepSize == %d (1/8)\n", ScrollStepSize);
1724 ScrollStepSize = TILEX / 4;
1725 printf("ScrollStepSize == %d (1/4)\n", ScrollStepSize);
1729 ScrollStepSize = TILEX / 2;
1730 printf("ScrollStepSize == %d (1/2)\n", ScrollStepSize);
1734 ScrollStepSize = TILEX;
1735 printf("ScrollStepSize == %d (1/1)\n", ScrollStepSize);
1739 printf("::: currently using game engine version %d\n",
1740 game.engine_version);
1751 if (key == KSYM_Escape)
1753 game_status = GAME_MODE_MAIN;
1761 void HandleNoEvent()
1763 if (button_status && game_status != GAME_MODE_PLAYING)
1765 HandleButton(0, 0, -button_status, button_status);
1776 #if defined(NETWORK_AVALIABLE)
1777 if (options.network)
1781 switch (game_status)
1783 case GAME_MODE_MAIN:
1784 DrawPreviewLevelAnimation();
1788 case GAME_MODE_LEVELS:
1789 case GAME_MODE_LEVELNR:
1790 case GAME_MODE_SETUP:
1791 case GAME_MODE_INFO:
1792 case GAME_MODE_SCORES:
1796 case GAME_MODE_EDITOR:
1797 HandleLevelEditorIdle();
1805 static int HandleJoystickForAllPlayers()
1810 for (i = 0; i < MAX_PLAYERS; i++)
1812 byte joy_action = 0;
1815 if (!setup.input[i].use_joystick)
1819 joy_action = Joystick(i);
1820 result |= joy_action;
1822 if (!setup.input[i].use_joystick)
1825 stored_player[i].action = joy_action;
1831 void HandleJoystick()
1833 int joystick = HandleJoystickForAllPlayers();
1834 int keyboard = key_joystick_mapping;
1835 int joy = (joystick | keyboard);
1836 int left = joy & JOY_LEFT;
1837 int right = joy & JOY_RIGHT;
1838 int up = joy & JOY_UP;
1839 int down = joy & JOY_DOWN;
1840 int button = joy & JOY_BUTTON;
1841 int newbutton = (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED);
1842 int dx = (left ? -1 : right ? 1 : 0);
1843 int dy = (up ? -1 : down ? 1 : 0);
1845 switch (game_status)
1847 case GAME_MODE_TITLE:
1848 case GAME_MODE_MAIN:
1849 case GAME_MODE_LEVELS:
1850 case GAME_MODE_LEVELNR:
1851 case GAME_MODE_SETUP:
1852 case GAME_MODE_INFO:
1854 static unsigned int joystickmove_delay = 0;
1856 if (joystick && !button &&
1857 !DelayReached(&joystickmove_delay, GADGET_FRAME_DELAY))
1858 newbutton = dx = dy = 0;
1860 if (game_status == GAME_MODE_TITLE)
1861 HandleTitleScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1862 else if (game_status == GAME_MODE_MAIN)
1863 HandleMainMenu(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1864 else if (game_status == GAME_MODE_LEVELS)
1865 HandleChooseLevelSet(0,0,dx,dy,newbutton?MB_MENU_CHOICE : MB_MENU_MARK);
1866 else if (game_status == GAME_MODE_LEVELNR)
1867 HandleChooseLevelNr(0,0,dx,dy,newbutton? MB_MENU_CHOICE : MB_MENU_MARK);
1868 else if (game_status == GAME_MODE_SETUP)
1869 HandleSetupScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1870 else if (game_status == GAME_MODE_INFO)
1871 HandleInfoScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1875 case GAME_MODE_SCORES:
1876 HandleHallOfFame(0, 0, dx, dy, !newbutton);
1880 case GAME_MODE_EDITOR:
1881 HandleLevelEditorIdle();
1885 case GAME_MODE_PLAYING:
1886 if (tape.playing || keyboard)
1887 newbutton = ((joy & JOY_BUTTON) != 0);
1890 if (newbutton && local_player->LevelSolved_GameEnd)
1892 if (newbutton && AllPlayersGone)