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 ClearPlayerAction()
183 /* simulate key release events for still pressed keys */
184 key_joystick_mapping = 0;
185 for (i=0; i<MAX_PLAYERS; i++)
186 stored_player[i].action = 0;
189 void SleepWhileUnmapped()
191 boolean window_unmapped = TRUE;
193 KeyboardAutoRepeatOn();
195 while(window_unmapped)
203 case EVENT_BUTTONRELEASE:
204 button_status = MB_RELEASED;
207 case EVENT_KEYRELEASE:
208 key_joystick_mapping = 0;
211 case EVENT_MAPNOTIFY:
212 window_unmapped = FALSE;
215 case EVENT_UNMAPNOTIFY:
216 /* this is only to surely prevent the 'should not happen' case
217 * of recursively looping between 'SleepWhileUnmapped()' and
218 * 'HandleOtherEvents()' which usually calls this funtion.
223 HandleOtherEvents(&event);
228 if (game_status == PLAYING)
229 KeyboardAutoRepeatOff();
232 void HandleExposeEvent(ExposeEvent *event)
235 RedrawPlayfield(FALSE, event->x, event->y, event->width, event->height);
240 void HandleButtonEvent(ButtonEvent *event)
242 motion_status = FALSE;
244 if (event->type == EVENT_BUTTONPRESS)
245 button_status = event->button;
247 button_status = MB_RELEASED;
249 HandleButton(event->x, event->y, button_status);
252 void HandleMotionEvent(MotionEvent *event)
254 if (!PointerInWindow(window))
255 return; /* window and pointer are on different screens */
258 if (button_status == MB_RELEASED && game_status != LEVELED)
262 motion_status = TRUE;
264 HandleButton(event->x, event->y, button_status);
267 void HandleKeyEvent(KeyEvent *event)
269 int key_status = (event->type==EVENT_KEYPRESS ? KEY_PRESSED : KEY_RELEASED);
270 boolean with_modifiers = (game_status == PLAYING ? FALSE : TRUE);
271 Key key = GetEventKey(event, with_modifiers);
273 HandleKey(key, key_status);
276 void HandleFocusEvent(FocusChangeEvent *event)
278 static int old_joystick_status = -1;
280 if (event->type == EVENT_FOCUSOUT)
282 KeyboardAutoRepeatOn();
283 old_joystick_status = joystick.status;
284 joystick.status = JOYSTICK_NOT_AVAILABLE;
288 else if (event->type == EVENT_FOCUSIN)
290 /* When there are two Rocks'n'Diamonds windows which overlap and
291 the player moves the pointer from one game window to the other,
292 a 'FocusOut' event is generated for the window the pointer is
293 leaving and a 'FocusIn' event is generated for the window the
294 pointer is entering. In some cases, it can happen that the
295 'FocusIn' event is handled by the one game process before the
296 'FocusOut' event by the other game process. In this case the
297 X11 environment would end up with activated keyboard auto repeat,
298 because unfortunately this is a global setting and not (which
299 would be far better) set for each X11 window individually.
300 The effect would be keyboard auto repeat while playing the game
301 (game_status == PLAYING), which is not desired.
302 To avoid this special case, we just wait 1/10 second before
303 processing the 'FocusIn' event.
306 if (game_status == PLAYING)
309 KeyboardAutoRepeatOff();
311 if (old_joystick_status != -1)
312 joystick.status = old_joystick_status;
316 void HandleClientMessageEvent(ClientMessageEvent *event)
318 if (CheckCloseWindowEvent(event))
322 void HandleButton(int mx, int my, int button)
324 static int old_mx = 0, old_my = 0;
338 HandleGadgets(mx, my, button);
343 HandleMainMenu(mx,my, 0,0, button);
347 HandleTypeName(0, KSYM_Return);
351 HandleChooseLevel(mx,my, 0,0, button);
355 HandleHallOfFame(0,0, 0,0, button);
362 HandleHelpScreen(button);
366 HandleSetupScreen(mx,my, 0,0, button);
371 if (button == MB_RELEASED)
373 int sx = (mx - SX) / TILEX;
374 int sy = (my - SY) / TILEY;
376 if (IN_VIS_FIELD(sx,sy))
381 printf("INFO: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
383 if (!IN_LEV_FIELD(x, y))
386 printf(" Feld[%d][%d] == %d\n", x,y, Feld[x][y]);
387 printf(" Store[%d][%d] == %d\n", x,y, Store[x][y]);
388 printf(" Store2[%d][%d] == %d\n", x,y, Store2[x][y]);
389 printf(" StorePlayer[%d][%d] == %d\n", x,y, StorePlayer[x][y]);
390 printf(" MovPos[%d][%d] == %d\n", x,y, MovPos[x][y]);
391 printf(" MovDir[%d][%d] == %d\n", x,y, MovDir[x][y]);
392 printf(" MovDelay[%d][%d] == %d\n", x,y, MovDelay[x][y]);
404 void HandleKey(Key key, int key_status)
407 boolean anyTextGadgetActiveOrJustFinished = anyTextGadgetActive();
408 static struct SetupKeyboardInfo custom_key;
416 { &custom_key.left, DEFAULT_KEY_LEFT, JOY_LEFT },
417 { &custom_key.right, DEFAULT_KEY_RIGHT, JOY_RIGHT },
418 { &custom_key.up, DEFAULT_KEY_UP, JOY_UP },
419 { &custom_key.down, DEFAULT_KEY_DOWN, JOY_DOWN },
420 { &custom_key.snap, DEFAULT_KEY_SNAP, JOY_BUTTON_1 },
421 { &custom_key.bomb, DEFAULT_KEY_BOMB, JOY_BUTTON_2 }
424 if (game_status == PLAYING)
428 for (pnr=0; pnr<MAX_PLAYERS; pnr++)
433 if (setup.input[pnr].use_joystick)
436 custom_key = setup.input[pnr].key;
439 if (key == *key_info[i].key_custom)
440 key_action |= key_info[i].action;
442 if (key_status == KEY_PRESSED)
443 stored_player[pnr].action |= key_action;
445 stored_player[pnr].action &= ~key_action;
453 if (key == key_info[i].key_default)
454 joy |= key_info[i].action;
459 if (key_status == KEY_PRESSED)
460 key_joystick_mapping |= joy;
462 key_joystick_mapping &= ~joy;
467 if (game_status != PLAYING)
468 key_joystick_mapping = 0;
470 if (key_status == KEY_RELEASED)
473 if ((key == KSYM_Return || key == KSYM_space) &&
474 game_status == PLAYING && AllPlayersGone)
476 CloseDoor(DOOR_CLOSE_1);
477 game_status = MAINMENU;
482 /* allow quick escape to the main menu with the Escape key */
483 if (key == KSYM_Escape &&
484 game_status != MAINMENU &&
485 game_status != PLAYING &&
486 game_status != LEVELED &&
487 game_status != CHOOSELEVEL &&
488 game_status != SETUP)
490 game_status = MAINMENU;
495 /* special shortcuts for quick game tape saving and loading */
496 if (game_status == MAINMENU || game_status == PLAYING)
498 if (key == setup.shortcut.save_game)
500 else if (key == setup.shortcut.load_game)
507 if (game_status == PLAYING && (tape.playing || tape.pausing))
514 HandleGadgetsKeyInput(key);
519 HandleTypeName(0, key);
529 if (game_status == MAINMENU)
530 HandleMainMenu(0,0, 0,0, MB_MENU_CHOICE);
531 else if (game_status == CHOOSELEVEL)
532 HandleChooseLevel(0,0, 0,0, MB_MENU_CHOICE);
533 else if (game_status == SETUP)
534 HandleSetupScreen(0,0, 0,0, MB_MENU_CHOICE);
538 if (game_status == CHOOSELEVEL)
539 HandleChooseLevel(0,0, 0,0, MB_MENU_LEAVE);
540 else if (game_status == SETUP)
541 HandleSetupScreen(0,0, 0,0, MB_MENU_LEAVE);
545 if (game_status == CHOOSELEVEL)
546 HandleChooseLevel(0,0, 0,-SCR_FIELDY, MB_MENU_MARK);
550 if (game_status == CHOOSELEVEL)
551 HandleChooseLevel(0,0, 0,SCR_FIELDY, MB_MENU_MARK);
566 HandleHelpScreen(MB_RELEASED);
574 game_status = MAINMENU;
580 HandleHallOfFame(0,0, 0,-SCR_FIELDY, MB_MENU_MARK);
584 HandleHallOfFame(0,0, 0,SCR_FIELDY, MB_MENU_MARK);
593 if (!anyTextGadgetActiveOrJustFinished || key == KSYM_Escape)
594 HandleLevelEditorKeyInput(key);
602 RequestQuitGame(setup.ask_on_escape);
618 if (GameFrameDelay == 500)
619 GameFrameDelay = GAME_FRAME_DELAY;
621 GameFrameDelay = 500;
624 GameFrameDelay = (key - KSYM_0) * 10;
625 printf("Game speed == %d%% (%d ms delay between two frames)\n",
626 GAME_FRAME_DELAY * 100 / GameFrameDelay, GameFrameDelay);
632 options.debug = FALSE;
633 printf("debug mode disabled\n");
637 options.debug = TRUE;
638 printf("debug mode enabled\n");
643 if (!global.fps_slowdown)
645 global.fps_slowdown = TRUE;
646 global.fps_slowdown_factor = 2;
647 printf("fps slowdown enabled -- display only every 2nd frame\n");
649 else if (global.fps_slowdown_factor == 2)
651 global.fps_slowdown_factor = 4;
652 printf("fps slowdown enabled -- display only every 4th frame\n");
656 global.fps_slowdown = FALSE;
657 global.fps_slowdown_factor = 1;
658 printf("fps slowdown disabled\n");
664 if (ScrollStepSize == TILEX/8)
665 ScrollStepSize = TILEX/4;
667 ScrollStepSize = TILEX/8;
668 printf("ScrollStepSize == %d\n", ScrollStepSize);
677 ScrollStepSize = TILEX/4;
682 ScrollStepSize = TILEX/8;
684 printf("MoveSpeed == %d\n", MoveSpeed);
689 ScrollStepSize = TILEX/8;
690 printf("ScrollStepSize == %d (1/8)\n", ScrollStepSize);
694 ScrollStepSize = TILEX/4;
695 printf("ScrollStepSize == %d (1/4)\n", ScrollStepSize);
699 ScrollStepSize = TILEX/2;
700 printf("ScrollStepSize == %d (1/2)\n", ScrollStepSize);
704 ScrollStepSize = TILEX;
705 printf("ScrollStepSize == %d (1/1)\n", ScrollStepSize);
710 local_player->dynamite = 1000;
721 for(i=0; i<MAX_PLAYERS; i++)
723 printf("Player %d:\n", i);
724 printf(" jx == %d, jy == %d\n",
725 stored_player[i].jx, stored_player[i].jy);
726 printf(" last_jx == %d, last_jy == %d\n",
727 stored_player[i].last_jx, stored_player[i].last_jy);
748 if (button_status && game_status != PLAYING)
750 HandleButton(0, 0, -button_status);
754 #if defined(PLATFORM_UNIX)
762 static int HandleJoystickForAllPlayers()
767 for (i=0; i<MAX_PLAYERS; i++)
772 if (!setup.input[i].use_joystick)
776 joy_action = Joystick(i);
777 result |= joy_action;
779 if (!setup.input[i].use_joystick)
782 stored_player[i].action = joy_action;
788 void HandleJoystick()
790 int joystick = HandleJoystickForAllPlayers();
791 int keyboard = key_joystick_mapping;
792 int joy = (joystick | keyboard);
793 int left = joy & JOY_LEFT;
794 int right = joy & JOY_RIGHT;
795 int up = joy & JOY_UP;
796 int down = joy & JOY_DOWN;
797 int button = joy & JOY_BUTTON;
798 int newbutton = (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED);
799 int dx = (left ? -1 : right ? 1 : 0);
800 int dy = (up ? -1 : down ? 1 : 0);
808 static unsigned long joystickmove_delay = 0;
810 if (joystick && !button &&
811 !DelayReached(&joystickmove_delay, GADGET_FRAME_DELAY))
812 newbutton = dx = dy = 0;
814 if (game_status==MAINMENU)
815 HandleMainMenu(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
816 else if (game_status==CHOOSELEVEL)
817 HandleChooseLevel(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
818 else if (game_status==SETUP)
819 HandleSetupScreen(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
824 HandleHallOfFame(0,0, dx,dy, !newbutton);
828 HandleHelpScreen(!newbutton);
832 if (tape.playing || keyboard)
833 newbutton = ((joy & JOY_BUTTON) != 0);
835 if (AllPlayersGone && newbutton)
837 CloseDoor(DOOR_CLOSE_1);
838 game_status = MAINMENU;