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 FadeSkipNextFadeIn();
816 if (game_status == GAME_MODE_TITLE)
817 HandleTitleScreen(0, 0, 0, 0, MB_MENU_LEAVE);
818 else if (game_status == GAME_MODE_LEVELS)
819 HandleChooseLevel(0, 0, 0, 0, MB_MENU_LEAVE);
820 else if (game_status == GAME_MODE_SETUP)
821 HandleSetupScreen(0, 0, 0, 0, MB_MENU_LEAVE);
822 else if (game_status == GAME_MODE_INFO)
823 HandleInfoScreen(0, 0, 0, 0, MB_MENU_LEAVE);
824 else if (game_status == GAME_MODE_SCORES)
825 HandleHallOfFame(0, 0, 0, 0, MB_MENU_LEAVE);
829 if (game_status == GAME_MODE_LEVELS)
830 HandleChooseLevel(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
831 else if (game_status == GAME_MODE_SETUP)
832 HandleSetupScreen(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
833 else if (game_status == GAME_MODE_INFO)
834 HandleInfoScreen(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
835 else if (game_status == GAME_MODE_SCORES)
836 HandleHallOfFame(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
840 if (game_status == GAME_MODE_LEVELS)
841 HandleChooseLevel(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
842 else if (game_status == GAME_MODE_SETUP)
843 HandleSetupScreen(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
844 else if (game_status == GAME_MODE_INFO)
845 HandleInfoScreen(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
846 else if (game_status == GAME_MODE_SCORES)
847 HandleHallOfFame(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
852 GameFrameDelay = (GameFrameDelay == 500 ? GAME_FRAME_DELAY : 500);
861 case GAME_MODE_EDITOR:
862 if (!anyTextGadgetActiveOrJustFinished || key == KSYM_Escape)
863 HandleLevelEditorKeyInput(key);
866 case GAME_MODE_PLAYING:
871 RequestQuitGame(setup.ask_on_escape);
889 if (GameFrameDelay == 500)
890 GameFrameDelay = GAME_FRAME_DELAY;
892 GameFrameDelay = 500;
895 GameFrameDelay = (key - KSYM_0) * 10;
896 printf("Game speed == %d%% (%d ms delay between two frames)\n",
897 GAME_FRAME_DELAY * 100 / GameFrameDelay, GameFrameDelay);
903 options.debug = FALSE;
904 printf("debug mode disabled\n");
908 options.debug = TRUE;
909 printf("debug mode enabled\n");
914 if (!global.fps_slowdown)
916 global.fps_slowdown = TRUE;
917 global.fps_slowdown_factor = 2;
918 printf("fps slowdown enabled -- display only every 2nd frame\n");
920 else if (global.fps_slowdown_factor == 2)
922 global.fps_slowdown_factor = 4;
923 printf("fps slowdown enabled -- display only every 4th frame\n");
927 global.fps_slowdown = FALSE;
928 global.fps_slowdown_factor = 1;
929 printf("fps slowdown disabled\n");
934 ScrollStepSize = TILEX/8;
935 printf("ScrollStepSize == %d (1/8)\n", ScrollStepSize);
939 ScrollStepSize = TILEX/4;
940 printf("ScrollStepSize == %d (1/4)\n", ScrollStepSize);
944 ScrollStepSize = TILEX/2;
945 printf("ScrollStepSize == %d (1/2)\n", ScrollStepSize);
949 ScrollStepSize = TILEX;
950 printf("ScrollStepSize == %d (1/1)\n", ScrollStepSize);
954 printf("::: currently using game engine version %d\n",
955 game.engine_version);
966 if (key == KSYM_Escape)
968 game_status = GAME_MODE_MAIN;
978 if (button_status && game_status != GAME_MODE_PLAYING)
980 HandleButton(0, 0, -button_status, button_status);
985 #if defined(NETWORK_AVALIABLE)
993 static int HandleJoystickForAllPlayers()
998 for (i = 0; i < MAX_PLAYERS; i++)
1000 byte joy_action = 0;
1003 if (!setup.input[i].use_joystick)
1007 joy_action = Joystick(i);
1008 result |= joy_action;
1010 if (!setup.input[i].use_joystick)
1013 stored_player[i].action = joy_action;
1019 void HandleJoystick()
1021 int joystick = HandleJoystickForAllPlayers();
1022 int keyboard = key_joystick_mapping;
1023 int joy = (joystick | keyboard);
1024 int left = joy & JOY_LEFT;
1025 int right = joy & JOY_RIGHT;
1026 int up = joy & JOY_UP;
1027 int down = joy & JOY_DOWN;
1028 int button = joy & JOY_BUTTON;
1029 int newbutton = (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED);
1030 int dx = (left ? -1 : right ? 1 : 0);
1031 int dy = (up ? -1 : down ? 1 : 0);
1033 switch (game_status)
1035 case GAME_MODE_TITLE:
1036 case GAME_MODE_MAIN:
1037 case GAME_MODE_LEVELS:
1038 case GAME_MODE_SETUP:
1039 case GAME_MODE_INFO:
1041 static unsigned long joystickmove_delay = 0;
1043 if (joystick && !button &&
1044 !DelayReached(&joystickmove_delay, GADGET_FRAME_DELAY))
1045 newbutton = dx = dy = 0;
1047 if (game_status == GAME_MODE_TITLE)
1048 HandleTitleScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1049 else if (game_status == GAME_MODE_MAIN)
1050 HandleMainMenu(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1051 else if (game_status == GAME_MODE_LEVELS)
1052 HandleChooseLevel(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1053 else if (game_status == GAME_MODE_SETUP)
1054 HandleSetupScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1055 else if (game_status == GAME_MODE_INFO)
1056 HandleInfoScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
1060 case GAME_MODE_SCORES:
1061 HandleHallOfFame(0, 0, dx, dy, !newbutton);
1064 case GAME_MODE_EDITOR:
1065 HandleLevelEditorIdle();
1068 case GAME_MODE_PLAYING:
1069 if (tape.playing || keyboard)
1070 newbutton = ((joy & JOY_BUTTON) != 0);
1073 if (local_player->LevelSolved_GameEnd && newbutton)
1075 if (AllPlayersGone && newbutton)