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 1
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);
171 case EVENT_TEXTINPUT:
172 HandleTextEvent((TextEvent *) &event);
177 case EVENT_KEYRELEASE:
178 HandleKeyEvent((KeyEvent *) &event);
182 HandleOtherEvents(&event);
189 /* when playing, display a special mouse pointer inside the playfield */
190 if (game_status == GAME_MODE_PLAYING && !tape.pausing)
192 if (!playfield_cursor_set && cursor_inside_playfield &&
193 DelayReached(&playfield_cursor_delay, 1000))
195 SetMouseCursor(CURSOR_PLAYFIELD);
196 playfield_cursor_set = TRUE;
199 else if (playfield_cursor_set)
201 SetMouseCursor(CURSOR_DEFAULT);
202 playfield_cursor_set = FALSE;
208 /* don't use all CPU time when idle; the main loop while playing
209 has its own synchronization and is CPU friendly, too */
211 if (game_status == GAME_MODE_PLAYING)
218 if (!PendingEvent()) /* delay only if no pending events */
222 /* refresh window contents from drawing buffer, if needed */
225 if (game_status == GAME_MODE_QUIT)
230 void HandleOtherEvents(Event *event)
235 HandleExposeEvent((ExposeEvent *) event);
238 case EVENT_UNMAPNOTIFY:
240 /* This causes the game to stop not only when iconified, but also
241 when on another virtual desktop, which might be not desired. */
242 SleepWhileUnmapped();
248 HandleFocusEvent((FocusChangeEvent *) event);
251 case EVENT_CLIENTMESSAGE:
252 HandleClientMessageEvent((ClientMessageEvent *) event);
255 #if defined(TARGET_SDL)
256 case SDL_JOYAXISMOTION:
257 case SDL_JOYBUTTONDOWN:
258 case SDL_JOYBUTTONUP:
259 HandleJoystickEvent(event);
263 HandleWindowManagerEvent(event);
272 void ClearEventQueue()
274 while (PendingEvent())
282 case EVENT_BUTTONRELEASE:
283 button_status = MB_RELEASED;
286 case EVENT_KEYRELEASE:
290 key_joystick_mapping = 0;
295 HandleOtherEvents(&event);
301 void ClearPlayerAction()
305 /* simulate key release events for still pressed keys */
306 key_joystick_mapping = 0;
307 for (i = 0; i < MAX_PLAYERS; i++)
308 stored_player[i].action = 0;
311 void SleepWhileUnmapped()
313 boolean window_unmapped = TRUE;
315 KeyboardAutoRepeatOn();
317 while (window_unmapped)
325 case EVENT_BUTTONRELEASE:
326 button_status = MB_RELEASED;
329 case EVENT_KEYRELEASE:
330 key_joystick_mapping = 0;
333 case EVENT_MAPNOTIFY:
334 window_unmapped = FALSE;
337 case EVENT_UNMAPNOTIFY:
338 /* this is only to surely prevent the 'should not happen' case
339 * of recursively looping between 'SleepWhileUnmapped()' and
340 * 'HandleOtherEvents()' which usually calls this funtion.
345 HandleOtherEvents(&event);
350 if (game_status == GAME_MODE_PLAYING)
351 KeyboardAutoRepeatOffUnlessAutoplay();
354 void HandleExposeEvent(ExposeEvent *event)
356 #if !defined(TARGET_SDL)
357 RedrawPlayfield(FALSE, event->x, event->y, event->width, event->height);
362 void HandleButtonEvent(ButtonEvent *event)
365 Error(ERR_DEBUG, "BUTTON EVENT: button %d %s, x/y %d/%d\n",
367 event->type == EVENT_BUTTONPRESS ? "pressed" : "released",
371 motion_status = FALSE;
373 if (event->type == EVENT_BUTTONPRESS)
374 button_status = event->button;
376 button_status = MB_RELEASED;
378 HandleButton(event->x, event->y, button_status, event->button);
381 void HandleMotionEvent(MotionEvent *event)
383 if (!PointerInWindow(window))
384 return; /* window and pointer are on different screens */
386 if (button_status == MB_RELEASED && game_status != GAME_MODE_EDITOR)
389 motion_status = TRUE;
391 Error(ERR_DEBUG, "MOTION EVENT: button %d moved, x/y %d/%d\n",
392 button_status, event->x, event->y);
394 HandleButton(event->x, event->y, button_status, button_status);
397 #if defined(TARGET_SDL2)
398 void HandleFingerEvent(FingerEvent *event)
401 static int num_events = 0;
406 Error(ERR_DEBUG, "FINGER EVENT: finger was %s, touch ID %lld, finger ID %lld, x/y %f/%f, dx/dy %f/%f, pressure %f",
407 event->type == EVENT_FINGERPRESS ? "pressed" :
408 event->type == EVENT_FINGERRELEASE ? "released" : "moved",
412 event->dx, event->dy,
417 int x = (int)(event->x * video.width);
418 int y = (int)(event->y * video.height);
419 int button = MB_LEFTBUTTON;
421 Error(ERR_DEBUG, "=> screen x/y %d/%d", x, y);
425 if (++num_events >= max_events)
431 if (event->type == EVENT_FINGERPRESS ||
432 event->type == EVENT_FINGERMOTION)
433 button_status = button;
435 button_status = MB_RELEASED;
437 int max_x = SX + SXSIZE;
438 int max_y = SY + SYSIZE;
442 if (game_status == GAME_MODE_PLAYING)
444 if (game_status == GAME_MODE_PLAYING &&
448 int key_status = (event->type == EVENT_FINGERRELEASE ? KEY_RELEASED :
451 Key key = (event->y < 1.0 / 3.0 ? setup.input[0].key.up :
452 event->y > 2.0 / 3.0 ? setup.input[0].key.down :
453 event->x < 1.0 / 3.0 ? setup.input[0].key.left :
454 event->x > 2.0 / 3.0 ? setup.input[0].key.right :
455 setup.input[0].key.drop);
457 Key key = (y < max_y / 3 ? setup.input[0].key.up :
458 y > 2 * max_y / 3 ? setup.input[0].key.down :
459 x < max_x / 3 ? setup.input[0].key.left :
460 x > 2 * max_x / 3 ? setup.input[0].key.right :
461 setup.input[0].key.drop);
464 Error(ERR_DEBUG, "=> key == %d, key_status == %d", key, key_status);
466 HandleKey(key, key_status);
471 Error(ERR_DEBUG, "::: button_status == %d, button == %d\n",
472 button_status, button);
474 HandleButton(x, y, button_status, button);
480 void HandleTextEvent(TextEvent *event)
482 char *text = event->text;
483 Key key = getKeyFromKeyName(text);
486 Error(ERR_DEBUG, "TEXT EVENT: text == '%s', resulting key == %d (%s)",
489 getKeyNameFromKey(key));
492 if (game_status != GAME_MODE_PLAYING && GetKeyModState() != KMOD_None)
494 HandleKey(key, KEY_PRESSED);
495 HandleKey(key, KEY_RELEASED);
500 void HandleKeyEvent(KeyEvent *event)
502 int key_status = (event->type == EVENT_KEYPRESS ? KEY_PRESSED : KEY_RELEASED);
503 boolean with_modifiers = (game_status == GAME_MODE_PLAYING ? FALSE : TRUE);
504 Key key = GetEventKey(event, with_modifiers);
505 Key keymod = (with_modifiers ? GetEventKey(event, FALSE) : key);
508 Error(ERR_DEBUG, "KEY EVENT: key was %s, keysym.scancode == %d, keysym.sym == %d, keymod = %d, GetKeyModState() = 0x%04x, resulting key == %d (%s)",
509 event->type == EVENT_KEYPRESS ? "pressed" : "released",
510 event->keysym.scancode,
515 getKeyNameFromKey(key));
519 if (key == KSYM_Menu)
520 Error(ERR_DEBUG, "menu key pressed");
521 else if (key == KSYM_Back)
522 Error(ERR_DEBUG, "back key pressed");
525 #if defined(PLATFORM_ANDROID)
526 // always map the "back" button to the "escape" key on Android devices
527 if (key == KSYM_Back)
531 #if defined(TARGET_SDL2)
532 HandleKeyModState(keymod, key_status);
534 if (game_status == GAME_MODE_PLAYING || GetKeyModState() == KMOD_None)
535 HandleKey(key, key_status);
537 HandleKeyModState(keymod, key_status);
538 HandleKey(key, key_status);
542 void HandleFocusEvent(FocusChangeEvent *event)
544 static int old_joystick_status = -1;
546 if (event->type == EVENT_FOCUSOUT)
548 KeyboardAutoRepeatOn();
549 old_joystick_status = joystick.status;
550 joystick.status = JOYSTICK_NOT_AVAILABLE;
554 else if (event->type == EVENT_FOCUSIN)
556 /* When there are two Rocks'n'Diamonds windows which overlap and
557 the player moves the pointer from one game window to the other,
558 a 'FocusOut' event is generated for the window the pointer is
559 leaving and a 'FocusIn' event is generated for the window the
560 pointer is entering. In some cases, it can happen that the
561 'FocusIn' event is handled by the one game process before the
562 'FocusOut' event by the other game process. In this case the
563 X11 environment would end up with activated keyboard auto repeat,
564 because unfortunately this is a global setting and not (which
565 would be far better) set for each X11 window individually.
566 The effect would be keyboard auto repeat while playing the game
567 (game_status == GAME_MODE_PLAYING), which is not desired.
568 To avoid this special case, we just wait 1/10 second before
569 processing the 'FocusIn' event.
572 if (game_status == GAME_MODE_PLAYING)
575 KeyboardAutoRepeatOffUnlessAutoplay();
578 if (old_joystick_status != -1)
579 joystick.status = old_joystick_status;
583 void HandleClientMessageEvent(ClientMessageEvent *event)
585 if (CheckCloseWindowEvent(event))
589 void HandleWindowManagerEvent(Event *event)
591 #if defined(TARGET_SDL)
592 SDLHandleWindowManagerEvent(event);
596 void HandleButton(int mx, int my, int button, int button_nr)
598 static int old_mx = 0, old_my = 0;
612 if (HandleGadgets(mx, my, button))
614 /* do not handle this button event anymore */
615 mx = my = -32; /* force mouse event to be outside screen tiles */
618 /* do not use scroll wheel button events for anything other than gadgets */
619 if (IS_WHEEL_BUTTON(button_nr))
622 Error(ERR_DEBUG, "::: game_status == %d", game_status);
626 case GAME_MODE_TITLE:
627 HandleTitleScreen(mx, my, 0, 0, button);
631 HandleMainMenu(mx, my, 0, 0, button);
634 case GAME_MODE_PSEUDO_TYPENAME:
635 HandleTypeName(0, KSYM_Return);
638 case GAME_MODE_LEVELS:
639 HandleChooseLevelSet(mx, my, 0, 0, button);
642 case GAME_MODE_LEVELNR:
643 HandleChooseLevelNr(mx, my, 0, 0, button);
646 case GAME_MODE_SCORES:
647 HandleHallOfFame(0, 0, 0, 0, button);
650 case GAME_MODE_EDITOR:
651 HandleLevelEditorIdle();
655 HandleInfoScreen(mx, my, 0, 0, button);
658 case GAME_MODE_SETUP:
659 HandleSetupScreen(mx, my, 0, 0, button);
662 case GAME_MODE_PLAYING:
664 if (button == MB_PRESSED && !motion_status && IN_GFX_SCREEN(mx, my))
665 DumpTile(LEVELX((mx - SX) / TILEX), LEVELY((my - SY) / TILEY));
674 static boolean is_string_suffix(char *string, char *suffix)
676 int string_len = strlen(string);
677 int suffix_len = strlen(suffix);
679 if (suffix_len > string_len)
682 return (strEqual(&string[string_len - suffix_len], suffix));
685 #define MAX_CHEAT_INPUT_LEN 32
687 static void HandleKeysSpecial(Key key)
689 static char cheat_input[2 * MAX_CHEAT_INPUT_LEN + 1] = "";
690 char letter = getCharFromKey(key);
691 int cheat_input_len = strlen(cheat_input);
697 if (cheat_input_len >= 2 * MAX_CHEAT_INPUT_LEN)
699 for (i = 0; i < MAX_CHEAT_INPUT_LEN + 1; i++)
700 cheat_input[i] = cheat_input[MAX_CHEAT_INPUT_LEN + i];
702 cheat_input_len = MAX_CHEAT_INPUT_LEN;
705 cheat_input[cheat_input_len++] = letter;
706 cheat_input[cheat_input_len] = '\0';
709 Error(ERR_DEBUG, "SPECIAL KEY '%s' [%d]\n", cheat_input, cheat_input_len);
712 if (game_status == GAME_MODE_MAIN)
714 if (is_string_suffix(cheat_input, ":insert-solution-tape") ||
715 is_string_suffix(cheat_input, ":ist"))
717 InsertSolutionTape();
719 else if (is_string_suffix(cheat_input, ":reload-graphics") ||
720 is_string_suffix(cheat_input, ":rg"))
722 ReloadCustomArtwork(1 << ARTWORK_TYPE_GRAPHICS);
725 else if (is_string_suffix(cheat_input, ":reload-sounds") ||
726 is_string_suffix(cheat_input, ":rs"))
728 ReloadCustomArtwork(1 << ARTWORK_TYPE_SOUNDS);
731 else if (is_string_suffix(cheat_input, ":reload-music") ||
732 is_string_suffix(cheat_input, ":rm"))
734 ReloadCustomArtwork(1 << ARTWORK_TYPE_MUSIC);
737 else if (is_string_suffix(cheat_input, ":reload-artwork") ||
738 is_string_suffix(cheat_input, ":ra"))
740 ReloadCustomArtwork(1 << ARTWORK_TYPE_GRAPHICS |
741 1 << ARTWORK_TYPE_SOUNDS |
742 1 << ARTWORK_TYPE_MUSIC);
745 else if (is_string_suffix(cheat_input, ":dump-level") ||
746 is_string_suffix(cheat_input, ":dl"))
750 else if (is_string_suffix(cheat_input, ":dump-tape") ||
751 is_string_suffix(cheat_input, ":dt"))
755 else if (is_string_suffix(cheat_input, ":save-native-level") ||
756 is_string_suffix(cheat_input, ":snl"))
758 SaveNativeLevel(&level);
761 else if (game_status == GAME_MODE_PLAYING)
764 if (is_string_suffix(cheat_input, ".q"))
765 DEBUG_SetMaximumDynamite();
768 else if (game_status == GAME_MODE_EDITOR)
770 if (is_string_suffix(cheat_input, ":dump-brush") ||
771 is_string_suffix(cheat_input, ":DB"))
775 else if (is_string_suffix(cheat_input, ":DDB"))
782 void HandleKey(Key key, int key_status)
784 boolean anyTextGadgetActiveOrJustFinished = anyTextGadgetActive();
785 static struct SetupKeyboardInfo ski;
786 static struct SetupShortcutInfo ssi;
795 { &ski.left, &ssi.snap_left, DEFAULT_KEY_LEFT, JOY_LEFT },
796 { &ski.right, &ssi.snap_right, DEFAULT_KEY_RIGHT, JOY_RIGHT },
797 { &ski.up, &ssi.snap_up, DEFAULT_KEY_UP, JOY_UP },
798 { &ski.down, &ssi.snap_down, DEFAULT_KEY_DOWN, JOY_DOWN },
799 { &ski.snap, NULL, DEFAULT_KEY_SNAP, JOY_BUTTON_SNAP },
800 { &ski.drop, NULL, DEFAULT_KEY_DROP, JOY_BUTTON_DROP }
805 if (game_status == GAME_MODE_PLAYING)
807 /* only needed for single-step tape recording mode */
808 static boolean clear_snap_button[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
809 static boolean clear_drop_button[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
810 static boolean element_snapped[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
811 static boolean element_dropped[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
814 for (pnr = 0; pnr < MAX_PLAYERS; pnr++)
818 if (setup.input[pnr].use_joystick)
821 ski = setup.input[pnr].key;
823 for (i = 0; i < NUM_PLAYER_ACTIONS; i++)
824 if (key == *key_info[i].key_custom)
825 key_action |= key_info[i].action;
827 /* use combined snap+direction keys for the first player only */
830 ssi = setup.shortcut;
832 for (i = 0; i < NUM_DIRECTIONS; i++)
833 if (key == *key_info[i].key_snap)
834 key_action |= key_info[i].action | JOY_BUTTON_SNAP;
837 /* clear delayed snap and drop actions in single step mode (see below) */
838 if (tape.single_step)
840 if (clear_snap_button[pnr])
842 stored_player[pnr].action &= ~KEY_BUTTON_SNAP;
843 clear_snap_button[pnr] = FALSE;
846 if (clear_drop_button[pnr])
848 stored_player[pnr].action &= ~KEY_BUTTON_DROP;
849 clear_drop_button[pnr] = FALSE;
853 if (key_status == KEY_PRESSED)
854 stored_player[pnr].action |= key_action;
856 stored_player[pnr].action &= ~key_action;
858 if (tape.single_step && tape.recording && tape.pausing)
860 if (key_status == KEY_PRESSED && key_action & KEY_MOTION)
862 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
864 /* if snap key already pressed, don't snap when releasing (below) */
865 if (stored_player[pnr].action & KEY_BUTTON_SNAP)
866 element_snapped[pnr] = TRUE;
868 /* if drop key already pressed, don't drop when releasing (below) */
869 if (stored_player[pnr].action & KEY_BUTTON_DROP)
870 element_dropped[pnr] = TRUE;
873 else if (key_status == KEY_PRESSED && key_action & KEY_BUTTON_DROP)
875 if (level.game_engine_type == GAME_ENGINE_TYPE_EM ||
876 level.game_engine_type == GAME_ENGINE_TYPE_SP)
879 printf("::: drop key pressed\n");
882 if (level.game_engine_type == GAME_ENGINE_TYPE_SP &&
883 getRedDiskReleaseFlag_SP() == 0)
884 stored_player[pnr].action &= ~KEY_BUTTON_DROP;
886 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
890 else if (key_status == KEY_RELEASED && key_action & KEY_BUTTON)
892 if (key_action & KEY_BUTTON_SNAP)
894 /* if snap key was released without moving (see above), snap now */
895 if (!element_snapped[pnr])
897 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
899 stored_player[pnr].action |= KEY_BUTTON_SNAP;
901 /* clear delayed snap button on next event */
902 clear_snap_button[pnr] = TRUE;
905 element_snapped[pnr] = FALSE;
909 if (key_action & KEY_BUTTON_DROP &&
910 level.game_engine_type == GAME_ENGINE_TYPE_RND)
912 /* if drop key was released without moving (see above), drop now */
913 if (!element_dropped[pnr])
915 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
917 if (level.game_engine_type != GAME_ENGINE_TYPE_SP ||
918 getRedDiskReleaseFlag_SP() != 0)
919 stored_player[pnr].action |= KEY_BUTTON_DROP;
921 /* clear delayed drop button on next event */
922 clear_drop_button[pnr] = TRUE;
925 element_dropped[pnr] = FALSE;
930 else if (tape.recording && tape.pausing)
932 /* prevent key release events from un-pausing a paused game */
933 if (key_status == KEY_PRESSED && key_action & KEY_ACTION)
934 TapeTogglePause(TAPE_TOGGLE_MANUAL);
940 for (i = 0; i < NUM_PLAYER_ACTIONS; i++)
941 if (key == key_info[i].key_default)
942 joy |= key_info[i].action;
947 if (key_status == KEY_PRESSED)
948 key_joystick_mapping |= joy;
950 key_joystick_mapping &= ~joy;
955 if (game_status != GAME_MODE_PLAYING)
956 key_joystick_mapping = 0;
958 if (key_status == KEY_RELEASED)
961 if ((key == KSYM_Return || key == KSYM_KP_Enter) &&
962 (GetKeyModState() & KMOD_Alt) && video.fullscreen_available)
964 setup.fullscreen = !setup.fullscreen;
966 ToggleFullscreenIfNeeded();
968 if (game_status == GAME_MODE_SETUP)
969 RedrawSetupScreenAfterFullscreenToggle();
975 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd &&
976 (key == KSYM_Return || key == setup.shortcut.toggle_pause))
978 if (game_status == GAME_MODE_PLAYING && AllPlayersGone &&
979 (key == KSYM_Return || key == setup.shortcut.toggle_pause))
987 if (game_status == GAME_MODE_MAIN &&
988 (key == setup.shortcut.toggle_pause || key == KSYM_space))
990 StartGameActions(options.network, setup.autorecord, level.random_seed);
995 if (game_status == GAME_MODE_MAIN || game_status == GAME_MODE_PLAYING)
997 if (key == setup.shortcut.save_game)
999 else if (key == setup.shortcut.load_game)
1001 else if (key == setup.shortcut.toggle_pause)
1002 TapeTogglePause(TAPE_TOGGLE_MANUAL);
1004 HandleTapeButtonKeys(key);
1005 HandleSoundButtonKeys(key);
1008 if (game_status == GAME_MODE_PLAYING && !network_playing)
1010 int centered_player_nr_next = -999;
1012 if (key == setup.shortcut.focus_player_all)
1013 centered_player_nr_next = -1;
1015 for (i = 0; i < MAX_PLAYERS; i++)
1016 if (key == setup.shortcut.focus_player[i])
1017 centered_player_nr_next = i;
1019 if (centered_player_nr_next != -999)
1021 game.centered_player_nr_next = centered_player_nr_next;
1022 game.set_centered_player = TRUE;
1026 tape.centered_player_nr_next = game.centered_player_nr_next;
1027 tape.set_centered_player = TRUE;
1032 HandleKeysSpecial(key);
1034 if (HandleGadgetsKeyInput(key))
1036 if (key != KSYM_Escape) /* always allow ESC key to be handled */
1037 key = KSYM_UNDEFINED;
1040 switch (game_status)
1042 case GAME_MODE_PSEUDO_TYPENAME:
1043 HandleTypeName(0, key);
1046 case GAME_MODE_TITLE:
1047 case GAME_MODE_MAIN:
1048 case GAME_MODE_LEVELS:
1049 case GAME_MODE_LEVELNR:
1050 case GAME_MODE_SETUP:
1051 case GAME_MODE_INFO:
1052 case GAME_MODE_SCORES:
1057 if (game_status == GAME_MODE_TITLE)
1058 HandleTitleScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1059 else if (game_status == GAME_MODE_MAIN)
1060 HandleMainMenu(0, 0, 0, 0, MB_MENU_CHOICE);
1061 else if (game_status == GAME_MODE_LEVELS)
1062 HandleChooseLevelSet(0, 0, 0, 0, MB_MENU_CHOICE);
1063 else if (game_status == GAME_MODE_LEVELNR)
1064 HandleChooseLevelNr(0, 0, 0, 0, MB_MENU_CHOICE);
1065 else if (game_status == GAME_MODE_SETUP)
1066 HandleSetupScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1067 else if (game_status == GAME_MODE_INFO)
1068 HandleInfoScreen(0, 0, 0, 0, MB_MENU_CHOICE);
1069 else if (game_status == GAME_MODE_SCORES)
1070 HandleHallOfFame(0, 0, 0, 0, MB_MENU_CHOICE);
1074 if (game_status != GAME_MODE_MAIN)
1075 FadeSkipNextFadeIn();
1077 if (game_status == GAME_MODE_TITLE)
1078 HandleTitleScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1079 else if (game_status == GAME_MODE_LEVELS)
1080 HandleChooseLevelSet(0, 0, 0, 0, MB_MENU_LEAVE);
1081 else if (game_status == GAME_MODE_LEVELNR)
1082 HandleChooseLevelNr(0, 0, 0, 0, MB_MENU_LEAVE);
1083 else if (game_status == GAME_MODE_SETUP)
1084 HandleSetupScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1085 else if (game_status == GAME_MODE_INFO)
1086 HandleInfoScreen(0, 0, 0, 0, MB_MENU_LEAVE);
1087 else if (game_status == GAME_MODE_SCORES)
1088 HandleHallOfFame(0, 0, 0, 0, MB_MENU_LEAVE);
1092 if (game_status == GAME_MODE_LEVELS)
1093 HandleChooseLevelSet(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1094 else if (game_status == GAME_MODE_LEVELNR)
1095 HandleChooseLevelNr(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1096 else if (game_status == GAME_MODE_SETUP)
1097 HandleSetupScreen(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1098 else if (game_status == GAME_MODE_INFO)
1099 HandleInfoScreen(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1100 else if (game_status == GAME_MODE_SCORES)
1101 HandleHallOfFame(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
1104 case KSYM_Page_Down:
1105 if (game_status == GAME_MODE_LEVELS)
1106 HandleChooseLevelSet(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1107 else if (game_status == GAME_MODE_LEVELNR)
1108 HandleChooseLevelNr(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1109 else if (game_status == GAME_MODE_SETUP)
1110 HandleSetupScreen(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1111 else if (game_status == GAME_MODE_INFO)
1112 HandleInfoScreen(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1113 else if (game_status == GAME_MODE_SCORES)
1114 HandleHallOfFame(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
1119 GameFrameDelay = (GameFrameDelay == 500 ? GAME_FRAME_DELAY : 500);
1123 setup.sp_show_border_elements = !setup.sp_show_border_elements;
1124 printf("Supaplex border elements %s\n",
1125 setup.sp_show_border_elements ? "enabled" : "disabled");
1134 case GAME_MODE_EDITOR:
1135 if (!anyTextGadgetActiveOrJustFinished || key == KSYM_Escape)
1136 HandleLevelEditorKeyInput(key);
1139 case GAME_MODE_PLAYING:
1144 RequestQuitGame(setup.ask_on_escape);
1162 if (GameFrameDelay == 500)
1163 GameFrameDelay = GAME_FRAME_DELAY;
1165 GameFrameDelay = 500;
1168 GameFrameDelay = (key - KSYM_0) * 10;
1169 printf("Game speed == %d%% (%d ms delay between two frames)\n",
1170 GAME_FRAME_DELAY * 100 / GameFrameDelay, GameFrameDelay);
1176 options.debug = FALSE;
1177 printf("debug mode disabled\n");
1181 options.debug = TRUE;
1182 printf("debug mode enabled\n");
1187 if (!global.fps_slowdown)
1189 global.fps_slowdown = TRUE;
1190 global.fps_slowdown_factor = 2;
1191 printf("fps slowdown enabled -- display only every 2nd frame\n");
1193 else if (global.fps_slowdown_factor == 2)
1195 global.fps_slowdown_factor = 4;
1196 printf("fps slowdown enabled -- display only every 4th frame\n");
1200 global.fps_slowdown = FALSE;
1201 global.fps_slowdown_factor = 1;
1202 printf("fps slowdown disabled\n");
1207 ScrollStepSize = TILEX / 8;
1208 printf("ScrollStepSize == %d (1/8)\n", ScrollStepSize);
1212 ScrollStepSize = TILEX / 4;
1213 printf("ScrollStepSize == %d (1/4)\n", ScrollStepSize);
1217 ScrollStepSize = TILEX / 2;
1218 printf("ScrollStepSize == %d (1/2)\n", ScrollStepSize);
1222 ScrollStepSize = TILEX;
1223 printf("ScrollStepSize == %d (1/1)\n", ScrollStepSize);
1227 printf("::: currently using game engine version %d\n",
1228 game.engine_version);
1239 if (key == KSYM_Escape)
1241 game_status = GAME_MODE_MAIN;
1249 void HandleNoEvent()
1251 if (button_status && game_status != GAME_MODE_PLAYING)
1253 HandleButton(0, 0, -button_status, button_status);
1258 #if defined(NETWORK_AVALIABLE)
1259 if (options.network)
1266 static int HandleJoystickForAllPlayers()
1271 for (i = 0; i < MAX_PLAYERS; i++)
1273 byte joy_action = 0;
1276 if (!setup.input[i].use_joystick)
1280 joy_action = Joystick(i);
1281 result |= joy_action;
1283 if (!setup.input[i].use_joystick)
1286 stored_player[i].action = joy_action;
1292 void HandleJoystick()
1294 int joystick = HandleJoystickForAllPlayers();
1295 int keyboard = key_joystick_mapping;
1296 int joy = (joystick | keyboard);
1297 int left = joy & JOY_LEFT;
1298 int right = joy & JOY_RIGHT;
1299 int up = joy & JOY_UP;
1300 int down = joy & JOY_DOWN;
1301 int button = joy & JOY_BUTTON;
1302 int newbutton = (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED);
1303 int dx = (left ? -1 : right ? 1 : 0);
1304 int dy = (up ? -1 : down ? 1 : 0);
1306 switch (game_status)
1308 case GAME_MODE_TITLE:
1309 case GAME_MODE_MAIN:
1310 case GAME_MODE_LEVELS:
1311 case GAME_MODE_LEVELNR:
1312 case GAME_MODE_SETUP:
1313 case GAME_MODE_INFO:
1315 static unsigned int joystickmove_delay = 0;
1317 if (joystick && !button &&
1318 !DelayReached(&joystickmove_delay, GADGET_FRAME_DELAY))
1319 newbutton = dx = dy = 0;
1321 if (game_status == GAME_MODE_TITLE)
1322 HandleTitleScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1323 else if (game_status == GAME_MODE_MAIN)
1324 HandleMainMenu(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1325 else if (game_status == GAME_MODE_LEVELS)
1326 HandleChooseLevelSet(0,0,dx,dy,newbutton?MB_MENU_CHOICE : MB_MENU_MARK);
1327 else if (game_status == GAME_MODE_LEVELNR)
1328 HandleChooseLevelNr(0,0,dx,dy,newbutton? MB_MENU_CHOICE : MB_MENU_MARK);
1329 else if (game_status == GAME_MODE_SETUP)
1330 HandleSetupScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1331 else if (game_status == GAME_MODE_INFO)
1332 HandleInfoScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1336 case GAME_MODE_SCORES:
1337 HandleHallOfFame(0, 0, dx, dy, !newbutton);
1340 case GAME_MODE_EDITOR:
1341 HandleLevelEditorIdle();
1344 case GAME_MODE_PLAYING:
1345 if (tape.playing || keyboard)
1346 newbutton = ((joy & JOY_BUTTON) != 0);
1349 if (local_player->LevelSolved_GameEnd && newbutton)
1351 if (AllPlayersGone && newbutton)