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) :
573 char *key_name = (key == setup.input[0].key.snap ? "SNAP" :
574 key == setup.input[0].key.drop ? "DROP" :
575 key == setup.input[0].key.up ? "UP" :
576 key == setup.input[0].key.down ? "DOWN" :
577 key == setup.input[0].key.left ? "LEFT" :
578 key == setup.input[0].key.right ? "RIGHT" : "(unknown)");
579 char *key_status_name = (key_status == KEY_RELEASED ? "KEY_RELEASED" :
582 Key key = (event->y < 1.0 / 3.0 ? setup.input[0].key.up :
583 event->y > 2.0 / 3.0 ? setup.input[0].key.down :
584 event->x < 1.0 / 3.0 ? setup.input[0].key.left :
585 event->x > 2.0 / 3.0 ? setup.input[0].key.right :
586 setup.input[0].key.snap);
590 Error(ERR_DEBUG, "::: key '%s' was '%s' [fingerId: %lld]",
591 getKeyNameFromKey(key), key_status_name, event->fingerId);
593 // check if we already know this touch event's finger id
594 for (i = 0; i < NUM_TOUCH_FINGERS; i++)
596 if (touch_info[i].touched &&
597 touch_info[i].finger_id == event->fingerId)
599 // Error(ERR_DEBUG, "MARK 1: %d", i);
605 if (i >= NUM_TOUCH_FINGERS)
607 if (key_status == KEY_PRESSED)
609 int oldest_pos = 0, oldest_counter = touch_info[0].counter;
611 // unknown finger id -- get new, empty slot, if available
612 for (i = 0; i < NUM_TOUCH_FINGERS; i++)
614 if (touch_info[i].counter < oldest_counter)
617 oldest_counter = touch_info[i].counter;
619 // Error(ERR_DEBUG, "MARK 2: %d", i);
622 if (!touch_info[i].touched)
624 // Error(ERR_DEBUG, "MARK 3: %d", i);
630 if (i >= NUM_TOUCH_FINGERS)
632 // all slots allocated -- use oldest slot
635 // Error(ERR_DEBUG, "MARK 4: %d", i);
640 // release of previously unknown key (should not happen)
642 if (key != KSYM_UNDEFINED)
644 HandleKey(key, KEY_RELEASED);
646 Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d] [1]",
647 getKeyNameFromKey(key), "KEY_RELEASED", i);
652 if (i < NUM_TOUCH_FINGERS)
654 if (key_status == KEY_PRESSED)
656 if (touch_info[i].key != key)
658 if (touch_info[i].key != KSYM_UNDEFINED)
660 HandleKey(touch_info[i].key, KEY_RELEASED);
662 Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d] [2]",
663 getKeyNameFromKey(touch_info[i].key), "KEY_RELEASED", i);
666 if (key != KSYM_UNDEFINED)
668 HandleKey(key, KEY_PRESSED);
670 Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d] [3]",
671 getKeyNameFromKey(key), "KEY_PRESSED", i);
675 touch_info[i].touched = TRUE;
676 touch_info[i].finger_id = event->fingerId;
677 touch_info[i].counter = Counter();
678 touch_info[i].key = key;
682 if (touch_info[i].key != KSYM_UNDEFINED)
684 HandleKey(touch_info[i].key, KEY_RELEASED);
686 Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d] [4]",
687 getKeyNameFromKey(touch_info[i].key), "KEY_RELEASED", i);
690 touch_info[i].touched = FALSE;
691 touch_info[i].finger_id = 0;
692 touch_info[i].counter = 0;
693 touch_info[i].key = 0;
699 Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d]",
700 key_name, key_status_name, i);
702 Error(ERR_DEBUG, "=> key == %d, key_status == %d [%d]", key, key_status, i);
709 if (event->type == EVENT_FINGERPRESS)
711 if (event_x > 1.0 / 3.0)
715 motion_id = event->fingerId;
720 motion_key_x = KSYM_UNDEFINED;
721 motion_key_y = KSYM_UNDEFINED;
723 Error(ERR_DEBUG, "---------- MOVE STARTED (WAIT) ----------");
729 button_id = event->fingerId;
734 button_key = setup.input[0].key.snap;
736 HandleKey(button_key, KEY_PRESSED);
738 Error(ERR_DEBUG, "---------- SNAP STARTED ----------");
741 else if (event->type == EVENT_FINGERRELEASE)
743 if (event->fingerId == motion_id)
747 if (motion_key_x != KSYM_UNDEFINED)
748 HandleKey(motion_key_x, KEY_RELEASED);
749 if (motion_key_y != KSYM_UNDEFINED)
750 HandleKey(motion_key_y, KEY_RELEASED);
752 motion_key_x = KSYM_UNDEFINED;
753 motion_key_y = KSYM_UNDEFINED;
755 Error(ERR_DEBUG, "---------- MOVE STOPPED ----------");
757 else if (event->fingerId == button_id)
761 if (button_key != KSYM_UNDEFINED)
762 HandleKey(button_key, KEY_RELEASED);
764 button_key = KSYM_UNDEFINED;
766 Error(ERR_DEBUG, "---------- SNAP STOPPED ----------");
769 else if (event->type == EVENT_FINGERMOTION)
771 if (event->fingerId == motion_id)
773 float distance_x = ABS(event_x - motion_x1);
774 float distance_y = ABS(event_y - motion_y1);
775 Key new_motion_key_x = (event_x < motion_x1 ? setup.input[0].key.left :
776 event_x > motion_x1 ? setup.input[0].key.right :
778 Key new_motion_key_y = (event_y < motion_y1 ? setup.input[0].key.up :
779 event_y > motion_y1 ? setup.input[0].key.down :
782 if (distance_x < trigger_distance / 2 ||
783 distance_x < distance_y)
784 new_motion_key_x = KSYM_UNDEFINED;
786 if (distance_y < trigger_distance / 2 ||
787 distance_y < distance_x)
788 new_motion_key_y = KSYM_UNDEFINED;
790 if (distance_x > trigger_distance ||
791 distance_y > trigger_distance)
793 if (new_motion_key_x != motion_key_x)
795 if (motion_key_x != KSYM_UNDEFINED)
796 HandleKey(motion_key_x, KEY_RELEASED);
797 if (new_motion_key_x != KSYM_UNDEFINED)
798 HandleKey(new_motion_key_x, KEY_PRESSED);
801 if (new_motion_key_y != motion_key_y)
803 if (motion_key_y != KSYM_UNDEFINED)
804 HandleKey(motion_key_y, KEY_RELEASED);
805 if (new_motion_key_y != KSYM_UNDEFINED)
806 HandleKey(new_motion_key_y, KEY_PRESSED);
812 motion_key_x = new_motion_key_x;
813 motion_key_y = new_motion_key_y;
815 Error(ERR_DEBUG, "---------- MOVE STARTED (MOVE) ----------");
818 else if (event->fingerId == button_id)
820 float distance_x = ABS(event_x - button_x1);
821 float distance_y = ABS(event_y - button_y1);
823 if (distance_x < trigger_distance / 2 &&
824 distance_y > trigger_distance)
826 if (button_key == setup.input[0].key.snap)
827 HandleKey(button_key, KEY_RELEASED);
832 button_key = setup.input[0].key.drop;
834 HandleKey(button_key, KEY_PRESSED);
836 Error(ERR_DEBUG, "---------- DROP STARTED ----------");
844 void HandleFingerEvent(FingerEvent *event)
847 static int num_events = 0;
853 Error(ERR_DEBUG, "FINGER EVENT: finger was %s, touch ID %lld, finger ID %lld, x/y %f/%f, dx/dy %f/%f, pressure %f",
854 event->type == EVENT_FINGERPRESS ? "pressed" :
855 event->type == EVENT_FINGERRELEASE ? "released" : "moved",
859 event->dx, event->dy,
865 int x = (int)(event->x * video.width);
866 int y = (int)(event->y * video.height);
867 int button = MB_LEFTBUTTON;
869 Error(ERR_DEBUG, "=> screen x/y %d/%d", x, y);
873 if (++num_events >= max_events)
879 if (event->type == EVENT_FINGERPRESS ||
880 event->type == EVENT_FINGERMOTION)
881 button_status = button;
883 button_status = MB_RELEASED;
885 int max_x = SX + SXSIZE;
886 int max_y = SY + SYSIZE;
890 if (game_status == GAME_MODE_PLAYING)
892 if (game_status == GAME_MODE_PLAYING &&
896 int key_status = (event->type == EVENT_FINGERRELEASE ? KEY_RELEASED :
899 Key key = (event->y < 1.0 / 3.0 ? setup.input[0].key.up :
900 event->y > 2.0 / 3.0 ? setup.input[0].key.down :
901 event->x < 1.0 / 3.0 ? setup.input[0].key.left :
902 event->x > 2.0 / 3.0 ? setup.input[0].key.right :
903 setup.input[0].key.drop);
905 Key key = (y < max_y / 3 ? setup.input[0].key.up :
906 y > 2 * max_y / 3 ? setup.input[0].key.down :
907 x < max_x / 3 ? setup.input[0].key.left :
908 x > 2 * max_x / 3 ? setup.input[0].key.right :
909 setup.input[0].key.drop);
912 Error(ERR_DEBUG, "=> key == %d, key_status == %d", key, key_status);
914 HandleKey(key, key_status);
919 Error(ERR_DEBUG, "::: button_status == %d, button == %d\n",
920 button_status, button);
922 HandleButton(x, y, button_status, button);
930 static boolean checkTextInputKeyModState()
932 // when playing, only handle raw key events and ignore text input
933 if (game_status == GAME_MODE_PLAYING)
936 return ((GetKeyModState() & KMOD_TextInput) != KMOD_None);
939 void HandleTextEvent(TextEvent *event)
941 char *text = event->text;
942 Key key = getKeyFromKeyName(text);
945 Error(ERR_DEBUG, "TEXT EVENT: text == '%s' [%d byte(s), '%c'/%d], resulting key == %d (%s) [%04x]",
948 text[0], (int)(text[0]),
950 getKeyNameFromKey(key),
954 // if (game_status != GAME_MODE_PLAYING && GetKeyModState() != KMOD_None)
956 if (game_status != GAME_MODE_PLAYING &&
957 (GetKeyModState() & KMOD_TextInput) != KMOD_None)
959 if (checkTextInputKeyModState())
961 HandleKey(key, KEY_PRESSED);
962 HandleKey(key, KEY_RELEASED);
967 void HandleKeyEvent(KeyEvent *event)
969 int key_status = (event->type == EVENT_KEYPRESS ? KEY_PRESSED : KEY_RELEASED);
970 boolean with_modifiers = (game_status == GAME_MODE_PLAYING ? FALSE : TRUE);
971 Key key = GetEventKey(event, with_modifiers);
972 Key keymod = (with_modifiers ? GetEventKey(event, FALSE) : key);
975 Error(ERR_DEBUG, "KEY EVENT: key was %s, keysym.scancode == %d, keysym.sym == %d, keymod = %d, GetKeyModState() = 0x%04x, resulting key == %d (%s)",
976 event->type == EVENT_KEYPRESS ? "pressed" : "released",
977 event->keysym.scancode,
982 getKeyNameFromKey(key));
986 if (key == KSYM_Menu)
987 Error(ERR_DEBUG, "menu key pressed");
988 else if (key == KSYM_Back)
989 Error(ERR_DEBUG, "back key pressed");
992 #if defined(PLATFORM_ANDROID)
993 // always map the "back" button to the "escape" key on Android devices
994 if (key == KSYM_Back)
998 HandleKeyModState(keymod, key_status);
1000 #if defined(TARGET_SDL2)
1002 // if (game_status == GAME_MODE_PLAYING || GetKeyModState() == KMOD_None)
1004 if (game_status == GAME_MODE_PLAYING ||
1005 (GetKeyModState() & KMOD_TextInput) == KMOD_None)
1007 if (!checkTextInputKeyModState())
1008 HandleKey(key, key_status);
1010 HandleKey(key, key_status);
1014 void HandleFocusEvent(FocusChangeEvent *event)
1016 static int old_joystick_status = -1;
1018 if (event->type == EVENT_FOCUSOUT)
1020 KeyboardAutoRepeatOn();
1021 old_joystick_status = joystick.status;
1022 joystick.status = JOYSTICK_NOT_AVAILABLE;
1024 ClearPlayerAction();
1026 else if (event->type == EVENT_FOCUSIN)
1028 /* When there are two Rocks'n'Diamonds windows which overlap and
1029 the player moves the pointer from one game window to the other,
1030 a 'FocusOut' event is generated for the window the pointer is
1031 leaving and a 'FocusIn' event is generated for the window the
1032 pointer is entering. In some cases, it can happen that the
1033 'FocusIn' event is handled by the one game process before the
1034 'FocusOut' event by the other game process. In this case the
1035 X11 environment would end up with activated keyboard auto repeat,
1036 because unfortunately this is a global setting and not (which
1037 would be far better) set for each X11 window individually.
1038 The effect would be keyboard auto repeat while playing the game
1039 (game_status == GAME_MODE_PLAYING), which is not desired.
1040 To avoid this special case, we just wait 1/10 second before
1041 processing the 'FocusIn' event.
1044 if (game_status == GAME_MODE_PLAYING)
1047 KeyboardAutoRepeatOffUnlessAutoplay();
1050 if (old_joystick_status != -1)
1051 joystick.status = old_joystick_status;
1055 void HandleClientMessageEvent(ClientMessageEvent *event)
1057 if (CheckCloseWindowEvent(event))
1061 void HandleWindowManagerEvent(Event *event)
1063 #if defined(TARGET_SDL)
1064 SDLHandleWindowManagerEvent(event);
1068 void HandleButton(int mx, int my, int button, int button_nr)
1070 static int old_mx = 0, old_my = 0;
1084 #if defined(PLATFORM_ANDROID)
1085 if (game_status != GAME_MODE_PLAYING &&
1086 HandleGadgets(mx, my, button))
1088 /* do not handle this button event anymore */
1089 mx = my = -32; /* force mouse event to be outside screen tiles */
1092 if (HandleGadgets(mx, my, button))
1094 /* do not handle this button event anymore */
1095 mx = my = -32; /* force mouse event to be outside screen tiles */
1099 /* do not use scroll wheel button events for anything other than gadgets */
1100 if (IS_WHEEL_BUTTON(button_nr))
1104 Error(ERR_DEBUG, "::: game_status == %d", game_status);
1107 switch (game_status)
1109 case GAME_MODE_TITLE:
1110 HandleTitleScreen(mx, my, 0, 0, button);
1113 case GAME_MODE_MAIN:
1114 HandleMainMenu(mx, my, 0, 0, button);
1117 case GAME_MODE_PSEUDO_TYPENAME:
1118 HandleTypeName(0, KSYM_Return);
1121 case GAME_MODE_LEVELS:
1122 HandleChooseLevelSet(mx, my, 0, 0, button);
1125 case GAME_MODE_LEVELNR:
1126 HandleChooseLevelNr(mx, my, 0, 0, button);
1129 case GAME_MODE_SCORES:
1130 HandleHallOfFame(0, 0, 0, 0, button);
1133 case GAME_MODE_EDITOR:
1134 HandleLevelEditorIdle();
1137 case GAME_MODE_INFO:
1138 HandleInfoScreen(mx, my, 0, 0, button);
1141 case GAME_MODE_SETUP:
1142 HandleSetupScreen(mx, my, 0, 0, button);
1145 case GAME_MODE_PLAYING:
1147 if (button == MB_PRESSED && !motion_status && IN_GFX_SCREEN(mx, my))
1148 DumpTile(LEVELX((mx - SX) / TILEX), LEVELY((my - SY) / TILEY));
1157 static boolean is_string_suffix(char *string, char *suffix)
1159 int string_len = strlen(string);
1160 int suffix_len = strlen(suffix);
1162 if (suffix_len > string_len)
1165 return (strEqual(&string[string_len - suffix_len], suffix));
1168 #define MAX_CHEAT_INPUT_LEN 32
1170 static void HandleKeysSpecial(Key key)
1172 static char cheat_input[2 * MAX_CHEAT_INPUT_LEN + 1] = "";
1173 char letter = getCharFromKey(key);
1174 int cheat_input_len = strlen(cheat_input);
1180 if (cheat_input_len >= 2 * MAX_CHEAT_INPUT_LEN)
1182 for (i = 0; i < MAX_CHEAT_INPUT_LEN + 1; i++)
1183 cheat_input[i] = cheat_input[MAX_CHEAT_INPUT_LEN + i];
1185 cheat_input_len = MAX_CHEAT_INPUT_LEN;
1188 cheat_input[cheat_input_len++] = letter;
1189 cheat_input[cheat_input_len] = '\0';
1192 Error(ERR_DEBUG, "SPECIAL KEY '%s' [%d]\n", cheat_input, cheat_input_len);
1195 if (game_status == GAME_MODE_MAIN)
1197 if (is_string_suffix(cheat_input, ":insert-solution-tape") ||
1198 is_string_suffix(cheat_input, ":ist"))
1200 InsertSolutionTape();
1202 else if (is_string_suffix(cheat_input, ":reload-graphics") ||
1203 is_string_suffix(cheat_input, ":rg"))
1205 ReloadCustomArtwork(1 << ARTWORK_TYPE_GRAPHICS);
1208 else if (is_string_suffix(cheat_input, ":reload-sounds") ||
1209 is_string_suffix(cheat_input, ":rs"))
1211 ReloadCustomArtwork(1 << ARTWORK_TYPE_SOUNDS);
1214 else if (is_string_suffix(cheat_input, ":reload-music") ||
1215 is_string_suffix(cheat_input, ":rm"))
1217 ReloadCustomArtwork(1 << ARTWORK_TYPE_MUSIC);
1220 else if (is_string_suffix(cheat_input, ":reload-artwork") ||
1221 is_string_suffix(cheat_input, ":ra"))
1223 ReloadCustomArtwork(1 << ARTWORK_TYPE_GRAPHICS |
1224 1 << ARTWORK_TYPE_SOUNDS |
1225 1 << ARTWORK_TYPE_MUSIC);
1228 else if (is_string_suffix(cheat_input, ":dump-level") ||
1229 is_string_suffix(cheat_input, ":dl"))
1233 else if (is_string_suffix(cheat_input, ":dump-tape") ||
1234 is_string_suffix(cheat_input, ":dt"))
1238 else if (is_string_suffix(cheat_input, ":save-native-level") ||
1239 is_string_suffix(cheat_input, ":snl"))
1241 SaveNativeLevel(&level);
1244 else if (game_status == GAME_MODE_PLAYING)
1247 if (is_string_suffix(cheat_input, ".q"))
1248 DEBUG_SetMaximumDynamite();
1251 else if (game_status == GAME_MODE_EDITOR)
1253 if (is_string_suffix(cheat_input, ":dump-brush") ||
1254 is_string_suffix(cheat_input, ":DB"))
1258 else if (is_string_suffix(cheat_input, ":DDB"))
1265 void HandleKey(Key key, int key_status)
1267 boolean anyTextGadgetActiveOrJustFinished = anyTextGadgetActive();
1268 static struct SetupKeyboardInfo ski;
1269 static struct SetupShortcutInfo ssi;
1278 { &ski.left, &ssi.snap_left, DEFAULT_KEY_LEFT, JOY_LEFT },
1279 { &ski.right, &ssi.snap_right, DEFAULT_KEY_RIGHT, JOY_RIGHT },
1280 { &ski.up, &ssi.snap_up, DEFAULT_KEY_UP, JOY_UP },
1281 { &ski.down, &ssi.snap_down, DEFAULT_KEY_DOWN, JOY_DOWN },
1282 { &ski.snap, NULL, DEFAULT_KEY_SNAP, JOY_BUTTON_SNAP },
1283 { &ski.drop, NULL, DEFAULT_KEY_DROP, JOY_BUTTON_DROP }
1288 if (game_status == GAME_MODE_PLAYING)
1290 /* only needed for single-step tape recording mode */
1291 static boolean clear_snap_button[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1292 static boolean clear_drop_button[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1293 static boolean element_snapped[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1294 static boolean element_dropped[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1297 for (pnr = 0; pnr < MAX_PLAYERS; pnr++)
1299 byte key_action = 0;
1301 if (setup.input[pnr].use_joystick)
1304 ski = setup.input[pnr].key;
1306 for (i = 0; i < NUM_PLAYER_ACTIONS; i++)
1307 if (key == *key_info[i].key_custom)
1308 key_action |= key_info[i].action;
1310 /* use combined snap+direction keys for the first player only */
1313 ssi = setup.shortcut;
1315 for (i = 0; i < NUM_DIRECTIONS; i++)
1316 if (key == *key_info[i].key_snap)
1317 key_action |= key_info[i].action | JOY_BUTTON_SNAP;
1320 /* clear delayed snap and drop actions in single step mode (see below) */
1321 if (tape.single_step)
1323 if (clear_snap_button[pnr])
1325 stored_player[pnr].action &= ~KEY_BUTTON_SNAP;
1326 clear_snap_button[pnr] = FALSE;
1329 if (clear_drop_button[pnr])
1331 stored_player[pnr].action &= ~KEY_BUTTON_DROP;
1332 clear_drop_button[pnr] = FALSE;
1336 if (key_status == KEY_PRESSED)
1337 stored_player[pnr].action |= key_action;
1339 stored_player[pnr].action &= ~key_action;
1341 if (tape.single_step && tape.recording && tape.pausing)
1343 if (key_status == KEY_PRESSED && key_action & KEY_MOTION)
1345 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1347 /* if snap key already pressed, don't snap when releasing (below) */
1348 if (stored_player[pnr].action & KEY_BUTTON_SNAP)
1349 element_snapped[pnr] = TRUE;
1351 /* if drop key already pressed, don't drop when releasing (below) */
1352 if (stored_player[pnr].action & KEY_BUTTON_DROP)
1353 element_dropped[pnr] = TRUE;
1356 else if (key_status == KEY_PRESSED && key_action & KEY_BUTTON_DROP)
1358 if (level.game_engine_type == GAME_ENGINE_TYPE_EM ||
1359 level.game_engine_type == GAME_ENGINE_TYPE_SP)
1362 printf("::: drop key pressed\n");
1365 if (level.game_engine_type == GAME_ENGINE_TYPE_SP &&
1366 getRedDiskReleaseFlag_SP() == 0)
1367 stored_player[pnr].action &= ~KEY_BUTTON_DROP;
1369 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1373 else if (key_status == KEY_RELEASED && key_action & KEY_BUTTON)
1375 if (key_action & KEY_BUTTON_SNAP)
1377 /* if snap key was released without moving (see above), snap now */
1378 if (!element_snapped[pnr])
1380 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1382 stored_player[pnr].action |= KEY_BUTTON_SNAP;
1384 /* clear delayed snap button on next event */
1385 clear_snap_button[pnr] = TRUE;
1388 element_snapped[pnr] = FALSE;
1392 if (key_action & KEY_BUTTON_DROP &&
1393 level.game_engine_type == GAME_ENGINE_TYPE_RND)
1395 /* if drop key was released without moving (see above), drop now */
1396 if (!element_dropped[pnr])
1398 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1400 if (level.game_engine_type != GAME_ENGINE_TYPE_SP ||
1401 getRedDiskReleaseFlag_SP() != 0)
1402 stored_player[pnr].action |= KEY_BUTTON_DROP;
1404 /* clear delayed drop button on next event */
1405 clear_drop_button[pnr] = TRUE;
1408 element_dropped[pnr] = FALSE;
1413 else if (tape.recording && tape.pausing)
1415 /* prevent key release events from un-pausing a paused game */
1416 if (key_status == KEY_PRESSED && key_action & KEY_ACTION)
1417 TapeTogglePause(TAPE_TOGGLE_MANUAL);
1423 for (i = 0; i < NUM_PLAYER_ACTIONS; i++)
1424 if (key == key_info[i].key_default)
1425 joy |= key_info[i].action;
1430 if (key_status == KEY_PRESSED)
1431 key_joystick_mapping |= joy;
1433 key_joystick_mapping &= ~joy;
1438 if (game_status != GAME_MODE_PLAYING)
1439 key_joystick_mapping = 0;
1441 if (key_status == KEY_RELEASED)
1444 if ((key == KSYM_Return || key == KSYM_KP_Enter) &&
1445 (GetKeyModState() & KMOD_Alt) && video.fullscreen_available)
1447 setup.fullscreen = !setup.fullscreen;
1450 printf("::: %d\n", setup.window_scaling_percent);
1453 ToggleFullscreenOrChangeWindowScalingIfNeeded();
1455 if (game_status == GAME_MODE_SETUP)
1456 RedrawSetupScreenAfterFullscreenToggle();
1461 if ((key == KSYM_minus || key == KSYM_plus || key == KSYM_0) &&
1462 (GetKeyModState() & KMOD_Alt) && video.window_scaling_available &&
1463 !video.fullscreen_enabled)
1466 setup.window_scaling_percent = STD_WINDOW_SCALING_PERCENT;
1468 setup.window_scaling_percent +=
1469 (key == KSYM_minus ? -1 : +1) * STEP_WINDOW_SCALING_PERCENT;
1471 if (setup.window_scaling_percent < MIN_WINDOW_SCALING_PERCENT)
1472 setup.window_scaling_percent = MIN_WINDOW_SCALING_PERCENT;
1473 else if (setup.window_scaling_percent > MAX_WINDOW_SCALING_PERCENT)
1474 setup.window_scaling_percent = MAX_WINDOW_SCALING_PERCENT;
1476 ToggleFullscreenOrChangeWindowScalingIfNeeded();
1478 if (game_status == GAME_MODE_SETUP)
1479 RedrawSetupScreenAfterFullscreenToggle();
1485 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd &&
1486 (key == KSYM_Return || key == setup.shortcut.toggle_pause))
1488 if (game_status == GAME_MODE_PLAYING && AllPlayersGone &&
1489 (key == KSYM_Return || key == setup.shortcut.toggle_pause))
1497 if (game_status == GAME_MODE_MAIN &&
1498 (key == setup.shortcut.toggle_pause || key == KSYM_space))
1500 StartGameActions(options.network, setup.autorecord, level.random_seed);
1505 if (game_status == GAME_MODE_MAIN || game_status == GAME_MODE_PLAYING)
1507 if (key == setup.shortcut.save_game)
1509 else if (key == setup.shortcut.load_game)
1511 else if (key == setup.shortcut.toggle_pause)
1512 TapeTogglePause(TAPE_TOGGLE_MANUAL);
1514 HandleTapeButtonKeys(key);
1515 HandleSoundButtonKeys(key);
1518 if (game_status == GAME_MODE_PLAYING && !network_playing)
1520 int centered_player_nr_next = -999;
1522 if (key == setup.shortcut.focus_player_all)
1523 centered_player_nr_next = -1;
1525 for (i = 0; i < MAX_PLAYERS; i++)
1526 if (key == setup.shortcut.focus_player[i])
1527 centered_player_nr_next = i;
1529 if (centered_player_nr_next != -999)
1531 game.centered_player_nr_next = centered_player_nr_next;
1532 game.set_centered_player = TRUE;
1536 tape.centered_player_nr_next = game.centered_player_nr_next;
1537 tape.set_centered_player = TRUE;
1542 HandleKeysSpecial(key);
1544 if (HandleGadgetsKeyInput(key))
1546 if (key != KSYM_Escape) /* always allow ESC key to be handled */
1547 key = KSYM_UNDEFINED;
1550 switch (game_status)
1552 case GAME_MODE_PSEUDO_TYPENAME:
1553 HandleTypeName(0, key);
1556 case GAME_MODE_TITLE:
1557 case GAME_MODE_MAIN:
1558 case GAME_MODE_LEVELS:
1559 case GAME_MODE_LEVELNR:
1560 case GAME_MODE_SETUP:
1561 case GAME_MODE_INFO:
1562 case GAME_MODE_SCORES:
1567 if (game_status == GAME_MODE_TITLE)
1568 HandleTitleScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1569 else if (game_status == GAME_MODE_MAIN)
1570 HandleMainMenu(0, 0, 0, 0, MB_MENU_CHOICE);
1571 else if (game_status == GAME_MODE_LEVELS)
1572 HandleChooseLevelSet(0, 0, 0, 0, MB_MENU_CHOICE);
1573 else if (game_status == GAME_MODE_LEVELNR)
1574 HandleChooseLevelNr(0, 0, 0, 0, MB_MENU_CHOICE);
1575 else if (game_status == GAME_MODE_SETUP)
1576 HandleSetupScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1577 else if (game_status == GAME_MODE_INFO)
1578 HandleInfoScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1579 else if (game_status == GAME_MODE_SCORES)
1580 HandleHallOfFame(0, 0, 0, 0, MB_MENU_CHOICE);
1584 if (game_status != GAME_MODE_MAIN)
1585 FadeSkipNextFadeIn();
1587 if (game_status == GAME_MODE_TITLE)
1588 HandleTitleScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1589 else if (game_status == GAME_MODE_LEVELS)
1590 HandleChooseLevelSet(0, 0, 0, 0, MB_MENU_LEAVE);
1591 else if (game_status == GAME_MODE_LEVELNR)
1592 HandleChooseLevelNr(0, 0, 0, 0, MB_MENU_LEAVE);
1593 else if (game_status == GAME_MODE_SETUP)
1594 HandleSetupScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1595 else if (game_status == GAME_MODE_INFO)
1596 HandleInfoScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1597 else if (game_status == GAME_MODE_SCORES)
1598 HandleHallOfFame(0, 0, 0, 0, MB_MENU_LEAVE);
1602 if (game_status == GAME_MODE_LEVELS)
1603 HandleChooseLevelSet(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1604 else if (game_status == GAME_MODE_LEVELNR)
1605 HandleChooseLevelNr(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1606 else if (game_status == GAME_MODE_SETUP)
1607 HandleSetupScreen(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1608 else if (game_status == GAME_MODE_INFO)
1609 HandleInfoScreen(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1610 else if (game_status == GAME_MODE_SCORES)
1611 HandleHallOfFame(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1614 case KSYM_Page_Down:
1615 if (game_status == GAME_MODE_LEVELS)
1616 HandleChooseLevelSet(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1617 else if (game_status == GAME_MODE_LEVELNR)
1618 HandleChooseLevelNr(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1619 else if (game_status == GAME_MODE_SETUP)
1620 HandleSetupScreen(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1621 else if (game_status == GAME_MODE_INFO)
1622 HandleInfoScreen(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1623 else if (game_status == GAME_MODE_SCORES)
1624 HandleHallOfFame(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1629 GameFrameDelay = (GameFrameDelay == 500 ? GAME_FRAME_DELAY : 500);
1633 setup.sp_show_border_elements = !setup.sp_show_border_elements;
1634 printf("Supaplex border elements %s\n",
1635 setup.sp_show_border_elements ? "enabled" : "disabled");
1644 case GAME_MODE_EDITOR:
1645 if (!anyTextGadgetActiveOrJustFinished || key == KSYM_Escape)
1646 HandleLevelEditorKeyInput(key);
1649 case GAME_MODE_PLAYING:
1654 RequestQuitGame(setup.ask_on_escape);
1672 if (GameFrameDelay == 500)
1673 GameFrameDelay = GAME_FRAME_DELAY;
1675 GameFrameDelay = 500;
1678 GameFrameDelay = (key - KSYM_0) * 10;
1679 printf("Game speed == %d%% (%d ms delay between two frames)\n",
1680 GAME_FRAME_DELAY * 100 / GameFrameDelay, GameFrameDelay);
1686 options.debug = FALSE;
1687 printf("debug mode disabled\n");
1691 options.debug = TRUE;
1692 printf("debug mode enabled\n");
1697 if (!global.fps_slowdown)
1699 global.fps_slowdown = TRUE;
1700 global.fps_slowdown_factor = 2;
1701 printf("fps slowdown enabled -- display only every 2nd frame\n");
1703 else if (global.fps_slowdown_factor == 2)
1705 global.fps_slowdown_factor = 4;
1706 printf("fps slowdown enabled -- display only every 4th frame\n");
1710 global.fps_slowdown = FALSE;
1711 global.fps_slowdown_factor = 1;
1712 printf("fps slowdown disabled\n");
1717 ScrollStepSize = TILEX / 8;
1718 printf("ScrollStepSize == %d (1/8)\n", ScrollStepSize);
1722 ScrollStepSize = TILEX / 4;
1723 printf("ScrollStepSize == %d (1/4)\n", ScrollStepSize);
1727 ScrollStepSize = TILEX / 2;
1728 printf("ScrollStepSize == %d (1/2)\n", ScrollStepSize);
1732 ScrollStepSize = TILEX;
1733 printf("ScrollStepSize == %d (1/1)\n", ScrollStepSize);
1737 printf("::: currently using game engine version %d\n",
1738 game.engine_version);
1749 if (key == KSYM_Escape)
1751 game_status = GAME_MODE_MAIN;
1759 void HandleNoEvent()
1761 if (button_status && game_status != GAME_MODE_PLAYING)
1763 HandleButton(0, 0, -button_status, button_status);
1774 #if defined(NETWORK_AVALIABLE)
1775 if (options.network)
1779 switch (game_status)
1781 case GAME_MODE_MAIN:
1782 DrawPreviewLevelAnimation();
1786 case GAME_MODE_LEVELS:
1787 case GAME_MODE_LEVELNR:
1788 case GAME_MODE_SETUP:
1789 case GAME_MODE_INFO:
1790 case GAME_MODE_SCORES:
1794 case GAME_MODE_EDITOR:
1795 HandleLevelEditorIdle();
1803 static int HandleJoystickForAllPlayers()
1808 for (i = 0; i < MAX_PLAYERS; i++)
1810 byte joy_action = 0;
1813 if (!setup.input[i].use_joystick)
1817 joy_action = Joystick(i);
1818 result |= joy_action;
1820 if (!setup.input[i].use_joystick)
1823 stored_player[i].action = joy_action;
1829 void HandleJoystick()
1831 int joystick = HandleJoystickForAllPlayers();
1832 int keyboard = key_joystick_mapping;
1833 int joy = (joystick | keyboard);
1834 int left = joy & JOY_LEFT;
1835 int right = joy & JOY_RIGHT;
1836 int up = joy & JOY_UP;
1837 int down = joy & JOY_DOWN;
1838 int button = joy & JOY_BUTTON;
1839 int newbutton = (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED);
1840 int dx = (left ? -1 : right ? 1 : 0);
1841 int dy = (up ? -1 : down ? 1 : 0);
1843 switch (game_status)
1845 case GAME_MODE_TITLE:
1846 case GAME_MODE_MAIN:
1847 case GAME_MODE_LEVELS:
1848 case GAME_MODE_LEVELNR:
1849 case GAME_MODE_SETUP:
1850 case GAME_MODE_INFO:
1852 static unsigned int joystickmove_delay = 0;
1854 if (joystick && !button &&
1855 !DelayReached(&joystickmove_delay, GADGET_FRAME_DELAY))
1856 newbutton = dx = dy = 0;
1858 if (game_status == GAME_MODE_TITLE)
1859 HandleTitleScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1860 else if (game_status == GAME_MODE_MAIN)
1861 HandleMainMenu(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1862 else if (game_status == GAME_MODE_LEVELS)
1863 HandleChooseLevelSet(0,0,dx,dy,newbutton?MB_MENU_CHOICE : MB_MENU_MARK);
1864 else if (game_status == GAME_MODE_LEVELNR)
1865 HandleChooseLevelNr(0,0,dx,dy,newbutton? MB_MENU_CHOICE : MB_MENU_MARK);
1866 else if (game_status == GAME_MODE_SETUP)
1867 HandleSetupScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1868 else if (game_status == GAME_MODE_INFO)
1869 HandleInfoScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1873 case GAME_MODE_SCORES:
1874 HandleHallOfFame(0, 0, dx, dy, !newbutton);
1878 case GAME_MODE_EDITOR:
1879 HandleLevelEditorIdle();
1883 case GAME_MODE_PLAYING:
1884 if (tape.playing || keyboard)
1885 newbutton = ((joy & JOY_BUTTON) != 0);
1888 if (newbutton && local_player->LevelSolved_GameEnd)
1890 if (newbutton && AllPlayersGone)