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);
165 case EVENT_KEYRELEASE:
166 HandleKeyEvent((KeyEvent *) &event);
170 HandleOtherEvents(&event);
177 /* when playing, display a special mouse pointer inside the playfield */
178 if (game_status == GAME_MODE_PLAYING && !tape.pausing)
180 if (!playfield_cursor_set && cursor_inside_playfield &&
181 DelayReached(&playfield_cursor_delay, 1000))
183 SetMouseCursor(CURSOR_PLAYFIELD);
184 playfield_cursor_set = TRUE;
187 else if (playfield_cursor_set)
189 SetMouseCursor(CURSOR_DEFAULT);
190 playfield_cursor_set = FALSE;
196 /* don't use all CPU time when idle; the main loop while playing
197 has its own synchronization and is CPU friendly, too */
199 if (game_status == GAME_MODE_PLAYING)
206 if (!PendingEvent()) /* delay only if no pending events */
210 /* refresh window contents from drawing buffer, if needed */
213 if (game_status == GAME_MODE_QUIT)
218 void HandleOtherEvents(Event *event)
223 HandleExposeEvent((ExposeEvent *) event);
226 case EVENT_UNMAPNOTIFY:
228 /* This causes the game to stop not only when iconified, but also
229 when on another virtual desktop, which might be not desired. */
230 SleepWhileUnmapped();
236 HandleFocusEvent((FocusChangeEvent *) event);
239 case EVENT_CLIENTMESSAGE:
240 HandleClientMessageEvent((ClientMessageEvent *) event);
243 #if defined(TARGET_SDL)
244 case SDL_JOYAXISMOTION:
245 case SDL_JOYBUTTONDOWN:
246 case SDL_JOYBUTTONUP:
247 HandleJoystickEvent(event);
251 HandleWindowManagerEvent(event);
260 void ClearEventQueue()
262 while (PendingEvent())
270 case EVENT_BUTTONRELEASE:
271 button_status = MB_RELEASED;
274 case EVENT_KEYRELEASE:
278 key_joystick_mapping = 0;
283 HandleOtherEvents(&event);
289 void ClearPlayerAction()
293 /* simulate key release events for still pressed keys */
294 key_joystick_mapping = 0;
295 for (i = 0; i < MAX_PLAYERS; i++)
296 stored_player[i].action = 0;
299 void SleepWhileUnmapped()
301 boolean window_unmapped = TRUE;
303 KeyboardAutoRepeatOn();
305 while (window_unmapped)
313 case EVENT_BUTTONRELEASE:
314 button_status = MB_RELEASED;
317 case EVENT_KEYRELEASE:
318 key_joystick_mapping = 0;
321 case EVENT_MAPNOTIFY:
322 window_unmapped = FALSE;
325 case EVENT_UNMAPNOTIFY:
326 /* this is only to surely prevent the 'should not happen' case
327 * of recursively looping between 'SleepWhileUnmapped()' and
328 * 'HandleOtherEvents()' which usually calls this funtion.
333 HandleOtherEvents(&event);
338 if (game_status == GAME_MODE_PLAYING)
339 KeyboardAutoRepeatOffUnlessAutoplay();
342 void HandleExposeEvent(ExposeEvent *event)
344 #if !defined(TARGET_SDL)
345 RedrawPlayfield(FALSE, event->x, event->y, event->width, event->height);
350 void HandleButtonEvent(ButtonEvent *event)
353 printf("::: BUTTON EVENT: button %d %s\n", event->button,
354 event->type == EVENT_BUTTONPRESS ? "pressed" : "released");
357 motion_status = FALSE;
359 if (event->type == EVENT_BUTTONPRESS)
360 button_status = event->button;
362 button_status = MB_RELEASED;
364 HandleButton(event->x, event->y, button_status, event->button);
367 void HandleMotionEvent(MotionEvent *event)
369 if (!PointerInWindow(window))
370 return; /* window and pointer are on different screens */
372 if (button_status == MB_RELEASED && game_status != GAME_MODE_EDITOR)
375 motion_status = TRUE;
377 HandleButton(event->x, event->y, button_status, button_status);
380 void HandleKeyEvent(KeyEvent *event)
382 int key_status = (event->type==EVENT_KEYPRESS ? KEY_PRESSED : KEY_RELEASED);
383 boolean with_modifiers = (game_status == GAME_MODE_PLAYING ? FALSE : TRUE);
384 Key key = GetEventKey(event, with_modifiers);
385 Key keymod = (with_modifiers ? GetEventKey(event, FALSE) : key);
388 printf("::: KEY EVENT: %d %s\n", GetEventKey(event, TRUE),
389 event->type == EVENT_KEYPRESS ? "pressed" : "released");
392 HandleKeyModState(keymod, key_status);
393 HandleKey(key, key_status);
396 void HandleFocusEvent(FocusChangeEvent *event)
398 static int old_joystick_status = -1;
400 if (event->type == EVENT_FOCUSOUT)
402 KeyboardAutoRepeatOn();
403 old_joystick_status = joystick.status;
404 joystick.status = JOYSTICK_NOT_AVAILABLE;
408 else if (event->type == EVENT_FOCUSIN)
410 /* When there are two Rocks'n'Diamonds windows which overlap and
411 the player moves the pointer from one game window to the other,
412 a 'FocusOut' event is generated for the window the pointer is
413 leaving and a 'FocusIn' event is generated for the window the
414 pointer is entering. In some cases, it can happen that the
415 'FocusIn' event is handled by the one game process before the
416 'FocusOut' event by the other game process. In this case the
417 X11 environment would end up with activated keyboard auto repeat,
418 because unfortunately this is a global setting and not (which
419 would be far better) set for each X11 window individually.
420 The effect would be keyboard auto repeat while playing the game
421 (game_status == GAME_MODE_PLAYING), which is not desired.
422 To avoid this special case, we just wait 1/10 second before
423 processing the 'FocusIn' event.
426 if (game_status == GAME_MODE_PLAYING)
429 KeyboardAutoRepeatOffUnlessAutoplay();
432 if (old_joystick_status != -1)
433 joystick.status = old_joystick_status;
437 void HandleClientMessageEvent(ClientMessageEvent *event)
439 if (CheckCloseWindowEvent(event))
443 void HandleWindowManagerEvent(Event *event)
445 #if defined(TARGET_SDL)
446 SDLHandleWindowManagerEvent(event);
450 void HandleButton(int mx, int my, int button, int button_nr)
452 static int old_mx = 0, old_my = 0;
466 if (HandleGadgets(mx, my, button))
468 /* do not handle this button event anymore */
469 mx = my = -32; /* force mouse event to be outside screen tiles */
472 /* do not use scroll wheel button events for anything other than gadgets */
473 if (IS_WHEEL_BUTTON(button_nr))
478 case GAME_MODE_TITLE:
479 HandleTitleScreen(mx, my, 0, 0, button);
483 HandleMainMenu(mx, my, 0, 0, button);
486 case GAME_MODE_PSEUDO_TYPENAME:
487 HandleTypeName(0, KSYM_Return);
490 case GAME_MODE_LEVELS:
491 HandleChooseLevelSet(mx, my, 0, 0, button);
494 case GAME_MODE_LEVELNR:
495 HandleChooseLevelNr(mx, my, 0, 0, button);
498 case GAME_MODE_SCORES:
499 HandleHallOfFame(0, 0, 0, 0, button);
502 case GAME_MODE_EDITOR:
503 HandleLevelEditorIdle();
507 HandleInfoScreen(mx, my, 0, 0, button);
510 case GAME_MODE_SETUP:
511 HandleSetupScreen(mx, my, 0, 0, button);
514 case GAME_MODE_PLAYING:
516 if (button == MB_PRESSED && !motion_status && IN_GFX_SCREEN(mx, my))
517 DumpTile(LEVELX((mx - SX) / TILEX), LEVELY((my - SY) / TILEY));
526 static boolean is_string_suffix(char *string, char *suffix)
528 int string_len = strlen(string);
529 int suffix_len = strlen(suffix);
531 if (suffix_len > string_len)
534 return (strEqual(&string[string_len - suffix_len], suffix));
537 #define MAX_CHEAT_INPUT_LEN 32
539 static void HandleKeysSpecial(Key key)
541 static char cheat_input[2 * MAX_CHEAT_INPUT_LEN + 1] = "";
542 char letter = getCharFromKey(key);
543 int cheat_input_len = strlen(cheat_input);
549 if (cheat_input_len >= 2 * MAX_CHEAT_INPUT_LEN)
551 for (i = 0; i < MAX_CHEAT_INPUT_LEN + 1; i++)
552 cheat_input[i] = cheat_input[MAX_CHEAT_INPUT_LEN + i];
554 cheat_input_len = MAX_CHEAT_INPUT_LEN;
557 cheat_input[cheat_input_len++] = letter;
558 cheat_input[cheat_input_len] = '\0';
561 printf("::: '%s' [%d]\n", cheat_input, cheat_input_len);
564 if (game_status == GAME_MODE_MAIN)
566 if (is_string_suffix(cheat_input, ":insert-solution-tape") ||
567 is_string_suffix(cheat_input, ":ist"))
569 InsertSolutionTape();
571 else if (is_string_suffix(cheat_input, ":reload-graphics") ||
572 is_string_suffix(cheat_input, ":rg"))
574 ReloadCustomArtwork(1 << ARTWORK_TYPE_GRAPHICS);
577 else if (is_string_suffix(cheat_input, ":reload-sounds") ||
578 is_string_suffix(cheat_input, ":rs"))
580 ReloadCustomArtwork(1 << ARTWORK_TYPE_SOUNDS);
583 else if (is_string_suffix(cheat_input, ":reload-music") ||
584 is_string_suffix(cheat_input, ":rm"))
586 ReloadCustomArtwork(1 << ARTWORK_TYPE_MUSIC);
589 else if (is_string_suffix(cheat_input, ":reload-artwork") ||
590 is_string_suffix(cheat_input, ":ra"))
592 ReloadCustomArtwork(1 << ARTWORK_TYPE_GRAPHICS |
593 1 << ARTWORK_TYPE_SOUNDS |
594 1 << ARTWORK_TYPE_MUSIC);
597 else if (is_string_suffix(cheat_input, ":dump-level") ||
598 is_string_suffix(cheat_input, ":dl"))
602 else if (is_string_suffix(cheat_input, ":dump-tape") ||
603 is_string_suffix(cheat_input, ":dt"))
607 else if (is_string_suffix(cheat_input, ":save-native-level") ||
608 is_string_suffix(cheat_input, ":snl"))
610 SaveNativeLevel(&level);
613 else if (game_status == GAME_MODE_PLAYING)
616 if (is_string_suffix(cheat_input, ".q"))
617 DEBUG_SetMaximumDynamite();
620 else if (game_status == GAME_MODE_EDITOR)
622 if (is_string_suffix(cheat_input, ":dump-brush") ||
623 is_string_suffix(cheat_input, ":DB"))
627 else if (is_string_suffix(cheat_input, ":DDB"))
634 void HandleKey(Key key, int key_status)
636 boolean anyTextGadgetActiveOrJustFinished = anyTextGadgetActive();
637 static struct SetupKeyboardInfo ski;
638 static struct SetupShortcutInfo ssi;
647 { &ski.left, &ssi.snap_left, DEFAULT_KEY_LEFT, JOY_LEFT },
648 { &ski.right, &ssi.snap_right, DEFAULT_KEY_RIGHT, JOY_RIGHT },
649 { &ski.up, &ssi.snap_up, DEFAULT_KEY_UP, JOY_UP },
650 { &ski.down, &ssi.snap_down, DEFAULT_KEY_DOWN, JOY_DOWN },
651 { &ski.snap, NULL, DEFAULT_KEY_SNAP, JOY_BUTTON_SNAP },
652 { &ski.drop, NULL, DEFAULT_KEY_DROP, JOY_BUTTON_DROP }
657 if (game_status == GAME_MODE_PLAYING)
659 /* only needed for single-step tape recording mode */
660 static boolean clear_snap_button[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
661 static boolean clear_drop_button[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
662 static boolean element_snapped[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
663 static boolean element_dropped[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
666 for (pnr = 0; pnr < MAX_PLAYERS; pnr++)
670 if (setup.input[pnr].use_joystick)
673 ski = setup.input[pnr].key;
675 for (i = 0; i < NUM_PLAYER_ACTIONS; i++)
676 if (key == *key_info[i].key_custom)
677 key_action |= key_info[i].action;
679 /* use combined snap+direction keys for the first player only */
682 ssi = setup.shortcut;
684 for (i = 0; i < NUM_DIRECTIONS; i++)
685 if (key == *key_info[i].key_snap)
686 key_action |= key_info[i].action | JOY_BUTTON_SNAP;
689 /* clear delayed snap and drop actions in single step mode (see below) */
690 if (tape.single_step)
692 if (clear_snap_button[pnr])
694 stored_player[pnr].action &= ~KEY_BUTTON_SNAP;
695 clear_snap_button[pnr] = FALSE;
698 if (clear_drop_button[pnr])
700 stored_player[pnr].action &= ~KEY_BUTTON_DROP;
701 clear_drop_button[pnr] = FALSE;
705 if (key_status == KEY_PRESSED)
706 stored_player[pnr].action |= key_action;
708 stored_player[pnr].action &= ~key_action;
710 if (tape.single_step && tape.recording && tape.pausing)
712 if (key_status == KEY_PRESSED && key_action & KEY_MOTION)
714 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
716 /* if snap key already pressed, don't snap when releasing (below) */
717 if (stored_player[pnr].action & KEY_BUTTON_SNAP)
718 element_snapped[pnr] = TRUE;
720 /* if drop key already pressed, don't drop when releasing (below) */
721 if (stored_player[pnr].action & KEY_BUTTON_DROP)
722 element_dropped[pnr] = TRUE;
725 else if (key_status == KEY_PRESSED && key_action & KEY_BUTTON_DROP)
727 if (level.game_engine_type == GAME_ENGINE_TYPE_EM ||
728 level.game_engine_type == GAME_ENGINE_TYPE_SP)
731 printf("::: drop key pressed\n");
734 if (level.game_engine_type == GAME_ENGINE_TYPE_SP &&
735 getRedDiskReleaseFlag_SP() == 0)
736 stored_player[pnr].action &= ~KEY_BUTTON_DROP;
738 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
742 else if (key_status == KEY_RELEASED && key_action & KEY_BUTTON)
744 if (key_action & KEY_BUTTON_SNAP)
746 /* if snap key was released without moving (see above), snap now */
747 if (!element_snapped[pnr])
749 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
751 stored_player[pnr].action |= KEY_BUTTON_SNAP;
753 /* clear delayed snap button on next event */
754 clear_snap_button[pnr] = TRUE;
757 element_snapped[pnr] = FALSE;
761 if (key_action & KEY_BUTTON_DROP &&
762 level.game_engine_type == GAME_ENGINE_TYPE_RND)
764 /* if drop key was released without moving (see above), drop now */
765 if (!element_dropped[pnr])
767 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
769 if (level.game_engine_type != GAME_ENGINE_TYPE_SP ||
770 getRedDiskReleaseFlag_SP() != 0)
771 stored_player[pnr].action |= KEY_BUTTON_DROP;
773 /* clear delayed drop button on next event */
774 clear_drop_button[pnr] = TRUE;
777 element_dropped[pnr] = FALSE;
782 else if (tape.recording && tape.pausing)
784 /* prevent key release events from un-pausing a paused game */
785 if (key_status == KEY_PRESSED && key_action & KEY_ACTION)
786 TapeTogglePause(TAPE_TOGGLE_MANUAL);
792 for (i = 0; i < NUM_PLAYER_ACTIONS; i++)
793 if (key == key_info[i].key_default)
794 joy |= key_info[i].action;
799 if (key_status == KEY_PRESSED)
800 key_joystick_mapping |= joy;
802 key_joystick_mapping &= ~joy;
807 if (game_status != GAME_MODE_PLAYING)
808 key_joystick_mapping = 0;
810 if (key_status == KEY_RELEASED)
813 if ((key == KSYM_Return || key == KSYM_KP_Enter) &&
814 (GetKeyModState() & KMOD_Alt) && video.fullscreen_available)
816 setup.fullscreen = !setup.fullscreen;
818 ToggleFullscreenIfNeeded();
820 if (game_status == GAME_MODE_SETUP)
821 RedrawSetupScreenAfterFullscreenToggle();
827 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd &&
828 (key == KSYM_Return || key == setup.shortcut.toggle_pause))
830 if (game_status == GAME_MODE_PLAYING && AllPlayersGone &&
831 (key == KSYM_Return || key == setup.shortcut.toggle_pause))
839 if (game_status == GAME_MODE_MAIN &&
840 (key == setup.shortcut.toggle_pause || key == KSYM_space))
842 StartGameActions(options.network, setup.autorecord, level.random_seed);
847 if (game_status == GAME_MODE_MAIN || game_status == GAME_MODE_PLAYING)
849 if (key == setup.shortcut.save_game)
851 else if (key == setup.shortcut.load_game)
853 else if (key == setup.shortcut.toggle_pause)
854 TapeTogglePause(TAPE_TOGGLE_MANUAL);
856 HandleTapeButtonKeys(key);
857 HandleSoundButtonKeys(key);
860 if (game_status == GAME_MODE_PLAYING && !network_playing)
862 int centered_player_nr_next = -999;
864 if (key == setup.shortcut.focus_player_all)
865 centered_player_nr_next = -1;
867 for (i = 0; i < MAX_PLAYERS; i++)
868 if (key == setup.shortcut.focus_player[i])
869 centered_player_nr_next = i;
871 if (centered_player_nr_next != -999)
873 game.centered_player_nr_next = centered_player_nr_next;
874 game.set_centered_player = TRUE;
878 tape.centered_player_nr_next = game.centered_player_nr_next;
879 tape.set_centered_player = TRUE;
884 HandleKeysSpecial(key);
886 if (HandleGadgetsKeyInput(key))
888 if (key != KSYM_Escape) /* always allow ESC key to be handled */
889 key = KSYM_UNDEFINED;
894 case GAME_MODE_PSEUDO_TYPENAME:
895 HandleTypeName(0, key);
898 case GAME_MODE_TITLE:
900 case GAME_MODE_LEVELS:
901 case GAME_MODE_LEVELNR:
902 case GAME_MODE_SETUP:
904 case GAME_MODE_SCORES:
909 if (game_status == GAME_MODE_TITLE)
910 HandleTitleScreen(0, 0, 0, 0, MB_MENU_CHOICE);
911 else if (game_status == GAME_MODE_MAIN)
912 HandleMainMenu(0, 0, 0, 0, MB_MENU_CHOICE);
913 else if (game_status == GAME_MODE_LEVELS)
914 HandleChooseLevelSet(0, 0, 0, 0, MB_MENU_CHOICE);
915 else if (game_status == GAME_MODE_LEVELNR)
916 HandleChooseLevelNr(0, 0, 0, 0, MB_MENU_CHOICE);
917 else if (game_status == GAME_MODE_SETUP)
918 HandleSetupScreen(0, 0, 0, 0, MB_MENU_CHOICE);
919 else if (game_status == GAME_MODE_INFO)
920 HandleInfoScreen(0, 0, 0, 0, MB_MENU_CHOICE);
921 else if (game_status == GAME_MODE_SCORES)
922 HandleHallOfFame(0, 0, 0, 0, MB_MENU_CHOICE);
926 if (game_status != GAME_MODE_MAIN)
927 FadeSkipNextFadeIn();
929 if (game_status == GAME_MODE_TITLE)
930 HandleTitleScreen(0, 0, 0, 0, MB_MENU_LEAVE);
931 else if (game_status == GAME_MODE_LEVELS)
932 HandleChooseLevelSet(0, 0, 0, 0, MB_MENU_LEAVE);
933 else if (game_status == GAME_MODE_LEVELNR)
934 HandleChooseLevelNr(0, 0, 0, 0, MB_MENU_LEAVE);
935 else if (game_status == GAME_MODE_SETUP)
936 HandleSetupScreen(0, 0, 0, 0, MB_MENU_LEAVE);
937 else if (game_status == GAME_MODE_INFO)
938 HandleInfoScreen(0, 0, 0, 0, MB_MENU_LEAVE);
939 else if (game_status == GAME_MODE_SCORES)
940 HandleHallOfFame(0, 0, 0, 0, MB_MENU_LEAVE);
944 if (game_status == GAME_MODE_LEVELS)
945 HandleChooseLevelSet(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
946 else if (game_status == GAME_MODE_LEVELNR)
947 HandleChooseLevelNr(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
948 else if (game_status == GAME_MODE_SETUP)
949 HandleSetupScreen(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
950 else if (game_status == GAME_MODE_INFO)
951 HandleInfoScreen(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
952 else if (game_status == GAME_MODE_SCORES)
953 HandleHallOfFame(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
957 if (game_status == GAME_MODE_LEVELS)
958 HandleChooseLevelSet(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
959 else if (game_status == GAME_MODE_LEVELNR)
960 HandleChooseLevelNr(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
961 else if (game_status == GAME_MODE_SETUP)
962 HandleSetupScreen(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
963 else if (game_status == GAME_MODE_INFO)
964 HandleInfoScreen(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
965 else if (game_status == GAME_MODE_SCORES)
966 HandleHallOfFame(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
971 GameFrameDelay = (GameFrameDelay == 500 ? GAME_FRAME_DELAY : 500);
975 setup.sp_show_border_elements = !setup.sp_show_border_elements;
976 printf("Supaplex border elements %s\n",
977 setup.sp_show_border_elements ? "enabled" : "disabled");
986 case GAME_MODE_EDITOR:
987 if (!anyTextGadgetActiveOrJustFinished || key == KSYM_Escape)
988 HandleLevelEditorKeyInput(key);
991 case GAME_MODE_PLAYING:
996 RequestQuitGame(setup.ask_on_escape);
1014 if (GameFrameDelay == 500)
1015 GameFrameDelay = GAME_FRAME_DELAY;
1017 GameFrameDelay = 500;
1020 GameFrameDelay = (key - KSYM_0) * 10;
1021 printf("Game speed == %d%% (%d ms delay between two frames)\n",
1022 GAME_FRAME_DELAY * 100 / GameFrameDelay, GameFrameDelay);
1028 options.debug = FALSE;
1029 printf("debug mode disabled\n");
1033 options.debug = TRUE;
1034 printf("debug mode enabled\n");
1039 if (!global.fps_slowdown)
1041 global.fps_slowdown = TRUE;
1042 global.fps_slowdown_factor = 2;
1043 printf("fps slowdown enabled -- display only every 2nd frame\n");
1045 else if (global.fps_slowdown_factor == 2)
1047 global.fps_slowdown_factor = 4;
1048 printf("fps slowdown enabled -- display only every 4th frame\n");
1052 global.fps_slowdown = FALSE;
1053 global.fps_slowdown_factor = 1;
1054 printf("fps slowdown disabled\n");
1059 ScrollStepSize = TILEX / 8;
1060 printf("ScrollStepSize == %d (1/8)\n", ScrollStepSize);
1064 ScrollStepSize = TILEX / 4;
1065 printf("ScrollStepSize == %d (1/4)\n", ScrollStepSize);
1069 ScrollStepSize = TILEX / 2;
1070 printf("ScrollStepSize == %d (1/2)\n", ScrollStepSize);
1074 ScrollStepSize = TILEX;
1075 printf("ScrollStepSize == %d (1/1)\n", ScrollStepSize);
1079 printf("::: currently using game engine version %d\n",
1080 game.engine_version);
1091 if (key == KSYM_Escape)
1093 game_status = GAME_MODE_MAIN;
1101 void HandleNoEvent()
1103 if (button_status && game_status != GAME_MODE_PLAYING)
1105 HandleButton(0, 0, -button_status, button_status);
1110 #if defined(NETWORK_AVALIABLE)
1111 if (options.network)
1118 static int HandleJoystickForAllPlayers()
1123 for (i = 0; i < MAX_PLAYERS; i++)
1125 byte joy_action = 0;
1128 if (!setup.input[i].use_joystick)
1132 joy_action = Joystick(i);
1133 result |= joy_action;
1135 if (!setup.input[i].use_joystick)
1138 stored_player[i].action = joy_action;
1144 void HandleJoystick()
1146 int joystick = HandleJoystickForAllPlayers();
1147 int keyboard = key_joystick_mapping;
1148 int joy = (joystick | keyboard);
1149 int left = joy & JOY_LEFT;
1150 int right = joy & JOY_RIGHT;
1151 int up = joy & JOY_UP;
1152 int down = joy & JOY_DOWN;
1153 int button = joy & JOY_BUTTON;
1154 int newbutton = (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED);
1155 int dx = (left ? -1 : right ? 1 : 0);
1156 int dy = (up ? -1 : down ? 1 : 0);
1158 switch (game_status)
1160 case GAME_MODE_TITLE:
1161 case GAME_MODE_MAIN:
1162 case GAME_MODE_LEVELS:
1163 case GAME_MODE_LEVELNR:
1164 case GAME_MODE_SETUP:
1165 case GAME_MODE_INFO:
1167 static unsigned int joystickmove_delay = 0;
1169 if (joystick && !button &&
1170 !DelayReached(&joystickmove_delay, GADGET_FRAME_DELAY))
1171 newbutton = dx = dy = 0;
1173 if (game_status == GAME_MODE_TITLE)
1174 HandleTitleScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1175 else if (game_status == GAME_MODE_MAIN)
1176 HandleMainMenu(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1177 else if (game_status == GAME_MODE_LEVELS)
1178 HandleChooseLevelSet(0,0,dx,dy,newbutton?MB_MENU_CHOICE : MB_MENU_MARK);
1179 else if (game_status == GAME_MODE_LEVELNR)
1180 HandleChooseLevelNr(0,0,dx,dy,newbutton? MB_MENU_CHOICE : MB_MENU_MARK);
1181 else if (game_status == GAME_MODE_SETUP)
1182 HandleSetupScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1183 else if (game_status == GAME_MODE_INFO)
1184 HandleInfoScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1188 case GAME_MODE_SCORES:
1189 HandleHallOfFame(0, 0, dx, dy, !newbutton);
1192 case GAME_MODE_EDITOR:
1193 HandleLevelEditorIdle();
1196 case GAME_MODE_PLAYING:
1197 if (tape.playing || keyboard)
1198 newbutton = ((joy & JOY_BUTTON) != 0);
1201 if (local_player->LevelSolved_GameEnd && newbutton)
1203 if (AllPlayersGone && newbutton)