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)
368 void HandleButtonEvent(ButtonEvent *event)
371 Error(ERR_DEBUG, "BUTTON EVENT: button %d %s, x/y %d/%d\n",
373 event->type == EVENT_BUTTONPRESS ? "pressed" : "released",
377 motion_status = FALSE;
379 if (event->type == EVENT_BUTTONPRESS)
380 button_status = event->button;
382 button_status = MB_RELEASED;
384 HandleButton(event->x, event->y, button_status, event->button);
387 void HandleMotionEvent(MotionEvent *event)
389 if (!PointerInWindow(window))
390 return; /* window and pointer are on different screens */
392 if (button_status == MB_RELEASED && game_status != GAME_MODE_EDITOR)
395 motion_status = TRUE;
398 Error(ERR_DEBUG, "MOTION EVENT: button %d moved, x/y %d/%d\n",
399 button_status, event->x, event->y);
402 HandleButton(event->x, event->y, button_status, button_status);
405 #if defined(TARGET_SDL2)
406 void HandleWindowEvent(WindowEvent *event)
409 int subtype = event->event;
412 (subtype == SDL_WINDOWEVENT_SHOWN ? "SDL_WINDOWEVENT_SHOWN" :
413 subtype == SDL_WINDOWEVENT_HIDDEN ? "SDL_WINDOWEVENT_HIDDEN" :
414 subtype == SDL_WINDOWEVENT_EXPOSED ? "SDL_WINDOWEVENT_EXPOSED" :
415 subtype == SDL_WINDOWEVENT_MOVED ? "SDL_WINDOWEVENT_MOVED" :
416 subtype == SDL_WINDOWEVENT_SIZE_CHANGED ? "SDL_WINDOWEVENT_SIZE_CHANGED" :
417 subtype == SDL_WINDOWEVENT_RESIZED ? "SDL_WINDOWEVENT_RESIZED" :
418 subtype == SDL_WINDOWEVENT_MINIMIZED ? "SDL_WINDOWEVENT_MINIMIZED" :
419 subtype == SDL_WINDOWEVENT_MAXIMIZED ? "SDL_WINDOWEVENT_MAXIMIZED" :
420 subtype == SDL_WINDOWEVENT_RESTORED ? "SDL_WINDOWEVENT_RESTORED" :
421 subtype == SDL_WINDOWEVENT_ENTER ? "SDL_WINDOWEVENT_ENTER" :
422 subtype == SDL_WINDOWEVENT_LEAVE ? "SDL_WINDOWEVENT_LEAVE" :
423 subtype == SDL_WINDOWEVENT_FOCUS_GAINED ? "SDL_WINDOWEVENT_FOCUS_GAINED" :
424 subtype == SDL_WINDOWEVENT_FOCUS_LOST ? "SDL_WINDOWEVENT_FOCUS_LOST" :
425 subtype == SDL_WINDOWEVENT_CLOSE ? "SDL_WINDOWEVENT_CLOSE" :
428 Error(ERR_DEBUG, "WINDOW EVENT: '%s', %ld, %ld",
429 event_name, event->data1, event->data2);
432 if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED ||
433 event->event == SDL_WINDOWEVENT_RESIZED ||
434 event->event == SDL_WINDOWEVENT_EXPOSED)
438 if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED)
440 // if game started in fullscreen mode, window will also get fullscreen size
441 if (!video.fullscreen_enabled && video.fullscreen_initial)
443 SDLSetWindowScaling(setup.window_scaling_percent);
445 // only do this correction once
446 video.fullscreen_initial = FALSE;
451 if (event->event == SDL_WINDOWEVENT_RESIZED && !video.fullscreen_enabled)
454 int new_window_width = event->data1;
455 int new_window_height = event->data2;
457 // if window size has changed after resizing, calculate new scaling factor
458 if (new_window_width != video.window_width ||
459 new_window_height != video.window_height)
461 int new_xpercent = (100 * new_window_width / video.width);
462 int new_ypercent = (100 * new_window_height / video.height);
465 printf("::: RESIZED from %d, %d to %d, %d\n",
466 video.window_width, video.window_height,
467 new_window_width, new_window_height);
470 setup.window_scaling_percent = video.window_scaling_percent =
471 MIN(MAX(MIN_WINDOW_SCALING_PERCENT, MIN(new_xpercent, new_ypercent)),
472 MAX_WINDOW_SCALING_PERCENT);
474 video.window_width = new_window_width;
475 video.window_height = new_window_height;
478 printf("::: setup.window_scaling_percent set to %d\n",
479 setup.window_scaling_percent);
482 if (game_status == GAME_MODE_SETUP)
483 RedrawSetupScreenAfterFullscreenToggle();
488 // prevent slightly wrong scaling factor due to rounding differences
489 float scaling_factor = (float)setup.window_scaling_percent / 100;
490 int old_xsize = (int)(scaling_factor * video.width);
491 int old_ysize = (int)(scaling_factor * video.height);
492 int new_xsize = event->data1;
493 int new_ysize = event->data2;
495 // window size is unchanged when going from fullscreen to window mode,
496 // but reverse calculation of scaling factor might result in a scaling
497 // factor that is slightly different due to rounding differences;
498 // therefore compare old/new window size and not old/new scaling factor
499 if (old_xsize != new_xsize ||
500 old_ysize != new_ysize)
502 int new_xpercent = (100 * new_xsize / video.width);
503 int new_ypercent = (100 * new_ysize / video.height);
505 setup.window_scaling_percent = MIN(new_xpercent, new_ypercent);
507 if (setup.window_scaling_percent < MIN_WINDOW_SCALING_PERCENT)
508 setup.window_scaling_percent = MIN_WINDOW_SCALING_PERCENT;
509 else if (setup.window_scaling_percent > MAX_WINDOW_SCALING_PERCENT)
510 setup.window_scaling_percent = MAX_WINDOW_SCALING_PERCENT;
512 printf("::: setup.window_scaling_percent set to %d\n",
513 setup.window_scaling_percent);
521 #define NUM_TOUCH_FINGERS 3
526 SDL_FingerID finger_id;
529 } touch_info[NUM_TOUCH_FINGERS];
531 void HandleFingerEvent(FingerEvent *event)
533 static Key motion_key_x = KSYM_UNDEFINED;
534 static Key motion_key_y = KSYM_UNDEFINED;
535 static Key button_key = KSYM_UNDEFINED;
536 static float motion_x1, motion_y1;
537 static float button_x1, button_y1;
538 static SDL_FingerID motion_id = -1;
539 static SDL_FingerID button_id = -1;
540 int move_trigger_distance_percent = 2; // percent of touchpad width/height
541 int drop_trigger_distance_percent = 5; // percent of touchpad width/height
542 float move_trigger_distance = (float)move_trigger_distance_percent / 100;
543 float drop_trigger_distance = (float)drop_trigger_distance_percent / 100;
544 float event_x = event->x;
545 float event_y = event->y;
549 Error(ERR_DEBUG, "FINGER EVENT: finger was %s, touch ID %lld, finger ID %lld, x/y %f/%f, dx/dy %f/%f, pressure %f",
550 event->type == EVENT_FINGERPRESS ? "pressed" :
551 event->type == EVENT_FINGERRELEASE ? "released" : "moved",
555 event->dx, event->dy,
560 if (game_status != GAME_MODE_PLAYING)
564 if (strEqual(setup.touch.control_type, TOUCH_CONTROL_VIRTUAL_BUTTONS))
566 boolean use_virtual_button_control = FALSE;
568 if (use_virtual_button_control)
571 int key_status = (event->type == EVENT_FINGERRELEASE ? KEY_RELEASED :
574 Key key = (event->x < 1.0 / 3.0 ?
575 (event->y < 1.0 / 2.0 ? setup.input[0].key.snap :
576 setup.input[0].key.drop) :
577 event->x > 2.0 / 3.0 ?
578 (event->y < 1.0 / 3.0 ? setup.input[0].key.up :
579 event->y > 2.0 / 3.0 ? setup.input[0].key.down :
580 event->x < 5.0 / 6.0 ? setup.input[0].key.left :
581 setup.input[0].key.right) :
584 char *key_name = (key == setup.input[0].key.snap ? "SNAP" :
585 key == setup.input[0].key.drop ? "DROP" :
586 key == setup.input[0].key.up ? "UP" :
587 key == setup.input[0].key.down ? "DOWN" :
588 key == setup.input[0].key.left ? "LEFT" :
589 key == setup.input[0].key.right ? "RIGHT" : "(unknown)");
591 char *key_status_name = (key_status == KEY_RELEASED ? "KEY_RELEASED" :
594 Key key = (event->y < 1.0 / 3.0 ? setup.input[0].key.up :
595 event->y > 2.0 / 3.0 ? setup.input[0].key.down :
596 event->x < 1.0 / 3.0 ? setup.input[0].key.left :
597 event->x > 2.0 / 3.0 ? setup.input[0].key.right :
598 setup.input[0].key.snap);
602 Error(ERR_DEBUG, "::: key '%s' was '%s' [fingerId: %lld]",
603 getKeyNameFromKey(key), key_status_name, event->fingerId);
605 // check if we already know this touch event's finger id
606 for (i = 0; i < NUM_TOUCH_FINGERS; i++)
608 if (touch_info[i].touched &&
609 touch_info[i].finger_id == event->fingerId)
611 // Error(ERR_DEBUG, "MARK 1: %d", i);
617 if (i >= NUM_TOUCH_FINGERS)
619 if (key_status == KEY_PRESSED)
621 int oldest_pos = 0, oldest_counter = touch_info[0].counter;
623 // unknown finger id -- get new, empty slot, if available
624 for (i = 0; i < NUM_TOUCH_FINGERS; i++)
626 if (touch_info[i].counter < oldest_counter)
629 oldest_counter = touch_info[i].counter;
631 // Error(ERR_DEBUG, "MARK 2: %d", i);
634 if (!touch_info[i].touched)
636 // Error(ERR_DEBUG, "MARK 3: %d", i);
642 if (i >= NUM_TOUCH_FINGERS)
644 // all slots allocated -- use oldest slot
647 // Error(ERR_DEBUG, "MARK 4: %d", i);
652 // release of previously unknown key (should not happen)
654 if (key != KSYM_UNDEFINED)
656 HandleKey(key, KEY_RELEASED);
658 Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d] [1]",
659 getKeyNameFromKey(key), "KEY_RELEASED", i);
664 if (i < NUM_TOUCH_FINGERS)
666 if (key_status == KEY_PRESSED)
668 if (touch_info[i].key != key)
670 if (touch_info[i].key != KSYM_UNDEFINED)
672 HandleKey(touch_info[i].key, KEY_RELEASED);
674 Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d] [2]",
675 getKeyNameFromKey(touch_info[i].key), "KEY_RELEASED", i);
678 if (key != KSYM_UNDEFINED)
680 HandleKey(key, KEY_PRESSED);
682 Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d] [3]",
683 getKeyNameFromKey(key), "KEY_PRESSED", i);
687 touch_info[i].touched = TRUE;
688 touch_info[i].finger_id = event->fingerId;
689 touch_info[i].counter = Counter();
690 touch_info[i].key = key;
694 if (touch_info[i].key != KSYM_UNDEFINED)
696 HandleKey(touch_info[i].key, KEY_RELEASED);
698 Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d] [4]",
699 getKeyNameFromKey(touch_info[i].key), "KEY_RELEASED", i);
702 touch_info[i].touched = FALSE;
703 touch_info[i].finger_id = 0;
704 touch_info[i].counter = 0;
705 touch_info[i].key = 0;
711 Error(ERR_DEBUG, "=> key == '%s', key_status == '%s' [slot %d]",
712 key_name, key_status_name, i);
714 Error(ERR_DEBUG, "=> key == %d, key_status == %d [%d]", key, key_status, i);
721 // use touch direction control
723 if (event->type == EVENT_FINGERPRESS)
725 if (event_x > 1.0 / 3.0)
729 motion_id = event->fingerId;
734 motion_key_x = KSYM_UNDEFINED;
735 motion_key_y = KSYM_UNDEFINED;
737 Error(ERR_DEBUG, "---------- MOVE STARTED (WAIT) ----------");
743 button_id = event->fingerId;
748 button_key = setup.input[0].key.snap;
750 HandleKey(button_key, KEY_PRESSED);
752 Error(ERR_DEBUG, "---------- SNAP STARTED ----------");
755 else if (event->type == EVENT_FINGERRELEASE)
757 if (event->fingerId == motion_id)
761 if (motion_key_x != KSYM_UNDEFINED)
762 HandleKey(motion_key_x, KEY_RELEASED);
763 if (motion_key_y != KSYM_UNDEFINED)
764 HandleKey(motion_key_y, KEY_RELEASED);
766 motion_key_x = KSYM_UNDEFINED;
767 motion_key_y = KSYM_UNDEFINED;
769 Error(ERR_DEBUG, "---------- MOVE STOPPED ----------");
771 else if (event->fingerId == button_id)
775 if (button_key != KSYM_UNDEFINED)
776 HandleKey(button_key, KEY_RELEASED);
778 button_key = KSYM_UNDEFINED;
780 Error(ERR_DEBUG, "---------- SNAP STOPPED ----------");
783 else if (event->type == EVENT_FINGERMOTION)
785 if (event->fingerId == motion_id)
787 float distance_x = ABS(event_x - motion_x1);
788 float distance_y = ABS(event_y - motion_y1);
789 Key new_motion_key_x = (event_x < motion_x1 ? setup.input[0].key.left :
790 event_x > motion_x1 ? setup.input[0].key.right :
792 Key new_motion_key_y = (event_y < motion_y1 ? setup.input[0].key.up :
793 event_y > motion_y1 ? setup.input[0].key.down :
796 if (distance_x < move_trigger_distance / 2 ||
797 distance_x < distance_y)
798 new_motion_key_x = KSYM_UNDEFINED;
800 if (distance_y < move_trigger_distance / 2 ||
801 distance_y < distance_x)
802 new_motion_key_y = KSYM_UNDEFINED;
804 if (distance_x > move_trigger_distance ||
805 distance_y > move_trigger_distance)
807 if (new_motion_key_x != motion_key_x)
809 if (motion_key_x != KSYM_UNDEFINED)
810 HandleKey(motion_key_x, KEY_RELEASED);
811 if (new_motion_key_x != KSYM_UNDEFINED)
812 HandleKey(new_motion_key_x, KEY_PRESSED);
815 if (new_motion_key_y != motion_key_y)
817 if (motion_key_y != KSYM_UNDEFINED)
818 HandleKey(motion_key_y, KEY_RELEASED);
819 if (new_motion_key_y != KSYM_UNDEFINED)
820 HandleKey(new_motion_key_y, KEY_PRESSED);
826 motion_key_x = new_motion_key_x;
827 motion_key_y = new_motion_key_y;
829 Error(ERR_DEBUG, "---------- MOVE STARTED (MOVE) ----------");
832 else if (event->fingerId == button_id)
834 float distance_x = ABS(event_x - button_x1);
835 float distance_y = ABS(event_y - button_y1);
837 if (distance_x < drop_trigger_distance / 2 &&
838 distance_y > drop_trigger_distance)
840 if (button_key == setup.input[0].key.snap)
841 HandleKey(button_key, KEY_RELEASED);
846 button_key = setup.input[0].key.drop;
848 HandleKey(button_key, KEY_PRESSED);
850 Error(ERR_DEBUG, "---------- DROP STARTED ----------");
858 void HandleFingerEvent(FingerEvent *event)
861 static int num_events = 0;
867 Error(ERR_DEBUG, "FINGER EVENT: finger was %s, touch ID %lld, finger ID %lld, x/y %f/%f, dx/dy %f/%f, pressure %f",
868 event->type == EVENT_FINGERPRESS ? "pressed" :
869 event->type == EVENT_FINGERRELEASE ? "released" : "moved",
873 event->dx, event->dy,
879 int x = (int)(event->x * video.width);
880 int y = (int)(event->y * video.height);
881 int button = MB_LEFTBUTTON;
883 Error(ERR_DEBUG, "=> screen x/y %d/%d", x, y);
887 if (++num_events >= max_events)
893 if (event->type == EVENT_FINGERPRESS ||
894 event->type == EVENT_FINGERMOTION)
895 button_status = button;
897 button_status = MB_RELEASED;
899 int max_x = SX + SXSIZE;
900 int max_y = SY + SYSIZE;
904 if (game_status == GAME_MODE_PLAYING)
906 if (game_status == GAME_MODE_PLAYING &&
910 int key_status = (event->type == EVENT_FINGERRELEASE ? KEY_RELEASED :
913 Key key = (event->y < 1.0 / 3.0 ? setup.input[0].key.up :
914 event->y > 2.0 / 3.0 ? setup.input[0].key.down :
915 event->x < 1.0 / 3.0 ? setup.input[0].key.left :
916 event->x > 2.0 / 3.0 ? setup.input[0].key.right :
917 setup.input[0].key.drop);
919 Key key = (y < max_y / 3 ? setup.input[0].key.up :
920 y > 2 * max_y / 3 ? setup.input[0].key.down :
921 x < max_x / 3 ? setup.input[0].key.left :
922 x > 2 * max_x / 3 ? setup.input[0].key.right :
923 setup.input[0].key.drop);
926 Error(ERR_DEBUG, "=> key == %d, key_status == %d", key, key_status);
928 HandleKey(key, key_status);
933 Error(ERR_DEBUG, "::: button_status == %d, button == %d\n",
934 button_status, button);
936 HandleButton(x, y, button_status, button);
944 static boolean checkTextInputKeyModState()
946 // when playing, only handle raw key events and ignore text input
947 if (game_status == GAME_MODE_PLAYING)
950 return ((GetKeyModState() & KMOD_TextInput) != KMOD_None);
953 void HandleTextEvent(TextEvent *event)
955 char *text = event->text;
956 Key key = getKeyFromKeyName(text);
959 Error(ERR_DEBUG, "TEXT EVENT: text == '%s' [%d byte(s), '%c'/%d], resulting key == %d (%s) [%04x]",
962 text[0], (int)(text[0]),
964 getKeyNameFromKey(key),
968 // if (game_status != GAME_MODE_PLAYING && GetKeyModState() != KMOD_None)
970 if (game_status != GAME_MODE_PLAYING &&
971 (GetKeyModState() & KMOD_TextInput) != KMOD_None)
973 if (checkTextInputKeyModState())
975 HandleKey(key, KEY_PRESSED);
976 HandleKey(key, KEY_RELEASED);
981 void HandleKeyEvent(KeyEvent *event)
983 int key_status = (event->type == EVENT_KEYPRESS ? KEY_PRESSED : KEY_RELEASED);
984 boolean with_modifiers = (game_status == GAME_MODE_PLAYING ? FALSE : TRUE);
985 Key key = GetEventKey(event, with_modifiers);
986 Key keymod = (with_modifiers ? GetEventKey(event, FALSE) : key);
989 Error(ERR_DEBUG, "KEY EVENT: key was %s, keysym.scancode == %d, keysym.sym == %d, keymod = %d, GetKeyModState() = 0x%04x, resulting key == %d (%s)",
990 event->type == EVENT_KEYPRESS ? "pressed" : "released",
991 event->keysym.scancode,
996 getKeyNameFromKey(key));
1000 if (key == KSYM_Menu)
1001 Error(ERR_DEBUG, "menu key pressed");
1002 else if (key == KSYM_Back)
1003 Error(ERR_DEBUG, "back key pressed");
1006 #if defined(PLATFORM_ANDROID)
1007 // always map the "back" button to the "escape" key on Android devices
1008 if (key == KSYM_Back)
1012 HandleKeyModState(keymod, key_status);
1014 #if defined(TARGET_SDL2)
1016 // if (game_status == GAME_MODE_PLAYING || GetKeyModState() == KMOD_None)
1018 if (game_status == GAME_MODE_PLAYING ||
1019 (GetKeyModState() & KMOD_TextInput) == KMOD_None)
1021 if (!checkTextInputKeyModState())
1022 HandleKey(key, key_status);
1024 HandleKey(key, key_status);
1028 void HandleFocusEvent(FocusChangeEvent *event)
1030 static int old_joystick_status = -1;
1032 if (event->type == EVENT_FOCUSOUT)
1034 KeyboardAutoRepeatOn();
1035 old_joystick_status = joystick.status;
1036 joystick.status = JOYSTICK_NOT_AVAILABLE;
1038 ClearPlayerAction();
1040 else if (event->type == EVENT_FOCUSIN)
1042 /* When there are two Rocks'n'Diamonds windows which overlap and
1043 the player moves the pointer from one game window to the other,
1044 a 'FocusOut' event is generated for the window the pointer is
1045 leaving and a 'FocusIn' event is generated for the window the
1046 pointer is entering. In some cases, it can happen that the
1047 'FocusIn' event is handled by the one game process before the
1048 'FocusOut' event by the other game process. In this case the
1049 X11 environment would end up with activated keyboard auto repeat,
1050 because unfortunately this is a global setting and not (which
1051 would be far better) set for each X11 window individually.
1052 The effect would be keyboard auto repeat while playing the game
1053 (game_status == GAME_MODE_PLAYING), which is not desired.
1054 To avoid this special case, we just wait 1/10 second before
1055 processing the 'FocusIn' event.
1058 if (game_status == GAME_MODE_PLAYING)
1061 KeyboardAutoRepeatOffUnlessAutoplay();
1064 if (old_joystick_status != -1)
1065 joystick.status = old_joystick_status;
1069 void HandleClientMessageEvent(ClientMessageEvent *event)
1071 if (CheckCloseWindowEvent(event))
1075 void HandleWindowManagerEvent(Event *event)
1077 #if defined(TARGET_SDL)
1078 SDLHandleWindowManagerEvent(event);
1082 void HandleButton(int mx, int my, int button, int button_nr)
1084 static int old_mx = 0, old_my = 0;
1098 #if defined(PLATFORM_ANDROID)
1099 if (game_status != GAME_MODE_PLAYING &&
1100 HandleGadgets(mx, my, button))
1102 /* do not handle this button event anymore */
1103 mx = my = -32; /* force mouse event to be outside screen tiles */
1106 if (HandleGadgets(mx, my, button))
1108 /* do not handle this button event anymore */
1109 mx = my = -32; /* force mouse event to be outside screen tiles */
1113 /* do not use scroll wheel button events for anything other than gadgets */
1114 if (IS_WHEEL_BUTTON(button_nr))
1118 Error(ERR_DEBUG, "::: game_status == %d", game_status);
1121 switch (game_status)
1123 case GAME_MODE_TITLE:
1124 HandleTitleScreen(mx, my, 0, 0, button);
1127 case GAME_MODE_MAIN:
1128 HandleMainMenu(mx, my, 0, 0, button);
1131 case GAME_MODE_PSEUDO_TYPENAME:
1132 HandleTypeName(0, KSYM_Return);
1135 case GAME_MODE_LEVELS:
1136 HandleChooseLevelSet(mx, my, 0, 0, button);
1139 case GAME_MODE_LEVELNR:
1140 HandleChooseLevelNr(mx, my, 0, 0, button);
1143 case GAME_MODE_SCORES:
1144 HandleHallOfFame(0, 0, 0, 0, button);
1147 case GAME_MODE_EDITOR:
1148 HandleLevelEditorIdle();
1151 case GAME_MODE_INFO:
1152 HandleInfoScreen(mx, my, 0, 0, button);
1155 case GAME_MODE_SETUP:
1156 HandleSetupScreen(mx, my, 0, 0, button);
1159 case GAME_MODE_PLAYING:
1161 if (button == MB_PRESSED && !motion_status && IN_GFX_FIELD_PLAY(mx, my))
1162 DumpTile(LEVELX((mx - SX) / TILESIZE_VAR),
1163 LEVELY((my - SY) / TILESIZE_VAR));
1164 // DumpTile(LEVELX((mx - SX) / TILEX), LEVELY((my - SY) / TILEY));
1173 static boolean is_string_suffix(char *string, char *suffix)
1175 int string_len = strlen(string);
1176 int suffix_len = strlen(suffix);
1178 if (suffix_len > string_len)
1181 return (strEqual(&string[string_len - suffix_len], suffix));
1184 #define MAX_CHEAT_INPUT_LEN 32
1186 static void HandleKeysSpecial(Key key)
1188 static char cheat_input[2 * MAX_CHEAT_INPUT_LEN + 1] = "";
1189 char letter = getCharFromKey(key);
1190 int cheat_input_len = strlen(cheat_input);
1196 if (cheat_input_len >= 2 * MAX_CHEAT_INPUT_LEN)
1198 for (i = 0; i < MAX_CHEAT_INPUT_LEN + 1; i++)
1199 cheat_input[i] = cheat_input[MAX_CHEAT_INPUT_LEN + i];
1201 cheat_input_len = MAX_CHEAT_INPUT_LEN;
1204 cheat_input[cheat_input_len++] = letter;
1205 cheat_input[cheat_input_len] = '\0';
1208 Error(ERR_DEBUG, "SPECIAL KEY '%s' [%d]\n", cheat_input, cheat_input_len);
1211 if (game_status == GAME_MODE_MAIN)
1213 if (is_string_suffix(cheat_input, ":insert-solution-tape") ||
1214 is_string_suffix(cheat_input, ":ist"))
1216 InsertSolutionTape();
1218 else if (is_string_suffix(cheat_input, ":reload-graphics") ||
1219 is_string_suffix(cheat_input, ":rg"))
1221 ReloadCustomArtwork(1 << ARTWORK_TYPE_GRAPHICS);
1224 else if (is_string_suffix(cheat_input, ":reload-sounds") ||
1225 is_string_suffix(cheat_input, ":rs"))
1227 ReloadCustomArtwork(1 << ARTWORK_TYPE_SOUNDS);
1230 else if (is_string_suffix(cheat_input, ":reload-music") ||
1231 is_string_suffix(cheat_input, ":rm"))
1233 ReloadCustomArtwork(1 << ARTWORK_TYPE_MUSIC);
1236 else if (is_string_suffix(cheat_input, ":reload-artwork") ||
1237 is_string_suffix(cheat_input, ":ra"))
1239 ReloadCustomArtwork(1 << ARTWORK_TYPE_GRAPHICS |
1240 1 << ARTWORK_TYPE_SOUNDS |
1241 1 << ARTWORK_TYPE_MUSIC);
1244 else if (is_string_suffix(cheat_input, ":dump-level") ||
1245 is_string_suffix(cheat_input, ":dl"))
1249 else if (is_string_suffix(cheat_input, ":dump-tape") ||
1250 is_string_suffix(cheat_input, ":dt"))
1254 else if (is_string_suffix(cheat_input, ":fix-tape") ||
1255 is_string_suffix(cheat_input, ":ft"))
1257 /* fix single-player tapes that contain player input for more than one
1258 player (due to a bug in 3.3.1.2 and earlier versions), which results
1259 in playing levels with more than one player in multi-player mode,
1260 even though the tape was originally recorded in single-player mode */
1262 /* remove player input actions for all players but the first one */
1263 for (i = 1; i < MAX_PLAYERS; i++)
1264 tape.player_participates[i] = FALSE;
1266 tape.changed = TRUE;
1268 else if (is_string_suffix(cheat_input, ":save-native-level") ||
1269 is_string_suffix(cheat_input, ":snl"))
1271 SaveNativeLevel(&level);
1274 else if (game_status == GAME_MODE_PLAYING)
1277 if (is_string_suffix(cheat_input, ".q"))
1278 DEBUG_SetMaximumDynamite();
1281 else if (game_status == GAME_MODE_EDITOR)
1283 if (is_string_suffix(cheat_input, ":dump-brush") ||
1284 is_string_suffix(cheat_input, ":DB"))
1288 else if (is_string_suffix(cheat_input, ":DDB"))
1295 void HandleKey(Key key, int key_status)
1297 boolean anyTextGadgetActiveOrJustFinished = anyTextGadgetActive();
1298 static struct SetupKeyboardInfo ski;
1299 static struct SetupShortcutInfo ssi;
1308 { &ski.left, &ssi.snap_left, DEFAULT_KEY_LEFT, JOY_LEFT },
1309 { &ski.right, &ssi.snap_right, DEFAULT_KEY_RIGHT, JOY_RIGHT },
1310 { &ski.up, &ssi.snap_up, DEFAULT_KEY_UP, JOY_UP },
1311 { &ski.down, &ssi.snap_down, DEFAULT_KEY_DOWN, JOY_DOWN },
1312 { &ski.snap, NULL, DEFAULT_KEY_SNAP, JOY_BUTTON_SNAP },
1313 { &ski.drop, NULL, DEFAULT_KEY_DROP, JOY_BUTTON_DROP }
1318 if (game_status == GAME_MODE_PLAYING)
1320 /* only needed for single-step tape recording mode */
1321 static boolean clear_snap_button[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1322 static boolean clear_drop_button[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1323 static boolean element_snapped[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1324 static boolean element_dropped[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
1327 for (pnr = 0; pnr < MAX_PLAYERS; pnr++)
1329 byte key_action = 0;
1331 if (setup.input[pnr].use_joystick)
1334 ski = setup.input[pnr].key;
1336 for (i = 0; i < NUM_PLAYER_ACTIONS; i++)
1337 if (key == *key_info[i].key_custom)
1338 key_action |= key_info[i].action;
1340 /* use combined snap+direction keys for the first player only */
1343 ssi = setup.shortcut;
1345 for (i = 0; i < NUM_DIRECTIONS; i++)
1346 if (key == *key_info[i].key_snap)
1347 key_action |= key_info[i].action | JOY_BUTTON_SNAP;
1350 /* clear delayed snap and drop actions in single step mode (see below) */
1351 if (tape.single_step)
1353 if (clear_snap_button[pnr])
1355 stored_player[pnr].action &= ~KEY_BUTTON_SNAP;
1356 clear_snap_button[pnr] = FALSE;
1359 if (clear_drop_button[pnr])
1361 stored_player[pnr].action &= ~KEY_BUTTON_DROP;
1362 clear_drop_button[pnr] = FALSE;
1366 if (key_status == KEY_PRESSED)
1367 stored_player[pnr].action |= key_action;
1369 stored_player[pnr].action &= ~key_action;
1371 if (tape.single_step && tape.recording && tape.pausing)
1373 if (key_status == KEY_PRESSED && key_action & KEY_MOTION)
1375 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1377 /* if snap key already pressed, don't snap when releasing (below) */
1378 if (stored_player[pnr].action & KEY_BUTTON_SNAP)
1379 element_snapped[pnr] = TRUE;
1381 /* if drop key already pressed, don't drop when releasing (below) */
1382 if (stored_player[pnr].action & KEY_BUTTON_DROP)
1383 element_dropped[pnr] = TRUE;
1386 else if (key_status == KEY_PRESSED && key_action & KEY_BUTTON_DROP)
1388 if (level.game_engine_type == GAME_ENGINE_TYPE_EM ||
1389 level.game_engine_type == GAME_ENGINE_TYPE_SP)
1392 printf("::: drop key pressed\n");
1395 if (level.game_engine_type == GAME_ENGINE_TYPE_SP &&
1396 getRedDiskReleaseFlag_SP() == 0)
1397 stored_player[pnr].action &= ~KEY_BUTTON_DROP;
1399 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1403 else if (key_status == KEY_RELEASED && key_action & KEY_BUTTON)
1405 if (key_action & KEY_BUTTON_SNAP)
1407 /* if snap key was released without moving (see above), snap now */
1408 if (!element_snapped[pnr])
1410 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1412 stored_player[pnr].action |= KEY_BUTTON_SNAP;
1414 /* clear delayed snap button on next event */
1415 clear_snap_button[pnr] = TRUE;
1418 element_snapped[pnr] = FALSE;
1422 if (key_action & KEY_BUTTON_DROP &&
1423 level.game_engine_type == GAME_ENGINE_TYPE_RND)
1425 /* if drop key was released without moving (see above), drop now */
1426 if (!element_dropped[pnr])
1428 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
1430 if (level.game_engine_type != GAME_ENGINE_TYPE_SP ||
1431 getRedDiskReleaseFlag_SP() != 0)
1432 stored_player[pnr].action |= KEY_BUTTON_DROP;
1434 /* clear delayed drop button on next event */
1435 clear_drop_button[pnr] = TRUE;
1438 element_dropped[pnr] = FALSE;
1443 else if (tape.recording && tape.pausing)
1445 /* prevent key release events from un-pausing a paused game */
1446 if (key_status == KEY_PRESSED && key_action & KEY_ACTION)
1447 TapeTogglePause(TAPE_TOGGLE_MANUAL);
1453 for (i = 0; i < NUM_PLAYER_ACTIONS; i++)
1454 if (key == key_info[i].key_default)
1455 joy |= key_info[i].action;
1460 if (key_status == KEY_PRESSED)
1461 key_joystick_mapping |= joy;
1463 key_joystick_mapping &= ~joy;
1468 if (game_status != GAME_MODE_PLAYING)
1469 key_joystick_mapping = 0;
1471 if (key_status == KEY_RELEASED)
1474 if ((key == KSYM_Return || key == KSYM_KP_Enter) &&
1475 (GetKeyModState() & KMOD_Alt) && video.fullscreen_available)
1477 setup.fullscreen = !setup.fullscreen;
1480 printf("::: %d\n", setup.window_scaling_percent);
1483 ToggleFullscreenOrChangeWindowScalingIfNeeded();
1485 if (game_status == GAME_MODE_SETUP)
1486 RedrawSetupScreenAfterFullscreenToggle();
1491 if ((key == KSYM_minus || key == KSYM_plus || key == KSYM_0) &&
1492 (GetKeyModState() & KMOD_Alt) && video.window_scaling_available &&
1493 !video.fullscreen_enabled)
1496 setup.window_scaling_percent = STD_WINDOW_SCALING_PERCENT;
1498 setup.window_scaling_percent +=
1499 (key == KSYM_minus ? -1 : +1) * STEP_WINDOW_SCALING_PERCENT;
1501 if (setup.window_scaling_percent < MIN_WINDOW_SCALING_PERCENT)
1502 setup.window_scaling_percent = MIN_WINDOW_SCALING_PERCENT;
1503 else if (setup.window_scaling_percent > MAX_WINDOW_SCALING_PERCENT)
1504 setup.window_scaling_percent = MAX_WINDOW_SCALING_PERCENT;
1506 ToggleFullscreenOrChangeWindowScalingIfNeeded();
1508 if (game_status == GAME_MODE_SETUP)
1509 RedrawSetupScreenAfterFullscreenToggle();
1515 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd &&
1516 (key == KSYM_Return || key == setup.shortcut.toggle_pause))
1518 if (game_status == GAME_MODE_PLAYING && AllPlayersGone &&
1519 (key == KSYM_Return || key == setup.shortcut.toggle_pause))
1527 if (game_status == GAME_MODE_MAIN &&
1528 (key == setup.shortcut.toggle_pause || key == KSYM_space))
1530 StartGameActions(options.network, setup.autorecord, level.random_seed);
1535 if (game_status == GAME_MODE_MAIN || game_status == GAME_MODE_PLAYING)
1537 if (key == setup.shortcut.save_game)
1539 else if (key == setup.shortcut.load_game)
1541 else if (key == setup.shortcut.toggle_pause)
1542 TapeTogglePause(TAPE_TOGGLE_MANUAL);
1544 HandleTapeButtonKeys(key);
1545 HandleSoundButtonKeys(key);
1548 if (game_status == GAME_MODE_PLAYING && !network_playing)
1550 int centered_player_nr_next = -999;
1552 if (key == setup.shortcut.focus_player_all)
1553 centered_player_nr_next = -1;
1555 for (i = 0; i < MAX_PLAYERS; i++)
1556 if (key == setup.shortcut.focus_player[i])
1557 centered_player_nr_next = i;
1559 if (centered_player_nr_next != -999)
1561 game.centered_player_nr_next = centered_player_nr_next;
1562 game.set_centered_player = TRUE;
1566 tape.centered_player_nr_next = game.centered_player_nr_next;
1567 tape.set_centered_player = TRUE;
1572 HandleKeysSpecial(key);
1574 if (HandleGadgetsKeyInput(key))
1576 if (key != KSYM_Escape) /* always allow ESC key to be handled */
1577 key = KSYM_UNDEFINED;
1580 switch (game_status)
1582 case GAME_MODE_PSEUDO_TYPENAME:
1583 HandleTypeName(0, key);
1586 case GAME_MODE_TITLE:
1587 case GAME_MODE_MAIN:
1588 case GAME_MODE_LEVELS:
1589 case GAME_MODE_LEVELNR:
1590 case GAME_MODE_SETUP:
1591 case GAME_MODE_INFO:
1592 case GAME_MODE_SCORES:
1597 if (game_status == GAME_MODE_TITLE)
1598 HandleTitleScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1599 else if (game_status == GAME_MODE_MAIN)
1600 HandleMainMenu(0, 0, 0, 0, MB_MENU_CHOICE);
1601 else if (game_status == GAME_MODE_LEVELS)
1602 HandleChooseLevelSet(0, 0, 0, 0, MB_MENU_CHOICE);
1603 else if (game_status == GAME_MODE_LEVELNR)
1604 HandleChooseLevelNr(0, 0, 0, 0, MB_MENU_CHOICE);
1605 else if (game_status == GAME_MODE_SETUP)
1606 HandleSetupScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1607 else if (game_status == GAME_MODE_INFO)
1608 HandleInfoScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1609 else if (game_status == GAME_MODE_SCORES)
1610 HandleHallOfFame(0, 0, 0, 0, MB_MENU_CHOICE);
1614 if (game_status != GAME_MODE_MAIN)
1615 FadeSkipNextFadeIn();
1617 if (game_status == GAME_MODE_TITLE)
1618 HandleTitleScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1619 else if (game_status == GAME_MODE_LEVELS)
1620 HandleChooseLevelSet(0, 0, 0, 0, MB_MENU_LEAVE);
1621 else if (game_status == GAME_MODE_LEVELNR)
1622 HandleChooseLevelNr(0, 0, 0, 0, MB_MENU_LEAVE);
1623 else if (game_status == GAME_MODE_SETUP)
1624 HandleSetupScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1625 else if (game_status == GAME_MODE_INFO)
1626 HandleInfoScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1627 else if (game_status == GAME_MODE_SCORES)
1628 HandleHallOfFame(0, 0, 0, 0, MB_MENU_LEAVE);
1632 if (game_status == GAME_MODE_LEVELS)
1633 HandleChooseLevelSet(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1634 else if (game_status == GAME_MODE_LEVELNR)
1635 HandleChooseLevelNr(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1636 else if (game_status == GAME_MODE_SETUP)
1637 HandleSetupScreen(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1638 else if (game_status == GAME_MODE_INFO)
1639 HandleInfoScreen(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1640 else if (game_status == GAME_MODE_SCORES)
1641 HandleHallOfFame(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1644 case KSYM_Page_Down:
1645 if (game_status == GAME_MODE_LEVELS)
1646 HandleChooseLevelSet(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1647 else if (game_status == GAME_MODE_LEVELNR)
1648 HandleChooseLevelNr(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1649 else if (game_status == GAME_MODE_SETUP)
1650 HandleSetupScreen(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1651 else if (game_status == GAME_MODE_INFO)
1652 HandleInfoScreen(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1653 else if (game_status == GAME_MODE_SCORES)
1654 HandleHallOfFame(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1659 GameFrameDelay = (GameFrameDelay == 500 ? GAME_FRAME_DELAY : 500);
1663 setup.sp_show_border_elements = !setup.sp_show_border_elements;
1664 printf("Supaplex border elements %s\n",
1665 setup.sp_show_border_elements ? "enabled" : "disabled");
1674 case GAME_MODE_EDITOR:
1675 if (!anyTextGadgetActiveOrJustFinished || key == KSYM_Escape)
1676 HandleLevelEditorKeyInput(key);
1679 case GAME_MODE_PLAYING:
1684 RequestQuitGame(setup.ask_on_escape);
1702 if (GameFrameDelay == 500)
1703 GameFrameDelay = GAME_FRAME_DELAY;
1705 GameFrameDelay = 500;
1708 GameFrameDelay = (key - KSYM_0) * 10;
1709 printf("Game speed == %d%% (%d ms delay between two frames)\n",
1710 GAME_FRAME_DELAY * 100 / GameFrameDelay, GameFrameDelay);
1716 options.debug = FALSE;
1717 printf("debug mode disabled\n");
1721 options.debug = TRUE;
1722 printf("debug mode enabled\n");
1728 if (!global.fps_slowdown)
1730 global.fps_slowdown = TRUE;
1731 global.fps_slowdown_factor = 2;
1732 printf("fps slowdown enabled -- display only every 2nd frame\n");
1734 else if (global.fps_slowdown_factor == 2)
1736 global.fps_slowdown_factor = 4;
1737 printf("fps slowdown enabled -- display only every 4th frame\n");
1741 global.fps_slowdown = FALSE;
1742 global.fps_slowdown_factor = 1;
1743 printf("fps slowdown disabled\n");
1750 ScrollStepSize = TILEX / 8;
1751 printf("ScrollStepSize == %d (1/8)\n", ScrollStepSize);
1755 ScrollStepSize = TILEX / 4;
1756 printf("ScrollStepSize == %d (1/4)\n", ScrollStepSize);
1760 ScrollStepSize = TILEX / 2;
1761 printf("ScrollStepSize == %d (1/2)\n", ScrollStepSize);
1765 ScrollStepSize = TILEX;
1766 printf("ScrollStepSize == %d (1/1)\n", ScrollStepSize);
1771 printf("::: currently using game engine version %d\n",
1772 game.engine_version);
1783 if (key == KSYM_Escape)
1785 game_status = GAME_MODE_MAIN;
1793 void HandleNoEvent()
1795 if (button_status && game_status != GAME_MODE_PLAYING)
1797 HandleButton(0, 0, -button_status, button_status);
1808 #if defined(NETWORK_AVALIABLE)
1809 if (options.network)
1813 switch (game_status)
1815 case GAME_MODE_MAIN:
1816 DrawPreviewLevelAnimation();
1820 case GAME_MODE_LEVELS:
1821 case GAME_MODE_LEVELNR:
1822 case GAME_MODE_SETUP:
1823 case GAME_MODE_INFO:
1824 case GAME_MODE_SCORES:
1828 case GAME_MODE_EDITOR:
1829 HandleLevelEditorIdle();
1837 static int HandleJoystickForAllPlayers()
1842 for (i = 0; i < MAX_PLAYERS; i++)
1844 byte joy_action = 0;
1847 if (!setup.input[i].use_joystick)
1851 joy_action = Joystick(i);
1852 result |= joy_action;
1854 if (!setup.input[i].use_joystick)
1857 stored_player[i].action = joy_action;
1863 void HandleJoystick()
1865 int joystick = HandleJoystickForAllPlayers();
1866 int keyboard = key_joystick_mapping;
1867 int joy = (joystick | keyboard);
1868 int left = joy & JOY_LEFT;
1869 int right = joy & JOY_RIGHT;
1870 int up = joy & JOY_UP;
1871 int down = joy & JOY_DOWN;
1872 int button = joy & JOY_BUTTON;
1873 int newbutton = (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED);
1874 int dx = (left ? -1 : right ? 1 : 0);
1875 int dy = (up ? -1 : down ? 1 : 0);
1877 switch (game_status)
1879 case GAME_MODE_TITLE:
1880 case GAME_MODE_MAIN:
1881 case GAME_MODE_LEVELS:
1882 case GAME_MODE_LEVELNR:
1883 case GAME_MODE_SETUP:
1884 case GAME_MODE_INFO:
1886 static unsigned int joystickmove_delay = 0;
1888 if (joystick && !button &&
1889 !DelayReached(&joystickmove_delay, GADGET_FRAME_DELAY))
1890 newbutton = dx = dy = 0;
1892 if (game_status == GAME_MODE_TITLE)
1893 HandleTitleScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1894 else if (game_status == GAME_MODE_MAIN)
1895 HandleMainMenu(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1896 else if (game_status == GAME_MODE_LEVELS)
1897 HandleChooseLevelSet(0,0,dx,dy,newbutton?MB_MENU_CHOICE : MB_MENU_MARK);
1898 else if (game_status == GAME_MODE_LEVELNR)
1899 HandleChooseLevelNr(0,0,dx,dy,newbutton? MB_MENU_CHOICE : MB_MENU_MARK);
1900 else if (game_status == GAME_MODE_SETUP)
1901 HandleSetupScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1902 else if (game_status == GAME_MODE_INFO)
1903 HandleInfoScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1907 case GAME_MODE_SCORES:
1908 HandleHallOfFame(0, 0, dx, dy, !newbutton);
1912 case GAME_MODE_EDITOR:
1913 HandleLevelEditorIdle();
1917 case GAME_MODE_PLAYING:
1918 if (tape.playing || keyboard)
1919 newbutton = ((joy & JOY_BUTTON) != 0);
1922 if (newbutton && local_player->LevelSolved_GameEnd)
1924 if (newbutton && AllPlayersGone)