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_NOT_AVAILABLE;
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);
397 if (button == MB_RELEASED)
399 int sx = (mx - SX) / TILEX;
400 int sy = (my - SY) / TILEY;
402 if (IN_VIS_FIELD(sx,sy))
407 printf("INFO: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
409 if (!IN_LEV_FIELD(x, y))
412 printf(" Feld[%d][%d] == %d\n", x,y, Feld[x][y]);
413 printf(" Store[%d][%d] == %d\n", x,y, Store[x][y]);
414 printf(" Store2[%d][%d] == %d\n", x,y, Store2[x][y]);
415 printf(" StorePlayer[%d][%d] == %d\n", x,y, StorePlayer[x][y]);
416 printf(" MovPos[%d][%d] == %d\n", x,y, MovPos[x][y]);
417 printf(" MovDir[%d][%d] == %d\n", x,y, MovDir[x][y]);
418 printf(" MovDelay[%d][%d] == %d\n", x,y, MovDelay[x][y]);
430 void HandleKey(Key key, int key_status)
433 boolean anyTextGadgetActiveOrJustFinished = anyTextGadgetActive();
434 static struct SetupKeyboardInfo custom_key;
442 { &custom_key.left, DEFAULT_KEY_LEFT, JOY_LEFT },
443 { &custom_key.right, DEFAULT_KEY_RIGHT, JOY_RIGHT },
444 { &custom_key.up, DEFAULT_KEY_UP, JOY_UP },
445 { &custom_key.down, DEFAULT_KEY_DOWN, JOY_DOWN },
446 { &custom_key.snap, DEFAULT_KEY_SNAP, JOY_BUTTON_1 },
447 { &custom_key.bomb, DEFAULT_KEY_BOMB, JOY_BUTTON_2 }
450 if (game_status == PLAYING)
454 for (pnr=0; pnr<MAX_PLAYERS; pnr++)
459 if (setup.input[pnr].use_joystick)
462 custom_key = setup.input[pnr].key;
465 if (key == *key_info[i].key_custom)
466 key_action |= key_info[i].action;
468 if (key_status == KEY_PRESSED)
469 stored_player[pnr].action |= key_action;
471 stored_player[pnr].action &= ~key_action;
479 if (key == key_info[i].key_default)
480 joy |= key_info[i].action;
485 if (key_status == KEY_PRESSED)
486 key_joystick_mapping |= joy;
488 key_joystick_mapping &= ~joy;
493 if (game_status != PLAYING)
494 key_joystick_mapping = 0;
496 if (key_status == KEY_RELEASED)
499 if ((key == KSYM_Return || key == KSYM_space) &&
500 game_status == PLAYING && AllPlayersGone)
502 CloseDoor(DOOR_CLOSE_1);
503 game_status = MAINMENU;
508 /* allow quick escape to the main menu with the Escape key */
509 if (key == KSYM_Escape &&
510 game_status != MAINMENU &&
511 game_status != LEVELED &&
512 game_status != CHOOSELEVEL &&
513 game_status != SETUP)
515 game_status = MAINMENU;
524 if (game_status == PLAYING && (tape.playing || tape.pausing))
531 HandleGadgetsKeyInput(key);
536 HandleTypeName(0, key);
546 if (game_status == MAINMENU)
547 HandleMainMenu(0,0, 0,0, MB_MENU_CHOICE);
548 else if (game_status == CHOOSELEVEL)
549 HandleChooseLevel(0,0, 0,0, MB_MENU_CHOICE);
550 else if (game_status == SETUP)
551 HandleSetupScreen(0,0, 0,0, MB_MENU_CHOICE);
555 if (game_status == CHOOSELEVEL)
556 HandleChooseLevel(0,0, 0,0, MB_MENU_LEAVE);
557 else if (game_status == SETUP)
558 HandleSetupScreen(0,0, 0,0, MB_MENU_LEAVE);
562 if (game_status == CHOOSELEVEL)
563 HandleChooseLevel(0,0, 0,-SCR_FIELDY, MB_MENU_MARK);
567 if (game_status == CHOOSELEVEL)
568 HandleChooseLevel(0,0, 0,SCR_FIELDY, MB_MENU_MARK);
583 HandleHelpScreen(MB_RELEASED);
591 game_status = MAINMENU;
597 HandleHallOfFame(0,0, 0,-SCR_FIELDY, MB_MENU_MARK);
601 HandleHallOfFame(0,0, 0,SCR_FIELDY, MB_MENU_MARK);
610 if (!anyTextGadgetActiveOrJustFinished || key == KSYM_Escape)
611 HandleLevelEditorKeyInput(key);
632 if (GameFrameDelay == 500)
633 GameFrameDelay = GAME_FRAME_DELAY;
635 GameFrameDelay = 500;
638 GameFrameDelay = (key - KSYM_0) * 10;
639 printf("Game speed == %d%% (%d ms delay between two frames)\n",
640 GAME_FRAME_DELAY * 100 / GameFrameDelay, GameFrameDelay);
646 options.debug = FALSE;
647 printf("debug mode disabled\n");
651 options.debug = TRUE;
652 printf("debug mode enabled\n");
657 if (!global.fps_slowdown)
659 global.fps_slowdown = TRUE;
660 global.fps_slowdown_factor = 2;
661 printf("fps slowdown enabled -- display only every 2nd frame\n");
663 else if (global.fps_slowdown_factor == 2)
665 global.fps_slowdown_factor = 4;
666 printf("fps slowdown enabled -- display only every 4th frame\n");
670 global.fps_slowdown = FALSE;
671 global.fps_slowdown_factor = 1;
672 printf("fps slowdown disabled\n");
678 if (ScrollStepSize == TILEX/8)
679 ScrollStepSize = TILEX/4;
681 ScrollStepSize = TILEX/8;
682 printf("ScrollStepSize == %d\n", ScrollStepSize);
691 ScrollStepSize = TILEX/4;
696 ScrollStepSize = TILEX/8;
698 printf("MoveSpeed == %d\n", MoveSpeed);
703 ScrollStepSize = TILEX/8;
704 printf("ScrollStepSize == %d (1/8)\n", ScrollStepSize);
708 ScrollStepSize = TILEX/4;
709 printf("ScrollStepSize == %d (1/4)\n", ScrollStepSize);
713 ScrollStepSize = TILEX/2;
714 printf("ScrollStepSize == %d (1/2)\n", ScrollStepSize);
718 ScrollStepSize = TILEX;
719 printf("ScrollStepSize == %d (1/1)\n", ScrollStepSize);
724 local_player->dynamite = 1000;
735 for(i=0; i<MAX_PLAYERS; i++)
737 printf("Player %d:\n", i);
738 printf(" jx == %d, jy == %d\n",
739 stored_player[i].jx, stored_player[i].jy);
740 printf(" last_jx == %d, last_jy == %d\n",
741 stored_player[i].last_jx, stored_player[i].last_jy);
762 if (button_status && game_status != PLAYING)
764 HandleButton(0, 0, -button_status);
768 #if defined(PLATFORM_UNIX)
776 static int HandleJoystickForAllPlayers()
781 for (i=0; i<MAX_PLAYERS; i++)
786 if (!setup.input[i].use_joystick)
790 joy_action = Joystick(i);
791 result |= joy_action;
794 if (!setup.input[i].use_joystick)
798 stored_player[i].action = joy_action;
804 void HandleJoystick()
806 int joystick = HandleJoystickForAllPlayers();
807 int keyboard = key_joystick_mapping;
808 int joy = (joystick | keyboard);
809 int left = joy & JOY_LEFT;
810 int right = joy & JOY_RIGHT;
811 int up = joy & JOY_UP;
812 int down = joy & JOY_DOWN;
813 int button = joy & JOY_BUTTON;
814 int newbutton = (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED);
815 int dx = (left ? -1 : right ? 1 : 0);
816 int dy = (up ? -1 : down ? 1 : 0);
824 static unsigned long joystickmove_delay = 0;
826 if (joystick && !button &&
827 !DelayReached(&joystickmove_delay, GADGET_FRAME_DELAY))
828 newbutton = dx = dy = 0;
830 if (game_status==MAINMENU)
831 HandleMainMenu(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
832 else if (game_status==CHOOSELEVEL)
833 HandleChooseLevel(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
834 else if (game_status==SETUP)
835 HandleSetupScreen(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
840 HandleHallOfFame(0,0, dx,dy, !newbutton);
844 HandleHelpScreen(!newbutton);
848 if (tape.playing || keyboard)
849 newbutton = ((joy & JOY_BUTTON) != 0);
851 if (AllPlayersGone && newbutton)
853 CloseDoor(DOOR_CLOSE_1);
854 game_status = MAINMENU;