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);
233 void ClearEventQueue()
235 while (PendingEvent())
243 case EVENT_BUTTONRELEASE:
244 button_status = MB_RELEASED;
247 case EVENT_KEYRELEASE:
251 key_joystick_mapping = 0;
256 HandleOtherEvents(&event);
262 void ClearPlayerAction()
266 /* simulate key release events for still pressed keys */
267 key_joystick_mapping = 0;
268 for (i = 0; i < MAX_PLAYERS; i++)
269 stored_player[i].action = 0;
272 void SleepWhileUnmapped()
274 boolean window_unmapped = TRUE;
276 KeyboardAutoRepeatOn();
278 while (window_unmapped)
286 case EVENT_BUTTONRELEASE:
287 button_status = MB_RELEASED;
290 case EVENT_KEYRELEASE:
291 key_joystick_mapping = 0;
294 case EVENT_MAPNOTIFY:
295 window_unmapped = FALSE;
298 case EVENT_UNMAPNOTIFY:
299 /* this is only to surely prevent the 'should not happen' case
300 * of recursively looping between 'SleepWhileUnmapped()' and
301 * 'HandleOtherEvents()' which usually calls this funtion.
306 HandleOtherEvents(&event);
311 if (game_status == GAME_MODE_PLAYING)
312 KeyboardAutoRepeatOffUnlessAutoplay();
315 void HandleExposeEvent(ExposeEvent *event)
318 RedrawPlayfield(FALSE, event->x, event->y, event->width, event->height);
323 void HandleButtonEvent(ButtonEvent *event)
326 printf("::: BUTTON EVENT: button %d %s\n", event->button,
327 event->type == EVENT_BUTTONPRESS ? "pressed" : "released");
330 motion_status = FALSE;
332 if (event->type == EVENT_BUTTONPRESS)
333 button_status = event->button;
335 button_status = MB_RELEASED;
337 HandleButton(event->x, event->y, button_status, event->button);
340 void HandleMotionEvent(MotionEvent *event)
342 if (!PointerInWindow(window))
343 return; /* window and pointer are on different screens */
345 if (button_status == MB_RELEASED && game_status != GAME_MODE_EDITOR)
348 motion_status = TRUE;
350 HandleButton(event->x, event->y, button_status, button_status);
353 void HandleKeyEvent(KeyEvent *event)
355 int key_status = (event->type==EVENT_KEYPRESS ? KEY_PRESSED : KEY_RELEASED);
356 boolean with_modifiers = (game_status == GAME_MODE_PLAYING ? FALSE : TRUE);
357 Key key = GetEventKey(event, with_modifiers);
358 Key keymod = (with_modifiers ? GetEventKey(event, FALSE) : key);
361 printf("::: KEY EVENT: %d %s\n", GetEventKey(event, TRUE),
362 event->type == EVENT_KEYPRESS ? "pressed" : "released");
365 HandleKeyModState(keymod, key_status);
366 HandleKey(key, key_status);
369 void HandleFocusEvent(FocusChangeEvent *event)
371 static int old_joystick_status = -1;
373 if (event->type == EVENT_FOCUSOUT)
375 KeyboardAutoRepeatOn();
376 old_joystick_status = joystick.status;
377 joystick.status = JOYSTICK_NOT_AVAILABLE;
381 else if (event->type == EVENT_FOCUSIN)
383 /* When there are two Rocks'n'Diamonds windows which overlap and
384 the player moves the pointer from one game window to the other,
385 a 'FocusOut' event is generated for the window the pointer is
386 leaving and a 'FocusIn' event is generated for the window the
387 pointer is entering. In some cases, it can happen that the
388 'FocusIn' event is handled by the one game process before the
389 'FocusOut' event by the other game process. In this case the
390 X11 environment would end up with activated keyboard auto repeat,
391 because unfortunately this is a global setting and not (which
392 would be far better) set for each X11 window individually.
393 The effect would be keyboard auto repeat while playing the game
394 (game_status == GAME_MODE_PLAYING), which is not desired.
395 To avoid this special case, we just wait 1/10 second before
396 processing the 'FocusIn' event.
399 if (game_status == GAME_MODE_PLAYING)
402 KeyboardAutoRepeatOffUnlessAutoplay();
405 if (old_joystick_status != -1)
406 joystick.status = old_joystick_status;
410 void HandleClientMessageEvent(ClientMessageEvent *event)
412 if (CheckCloseWindowEvent(event))
416 void HandleButton(int mx, int my, int button, int button_nr)
418 static int old_mx = 0, old_my = 0;
432 if (HandleGadgets(mx, my, button))
434 /* do not handle this button event anymore */
435 mx = my = -32; /* force mouse event to be outside screen tiles */
438 /* do not use scroll wheel button events for anything other than gadgets */
439 if (IS_WHEEL_BUTTON(button_nr))
444 case GAME_MODE_TITLE:
445 HandleTitleScreen(mx, my, 0, 0, button);
449 HandleMainMenu(mx, my, 0, 0, button);
452 case GAME_MODE_PSEUDO_TYPENAME:
453 HandleTypeName(0, KSYM_Return);
456 case GAME_MODE_LEVELS:
457 HandleChooseLevel(mx, my, 0, 0, button);
460 case GAME_MODE_SCORES:
461 HandleHallOfFame(0, 0, 0, 0, button);
464 case GAME_MODE_EDITOR:
465 HandleLevelEditorIdle();
469 HandleInfoScreen(mx, my, 0, 0, button);
472 case GAME_MODE_SETUP:
473 HandleSetupScreen(mx, my, 0, 0, button);
476 case GAME_MODE_PLAYING:
478 if (button == MB_PRESSED && !motion_status && IN_GFX_SCREEN(mx, my))
479 DumpTile(LEVELX((mx - SX) / TILEX), LEVELY((my - SY) / TILEY));
488 static boolean is_string_suffix(char *string, char *suffix)
490 int string_len = strlen(string);
491 int suffix_len = strlen(suffix);
493 if (suffix_len > string_len)
496 return (strEqual(&string[string_len - suffix_len], suffix));
499 #define MAX_CHEAT_INPUT_LEN 32
501 static void HandleKeysSpecial(Key key)
503 static char cheat_input[2 * MAX_CHEAT_INPUT_LEN + 1] = "";
504 char letter = getCharFromKey(key);
505 int cheat_input_len = strlen(cheat_input);
511 if (cheat_input_len >= 2 * MAX_CHEAT_INPUT_LEN)
513 for (i = 0; i < MAX_CHEAT_INPUT_LEN + 1; i++)
514 cheat_input[i] = cheat_input[MAX_CHEAT_INPUT_LEN + i];
516 cheat_input_len = MAX_CHEAT_INPUT_LEN;
519 cheat_input[cheat_input_len++] = letter;
520 cheat_input[cheat_input_len] = '\0';
523 printf("::: '%s' [%d]\n", cheat_input, cheat_input_len);
526 if (game_status == GAME_MODE_MAIN)
528 if (is_string_suffix(cheat_input, ":insert-solution-tape") ||
529 is_string_suffix(cheat_input, ":ist"))
531 InsertSolutionTape();
533 else if (is_string_suffix(cheat_input, ":reload-graphics") ||
534 is_string_suffix(cheat_input, ":rg"))
536 ReloadCustomArtwork(1 << ARTWORK_TYPE_GRAPHICS);
539 else if (is_string_suffix(cheat_input, ":reload-sounds") ||
540 is_string_suffix(cheat_input, ":rs"))
542 ReloadCustomArtwork(1 << ARTWORK_TYPE_SOUNDS);
545 else if (is_string_suffix(cheat_input, ":reload-music") ||
546 is_string_suffix(cheat_input, ":rm"))
548 ReloadCustomArtwork(1 << ARTWORK_TYPE_MUSIC);
551 else if (is_string_suffix(cheat_input, ":reload-artwork") ||
552 is_string_suffix(cheat_input, ":ra"))
554 ReloadCustomArtwork(1 << ARTWORK_TYPE_GRAPHICS |
555 1 << ARTWORK_TYPE_SOUNDS |
556 1 << ARTWORK_TYPE_MUSIC);
559 else if (is_string_suffix(cheat_input, ":dump-level") ||
560 is_string_suffix(cheat_input, ":dl"))
564 else if (is_string_suffix(cheat_input, ":dump-tape") ||
565 is_string_suffix(cheat_input, ":dt"))
570 else if (game_status == GAME_MODE_PLAYING)
573 if (is_string_suffix(cheat_input, ".q"))
574 DEBUG_SetMaximumDynamite();
577 else if (game_status == GAME_MODE_EDITOR)
579 if (is_string_suffix(cheat_input, ":dump-brush") ||
580 is_string_suffix(cheat_input, ":DB"))
584 else if (is_string_suffix(cheat_input, ":DDB"))
591 void HandleKey(Key key, int key_status)
593 boolean anyTextGadgetActiveOrJustFinished = anyTextGadgetActive();
594 static struct SetupKeyboardInfo custom_key;
602 { &custom_key.left, DEFAULT_KEY_LEFT, JOY_LEFT },
603 { &custom_key.right, DEFAULT_KEY_RIGHT, JOY_RIGHT },
604 { &custom_key.up, DEFAULT_KEY_UP, JOY_UP },
605 { &custom_key.down, DEFAULT_KEY_DOWN, JOY_DOWN },
606 { &custom_key.snap, DEFAULT_KEY_SNAP, JOY_BUTTON_1 },
607 { &custom_key.drop, DEFAULT_KEY_DROP, JOY_BUTTON_2 }
612 if (game_status == GAME_MODE_PLAYING)
614 /* only needed for single-step tape recording mode */
615 static boolean clear_button_2[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
616 static boolean element_dropped[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
619 for (pnr = 0; pnr < MAX_PLAYERS; pnr++)
623 if (setup.input[pnr].use_joystick)
626 custom_key = setup.input[pnr].key;
628 for (i = 0; i < 6; i++)
629 if (key == *key_info[i].key_custom)
630 key_action |= key_info[i].action;
632 if (tape.single_step && clear_button_2[pnr])
634 stored_player[pnr].action &= ~KEY_BUTTON_2;
635 clear_button_2[pnr] = FALSE;
638 if (key_status == KEY_PRESSED)
639 stored_player[pnr].action |= key_action;
641 stored_player[pnr].action &= ~key_action;
643 if (tape.single_step && tape.recording && tape.pausing)
645 if (key_status == KEY_PRESSED &&
646 (key_action & (KEY_MOTION | KEY_BUTTON_1)))
648 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
650 if (key_action & KEY_MOTION)
652 if (stored_player[pnr].action & KEY_BUTTON_2)
653 element_dropped[pnr] = TRUE;
656 else if (key_status == KEY_RELEASED &&
657 (key_action & KEY_BUTTON_2))
659 if (!element_dropped[pnr])
661 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
663 stored_player[pnr].action |= KEY_BUTTON_2;
664 clear_button_2[pnr] = TRUE;
667 element_dropped[pnr] = FALSE;
671 else if (tape.recording && tape.pausing)
673 /* prevent key release events from un-pausing a paused game */
674 if (key_status == KEY_PRESSED &&
675 (key_action & KEY_ACTION))
676 TapeTogglePause(TAPE_TOGGLE_MANUAL);
679 else if (tape.recording && tape.pausing && (key_action & KEY_ACTION))
680 TapeTogglePause(TAPE_TOGGLE_MANUAL);
686 for (i = 0; i < 6; i++)
687 if (key == key_info[i].key_default)
688 joy |= key_info[i].action;
693 if (key_status == KEY_PRESSED)
694 key_joystick_mapping |= joy;
696 key_joystick_mapping &= ~joy;
701 if (game_status != GAME_MODE_PLAYING)
702 key_joystick_mapping = 0;
704 if (key_status == KEY_RELEASED)
707 if ((key == KSYM_Return || key == KSYM_KP_Enter) &&
708 (GetKeyModState() & KMOD_Alt) && video.fullscreen_available)
710 setup.fullscreen = !setup.fullscreen;
712 ToggleFullscreenIfNeeded();
714 if (game_status == GAME_MODE_SETUP)
715 RedrawSetupScreenAfterFullscreenToggle();
721 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd &&
722 (key == KSYM_Return || key == setup.shortcut.toggle_pause))
724 if (game_status == GAME_MODE_PLAYING && AllPlayersGone &&
725 (key == KSYM_Return || key == setup.shortcut.toggle_pause))
733 if (game_status == GAME_MODE_MAIN &&
734 (key == setup.shortcut.toggle_pause || key == KSYM_space))
736 StartGameActions(options.network, setup.autorecord, NEW_RANDOMIZE);
741 if (game_status == GAME_MODE_MAIN || game_status == GAME_MODE_PLAYING)
743 if (key == setup.shortcut.save_game)
745 else if (key == setup.shortcut.load_game)
747 else if (key == setup.shortcut.toggle_pause)
748 TapeTogglePause(TAPE_TOGGLE_MANUAL);
751 if (game_status == GAME_MODE_PLAYING && !network_playing)
753 int centered_player_nr_next = -999;
755 if (key == setup.shortcut.focus_player_all)
756 centered_player_nr_next = -1;
758 for (i = 0; i < MAX_PLAYERS; i++)
759 if (key == setup.shortcut.focus_player[i])
760 centered_player_nr_next = i;
762 if (centered_player_nr_next != -999)
764 game.centered_player_nr_next = centered_player_nr_next;
765 game.set_centered_player = TRUE;
769 tape.centered_player_nr_next = game.centered_player_nr_next;
770 tape.set_centered_player = TRUE;
775 HandleKeysSpecial(key);
777 if (HandleGadgetsKeyInput(key))
779 if (key != KSYM_Escape) /* always allow ESC key to be handled */
780 key = KSYM_UNDEFINED;
785 case GAME_MODE_PSEUDO_TYPENAME:
786 HandleTypeName(0, key);
789 case GAME_MODE_TITLE:
791 case GAME_MODE_LEVELS:
792 case GAME_MODE_SETUP:
794 case GAME_MODE_SCORES:
799 if (game_status == GAME_MODE_TITLE)
800 HandleTitleScreen(0, 0, 0, 0, MB_MENU_CHOICE);
801 else if (game_status == GAME_MODE_MAIN)
802 HandleMainMenu(0, 0, 0, 0, MB_MENU_CHOICE);
803 else if (game_status == GAME_MODE_LEVELS)
804 HandleChooseLevel(0, 0, 0, 0, MB_MENU_CHOICE);
805 else if (game_status == GAME_MODE_SETUP)
806 HandleSetupScreen(0, 0, 0, 0, MB_MENU_CHOICE);
807 else if (game_status == GAME_MODE_INFO)
808 HandleInfoScreen(0, 0, 0, 0, MB_MENU_CHOICE);
809 else if (game_status == GAME_MODE_SCORES)
810 HandleHallOfFame(0, 0, 0, 0, MB_MENU_CHOICE);
814 if (game_status != GAME_MODE_MAIN)
815 FadeSkipNextFadeIn();
817 if (game_status == GAME_MODE_TITLE)
818 HandleTitleScreen(0, 0, 0, 0, MB_MENU_LEAVE);
819 else if (game_status == GAME_MODE_LEVELS)
820 HandleChooseLevel(0, 0, 0, 0, MB_MENU_LEAVE);
821 else if (game_status == GAME_MODE_SETUP)
822 HandleSetupScreen(0, 0, 0, 0, MB_MENU_LEAVE);
823 else if (game_status == GAME_MODE_INFO)
824 HandleInfoScreen(0, 0, 0, 0, MB_MENU_LEAVE);
825 else if (game_status == GAME_MODE_SCORES)
826 HandleHallOfFame(0, 0, 0, 0, MB_MENU_LEAVE);
830 if (game_status == GAME_MODE_LEVELS)
831 HandleChooseLevel(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
832 else if (game_status == GAME_MODE_SETUP)
833 HandleSetupScreen(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
834 else if (game_status == GAME_MODE_INFO)
835 HandleInfoScreen(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
836 else if (game_status == GAME_MODE_SCORES)
837 HandleHallOfFame(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
841 if (game_status == GAME_MODE_LEVELS)
842 HandleChooseLevel(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
843 else if (game_status == GAME_MODE_SETUP)
844 HandleSetupScreen(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
845 else if (game_status == GAME_MODE_INFO)
846 HandleInfoScreen(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
847 else if (game_status == GAME_MODE_SCORES)
848 HandleHallOfFame(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
853 GameFrameDelay = (GameFrameDelay == 500 ? GAME_FRAME_DELAY : 500);
862 case GAME_MODE_EDITOR:
863 if (!anyTextGadgetActiveOrJustFinished || key == KSYM_Escape)
864 HandleLevelEditorKeyInput(key);
867 case GAME_MODE_PLAYING:
872 RequestQuitGame(setup.ask_on_escape);
890 if (GameFrameDelay == 500)
891 GameFrameDelay = GAME_FRAME_DELAY;
893 GameFrameDelay = 500;
896 GameFrameDelay = (key - KSYM_0) * 10;
897 printf("Game speed == %d%% (%d ms delay between two frames)\n",
898 GAME_FRAME_DELAY * 100 / GameFrameDelay, GameFrameDelay);
904 options.debug = FALSE;
905 printf("debug mode disabled\n");
909 options.debug = TRUE;
910 printf("debug mode enabled\n");
915 if (!global.fps_slowdown)
917 global.fps_slowdown = TRUE;
918 global.fps_slowdown_factor = 2;
919 printf("fps slowdown enabled -- display only every 2nd frame\n");
921 else if (global.fps_slowdown_factor == 2)
923 global.fps_slowdown_factor = 4;
924 printf("fps slowdown enabled -- display only every 4th frame\n");
928 global.fps_slowdown = FALSE;
929 global.fps_slowdown_factor = 1;
930 printf("fps slowdown disabled\n");
935 ScrollStepSize = TILEX/8;
936 printf("ScrollStepSize == %d (1/8)\n", ScrollStepSize);
940 ScrollStepSize = TILEX/4;
941 printf("ScrollStepSize == %d (1/4)\n", ScrollStepSize);
945 ScrollStepSize = TILEX/2;
946 printf("ScrollStepSize == %d (1/2)\n", ScrollStepSize);
950 ScrollStepSize = TILEX;
951 printf("ScrollStepSize == %d (1/1)\n", ScrollStepSize);
955 printf("::: currently using game engine version %d\n",
956 game.engine_version);
967 if (key == KSYM_Escape)
969 game_status = GAME_MODE_MAIN;
979 if (button_status && game_status != GAME_MODE_PLAYING)
981 HandleButton(0, 0, -button_status, button_status);
986 #if defined(NETWORK_AVALIABLE)
994 static int HandleJoystickForAllPlayers()
999 for (i = 0; i < MAX_PLAYERS; i++)
1001 byte joy_action = 0;
1004 if (!setup.input[i].use_joystick)
1008 joy_action = Joystick(i);
1009 result |= joy_action;
1011 if (!setup.input[i].use_joystick)
1014 stored_player[i].action = joy_action;
1020 void HandleJoystick()
1022 int joystick = HandleJoystickForAllPlayers();
1023 int keyboard = key_joystick_mapping;
1024 int joy = (joystick | keyboard);
1025 int left = joy & JOY_LEFT;
1026 int right = joy & JOY_RIGHT;
1027 int up = joy & JOY_UP;
1028 int down = joy & JOY_DOWN;
1029 int button = joy & JOY_BUTTON;
1030 int newbutton = (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED);
1031 int dx = (left ? -1 : right ? 1 : 0);
1032 int dy = (up ? -1 : down ? 1 : 0);
1034 switch (game_status)
1036 case GAME_MODE_TITLE:
1037 case GAME_MODE_MAIN:
1038 case GAME_MODE_LEVELS:
1039 case GAME_MODE_SETUP:
1040 case GAME_MODE_INFO:
1042 static unsigned long joystickmove_delay = 0;
1044 if (joystick && !button &&
1045 !DelayReached(&joystickmove_delay, GADGET_FRAME_DELAY))
1046 newbutton = dx = dy = 0;
1048 if (game_status == GAME_MODE_TITLE)
1049 HandleTitleScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1050 else if (game_status == GAME_MODE_MAIN)
1051 HandleMainMenu(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1052 else if (game_status == GAME_MODE_LEVELS)
1053 HandleChooseLevel(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1054 else if (game_status == GAME_MODE_SETUP)
1055 HandleSetupScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1056 else if (game_status == GAME_MODE_INFO)
1057 HandleInfoScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1061 case GAME_MODE_SCORES:
1062 HandleHallOfFame(0, 0, dx, dy, !newbutton);
1065 case GAME_MODE_EDITOR:
1066 HandleLevelEditorIdle();
1069 case GAME_MODE_PLAYING:
1070 if (tape.playing || keyboard)
1071 newbutton = ((joy & JOY_BUTTON) != 0);
1074 if (local_player->LevelSolved_GameEnd && newbutton)
1076 if (AllPlayersGone && newbutton)