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 long 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 int FilterMouseMotionEvents(const Event *event)
43 /* non-motion events are directly passed to event handler functions */
44 if (event->type != EVENT_MOTIONNOTIFY)
47 motion = (MotionEvent *)event;
48 cursor_inside_playfield = (motion->x >= SX && motion->x < SX + SXSIZE &&
49 motion->y >= SY && motion->y < SY + SYSIZE);
51 if (game_status == GAME_MODE_PLAYING && playfield_cursor_set)
53 SetMouseCursor(CURSOR_DEFAULT);
54 playfield_cursor_set = FALSE;
55 DelayReached(&playfield_cursor_delay, 0);
58 /* skip mouse motion events without pressed button outside level editor */
59 if (button_status == MB_RELEASED &&
60 game_status != GAME_MODE_EDITOR && game_status != GAME_MODE_PLAYING)
66 /* to prevent delay problems, skip mouse motion events if the very next
67 event is also a mouse motion event (and therefore effectively only
68 handling the last of a row of mouse motion events in the event queue) */
70 boolean SkipPressedMouseMotionEvent(const Event *event)
72 /* nothing to do if the current event is not a mouse motion event */
73 if (event->type != EVENT_MOTIONNOTIFY)
76 /* only skip motion events with pressed button outside level editor */
77 if (button_status == MB_RELEASED ||
78 game_status == GAME_MODE_EDITOR || game_status == GAME_MODE_PLAYING)
85 PeekEvent(&next_event);
87 /* if next event is also a mouse motion event, skip the current one */
88 if (next_event.type == EVENT_MOTIONNOTIFY)
95 /* this is only really needed for non-SDL targets to filter unwanted events;
96 when using SDL with properly installed event filter, this function can be
97 replaced with a simple "NextEvent()" call, but it doesn't hurt either */
99 static boolean NextValidEvent(Event *event)
101 while (PendingEvent())
103 boolean handle_this_event = FALSE;
107 if (FilterMouseMotionEvents(event))
108 handle_this_event = TRUE;
110 if (SkipPressedMouseMotionEvent(event))
111 handle_this_event = FALSE;
113 if (handle_this_event)
124 if (PendingEvent()) /* got event */
128 while (NextValidEvent(&event))
132 case EVENT_BUTTONPRESS:
133 case EVENT_BUTTONRELEASE:
134 HandleButtonEvent((ButtonEvent *) &event);
137 case EVENT_MOTIONNOTIFY:
138 HandleMotionEvent((MotionEvent *) &event);
142 case EVENT_KEYRELEASE:
143 HandleKeyEvent((KeyEvent *) &event);
147 HandleOtherEvents(&event);
154 /* when playing, display a special mouse pointer inside the playfield */
155 if (game_status == GAME_MODE_PLAYING && !tape.pausing)
157 if (!playfield_cursor_set && cursor_inside_playfield &&
158 DelayReached(&playfield_cursor_delay, 1000))
160 SetMouseCursor(CURSOR_PLAYFIELD);
161 playfield_cursor_set = TRUE;
164 else if (playfield_cursor_set)
166 SetMouseCursor(CURSOR_DEFAULT);
167 playfield_cursor_set = FALSE;
173 /* don't use all CPU time when idle; the main loop while playing
174 has its own synchronization and is CPU friendly, too */
176 if (game_status == GAME_MODE_PLAYING)
183 if (!PendingEvent()) /* delay only if no pending events */
187 /* refresh window contents from drawing buffer, if needed */
190 if (game_status == GAME_MODE_QUIT)
195 void HandleOtherEvents(Event *event)
200 HandleExposeEvent((ExposeEvent *) event);
203 case EVENT_UNMAPNOTIFY:
205 /* This causes the game to stop not only when iconified, but also
206 when on another virtual desktop, which might be not desired. */
207 SleepWhileUnmapped();
213 HandleFocusEvent((FocusChangeEvent *) event);
216 case EVENT_CLIENTMESSAGE:
217 HandleClientMessageEvent((ClientMessageEvent *) event);
220 #if defined(TARGET_SDL)
221 case SDL_JOYAXISMOTION:
222 case SDL_JOYBUTTONDOWN:
223 case SDL_JOYBUTTONUP:
224 HandleJoystickEvent(event);
228 HandleWindowManagerEvent(event);
237 void ClearEventQueue()
239 while (PendingEvent())
247 case EVENT_BUTTONRELEASE:
248 button_status = MB_RELEASED;
251 case EVENT_KEYRELEASE:
255 key_joystick_mapping = 0;
260 HandleOtherEvents(&event);
266 void ClearPlayerAction()
270 /* simulate key release events for still pressed keys */
271 key_joystick_mapping = 0;
272 for (i = 0; i < MAX_PLAYERS; i++)
273 stored_player[i].action = 0;
276 void SleepWhileUnmapped()
278 boolean window_unmapped = TRUE;
280 KeyboardAutoRepeatOn();
282 while (window_unmapped)
290 case EVENT_BUTTONRELEASE:
291 button_status = MB_RELEASED;
294 case EVENT_KEYRELEASE:
295 key_joystick_mapping = 0;
298 case EVENT_MAPNOTIFY:
299 window_unmapped = FALSE;
302 case EVENT_UNMAPNOTIFY:
303 /* this is only to surely prevent the 'should not happen' case
304 * of recursively looping between 'SleepWhileUnmapped()' and
305 * 'HandleOtherEvents()' which usually calls this funtion.
310 HandleOtherEvents(&event);
315 if (game_status == GAME_MODE_PLAYING)
316 KeyboardAutoRepeatOffUnlessAutoplay();
319 void HandleExposeEvent(ExposeEvent *event)
322 RedrawPlayfield(FALSE, event->x, event->y, event->width, event->height);
327 void HandleButtonEvent(ButtonEvent *event)
330 printf("::: BUTTON EVENT: button %d %s\n", event->button,
331 event->type == EVENT_BUTTONPRESS ? "pressed" : "released");
334 motion_status = FALSE;
336 if (event->type == EVENT_BUTTONPRESS)
337 button_status = event->button;
339 button_status = MB_RELEASED;
341 HandleButton(event->x, event->y, button_status, event->button);
344 void HandleMotionEvent(MotionEvent *event)
346 if (!PointerInWindow(window))
347 return; /* window and pointer are on different screens */
349 if (button_status == MB_RELEASED && game_status != GAME_MODE_EDITOR)
352 motion_status = TRUE;
354 HandleButton(event->x, event->y, button_status, button_status);
357 void HandleKeyEvent(KeyEvent *event)
359 int key_status = (event->type==EVENT_KEYPRESS ? KEY_PRESSED : KEY_RELEASED);
360 boolean with_modifiers = (game_status == GAME_MODE_PLAYING ? FALSE : TRUE);
361 Key key = GetEventKey(event, with_modifiers);
362 Key keymod = (with_modifiers ? GetEventKey(event, FALSE) : key);
365 printf("::: KEY EVENT: %d %s\n", GetEventKey(event, TRUE),
366 event->type == EVENT_KEYPRESS ? "pressed" : "released");
369 HandleKeyModState(keymod, key_status);
370 HandleKey(key, key_status);
373 void HandleFocusEvent(FocusChangeEvent *event)
375 static int old_joystick_status = -1;
377 if (event->type == EVENT_FOCUSOUT)
379 KeyboardAutoRepeatOn();
380 old_joystick_status = joystick.status;
381 joystick.status = JOYSTICK_NOT_AVAILABLE;
385 else if (event->type == EVENT_FOCUSIN)
387 /* When there are two Rocks'n'Diamonds windows which overlap and
388 the player moves the pointer from one game window to the other,
389 a 'FocusOut' event is generated for the window the pointer is
390 leaving and a 'FocusIn' event is generated for the window the
391 pointer is entering. In some cases, it can happen that the
392 'FocusIn' event is handled by the one game process before the
393 'FocusOut' event by the other game process. In this case the
394 X11 environment would end up with activated keyboard auto repeat,
395 because unfortunately this is a global setting and not (which
396 would be far better) set for each X11 window individually.
397 The effect would be keyboard auto repeat while playing the game
398 (game_status == GAME_MODE_PLAYING), which is not desired.
399 To avoid this special case, we just wait 1/10 second before
400 processing the 'FocusIn' event.
403 if (game_status == GAME_MODE_PLAYING)
406 KeyboardAutoRepeatOffUnlessAutoplay();
409 if (old_joystick_status != -1)
410 joystick.status = old_joystick_status;
414 void HandleClientMessageEvent(ClientMessageEvent *event)
416 if (CheckCloseWindowEvent(event))
420 void HandleWindowManagerEvent(Event *event)
422 #if defined(TARGET_SDL)
423 SDLHandleWindowManagerEvent(event);
427 void HandleButton(int mx, int my, int button, int button_nr)
429 static int old_mx = 0, old_my = 0;
443 if (HandleGadgets(mx, my, button))
445 /* do not handle this button event anymore */
446 mx = my = -32; /* force mouse event to be outside screen tiles */
449 /* do not use scroll wheel button events for anything other than gadgets */
450 if (IS_WHEEL_BUTTON(button_nr))
455 case GAME_MODE_TITLE:
456 HandleTitleScreen(mx, my, 0, 0, button);
460 HandleMainMenu(mx, my, 0, 0, button);
463 case GAME_MODE_PSEUDO_TYPENAME:
464 HandleTypeName(0, KSYM_Return);
467 case GAME_MODE_LEVELS:
468 HandleChooseLevel(mx, my, 0, 0, button);
471 case GAME_MODE_SCORES:
472 HandleHallOfFame(0, 0, 0, 0, button);
475 case GAME_MODE_EDITOR:
476 HandleLevelEditorIdle();
480 HandleInfoScreen(mx, my, 0, 0, button);
483 case GAME_MODE_SETUP:
484 HandleSetupScreen(mx, my, 0, 0, button);
487 case GAME_MODE_PLAYING:
489 if (button == MB_PRESSED && !motion_status && IN_GFX_SCREEN(mx, my))
490 DumpTile(LEVELX((mx - SX) / TILEX), LEVELY((my - SY) / TILEY));
499 static boolean is_string_suffix(char *string, char *suffix)
501 int string_len = strlen(string);
502 int suffix_len = strlen(suffix);
504 if (suffix_len > string_len)
507 return (strEqual(&string[string_len - suffix_len], suffix));
510 #define MAX_CHEAT_INPUT_LEN 32
512 static void HandleKeysSpecial(Key key)
514 static char cheat_input[2 * MAX_CHEAT_INPUT_LEN + 1] = "";
515 char letter = getCharFromKey(key);
516 int cheat_input_len = strlen(cheat_input);
522 if (cheat_input_len >= 2 * MAX_CHEAT_INPUT_LEN)
524 for (i = 0; i < MAX_CHEAT_INPUT_LEN + 1; i++)
525 cheat_input[i] = cheat_input[MAX_CHEAT_INPUT_LEN + i];
527 cheat_input_len = MAX_CHEAT_INPUT_LEN;
530 cheat_input[cheat_input_len++] = letter;
531 cheat_input[cheat_input_len] = '\0';
534 printf("::: '%s' [%d]\n", cheat_input, cheat_input_len);
537 if (game_status == GAME_MODE_MAIN)
539 if (is_string_suffix(cheat_input, ":insert-solution-tape") ||
540 is_string_suffix(cheat_input, ":ist"))
542 InsertSolutionTape();
544 else if (is_string_suffix(cheat_input, ":reload-graphics") ||
545 is_string_suffix(cheat_input, ":rg"))
547 ReloadCustomArtwork(1 << ARTWORK_TYPE_GRAPHICS);
550 else if (is_string_suffix(cheat_input, ":reload-sounds") ||
551 is_string_suffix(cheat_input, ":rs"))
553 ReloadCustomArtwork(1 << ARTWORK_TYPE_SOUNDS);
556 else if (is_string_suffix(cheat_input, ":reload-music") ||
557 is_string_suffix(cheat_input, ":rm"))
559 ReloadCustomArtwork(1 << ARTWORK_TYPE_MUSIC);
562 else if (is_string_suffix(cheat_input, ":reload-artwork") ||
563 is_string_suffix(cheat_input, ":ra"))
565 ReloadCustomArtwork(1 << ARTWORK_TYPE_GRAPHICS |
566 1 << ARTWORK_TYPE_SOUNDS |
567 1 << ARTWORK_TYPE_MUSIC);
570 else if (is_string_suffix(cheat_input, ":dump-level") ||
571 is_string_suffix(cheat_input, ":dl"))
575 else if (is_string_suffix(cheat_input, ":dump-tape") ||
576 is_string_suffix(cheat_input, ":dt"))
580 else if (is_string_suffix(cheat_input, ":save-native-level") ||
581 is_string_suffix(cheat_input, ":snl"))
583 SaveNativeLevel(&level);
586 else if (game_status == GAME_MODE_PLAYING)
589 if (is_string_suffix(cheat_input, ".q"))
590 DEBUG_SetMaximumDynamite();
593 else if (game_status == GAME_MODE_EDITOR)
595 if (is_string_suffix(cheat_input, ":dump-brush") ||
596 is_string_suffix(cheat_input, ":DB"))
600 else if (is_string_suffix(cheat_input, ":DDB"))
607 void HandleKey(Key key, int key_status)
609 boolean anyTextGadgetActiveOrJustFinished = anyTextGadgetActive();
610 static struct SetupKeyboardInfo ski;
611 static struct SetupShortcutInfo ssi;
620 { &ski.left, &ssi.snap_left, DEFAULT_KEY_LEFT, JOY_LEFT },
621 { &ski.right, &ssi.snap_right, DEFAULT_KEY_RIGHT, JOY_RIGHT },
622 { &ski.up, &ssi.snap_up, DEFAULT_KEY_UP, JOY_UP },
623 { &ski.down, &ssi.snap_down, DEFAULT_KEY_DOWN, JOY_DOWN },
624 { &ski.snap, NULL, DEFAULT_KEY_SNAP, JOY_BUTTON_SNAP },
625 { &ski.drop, NULL, DEFAULT_KEY_DROP, JOY_BUTTON_DROP }
630 if (game_status == GAME_MODE_PLAYING)
632 /* only needed for single-step tape recording mode */
633 static boolean clear_snap_button[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
634 static boolean clear_drop_button[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
635 static boolean element_snapped[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
636 static boolean element_dropped[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
639 for (pnr = 0; pnr < MAX_PLAYERS; pnr++)
643 if (setup.input[pnr].use_joystick)
646 ski = setup.input[pnr].key;
648 for (i = 0; i < NUM_PLAYER_ACTIONS; i++)
649 if (key == *key_info[i].key_custom)
650 key_action |= key_info[i].action;
652 /* use combined snap+direction keys for the first player only */
655 ssi = setup.shortcut;
657 for (i = 0; i < NUM_DIRECTIONS; i++)
658 if (key == *key_info[i].key_snap)
659 key_action |= key_info[i].action | JOY_BUTTON_SNAP;
662 /* clear delayed snap and drop actions in single step mode (see below) */
663 if (tape.single_step)
665 if (clear_snap_button[pnr])
667 stored_player[pnr].action &= ~KEY_BUTTON_SNAP;
668 clear_snap_button[pnr] = FALSE;
671 if (clear_drop_button[pnr])
673 stored_player[pnr].action &= ~KEY_BUTTON_DROP;
674 clear_drop_button[pnr] = FALSE;
678 if (key_status == KEY_PRESSED)
679 stored_player[pnr].action |= key_action;
681 stored_player[pnr].action &= ~key_action;
683 if (tape.single_step && tape.recording && tape.pausing)
685 if (key_status == KEY_PRESSED && key_action & KEY_MOTION)
687 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
689 /* if snap key already pressed, don't snap when releasing (below) */
690 if (stored_player[pnr].action & KEY_BUTTON_SNAP)
691 element_snapped[pnr] = TRUE;
693 /* if drop key already pressed, don't drop when releasing (below) */
694 if (stored_player[pnr].action & KEY_BUTTON_DROP)
695 element_dropped[pnr] = TRUE;
698 else if (key_status == KEY_PRESSED && key_action & KEY_BUTTON_DROP)
700 if (level.game_engine_type == GAME_ENGINE_TYPE_EM ||
701 level.game_engine_type == GAME_ENGINE_TYPE_SP)
704 printf("::: drop key pressed\n");
707 if (level.game_engine_type == GAME_ENGINE_TYPE_SP &&
708 getRedDiskReleaseFlag_SP() == 0)
709 stored_player[pnr].action &= ~KEY_BUTTON_DROP;
711 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
715 else if (key_status == KEY_RELEASED && key_action & KEY_BUTTON)
717 if (key_action & KEY_BUTTON_SNAP)
719 /* if snap key was released without moving (see above), snap now */
720 if (!element_snapped[pnr])
722 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
724 stored_player[pnr].action |= KEY_BUTTON_SNAP;
726 /* clear delayed snap button on next event */
727 clear_snap_button[pnr] = TRUE;
730 element_snapped[pnr] = FALSE;
734 if (key_action & KEY_BUTTON_DROP &&
735 level.game_engine_type == GAME_ENGINE_TYPE_RND)
737 /* if drop key was released without moving (see above), drop now */
738 if (!element_dropped[pnr])
740 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
742 if (level.game_engine_type != GAME_ENGINE_TYPE_SP ||
743 getRedDiskReleaseFlag_SP() != 0)
744 stored_player[pnr].action |= KEY_BUTTON_DROP;
746 /* clear delayed drop button on next event */
747 clear_drop_button[pnr] = TRUE;
750 element_dropped[pnr] = FALSE;
755 else if (tape.recording && tape.pausing)
757 /* prevent key release events from un-pausing a paused game */
758 if (key_status == KEY_PRESSED && key_action & KEY_ACTION)
759 TapeTogglePause(TAPE_TOGGLE_MANUAL);
765 for (i = 0; i < NUM_PLAYER_ACTIONS; i++)
766 if (key == key_info[i].key_default)
767 joy |= key_info[i].action;
772 if (key_status == KEY_PRESSED)
773 key_joystick_mapping |= joy;
775 key_joystick_mapping &= ~joy;
780 if (game_status != GAME_MODE_PLAYING)
781 key_joystick_mapping = 0;
783 if (key_status == KEY_RELEASED)
786 if ((key == KSYM_Return || key == KSYM_KP_Enter) &&
787 (GetKeyModState() & KMOD_Alt) && video.fullscreen_available)
789 setup.fullscreen = !setup.fullscreen;
791 ToggleFullscreenIfNeeded();
793 if (game_status == GAME_MODE_SETUP)
794 RedrawSetupScreenAfterFullscreenToggle();
800 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd &&
801 (key == KSYM_Return || key == setup.shortcut.toggle_pause))
803 if (game_status == GAME_MODE_PLAYING && AllPlayersGone &&
804 (key == KSYM_Return || key == setup.shortcut.toggle_pause))
812 if (game_status == GAME_MODE_MAIN &&
813 (key == setup.shortcut.toggle_pause || key == KSYM_space))
815 StartGameActions(options.network, setup.autorecord, level.random_seed);
820 if (game_status == GAME_MODE_MAIN || game_status == GAME_MODE_PLAYING)
822 if (key == setup.shortcut.save_game)
824 else if (key == setup.shortcut.load_game)
826 else if (key == setup.shortcut.toggle_pause)
827 TapeTogglePause(TAPE_TOGGLE_MANUAL);
829 HandleTapeButtonKeys(key);
830 HandleSoundButtonKeys(key);
833 if (game_status == GAME_MODE_PLAYING && !network_playing)
835 int centered_player_nr_next = -999;
837 if (key == setup.shortcut.focus_player_all)
838 centered_player_nr_next = -1;
840 for (i = 0; i < MAX_PLAYERS; i++)
841 if (key == setup.shortcut.focus_player[i])
842 centered_player_nr_next = i;
844 if (centered_player_nr_next != -999)
846 game.centered_player_nr_next = centered_player_nr_next;
847 game.set_centered_player = TRUE;
851 tape.centered_player_nr_next = game.centered_player_nr_next;
852 tape.set_centered_player = TRUE;
857 HandleKeysSpecial(key);
859 if (HandleGadgetsKeyInput(key))
861 if (key != KSYM_Escape) /* always allow ESC key to be handled */
862 key = KSYM_UNDEFINED;
867 case GAME_MODE_PSEUDO_TYPENAME:
868 HandleTypeName(0, key);
871 case GAME_MODE_TITLE:
873 case GAME_MODE_LEVELS:
874 case GAME_MODE_SETUP:
876 case GAME_MODE_SCORES:
881 if (game_status == GAME_MODE_TITLE)
882 HandleTitleScreen(0, 0, 0, 0, MB_MENU_CHOICE);
883 else if (game_status == GAME_MODE_MAIN)
884 HandleMainMenu(0, 0, 0, 0, MB_MENU_CHOICE);
885 else if (game_status == GAME_MODE_LEVELS)
886 HandleChooseLevel(0, 0, 0, 0, MB_MENU_CHOICE);
887 else if (game_status == GAME_MODE_SETUP)
888 HandleSetupScreen(0, 0, 0, 0, MB_MENU_CHOICE);
889 else if (game_status == GAME_MODE_INFO)
890 HandleInfoScreen(0, 0, 0, 0, MB_MENU_CHOICE);
891 else if (game_status == GAME_MODE_SCORES)
892 HandleHallOfFame(0, 0, 0, 0, MB_MENU_CHOICE);
896 if (game_status != GAME_MODE_MAIN)
897 FadeSkipNextFadeIn();
899 if (game_status == GAME_MODE_TITLE)
900 HandleTitleScreen(0, 0, 0, 0, MB_MENU_LEAVE);
901 else if (game_status == GAME_MODE_LEVELS)
902 HandleChooseLevel(0, 0, 0, 0, MB_MENU_LEAVE);
903 else if (game_status == GAME_MODE_SETUP)
904 HandleSetupScreen(0, 0, 0, 0, MB_MENU_LEAVE);
905 else if (game_status == GAME_MODE_INFO)
906 HandleInfoScreen(0, 0, 0, 0, MB_MENU_LEAVE);
907 else if (game_status == GAME_MODE_SCORES)
908 HandleHallOfFame(0, 0, 0, 0, MB_MENU_LEAVE);
912 if (game_status == GAME_MODE_LEVELS)
913 HandleChooseLevel(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
914 else if (game_status == GAME_MODE_SETUP)
915 HandleSetupScreen(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
916 else if (game_status == GAME_MODE_INFO)
917 HandleInfoScreen(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
918 else if (game_status == GAME_MODE_SCORES)
919 HandleHallOfFame(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
923 if (game_status == GAME_MODE_LEVELS)
924 HandleChooseLevel(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
925 else if (game_status == GAME_MODE_SETUP)
926 HandleSetupScreen(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
927 else if (game_status == GAME_MODE_INFO)
928 HandleInfoScreen(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
929 else if (game_status == GAME_MODE_SCORES)
930 HandleHallOfFame(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
935 GameFrameDelay = (GameFrameDelay == 500 ? GAME_FRAME_DELAY : 500);
939 setup.sp_show_border_elements = !setup.sp_show_border_elements;
940 printf("Supaplex border elements %s\n",
941 setup.sp_show_border_elements ? "enabled" : "disabled");
950 case GAME_MODE_EDITOR:
951 if (!anyTextGadgetActiveOrJustFinished || key == KSYM_Escape)
952 HandleLevelEditorKeyInput(key);
955 case GAME_MODE_PLAYING:
960 RequestQuitGame(setup.ask_on_escape);
978 if (GameFrameDelay == 500)
979 GameFrameDelay = GAME_FRAME_DELAY;
981 GameFrameDelay = 500;
984 GameFrameDelay = (key - KSYM_0) * 10;
985 printf("Game speed == %d%% (%d ms delay between two frames)\n",
986 GAME_FRAME_DELAY * 100 / GameFrameDelay, GameFrameDelay);
992 options.debug = FALSE;
993 printf("debug mode disabled\n");
997 options.debug = TRUE;
998 printf("debug mode enabled\n");
1003 if (!global.fps_slowdown)
1005 global.fps_slowdown = TRUE;
1006 global.fps_slowdown_factor = 2;
1007 printf("fps slowdown enabled -- display only every 2nd frame\n");
1009 else if (global.fps_slowdown_factor == 2)
1011 global.fps_slowdown_factor = 4;
1012 printf("fps slowdown enabled -- display only every 4th frame\n");
1016 global.fps_slowdown = FALSE;
1017 global.fps_slowdown_factor = 1;
1018 printf("fps slowdown disabled\n");
1023 ScrollStepSize = TILEX / 8;
1024 printf("ScrollStepSize == %d (1/8)\n", ScrollStepSize);
1028 ScrollStepSize = TILEX / 4;
1029 printf("ScrollStepSize == %d (1/4)\n", ScrollStepSize);
1033 ScrollStepSize = TILEX / 2;
1034 printf("ScrollStepSize == %d (1/2)\n", ScrollStepSize);
1038 ScrollStepSize = TILEX;
1039 printf("ScrollStepSize == %d (1/1)\n", ScrollStepSize);
1043 printf("::: currently using game engine version %d\n",
1044 game.engine_version);
1055 if (key == KSYM_Escape)
1057 game_status = GAME_MODE_MAIN;
1065 void HandleNoEvent()
1067 if (button_status && game_status != GAME_MODE_PLAYING)
1069 HandleButton(0, 0, -button_status, button_status);
1074 #if defined(NETWORK_AVALIABLE)
1075 if (options.network)
1082 static int HandleJoystickForAllPlayers()
1087 for (i = 0; i < MAX_PLAYERS; i++)
1089 byte joy_action = 0;
1092 if (!setup.input[i].use_joystick)
1096 joy_action = Joystick(i);
1097 result |= joy_action;
1099 if (!setup.input[i].use_joystick)
1102 stored_player[i].action = joy_action;
1108 void HandleJoystick()
1110 int joystick = HandleJoystickForAllPlayers();
1111 int keyboard = key_joystick_mapping;
1112 int joy = (joystick | keyboard);
1113 int left = joy & JOY_LEFT;
1114 int right = joy & JOY_RIGHT;
1115 int up = joy & JOY_UP;
1116 int down = joy & JOY_DOWN;
1117 int button = joy & JOY_BUTTON;
1118 int newbutton = (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED);
1119 int dx = (left ? -1 : right ? 1 : 0);
1120 int dy = (up ? -1 : down ? 1 : 0);
1122 switch (game_status)
1124 case GAME_MODE_TITLE:
1125 case GAME_MODE_MAIN:
1126 case GAME_MODE_LEVELS:
1127 case GAME_MODE_SETUP:
1128 case GAME_MODE_INFO:
1130 static unsigned long joystickmove_delay = 0;
1132 if (joystick && !button &&
1133 !DelayReached(&joystickmove_delay, GADGET_FRAME_DELAY))
1134 newbutton = dx = dy = 0;
1136 if (game_status == GAME_MODE_TITLE)
1137 HandleTitleScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1138 else if (game_status == GAME_MODE_MAIN)
1139 HandleMainMenu(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1140 else if (game_status == GAME_MODE_LEVELS)
1141 HandleChooseLevel(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1142 else if (game_status == GAME_MODE_SETUP)
1143 HandleSetupScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1144 else if (game_status == GAME_MODE_INFO)
1145 HandleInfoScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1149 case GAME_MODE_SCORES:
1150 HandleHallOfFame(0, 0, dx, dy, !newbutton);
1153 case GAME_MODE_EDITOR:
1154 HandleLevelEditorIdle();
1157 case GAME_MODE_PLAYING:
1158 if (tape.playing || keyboard)
1159 newbutton = ((joy & JOY_BUTTON) != 0);
1162 if (local_player->LevelSolved_GameEnd && newbutton)
1164 if (AllPlayersGone && newbutton)