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 int x = event->x, y = event->y;
226 int width = event->width, height = event->height;
228 if (setup.direct_draw && game_status==PLAYING)
231 int x1 = (x-SX)/TILEX, y1 = (y-SY)/TILEY;
232 int x2 = (x-SX+width)/TILEX, y2 = (y-SY+height)/TILEY;
234 SetDrawtoField(DRAW_BACKBUFFER);
236 for(xx=0; xx<SCR_FIELDX; xx++)
237 for(yy=0; yy<SCR_FIELDY; yy++)
238 if (xx>=x1 && xx<=x2 && yy>=y1 && yy<=y2)
239 DrawScreenField(xx,yy);
242 SetDrawtoField(DRAW_DIRECT);
245 if (setup.soft_scrolling && game_status == PLAYING)
247 int fx = FX, fy = FY;
249 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
250 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
252 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
255 BlitBitmap(drawto, window, x,y, width,height, x,y);
261 void HandleButtonEvent(ButtonEvent *event)
263 motion_status = FALSE;
265 if (event->type == EVENT_BUTTONPRESS)
266 button_status = event->button;
268 button_status = MB_RELEASED;
270 HandleButton(event->x, event->y, button_status);
273 void HandleMotionEvent(MotionEvent *event)
275 if (!PointerInWindow(window))
276 return; /* window and pointer are on different screens */
279 if (button_status == MB_RELEASED && game_status != LEVELED)
283 motion_status = TRUE;
285 HandleButton(event->x, event->y, button_status);
288 void HandleKeyEvent(KeyEvent *event)
290 int key_status = (event->type==EVENT_KEYPRESS ? KEY_PRESSED : KEY_RELEASED);
291 boolean with_modifiers = (game_status == PLAYING ? FALSE : TRUE);
292 Key key = GetEventKey(event, with_modifiers);
294 HandleKey(key, key_status);
297 void HandleFocusEvent(FocusChangeEvent *event)
299 static int old_joystick_status = -1;
301 if (event->type == EVENT_FOCUSOUT)
305 KeyboardAutoRepeatOn();
306 old_joystick_status = joystick_status;
307 joystick_status = JOYSTICK_OFF;
309 /* simulate key release events for still pressed keys */
310 key_joystick_mapping = 0;
311 for (i=0; i<MAX_PLAYERS; i++)
312 stored_player[i].action = 0;
314 else if (event->type == EVENT_FOCUSIN)
316 /* When there are two Rocks'n'Diamonds windows which overlap and
317 the player moves the pointer from one game window to the other,
318 a 'FocusOut' event is generated for the window the pointer is
319 leaving and a 'FocusIn' event is generated for the window the
320 pointer is entering. In some cases, it can happen that the
321 'FocusIn' event is handled by the one game process before the
322 'FocusOut' event by the other game process. In this case the
323 X11 environment would end up with activated keyboard auto repeat,
324 because unfortunately this is a global setting and not (which
325 would be far better) set for each X11 window individually.
326 The effect would be keyboard auto repeat while playing the game
327 (game_status == PLAYING), which is not desired.
328 To avoid this special case, we just wait 1/10 second before
329 processing the 'FocusIn' event.
332 if (game_status == PLAYING)
335 KeyboardAutoRepeatOff();
337 if (old_joystick_status != -1)
338 joystick_status = old_joystick_status;
342 void HandleClientMessageEvent(ClientMessageEvent *event)
344 if (CheckCloseWindowEvent(event))
348 void HandleButton(int mx, int my, int button)
350 static int old_mx = 0, old_my = 0;
364 HandleGadgets(mx, my, button);
369 HandleMainMenu(mx,my, 0,0, button);
373 HandleTypeName(0, KSYM_Return);
377 HandleChooseLevel(mx,my, 0,0, button);
381 HandleHallOfFame(0,0, 0,0, button);
388 HandleHelpScreen(button);
392 HandleSetupScreen(mx,my, 0,0, button);
396 HandleSetupInputScreen(mx,my, 0,0, button);
401 if (button == MB_RELEASED)
403 int sx = (mx - SX) / TILEX;
404 int sy = (my - SY) / TILEY;
406 if (IN_VIS_FIELD(sx,sy))
411 printf("INFO: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
413 if (!IN_LEV_FIELD(x, y))
416 printf(" Feld[%d][%d] == %d\n", x,y, Feld[x][y]);
417 printf(" Store[%d][%d] == %d\n", x,y, Store[x][y]);
418 printf(" Store2[%d][%d] == %d\n", x,y, Store2[x][y]);
419 printf(" StorePlayer[%d][%d] == %d\n", x,y, StorePlayer[x][y]);
420 printf(" MovPos[%d][%d] == %d\n", x,y, MovPos[x][y]);
421 printf(" MovDir[%d][%d] == %d\n", x,y, MovDir[x][y]);
422 printf(" MovDelay[%d][%d] == %d\n", x,y, MovDelay[x][y]);
434 void HandleKey(Key key, int key_status)
437 boolean anyTextGadgetActiveOrJustFinished = anyTextGadgetActive();
438 static struct SetupKeyboardInfo custom_key;
446 { &custom_key.left, DEFAULT_KEY_LEFT, JOY_LEFT },
447 { &custom_key.right, DEFAULT_KEY_RIGHT, JOY_RIGHT },
448 { &custom_key.up, DEFAULT_KEY_UP, JOY_UP },
449 { &custom_key.down, DEFAULT_KEY_DOWN, JOY_DOWN },
450 { &custom_key.snap, DEFAULT_KEY_SNAP, JOY_BUTTON_1 },
451 { &custom_key.bomb, DEFAULT_KEY_BOMB, JOY_BUTTON_2 }
454 if (game_status == PLAYING)
458 for (pnr=0; pnr<MAX_PLAYERS; pnr++)
463 if (setup.input[pnr].use_joystick)
466 custom_key = setup.input[pnr].key;
469 if (key == *key_info[i].key_custom)
470 key_action |= key_info[i].action;
472 if (key_status == KEY_PRESSED)
473 stored_player[pnr].action |= key_action;
475 stored_player[pnr].action &= ~key_action;
483 if (key == key_info[i].key_default)
484 joy |= key_info[i].action;
489 if (key_status == KEY_PRESSED)
490 key_joystick_mapping |= joy;
492 key_joystick_mapping &= ~joy;
497 if (game_status != PLAYING)
498 key_joystick_mapping = 0;
500 if (key_status == KEY_RELEASED)
503 if ((key == KSYM_Return || key == KSYM_space) &&
504 game_status == PLAYING && AllPlayersGone)
506 CloseDoor(DOOR_CLOSE_1);
507 game_status = MAINMENU;
512 /* allow quick escape to the main menu with the Escape key */
513 if (key == KSYM_Escape && game_status != MAINMENU)
515 CloseDoor(DOOR_CLOSE_1 | DOOR_OPEN_2 | DOOR_NO_DELAY);
516 game_status = MAINMENU;
525 if (game_status == PLAYING && (tape.playing || tape.pausing))
532 HandleGadgetsKeyInput(key);
537 HandleTypeName(0, key);
548 if (game_status == MAINMENU)
549 HandleMainMenu(0,0, 0,0, MB_MENU_CHOICE);
550 else if (game_status == CHOOSELEVEL)
551 HandleChooseLevel(0,0, 0,0, MB_MENU_CHOICE);
552 else if (game_status == SETUP)
553 HandleSetupScreen(0,0, 0,0, MB_MENU_CHOICE);
554 else if (game_status == SETUPINPUT)
555 HandleSetupInputScreen(0,0, 0,0, MB_MENU_CHOICE);
559 if (game_status == CHOOSELEVEL)
560 HandleChooseLevel(0,0, 0,-SCR_FIELDY, MB_MENU_MARK);
564 if (game_status == CHOOSELEVEL)
565 HandleChooseLevel(0,0, 0,SCR_FIELDY, MB_MENU_MARK);
574 HandleHelpScreen(MB_RELEASED);
582 game_status = MAINMENU;
588 HandleHallOfFame(0,0, 0,-SCR_FIELDY, MB_MENU_MARK);
592 HandleHallOfFame(0,0, 0,SCR_FIELDY, MB_MENU_MARK);
601 if (!anyTextGadgetActiveOrJustFinished)
602 HandleLevelEditorKeyInput(key);
623 if (GameFrameDelay == 500)
624 GameFrameDelay = GAME_FRAME_DELAY;
626 GameFrameDelay = 500;
629 GameFrameDelay = (key - KSYM_0) * 10;
630 printf("Game speed == %d%% (%d ms delay between two frames)\n",
631 GAME_FRAME_DELAY * 100 / GameFrameDelay, GameFrameDelay);
637 options.debug = FALSE;
638 printf("debug mode disabled\n");
642 options.debug = TRUE;
643 printf("debug mode enabled\n");
648 if (!global.fps_slowdown)
650 global.fps_slowdown = TRUE;
651 global.fps_slowdown_factor = 2;
652 printf("fps slowdown enabled -- display only every 2nd frame\n");
654 else if (global.fps_slowdown_factor == 2)
656 global.fps_slowdown_factor = 4;
657 printf("fps slowdown enabled -- display only every 4th frame\n");
661 global.fps_slowdown = FALSE;
662 global.fps_slowdown_factor = 1;
663 printf("fps slowdown disabled\n");
669 if (ScrollStepSize == TILEX/8)
670 ScrollStepSize = TILEX/4;
672 ScrollStepSize = TILEX/8;
673 printf("ScrollStepSize == %d\n", ScrollStepSize);
682 ScrollStepSize = TILEX/4;
687 ScrollStepSize = TILEX/8;
689 printf("MoveSpeed == %d\n", MoveSpeed);
694 ScrollStepSize = TILEX/8;
695 printf("ScrollStepSize == %d (1/8)\n", ScrollStepSize);
699 ScrollStepSize = TILEX/4;
700 printf("ScrollStepSize == %d (1/4)\n", ScrollStepSize);
704 ScrollStepSize = TILEX/2;
705 printf("ScrollStepSize == %d (1/2)\n", ScrollStepSize);
709 ScrollStepSize = TILEX;
710 printf("ScrollStepSize == %d (1/1)\n", ScrollStepSize);
715 local_player->dynamite = 1000;
726 for(i=0; i<MAX_PLAYERS; i++)
728 printf("Player %d:\n", i);
729 printf(" jx == %d, jy == %d\n",
730 stored_player[i].jx, stored_player[i].jy);
731 printf(" last_jx == %d, last_jy == %d\n",
732 stored_player[i].last_jx, stored_player[i].last_jy);
753 if (button_status && game_status != PLAYING)
755 HandleButton(0, 0, -button_status);
759 #if defined(PLATFORM_UNIX)
767 static int HandleJoystickForAllPlayers()
772 for (i=0; i<MAX_PLAYERS; i++)
777 if (!setup.input[i].use_joystick)
781 joy_action = Joystick(i);
782 result |= joy_action;
785 if (!setup.input[i].use_joystick)
789 stored_player[i].action = joy_action;
795 void HandleJoystick()
797 int joystick = HandleJoystickForAllPlayers();
798 int keyboard = key_joystick_mapping;
799 int joy = (joystick | keyboard);
800 int left = joy & JOY_LEFT;
801 int right = joy & JOY_RIGHT;
802 int up = joy & JOY_UP;
803 int down = joy & JOY_DOWN;
804 int button = joy & JOY_BUTTON;
805 int newbutton = (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED);
806 int dx = (left ? -1 : right ? 1 : 0);
807 int dy = (up ? -1 : down ? 1 : 0);
816 static unsigned long joystickmove_delay = 0;
818 if (joystick && !button &&
819 !DelayReached(&joystickmove_delay, GADGET_FRAME_DELAY))
820 newbutton = dx = dy = 0;
822 if (game_status==MAINMENU)
823 HandleMainMenu(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
824 else if (game_status==CHOOSELEVEL)
825 HandleChooseLevel(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
826 else if (game_status==SETUP)
827 HandleSetupScreen(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
828 else if (game_status==SETUPINPUT)
829 HandleSetupInputScreen(0,0,dx,dy,
830 newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
835 HandleHallOfFame(0,0, dx,dy, !newbutton);
839 HandleHelpScreen(!newbutton);
843 if (tape.playing || keyboard)
844 newbutton = ((joy & JOY_BUTTON) != 0);
846 if (AllPlayersGone && newbutton)
848 CloseDoor(DOOR_CLOSE_1);
849 game_status = MAINMENU;