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 = -1;
543 static SDL_FingerID button_id = -1;
544 int move_trigger_distance_percent = 2; // percent of touchpad width/height
545 int drop_trigger_distance_percent = 5; // percent of touchpad width/height
546 float move_trigger_distance = (float)move_trigger_distance_percent / 100;
547 float drop_trigger_distance = (float)drop_trigger_distance_percent / 100;
548 float event_x = event->x;
549 float event_y = event->y;
553 Error(ERR_DEBUG, "FINGER EVENT: finger was %s, touch ID %lld, finger ID %lld, x/y %f/%f, dx/dy %f/%f, pressure %f",
554 event->type == EVENT_FINGERPRESS ? "pressed" :
555 event->type == EVENT_FINGERRELEASE ? "released" : "moved",
559 event->dx, event->dy,
564 if (game_status != GAME_MODE_PLAYING)
568 if (strEqual(setup.touch.control_type, TOUCH_CONTROL_VIRTUAL_BUTTONS))
570 boolean use_virtual_button_control = FALSE;
572 if (use_virtual_button_control)
575 int key_status = (event->type == EVENT_FINGERRELEASE ? KEY_RELEASED :
578 Key key = (event->x < 1.0 / 3.0 ?
579 (event->y < 1.0 / 2.0 ? setup.input[0].key.snap :
580 setup.input[0].key.drop) :
581 event->x > 2.0 / 3.0 ?
582 (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 < 5.0 / 6.0 ? setup.input[0].key.left :
585 setup.input[0].key.right) :
588 char *key_name = (key == setup.input[0].key.snap ? "SNAP" :
589 key == setup.input[0].key.drop ? "DROP" :
590 key == setup.input[0].key.up ? "UP" :
591 key == setup.input[0].key.down ? "DOWN" :
592 key == setup.input[0].key.left ? "LEFT" :
593 key == setup.input[0].key.right ? "RIGHT" : "(unknown)");
595 char *key_status_name = (key_status == KEY_RELEASED ? "KEY_RELEASED" :
598 Key key = (event->y < 1.0 / 3.0 ? setup.input[0].key.up :
599 event->y > 2.0 / 3.0 ? setup.input[0].key.down :
600 event->x < 1.0 / 3.0 ? setup.input[0].key.left :
601 event->x > 2.0 / 3.0 ? setup.input[0].key.right :
602 setup.input[0].key.snap);
606 Error(ERR_DEBUG, "::: key '%s' was '%s' [fingerId: %lld]",
607 getKeyNameFromKey(key), key_status_name, event->fingerId);
609 // check if we already know this touch event's finger id
610 for (i = 0; i < NUM_TOUCH_FINGERS; i++)
612 if (touch_info[i].touched &&
613 touch_info[i].finger_id == event->fingerId)
615 // Error(ERR_DEBUG, "MARK 1: %d", i);
621 if (i >= NUM_TOUCH_FINGERS)
623 if (key_status == KEY_PRESSED)
625 int oldest_pos = 0, oldest_counter = touch_info[0].counter;
627 // unknown finger id -- get new, empty slot, if available
628 for (i = 0; i < NUM_TOUCH_FINGERS; i++)
630 if (touch_info[i].counter < oldest_counter)
633 oldest_counter = touch_info[i].counter;
635 // Error(ERR_DEBUG, "MARK 2: %d", i);
638 if (!touch_info[i].touched)
640 // Error(ERR_DEBUG, "MARK 3: %d", i);
646 if (i >= NUM_TOUCH_FINGERS)
648 // all slots allocated -- use oldest slot
651 // Error(ERR_DEBUG, "MARK 4: %d", i);
656 // release of previously unknown key (should not happen)
658 if (key != KSYM_UNDEFINED)
660 HandleKey(key, KEY_RELEASED);
662 Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d] [1]",
663 getKeyNameFromKey(key), "KEY_RELEASED", i);
668 if (i < NUM_TOUCH_FINGERS)
670 if (key_status == KEY_PRESSED)
672 if (touch_info[i].key != key)
674 if (touch_info[i].key != KSYM_UNDEFINED)
676 HandleKey(touch_info[i].key, KEY_RELEASED);
678 Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d] [2]",
679 getKeyNameFromKey(touch_info[i].key), "KEY_RELEASED", i);
682 if (key != KSYM_UNDEFINED)
684 HandleKey(key, KEY_PRESSED);
686 Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d] [3]",
687 getKeyNameFromKey(key), "KEY_PRESSED", i);
691 touch_info[i].touched = TRUE;
692 touch_info[i].finger_id = event->fingerId;
693 touch_info[i].counter = Counter();
694 touch_info[i].key = key;
698 if (touch_info[i].key != KSYM_UNDEFINED)
700 HandleKey(touch_info[i].key, KEY_RELEASED);
702 Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d] [4]",
703 getKeyNameFromKey(touch_info[i].key), "KEY_RELEASED", i);
706 touch_info[i].touched = FALSE;
707 touch_info[i].finger_id = 0;
708 touch_info[i].counter = 0;
709 touch_info[i].key = 0;
715 Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d]",
716 key_name, key_status_name, i);
718 Error(ERR_DEBUG, "=> key == %d, key_status == %d [%d]", key, key_status, i);
725 // use touch direction control
727 if (event->type == EVENT_FINGERPRESS)
729 if (event_x > 1.0 / 3.0)
733 motion_id = event->fingerId;
738 motion_key_x = KSYM_UNDEFINED;
739 motion_key_y = KSYM_UNDEFINED;
741 Error(ERR_DEBUG, "---------- MOVE STARTED (WAIT) ----------");
747 button_id = event->fingerId;
752 button_key = setup.input[0].key.snap;
754 HandleKey(button_key, KEY_PRESSED);
756 Error(ERR_DEBUG, "---------- SNAP STARTED ----------");
759 else if (event->type == EVENT_FINGERRELEASE)
761 if (event->fingerId == motion_id)
765 if (motion_key_x != KSYM_UNDEFINED)
766 HandleKey(motion_key_x, KEY_RELEASED);
767 if (motion_key_y != KSYM_UNDEFINED)
768 HandleKey(motion_key_y, KEY_RELEASED);
770 motion_key_x = KSYM_UNDEFINED;
771 motion_key_y = KSYM_UNDEFINED;
773 Error(ERR_DEBUG, "---------- MOVE STOPPED ----------");
775 else if (event->fingerId == button_id)
779 if (button_key != KSYM_UNDEFINED)
780 HandleKey(button_key, KEY_RELEASED);
782 button_key = KSYM_UNDEFINED;
784 Error(ERR_DEBUG, "---------- SNAP STOPPED ----------");
787 else if (event->type == EVENT_FINGERMOTION)
789 if (event->fingerId == motion_id)
791 float distance_x = ABS(event_x - motion_x1);
792 float distance_y = ABS(event_y - motion_y1);
793 Key new_motion_key_x = (event_x < motion_x1 ? setup.input[0].key.left :
794 event_x > motion_x1 ? setup.input[0].key.right :
796 Key new_motion_key_y = (event_y < motion_y1 ? setup.input[0].key.up :
797 event_y > motion_y1 ? setup.input[0].key.down :
800 if (distance_x < move_trigger_distance / 2 ||
801 distance_x < distance_y)
802 new_motion_key_x = KSYM_UNDEFINED;
804 if (distance_y < move_trigger_distance / 2 ||
805 distance_y < distance_x)
806 new_motion_key_y = KSYM_UNDEFINED;
808 if (distance_x > move_trigger_distance ||
809 distance_y > move_trigger_distance)
811 if (new_motion_key_x != motion_key_x)
813 if (motion_key_x != KSYM_UNDEFINED)
814 HandleKey(motion_key_x, KEY_RELEASED);
815 if (new_motion_key_x != KSYM_UNDEFINED)
816 HandleKey(new_motion_key_x, KEY_PRESSED);
819 if (new_motion_key_y != motion_key_y)
821 if (motion_key_y != KSYM_UNDEFINED)
822 HandleKey(motion_key_y, KEY_RELEASED);
823 if (new_motion_key_y != KSYM_UNDEFINED)
824 HandleKey(new_motion_key_y, KEY_PRESSED);
830 motion_key_x = new_motion_key_x;
831 motion_key_y = new_motion_key_y;
833 Error(ERR_DEBUG, "---------- MOVE STARTED (MOVE) ----------");
836 else if (event->fingerId == button_id)
838 float distance_x = ABS(event_x - button_x1);
839 float distance_y = ABS(event_y - button_y1);
841 if (distance_x < drop_trigger_distance / 2 &&
842 distance_y > drop_trigger_distance)
844 if (button_key == setup.input[0].key.snap)
845 HandleKey(button_key, KEY_RELEASED);
850 button_key = setup.input[0].key.drop;
852 HandleKey(button_key, KEY_PRESSED);
854 Error(ERR_DEBUG, "---------- DROP STARTED ----------");
862 void HandleFingerEvent(FingerEvent *event)
865 static int num_events = 0;
871 Error(ERR_DEBUG, "FINGER EVENT: finger was %s, touch ID %lld, finger ID %lld, x/y %f/%f, dx/dy %f/%f, pressure %f",
872 event->type == EVENT_FINGERPRESS ? "pressed" :
873 event->type == EVENT_FINGERRELEASE ? "released" : "moved",
877 event->dx, event->dy,
883 int x = (int)(event->x * video.width);
884 int y = (int)(event->y * video.height);
885 int button = MB_LEFTBUTTON;
887 Error(ERR_DEBUG, "=> screen x/y %d/%d", x, y);
891 if (++num_events >= max_events)
897 if (event->type == EVENT_FINGERPRESS ||
898 event->type == EVENT_FINGERMOTION)
899 button_status = button;
901 button_status = MB_RELEASED;
903 int max_x = SX + SXSIZE;
904 int max_y = SY + SYSIZE;
908 if (game_status == GAME_MODE_PLAYING)
910 if (game_status == GAME_MODE_PLAYING &&
914 int key_status = (event->type == EVENT_FINGERRELEASE ? KEY_RELEASED :
917 Key key = (event->y < 1.0 / 3.0 ? setup.input[0].key.up :
918 event->y > 2.0 / 3.0 ? setup.input[0].key.down :
919 event->x < 1.0 / 3.0 ? setup.input[0].key.left :
920 event->x > 2.0 / 3.0 ? setup.input[0].key.right :
921 setup.input[0].key.drop);
923 Key key = (y < max_y / 3 ? setup.input[0].key.up :
924 y > 2 * max_y / 3 ? setup.input[0].key.down :
925 x < max_x / 3 ? setup.input[0].key.left :
926 x > 2 * max_x / 3 ? setup.input[0].key.right :
927 setup.input[0].key.drop);
930 Error(ERR_DEBUG, "=> key == %d, key_status == %d", key, key_status);
932 HandleKey(key, key_status);
937 Error(ERR_DEBUG, "::: button_status == %d, button == %d\n",
938 button_status, button);
940 HandleButton(x, y, button_status, button);
948 static boolean checkTextInputKeyModState()
950 // when playing, only handle raw key events and ignore text input
951 if (game_status == GAME_MODE_PLAYING)
954 return ((GetKeyModState() & KMOD_TextInput) != KMOD_None);
957 void HandleTextEvent(TextEvent *event)
959 char *text = event->text;
960 Key key = getKeyFromKeyName(text);
963 Error(ERR_DEBUG, "TEXT EVENT: text == '%s' [%d byte(s), '%c'/%d], resulting key == %d (%s) [%04x]",
966 text[0], (int)(text[0]),
968 getKeyNameFromKey(key),
972 // if (game_status != GAME_MODE_PLAYING && GetKeyModState() != KMOD_None)
974 if (game_status != GAME_MODE_PLAYING &&
975 (GetKeyModState() & KMOD_TextInput) != KMOD_None)
977 if (checkTextInputKeyModState())
979 HandleKey(key, KEY_PRESSED);
980 HandleKey(key, KEY_RELEASED);
985 void HandleKeyEvent(KeyEvent *event)
987 int key_status = (event->type == EVENT_KEYPRESS ? KEY_PRESSED : KEY_RELEASED);
988 boolean with_modifiers = (game_status == GAME_MODE_PLAYING ? FALSE : TRUE);
989 Key key = GetEventKey(event, with_modifiers);
990 Key keymod = (with_modifiers ? GetEventKey(event, FALSE) : key);
993 Error(ERR_DEBUG, "KEY EVENT: key was %s, keysym.scancode == %d, keysym.sym == %d, keymod = %d, GetKeyModState() = 0x%04x, resulting key == %d (%s)",
994 event->type == EVENT_KEYPRESS ? "pressed" : "released",
995 event->keysym.scancode,
1000 getKeyNameFromKey(key));
1004 if (key == KSYM_Menu)
1005 Error(ERR_DEBUG, "menu key pressed");
1006 else if (key == KSYM_Back)
1007 Error(ERR_DEBUG, "back key pressed");
1010 #if defined(PLATFORM_ANDROID)
1011 // always map the "back" button to the "escape" key on Android devices
1012 if (key == KSYM_Back)
1016 HandleKeyModState(keymod, key_status);
1018 #if defined(TARGET_SDL2)
1020 // if (game_status == GAME_MODE_PLAYING || GetKeyModState() == KMOD_None)
1022 if (game_status == GAME_MODE_PLAYING ||
1023 (GetKeyModState() & KMOD_TextInput) == KMOD_None)
1025 if (!checkTextInputKeyModState())
1026 HandleKey(key, key_status);
1028 HandleKey(key, key_status);
1032 void HandleFocusEvent(FocusChangeEvent *event)
1034 static int old_joystick_status = -1;
1036 if (event->type == EVENT_FOCUSOUT)
1038 KeyboardAutoRepeatOn();
1039 old_joystick_status = joystick.status;
1040 joystick.status = JOYSTICK_NOT_AVAILABLE;
1042 ClearPlayerAction();
1044 else if (event->type == EVENT_FOCUSIN)
1046 /* When there are two Rocks'n'Diamonds windows which overlap and
1047 the player moves the pointer from one game window to the other,
1048 a 'FocusOut' event is generated for the window the pointer is
1049 leaving and a 'FocusIn' event is generated for the window the
1050 pointer is entering. In some cases, it can happen that the
1051 'FocusIn' event is handled by the one game process before the
1052 'FocusOut' event by the other game process. In this case the
1053 X11 environment would end up with activated keyboard auto repeat,
1054 because unfortunately this is a global setting and not (which
1055 would be far better) set for each X11 window individually.
1056 The effect would be keyboard auto repeat while playing the game
1057 (game_status == GAME_MODE_PLAYING), which is not desired.
1058 To avoid this special case, we just wait 1/10 second before
1059 processing the 'FocusIn' event.
1062 if (game_status == GAME_MODE_PLAYING)
1065 KeyboardAutoRepeatOffUnlessAutoplay();
1068 if (old_joystick_status != -1)
1069 joystick.status = old_joystick_status;
1073 void HandleClientMessageEvent(ClientMessageEvent *event)
1075 if (CheckCloseWindowEvent(event))
1079 void HandleWindowManagerEvent(Event *event)
1081 #if defined(TARGET_SDL)
1082 SDLHandleWindowManagerEvent(event);
1086 void HandleButton(int mx, int my, int button, int button_nr)
1088 static int old_mx = 0, old_my = 0;
1102 #if defined(PLATFORM_ANDROID)
1103 if (game_status != GAME_MODE_PLAYING &&
1104 HandleGadgets(mx, my, button))
1106 /* do not handle this button event anymore */
1107 mx = my = -32; /* force mouse event to be outside screen tiles */
1110 if (HandleGadgets(mx, my, button))
1112 /* do not handle this button event anymore */
1113 mx = my = -32; /* force mouse event to be outside screen tiles */
1117 /* do not use scroll wheel button events for anything other than gadgets */
1118 if (IS_WHEEL_BUTTON(button_nr))
1122 Error(ERR_DEBUG, "::: game_status == %d", game_status);
1125 switch (game_status)
1127 case GAME_MODE_TITLE:
1128 HandleTitleScreen(mx, my, 0, 0, button);
1131 case GAME_MODE_MAIN:
1132 HandleMainMenu(mx, my, 0, 0, button);
1135 case GAME_MODE_PSEUDO_TYPENAME:
1136 HandleTypeName(0, KSYM_Return);
1139 case GAME_MODE_LEVELS:
1140 HandleChooseLevelSet(mx, my, 0, 0, button);
1143 case GAME_MODE_LEVELNR:
1144 HandleChooseLevelNr(mx, my, 0, 0, button);
1147 case GAME_MODE_SCORES:
1148 HandleHallOfFame(0, 0, 0, 0, button);
1151 case GAME_MODE_EDITOR:
1152 HandleLevelEditorIdle();
1155 case GAME_MODE_INFO:
1156 HandleInfoScreen(mx, my, 0, 0, button);
1159 case GAME_MODE_SETUP:
1160 HandleSetupScreen(mx, my, 0, 0, button);
1163 case GAME_MODE_PLAYING:
1165 if (button == MB_PRESSED && !motion_status && IN_GFX_FIELD_PLAY(mx, my))
1166 DumpTile(LEVELX((mx - SX) / TILEX), LEVELY((my - SY) / TILEY));
1175 static boolean is_string_suffix(char *string, char *suffix)
1177 int string_len = strlen(string);
1178 int suffix_len = strlen(suffix);
1180 if (suffix_len > string_len)
1183 return (strEqual(&string[string_len - suffix_len], suffix));
1186 #define MAX_CHEAT_INPUT_LEN 32
1188 static void HandleKeysSpecial(Key key)
1190 static char cheat_input[2 * MAX_CHEAT_INPUT_LEN + 1] = "";
1191 char letter = getCharFromKey(key);
1192 int cheat_input_len = strlen(cheat_input);
1198 if (cheat_input_len >= 2 * MAX_CHEAT_INPUT_LEN)
1200 for (i = 0; i < MAX_CHEAT_INPUT_LEN + 1; i++)
1201 cheat_input[i] = cheat_input[MAX_CHEAT_INPUT_LEN + i];
1203 cheat_input_len = MAX_CHEAT_INPUT_LEN;
1206 cheat_input[cheat_input_len++] = letter;
1207 cheat_input[cheat_input_len] = '\0';
1210 Error(ERR_DEBUG, "SPECIAL KEY '%s' [%d]\n", cheat_input, cheat_input_len);
1213 if (game_status == GAME_MODE_MAIN)
1215 if (is_string_suffix(cheat_input, ":insert-solution-tape") ||
1216 is_string_suffix(cheat_input, ":ist"))
1218 InsertSolutionTape();
1220 else if (is_string_suffix(cheat_input, ":reload-graphics") ||
1221 is_string_suffix(cheat_input, ":rg"))
1223 ReloadCustomArtwork(1 << ARTWORK_TYPE_GRAPHICS);
1226 else if (is_string_suffix(cheat_input, ":reload-sounds") ||
1227 is_string_suffix(cheat_input, ":rs"))
1229 ReloadCustomArtwork(1 << ARTWORK_TYPE_SOUNDS);
1232 else if (is_string_suffix(cheat_input, ":reload-music") ||
1233 is_string_suffix(cheat_input, ":rm"))
1235 ReloadCustomArtwork(1 << ARTWORK_TYPE_MUSIC);
1238 else if (is_string_suffix(cheat_input, ":reload-artwork") ||
1239 is_string_suffix(cheat_input, ":ra"))
1241 ReloadCustomArtwork(1 << ARTWORK_TYPE_GRAPHICS |
1242 1 << ARTWORK_TYPE_SOUNDS |
1243 1 << ARTWORK_TYPE_MUSIC);
1246 else if (is_string_suffix(cheat_input, ":dump-level") ||
1247 is_string_suffix(cheat_input, ":dl"))
1251 else if (is_string_suffix(cheat_input, ":dump-tape") ||
1252 is_string_suffix(cheat_input, ":dt"))
1256 else if (is_string_suffix(cheat_input, ":fix-tape") ||
1257 is_string_suffix(cheat_input, ":ft"))
1259 /* fix single-player tapes that contain player input for more than one
1260 player (due to a bug in 3.3.1.2 and earlier versions), which results
1261 in playing levels with more than one player in multi-player mode,
1262 even though the tape was originally recorded in single-player mode */
1264 /* remove player input actions for all players but the first one */
1265 for (i = 1; i < MAX_PLAYERS; i++)
1266 tape.player_participates[i] = FALSE;
1268 tape.changed = TRUE;
1270 else if (is_string_suffix(cheat_input, ":save-native-level") ||
1271 is_string_suffix(cheat_input, ":snl"))
1273 SaveNativeLevel(&level);
1276 else if (game_status == GAME_MODE_PLAYING)
1279 if (is_string_suffix(cheat_input, ".q"))
1280 DEBUG_SetMaximumDynamite();
1283 else if (game_status == GAME_MODE_EDITOR)
1285 if (is_string_suffix(cheat_input, ":dump-brush") ||
1286 is_string_suffix(cheat_input, ":DB"))
1290 else if (is_string_suffix(cheat_input, ":DDB"))
1297 void HandleKey(Key key, int key_status)
1299 boolean anyTextGadgetActiveOrJustFinished = anyTextGadgetActive();
1300 static struct SetupKeyboardInfo ski;
1301 static struct SetupShortcutInfo ssi;
1310 { &ski.left, &ssi.snap_left, DEFAULT_KEY_LEFT, JOY_LEFT },
1311 { &ski.right, &ssi.snap_right, DEFAULT_KEY_RIGHT, JOY_RIGHT },
1312 { &ski.up, &ssi.snap_up, DEFAULT_KEY_UP, JOY_UP },
1313 { &ski.down, &ssi.snap_down, DEFAULT_KEY_DOWN, JOY_DOWN },
1314 { &ski.snap, NULL, DEFAULT_KEY_SNAP, JOY_BUTTON_SNAP },
1315 { &ski.drop, NULL, DEFAULT_KEY_DROP, JOY_BUTTON_DROP }
1320 if (game_status == GAME_MODE_PLAYING)
1322 /* only needed for single-step tape recording mode */
1323 static boolean clear_snap_button[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1324 static boolean clear_drop_button[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1325 static boolean element_snapped[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1326 static boolean element_dropped[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1329 for (pnr = 0; pnr < MAX_PLAYERS; pnr++)
1331 byte key_action = 0;
1333 if (setup.input[pnr].use_joystick)
1336 ski = setup.input[pnr].key;
1338 for (i = 0; i < NUM_PLAYER_ACTIONS; i++)
1339 if (key == *key_info[i].key_custom)
1340 key_action |= key_info[i].action;
1342 /* use combined snap+direction keys for the first player only */
1345 ssi = setup.shortcut;
1347 for (i = 0; i < NUM_DIRECTIONS; i++)
1348 if (key == *key_info[i].key_snap)
1349 key_action |= key_info[i].action | JOY_BUTTON_SNAP;
1352 /* clear delayed snap and drop actions in single step mode (see below) */
1353 if (tape.single_step)
1355 if (clear_snap_button[pnr])
1357 stored_player[pnr].action &= ~KEY_BUTTON_SNAP;
1358 clear_snap_button[pnr] = FALSE;
1361 if (clear_drop_button[pnr])
1363 stored_player[pnr].action &= ~KEY_BUTTON_DROP;
1364 clear_drop_button[pnr] = FALSE;
1368 if (key_status == KEY_PRESSED)
1369 stored_player[pnr].action |= key_action;
1371 stored_player[pnr].action &= ~key_action;
1373 if (tape.single_step && tape.recording && tape.pausing)
1375 if (key_status == KEY_PRESSED && key_action & KEY_MOTION)
1377 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1379 /* if snap key already pressed, don't snap when releasing (below) */
1380 if (stored_player[pnr].action & KEY_BUTTON_SNAP)
1381 element_snapped[pnr] = TRUE;
1383 /* if drop key already pressed, don't drop when releasing (below) */
1384 if (stored_player[pnr].action & KEY_BUTTON_DROP)
1385 element_dropped[pnr] = TRUE;
1388 else if (key_status == KEY_PRESSED && key_action & KEY_BUTTON_DROP)
1390 if (level.game_engine_type == GAME_ENGINE_TYPE_EM ||
1391 level.game_engine_type == GAME_ENGINE_TYPE_SP)
1394 printf("::: drop key pressed\n");
1397 if (level.game_engine_type == GAME_ENGINE_TYPE_SP &&
1398 getRedDiskReleaseFlag_SP() == 0)
1399 stored_player[pnr].action &= ~KEY_BUTTON_DROP;
1401 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1405 else if (key_status == KEY_RELEASED && key_action & KEY_BUTTON)
1407 if (key_action & KEY_BUTTON_SNAP)
1409 /* if snap key was released without moving (see above), snap now */
1410 if (!element_snapped[pnr])
1412 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1414 stored_player[pnr].action |= KEY_BUTTON_SNAP;
1416 /* clear delayed snap button on next event */
1417 clear_snap_button[pnr] = TRUE;
1420 element_snapped[pnr] = FALSE;
1424 if (key_action & KEY_BUTTON_DROP &&
1425 level.game_engine_type == GAME_ENGINE_TYPE_RND)
1427 /* if drop key was released without moving (see above), drop now */
1428 if (!element_dropped[pnr])
1430 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1432 if (level.game_engine_type != GAME_ENGINE_TYPE_SP ||
1433 getRedDiskReleaseFlag_SP() != 0)
1434 stored_player[pnr].action |= KEY_BUTTON_DROP;
1436 /* clear delayed drop button on next event */
1437 clear_drop_button[pnr] = TRUE;
1440 element_dropped[pnr] = FALSE;
1445 else if (tape.recording && tape.pausing)
1447 /* prevent key release events from un-pausing a paused game */
1448 if (key_status == KEY_PRESSED && key_action & KEY_ACTION)
1449 TapeTogglePause(TAPE_TOGGLE_MANUAL);
1455 for (i = 0; i < NUM_PLAYER_ACTIONS; i++)
1456 if (key == key_info[i].key_default)
1457 joy |= key_info[i].action;
1462 if (key_status == KEY_PRESSED)
1463 key_joystick_mapping |= joy;
1465 key_joystick_mapping &= ~joy;
1470 if (game_status != GAME_MODE_PLAYING)
1471 key_joystick_mapping = 0;
1473 if (key_status == KEY_RELEASED)
1476 if ((key == KSYM_Return || key == KSYM_KP_Enter) &&
1477 (GetKeyModState() & KMOD_Alt) && video.fullscreen_available)
1479 setup.fullscreen = !setup.fullscreen;
1482 printf("::: %d\n", setup.window_scaling_percent);
1485 ToggleFullscreenOrChangeWindowScalingIfNeeded();
1487 if (game_status == GAME_MODE_SETUP)
1488 RedrawSetupScreenAfterFullscreenToggle();
1493 if ((key == KSYM_minus || key == KSYM_plus || key == KSYM_0) &&
1494 (GetKeyModState() & KMOD_Alt) && video.window_scaling_available &&
1495 !video.fullscreen_enabled)
1498 setup.window_scaling_percent = STD_WINDOW_SCALING_PERCENT;
1500 setup.window_scaling_percent +=
1501 (key == KSYM_minus ? -1 : +1) * STEP_WINDOW_SCALING_PERCENT;
1503 if (setup.window_scaling_percent < MIN_WINDOW_SCALING_PERCENT)
1504 setup.window_scaling_percent = MIN_WINDOW_SCALING_PERCENT;
1505 else if (setup.window_scaling_percent > MAX_WINDOW_SCALING_PERCENT)
1506 setup.window_scaling_percent = MAX_WINDOW_SCALING_PERCENT;
1508 ToggleFullscreenOrChangeWindowScalingIfNeeded();
1510 if (game_status == GAME_MODE_SETUP)
1511 RedrawSetupScreenAfterFullscreenToggle();
1517 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd &&
1518 (key == KSYM_Return || key == setup.shortcut.toggle_pause))
1520 if (game_status == GAME_MODE_PLAYING && AllPlayersGone &&
1521 (key == KSYM_Return || key == setup.shortcut.toggle_pause))
1529 if (game_status == GAME_MODE_MAIN &&
1530 (key == setup.shortcut.toggle_pause || key == KSYM_space))
1532 StartGameActions(options.network, setup.autorecord, level.random_seed);
1537 if (game_status == GAME_MODE_MAIN || game_status == GAME_MODE_PLAYING)
1539 if (key == setup.shortcut.save_game)
1541 else if (key == setup.shortcut.load_game)
1543 else if (key == setup.shortcut.toggle_pause)
1544 TapeTogglePause(TAPE_TOGGLE_MANUAL);
1546 HandleTapeButtonKeys(key);
1547 HandleSoundButtonKeys(key);
1550 if (game_status == GAME_MODE_PLAYING && !network_playing)
1552 int centered_player_nr_next = -999;
1554 if (key == setup.shortcut.focus_player_all)
1555 centered_player_nr_next = -1;
1557 for (i = 0; i < MAX_PLAYERS; i++)
1558 if (key == setup.shortcut.focus_player[i])
1559 centered_player_nr_next = i;
1561 if (centered_player_nr_next != -999)
1563 game.centered_player_nr_next = centered_player_nr_next;
1564 game.set_centered_player = TRUE;
1568 tape.centered_player_nr_next = game.centered_player_nr_next;
1569 tape.set_centered_player = TRUE;
1574 HandleKeysSpecial(key);
1576 if (HandleGadgetsKeyInput(key))
1578 if (key != KSYM_Escape) /* always allow ESC key to be handled */
1579 key = KSYM_UNDEFINED;
1582 switch (game_status)
1584 case GAME_MODE_PSEUDO_TYPENAME:
1585 HandleTypeName(0, key);
1588 case GAME_MODE_TITLE:
1589 case GAME_MODE_MAIN:
1590 case GAME_MODE_LEVELS:
1591 case GAME_MODE_LEVELNR:
1592 case GAME_MODE_SETUP:
1593 case GAME_MODE_INFO:
1594 case GAME_MODE_SCORES:
1599 if (game_status == GAME_MODE_TITLE)
1600 HandleTitleScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1601 else if (game_status == GAME_MODE_MAIN)
1602 HandleMainMenu(0, 0, 0, 0, MB_MENU_CHOICE);
1603 else if (game_status == GAME_MODE_LEVELS)
1604 HandleChooseLevelSet(0, 0, 0, 0, MB_MENU_CHOICE);
1605 else if (game_status == GAME_MODE_LEVELNR)
1606 HandleChooseLevelNr(0, 0, 0, 0, MB_MENU_CHOICE);
1607 else if (game_status == GAME_MODE_SETUP)
1608 HandleSetupScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1609 else if (game_status == GAME_MODE_INFO)
1610 HandleInfoScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1611 else if (game_status == GAME_MODE_SCORES)
1612 HandleHallOfFame(0, 0, 0, 0, MB_MENU_CHOICE);
1616 if (game_status != GAME_MODE_MAIN)
1617 FadeSkipNextFadeIn();
1619 if (game_status == GAME_MODE_TITLE)
1620 HandleTitleScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1621 else if (game_status == GAME_MODE_LEVELS)
1622 HandleChooseLevelSet(0, 0, 0, 0, MB_MENU_LEAVE);
1623 else if (game_status == GAME_MODE_LEVELNR)
1624 HandleChooseLevelNr(0, 0, 0, 0, MB_MENU_LEAVE);
1625 else if (game_status == GAME_MODE_SETUP)
1626 HandleSetupScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1627 else if (game_status == GAME_MODE_INFO)
1628 HandleInfoScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1629 else if (game_status == GAME_MODE_SCORES)
1630 HandleHallOfFame(0, 0, 0, 0, MB_MENU_LEAVE);
1634 if (game_status == GAME_MODE_LEVELS)
1635 HandleChooseLevelSet(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1636 else if (game_status == GAME_MODE_LEVELNR)
1637 HandleChooseLevelNr(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1638 else if (game_status == GAME_MODE_SETUP)
1639 HandleSetupScreen(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1640 else if (game_status == GAME_MODE_INFO)
1641 HandleInfoScreen(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1642 else if (game_status == GAME_MODE_SCORES)
1643 HandleHallOfFame(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1646 case KSYM_Page_Down:
1647 if (game_status == GAME_MODE_LEVELS)
1648 HandleChooseLevelSet(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1649 else if (game_status == GAME_MODE_LEVELNR)
1650 HandleChooseLevelNr(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1651 else if (game_status == GAME_MODE_SETUP)
1652 HandleSetupScreen(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1653 else if (game_status == GAME_MODE_INFO)
1654 HandleInfoScreen(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1655 else if (game_status == GAME_MODE_SCORES)
1656 HandleHallOfFame(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1661 GameFrameDelay = (GameFrameDelay == 500 ? GAME_FRAME_DELAY : 500);
1665 setup.sp_show_border_elements = !setup.sp_show_border_elements;
1666 printf("Supaplex border elements %s\n",
1667 setup.sp_show_border_elements ? "enabled" : "disabled");
1676 case GAME_MODE_EDITOR:
1677 if (!anyTextGadgetActiveOrJustFinished || key == KSYM_Escape)
1678 HandleLevelEditorKeyInput(key);
1681 case GAME_MODE_PLAYING:
1686 RequestQuitGame(setup.ask_on_escape);
1704 if (GameFrameDelay == 500)
1705 GameFrameDelay = GAME_FRAME_DELAY;
1707 GameFrameDelay = 500;
1710 GameFrameDelay = (key - KSYM_0) * 10;
1711 printf("Game speed == %d%% (%d ms delay between two frames)\n",
1712 GAME_FRAME_DELAY * 100 / GameFrameDelay, GameFrameDelay);
1718 options.debug = FALSE;
1719 printf("debug mode disabled\n");
1723 options.debug = TRUE;
1724 printf("debug mode enabled\n");
1730 if (!global.fps_slowdown)
1732 global.fps_slowdown = TRUE;
1733 global.fps_slowdown_factor = 2;
1734 printf("fps slowdown enabled -- display only every 2nd frame\n");
1736 else if (global.fps_slowdown_factor == 2)
1738 global.fps_slowdown_factor = 4;
1739 printf("fps slowdown enabled -- display only every 4th frame\n");
1743 global.fps_slowdown = FALSE;
1744 global.fps_slowdown_factor = 1;
1745 printf("fps slowdown disabled\n");
1752 ScrollStepSize = TILEX / 8;
1753 printf("ScrollStepSize == %d (1/8)\n", ScrollStepSize);
1757 ScrollStepSize = TILEX / 4;
1758 printf("ScrollStepSize == %d (1/4)\n", ScrollStepSize);
1762 ScrollStepSize = TILEX / 2;
1763 printf("ScrollStepSize == %d (1/2)\n", ScrollStepSize);
1767 ScrollStepSize = TILEX;
1768 printf("ScrollStepSize == %d (1/1)\n", ScrollStepSize);
1773 printf("::: currently using game engine version %d\n",
1774 game.engine_version);
1785 if (key == KSYM_Escape)
1787 game_status = GAME_MODE_MAIN;
1795 void HandleNoEvent()
1797 if (button_status && game_status != GAME_MODE_PLAYING)
1799 HandleButton(0, 0, -button_status, button_status);
1810 #if defined(NETWORK_AVALIABLE)
1811 if (options.network)
1815 switch (game_status)
1817 case GAME_MODE_MAIN:
1818 DrawPreviewLevelAnimation();
1822 case GAME_MODE_LEVELS:
1823 case GAME_MODE_LEVELNR:
1824 case GAME_MODE_SETUP:
1825 case GAME_MODE_INFO:
1826 case GAME_MODE_SCORES:
1830 case GAME_MODE_EDITOR:
1831 HandleLevelEditorIdle();
1839 static int HandleJoystickForAllPlayers()
1844 for (i = 0; i < MAX_PLAYERS; i++)
1846 byte joy_action = 0;
1849 if (!setup.input[i].use_joystick)
1853 joy_action = Joystick(i);
1854 result |= joy_action;
1856 if (!setup.input[i].use_joystick)
1859 stored_player[i].action = joy_action;
1865 void HandleJoystick()
1867 int joystick = HandleJoystickForAllPlayers();
1868 int keyboard = key_joystick_mapping;
1869 int joy = (joystick | keyboard);
1870 int left = joy & JOY_LEFT;
1871 int right = joy & JOY_RIGHT;
1872 int up = joy & JOY_UP;
1873 int down = joy & JOY_DOWN;
1874 int button = joy & JOY_BUTTON;
1875 int newbutton = (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED);
1876 int dx = (left ? -1 : right ? 1 : 0);
1877 int dy = (up ? -1 : down ? 1 : 0);
1879 switch (game_status)
1881 case GAME_MODE_TITLE:
1882 case GAME_MODE_MAIN:
1883 case GAME_MODE_LEVELS:
1884 case GAME_MODE_LEVELNR:
1885 case GAME_MODE_SETUP:
1886 case GAME_MODE_INFO:
1888 static unsigned int joystickmove_delay = 0;
1890 if (joystick && !button &&
1891 !DelayReached(&joystickmove_delay, GADGET_FRAME_DELAY))
1892 newbutton = dx = dy = 0;
1894 if (game_status == GAME_MODE_TITLE)
1895 HandleTitleScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1896 else if (game_status == GAME_MODE_MAIN)
1897 HandleMainMenu(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1898 else if (game_status == GAME_MODE_LEVELS)
1899 HandleChooseLevelSet(0,0,dx,dy,newbutton?MB_MENU_CHOICE : MB_MENU_MARK);
1900 else if (game_status == GAME_MODE_LEVELNR)
1901 HandleChooseLevelNr(0,0,dx,dy,newbutton? MB_MENU_CHOICE : MB_MENU_MARK);
1902 else if (game_status == GAME_MODE_SETUP)
1903 HandleSetupScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1904 else if (game_status == GAME_MODE_INFO)
1905 HandleInfoScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1909 case GAME_MODE_SCORES:
1910 HandleHallOfFame(0, 0, dx, dy, !newbutton);
1914 case GAME_MODE_EDITOR:
1915 HandleLevelEditorIdle();
1919 case GAME_MODE_PLAYING:
1920 if (tape.playing || keyboard)
1921 newbutton = ((joy & JOY_BUTTON) != 0);
1924 if (newbutton && local_player->LevelSolved_GameEnd)
1926 if (newbutton && AllPlayersGone)