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 1
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 EVENT_FINGERPRESS:
166 case EVENT_FINGERRELEASE:
167 case EVENT_FINGERMOTION:
168 HandleFingerEvent((FingerEvent *) &event);
173 case EVENT_KEYRELEASE:
174 HandleKeyEvent((KeyEvent *) &event);
178 HandleOtherEvents(&event);
185 /* when playing, display a special mouse pointer inside the playfield */
186 if (game_status == GAME_MODE_PLAYING && !tape.pausing)
188 if (!playfield_cursor_set && cursor_inside_playfield &&
189 DelayReached(&playfield_cursor_delay, 1000))
191 SetMouseCursor(CURSOR_PLAYFIELD);
192 playfield_cursor_set = TRUE;
195 else if (playfield_cursor_set)
197 SetMouseCursor(CURSOR_DEFAULT);
198 playfield_cursor_set = FALSE;
204 /* don't use all CPU time when idle; the main loop while playing
205 has its own synchronization and is CPU friendly, too */
207 if (game_status == GAME_MODE_PLAYING)
214 if (!PendingEvent()) /* delay only if no pending events */
218 /* refresh window contents from drawing buffer, if needed */
221 if (game_status == GAME_MODE_QUIT)
226 void HandleOtherEvents(Event *event)
231 HandleExposeEvent((ExposeEvent *) event);
234 case EVENT_UNMAPNOTIFY:
236 /* This causes the game to stop not only when iconified, but also
237 when on another virtual desktop, which might be not desired. */
238 SleepWhileUnmapped();
244 HandleFocusEvent((FocusChangeEvent *) event);
247 case EVENT_CLIENTMESSAGE:
248 HandleClientMessageEvent((ClientMessageEvent *) event);
251 #if defined(TARGET_SDL)
252 case SDL_JOYAXISMOTION:
253 case SDL_JOYBUTTONDOWN:
254 case SDL_JOYBUTTONUP:
255 HandleJoystickEvent(event);
259 HandleWindowManagerEvent(event);
268 void ClearEventQueue()
270 while (PendingEvent())
278 case EVENT_BUTTONRELEASE:
279 button_status = MB_RELEASED;
282 case EVENT_KEYRELEASE:
286 key_joystick_mapping = 0;
291 HandleOtherEvents(&event);
297 void ClearPlayerAction()
301 /* simulate key release events for still pressed keys */
302 key_joystick_mapping = 0;
303 for (i = 0; i < MAX_PLAYERS; i++)
304 stored_player[i].action = 0;
307 void SleepWhileUnmapped()
309 boolean window_unmapped = TRUE;
311 KeyboardAutoRepeatOn();
313 while (window_unmapped)
321 case EVENT_BUTTONRELEASE:
322 button_status = MB_RELEASED;
325 case EVENT_KEYRELEASE:
326 key_joystick_mapping = 0;
329 case EVENT_MAPNOTIFY:
330 window_unmapped = FALSE;
333 case EVENT_UNMAPNOTIFY:
334 /* this is only to surely prevent the 'should not happen' case
335 * of recursively looping between 'SleepWhileUnmapped()' and
336 * 'HandleOtherEvents()' which usually calls this funtion.
341 HandleOtherEvents(&event);
346 if (game_status == GAME_MODE_PLAYING)
347 KeyboardAutoRepeatOffUnlessAutoplay();
350 void HandleExposeEvent(ExposeEvent *event)
352 #if !defined(TARGET_SDL)
353 RedrawPlayfield(FALSE, event->x, event->y, event->width, event->height);
358 void HandleButtonEvent(ButtonEvent *event)
361 Error(ERR_DEBUG, "BUTTON EVENT: button %d %s, x/y %d/%d\n",
363 event->type == EVENT_BUTTONPRESS ? "pressed" : "released",
367 motion_status = FALSE;
369 if (event->type == EVENT_BUTTONPRESS)
370 button_status = event->button;
372 button_status = MB_RELEASED;
374 HandleButton(event->x, event->y, button_status, event->button);
377 void HandleMotionEvent(MotionEvent *event)
379 if (!PointerInWindow(window))
380 return; /* window and pointer are on different screens */
382 if (button_status == MB_RELEASED && game_status != GAME_MODE_EDITOR)
385 motion_status = TRUE;
387 Error(ERR_DEBUG, "MOTION EVENT: button %d moved, x/y %d/%d\n",
388 button_status, event->x, event->y);
390 HandleButton(event->x, event->y, button_status, button_status);
393 #if defined(TARGET_SDL2)
394 void HandleFingerEvent(FingerEvent *event)
397 static int num_events = 0;
402 Error(ERR_DEBUG, "FINGER EVENT: finger was %s, touch ID %lld, finger ID %lld, x/y %f/%f, dx/dy %f/%f, pressure %f",
403 event->type == EVENT_FINGERPRESS ? "pressed" :
404 event->type == EVENT_FINGERRELEASE ? "released" : "moved",
408 event->dx, event->dy,
412 int x = (int)(event->x * video.width);
413 int y = (int)(event->y * video.height);
414 int button = MB_LEFTBUTTON;
416 Error(ERR_DEBUG, "=> screen x/y %d/%d", x, y);
419 if (++num_events >= max_events)
424 if (event->type == EVENT_FINGERPRESS ||
425 event->type == EVENT_FINGERMOTION)
426 button_status = button;
428 button_status = MB_RELEASED;
430 int max_x = SX + SXSIZE;
431 int max_y = SY + SYSIZE;
433 if (game_status == GAME_MODE_PLAYING &&
436 int key_status = (event->type == EVENT_FINGERRELEASE ? KEY_RELEASED :
438 Key key = (y < max_y / 3 ? setup.input[0].key.up :
439 y > 2 * max_y / 3 ? setup.input[0].key.down :
440 x < max_x / 3 ? setup.input[0].key.left :
441 x > 2 * max_x / 3 ? setup.input[0].key.right :
442 setup.input[0].key.drop);
444 Error(ERR_DEBUG, "=> key == %d, key_status == %d", key, key_status);
446 HandleKey(key, key_status);
451 Error(ERR_DEBUG, "::: button_status == %d, button == %d\n",
452 button_status, button);
456 HandleButton(x, y, button_status, button);
463 void HandleKeyEvent(KeyEvent *event)
465 int key_status = (event->type == EVENT_KEYPRESS ? KEY_PRESSED : KEY_RELEASED);
466 boolean with_modifiers = (game_status == GAME_MODE_PLAYING ? FALSE : TRUE);
467 Key key = GetEventKey(event, with_modifiers);
468 Key keymod = (with_modifiers ? GetEventKey(event, FALSE) : key);
471 Error(ERR_DEBUG, "KEY EVENT: key was %s, keysym.scancode == %d, keysym.sym == %d, resulting key == %d (%s)",
472 event->type == EVENT_KEYPRESS ? "pressed" : "released",
473 event->keysym.scancode,
475 GetEventKey(event, TRUE),
476 getKeyNameFromKey(key));
480 if (key == KSYM_Menu)
481 Error(ERR_DEBUG, "menu key pressed");
482 else if (key == KSYM_Back)
483 Error(ERR_DEBUG, "back key pressed");
486 #if defined(PLATFORM_ANDROID)
487 // always map the "back" button to the "escape" key on Android devices
488 if (key == KSYM_Back)
492 HandleKeyModState(keymod, key_status);
493 HandleKey(key, key_status);
496 void HandleFocusEvent(FocusChangeEvent *event)
498 static int old_joystick_status = -1;
500 if (event->type == EVENT_FOCUSOUT)
502 KeyboardAutoRepeatOn();
503 old_joystick_status = joystick.status;
504 joystick.status = JOYSTICK_NOT_AVAILABLE;
508 else if (event->type == EVENT_FOCUSIN)
510 /* When there are two Rocks'n'Diamonds windows which overlap and
511 the player moves the pointer from one game window to the other,
512 a 'FocusOut' event is generated for the window the pointer is
513 leaving and a 'FocusIn' event is generated for the window the
514 pointer is entering. In some cases, it can happen that the
515 'FocusIn' event is handled by the one game process before the
516 'FocusOut' event by the other game process. In this case the
517 X11 environment would end up with activated keyboard auto repeat,
518 because unfortunately this is a global setting and not (which
519 would be far better) set for each X11 window individually.
520 The effect would be keyboard auto repeat while playing the game
521 (game_status == GAME_MODE_PLAYING), which is not desired.
522 To avoid this special case, we just wait 1/10 second before
523 processing the 'FocusIn' event.
526 if (game_status == GAME_MODE_PLAYING)
529 KeyboardAutoRepeatOffUnlessAutoplay();
532 if (old_joystick_status != -1)
533 joystick.status = old_joystick_status;
537 void HandleClientMessageEvent(ClientMessageEvent *event)
539 if (CheckCloseWindowEvent(event))
543 void HandleWindowManagerEvent(Event *event)
545 #if defined(TARGET_SDL)
546 SDLHandleWindowManagerEvent(event);
550 void HandleButton(int mx, int my, int button, int button_nr)
552 static int old_mx = 0, old_my = 0;
566 if (HandleGadgets(mx, my, button))
568 /* do not handle this button event anymore */
569 mx = my = -32; /* force mouse event to be outside screen tiles */
572 /* do not use scroll wheel button events for anything other than gadgets */
573 if (IS_WHEEL_BUTTON(button_nr))
576 Error(ERR_DEBUG, "::: game_status == %d", game_status);
580 case GAME_MODE_TITLE:
581 HandleTitleScreen(mx, my, 0, 0, button);
585 HandleMainMenu(mx, my, 0, 0, button);
588 case GAME_MODE_PSEUDO_TYPENAME:
589 HandleTypeName(0, KSYM_Return);
592 case GAME_MODE_LEVELS:
593 HandleChooseLevelSet(mx, my, 0, 0, button);
596 case GAME_MODE_LEVELNR:
597 HandleChooseLevelNr(mx, my, 0, 0, button);
600 case GAME_MODE_SCORES:
601 HandleHallOfFame(0, 0, 0, 0, button);
604 case GAME_MODE_EDITOR:
605 HandleLevelEditorIdle();
609 HandleInfoScreen(mx, my, 0, 0, button);
612 case GAME_MODE_SETUP:
613 HandleSetupScreen(mx, my, 0, 0, button);
616 case GAME_MODE_PLAYING:
618 if (button == MB_PRESSED && !motion_status && IN_GFX_SCREEN(mx, my))
619 DumpTile(LEVELX((mx - SX) / TILEX), LEVELY((my - SY) / TILEY));
628 static boolean is_string_suffix(char *string, char *suffix)
630 int string_len = strlen(string);
631 int suffix_len = strlen(suffix);
633 if (suffix_len > string_len)
636 return (strEqual(&string[string_len - suffix_len], suffix));
639 #define MAX_CHEAT_INPUT_LEN 32
641 static void HandleKeysSpecial(Key key)
643 static char cheat_input[2 * MAX_CHEAT_INPUT_LEN + 1] = "";
644 char letter = getCharFromKey(key);
645 int cheat_input_len = strlen(cheat_input);
651 if (cheat_input_len >= 2 * MAX_CHEAT_INPUT_LEN)
653 for (i = 0; i < MAX_CHEAT_INPUT_LEN + 1; i++)
654 cheat_input[i] = cheat_input[MAX_CHEAT_INPUT_LEN + i];
656 cheat_input_len = MAX_CHEAT_INPUT_LEN;
659 cheat_input[cheat_input_len++] = letter;
660 cheat_input[cheat_input_len] = '\0';
663 Error(ERR_DEBUG, "SPECIAL KEY '%s' [%d]\n", cheat_input, cheat_input_len);
666 if (game_status == GAME_MODE_MAIN)
668 if (is_string_suffix(cheat_input, ":insert-solution-tape") ||
669 is_string_suffix(cheat_input, ":ist"))
671 InsertSolutionTape();
673 else if (is_string_suffix(cheat_input, ":reload-graphics") ||
674 is_string_suffix(cheat_input, ":rg"))
676 ReloadCustomArtwork(1 << ARTWORK_TYPE_GRAPHICS);
679 else if (is_string_suffix(cheat_input, ":reload-sounds") ||
680 is_string_suffix(cheat_input, ":rs"))
682 ReloadCustomArtwork(1 << ARTWORK_TYPE_SOUNDS);
685 else if (is_string_suffix(cheat_input, ":reload-music") ||
686 is_string_suffix(cheat_input, ":rm"))
688 ReloadCustomArtwork(1 << ARTWORK_TYPE_MUSIC);
691 else if (is_string_suffix(cheat_input, ":reload-artwork") ||
692 is_string_suffix(cheat_input, ":ra"))
694 ReloadCustomArtwork(1 << ARTWORK_TYPE_GRAPHICS |
695 1 << ARTWORK_TYPE_SOUNDS |
696 1 << ARTWORK_TYPE_MUSIC);
699 else if (is_string_suffix(cheat_input, ":dump-level") ||
700 is_string_suffix(cheat_input, ":dl"))
704 else if (is_string_suffix(cheat_input, ":dump-tape") ||
705 is_string_suffix(cheat_input, ":dt"))
709 else if (is_string_suffix(cheat_input, ":save-native-level") ||
710 is_string_suffix(cheat_input, ":snl"))
712 SaveNativeLevel(&level);
715 else if (game_status == GAME_MODE_PLAYING)
718 if (is_string_suffix(cheat_input, ".q"))
719 DEBUG_SetMaximumDynamite();
722 else if (game_status == GAME_MODE_EDITOR)
724 if (is_string_suffix(cheat_input, ":dump-brush") ||
725 is_string_suffix(cheat_input, ":DB"))
729 else if (is_string_suffix(cheat_input, ":DDB"))
736 void HandleKey(Key key, int key_status)
738 boolean anyTextGadgetActiveOrJustFinished = anyTextGadgetActive();
739 static struct SetupKeyboardInfo ski;
740 static struct SetupShortcutInfo ssi;
749 { &ski.left, &ssi.snap_left, DEFAULT_KEY_LEFT, JOY_LEFT },
750 { &ski.right, &ssi.snap_right, DEFAULT_KEY_RIGHT, JOY_RIGHT },
751 { &ski.up, &ssi.snap_up, DEFAULT_KEY_UP, JOY_UP },
752 { &ski.down, &ssi.snap_down, DEFAULT_KEY_DOWN, JOY_DOWN },
753 { &ski.snap, NULL, DEFAULT_KEY_SNAP, JOY_BUTTON_SNAP },
754 { &ski.drop, NULL, DEFAULT_KEY_DROP, JOY_BUTTON_DROP }
759 if (game_status == GAME_MODE_PLAYING)
761 /* only needed for single-step tape recording mode */
762 static boolean clear_snap_button[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
763 static boolean clear_drop_button[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
764 static boolean element_snapped[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
765 static boolean element_dropped[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
768 for (pnr = 0; pnr < MAX_PLAYERS; pnr++)
772 if (setup.input[pnr].use_joystick)
775 ski = setup.input[pnr].key;
777 for (i = 0; i < NUM_PLAYER_ACTIONS; i++)
778 if (key == *key_info[i].key_custom)
779 key_action |= key_info[i].action;
781 /* use combined snap+direction keys for the first player only */
784 ssi = setup.shortcut;
786 for (i = 0; i < NUM_DIRECTIONS; i++)
787 if (key == *key_info[i].key_snap)
788 key_action |= key_info[i].action | JOY_BUTTON_SNAP;
791 /* clear delayed snap and drop actions in single step mode (see below) */
792 if (tape.single_step)
794 if (clear_snap_button[pnr])
796 stored_player[pnr].action &= ~KEY_BUTTON_SNAP;
797 clear_snap_button[pnr] = FALSE;
800 if (clear_drop_button[pnr])
802 stored_player[pnr].action &= ~KEY_BUTTON_DROP;
803 clear_drop_button[pnr] = FALSE;
807 if (key_status == KEY_PRESSED)
808 stored_player[pnr].action |= key_action;
810 stored_player[pnr].action &= ~key_action;
812 if (tape.single_step && tape.recording && tape.pausing)
814 if (key_status == KEY_PRESSED && key_action & KEY_MOTION)
816 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
818 /* if snap key already pressed, don't snap when releasing (below) */
819 if (stored_player[pnr].action & KEY_BUTTON_SNAP)
820 element_snapped[pnr] = TRUE;
822 /* if drop key already pressed, don't drop when releasing (below) */
823 if (stored_player[pnr].action & KEY_BUTTON_DROP)
824 element_dropped[pnr] = TRUE;
827 else if (key_status == KEY_PRESSED && key_action & KEY_BUTTON_DROP)
829 if (level.game_engine_type == GAME_ENGINE_TYPE_EM ||
830 level.game_engine_type == GAME_ENGINE_TYPE_SP)
833 printf("::: drop key pressed\n");
836 if (level.game_engine_type == GAME_ENGINE_TYPE_SP &&
837 getRedDiskReleaseFlag_SP() == 0)
838 stored_player[pnr].action &= ~KEY_BUTTON_DROP;
840 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
844 else if (key_status == KEY_RELEASED && key_action & KEY_BUTTON)
846 if (key_action & KEY_BUTTON_SNAP)
848 /* if snap key was released without moving (see above), snap now */
849 if (!element_snapped[pnr])
851 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
853 stored_player[pnr].action |= KEY_BUTTON_SNAP;
855 /* clear delayed snap button on next event */
856 clear_snap_button[pnr] = TRUE;
859 element_snapped[pnr] = FALSE;
863 if (key_action & KEY_BUTTON_DROP &&
864 level.game_engine_type == GAME_ENGINE_TYPE_RND)
866 /* if drop key was released without moving (see above), drop now */
867 if (!element_dropped[pnr])
869 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
871 if (level.game_engine_type != GAME_ENGINE_TYPE_SP ||
872 getRedDiskReleaseFlag_SP() != 0)
873 stored_player[pnr].action |= KEY_BUTTON_DROP;
875 /* clear delayed drop button on next event */
876 clear_drop_button[pnr] = TRUE;
879 element_dropped[pnr] = FALSE;
884 else if (tape.recording && tape.pausing)
886 /* prevent key release events from un-pausing a paused game */
887 if (key_status == KEY_PRESSED && key_action & KEY_ACTION)
888 TapeTogglePause(TAPE_TOGGLE_MANUAL);
894 for (i = 0; i < NUM_PLAYER_ACTIONS; i++)
895 if (key == key_info[i].key_default)
896 joy |= key_info[i].action;
901 if (key_status == KEY_PRESSED)
902 key_joystick_mapping |= joy;
904 key_joystick_mapping &= ~joy;
909 if (game_status != GAME_MODE_PLAYING)
910 key_joystick_mapping = 0;
912 if (key_status == KEY_RELEASED)
915 if ((key == KSYM_Return || key == KSYM_KP_Enter) &&
916 (GetKeyModState() & KMOD_Alt) && video.fullscreen_available)
918 setup.fullscreen = !setup.fullscreen;
920 ToggleFullscreenIfNeeded();
922 if (game_status == GAME_MODE_SETUP)
923 RedrawSetupScreenAfterFullscreenToggle();
929 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd &&
930 (key == KSYM_Return || key == setup.shortcut.toggle_pause))
932 if (game_status == GAME_MODE_PLAYING && AllPlayersGone &&
933 (key == KSYM_Return || key == setup.shortcut.toggle_pause))
941 if (game_status == GAME_MODE_MAIN &&
942 (key == setup.shortcut.toggle_pause || key == KSYM_space))
944 StartGameActions(options.network, setup.autorecord, level.random_seed);
949 if (game_status == GAME_MODE_MAIN || game_status == GAME_MODE_PLAYING)
951 if (key == setup.shortcut.save_game)
953 else if (key == setup.shortcut.load_game)
955 else if (key == setup.shortcut.toggle_pause)
956 TapeTogglePause(TAPE_TOGGLE_MANUAL);
958 HandleTapeButtonKeys(key);
959 HandleSoundButtonKeys(key);
962 if (game_status == GAME_MODE_PLAYING && !network_playing)
964 int centered_player_nr_next = -999;
966 if (key == setup.shortcut.focus_player_all)
967 centered_player_nr_next = -1;
969 for (i = 0; i < MAX_PLAYERS; i++)
970 if (key == setup.shortcut.focus_player[i])
971 centered_player_nr_next = i;
973 if (centered_player_nr_next != -999)
975 game.centered_player_nr_next = centered_player_nr_next;
976 game.set_centered_player = TRUE;
980 tape.centered_player_nr_next = game.centered_player_nr_next;
981 tape.set_centered_player = TRUE;
986 HandleKeysSpecial(key);
988 if (HandleGadgetsKeyInput(key))
990 if (key != KSYM_Escape) /* always allow ESC key to be handled */
991 key = KSYM_UNDEFINED;
996 case GAME_MODE_PSEUDO_TYPENAME:
997 HandleTypeName(0, key);
1000 case GAME_MODE_TITLE:
1001 case GAME_MODE_MAIN:
1002 case GAME_MODE_LEVELS:
1003 case GAME_MODE_LEVELNR:
1004 case GAME_MODE_SETUP:
1005 case GAME_MODE_INFO:
1006 case GAME_MODE_SCORES:
1011 if (game_status == GAME_MODE_TITLE)
1012 HandleTitleScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1013 else if (game_status == GAME_MODE_MAIN)
1014 HandleMainMenu(0, 0, 0, 0, MB_MENU_CHOICE);
1015 else if (game_status == GAME_MODE_LEVELS)
1016 HandleChooseLevelSet(0, 0, 0, 0, MB_MENU_CHOICE);
1017 else if (game_status == GAME_MODE_LEVELNR)
1018 HandleChooseLevelNr(0, 0, 0, 0, MB_MENU_CHOICE);
1019 else if (game_status == GAME_MODE_SETUP)
1020 HandleSetupScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1021 else if (game_status == GAME_MODE_INFO)
1022 HandleInfoScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1023 else if (game_status == GAME_MODE_SCORES)
1024 HandleHallOfFame(0, 0, 0, 0, MB_MENU_CHOICE);
1028 if (game_status != GAME_MODE_MAIN)
1029 FadeSkipNextFadeIn();
1031 if (game_status == GAME_MODE_TITLE)
1032 HandleTitleScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1033 else if (game_status == GAME_MODE_LEVELS)
1034 HandleChooseLevelSet(0, 0, 0, 0, MB_MENU_LEAVE);
1035 else if (game_status == GAME_MODE_LEVELNR)
1036 HandleChooseLevelNr(0, 0, 0, 0, MB_MENU_LEAVE);
1037 else if (game_status == GAME_MODE_SETUP)
1038 HandleSetupScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1039 else if (game_status == GAME_MODE_INFO)
1040 HandleInfoScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1041 else if (game_status == GAME_MODE_SCORES)
1042 HandleHallOfFame(0, 0, 0, 0, MB_MENU_LEAVE);
1046 if (game_status == GAME_MODE_LEVELS)
1047 HandleChooseLevelSet(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1048 else if (game_status == GAME_MODE_LEVELNR)
1049 HandleChooseLevelNr(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1050 else if (game_status == GAME_MODE_SETUP)
1051 HandleSetupScreen(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1052 else if (game_status == GAME_MODE_INFO)
1053 HandleInfoScreen(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1054 else if (game_status == GAME_MODE_SCORES)
1055 HandleHallOfFame(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1058 case KSYM_Page_Down:
1059 if (game_status == GAME_MODE_LEVELS)
1060 HandleChooseLevelSet(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1061 else if (game_status == GAME_MODE_LEVELNR)
1062 HandleChooseLevelNr(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1063 else if (game_status == GAME_MODE_SETUP)
1064 HandleSetupScreen(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1065 else if (game_status == GAME_MODE_INFO)
1066 HandleInfoScreen(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1067 else if (game_status == GAME_MODE_SCORES)
1068 HandleHallOfFame(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1073 GameFrameDelay = (GameFrameDelay == 500 ? GAME_FRAME_DELAY : 500);
1077 setup.sp_show_border_elements = !setup.sp_show_border_elements;
1078 printf("Supaplex border elements %s\n",
1079 setup.sp_show_border_elements ? "enabled" : "disabled");
1088 case GAME_MODE_EDITOR:
1089 if (!anyTextGadgetActiveOrJustFinished || key == KSYM_Escape)
1090 HandleLevelEditorKeyInput(key);
1093 case GAME_MODE_PLAYING:
1098 RequestQuitGame(setup.ask_on_escape);
1116 if (GameFrameDelay == 500)
1117 GameFrameDelay = GAME_FRAME_DELAY;
1119 GameFrameDelay = 500;
1122 GameFrameDelay = (key - KSYM_0) * 10;
1123 printf("Game speed == %d%% (%d ms delay between two frames)\n",
1124 GAME_FRAME_DELAY * 100 / GameFrameDelay, GameFrameDelay);
1130 options.debug = FALSE;
1131 printf("debug mode disabled\n");
1135 options.debug = TRUE;
1136 printf("debug mode enabled\n");
1141 if (!global.fps_slowdown)
1143 global.fps_slowdown = TRUE;
1144 global.fps_slowdown_factor = 2;
1145 printf("fps slowdown enabled -- display only every 2nd frame\n");
1147 else if (global.fps_slowdown_factor == 2)
1149 global.fps_slowdown_factor = 4;
1150 printf("fps slowdown enabled -- display only every 4th frame\n");
1154 global.fps_slowdown = FALSE;
1155 global.fps_slowdown_factor = 1;
1156 printf("fps slowdown disabled\n");
1161 ScrollStepSize = TILEX / 8;
1162 printf("ScrollStepSize == %d (1/8)\n", ScrollStepSize);
1166 ScrollStepSize = TILEX / 4;
1167 printf("ScrollStepSize == %d (1/4)\n", ScrollStepSize);
1171 ScrollStepSize = TILEX / 2;
1172 printf("ScrollStepSize == %d (1/2)\n", ScrollStepSize);
1176 ScrollStepSize = TILEX;
1177 printf("ScrollStepSize == %d (1/1)\n", ScrollStepSize);
1181 printf("::: currently using game engine version %d\n",
1182 game.engine_version);
1193 if (key == KSYM_Escape)
1195 game_status = GAME_MODE_MAIN;
1203 void HandleNoEvent()
1205 if (button_status && game_status != GAME_MODE_PLAYING)
1207 HandleButton(0, 0, -button_status, button_status);
1212 #if defined(NETWORK_AVALIABLE)
1213 if (options.network)
1220 static int HandleJoystickForAllPlayers()
1225 for (i = 0; i < MAX_PLAYERS; i++)
1227 byte joy_action = 0;
1230 if (!setup.input[i].use_joystick)
1234 joy_action = Joystick(i);
1235 result |= joy_action;
1237 if (!setup.input[i].use_joystick)
1240 stored_player[i].action = joy_action;
1246 void HandleJoystick()
1248 int joystick = HandleJoystickForAllPlayers();
1249 int keyboard = key_joystick_mapping;
1250 int joy = (joystick | keyboard);
1251 int left = joy & JOY_LEFT;
1252 int right = joy & JOY_RIGHT;
1253 int up = joy & JOY_UP;
1254 int down = joy & JOY_DOWN;
1255 int button = joy & JOY_BUTTON;
1256 int newbutton = (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED);
1257 int dx = (left ? -1 : right ? 1 : 0);
1258 int dy = (up ? -1 : down ? 1 : 0);
1260 switch (game_status)
1262 case GAME_MODE_TITLE:
1263 case GAME_MODE_MAIN:
1264 case GAME_MODE_LEVELS:
1265 case GAME_MODE_LEVELNR:
1266 case GAME_MODE_SETUP:
1267 case GAME_MODE_INFO:
1269 static unsigned int joystickmove_delay = 0;
1271 if (joystick && !button &&
1272 !DelayReached(&joystickmove_delay, GADGET_FRAME_DELAY))
1273 newbutton = dx = dy = 0;
1275 if (game_status == GAME_MODE_TITLE)
1276 HandleTitleScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1277 else if (game_status == GAME_MODE_MAIN)
1278 HandleMainMenu(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1279 else if (game_status == GAME_MODE_LEVELS)
1280 HandleChooseLevelSet(0,0,dx,dy,newbutton?MB_MENU_CHOICE : MB_MENU_MARK);
1281 else if (game_status == GAME_MODE_LEVELNR)
1282 HandleChooseLevelNr(0,0,dx,dy,newbutton? MB_MENU_CHOICE : MB_MENU_MARK);
1283 else if (game_status == GAME_MODE_SETUP)
1284 HandleSetupScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1285 else if (game_status == GAME_MODE_INFO)
1286 HandleInfoScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1290 case GAME_MODE_SCORES:
1291 HandleHallOfFame(0, 0, dx, dy, !newbutton);
1294 case GAME_MODE_EDITOR:
1295 HandleLevelEditorIdle();
1298 case GAME_MODE_PLAYING:
1299 if (tape.playing || keyboard)
1300 newbutton = ((joy & JOY_BUTTON) != 0);
1303 if (local_player->LevelSolved_GameEnd && newbutton)
1305 if (AllPlayersGone && newbutton)