1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2001 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
14 #include "libgame/libgame.h"
26 /* values for key_status */
27 #define KEY_NOT_PRESSED FALSE
28 #define KEY_RELEASED FALSE
29 #define KEY_PRESSED TRUE
32 /* event filter especially needed for SDL event filtering due to
33 delay problems with lots of mouse motion events when mouse
36 int FilterMouseMotionEvents(const Event *event)
38 if (event->type != EVENT_MOTIONNOTIFY)
41 /* get mouse motion events without pressed button only in level editor */
42 if (button_status == MB_RELEASED && game_status != LEVELED)
48 /* this is only really needed for non-SDL targets to filter unwanted events;
49 when using SDL with properly installed event filter, this function can be
50 replaced with a simple "NextEvent()" call, but it doesn't hurt either */
52 static boolean NextValidEvent(Event *event)
54 while (PendingEvent())
58 if (FilterMouseMotionEvents(event))
69 if (PendingEvent()) /* got event */
73 if (NextValidEvent(&event))
77 case EVENT_BUTTONPRESS:
78 case EVENT_BUTTONRELEASE:
79 HandleButtonEvent((ButtonEvent *) &event);
82 case EVENT_MOTIONNOTIFY:
83 HandleMotionEvent((MotionEvent *) &event);
87 case EVENT_KEYRELEASE:
88 HandleKeyEvent((KeyEvent *) &event);
92 HandleOtherEvents(&event);
100 /* don't use all CPU time when idle; the main loop while playing
101 has its own synchronization and is CPU friendly, too */
103 if (game_status == PLAYING)
108 if (!PendingEvent()) /* delay only if no pending events */
112 /* refresh window contents from drawing buffer, if needed */
115 if (game_status == EXITGAME)
120 void HandleOtherEvents(Event *event)
125 HandleExposeEvent((ExposeEvent *) event);
128 case EVENT_UNMAPNOTIFY:
129 SleepWhileUnmapped();
134 HandleFocusEvent((FocusChangeEvent *) event);
137 case EVENT_CLIENTMESSAGE:
138 HandleClientMessageEvent((ClientMessageEvent *) event);
141 #if defined(TARGET_SDL)
142 case SDL_JOYAXISMOTION:
143 case SDL_JOYBUTTONDOWN:
144 case SDL_JOYBUTTONUP:
145 HandleJoystickEvent(event);
154 void ClearEventQueue()
156 while (PendingEvent())
164 case EVENT_BUTTONRELEASE:
165 button_status = MB_RELEASED;
168 case EVENT_KEYRELEASE:
169 key_joystick_mapping = 0;
173 HandleOtherEvents(&event);
179 void SleepWhileUnmapped()
181 boolean window_unmapped = TRUE;
183 KeyboardAutoRepeatOn();
185 while(window_unmapped)
193 case EVENT_BUTTONRELEASE:
194 button_status = MB_RELEASED;
197 case EVENT_KEYRELEASE:
198 key_joystick_mapping = 0;
201 case EVENT_MAPNOTIFY:
202 window_unmapped = FALSE;
205 case EVENT_UNMAPNOTIFY:
206 /* this is only to surely prevent the 'should not happen' case
207 * of recursively looping between 'SleepWhileUnmapped()' and
208 * 'HandleOtherEvents()' which usually calls this funtion.
213 HandleOtherEvents(&event);
218 if (game_status == PLAYING)
219 KeyboardAutoRepeatOff();
222 void HandleExposeEvent(ExposeEvent *event)
225 RedrawPlayfield(FALSE, event->x, event->y, event->width, event->height);
230 void HandleButtonEvent(ButtonEvent *event)
232 motion_status = FALSE;
234 if (event->type == EVENT_BUTTONPRESS)
235 button_status = event->button;
237 button_status = MB_RELEASED;
239 HandleButton(event->x, event->y, button_status);
242 void HandleMotionEvent(MotionEvent *event)
244 if (!PointerInWindow(window))
245 return; /* window and pointer are on different screens */
248 if (button_status == MB_RELEASED && game_status != LEVELED)
252 motion_status = TRUE;
254 HandleButton(event->x, event->y, button_status);
257 void HandleKeyEvent(KeyEvent *event)
259 int key_status = (event->type==EVENT_KEYPRESS ? KEY_PRESSED : KEY_RELEASED);
260 boolean with_modifiers = (game_status == PLAYING ? FALSE : TRUE);
261 Key key = GetEventKey(event, with_modifiers);
263 HandleKey(key, key_status);
266 void HandleFocusEvent(FocusChangeEvent *event)
268 static int old_joystick_status = -1;
270 if (event->type == EVENT_FOCUSOUT)
274 KeyboardAutoRepeatOn();
275 old_joystick_status = joystick.status;
276 joystick.status = JOYSTICK_NOT_AVAILABLE;
278 /* simulate key release events for still pressed keys */
279 key_joystick_mapping = 0;
280 for (i=0; i<MAX_PLAYERS; i++)
281 stored_player[i].action = 0;
283 else if (event->type == EVENT_FOCUSIN)
285 /* When there are two Rocks'n'Diamonds windows which overlap and
286 the player moves the pointer from one game window to the other,
287 a 'FocusOut' event is generated for the window the pointer is
288 leaving and a 'FocusIn' event is generated for the window the
289 pointer is entering. In some cases, it can happen that the
290 'FocusIn' event is handled by the one game process before the
291 'FocusOut' event by the other game process. In this case the
292 X11 environment would end up with activated keyboard auto repeat,
293 because unfortunately this is a global setting and not (which
294 would be far better) set for each X11 window individually.
295 The effect would be keyboard auto repeat while playing the game
296 (game_status == PLAYING), which is not desired.
297 To avoid this special case, we just wait 1/10 second before
298 processing the 'FocusIn' event.
301 if (game_status == PLAYING)
304 KeyboardAutoRepeatOff();
306 if (old_joystick_status != -1)
307 joystick.status = old_joystick_status;
311 void HandleClientMessageEvent(ClientMessageEvent *event)
313 if (CheckCloseWindowEvent(event))
317 void HandleButton(int mx, int my, int button)
319 static int old_mx = 0, old_my = 0;
333 HandleGadgets(mx, my, button);
338 HandleMainMenu(mx,my, 0,0, button);
342 HandleTypeName(0, KSYM_Return);
346 HandleChooseLevel(mx,my, 0,0, button);
350 HandleHallOfFame(0,0, 0,0, button);
357 HandleHelpScreen(button);
361 HandleSetupScreen(mx,my, 0,0, button);
366 if (button == MB_RELEASED)
368 int sx = (mx - SX) / TILEX;
369 int sy = (my - SY) / TILEY;
371 if (IN_VIS_FIELD(sx,sy))
376 printf("INFO: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
378 if (!IN_LEV_FIELD(x, y))
381 printf(" Feld[%d][%d] == %d\n", x,y, Feld[x][y]);
382 printf(" Store[%d][%d] == %d\n", x,y, Store[x][y]);
383 printf(" Store2[%d][%d] == %d\n", x,y, Store2[x][y]);
384 printf(" StorePlayer[%d][%d] == %d\n", x,y, StorePlayer[x][y]);
385 printf(" MovPos[%d][%d] == %d\n", x,y, MovPos[x][y]);
386 printf(" MovDir[%d][%d] == %d\n", x,y, MovDir[x][y]);
387 printf(" MovDelay[%d][%d] == %d\n", x,y, MovDelay[x][y]);
399 void HandleKey(Key key, int key_status)
402 boolean anyTextGadgetActiveOrJustFinished = anyTextGadgetActive();
403 static struct SetupKeyboardInfo custom_key;
411 { &custom_key.left, DEFAULT_KEY_LEFT, JOY_LEFT },
412 { &custom_key.right, DEFAULT_KEY_RIGHT, JOY_RIGHT },
413 { &custom_key.up, DEFAULT_KEY_UP, JOY_UP },
414 { &custom_key.down, DEFAULT_KEY_DOWN, JOY_DOWN },
415 { &custom_key.snap, DEFAULT_KEY_SNAP, JOY_BUTTON_1 },
416 { &custom_key.bomb, DEFAULT_KEY_BOMB, JOY_BUTTON_2 }
419 if (game_status == PLAYING)
423 for (pnr=0; pnr<MAX_PLAYERS; pnr++)
428 if (setup.input[pnr].use_joystick)
431 custom_key = setup.input[pnr].key;
434 if (key == *key_info[i].key_custom)
435 key_action |= key_info[i].action;
437 if (key_status == KEY_PRESSED)
438 stored_player[pnr].action |= key_action;
440 stored_player[pnr].action &= ~key_action;
448 if (key == key_info[i].key_default)
449 joy |= key_info[i].action;
454 if (key_status == KEY_PRESSED)
455 key_joystick_mapping |= joy;
457 key_joystick_mapping &= ~joy;
462 if (game_status != PLAYING)
463 key_joystick_mapping = 0;
465 if (key_status == KEY_RELEASED)
468 if ((key == KSYM_Return || key == KSYM_space) &&
469 game_status == PLAYING && AllPlayersGone)
471 CloseDoor(DOOR_CLOSE_1);
472 game_status = MAINMENU;
477 /* allow quick escape to the main menu with the Escape key */
478 if (key == KSYM_Escape &&
479 game_status != MAINMENU &&
480 game_status != PLAYING &&
481 game_status != LEVELED &&
482 game_status != CHOOSELEVEL &&
483 game_status != SETUP)
485 game_status = MAINMENU;
490 /* special shortcuts for quick game tape saving and loading */
491 if (game_status == MAINMENU || game_status == PLAYING)
493 if (key == setup.shortcut.save_game)
495 else if (key == setup.shortcut.load_game)
502 if (game_status == PLAYING && (tape.playing || tape.pausing))
509 HandleGadgetsKeyInput(key);
514 HandleTypeName(0, key);
524 if (game_status == MAINMENU)
525 HandleMainMenu(0,0, 0,0, MB_MENU_CHOICE);
526 else if (game_status == CHOOSELEVEL)
527 HandleChooseLevel(0,0, 0,0, MB_MENU_CHOICE);
528 else if (game_status == SETUP)
529 HandleSetupScreen(0,0, 0,0, MB_MENU_CHOICE);
533 if (game_status == CHOOSELEVEL)
534 HandleChooseLevel(0,0, 0,0, MB_MENU_LEAVE);
535 else if (game_status == SETUP)
536 HandleSetupScreen(0,0, 0,0, MB_MENU_LEAVE);
540 if (game_status == CHOOSELEVEL)
541 HandleChooseLevel(0,0, 0,-SCR_FIELDY, MB_MENU_MARK);
545 if (game_status == CHOOSELEVEL)
546 HandleChooseLevel(0,0, 0,SCR_FIELDY, MB_MENU_MARK);
561 HandleHelpScreen(MB_RELEASED);
569 game_status = MAINMENU;
575 HandleHallOfFame(0,0, 0,-SCR_FIELDY, MB_MENU_MARK);
579 HandleHallOfFame(0,0, 0,SCR_FIELDY, MB_MENU_MARK);
588 if (!anyTextGadgetActiveOrJustFinished || key == KSYM_Escape)
589 HandleLevelEditorKeyInput(key);
613 if (GameFrameDelay == 500)
614 GameFrameDelay = GAME_FRAME_DELAY;
616 GameFrameDelay = 500;
619 GameFrameDelay = (key - KSYM_0) * 10;
620 printf("Game speed == %d%% (%d ms delay between two frames)\n",
621 GAME_FRAME_DELAY * 100 / GameFrameDelay, GameFrameDelay);
627 options.debug = FALSE;
628 printf("debug mode disabled\n");
632 options.debug = TRUE;
633 printf("debug mode enabled\n");
638 if (!global.fps_slowdown)
640 global.fps_slowdown = TRUE;
641 global.fps_slowdown_factor = 2;
642 printf("fps slowdown enabled -- display only every 2nd frame\n");
644 else if (global.fps_slowdown_factor == 2)
646 global.fps_slowdown_factor = 4;
647 printf("fps slowdown enabled -- display only every 4th frame\n");
651 global.fps_slowdown = FALSE;
652 global.fps_slowdown_factor = 1;
653 printf("fps slowdown disabled\n");
659 if (ScrollStepSize == TILEX/8)
660 ScrollStepSize = TILEX/4;
662 ScrollStepSize = TILEX/8;
663 printf("ScrollStepSize == %d\n", ScrollStepSize);
672 ScrollStepSize = TILEX/4;
677 ScrollStepSize = TILEX/8;
679 printf("MoveSpeed == %d\n", MoveSpeed);
684 ScrollStepSize = TILEX/8;
685 printf("ScrollStepSize == %d (1/8)\n", ScrollStepSize);
689 ScrollStepSize = TILEX/4;
690 printf("ScrollStepSize == %d (1/4)\n", ScrollStepSize);
694 ScrollStepSize = TILEX/2;
695 printf("ScrollStepSize == %d (1/2)\n", ScrollStepSize);
699 ScrollStepSize = TILEX;
700 printf("ScrollStepSize == %d (1/1)\n", ScrollStepSize);
705 local_player->dynamite = 1000;
716 for(i=0; i<MAX_PLAYERS; i++)
718 printf("Player %d:\n", i);
719 printf(" jx == %d, jy == %d\n",
720 stored_player[i].jx, stored_player[i].jy);
721 printf(" last_jx == %d, last_jy == %d\n",
722 stored_player[i].last_jx, stored_player[i].last_jy);
743 if (button_status && game_status != PLAYING)
745 HandleButton(0, 0, -button_status);
749 #if defined(PLATFORM_UNIX)
757 static int HandleJoystickForAllPlayers()
762 for (i=0; i<MAX_PLAYERS; i++)
767 if (!setup.input[i].use_joystick)
771 joy_action = Joystick(i);
772 result |= joy_action;
775 if (!setup.input[i].use_joystick)
779 stored_player[i].action = joy_action;
785 void HandleJoystick()
787 int joystick = HandleJoystickForAllPlayers();
788 int keyboard = key_joystick_mapping;
789 int joy = (joystick | keyboard);
790 int left = joy & JOY_LEFT;
791 int right = joy & JOY_RIGHT;
792 int up = joy & JOY_UP;
793 int down = joy & JOY_DOWN;
794 int button = joy & JOY_BUTTON;
795 int newbutton = (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED);
796 int dx = (left ? -1 : right ? 1 : 0);
797 int dy = (up ? -1 : down ? 1 : 0);
805 static unsigned long joystickmove_delay = 0;
807 if (joystick && !button &&
808 !DelayReached(&joystickmove_delay, GADGET_FRAME_DELAY))
809 newbutton = dx = dy = 0;
811 if (game_status==MAINMENU)
812 HandleMainMenu(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
813 else if (game_status==CHOOSELEVEL)
814 HandleChooseLevel(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
815 else if (game_status==SETUP)
816 HandleSetupScreen(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
821 HandleHallOfFame(0,0, dx,dy, !newbutton);
825 HandleHelpScreen(!newbutton);
829 if (tape.playing || keyboard)
830 newbutton = ((joy & JOY_BUTTON) != 0);
832 if (AllPlayersGone && newbutton)
834 CloseDoor(DOOR_CLOSE_1);
835 game_status = MAINMENU;