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 int FilterEvents(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 /* to prevent delay problems, skip mouse motion events if the very next
78 event is also a mouse motion event (and therefore effectively only
79 handling the last of a row of mouse motion events in the event queue) */
81 boolean SkipPressedMouseMotionEvent(const Event *event)
83 /* nothing to do if the current event is not a mouse motion event */
84 if (event->type != EVENT_MOTIONNOTIFY)
87 /* only skip motion events with pressed button outside level editor */
88 if (button_status == MB_RELEASED ||
89 game_status == GAME_MODE_EDITOR || game_status == GAME_MODE_PLAYING)
96 PeekEvent(&next_event);
98 /* if next event is also a mouse motion event, skip the current one */
99 if (next_event.type == EVENT_MOTIONNOTIFY)
106 /* this is only really needed for non-SDL targets to filter unwanted events;
107 when using SDL with properly installed event filter, this function can be
108 replaced with a simple "NextEvent()" call, but it doesn't hurt either */
110 static boolean NextValidEvent(Event *event)
112 while (PendingEvent())
114 boolean handle_this_event = FALSE;
118 if (FilterMouseMotionEvents(event))
119 handle_this_event = TRUE;
121 if (SkipPressedMouseMotionEvent(event))
122 handle_this_event = FALSE;
124 if (handle_this_event)
135 if (PendingEvent()) /* got event */
139 while (NextValidEvent(&event))
143 case EVENT_BUTTONPRESS:
144 case EVENT_BUTTONRELEASE:
145 HandleButtonEvent((ButtonEvent *) &event);
148 case EVENT_MOTIONNOTIFY:
149 HandleMotionEvent((MotionEvent *) &event);
153 case EVENT_KEYRELEASE:
154 HandleKeyEvent((KeyEvent *) &event);
158 HandleOtherEvents(&event);
165 /* when playing, display a special mouse pointer inside the playfield */
166 if (game_status == GAME_MODE_PLAYING && !tape.pausing)
168 if (!playfield_cursor_set && cursor_inside_playfield &&
169 DelayReached(&playfield_cursor_delay, 1000))
171 SetMouseCursor(CURSOR_PLAYFIELD);
172 playfield_cursor_set = TRUE;
175 else if (playfield_cursor_set)
177 SetMouseCursor(CURSOR_DEFAULT);
178 playfield_cursor_set = FALSE;
184 /* don't use all CPU time when idle; the main loop while playing
185 has its own synchronization and is CPU friendly, too */
187 if (game_status == GAME_MODE_PLAYING)
194 if (!PendingEvent()) /* delay only if no pending events */
198 /* refresh window contents from drawing buffer, if needed */
201 if (game_status == GAME_MODE_QUIT)
206 void HandleOtherEvents(Event *event)
211 HandleExposeEvent((ExposeEvent *) event);
214 case EVENT_UNMAPNOTIFY:
216 /* This causes the game to stop not only when iconified, but also
217 when on another virtual desktop, which might be not desired. */
218 SleepWhileUnmapped();
224 HandleFocusEvent((FocusChangeEvent *) event);
227 case EVENT_CLIENTMESSAGE:
228 HandleClientMessageEvent((ClientMessageEvent *) event);
231 #if defined(TARGET_SDL)
232 case SDL_JOYAXISMOTION:
233 case SDL_JOYBUTTONDOWN:
234 case SDL_JOYBUTTONUP:
235 HandleJoystickEvent(event);
239 HandleWindowManagerEvent(event);
248 void ClearEventQueue()
250 while (PendingEvent())
258 case EVENT_BUTTONRELEASE:
259 button_status = MB_RELEASED;
262 case EVENT_KEYRELEASE:
266 key_joystick_mapping = 0;
271 HandleOtherEvents(&event);
277 void ClearPlayerAction()
281 /* simulate key release events for still pressed keys */
282 key_joystick_mapping = 0;
283 for (i = 0; i < MAX_PLAYERS; i++)
284 stored_player[i].action = 0;
287 void SleepWhileUnmapped()
289 boolean window_unmapped = TRUE;
291 KeyboardAutoRepeatOn();
293 while (window_unmapped)
301 case EVENT_BUTTONRELEASE:
302 button_status = MB_RELEASED;
305 case EVENT_KEYRELEASE:
306 key_joystick_mapping = 0;
309 case EVENT_MAPNOTIFY:
310 window_unmapped = FALSE;
313 case EVENT_UNMAPNOTIFY:
314 /* this is only to surely prevent the 'should not happen' case
315 * of recursively looping between 'SleepWhileUnmapped()' and
316 * 'HandleOtherEvents()' which usually calls this funtion.
321 HandleOtherEvents(&event);
326 if (game_status == GAME_MODE_PLAYING)
327 KeyboardAutoRepeatOffUnlessAutoplay();
330 void HandleExposeEvent(ExposeEvent *event)
332 #if !defined(TARGET_SDL)
333 RedrawPlayfield(FALSE, event->x, event->y, event->width, event->height);
338 void HandleButtonEvent(ButtonEvent *event)
341 printf("::: BUTTON EVENT: button %d %s\n", event->button,
342 event->type == EVENT_BUTTONPRESS ? "pressed" : "released");
345 motion_status = FALSE;
347 if (event->type == EVENT_BUTTONPRESS)
348 button_status = event->button;
350 button_status = MB_RELEASED;
352 HandleButton(event->x, event->y, button_status, event->button);
355 void HandleMotionEvent(MotionEvent *event)
357 if (!PointerInWindow(window))
358 return; /* window and pointer are on different screens */
360 if (button_status == MB_RELEASED && game_status != GAME_MODE_EDITOR)
363 motion_status = TRUE;
365 HandleButton(event->x, event->y, button_status, button_status);
368 void HandleKeyEvent(KeyEvent *event)
370 int key_status = (event->type==EVENT_KEYPRESS ? KEY_PRESSED : KEY_RELEASED);
371 boolean with_modifiers = (game_status == GAME_MODE_PLAYING ? FALSE : TRUE);
372 Key key = GetEventKey(event, with_modifiers);
373 Key keymod = (with_modifiers ? GetEventKey(event, FALSE) : key);
376 printf("::: KEY EVENT: %d %s\n", GetEventKey(event, TRUE),
377 event->type == EVENT_KEYPRESS ? "pressed" : "released");
380 HandleKeyModState(keymod, key_status);
381 HandleKey(key, key_status);
384 void HandleFocusEvent(FocusChangeEvent *event)
386 static int old_joystick_status = -1;
388 if (event->type == EVENT_FOCUSOUT)
390 KeyboardAutoRepeatOn();
391 old_joystick_status = joystick.status;
392 joystick.status = JOYSTICK_NOT_AVAILABLE;
396 else if (event->type == EVENT_FOCUSIN)
398 /* When there are two Rocks'n'Diamonds windows which overlap and
399 the player moves the pointer from one game window to the other,
400 a 'FocusOut' event is generated for the window the pointer is
401 leaving and a 'FocusIn' event is generated for the window the
402 pointer is entering. In some cases, it can happen that the
403 'FocusIn' event is handled by the one game process before the
404 'FocusOut' event by the other game process. In this case the
405 X11 environment would end up with activated keyboard auto repeat,
406 because unfortunately this is a global setting and not (which
407 would be far better) set for each X11 window individually.
408 The effect would be keyboard auto repeat while playing the game
409 (game_status == GAME_MODE_PLAYING), which is not desired.
410 To avoid this special case, we just wait 1/10 second before
411 processing the 'FocusIn' event.
414 if (game_status == GAME_MODE_PLAYING)
417 KeyboardAutoRepeatOffUnlessAutoplay();
420 if (old_joystick_status != -1)
421 joystick.status = old_joystick_status;
425 void HandleClientMessageEvent(ClientMessageEvent *event)
427 if (CheckCloseWindowEvent(event))
431 void HandleWindowManagerEvent(Event *event)
433 #if defined(TARGET_SDL)
434 SDLHandleWindowManagerEvent(event);
438 void HandleButton(int mx, int my, int button, int button_nr)
440 static int old_mx = 0, old_my = 0;
454 if (HandleGadgets(mx, my, button))
456 /* do not handle this button event anymore */
457 mx = my = -32; /* force mouse event to be outside screen tiles */
460 /* do not use scroll wheel button events for anything other than gadgets */
461 if (IS_WHEEL_BUTTON(button_nr))
466 case GAME_MODE_TITLE:
467 HandleTitleScreen(mx, my, 0, 0, button);
471 HandleMainMenu(mx, my, 0, 0, button);
474 case GAME_MODE_PSEUDO_TYPENAME:
475 HandleTypeName(0, KSYM_Return);
478 case GAME_MODE_LEVELS:
479 HandleChooseLevelSet(mx, my, 0, 0, button);
482 case GAME_MODE_LEVELNR:
483 HandleChooseLevelNr(mx, my, 0, 0, button);
486 case GAME_MODE_SCORES:
487 HandleHallOfFame(0, 0, 0, 0, button);
490 case GAME_MODE_EDITOR:
491 HandleLevelEditorIdle();
495 HandleInfoScreen(mx, my, 0, 0, button);
498 case GAME_MODE_SETUP:
499 HandleSetupScreen(mx, my, 0, 0, button);
502 case GAME_MODE_PLAYING:
504 if (button == MB_PRESSED && !motion_status && IN_GFX_SCREEN(mx, my))
505 DumpTile(LEVELX((mx - SX) / TILEX), LEVELY((my - SY) / TILEY));
514 static boolean is_string_suffix(char *string, char *suffix)
516 int string_len = strlen(string);
517 int suffix_len = strlen(suffix);
519 if (suffix_len > string_len)
522 return (strEqual(&string[string_len - suffix_len], suffix));
525 #define MAX_CHEAT_INPUT_LEN 32
527 static void HandleKeysSpecial(Key key)
529 static char cheat_input[2 * MAX_CHEAT_INPUT_LEN + 1] = "";
530 char letter = getCharFromKey(key);
531 int cheat_input_len = strlen(cheat_input);
537 if (cheat_input_len >= 2 * MAX_CHEAT_INPUT_LEN)
539 for (i = 0; i < MAX_CHEAT_INPUT_LEN + 1; i++)
540 cheat_input[i] = cheat_input[MAX_CHEAT_INPUT_LEN + i];
542 cheat_input_len = MAX_CHEAT_INPUT_LEN;
545 cheat_input[cheat_input_len++] = letter;
546 cheat_input[cheat_input_len] = '\0';
549 printf("::: '%s' [%d]\n", cheat_input, cheat_input_len);
552 if (game_status == GAME_MODE_MAIN)
554 if (is_string_suffix(cheat_input, ":insert-solution-tape") ||
555 is_string_suffix(cheat_input, ":ist"))
557 InsertSolutionTape();
559 else if (is_string_suffix(cheat_input, ":reload-graphics") ||
560 is_string_suffix(cheat_input, ":rg"))
562 ReloadCustomArtwork(1 << ARTWORK_TYPE_GRAPHICS);
565 else if (is_string_suffix(cheat_input, ":reload-sounds") ||
566 is_string_suffix(cheat_input, ":rs"))
568 ReloadCustomArtwork(1 << ARTWORK_TYPE_SOUNDS);
571 else if (is_string_suffix(cheat_input, ":reload-music") ||
572 is_string_suffix(cheat_input, ":rm"))
574 ReloadCustomArtwork(1 << ARTWORK_TYPE_MUSIC);
577 else if (is_string_suffix(cheat_input, ":reload-artwork") ||
578 is_string_suffix(cheat_input, ":ra"))
580 ReloadCustomArtwork(1 << ARTWORK_TYPE_GRAPHICS |
581 1 << ARTWORK_TYPE_SOUNDS |
582 1 << ARTWORK_TYPE_MUSIC);
585 else if (is_string_suffix(cheat_input, ":dump-level") ||
586 is_string_suffix(cheat_input, ":dl"))
590 else if (is_string_suffix(cheat_input, ":dump-tape") ||
591 is_string_suffix(cheat_input, ":dt"))
595 else if (is_string_suffix(cheat_input, ":save-native-level") ||
596 is_string_suffix(cheat_input, ":snl"))
598 SaveNativeLevel(&level);
601 else if (game_status == GAME_MODE_PLAYING)
604 if (is_string_suffix(cheat_input, ".q"))
605 DEBUG_SetMaximumDynamite();
608 else if (game_status == GAME_MODE_EDITOR)
610 if (is_string_suffix(cheat_input, ":dump-brush") ||
611 is_string_suffix(cheat_input, ":DB"))
615 else if (is_string_suffix(cheat_input, ":DDB"))
622 void HandleKey(Key key, int key_status)
624 boolean anyTextGadgetActiveOrJustFinished = anyTextGadgetActive();
625 static struct SetupKeyboardInfo ski;
626 static struct SetupShortcutInfo ssi;
635 { &ski.left, &ssi.snap_left, DEFAULT_KEY_LEFT, JOY_LEFT },
636 { &ski.right, &ssi.snap_right, DEFAULT_KEY_RIGHT, JOY_RIGHT },
637 { &ski.up, &ssi.snap_up, DEFAULT_KEY_UP, JOY_UP },
638 { &ski.down, &ssi.snap_down, DEFAULT_KEY_DOWN, JOY_DOWN },
639 { &ski.snap, NULL, DEFAULT_KEY_SNAP, JOY_BUTTON_SNAP },
640 { &ski.drop, NULL, DEFAULT_KEY_DROP, JOY_BUTTON_DROP }
645 if (game_status == GAME_MODE_PLAYING)
647 /* only needed for single-step tape recording mode */
648 static boolean clear_snap_button[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
649 static boolean clear_drop_button[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
650 static boolean element_snapped[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
651 static boolean element_dropped[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
654 for (pnr = 0; pnr < MAX_PLAYERS; pnr++)
658 if (setup.input[pnr].use_joystick)
661 ski = setup.input[pnr].key;
663 for (i = 0; i < NUM_PLAYER_ACTIONS; i++)
664 if (key == *key_info[i].key_custom)
665 key_action |= key_info[i].action;
667 /* use combined snap+direction keys for the first player only */
670 ssi = setup.shortcut;
672 for (i = 0; i < NUM_DIRECTIONS; i++)
673 if (key == *key_info[i].key_snap)
674 key_action |= key_info[i].action | JOY_BUTTON_SNAP;
677 /* clear delayed snap and drop actions in single step mode (see below) */
678 if (tape.single_step)
680 if (clear_snap_button[pnr])
682 stored_player[pnr].action &= ~KEY_BUTTON_SNAP;
683 clear_snap_button[pnr] = FALSE;
686 if (clear_drop_button[pnr])
688 stored_player[pnr].action &= ~KEY_BUTTON_DROP;
689 clear_drop_button[pnr] = FALSE;
693 if (key_status == KEY_PRESSED)
694 stored_player[pnr].action |= key_action;
696 stored_player[pnr].action &= ~key_action;
698 if (tape.single_step && tape.recording && tape.pausing)
700 if (key_status == KEY_PRESSED && key_action & KEY_MOTION)
702 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
704 /* if snap key already pressed, don't snap when releasing (below) */
705 if (stored_player[pnr].action & KEY_BUTTON_SNAP)
706 element_snapped[pnr] = TRUE;
708 /* if drop key already pressed, don't drop when releasing (below) */
709 if (stored_player[pnr].action & KEY_BUTTON_DROP)
710 element_dropped[pnr] = TRUE;
713 else if (key_status == KEY_PRESSED && key_action & KEY_BUTTON_DROP)
715 if (level.game_engine_type == GAME_ENGINE_TYPE_EM ||
716 level.game_engine_type == GAME_ENGINE_TYPE_SP)
719 printf("::: drop key pressed\n");
722 if (level.game_engine_type == GAME_ENGINE_TYPE_SP &&
723 getRedDiskReleaseFlag_SP() == 0)
724 stored_player[pnr].action &= ~KEY_BUTTON_DROP;
726 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
730 else if (key_status == KEY_RELEASED && key_action & KEY_BUTTON)
732 if (key_action & KEY_BUTTON_SNAP)
734 /* if snap key was released without moving (see above), snap now */
735 if (!element_snapped[pnr])
737 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
739 stored_player[pnr].action |= KEY_BUTTON_SNAP;
741 /* clear delayed snap button on next event */
742 clear_snap_button[pnr] = TRUE;
745 element_snapped[pnr] = FALSE;
749 if (key_action & KEY_BUTTON_DROP &&
750 level.game_engine_type == GAME_ENGINE_TYPE_RND)
752 /* if drop key was released without moving (see above), drop now */
753 if (!element_dropped[pnr])
755 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
757 if (level.game_engine_type != GAME_ENGINE_TYPE_SP ||
758 getRedDiskReleaseFlag_SP() != 0)
759 stored_player[pnr].action |= KEY_BUTTON_DROP;
761 /* clear delayed drop button on next event */
762 clear_drop_button[pnr] = TRUE;
765 element_dropped[pnr] = FALSE;
770 else if (tape.recording && tape.pausing)
772 /* prevent key release events from un-pausing a paused game */
773 if (key_status == KEY_PRESSED && key_action & KEY_ACTION)
774 TapeTogglePause(TAPE_TOGGLE_MANUAL);
780 for (i = 0; i < NUM_PLAYER_ACTIONS; i++)
781 if (key == key_info[i].key_default)
782 joy |= key_info[i].action;
787 if (key_status == KEY_PRESSED)
788 key_joystick_mapping |= joy;
790 key_joystick_mapping &= ~joy;
795 if (game_status != GAME_MODE_PLAYING)
796 key_joystick_mapping = 0;
798 if (key_status == KEY_RELEASED)
801 if ((key == KSYM_Return || key == KSYM_KP_Enter) &&
802 (GetKeyModState() & KMOD_Alt) && video.fullscreen_available)
804 setup.fullscreen = !setup.fullscreen;
806 ToggleFullscreenIfNeeded();
808 if (game_status == GAME_MODE_SETUP)
809 RedrawSetupScreenAfterFullscreenToggle();
815 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd &&
816 (key == KSYM_Return || key == setup.shortcut.toggle_pause))
818 if (game_status == GAME_MODE_PLAYING && AllPlayersGone &&
819 (key == KSYM_Return || key == setup.shortcut.toggle_pause))
827 if (game_status == GAME_MODE_MAIN &&
828 (key == setup.shortcut.toggle_pause || key == KSYM_space))
830 StartGameActions(options.network, setup.autorecord, level.random_seed);
835 if (game_status == GAME_MODE_MAIN || game_status == GAME_MODE_PLAYING)
837 if (key == setup.shortcut.save_game)
839 else if (key == setup.shortcut.load_game)
841 else if (key == setup.shortcut.toggle_pause)
842 TapeTogglePause(TAPE_TOGGLE_MANUAL);
844 HandleTapeButtonKeys(key);
845 HandleSoundButtonKeys(key);
848 if (game_status == GAME_MODE_PLAYING && !network_playing)
850 int centered_player_nr_next = -999;
852 if (key == setup.shortcut.focus_player_all)
853 centered_player_nr_next = -1;
855 for (i = 0; i < MAX_PLAYERS; i++)
856 if (key == setup.shortcut.focus_player[i])
857 centered_player_nr_next = i;
859 if (centered_player_nr_next != -999)
861 game.centered_player_nr_next = centered_player_nr_next;
862 game.set_centered_player = TRUE;
866 tape.centered_player_nr_next = game.centered_player_nr_next;
867 tape.set_centered_player = TRUE;
872 HandleKeysSpecial(key);
874 if (HandleGadgetsKeyInput(key))
876 if (key != KSYM_Escape) /* always allow ESC key to be handled */
877 key = KSYM_UNDEFINED;
882 case GAME_MODE_PSEUDO_TYPENAME:
883 HandleTypeName(0, key);
886 case GAME_MODE_TITLE:
888 case GAME_MODE_LEVELS:
889 case GAME_MODE_LEVELNR:
890 case GAME_MODE_SETUP:
892 case GAME_MODE_SCORES:
897 if (game_status == GAME_MODE_TITLE)
898 HandleTitleScreen(0, 0, 0, 0, MB_MENU_CHOICE);
899 else if (game_status == GAME_MODE_MAIN)
900 HandleMainMenu(0, 0, 0, 0, MB_MENU_CHOICE);
901 else if (game_status == GAME_MODE_LEVELS)
902 HandleChooseLevelSet(0, 0, 0, 0, MB_MENU_CHOICE);
903 else if (game_status == GAME_MODE_LEVELNR)
904 HandleChooseLevelNr(0, 0, 0, 0, MB_MENU_CHOICE);
905 else if (game_status == GAME_MODE_SETUP)
906 HandleSetupScreen(0, 0, 0, 0, MB_MENU_CHOICE);
907 else if (game_status == GAME_MODE_INFO)
908 HandleInfoScreen(0, 0, 0, 0, MB_MENU_CHOICE);
909 else if (game_status == GAME_MODE_SCORES)
910 HandleHallOfFame(0, 0, 0, 0, MB_MENU_CHOICE);
914 if (game_status != GAME_MODE_MAIN)
915 FadeSkipNextFadeIn();
917 if (game_status == GAME_MODE_TITLE)
918 HandleTitleScreen(0, 0, 0, 0, MB_MENU_LEAVE);
919 else if (game_status == GAME_MODE_LEVELS)
920 HandleChooseLevelSet(0, 0, 0, 0, MB_MENU_LEAVE);
921 else if (game_status == GAME_MODE_LEVELNR)
922 HandleChooseLevelNr(0, 0, 0, 0, MB_MENU_LEAVE);
923 else if (game_status == GAME_MODE_SETUP)
924 HandleSetupScreen(0, 0, 0, 0, MB_MENU_LEAVE);
925 else if (game_status == GAME_MODE_INFO)
926 HandleInfoScreen(0, 0, 0, 0, MB_MENU_LEAVE);
927 else if (game_status == GAME_MODE_SCORES)
928 HandleHallOfFame(0, 0, 0, 0, MB_MENU_LEAVE);
932 if (game_status == GAME_MODE_LEVELS)
933 HandleChooseLevelSet(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
934 else if (game_status == GAME_MODE_LEVELNR)
935 HandleChooseLevelNr(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
936 else if (game_status == GAME_MODE_SETUP)
937 HandleSetupScreen(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
938 else if (game_status == GAME_MODE_INFO)
939 HandleInfoScreen(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
940 else if (game_status == GAME_MODE_SCORES)
941 HandleHallOfFame(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
945 if (game_status == GAME_MODE_LEVELS)
946 HandleChooseLevelSet(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
947 else if (game_status == GAME_MODE_LEVELNR)
948 HandleChooseLevelNr(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
949 else if (game_status == GAME_MODE_SETUP)
950 HandleSetupScreen(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
951 else if (game_status == GAME_MODE_INFO)
952 HandleInfoScreen(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
953 else if (game_status == GAME_MODE_SCORES)
954 HandleHallOfFame(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
959 GameFrameDelay = (GameFrameDelay == 500 ? GAME_FRAME_DELAY : 500);
963 setup.sp_show_border_elements = !setup.sp_show_border_elements;
964 printf("Supaplex border elements %s\n",
965 setup.sp_show_border_elements ? "enabled" : "disabled");
974 case GAME_MODE_EDITOR:
975 if (!anyTextGadgetActiveOrJustFinished || key == KSYM_Escape)
976 HandleLevelEditorKeyInput(key);
979 case GAME_MODE_PLAYING:
984 RequestQuitGame(setup.ask_on_escape);
1002 if (GameFrameDelay == 500)
1003 GameFrameDelay = GAME_FRAME_DELAY;
1005 GameFrameDelay = 500;
1008 GameFrameDelay = (key - KSYM_0) * 10;
1009 printf("Game speed == %d%% (%d ms delay between two frames)\n",
1010 GAME_FRAME_DELAY * 100 / GameFrameDelay, GameFrameDelay);
1016 options.debug = FALSE;
1017 printf("debug mode disabled\n");
1021 options.debug = TRUE;
1022 printf("debug mode enabled\n");
1027 if (!global.fps_slowdown)
1029 global.fps_slowdown = TRUE;
1030 global.fps_slowdown_factor = 2;
1031 printf("fps slowdown enabled -- display only every 2nd frame\n");
1033 else if (global.fps_slowdown_factor == 2)
1035 global.fps_slowdown_factor = 4;
1036 printf("fps slowdown enabled -- display only every 4th frame\n");
1040 global.fps_slowdown = FALSE;
1041 global.fps_slowdown_factor = 1;
1042 printf("fps slowdown disabled\n");
1047 ScrollStepSize = TILEX / 8;
1048 printf("ScrollStepSize == %d (1/8)\n", ScrollStepSize);
1052 ScrollStepSize = TILEX / 4;
1053 printf("ScrollStepSize == %d (1/4)\n", ScrollStepSize);
1057 ScrollStepSize = TILEX / 2;
1058 printf("ScrollStepSize == %d (1/2)\n", ScrollStepSize);
1062 ScrollStepSize = TILEX;
1063 printf("ScrollStepSize == %d (1/1)\n", ScrollStepSize);
1067 printf("::: currently using game engine version %d\n",
1068 game.engine_version);
1079 if (key == KSYM_Escape)
1081 game_status = GAME_MODE_MAIN;
1089 void HandleNoEvent()
1091 if (button_status && game_status != GAME_MODE_PLAYING)
1093 HandleButton(0, 0, -button_status, button_status);
1098 #if defined(NETWORK_AVALIABLE)
1099 if (options.network)
1106 static int HandleJoystickForAllPlayers()
1111 for (i = 0; i < MAX_PLAYERS; i++)
1113 byte joy_action = 0;
1116 if (!setup.input[i].use_joystick)
1120 joy_action = Joystick(i);
1121 result |= joy_action;
1123 if (!setup.input[i].use_joystick)
1126 stored_player[i].action = joy_action;
1132 void HandleJoystick()
1134 int joystick = HandleJoystickForAllPlayers();
1135 int keyboard = key_joystick_mapping;
1136 int joy = (joystick | keyboard);
1137 int left = joy & JOY_LEFT;
1138 int right = joy & JOY_RIGHT;
1139 int up = joy & JOY_UP;
1140 int down = joy & JOY_DOWN;
1141 int button = joy & JOY_BUTTON;
1142 int newbutton = (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED);
1143 int dx = (left ? -1 : right ? 1 : 0);
1144 int dy = (up ? -1 : down ? 1 : 0);
1146 switch (game_status)
1148 case GAME_MODE_TITLE:
1149 case GAME_MODE_MAIN:
1150 case GAME_MODE_LEVELS:
1151 case GAME_MODE_LEVELNR:
1152 case GAME_MODE_SETUP:
1153 case GAME_MODE_INFO:
1155 static unsigned int joystickmove_delay = 0;
1157 if (joystick && !button &&
1158 !DelayReached(&joystickmove_delay, GADGET_FRAME_DELAY))
1159 newbutton = dx = dy = 0;
1161 if (game_status == GAME_MODE_TITLE)
1162 HandleTitleScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1163 else if (game_status == GAME_MODE_MAIN)
1164 HandleMainMenu(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1165 else if (game_status == GAME_MODE_LEVELS)
1166 HandleChooseLevelSet(0,0,dx,dy,newbutton?MB_MENU_CHOICE : MB_MENU_MARK);
1167 else if (game_status == GAME_MODE_LEVELNR)
1168 HandleChooseLevelNr(0,0,dx,dy,newbutton? MB_MENU_CHOICE : MB_MENU_MARK);
1169 else if (game_status == GAME_MODE_SETUP)
1170 HandleSetupScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1171 else if (game_status == GAME_MODE_INFO)
1172 HandleInfoScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1176 case GAME_MODE_SCORES:
1177 HandleHallOfFame(0, 0, dx, dy, !newbutton);
1180 case GAME_MODE_EDITOR:
1181 HandleLevelEditorIdle();
1184 case GAME_MODE_PLAYING:
1185 if (tape.playing || keyboard)
1186 newbutton = ((joy & JOY_BUTTON) != 0);
1189 if (local_player->LevelSolved_GameEnd && newbutton)
1191 if (AllPlayersGone && newbutton)