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"
27 /* values for key_status */
28 #define KEY_NOT_PRESSED FALSE
29 #define KEY_RELEASED FALSE
30 #define KEY_PRESSED TRUE
33 /* event filter especially needed for SDL event filtering due to
34 delay problems with lots of mouse motion events when mouse
37 int FilterMouseMotionEvents(const Event *event)
39 if (event->type != EVENT_MOTIONNOTIFY)
42 /* get mouse motion events without pressed button only in level editor */
43 if (button_status == MB_RELEASED && game_status != LEVELED)
49 /* this is only really needed for non-SDL targets to filter unwanted events;
50 when using SDL with properly installed event filter, this function can be
51 replaced with a simple "NextEvent()" call, but it doesn't hurt either */
53 static boolean NextValidEvent(Event *event)
55 while (PendingEvent())
59 if (FilterMouseMotionEvents(event))
70 if (PendingEvent()) /* got event */
74 if (NextValidEvent(&event))
78 case EVENT_BUTTONPRESS:
79 case EVENT_BUTTONRELEASE:
80 HandleButtonEvent((ButtonEvent *) &event);
83 case EVENT_MOTIONNOTIFY:
84 HandleMotionEvent((MotionEvent *) &event);
88 case EVENT_KEYRELEASE:
89 HandleKeyEvent((KeyEvent *) &event);
93 HandleOtherEvents(&event);
101 /* don't use all CPU time when idle; the main loop while playing
102 has its own synchronization and is CPU friendly, too */
104 if (game_status == PLAYING)
109 if (!PendingEvent()) /* delay only if no pending events */
113 /* refresh window contents from drawing buffer, if needed */
116 if (game_status == EXITGAME)
121 void HandleOtherEvents(Event *event)
126 HandleExposeEvent((ExposeEvent *) event);
129 case EVENT_UNMAPNOTIFY:
130 SleepWhileUnmapped();
135 HandleFocusEvent((FocusChangeEvent *) event);
138 case EVENT_CLIENTMESSAGE:
139 HandleClientMessageEvent((ClientMessageEvent *) event);
142 #if defined(TARGET_SDL)
143 case SDL_JOYAXISMOTION:
144 case SDL_JOYBUTTONDOWN:
145 case SDL_JOYBUTTONUP:
146 HandleJoystickEvent(event);
155 void ClearEventQueue()
157 while (PendingEvent())
165 case EVENT_BUTTONRELEASE:
166 button_status = MB_RELEASED;
169 case EVENT_KEYRELEASE:
170 key_joystick_mapping = 0;
174 HandleOtherEvents(&event);
180 void SleepWhileUnmapped()
182 boolean window_unmapped = TRUE;
184 KeyboardAutoRepeatOn();
186 while(window_unmapped)
194 case EVENT_BUTTONRELEASE:
195 button_status = MB_RELEASED;
198 case EVENT_KEYRELEASE:
199 key_joystick_mapping = 0;
202 case EVENT_MAPNOTIFY:
203 window_unmapped = FALSE;
206 case EVENT_UNMAPNOTIFY:
207 /* this is only to surely prevent the 'should not happen' case
208 * of recursively looping between 'SleepWhileUnmapped()' and
209 * 'HandleOtherEvents()' which usually calls this funtion.
214 HandleOtherEvents(&event);
219 if (game_status == PLAYING)
220 KeyboardAutoRepeatOff();
223 void HandleExposeEvent(ExposeEvent *event)
226 int x = event->x, y = event->y;
227 int width = event->width, height = event->height;
229 if (setup.direct_draw && game_status==PLAYING)
232 int x1 = (x-SX)/TILEX, y1 = (y-SY)/TILEY;
233 int x2 = (x-SX+width)/TILEX, y2 = (y-SY+height)/TILEY;
235 SetDrawtoField(DRAW_BACKBUFFER);
237 for(xx=0; xx<SCR_FIELDX; xx++)
238 for(yy=0; yy<SCR_FIELDY; yy++)
239 if (xx>=x1 && xx<=x2 && yy>=y1 && yy<=y2)
240 DrawScreenField(xx,yy);
243 SetDrawtoField(DRAW_DIRECT);
246 if (setup.soft_scrolling && game_status == PLAYING)
248 int fx = FX, fy = FY;
250 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
251 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
253 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
256 BlitBitmap(drawto, window, x,y, width,height, x,y);
262 void HandleButtonEvent(ButtonEvent *event)
264 motion_status = FALSE;
266 if (event->type == EVENT_BUTTONPRESS)
267 button_status = event->button;
269 button_status = MB_RELEASED;
271 HandleButton(event->x, event->y, button_status);
274 void HandleMotionEvent(MotionEvent *event)
276 if (!PointerInWindow(window))
277 return; /* window and pointer are on different screens */
280 if (button_status == MB_RELEASED && game_status != LEVELED)
284 motion_status = TRUE;
286 HandleButton(event->x, event->y, button_status);
289 void HandleKeyEvent(KeyEvent *event)
291 int key_status = (event->type==EVENT_KEYPRESS ? KEY_PRESSED : KEY_RELEASED);
292 boolean with_modifiers = (game_status == PLAYING ? FALSE : TRUE);
293 Key key = GetEventKey(event, with_modifiers);
295 HandleKey(key, key_status);
298 void HandleFocusEvent(FocusChangeEvent *event)
300 static int old_joystick_status = -1;
302 if (event->type == EVENT_FOCUSOUT)
306 KeyboardAutoRepeatOn();
307 old_joystick_status = joystick_status;
308 joystick_status = JOYSTICK_OFF;
310 /* simulate key release events for still pressed keys */
311 key_joystick_mapping = 0;
312 for (i=0; i<MAX_PLAYERS; i++)
313 stored_player[i].action = 0;
315 else if (event->type == EVENT_FOCUSIN)
317 /* When there are two Rocks'n'Diamonds windows which overlap and
318 the player moves the pointer from one game window to the other,
319 a 'FocusOut' event is generated for the window the pointer is
320 leaving and a 'FocusIn' event is generated for the window the
321 pointer is entering. In some cases, it can happen that the
322 'FocusIn' event is handled by the one game process before the
323 'FocusOut' event by the other game process. In this case the
324 X11 environment would end up with activated keyboard auto repeat,
325 because unfortunately this is a global setting and not (which
326 would be far better) set for each X11 window individually.
327 The effect would be keyboard auto repeat while playing the game
328 (game_status == PLAYING), which is not desired.
329 To avoid this special case, we just wait 1/10 second before
330 processing the 'FocusIn' event.
333 if (game_status == PLAYING)
336 KeyboardAutoRepeatOff();
338 if (old_joystick_status != -1)
339 joystick_status = old_joystick_status;
343 void HandleClientMessageEvent(ClientMessageEvent *event)
345 if (CheckCloseWindowEvent(event))
349 void HandleButton(int mx, int my, int button)
351 static int old_mx = 0, old_my = 0;
365 HandleGadgets(mx, my, button);
370 HandleMainMenu(mx,my, 0,0, button);
374 HandleTypeName(0, KSYM_Return);
378 HandleChooseLevel(mx,my, 0,0, button);
382 HandleHallOfFame(0,0, 0,0, button);
389 HandleHelpScreen(button);
393 HandleSetupScreen(mx,my, 0,0, button);
397 HandleSetupInputScreen(mx,my, 0,0, button);
402 if (button == MB_RELEASED)
404 int sx = (mx - SX) / TILEX;
405 int sy = (my - SY) / TILEY;
407 if (IN_VIS_FIELD(sx,sy))
412 printf("INFO: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
414 if (!IN_LEV_FIELD(x, y))
417 printf(" Feld[%d][%d] == %d\n", x,y, Feld[x][y]);
418 printf(" Store[%d][%d] == %d\n", x,y, Store[x][y]);
419 printf(" Store2[%d][%d] == %d\n", x,y, Store2[x][y]);
420 printf(" StorePlayer[%d][%d] == %d\n", x,y, StorePlayer[x][y]);
421 printf(" MovPos[%d][%d] == %d\n", x,y, MovPos[x][y]);
422 printf(" MovDir[%d][%d] == %d\n", x,y, MovDir[x][y]);
423 printf(" MovDelay[%d][%d] == %d\n", x,y, MovDelay[x][y]);
435 void HandleKey(Key key, int key_status)
438 boolean anyTextGadgetActiveOrJustFinished = anyTextGadgetActive();
439 static struct SetupKeyboardInfo custom_key;
447 { &custom_key.left, DEFAULT_KEY_LEFT, JOY_LEFT },
448 { &custom_key.right, DEFAULT_KEY_RIGHT, JOY_RIGHT },
449 { &custom_key.up, DEFAULT_KEY_UP, JOY_UP },
450 { &custom_key.down, DEFAULT_KEY_DOWN, JOY_DOWN },
451 { &custom_key.snap, DEFAULT_KEY_SNAP, JOY_BUTTON_1 },
452 { &custom_key.bomb, DEFAULT_KEY_BOMB, JOY_BUTTON_2 }
455 if (game_status == PLAYING)
459 for (pnr=0; pnr<MAX_PLAYERS; pnr++)
464 if (setup.input[pnr].use_joystick)
467 custom_key = setup.input[pnr].key;
470 if (key == *key_info[i].key_custom)
471 key_action |= key_info[i].action;
473 if (key_status == KEY_PRESSED)
474 stored_player[pnr].action |= key_action;
476 stored_player[pnr].action &= ~key_action;
484 if (key == key_info[i].key_default)
485 joy |= key_info[i].action;
490 if (key_status == KEY_PRESSED)
491 key_joystick_mapping |= joy;
493 key_joystick_mapping &= ~joy;
498 if (game_status != PLAYING)
499 key_joystick_mapping = 0;
501 if (key_status == KEY_RELEASED)
504 if ((key == KSYM_Return || key == KSYM_space) &&
505 game_status == PLAYING && AllPlayersGone)
507 CloseDoor(DOOR_CLOSE_1);
508 game_status = MAINMENU;
513 /* allow quick escape to the main menu with the Escape key */
514 if (key == KSYM_Escape &&
515 game_status != MAINMENU && game_status != LEVELED)
517 game_status = MAINMENU;
526 if (game_status == PLAYING && (tape.playing || tape.pausing))
533 HandleGadgetsKeyInput(key);
538 HandleTypeName(0, key);
549 if (game_status == MAINMENU)
550 HandleMainMenu(0,0, 0,0, MB_MENU_CHOICE);
551 else if (game_status == CHOOSELEVEL)
552 HandleChooseLevel(0,0, 0,0, MB_MENU_CHOICE);
553 else if (game_status == SETUP)
554 HandleSetupScreen(0,0, 0,0, MB_MENU_CHOICE);
555 else if (game_status == SETUPINPUT)
556 HandleSetupInputScreen(0,0, 0,0, MB_MENU_CHOICE);
560 if (game_status == CHOOSELEVEL)
561 HandleChooseLevel(0,0, 0,-SCR_FIELDY, MB_MENU_MARK);
565 if (game_status == CHOOSELEVEL)
566 HandleChooseLevel(0,0, 0,SCR_FIELDY, MB_MENU_MARK);
581 HandleHelpScreen(MB_RELEASED);
589 game_status = MAINMENU;
595 HandleHallOfFame(0,0, 0,-SCR_FIELDY, MB_MENU_MARK);
599 HandleHallOfFame(0,0, 0,SCR_FIELDY, MB_MENU_MARK);
608 if (!anyTextGadgetActiveOrJustFinished || key == KSYM_Escape)
609 HandleLevelEditorKeyInput(key);
630 if (GameFrameDelay == 500)
631 GameFrameDelay = GAME_FRAME_DELAY;
633 GameFrameDelay = 500;
636 GameFrameDelay = (key - KSYM_0) * 10;
637 printf("Game speed == %d%% (%d ms delay between two frames)\n",
638 GAME_FRAME_DELAY * 100 / GameFrameDelay, GameFrameDelay);
644 options.debug = FALSE;
645 printf("debug mode disabled\n");
649 options.debug = TRUE;
650 printf("debug mode enabled\n");
655 if (!global.fps_slowdown)
657 global.fps_slowdown = TRUE;
658 global.fps_slowdown_factor = 2;
659 printf("fps slowdown enabled -- display only every 2nd frame\n");
661 else if (global.fps_slowdown_factor == 2)
663 global.fps_slowdown_factor = 4;
664 printf("fps slowdown enabled -- display only every 4th frame\n");
668 global.fps_slowdown = FALSE;
669 global.fps_slowdown_factor = 1;
670 printf("fps slowdown disabled\n");
676 if (ScrollStepSize == TILEX/8)
677 ScrollStepSize = TILEX/4;
679 ScrollStepSize = TILEX/8;
680 printf("ScrollStepSize == %d\n", ScrollStepSize);
689 ScrollStepSize = TILEX/4;
694 ScrollStepSize = TILEX/8;
696 printf("MoveSpeed == %d\n", MoveSpeed);
701 ScrollStepSize = TILEX/8;
702 printf("ScrollStepSize == %d (1/8)\n", ScrollStepSize);
706 ScrollStepSize = TILEX/4;
707 printf("ScrollStepSize == %d (1/4)\n", ScrollStepSize);
711 ScrollStepSize = TILEX/2;
712 printf("ScrollStepSize == %d (1/2)\n", ScrollStepSize);
716 ScrollStepSize = TILEX;
717 printf("ScrollStepSize == %d (1/1)\n", ScrollStepSize);
722 local_player->dynamite = 1000;
733 for(i=0; i<MAX_PLAYERS; i++)
735 printf("Player %d:\n", i);
736 printf(" jx == %d, jy == %d\n",
737 stored_player[i].jx, stored_player[i].jy);
738 printf(" last_jx == %d, last_jy == %d\n",
739 stored_player[i].last_jx, stored_player[i].last_jy);
760 if (button_status && game_status != PLAYING)
762 HandleButton(0, 0, -button_status);
766 #if defined(PLATFORM_UNIX)
774 static int HandleJoystickForAllPlayers()
779 for (i=0; i<MAX_PLAYERS; i++)
784 if (!setup.input[i].use_joystick)
788 joy_action = Joystick(i);
789 result |= joy_action;
792 if (!setup.input[i].use_joystick)
796 stored_player[i].action = joy_action;
802 void HandleJoystick()
804 int joystick = HandleJoystickForAllPlayers();
805 int keyboard = key_joystick_mapping;
806 int joy = (joystick | keyboard);
807 int left = joy & JOY_LEFT;
808 int right = joy & JOY_RIGHT;
809 int up = joy & JOY_UP;
810 int down = joy & JOY_DOWN;
811 int button = joy & JOY_BUTTON;
812 int newbutton = (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED);
813 int dx = (left ? -1 : right ? 1 : 0);
814 int dy = (up ? -1 : down ? 1 : 0);
823 static unsigned long joystickmove_delay = 0;
825 if (joystick && !button &&
826 !DelayReached(&joystickmove_delay, GADGET_FRAME_DELAY))
827 newbutton = dx = dy = 0;
829 if (game_status==MAINMENU)
830 HandleMainMenu(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
831 else if (game_status==CHOOSELEVEL)
832 HandleChooseLevel(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
833 else if (game_status==SETUP)
834 HandleSetupScreen(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
835 else if (game_status==SETUPINPUT)
836 HandleSetupInputScreen(0,0,dx,dy,
837 newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
842 HandleHallOfFame(0,0, dx,dy, !newbutton);
846 HandleHelpScreen(!newbutton);
850 if (tape.playing || keyboard)
851 newbutton = ((joy & JOY_BUTTON) != 0);
853 if (AllPlayersGone && newbutton)
855 CloseDoor(DOOR_CLOSE_1);
856 game_status = MAINMENU;