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);
164 #if defined(TARGET_SDL2)
165 case EVENT_FINGERPRESS:
166 case EVENT_FINGERRELEASE:
167 case EVENT_FINGERMOTION:
168 HandleFingerEvent((FingerEvent *) &event);
173 case EVENT_KEYRELEASE:
174 HandleKeyEvent((KeyEvent *) &event);
178 HandleOtherEvents(&event);
185 /* when playing, display a special mouse pointer inside the playfield */
186 if (game_status == GAME_MODE_PLAYING && !tape.pausing)
188 if (!playfield_cursor_set && cursor_inside_playfield &&
189 DelayReached(&playfield_cursor_delay, 1000))
191 SetMouseCursor(CURSOR_PLAYFIELD);
192 playfield_cursor_set = TRUE;
195 else if (playfield_cursor_set)
197 SetMouseCursor(CURSOR_DEFAULT);
198 playfield_cursor_set = FALSE;
204 /* don't use all CPU time when idle; the main loop while playing
205 has its own synchronization and is CPU friendly, too */
207 if (game_status == GAME_MODE_PLAYING)
214 if (!PendingEvent()) /* delay only if no pending events */
218 /* refresh window contents from drawing buffer, if needed */
221 if (game_status == GAME_MODE_QUIT)
226 void HandleOtherEvents(Event *event)
231 HandleExposeEvent((ExposeEvent *) event);
234 case EVENT_UNMAPNOTIFY:
236 /* This causes the game to stop not only when iconified, but also
237 when on another virtual desktop, which might be not desired. */
238 SleepWhileUnmapped();
244 HandleFocusEvent((FocusChangeEvent *) event);
247 case EVENT_CLIENTMESSAGE:
248 HandleClientMessageEvent((ClientMessageEvent *) event);
251 #if defined(TARGET_SDL)
252 case SDL_JOYAXISMOTION:
253 case SDL_JOYBUTTONDOWN:
254 case SDL_JOYBUTTONUP:
255 HandleJoystickEvent(event);
259 HandleWindowManagerEvent(event);
268 void ClearEventQueue()
270 while (PendingEvent())
278 case EVENT_BUTTONRELEASE:
279 button_status = MB_RELEASED;
282 case EVENT_KEYRELEASE:
286 key_joystick_mapping = 0;
291 HandleOtherEvents(&event);
297 void ClearPlayerAction()
301 /* simulate key release events for still pressed keys */
302 key_joystick_mapping = 0;
303 for (i = 0; i < MAX_PLAYERS; i++)
304 stored_player[i].action = 0;
307 void SleepWhileUnmapped()
309 boolean window_unmapped = TRUE;
311 KeyboardAutoRepeatOn();
313 while (window_unmapped)
321 case EVENT_BUTTONRELEASE:
322 button_status = MB_RELEASED;
325 case EVENT_KEYRELEASE:
326 key_joystick_mapping = 0;
329 case EVENT_MAPNOTIFY:
330 window_unmapped = FALSE;
333 case EVENT_UNMAPNOTIFY:
334 /* this is only to surely prevent the 'should not happen' case
335 * of recursively looping between 'SleepWhileUnmapped()' and
336 * 'HandleOtherEvents()' which usually calls this funtion.
341 HandleOtherEvents(&event);
346 if (game_status == GAME_MODE_PLAYING)
347 KeyboardAutoRepeatOffUnlessAutoplay();
350 void HandleExposeEvent(ExposeEvent *event)
352 #if !defined(TARGET_SDL)
353 RedrawPlayfield(FALSE, event->x, event->y, event->width, event->height);
358 void HandleButtonEvent(ButtonEvent *event)
361 printf("::: BUTTON EVENT: button %d %s\n", event->button,
362 event->type == EVENT_BUTTONPRESS ? "pressed" : "released");
365 motion_status = FALSE;
367 if (event->type == EVENT_BUTTONPRESS)
368 button_status = event->button;
370 button_status = MB_RELEASED;
372 HandleButton(event->x, event->y, button_status, event->button);
375 void HandleMotionEvent(MotionEvent *event)
377 if (!PointerInWindow(window))
378 return; /* window and pointer are on different screens */
380 if (button_status == MB_RELEASED && game_status != GAME_MODE_EDITOR)
383 motion_status = TRUE;
385 HandleButton(event->x, event->y, button_status, button_status);
388 #if defined(TARGET_SDL2)
389 void HandleFingerEvent(FingerEvent *event)
392 Error(ERR_DEBUG, "FINGER EVENT: finger was %s, touch ID %lld, finger ID %lld, x/y %f/%f, dx/dy %f/%f, pressure %f",
393 (event->type == EVENT_FINGERPRESS ? "pressed" :
394 event->type == EVENT_FINGERRELEASE ? "released" : "moved"),
398 event->dx, event->dy,
405 if (event->type == EVENT_FINGERPRESS)
406 button_status = event->button;
408 button_status = MB_RELEASED;
410 HandleButton(event->x, event->y, button_status, event->button);
415 void HandleKeyEvent(KeyEvent *event)
417 int key_status = (event->type==EVENT_KEYPRESS ? KEY_PRESSED : KEY_RELEASED);
418 boolean with_modifiers = (game_status == GAME_MODE_PLAYING ? FALSE : TRUE);
419 Key key = GetEventKey(event, with_modifiers);
420 Key keymod = (with_modifiers ? GetEventKey(event, FALSE) : key);
423 printf("::: KEY EVENT: %d %s\n", GetEventKey(event, TRUE),
424 event->type == EVENT_KEYPRESS ? "pressed" : "released");
427 HandleKeyModState(keymod, key_status);
428 HandleKey(key, key_status);
431 void HandleFocusEvent(FocusChangeEvent *event)
433 static int old_joystick_status = -1;
435 if (event->type == EVENT_FOCUSOUT)
437 KeyboardAutoRepeatOn();
438 old_joystick_status = joystick.status;
439 joystick.status = JOYSTICK_NOT_AVAILABLE;
443 else if (event->type == EVENT_FOCUSIN)
445 /* When there are two Rocks'n'Diamonds windows which overlap and
446 the player moves the pointer from one game window to the other,
447 a 'FocusOut' event is generated for the window the pointer is
448 leaving and a 'FocusIn' event is generated for the window the
449 pointer is entering. In some cases, it can happen that the
450 'FocusIn' event is handled by the one game process before the
451 'FocusOut' event by the other game process. In this case the
452 X11 environment would end up with activated keyboard auto repeat,
453 because unfortunately this is a global setting and not (which
454 would be far better) set for each X11 window individually.
455 The effect would be keyboard auto repeat while playing the game
456 (game_status == GAME_MODE_PLAYING), which is not desired.
457 To avoid this special case, we just wait 1/10 second before
458 processing the 'FocusIn' event.
461 if (game_status == GAME_MODE_PLAYING)
464 KeyboardAutoRepeatOffUnlessAutoplay();
467 if (old_joystick_status != -1)
468 joystick.status = old_joystick_status;
472 void HandleClientMessageEvent(ClientMessageEvent *event)
474 if (CheckCloseWindowEvent(event))
478 void HandleWindowManagerEvent(Event *event)
480 #if defined(TARGET_SDL)
481 SDLHandleWindowManagerEvent(event);
485 void HandleButton(int mx, int my, int button, int button_nr)
487 static int old_mx = 0, old_my = 0;
501 if (HandleGadgets(mx, my, button))
503 /* do not handle this button event anymore */
504 mx = my = -32; /* force mouse event to be outside screen tiles */
507 /* do not use scroll wheel button events for anything other than gadgets */
508 if (IS_WHEEL_BUTTON(button_nr))
513 case GAME_MODE_TITLE:
514 HandleTitleScreen(mx, my, 0, 0, button);
518 HandleMainMenu(mx, my, 0, 0, button);
521 case GAME_MODE_PSEUDO_TYPENAME:
522 HandleTypeName(0, KSYM_Return);
525 case GAME_MODE_LEVELS:
526 HandleChooseLevelSet(mx, my, 0, 0, button);
529 case GAME_MODE_LEVELNR:
530 HandleChooseLevelNr(mx, my, 0, 0, button);
533 case GAME_MODE_SCORES:
534 HandleHallOfFame(0, 0, 0, 0, button);
537 case GAME_MODE_EDITOR:
538 HandleLevelEditorIdle();
542 HandleInfoScreen(mx, my, 0, 0, button);
545 case GAME_MODE_SETUP:
546 HandleSetupScreen(mx, my, 0, 0, button);
549 case GAME_MODE_PLAYING:
551 if (button == MB_PRESSED && !motion_status && IN_GFX_SCREEN(mx, my))
552 DumpTile(LEVELX((mx - SX) / TILEX), LEVELY((my - SY) / TILEY));
561 static boolean is_string_suffix(char *string, char *suffix)
563 int string_len = strlen(string);
564 int suffix_len = strlen(suffix);
566 if (suffix_len > string_len)
569 return (strEqual(&string[string_len - suffix_len], suffix));
572 #define MAX_CHEAT_INPUT_LEN 32
574 static void HandleKeysSpecial(Key key)
576 static char cheat_input[2 * MAX_CHEAT_INPUT_LEN + 1] = "";
577 char letter = getCharFromKey(key);
578 int cheat_input_len = strlen(cheat_input);
584 if (cheat_input_len >= 2 * MAX_CHEAT_INPUT_LEN)
586 for (i = 0; i < MAX_CHEAT_INPUT_LEN + 1; i++)
587 cheat_input[i] = cheat_input[MAX_CHEAT_INPUT_LEN + i];
589 cheat_input_len = MAX_CHEAT_INPUT_LEN;
592 cheat_input[cheat_input_len++] = letter;
593 cheat_input[cheat_input_len] = '\0';
596 printf("::: '%s' [%d]\n", cheat_input, cheat_input_len);
599 if (game_status == GAME_MODE_MAIN)
601 if (is_string_suffix(cheat_input, ":insert-solution-tape") ||
602 is_string_suffix(cheat_input, ":ist"))
604 InsertSolutionTape();
606 else if (is_string_suffix(cheat_input, ":reload-graphics") ||
607 is_string_suffix(cheat_input, ":rg"))
609 ReloadCustomArtwork(1 << ARTWORK_TYPE_GRAPHICS);
612 else if (is_string_suffix(cheat_input, ":reload-sounds") ||
613 is_string_suffix(cheat_input, ":rs"))
615 ReloadCustomArtwork(1 << ARTWORK_TYPE_SOUNDS);
618 else if (is_string_suffix(cheat_input, ":reload-music") ||
619 is_string_suffix(cheat_input, ":rm"))
621 ReloadCustomArtwork(1 << ARTWORK_TYPE_MUSIC);
624 else if (is_string_suffix(cheat_input, ":reload-artwork") ||
625 is_string_suffix(cheat_input, ":ra"))
627 ReloadCustomArtwork(1 << ARTWORK_TYPE_GRAPHICS |
628 1 << ARTWORK_TYPE_SOUNDS |
629 1 << ARTWORK_TYPE_MUSIC);
632 else if (is_string_suffix(cheat_input, ":dump-level") ||
633 is_string_suffix(cheat_input, ":dl"))
637 else if (is_string_suffix(cheat_input, ":dump-tape") ||
638 is_string_suffix(cheat_input, ":dt"))
642 else if (is_string_suffix(cheat_input, ":save-native-level") ||
643 is_string_suffix(cheat_input, ":snl"))
645 SaveNativeLevel(&level);
648 else if (game_status == GAME_MODE_PLAYING)
651 if (is_string_suffix(cheat_input, ".q"))
652 DEBUG_SetMaximumDynamite();
655 else if (game_status == GAME_MODE_EDITOR)
657 if (is_string_suffix(cheat_input, ":dump-brush") ||
658 is_string_suffix(cheat_input, ":DB"))
662 else if (is_string_suffix(cheat_input, ":DDB"))
669 void HandleKey(Key key, int key_status)
671 boolean anyTextGadgetActiveOrJustFinished = anyTextGadgetActive();
672 static struct SetupKeyboardInfo ski;
673 static struct SetupShortcutInfo ssi;
682 { &ski.left, &ssi.snap_left, DEFAULT_KEY_LEFT, JOY_LEFT },
683 { &ski.right, &ssi.snap_right, DEFAULT_KEY_RIGHT, JOY_RIGHT },
684 { &ski.up, &ssi.snap_up, DEFAULT_KEY_UP, JOY_UP },
685 { &ski.down, &ssi.snap_down, DEFAULT_KEY_DOWN, JOY_DOWN },
686 { &ski.snap, NULL, DEFAULT_KEY_SNAP, JOY_BUTTON_SNAP },
687 { &ski.drop, NULL, DEFAULT_KEY_DROP, JOY_BUTTON_DROP }
692 if (game_status == GAME_MODE_PLAYING)
694 /* only needed for single-step tape recording mode */
695 static boolean clear_snap_button[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
696 static boolean clear_drop_button[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
697 static boolean element_snapped[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
698 static boolean element_dropped[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
701 for (pnr = 0; pnr < MAX_PLAYERS; pnr++)
705 if (setup.input[pnr].use_joystick)
708 ski = setup.input[pnr].key;
710 for (i = 0; i < NUM_PLAYER_ACTIONS; i++)
711 if (key == *key_info[i].key_custom)
712 key_action |= key_info[i].action;
714 /* use combined snap+direction keys for the first player only */
717 ssi = setup.shortcut;
719 for (i = 0; i < NUM_DIRECTIONS; i++)
720 if (key == *key_info[i].key_snap)
721 key_action |= key_info[i].action | JOY_BUTTON_SNAP;
724 /* clear delayed snap and drop actions in single step mode (see below) */
725 if (tape.single_step)
727 if (clear_snap_button[pnr])
729 stored_player[pnr].action &= ~KEY_BUTTON_SNAP;
730 clear_snap_button[pnr] = FALSE;
733 if (clear_drop_button[pnr])
735 stored_player[pnr].action &= ~KEY_BUTTON_DROP;
736 clear_drop_button[pnr] = FALSE;
740 if (key_status == KEY_PRESSED)
741 stored_player[pnr].action |= key_action;
743 stored_player[pnr].action &= ~key_action;
745 if (tape.single_step && tape.recording && tape.pausing)
747 if (key_status == KEY_PRESSED && key_action & KEY_MOTION)
749 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
751 /* if snap key already pressed, don't snap when releasing (below) */
752 if (stored_player[pnr].action & KEY_BUTTON_SNAP)
753 element_snapped[pnr] = TRUE;
755 /* if drop key already pressed, don't drop when releasing (below) */
756 if (stored_player[pnr].action & KEY_BUTTON_DROP)
757 element_dropped[pnr] = TRUE;
760 else if (key_status == KEY_PRESSED && key_action & KEY_BUTTON_DROP)
762 if (level.game_engine_type == GAME_ENGINE_TYPE_EM ||
763 level.game_engine_type == GAME_ENGINE_TYPE_SP)
766 printf("::: drop key pressed\n");
769 if (level.game_engine_type == GAME_ENGINE_TYPE_SP &&
770 getRedDiskReleaseFlag_SP() == 0)
771 stored_player[pnr].action &= ~KEY_BUTTON_DROP;
773 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
777 else if (key_status == KEY_RELEASED && key_action & KEY_BUTTON)
779 if (key_action & KEY_BUTTON_SNAP)
781 /* if snap key was released without moving (see above), snap now */
782 if (!element_snapped[pnr])
784 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
786 stored_player[pnr].action |= KEY_BUTTON_SNAP;
788 /* clear delayed snap button on next event */
789 clear_snap_button[pnr] = TRUE;
792 element_snapped[pnr] = FALSE;
796 if (key_action & KEY_BUTTON_DROP &&
797 level.game_engine_type == GAME_ENGINE_TYPE_RND)
799 /* if drop key was released without moving (see above), drop now */
800 if (!element_dropped[pnr])
802 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
804 if (level.game_engine_type != GAME_ENGINE_TYPE_SP ||
805 getRedDiskReleaseFlag_SP() != 0)
806 stored_player[pnr].action |= KEY_BUTTON_DROP;
808 /* clear delayed drop button on next event */
809 clear_drop_button[pnr] = TRUE;
812 element_dropped[pnr] = FALSE;
817 else if (tape.recording && tape.pausing)
819 /* prevent key release events from un-pausing a paused game */
820 if (key_status == KEY_PRESSED && key_action & KEY_ACTION)
821 TapeTogglePause(TAPE_TOGGLE_MANUAL);
827 for (i = 0; i < NUM_PLAYER_ACTIONS; i++)
828 if (key == key_info[i].key_default)
829 joy |= key_info[i].action;
834 if (key_status == KEY_PRESSED)
835 key_joystick_mapping |= joy;
837 key_joystick_mapping &= ~joy;
842 if (game_status != GAME_MODE_PLAYING)
843 key_joystick_mapping = 0;
845 if (key_status == KEY_RELEASED)
848 if ((key == KSYM_Return || key == KSYM_KP_Enter) &&
849 (GetKeyModState() & KMOD_Alt) && video.fullscreen_available)
851 setup.fullscreen = !setup.fullscreen;
853 ToggleFullscreenIfNeeded();
855 if (game_status == GAME_MODE_SETUP)
856 RedrawSetupScreenAfterFullscreenToggle();
862 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd &&
863 (key == KSYM_Return || key == setup.shortcut.toggle_pause))
865 if (game_status == GAME_MODE_PLAYING && AllPlayersGone &&
866 (key == KSYM_Return || key == setup.shortcut.toggle_pause))
874 if (game_status == GAME_MODE_MAIN &&
875 (key == setup.shortcut.toggle_pause || key == KSYM_space))
877 StartGameActions(options.network, setup.autorecord, level.random_seed);
882 if (game_status == GAME_MODE_MAIN || game_status == GAME_MODE_PLAYING)
884 if (key == setup.shortcut.save_game)
886 else if (key == setup.shortcut.load_game)
888 else if (key == setup.shortcut.toggle_pause)
889 TapeTogglePause(TAPE_TOGGLE_MANUAL);
891 HandleTapeButtonKeys(key);
892 HandleSoundButtonKeys(key);
895 if (game_status == GAME_MODE_PLAYING && !network_playing)
897 int centered_player_nr_next = -999;
899 if (key == setup.shortcut.focus_player_all)
900 centered_player_nr_next = -1;
902 for (i = 0; i < MAX_PLAYERS; i++)
903 if (key == setup.shortcut.focus_player[i])
904 centered_player_nr_next = i;
906 if (centered_player_nr_next != -999)
908 game.centered_player_nr_next = centered_player_nr_next;
909 game.set_centered_player = TRUE;
913 tape.centered_player_nr_next = game.centered_player_nr_next;
914 tape.set_centered_player = TRUE;
919 HandleKeysSpecial(key);
921 if (HandleGadgetsKeyInput(key))
923 if (key != KSYM_Escape) /* always allow ESC key to be handled */
924 key = KSYM_UNDEFINED;
929 case GAME_MODE_PSEUDO_TYPENAME:
930 HandleTypeName(0, key);
933 case GAME_MODE_TITLE:
935 case GAME_MODE_LEVELS:
936 case GAME_MODE_LEVELNR:
937 case GAME_MODE_SETUP:
939 case GAME_MODE_SCORES:
944 if (game_status == GAME_MODE_TITLE)
945 HandleTitleScreen(0, 0, 0, 0, MB_MENU_CHOICE);
946 else if (game_status == GAME_MODE_MAIN)
947 HandleMainMenu(0, 0, 0, 0, MB_MENU_CHOICE);
948 else if (game_status == GAME_MODE_LEVELS)
949 HandleChooseLevelSet(0, 0, 0, 0, MB_MENU_CHOICE);
950 else if (game_status == GAME_MODE_LEVELNR)
951 HandleChooseLevelNr(0, 0, 0, 0, MB_MENU_CHOICE);
952 else if (game_status == GAME_MODE_SETUP)
953 HandleSetupScreen(0, 0, 0, 0, MB_MENU_CHOICE);
954 else if (game_status == GAME_MODE_INFO)
955 HandleInfoScreen(0, 0, 0, 0, MB_MENU_CHOICE);
956 else if (game_status == GAME_MODE_SCORES)
957 HandleHallOfFame(0, 0, 0, 0, MB_MENU_CHOICE);
961 if (game_status != GAME_MODE_MAIN)
962 FadeSkipNextFadeIn();
964 if (game_status == GAME_MODE_TITLE)
965 HandleTitleScreen(0, 0, 0, 0, MB_MENU_LEAVE);
966 else if (game_status == GAME_MODE_LEVELS)
967 HandleChooseLevelSet(0, 0, 0, 0, MB_MENU_LEAVE);
968 else if (game_status == GAME_MODE_LEVELNR)
969 HandleChooseLevelNr(0, 0, 0, 0, MB_MENU_LEAVE);
970 else if (game_status == GAME_MODE_SETUP)
971 HandleSetupScreen(0, 0, 0, 0, MB_MENU_LEAVE);
972 else if (game_status == GAME_MODE_INFO)
973 HandleInfoScreen(0, 0, 0, 0, MB_MENU_LEAVE);
974 else if (game_status == GAME_MODE_SCORES)
975 HandleHallOfFame(0, 0, 0, 0, MB_MENU_LEAVE);
979 if (game_status == GAME_MODE_LEVELS)
980 HandleChooseLevelSet(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
981 else if (game_status == GAME_MODE_LEVELNR)
982 HandleChooseLevelNr(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
983 else if (game_status == GAME_MODE_SETUP)
984 HandleSetupScreen(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
985 else if (game_status == GAME_MODE_INFO)
986 HandleInfoScreen(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
987 else if (game_status == GAME_MODE_SCORES)
988 HandleHallOfFame(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
992 if (game_status == GAME_MODE_LEVELS)
993 HandleChooseLevelSet(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
994 else if (game_status == GAME_MODE_LEVELNR)
995 HandleChooseLevelNr(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
996 else if (game_status == GAME_MODE_SETUP)
997 HandleSetupScreen(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
998 else if (game_status == GAME_MODE_INFO)
999 HandleInfoScreen(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1000 else if (game_status == GAME_MODE_SCORES)
1001 HandleHallOfFame(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1006 GameFrameDelay = (GameFrameDelay == 500 ? GAME_FRAME_DELAY : 500);
1010 setup.sp_show_border_elements = !setup.sp_show_border_elements;
1011 printf("Supaplex border elements %s\n",
1012 setup.sp_show_border_elements ? "enabled" : "disabled");
1021 case GAME_MODE_EDITOR:
1022 if (!anyTextGadgetActiveOrJustFinished || key == KSYM_Escape)
1023 HandleLevelEditorKeyInput(key);
1026 case GAME_MODE_PLAYING:
1031 RequestQuitGame(setup.ask_on_escape);
1049 if (GameFrameDelay == 500)
1050 GameFrameDelay = GAME_FRAME_DELAY;
1052 GameFrameDelay = 500;
1055 GameFrameDelay = (key - KSYM_0) * 10;
1056 printf("Game speed == %d%% (%d ms delay between two frames)\n",
1057 GAME_FRAME_DELAY * 100 / GameFrameDelay, GameFrameDelay);
1063 options.debug = FALSE;
1064 printf("debug mode disabled\n");
1068 options.debug = TRUE;
1069 printf("debug mode enabled\n");
1074 if (!global.fps_slowdown)
1076 global.fps_slowdown = TRUE;
1077 global.fps_slowdown_factor = 2;
1078 printf("fps slowdown enabled -- display only every 2nd frame\n");
1080 else if (global.fps_slowdown_factor == 2)
1082 global.fps_slowdown_factor = 4;
1083 printf("fps slowdown enabled -- display only every 4th frame\n");
1087 global.fps_slowdown = FALSE;
1088 global.fps_slowdown_factor = 1;
1089 printf("fps slowdown disabled\n");
1094 ScrollStepSize = TILEX / 8;
1095 printf("ScrollStepSize == %d (1/8)\n", ScrollStepSize);
1099 ScrollStepSize = TILEX / 4;
1100 printf("ScrollStepSize == %d (1/4)\n", ScrollStepSize);
1104 ScrollStepSize = TILEX / 2;
1105 printf("ScrollStepSize == %d (1/2)\n", ScrollStepSize);
1109 ScrollStepSize = TILEX;
1110 printf("ScrollStepSize == %d (1/1)\n", ScrollStepSize);
1114 printf("::: currently using game engine version %d\n",
1115 game.engine_version);
1126 if (key == KSYM_Escape)
1128 game_status = GAME_MODE_MAIN;
1136 void HandleNoEvent()
1138 if (button_status && game_status != GAME_MODE_PLAYING)
1140 HandleButton(0, 0, -button_status, button_status);
1145 #if defined(NETWORK_AVALIABLE)
1146 if (options.network)
1153 static int HandleJoystickForAllPlayers()
1158 for (i = 0; i < MAX_PLAYERS; i++)
1160 byte joy_action = 0;
1163 if (!setup.input[i].use_joystick)
1167 joy_action = Joystick(i);
1168 result |= joy_action;
1170 if (!setup.input[i].use_joystick)
1173 stored_player[i].action = joy_action;
1179 void HandleJoystick()
1181 int joystick = HandleJoystickForAllPlayers();
1182 int keyboard = key_joystick_mapping;
1183 int joy = (joystick | keyboard);
1184 int left = joy & JOY_LEFT;
1185 int right = joy & JOY_RIGHT;
1186 int up = joy & JOY_UP;
1187 int down = joy & JOY_DOWN;
1188 int button = joy & JOY_BUTTON;
1189 int newbutton = (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED);
1190 int dx = (left ? -1 : right ? 1 : 0);
1191 int dy = (up ? -1 : down ? 1 : 0);
1193 switch (game_status)
1195 case GAME_MODE_TITLE:
1196 case GAME_MODE_MAIN:
1197 case GAME_MODE_LEVELS:
1198 case GAME_MODE_LEVELNR:
1199 case GAME_MODE_SETUP:
1200 case GAME_MODE_INFO:
1202 static unsigned int joystickmove_delay = 0;
1204 if (joystick && !button &&
1205 !DelayReached(&joystickmove_delay, GADGET_FRAME_DELAY))
1206 newbutton = dx = dy = 0;
1208 if (game_status == GAME_MODE_TITLE)
1209 HandleTitleScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1210 else if (game_status == GAME_MODE_MAIN)
1211 HandleMainMenu(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1212 else if (game_status == GAME_MODE_LEVELS)
1213 HandleChooseLevelSet(0,0,dx,dy,newbutton?MB_MENU_CHOICE : MB_MENU_MARK);
1214 else if (game_status == GAME_MODE_LEVELNR)
1215 HandleChooseLevelNr(0,0,dx,dy,newbutton? MB_MENU_CHOICE : MB_MENU_MARK);
1216 else if (game_status == GAME_MODE_SETUP)
1217 HandleSetupScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1218 else if (game_status == GAME_MODE_INFO)
1219 HandleInfoScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1223 case GAME_MODE_SCORES:
1224 HandleHallOfFame(0, 0, dx, dy, !newbutton);
1227 case GAME_MODE_EDITOR:
1228 HandleLevelEditorIdle();
1231 case GAME_MODE_PLAYING:
1232 if (tape.playing || keyboard)
1233 newbutton = ((joy & JOY_BUTTON) != 0);
1236 if (local_player->LevelSolved_GameEnd && newbutton)
1238 if (AllPlayersGone && newbutton)