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 #if defined(PLATFORM_ANDROID)
162 case EVENT_BUTTONPRESS:
163 case EVENT_BUTTONRELEASE:
164 HandleButtonEvent((ButtonEvent *) &event);
167 case EVENT_MOTIONNOTIFY:
168 HandleMotionEvent((MotionEvent *) &event);
172 case EVENT_KEYRELEASE:
173 HandleKeyEvent((KeyEvent *) &event);
177 HandleOtherEvents(&event);
184 /* when playing, display a special mouse pointer inside the playfield */
185 if (game_status == GAME_MODE_PLAYING && !tape.pausing)
187 if (!playfield_cursor_set && cursor_inside_playfield &&
188 DelayReached(&playfield_cursor_delay, 1000))
190 SetMouseCursor(CURSOR_PLAYFIELD);
191 playfield_cursor_set = TRUE;
194 else if (playfield_cursor_set)
196 SetMouseCursor(CURSOR_DEFAULT);
197 playfield_cursor_set = FALSE;
203 /* don't use all CPU time when idle; the main loop while playing
204 has its own synchronization and is CPU friendly, too */
206 if (game_status == GAME_MODE_PLAYING)
213 if (!PendingEvent()) /* delay only if no pending events */
217 /* refresh window contents from drawing buffer, if needed */
220 if (game_status == GAME_MODE_QUIT)
225 void HandleOtherEvents(Event *event)
230 HandleExposeEvent((ExposeEvent *) event);
233 case EVENT_UNMAPNOTIFY:
235 /* This causes the game to stop not only when iconified, but also
236 when on another virtual desktop, which might be not desired. */
237 SleepWhileUnmapped();
243 HandleFocusEvent((FocusChangeEvent *) event);
246 case EVENT_CLIENTMESSAGE:
247 HandleClientMessageEvent((ClientMessageEvent *) event);
250 #if defined(TARGET_SDL)
251 case SDL_JOYAXISMOTION:
252 case SDL_JOYBUTTONDOWN:
253 case SDL_JOYBUTTONUP:
254 HandleJoystickEvent(event);
258 HandleWindowManagerEvent(event);
267 void ClearEventQueue()
269 while (PendingEvent())
277 case EVENT_BUTTONRELEASE:
278 button_status = MB_RELEASED;
281 case EVENT_KEYRELEASE:
285 key_joystick_mapping = 0;
290 HandleOtherEvents(&event);
296 void ClearPlayerAction()
300 /* simulate key release events for still pressed keys */
301 key_joystick_mapping = 0;
302 for (i = 0; i < MAX_PLAYERS; i++)
303 stored_player[i].action = 0;
306 void SleepWhileUnmapped()
308 boolean window_unmapped = TRUE;
310 KeyboardAutoRepeatOn();
312 while (window_unmapped)
320 case EVENT_BUTTONRELEASE:
321 button_status = MB_RELEASED;
324 case EVENT_KEYRELEASE:
325 key_joystick_mapping = 0;
328 case EVENT_MAPNOTIFY:
329 window_unmapped = FALSE;
332 case EVENT_UNMAPNOTIFY:
333 /* this is only to surely prevent the 'should not happen' case
334 * of recursively looping between 'SleepWhileUnmapped()' and
335 * 'HandleOtherEvents()' which usually calls this funtion.
340 HandleOtherEvents(&event);
345 if (game_status == GAME_MODE_PLAYING)
346 KeyboardAutoRepeatOffUnlessAutoplay();
349 void HandleExposeEvent(ExposeEvent *event)
351 #if !defined(TARGET_SDL)
352 RedrawPlayfield(FALSE, event->x, event->y, event->width, event->height);
357 void HandleButtonEvent(ButtonEvent *event)
360 printf("::: BUTTON EVENT: button %d %s\n", event->button,
361 event->type == EVENT_BUTTONPRESS ? "pressed" : "released");
364 motion_status = FALSE;
366 if (event->type == EVENT_BUTTONPRESS)
367 button_status = event->button;
369 button_status = MB_RELEASED;
371 HandleButton(event->x, event->y, button_status, event->button);
374 void HandleMotionEvent(MotionEvent *event)
376 if (!PointerInWindow(window))
377 return; /* window and pointer are on different screens */
379 if (button_status == MB_RELEASED && game_status != GAME_MODE_EDITOR)
382 motion_status = TRUE;
384 HandleButton(event->x, event->y, button_status, button_status);
387 void HandleKeyEvent(KeyEvent *event)
389 int key_status = (event->type==EVENT_KEYPRESS ? KEY_PRESSED : KEY_RELEASED);
390 boolean with_modifiers = (game_status == GAME_MODE_PLAYING ? FALSE : TRUE);
391 Key key = GetEventKey(event, with_modifiers);
392 Key keymod = (with_modifiers ? GetEventKey(event, FALSE) : key);
395 printf("::: KEY EVENT: %d %s\n", GetEventKey(event, TRUE),
396 event->type == EVENT_KEYPRESS ? "pressed" : "released");
399 HandleKeyModState(keymod, key_status);
400 HandleKey(key, key_status);
403 void HandleFocusEvent(FocusChangeEvent *event)
405 static int old_joystick_status = -1;
407 if (event->type == EVENT_FOCUSOUT)
409 KeyboardAutoRepeatOn();
410 old_joystick_status = joystick.status;
411 joystick.status = JOYSTICK_NOT_AVAILABLE;
415 else if (event->type == EVENT_FOCUSIN)
417 /* When there are two Rocks'n'Diamonds windows which overlap and
418 the player moves the pointer from one game window to the other,
419 a 'FocusOut' event is generated for the window the pointer is
420 leaving and a 'FocusIn' event is generated for the window the
421 pointer is entering. In some cases, it can happen that the
422 'FocusIn' event is handled by the one game process before the
423 'FocusOut' event by the other game process. In this case the
424 X11 environment would end up with activated keyboard auto repeat,
425 because unfortunately this is a global setting and not (which
426 would be far better) set for each X11 window individually.
427 The effect would be keyboard auto repeat while playing the game
428 (game_status == GAME_MODE_PLAYING), which is not desired.
429 To avoid this special case, we just wait 1/10 second before
430 processing the 'FocusIn' event.
433 if (game_status == GAME_MODE_PLAYING)
436 KeyboardAutoRepeatOffUnlessAutoplay();
439 if (old_joystick_status != -1)
440 joystick.status = old_joystick_status;
444 void HandleClientMessageEvent(ClientMessageEvent *event)
446 if (CheckCloseWindowEvent(event))
450 void HandleWindowManagerEvent(Event *event)
452 #if defined(TARGET_SDL)
453 SDLHandleWindowManagerEvent(event);
457 void HandleButton(int mx, int my, int button, int button_nr)
459 static int old_mx = 0, old_my = 0;
473 if (HandleGadgets(mx, my, button))
475 /* do not handle this button event anymore */
476 mx = my = -32; /* force mouse event to be outside screen tiles */
479 /* do not use scroll wheel button events for anything other than gadgets */
480 if (IS_WHEEL_BUTTON(button_nr))
485 case GAME_MODE_TITLE:
486 HandleTitleScreen(mx, my, 0, 0, button);
490 HandleMainMenu(mx, my, 0, 0, button);
493 case GAME_MODE_PSEUDO_TYPENAME:
494 HandleTypeName(0, KSYM_Return);
497 case GAME_MODE_LEVELS:
498 HandleChooseLevelSet(mx, my, 0, 0, button);
501 case GAME_MODE_LEVELNR:
502 HandleChooseLevelNr(mx, my, 0, 0, button);
505 case GAME_MODE_SCORES:
506 HandleHallOfFame(0, 0, 0, 0, button);
509 case GAME_MODE_EDITOR:
510 HandleLevelEditorIdle();
514 HandleInfoScreen(mx, my, 0, 0, button);
517 case GAME_MODE_SETUP:
518 HandleSetupScreen(mx, my, 0, 0, button);
521 case GAME_MODE_PLAYING:
523 if (button == MB_PRESSED && !motion_status && IN_GFX_SCREEN(mx, my))
524 DumpTile(LEVELX((mx - SX) / TILEX), LEVELY((my - SY) / TILEY));
533 static boolean is_string_suffix(char *string, char *suffix)
535 int string_len = strlen(string);
536 int suffix_len = strlen(suffix);
538 if (suffix_len > string_len)
541 return (strEqual(&string[string_len - suffix_len], suffix));
544 #define MAX_CHEAT_INPUT_LEN 32
546 static void HandleKeysSpecial(Key key)
548 static char cheat_input[2 * MAX_CHEAT_INPUT_LEN + 1] = "";
549 char letter = getCharFromKey(key);
550 int cheat_input_len = strlen(cheat_input);
556 if (cheat_input_len >= 2 * MAX_CHEAT_INPUT_LEN)
558 for (i = 0; i < MAX_CHEAT_INPUT_LEN + 1; i++)
559 cheat_input[i] = cheat_input[MAX_CHEAT_INPUT_LEN + i];
561 cheat_input_len = MAX_CHEAT_INPUT_LEN;
564 cheat_input[cheat_input_len++] = letter;
565 cheat_input[cheat_input_len] = '\0';
568 printf("::: '%s' [%d]\n", cheat_input, cheat_input_len);
571 if (game_status == GAME_MODE_MAIN)
573 if (is_string_suffix(cheat_input, ":insert-solution-tape") ||
574 is_string_suffix(cheat_input, ":ist"))
576 InsertSolutionTape();
578 else if (is_string_suffix(cheat_input, ":reload-graphics") ||
579 is_string_suffix(cheat_input, ":rg"))
581 ReloadCustomArtwork(1 << ARTWORK_TYPE_GRAPHICS);
584 else if (is_string_suffix(cheat_input, ":reload-sounds") ||
585 is_string_suffix(cheat_input, ":rs"))
587 ReloadCustomArtwork(1 << ARTWORK_TYPE_SOUNDS);
590 else if (is_string_suffix(cheat_input, ":reload-music") ||
591 is_string_suffix(cheat_input, ":rm"))
593 ReloadCustomArtwork(1 << ARTWORK_TYPE_MUSIC);
596 else if (is_string_suffix(cheat_input, ":reload-artwork") ||
597 is_string_suffix(cheat_input, ":ra"))
599 ReloadCustomArtwork(1 << ARTWORK_TYPE_GRAPHICS |
600 1 << ARTWORK_TYPE_SOUNDS |
601 1 << ARTWORK_TYPE_MUSIC);
604 else if (is_string_suffix(cheat_input, ":dump-level") ||
605 is_string_suffix(cheat_input, ":dl"))
609 else if (is_string_suffix(cheat_input, ":dump-tape") ||
610 is_string_suffix(cheat_input, ":dt"))
614 else if (is_string_suffix(cheat_input, ":save-native-level") ||
615 is_string_suffix(cheat_input, ":snl"))
617 SaveNativeLevel(&level);
620 else if (game_status == GAME_MODE_PLAYING)
623 if (is_string_suffix(cheat_input, ".q"))
624 DEBUG_SetMaximumDynamite();
627 else if (game_status == GAME_MODE_EDITOR)
629 if (is_string_suffix(cheat_input, ":dump-brush") ||
630 is_string_suffix(cheat_input, ":DB"))
634 else if (is_string_suffix(cheat_input, ":DDB"))
641 void HandleKey(Key key, int key_status)
643 boolean anyTextGadgetActiveOrJustFinished = anyTextGadgetActive();
644 static struct SetupKeyboardInfo ski;
645 static struct SetupShortcutInfo ssi;
654 { &ski.left, &ssi.snap_left, DEFAULT_KEY_LEFT, JOY_LEFT },
655 { &ski.right, &ssi.snap_right, DEFAULT_KEY_RIGHT, JOY_RIGHT },
656 { &ski.up, &ssi.snap_up, DEFAULT_KEY_UP, JOY_UP },
657 { &ski.down, &ssi.snap_down, DEFAULT_KEY_DOWN, JOY_DOWN },
658 { &ski.snap, NULL, DEFAULT_KEY_SNAP, JOY_BUTTON_SNAP },
659 { &ski.drop, NULL, DEFAULT_KEY_DROP, JOY_BUTTON_DROP }
664 if (game_status == GAME_MODE_PLAYING)
666 /* only needed for single-step tape recording mode */
667 static boolean clear_snap_button[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
668 static boolean clear_drop_button[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
669 static boolean element_snapped[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
670 static boolean element_dropped[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
673 for (pnr = 0; pnr < MAX_PLAYERS; pnr++)
677 if (setup.input[pnr].use_joystick)
680 ski = setup.input[pnr].key;
682 for (i = 0; i < NUM_PLAYER_ACTIONS; i++)
683 if (key == *key_info[i].key_custom)
684 key_action |= key_info[i].action;
686 /* use combined snap+direction keys for the first player only */
689 ssi = setup.shortcut;
691 for (i = 0; i < NUM_DIRECTIONS; i++)
692 if (key == *key_info[i].key_snap)
693 key_action |= key_info[i].action | JOY_BUTTON_SNAP;
696 /* clear delayed snap and drop actions in single step mode (see below) */
697 if (tape.single_step)
699 if (clear_snap_button[pnr])
701 stored_player[pnr].action &= ~KEY_BUTTON_SNAP;
702 clear_snap_button[pnr] = FALSE;
705 if (clear_drop_button[pnr])
707 stored_player[pnr].action &= ~KEY_BUTTON_DROP;
708 clear_drop_button[pnr] = FALSE;
712 if (key_status == KEY_PRESSED)
713 stored_player[pnr].action |= key_action;
715 stored_player[pnr].action &= ~key_action;
717 if (tape.single_step && tape.recording && tape.pausing)
719 if (key_status == KEY_PRESSED && key_action & KEY_MOTION)
721 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
723 /* if snap key already pressed, don't snap when releasing (below) */
724 if (stored_player[pnr].action & KEY_BUTTON_SNAP)
725 element_snapped[pnr] = TRUE;
727 /* if drop key already pressed, don't drop when releasing (below) */
728 if (stored_player[pnr].action & KEY_BUTTON_DROP)
729 element_dropped[pnr] = TRUE;
732 else if (key_status == KEY_PRESSED && key_action & KEY_BUTTON_DROP)
734 if (level.game_engine_type == GAME_ENGINE_TYPE_EM ||
735 level.game_engine_type == GAME_ENGINE_TYPE_SP)
738 printf("::: drop key pressed\n");
741 if (level.game_engine_type == GAME_ENGINE_TYPE_SP &&
742 getRedDiskReleaseFlag_SP() == 0)
743 stored_player[pnr].action &= ~KEY_BUTTON_DROP;
745 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
749 else if (key_status == KEY_RELEASED && key_action & KEY_BUTTON)
751 if (key_action & KEY_BUTTON_SNAP)
753 /* if snap key was released without moving (see above), snap now */
754 if (!element_snapped[pnr])
756 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
758 stored_player[pnr].action |= KEY_BUTTON_SNAP;
760 /* clear delayed snap button on next event */
761 clear_snap_button[pnr] = TRUE;
764 element_snapped[pnr] = FALSE;
768 if (key_action & KEY_BUTTON_DROP &&
769 level.game_engine_type == GAME_ENGINE_TYPE_RND)
771 /* if drop key was released without moving (see above), drop now */
772 if (!element_dropped[pnr])
774 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
776 if (level.game_engine_type != GAME_ENGINE_TYPE_SP ||
777 getRedDiskReleaseFlag_SP() != 0)
778 stored_player[pnr].action |= KEY_BUTTON_DROP;
780 /* clear delayed drop button on next event */
781 clear_drop_button[pnr] = TRUE;
784 element_dropped[pnr] = FALSE;
789 else if (tape.recording && tape.pausing)
791 /* prevent key release events from un-pausing a paused game */
792 if (key_status == KEY_PRESSED && key_action & KEY_ACTION)
793 TapeTogglePause(TAPE_TOGGLE_MANUAL);
799 for (i = 0; i < NUM_PLAYER_ACTIONS; i++)
800 if (key == key_info[i].key_default)
801 joy |= key_info[i].action;
806 if (key_status == KEY_PRESSED)
807 key_joystick_mapping |= joy;
809 key_joystick_mapping &= ~joy;
814 if (game_status != GAME_MODE_PLAYING)
815 key_joystick_mapping = 0;
817 if (key_status == KEY_RELEASED)
820 if ((key == KSYM_Return || key == KSYM_KP_Enter) &&
821 (GetKeyModState() & KMOD_Alt) && video.fullscreen_available)
823 setup.fullscreen = !setup.fullscreen;
825 ToggleFullscreenIfNeeded();
827 if (game_status == GAME_MODE_SETUP)
828 RedrawSetupScreenAfterFullscreenToggle();
834 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd &&
835 (key == KSYM_Return || key == setup.shortcut.toggle_pause))
837 if (game_status == GAME_MODE_PLAYING && AllPlayersGone &&
838 (key == KSYM_Return || key == setup.shortcut.toggle_pause))
846 if (game_status == GAME_MODE_MAIN &&
847 (key == setup.shortcut.toggle_pause || key == KSYM_space))
849 StartGameActions(options.network, setup.autorecord, level.random_seed);
854 if (game_status == GAME_MODE_MAIN || game_status == GAME_MODE_PLAYING)
856 if (key == setup.shortcut.save_game)
858 else if (key == setup.shortcut.load_game)
860 else if (key == setup.shortcut.toggle_pause)
861 TapeTogglePause(TAPE_TOGGLE_MANUAL);
863 HandleTapeButtonKeys(key);
864 HandleSoundButtonKeys(key);
867 if (game_status == GAME_MODE_PLAYING && !network_playing)
869 int centered_player_nr_next = -999;
871 if (key == setup.shortcut.focus_player_all)
872 centered_player_nr_next = -1;
874 for (i = 0; i < MAX_PLAYERS; i++)
875 if (key == setup.shortcut.focus_player[i])
876 centered_player_nr_next = i;
878 if (centered_player_nr_next != -999)
880 game.centered_player_nr_next = centered_player_nr_next;
881 game.set_centered_player = TRUE;
885 tape.centered_player_nr_next = game.centered_player_nr_next;
886 tape.set_centered_player = TRUE;
891 HandleKeysSpecial(key);
893 if (HandleGadgetsKeyInput(key))
895 if (key != KSYM_Escape) /* always allow ESC key to be handled */
896 key = KSYM_UNDEFINED;
901 case GAME_MODE_PSEUDO_TYPENAME:
902 HandleTypeName(0, key);
905 case GAME_MODE_TITLE:
907 case GAME_MODE_LEVELS:
908 case GAME_MODE_LEVELNR:
909 case GAME_MODE_SETUP:
911 case GAME_MODE_SCORES:
916 if (game_status == GAME_MODE_TITLE)
917 HandleTitleScreen(0, 0, 0, 0, MB_MENU_CHOICE);
918 else if (game_status == GAME_MODE_MAIN)
919 HandleMainMenu(0, 0, 0, 0, MB_MENU_CHOICE);
920 else if (game_status == GAME_MODE_LEVELS)
921 HandleChooseLevelSet(0, 0, 0, 0, MB_MENU_CHOICE);
922 else if (game_status == GAME_MODE_LEVELNR)
923 HandleChooseLevelNr(0, 0, 0, 0, MB_MENU_CHOICE);
924 else if (game_status == GAME_MODE_SETUP)
925 HandleSetupScreen(0, 0, 0, 0, MB_MENU_CHOICE);
926 else if (game_status == GAME_MODE_INFO)
927 HandleInfoScreen(0, 0, 0, 0, MB_MENU_CHOICE);
928 else if (game_status == GAME_MODE_SCORES)
929 HandleHallOfFame(0, 0, 0, 0, MB_MENU_CHOICE);
933 if (game_status != GAME_MODE_MAIN)
934 FadeSkipNextFadeIn();
936 if (game_status == GAME_MODE_TITLE)
937 HandleTitleScreen(0, 0, 0, 0, MB_MENU_LEAVE);
938 else if (game_status == GAME_MODE_LEVELS)
939 HandleChooseLevelSet(0, 0, 0, 0, MB_MENU_LEAVE);
940 else if (game_status == GAME_MODE_LEVELNR)
941 HandleChooseLevelNr(0, 0, 0, 0, MB_MENU_LEAVE);
942 else if (game_status == GAME_MODE_SETUP)
943 HandleSetupScreen(0, 0, 0, 0, MB_MENU_LEAVE);
944 else if (game_status == GAME_MODE_INFO)
945 HandleInfoScreen(0, 0, 0, 0, MB_MENU_LEAVE);
946 else if (game_status == GAME_MODE_SCORES)
947 HandleHallOfFame(0, 0, 0, 0, MB_MENU_LEAVE);
951 if (game_status == GAME_MODE_LEVELS)
952 HandleChooseLevelSet(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
953 else if (game_status == GAME_MODE_LEVELNR)
954 HandleChooseLevelNr(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
955 else if (game_status == GAME_MODE_SETUP)
956 HandleSetupScreen(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
957 else if (game_status == GAME_MODE_INFO)
958 HandleInfoScreen(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
959 else if (game_status == GAME_MODE_SCORES)
960 HandleHallOfFame(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
964 if (game_status == GAME_MODE_LEVELS)
965 HandleChooseLevelSet(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
966 else if (game_status == GAME_MODE_LEVELNR)
967 HandleChooseLevelNr(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
968 else if (game_status == GAME_MODE_SETUP)
969 HandleSetupScreen(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
970 else if (game_status == GAME_MODE_INFO)
971 HandleInfoScreen(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
972 else if (game_status == GAME_MODE_SCORES)
973 HandleHallOfFame(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
978 GameFrameDelay = (GameFrameDelay == 500 ? GAME_FRAME_DELAY : 500);
982 setup.sp_show_border_elements = !setup.sp_show_border_elements;
983 printf("Supaplex border elements %s\n",
984 setup.sp_show_border_elements ? "enabled" : "disabled");
993 case GAME_MODE_EDITOR:
994 if (!anyTextGadgetActiveOrJustFinished || key == KSYM_Escape)
995 HandleLevelEditorKeyInput(key);
998 case GAME_MODE_PLAYING:
1003 RequestQuitGame(setup.ask_on_escape);
1021 if (GameFrameDelay == 500)
1022 GameFrameDelay = GAME_FRAME_DELAY;
1024 GameFrameDelay = 500;
1027 GameFrameDelay = (key - KSYM_0) * 10;
1028 printf("Game speed == %d%% (%d ms delay between two frames)\n",
1029 GAME_FRAME_DELAY * 100 / GameFrameDelay, GameFrameDelay);
1035 options.debug = FALSE;
1036 printf("debug mode disabled\n");
1040 options.debug = TRUE;
1041 printf("debug mode enabled\n");
1046 if (!global.fps_slowdown)
1048 global.fps_slowdown = TRUE;
1049 global.fps_slowdown_factor = 2;
1050 printf("fps slowdown enabled -- display only every 2nd frame\n");
1052 else if (global.fps_slowdown_factor == 2)
1054 global.fps_slowdown_factor = 4;
1055 printf("fps slowdown enabled -- display only every 4th frame\n");
1059 global.fps_slowdown = FALSE;
1060 global.fps_slowdown_factor = 1;
1061 printf("fps slowdown disabled\n");
1066 ScrollStepSize = TILEX / 8;
1067 printf("ScrollStepSize == %d (1/8)\n", ScrollStepSize);
1071 ScrollStepSize = TILEX / 4;
1072 printf("ScrollStepSize == %d (1/4)\n", ScrollStepSize);
1076 ScrollStepSize = TILEX / 2;
1077 printf("ScrollStepSize == %d (1/2)\n", ScrollStepSize);
1081 ScrollStepSize = TILEX;
1082 printf("ScrollStepSize == %d (1/1)\n", ScrollStepSize);
1086 printf("::: currently using game engine version %d\n",
1087 game.engine_version);
1098 if (key == KSYM_Escape)
1100 game_status = GAME_MODE_MAIN;
1108 void HandleNoEvent()
1110 if (button_status && game_status != GAME_MODE_PLAYING)
1112 HandleButton(0, 0, -button_status, button_status);
1117 #if defined(NETWORK_AVALIABLE)
1118 if (options.network)
1125 static int HandleJoystickForAllPlayers()
1130 for (i = 0; i < MAX_PLAYERS; i++)
1132 byte joy_action = 0;
1135 if (!setup.input[i].use_joystick)
1139 joy_action = Joystick(i);
1140 result |= joy_action;
1142 if (!setup.input[i].use_joystick)
1145 stored_player[i].action = joy_action;
1151 void HandleJoystick()
1153 int joystick = HandleJoystickForAllPlayers();
1154 int keyboard = key_joystick_mapping;
1155 int joy = (joystick | keyboard);
1156 int left = joy & JOY_LEFT;
1157 int right = joy & JOY_RIGHT;
1158 int up = joy & JOY_UP;
1159 int down = joy & JOY_DOWN;
1160 int button = joy & JOY_BUTTON;
1161 int newbutton = (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED);
1162 int dx = (left ? -1 : right ? 1 : 0);
1163 int dy = (up ? -1 : down ? 1 : 0);
1165 switch (game_status)
1167 case GAME_MODE_TITLE:
1168 case GAME_MODE_MAIN:
1169 case GAME_MODE_LEVELS:
1170 case GAME_MODE_LEVELNR:
1171 case GAME_MODE_SETUP:
1172 case GAME_MODE_INFO:
1174 static unsigned int joystickmove_delay = 0;
1176 if (joystick && !button &&
1177 !DelayReached(&joystickmove_delay, GADGET_FRAME_DELAY))
1178 newbutton = dx = dy = 0;
1180 if (game_status == GAME_MODE_TITLE)
1181 HandleTitleScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1182 else if (game_status == GAME_MODE_MAIN)
1183 HandleMainMenu(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1184 else if (game_status == GAME_MODE_LEVELS)
1185 HandleChooseLevelSet(0,0,dx,dy,newbutton?MB_MENU_CHOICE : MB_MENU_MARK);
1186 else if (game_status == GAME_MODE_LEVELNR)
1187 HandleChooseLevelNr(0,0,dx,dy,newbutton? MB_MENU_CHOICE : MB_MENU_MARK);
1188 else if (game_status == GAME_MODE_SETUP)
1189 HandleSetupScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1190 else if (game_status == GAME_MODE_INFO)
1191 HandleInfoScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1195 case GAME_MODE_SCORES:
1196 HandleHallOfFame(0, 0, dx, dy, !newbutton);
1199 case GAME_MODE_EDITOR:
1200 HandleLevelEditorIdle();
1203 case GAME_MODE_PLAYING:
1204 if (tape.playing || keyboard)
1205 newbutton = ((joy & JOY_BUTTON) != 0);
1208 if (local_player->LevelSolved_GameEnd && newbutton)
1210 if (AllPlayersGone && newbutton)