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,
413 int x = (int)(event->x * video.width);
414 int y = (int)(event->y * video.height);
415 int button = MB_LEFTBUTTON;
417 Error(ERR_DEBUG, "=> screen x/y %d/%d", x, y);
421 if (++num_events >= max_events)
427 if (event->type == EVENT_FINGERPRESS ||
428 event->type == EVENT_FINGERMOTION)
429 button_status = button;
431 button_status = MB_RELEASED;
433 int max_x = SX + SXSIZE;
434 int max_y = SY + SYSIZE;
438 if (game_status == GAME_MODE_PLAYING)
440 if (game_status == GAME_MODE_PLAYING &&
444 int key_status = (event->type == EVENT_FINGERRELEASE ? KEY_RELEASED :
447 Key key = (event->y < 1.0 / 3.0 ? setup.input[0].key.up :
448 event->y > 2.0 / 3.0 ? setup.input[0].key.down :
449 event->x < 1.0 / 3.0 ? setup.input[0].key.left :
450 event->x > 2.0 / 3.0 ? setup.input[0].key.right :
451 setup.input[0].key.drop);
453 Key key = (y < max_y / 3 ? setup.input[0].key.up :
454 y > 2 * max_y / 3 ? setup.input[0].key.down :
455 x < max_x / 3 ? setup.input[0].key.left :
456 x > 2 * max_x / 3 ? setup.input[0].key.right :
457 setup.input[0].key.drop);
460 Error(ERR_DEBUG, "=> key == %d, key_status == %d", key, key_status);
462 HandleKey(key, key_status);
467 Error(ERR_DEBUG, "::: button_status == %d, button == %d\n",
468 button_status, button);
470 HandleButton(x, y, button_status, button);
477 void HandleKeyEvent(KeyEvent *event)
479 int key_status = (event->type == EVENT_KEYPRESS ? KEY_PRESSED : KEY_RELEASED);
480 boolean with_modifiers = (game_status == GAME_MODE_PLAYING ? FALSE : TRUE);
481 Key key = GetEventKey(event, with_modifiers);
482 Key keymod = (with_modifiers ? GetEventKey(event, FALSE) : key);
485 Error(ERR_DEBUG, "KEY EVENT: key was %s, keysym.scancode == %d, keysym.sym == %d, resulting key == %d (%s)",
486 event->type == EVENT_KEYPRESS ? "pressed" : "released",
487 event->keysym.scancode,
489 GetEventKey(event, TRUE),
490 getKeyNameFromKey(key));
494 if (key == KSYM_Menu)
495 Error(ERR_DEBUG, "menu key pressed");
496 else if (key == KSYM_Back)
497 Error(ERR_DEBUG, "back key pressed");
500 #if defined(PLATFORM_ANDROID)
501 // always map the "back" button to the "escape" key on Android devices
502 if (key == KSYM_Back)
506 HandleKeyModState(keymod, key_status);
507 HandleKey(key, key_status);
510 void HandleFocusEvent(FocusChangeEvent *event)
512 static int old_joystick_status = -1;
514 if (event->type == EVENT_FOCUSOUT)
516 KeyboardAutoRepeatOn();
517 old_joystick_status = joystick.status;
518 joystick.status = JOYSTICK_NOT_AVAILABLE;
522 else if (event->type == EVENT_FOCUSIN)
524 /* When there are two Rocks'n'Diamonds windows which overlap and
525 the player moves the pointer from one game window to the other,
526 a 'FocusOut' event is generated for the window the pointer is
527 leaving and a 'FocusIn' event is generated for the window the
528 pointer is entering. In some cases, it can happen that the
529 'FocusIn' event is handled by the one game process before the
530 'FocusOut' event by the other game process. In this case the
531 X11 environment would end up with activated keyboard auto repeat,
532 because unfortunately this is a global setting and not (which
533 would be far better) set for each X11 window individually.
534 The effect would be keyboard auto repeat while playing the game
535 (game_status == GAME_MODE_PLAYING), which is not desired.
536 To avoid this special case, we just wait 1/10 second before
537 processing the 'FocusIn' event.
540 if (game_status == GAME_MODE_PLAYING)
543 KeyboardAutoRepeatOffUnlessAutoplay();
546 if (old_joystick_status != -1)
547 joystick.status = old_joystick_status;
551 void HandleClientMessageEvent(ClientMessageEvent *event)
553 if (CheckCloseWindowEvent(event))
557 void HandleWindowManagerEvent(Event *event)
559 #if defined(TARGET_SDL)
560 SDLHandleWindowManagerEvent(event);
564 void HandleButton(int mx, int my, int button, int button_nr)
566 static int old_mx = 0, old_my = 0;
580 if (HandleGadgets(mx, my, button))
582 /* do not handle this button event anymore */
583 mx = my = -32; /* force mouse event to be outside screen tiles */
586 /* do not use scroll wheel button events for anything other than gadgets */
587 if (IS_WHEEL_BUTTON(button_nr))
590 Error(ERR_DEBUG, "::: game_status == %d", game_status);
594 case GAME_MODE_TITLE:
595 HandleTitleScreen(mx, my, 0, 0, button);
599 HandleMainMenu(mx, my, 0, 0, button);
602 case GAME_MODE_PSEUDO_TYPENAME:
603 HandleTypeName(0, KSYM_Return);
606 case GAME_MODE_LEVELS:
607 HandleChooseLevelSet(mx, my, 0, 0, button);
610 case GAME_MODE_LEVELNR:
611 HandleChooseLevelNr(mx, my, 0, 0, button);
614 case GAME_MODE_SCORES:
615 HandleHallOfFame(0, 0, 0, 0, button);
618 case GAME_MODE_EDITOR:
619 HandleLevelEditorIdle();
623 HandleInfoScreen(mx, my, 0, 0, button);
626 case GAME_MODE_SETUP:
627 HandleSetupScreen(mx, my, 0, 0, button);
630 case GAME_MODE_PLAYING:
632 if (button == MB_PRESSED && !motion_status && IN_GFX_SCREEN(mx, my))
633 DumpTile(LEVELX((mx - SX) / TILEX), LEVELY((my - SY) / TILEY));
642 static boolean is_string_suffix(char *string, char *suffix)
644 int string_len = strlen(string);
645 int suffix_len = strlen(suffix);
647 if (suffix_len > string_len)
650 return (strEqual(&string[string_len - suffix_len], suffix));
653 #define MAX_CHEAT_INPUT_LEN 32
655 static void HandleKeysSpecial(Key key)
657 static char cheat_input[2 * MAX_CHEAT_INPUT_LEN + 1] = "";
658 char letter = getCharFromKey(key);
659 int cheat_input_len = strlen(cheat_input);
665 if (cheat_input_len >= 2 * MAX_CHEAT_INPUT_LEN)
667 for (i = 0; i < MAX_CHEAT_INPUT_LEN + 1; i++)
668 cheat_input[i] = cheat_input[MAX_CHEAT_INPUT_LEN + i];
670 cheat_input_len = MAX_CHEAT_INPUT_LEN;
673 cheat_input[cheat_input_len++] = letter;
674 cheat_input[cheat_input_len] = '\0';
677 Error(ERR_DEBUG, "SPECIAL KEY '%s' [%d]\n", cheat_input, cheat_input_len);
680 if (game_status == GAME_MODE_MAIN)
682 if (is_string_suffix(cheat_input, ":insert-solution-tape") ||
683 is_string_suffix(cheat_input, ":ist"))
685 InsertSolutionTape();
687 else if (is_string_suffix(cheat_input, ":reload-graphics") ||
688 is_string_suffix(cheat_input, ":rg"))
690 ReloadCustomArtwork(1 << ARTWORK_TYPE_GRAPHICS);
693 else if (is_string_suffix(cheat_input, ":reload-sounds") ||
694 is_string_suffix(cheat_input, ":rs"))
696 ReloadCustomArtwork(1 << ARTWORK_TYPE_SOUNDS);
699 else if (is_string_suffix(cheat_input, ":reload-music") ||
700 is_string_suffix(cheat_input, ":rm"))
702 ReloadCustomArtwork(1 << ARTWORK_TYPE_MUSIC);
705 else if (is_string_suffix(cheat_input, ":reload-artwork") ||
706 is_string_suffix(cheat_input, ":ra"))
708 ReloadCustomArtwork(1 << ARTWORK_TYPE_GRAPHICS |
709 1 << ARTWORK_TYPE_SOUNDS |
710 1 << ARTWORK_TYPE_MUSIC);
713 else if (is_string_suffix(cheat_input, ":dump-level") ||
714 is_string_suffix(cheat_input, ":dl"))
718 else if (is_string_suffix(cheat_input, ":dump-tape") ||
719 is_string_suffix(cheat_input, ":dt"))
723 else if (is_string_suffix(cheat_input, ":save-native-level") ||
724 is_string_suffix(cheat_input, ":snl"))
726 SaveNativeLevel(&level);
729 else if (game_status == GAME_MODE_PLAYING)
732 if (is_string_suffix(cheat_input, ".q"))
733 DEBUG_SetMaximumDynamite();
736 else if (game_status == GAME_MODE_EDITOR)
738 if (is_string_suffix(cheat_input, ":dump-brush") ||
739 is_string_suffix(cheat_input, ":DB"))
743 else if (is_string_suffix(cheat_input, ":DDB"))
750 void HandleKey(Key key, int key_status)
752 boolean anyTextGadgetActiveOrJustFinished = anyTextGadgetActive();
753 static struct SetupKeyboardInfo ski;
754 static struct SetupShortcutInfo ssi;
763 { &ski.left, &ssi.snap_left, DEFAULT_KEY_LEFT, JOY_LEFT },
764 { &ski.right, &ssi.snap_right, DEFAULT_KEY_RIGHT, JOY_RIGHT },
765 { &ski.up, &ssi.snap_up, DEFAULT_KEY_UP, JOY_UP },
766 { &ski.down, &ssi.snap_down, DEFAULT_KEY_DOWN, JOY_DOWN },
767 { &ski.snap, NULL, DEFAULT_KEY_SNAP, JOY_BUTTON_SNAP },
768 { &ski.drop, NULL, DEFAULT_KEY_DROP, JOY_BUTTON_DROP }
773 if (game_status == GAME_MODE_PLAYING)
775 /* only needed for single-step tape recording mode */
776 static boolean clear_snap_button[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
777 static boolean clear_drop_button[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
778 static boolean element_snapped[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
779 static boolean element_dropped[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
782 for (pnr = 0; pnr < MAX_PLAYERS; pnr++)
786 if (setup.input[pnr].use_joystick)
789 ski = setup.input[pnr].key;
791 for (i = 0; i < NUM_PLAYER_ACTIONS; i++)
792 if (key == *key_info[i].key_custom)
793 key_action |= key_info[i].action;
795 /* use combined snap+direction keys for the first player only */
798 ssi = setup.shortcut;
800 for (i = 0; i < NUM_DIRECTIONS; i++)
801 if (key == *key_info[i].key_snap)
802 key_action |= key_info[i].action | JOY_BUTTON_SNAP;
805 /* clear delayed snap and drop actions in single step mode (see below) */
806 if (tape.single_step)
808 if (clear_snap_button[pnr])
810 stored_player[pnr].action &= ~KEY_BUTTON_SNAP;
811 clear_snap_button[pnr] = FALSE;
814 if (clear_drop_button[pnr])
816 stored_player[pnr].action &= ~KEY_BUTTON_DROP;
817 clear_drop_button[pnr] = FALSE;
821 if (key_status == KEY_PRESSED)
822 stored_player[pnr].action |= key_action;
824 stored_player[pnr].action &= ~key_action;
826 if (tape.single_step && tape.recording && tape.pausing)
828 if (key_status == KEY_PRESSED && key_action & KEY_MOTION)
830 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
832 /* if snap key already pressed, don't snap when releasing (below) */
833 if (stored_player[pnr].action & KEY_BUTTON_SNAP)
834 element_snapped[pnr] = TRUE;
836 /* if drop key already pressed, don't drop when releasing (below) */
837 if (stored_player[pnr].action & KEY_BUTTON_DROP)
838 element_dropped[pnr] = TRUE;
841 else if (key_status == KEY_PRESSED && key_action & KEY_BUTTON_DROP)
843 if (level.game_engine_type == GAME_ENGINE_TYPE_EM ||
844 level.game_engine_type == GAME_ENGINE_TYPE_SP)
847 printf("::: drop key pressed\n");
850 if (level.game_engine_type == GAME_ENGINE_TYPE_SP &&
851 getRedDiskReleaseFlag_SP() == 0)
852 stored_player[pnr].action &= ~KEY_BUTTON_DROP;
854 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
858 else if (key_status == KEY_RELEASED && key_action & KEY_BUTTON)
860 if (key_action & KEY_BUTTON_SNAP)
862 /* if snap key was released without moving (see above), snap now */
863 if (!element_snapped[pnr])
865 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
867 stored_player[pnr].action |= KEY_BUTTON_SNAP;
869 /* clear delayed snap button on next event */
870 clear_snap_button[pnr] = TRUE;
873 element_snapped[pnr] = FALSE;
877 if (key_action & KEY_BUTTON_DROP &&
878 level.game_engine_type == GAME_ENGINE_TYPE_RND)
880 /* if drop key was released without moving (see above), drop now */
881 if (!element_dropped[pnr])
883 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
885 if (level.game_engine_type != GAME_ENGINE_TYPE_SP ||
886 getRedDiskReleaseFlag_SP() != 0)
887 stored_player[pnr].action |= KEY_BUTTON_DROP;
889 /* clear delayed drop button on next event */
890 clear_drop_button[pnr] = TRUE;
893 element_dropped[pnr] = FALSE;
898 else if (tape.recording && tape.pausing)
900 /* prevent key release events from un-pausing a paused game */
901 if (key_status == KEY_PRESSED && key_action & KEY_ACTION)
902 TapeTogglePause(TAPE_TOGGLE_MANUAL);
908 for (i = 0; i < NUM_PLAYER_ACTIONS; i++)
909 if (key == key_info[i].key_default)
910 joy |= key_info[i].action;
915 if (key_status == KEY_PRESSED)
916 key_joystick_mapping |= joy;
918 key_joystick_mapping &= ~joy;
923 if (game_status != GAME_MODE_PLAYING)
924 key_joystick_mapping = 0;
926 if (key_status == KEY_RELEASED)
929 if ((key == KSYM_Return || key == KSYM_KP_Enter) &&
930 (GetKeyModState() & KMOD_Alt) && video.fullscreen_available)
932 setup.fullscreen = !setup.fullscreen;
934 ToggleFullscreenIfNeeded();
936 if (game_status == GAME_MODE_SETUP)
937 RedrawSetupScreenAfterFullscreenToggle();
943 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd &&
944 (key == KSYM_Return || key == setup.shortcut.toggle_pause))
946 if (game_status == GAME_MODE_PLAYING && AllPlayersGone &&
947 (key == KSYM_Return || key == setup.shortcut.toggle_pause))
955 if (game_status == GAME_MODE_MAIN &&
956 (key == setup.shortcut.toggle_pause || key == KSYM_space))
958 StartGameActions(options.network, setup.autorecord, level.random_seed);
963 if (game_status == GAME_MODE_MAIN || game_status == GAME_MODE_PLAYING)
965 if (key == setup.shortcut.save_game)
967 else if (key == setup.shortcut.load_game)
969 else if (key == setup.shortcut.toggle_pause)
970 TapeTogglePause(TAPE_TOGGLE_MANUAL);
972 HandleTapeButtonKeys(key);
973 HandleSoundButtonKeys(key);
976 if (game_status == GAME_MODE_PLAYING && !network_playing)
978 int centered_player_nr_next = -999;
980 if (key == setup.shortcut.focus_player_all)
981 centered_player_nr_next = -1;
983 for (i = 0; i < MAX_PLAYERS; i++)
984 if (key == setup.shortcut.focus_player[i])
985 centered_player_nr_next = i;
987 if (centered_player_nr_next != -999)
989 game.centered_player_nr_next = centered_player_nr_next;
990 game.set_centered_player = TRUE;
994 tape.centered_player_nr_next = game.centered_player_nr_next;
995 tape.set_centered_player = TRUE;
1000 HandleKeysSpecial(key);
1002 if (HandleGadgetsKeyInput(key))
1004 if (key != KSYM_Escape) /* always allow ESC key to be handled */
1005 key = KSYM_UNDEFINED;
1008 switch (game_status)
1010 case GAME_MODE_PSEUDO_TYPENAME:
1011 HandleTypeName(0, key);
1014 case GAME_MODE_TITLE:
1015 case GAME_MODE_MAIN:
1016 case GAME_MODE_LEVELS:
1017 case GAME_MODE_LEVELNR:
1018 case GAME_MODE_SETUP:
1019 case GAME_MODE_INFO:
1020 case GAME_MODE_SCORES:
1025 if (game_status == GAME_MODE_TITLE)
1026 HandleTitleScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1027 else if (game_status == GAME_MODE_MAIN)
1028 HandleMainMenu(0, 0, 0, 0, MB_MENU_CHOICE);
1029 else if (game_status == GAME_MODE_LEVELS)
1030 HandleChooseLevelSet(0, 0, 0, 0, MB_MENU_CHOICE);
1031 else if (game_status == GAME_MODE_LEVELNR)
1032 HandleChooseLevelNr(0, 0, 0, 0, MB_MENU_CHOICE);
1033 else if (game_status == GAME_MODE_SETUP)
1034 HandleSetupScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1035 else if (game_status == GAME_MODE_INFO)
1036 HandleInfoScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1037 else if (game_status == GAME_MODE_SCORES)
1038 HandleHallOfFame(0, 0, 0, 0, MB_MENU_CHOICE);
1042 if (game_status != GAME_MODE_MAIN)
1043 FadeSkipNextFadeIn();
1045 if (game_status == GAME_MODE_TITLE)
1046 HandleTitleScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1047 else if (game_status == GAME_MODE_LEVELS)
1048 HandleChooseLevelSet(0, 0, 0, 0, MB_MENU_LEAVE);
1049 else if (game_status == GAME_MODE_LEVELNR)
1050 HandleChooseLevelNr(0, 0, 0, 0, MB_MENU_LEAVE);
1051 else if (game_status == GAME_MODE_SETUP)
1052 HandleSetupScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1053 else if (game_status == GAME_MODE_INFO)
1054 HandleInfoScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1055 else if (game_status == GAME_MODE_SCORES)
1056 HandleHallOfFame(0, 0, 0, 0, MB_MENU_LEAVE);
1060 if (game_status == GAME_MODE_LEVELS)
1061 HandleChooseLevelSet(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1062 else if (game_status == GAME_MODE_LEVELNR)
1063 HandleChooseLevelNr(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1064 else if (game_status == GAME_MODE_SETUP)
1065 HandleSetupScreen(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1066 else if (game_status == GAME_MODE_INFO)
1067 HandleInfoScreen(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1068 else if (game_status == GAME_MODE_SCORES)
1069 HandleHallOfFame(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1072 case KSYM_Page_Down:
1073 if (game_status == GAME_MODE_LEVELS)
1074 HandleChooseLevelSet(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1075 else if (game_status == GAME_MODE_LEVELNR)
1076 HandleChooseLevelNr(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1077 else if (game_status == GAME_MODE_SETUP)
1078 HandleSetupScreen(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1079 else if (game_status == GAME_MODE_INFO)
1080 HandleInfoScreen(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1081 else if (game_status == GAME_MODE_SCORES)
1082 HandleHallOfFame(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1087 GameFrameDelay = (GameFrameDelay == 500 ? GAME_FRAME_DELAY : 500);
1091 setup.sp_show_border_elements = !setup.sp_show_border_elements;
1092 printf("Supaplex border elements %s\n",
1093 setup.sp_show_border_elements ? "enabled" : "disabled");
1102 case GAME_MODE_EDITOR:
1103 if (!anyTextGadgetActiveOrJustFinished || key == KSYM_Escape)
1104 HandleLevelEditorKeyInput(key);
1107 case GAME_MODE_PLAYING:
1112 RequestQuitGame(setup.ask_on_escape);
1130 if (GameFrameDelay == 500)
1131 GameFrameDelay = GAME_FRAME_DELAY;
1133 GameFrameDelay = 500;
1136 GameFrameDelay = (key - KSYM_0) * 10;
1137 printf("Game speed == %d%% (%d ms delay between two frames)\n",
1138 GAME_FRAME_DELAY * 100 / GameFrameDelay, GameFrameDelay);
1144 options.debug = FALSE;
1145 printf("debug mode disabled\n");
1149 options.debug = TRUE;
1150 printf("debug mode enabled\n");
1155 if (!global.fps_slowdown)
1157 global.fps_slowdown = TRUE;
1158 global.fps_slowdown_factor = 2;
1159 printf("fps slowdown enabled -- display only every 2nd frame\n");
1161 else if (global.fps_slowdown_factor == 2)
1163 global.fps_slowdown_factor = 4;
1164 printf("fps slowdown enabled -- display only every 4th frame\n");
1168 global.fps_slowdown = FALSE;
1169 global.fps_slowdown_factor = 1;
1170 printf("fps slowdown disabled\n");
1175 ScrollStepSize = TILEX / 8;
1176 printf("ScrollStepSize == %d (1/8)\n", ScrollStepSize);
1180 ScrollStepSize = TILEX / 4;
1181 printf("ScrollStepSize == %d (1/4)\n", ScrollStepSize);
1185 ScrollStepSize = TILEX / 2;
1186 printf("ScrollStepSize == %d (1/2)\n", ScrollStepSize);
1190 ScrollStepSize = TILEX;
1191 printf("ScrollStepSize == %d (1/1)\n", ScrollStepSize);
1195 printf("::: currently using game engine version %d\n",
1196 game.engine_version);
1207 if (key == KSYM_Escape)
1209 game_status = GAME_MODE_MAIN;
1217 void HandleNoEvent()
1219 if (button_status && game_status != GAME_MODE_PLAYING)
1221 HandleButton(0, 0, -button_status, button_status);
1226 #if defined(NETWORK_AVALIABLE)
1227 if (options.network)
1234 static int HandleJoystickForAllPlayers()
1239 for (i = 0; i < MAX_PLAYERS; i++)
1241 byte joy_action = 0;
1244 if (!setup.input[i].use_joystick)
1248 joy_action = Joystick(i);
1249 result |= joy_action;
1251 if (!setup.input[i].use_joystick)
1254 stored_player[i].action = joy_action;
1260 void HandleJoystick()
1262 int joystick = HandleJoystickForAllPlayers();
1263 int keyboard = key_joystick_mapping;
1264 int joy = (joystick | keyboard);
1265 int left = joy & JOY_LEFT;
1266 int right = joy & JOY_RIGHT;
1267 int up = joy & JOY_UP;
1268 int down = joy & JOY_DOWN;
1269 int button = joy & JOY_BUTTON;
1270 int newbutton = (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED);
1271 int dx = (left ? -1 : right ? 1 : 0);
1272 int dy = (up ? -1 : down ? 1 : 0);
1274 switch (game_status)
1276 case GAME_MODE_TITLE:
1277 case GAME_MODE_MAIN:
1278 case GAME_MODE_LEVELS:
1279 case GAME_MODE_LEVELNR:
1280 case GAME_MODE_SETUP:
1281 case GAME_MODE_INFO:
1283 static unsigned int joystickmove_delay = 0;
1285 if (joystick && !button &&
1286 !DelayReached(&joystickmove_delay, GADGET_FRAME_DELAY))
1287 newbutton = dx = dy = 0;
1289 if (game_status == GAME_MODE_TITLE)
1290 HandleTitleScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1291 else if (game_status == GAME_MODE_MAIN)
1292 HandleMainMenu(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1293 else if (game_status == GAME_MODE_LEVELS)
1294 HandleChooseLevelSet(0,0,dx,dy,newbutton?MB_MENU_CHOICE : MB_MENU_MARK);
1295 else if (game_status == GAME_MODE_LEVELNR)
1296 HandleChooseLevelNr(0,0,dx,dy,newbutton? MB_MENU_CHOICE : MB_MENU_MARK);
1297 else if (game_status == GAME_MODE_SETUP)
1298 HandleSetupScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1299 else if (game_status == GAME_MODE_INFO)
1300 HandleInfoScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1304 case GAME_MODE_SCORES:
1305 HandleHallOfFame(0, 0, dx, dy, !newbutton);
1308 case GAME_MODE_EDITOR:
1309 HandleLevelEditorIdle();
1312 case GAME_MODE_PLAYING:
1313 if (tape.playing || keyboard)
1314 newbutton = ((joy & JOY_BUTTON) != 0);
1317 if (local_player->LevelSolved_GameEnd && newbutton)
1319 if (AllPlayersGone && newbutton)