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;
493 if (game_status == PLAYING && (tape.playing || tape.pausing))
500 HandleGadgetsKeyInput(key);
505 HandleTypeName(0, key);
515 if (game_status == MAINMENU)
516 HandleMainMenu(0,0, 0,0, MB_MENU_CHOICE);
517 else if (game_status == CHOOSELEVEL)
518 HandleChooseLevel(0,0, 0,0, MB_MENU_CHOICE);
519 else if (game_status == SETUP)
520 HandleSetupScreen(0,0, 0,0, MB_MENU_CHOICE);
524 if (game_status == CHOOSELEVEL)
525 HandleChooseLevel(0,0, 0,0, MB_MENU_LEAVE);
526 else if (game_status == SETUP)
527 HandleSetupScreen(0,0, 0,0, MB_MENU_LEAVE);
531 if (game_status == CHOOSELEVEL)
532 HandleChooseLevel(0,0, 0,-SCR_FIELDY, MB_MENU_MARK);
536 if (game_status == CHOOSELEVEL)
537 HandleChooseLevel(0,0, 0,SCR_FIELDY, MB_MENU_MARK);
552 HandleHelpScreen(MB_RELEASED);
560 game_status = MAINMENU;
566 HandleHallOfFame(0,0, 0,-SCR_FIELDY, MB_MENU_MARK);
570 HandleHallOfFame(0,0, 0,SCR_FIELDY, MB_MENU_MARK);
579 if (!anyTextGadgetActiveOrJustFinished || key == KSYM_Escape)
580 HandleLevelEditorKeyInput(key);
601 if (GameFrameDelay == 500)
602 GameFrameDelay = GAME_FRAME_DELAY;
604 GameFrameDelay = 500;
607 GameFrameDelay = (key - KSYM_0) * 10;
608 printf("Game speed == %d%% (%d ms delay between two frames)\n",
609 GAME_FRAME_DELAY * 100 / GameFrameDelay, GameFrameDelay);
615 options.debug = FALSE;
616 printf("debug mode disabled\n");
620 options.debug = TRUE;
621 printf("debug mode enabled\n");
626 if (!global.fps_slowdown)
628 global.fps_slowdown = TRUE;
629 global.fps_slowdown_factor = 2;
630 printf("fps slowdown enabled -- display only every 2nd frame\n");
632 else if (global.fps_slowdown_factor == 2)
634 global.fps_slowdown_factor = 4;
635 printf("fps slowdown enabled -- display only every 4th frame\n");
639 global.fps_slowdown = FALSE;
640 global.fps_slowdown_factor = 1;
641 printf("fps slowdown disabled\n");
647 if (ScrollStepSize == TILEX/8)
648 ScrollStepSize = TILEX/4;
650 ScrollStepSize = TILEX/8;
651 printf("ScrollStepSize == %d\n", ScrollStepSize);
660 ScrollStepSize = TILEX/4;
665 ScrollStepSize = TILEX/8;
667 printf("MoveSpeed == %d\n", MoveSpeed);
672 ScrollStepSize = TILEX/8;
673 printf("ScrollStepSize == %d (1/8)\n", ScrollStepSize);
677 ScrollStepSize = TILEX/4;
678 printf("ScrollStepSize == %d (1/4)\n", ScrollStepSize);
682 ScrollStepSize = TILEX/2;
683 printf("ScrollStepSize == %d (1/2)\n", ScrollStepSize);
687 ScrollStepSize = TILEX;
688 printf("ScrollStepSize == %d (1/1)\n", ScrollStepSize);
693 local_player->dynamite = 1000;
704 for(i=0; i<MAX_PLAYERS; i++)
706 printf("Player %d:\n", i);
707 printf(" jx == %d, jy == %d\n",
708 stored_player[i].jx, stored_player[i].jy);
709 printf(" last_jx == %d, last_jy == %d\n",
710 stored_player[i].last_jx, stored_player[i].last_jy);
731 if (button_status && game_status != PLAYING)
733 HandleButton(0, 0, -button_status);
737 #if defined(PLATFORM_UNIX)
745 static int HandleJoystickForAllPlayers()
750 for (i=0; i<MAX_PLAYERS; i++)
755 if (!setup.input[i].use_joystick)
759 joy_action = Joystick(i);
760 result |= joy_action;
763 if (!setup.input[i].use_joystick)
767 stored_player[i].action = joy_action;
773 void HandleJoystick()
775 int joystick = HandleJoystickForAllPlayers();
776 int keyboard = key_joystick_mapping;
777 int joy = (joystick | keyboard);
778 int left = joy & JOY_LEFT;
779 int right = joy & JOY_RIGHT;
780 int up = joy & JOY_UP;
781 int down = joy & JOY_DOWN;
782 int button = joy & JOY_BUTTON;
783 int newbutton = (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED);
784 int dx = (left ? -1 : right ? 1 : 0);
785 int dy = (up ? -1 : down ? 1 : 0);
793 static unsigned long joystickmove_delay = 0;
795 if (joystick && !button &&
796 !DelayReached(&joystickmove_delay, GADGET_FRAME_DELAY))
797 newbutton = dx = dy = 0;
799 if (game_status==MAINMENU)
800 HandleMainMenu(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
801 else if (game_status==CHOOSELEVEL)
802 HandleChooseLevel(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
803 else if (game_status==SETUP)
804 HandleSetupScreen(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
809 HandleHallOfFame(0,0, dx,dy, !newbutton);
813 HandleHelpScreen(!newbutton);
817 if (tape.playing || keyboard)
818 newbutton = ((joy & JOY_BUTTON) != 0);
820 if (AllPlayersGone && newbutton)
822 CloseDoor(DOOR_CLOSE_1);
823 game_status = MAINMENU;