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 != LEVELED &&
481 game_status != CHOOSELEVEL &&
482 game_status != SETUP)
484 game_status = MAINMENU;
489 /* special shortcuts for quick game tape saving and loading */
490 if (game_status == MAINMENU || game_status == PLAYING)
492 if (key == setup.shortcut.save_game)
494 else if (key == setup.shortcut.load_game)
501 if (game_status == PLAYING && (tape.playing || tape.pausing))
508 HandleGadgetsKeyInput(key);
513 HandleTypeName(0, key);
523 if (game_status == MAINMENU)
524 HandleMainMenu(0,0, 0,0, MB_MENU_CHOICE);
525 else if (game_status == CHOOSELEVEL)
526 HandleChooseLevel(0,0, 0,0, MB_MENU_CHOICE);
527 else if (game_status == SETUP)
528 HandleSetupScreen(0,0, 0,0, MB_MENU_CHOICE);
532 if (game_status == CHOOSELEVEL)
533 HandleChooseLevel(0,0, 0,0, MB_MENU_LEAVE);
534 else if (game_status == SETUP)
535 HandleSetupScreen(0,0, 0,0, MB_MENU_LEAVE);
539 if (game_status == CHOOSELEVEL)
540 HandleChooseLevel(0,0, 0,-SCR_FIELDY, MB_MENU_MARK);
544 if (game_status == CHOOSELEVEL)
545 HandleChooseLevel(0,0, 0,SCR_FIELDY, MB_MENU_MARK);
560 HandleHelpScreen(MB_RELEASED);
568 game_status = MAINMENU;
574 HandleHallOfFame(0,0, 0,-SCR_FIELDY, MB_MENU_MARK);
578 HandleHallOfFame(0,0, 0,SCR_FIELDY, MB_MENU_MARK);
587 if (!anyTextGadgetActiveOrJustFinished || key == KSYM_Escape)
588 HandleLevelEditorKeyInput(key);
609 if (GameFrameDelay == 500)
610 GameFrameDelay = GAME_FRAME_DELAY;
612 GameFrameDelay = 500;
615 GameFrameDelay = (key - KSYM_0) * 10;
616 printf("Game speed == %d%% (%d ms delay between two frames)\n",
617 GAME_FRAME_DELAY * 100 / GameFrameDelay, GameFrameDelay);
623 options.debug = FALSE;
624 printf("debug mode disabled\n");
628 options.debug = TRUE;
629 printf("debug mode enabled\n");
634 if (!global.fps_slowdown)
636 global.fps_slowdown = TRUE;
637 global.fps_slowdown_factor = 2;
638 printf("fps slowdown enabled -- display only every 2nd frame\n");
640 else if (global.fps_slowdown_factor == 2)
642 global.fps_slowdown_factor = 4;
643 printf("fps slowdown enabled -- display only every 4th frame\n");
647 global.fps_slowdown = FALSE;
648 global.fps_slowdown_factor = 1;
649 printf("fps slowdown disabled\n");
655 if (ScrollStepSize == TILEX/8)
656 ScrollStepSize = TILEX/4;
658 ScrollStepSize = TILEX/8;
659 printf("ScrollStepSize == %d\n", ScrollStepSize);
668 ScrollStepSize = TILEX/4;
673 ScrollStepSize = TILEX/8;
675 printf("MoveSpeed == %d\n", MoveSpeed);
680 ScrollStepSize = TILEX/8;
681 printf("ScrollStepSize == %d (1/8)\n", ScrollStepSize);
685 ScrollStepSize = TILEX/4;
686 printf("ScrollStepSize == %d (1/4)\n", ScrollStepSize);
690 ScrollStepSize = TILEX/2;
691 printf("ScrollStepSize == %d (1/2)\n", ScrollStepSize);
695 ScrollStepSize = TILEX;
696 printf("ScrollStepSize == %d (1/1)\n", ScrollStepSize);
701 local_player->dynamite = 1000;
712 for(i=0; i<MAX_PLAYERS; i++)
714 printf("Player %d:\n", i);
715 printf(" jx == %d, jy == %d\n",
716 stored_player[i].jx, stored_player[i].jy);
717 printf(" last_jx == %d, last_jy == %d\n",
718 stored_player[i].last_jx, stored_player[i].last_jy);
739 if (button_status && game_status != PLAYING)
741 HandleButton(0, 0, -button_status);
745 #if defined(PLATFORM_UNIX)
753 static int HandleJoystickForAllPlayers()
758 for (i=0; i<MAX_PLAYERS; i++)
763 if (!setup.input[i].use_joystick)
767 joy_action = Joystick(i);
768 result |= joy_action;
771 if (!setup.input[i].use_joystick)
775 stored_player[i].action = joy_action;
781 void HandleJoystick()
783 int joystick = HandleJoystickForAllPlayers();
784 int keyboard = key_joystick_mapping;
785 int joy = (joystick | keyboard);
786 int left = joy & JOY_LEFT;
787 int right = joy & JOY_RIGHT;
788 int up = joy & JOY_UP;
789 int down = joy & JOY_DOWN;
790 int button = joy & JOY_BUTTON;
791 int newbutton = (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED);
792 int dx = (left ? -1 : right ? 1 : 0);
793 int dy = (up ? -1 : down ? 1 : 0);
801 static unsigned long joystickmove_delay = 0;
803 if (joystick && !button &&
804 !DelayReached(&joystickmove_delay, GADGET_FRAME_DELAY))
805 newbutton = dx = dy = 0;
807 if (game_status==MAINMENU)
808 HandleMainMenu(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
809 else if (game_status==CHOOSELEVEL)
810 HandleChooseLevel(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
811 else if (game_status==SETUP)
812 HandleSetupScreen(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
817 HandleHallOfFame(0,0, dx,dy, !newbutton);
821 HandleHelpScreen(!newbutton);
825 if (tape.playing || keyboard)
826 newbutton = ((joy & JOY_BUTTON) != 0);
828 if (AllPlayersGone && newbutton)
830 CloseDoor(DOOR_CLOSE_1);
831 game_status = MAINMENU;