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);
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 &&
514 game_status != MAINMENU && game_status != LEVELED)
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);
580 HandleHelpScreen(MB_RELEASED);
588 game_status = MAINMENU;
594 HandleHallOfFame(0,0, 0,-SCR_FIELDY, MB_MENU_MARK);
598 HandleHallOfFame(0,0, 0,SCR_FIELDY, MB_MENU_MARK);
607 if (!anyTextGadgetActiveOrJustFinished || key == KSYM_Escape)
608 HandleLevelEditorKeyInput(key);
629 if (GameFrameDelay == 500)
630 GameFrameDelay = GAME_FRAME_DELAY;
632 GameFrameDelay = 500;
635 GameFrameDelay = (key - KSYM_0) * 10;
636 printf("Game speed == %d%% (%d ms delay between two frames)\n",
637 GAME_FRAME_DELAY * 100 / GameFrameDelay, GameFrameDelay);
643 options.debug = FALSE;
644 printf("debug mode disabled\n");
648 options.debug = TRUE;
649 printf("debug mode enabled\n");
654 if (!global.fps_slowdown)
656 global.fps_slowdown = TRUE;
657 global.fps_slowdown_factor = 2;
658 printf("fps slowdown enabled -- display only every 2nd frame\n");
660 else if (global.fps_slowdown_factor == 2)
662 global.fps_slowdown_factor = 4;
663 printf("fps slowdown enabled -- display only every 4th frame\n");
667 global.fps_slowdown = FALSE;
668 global.fps_slowdown_factor = 1;
669 printf("fps slowdown disabled\n");
675 if (ScrollStepSize == TILEX/8)
676 ScrollStepSize = TILEX/4;
678 ScrollStepSize = TILEX/8;
679 printf("ScrollStepSize == %d\n", ScrollStepSize);
688 ScrollStepSize = TILEX/4;
693 ScrollStepSize = TILEX/8;
695 printf("MoveSpeed == %d\n", MoveSpeed);
700 ScrollStepSize = TILEX/8;
701 printf("ScrollStepSize == %d (1/8)\n", ScrollStepSize);
705 ScrollStepSize = TILEX/4;
706 printf("ScrollStepSize == %d (1/4)\n", ScrollStepSize);
710 ScrollStepSize = TILEX/2;
711 printf("ScrollStepSize == %d (1/2)\n", ScrollStepSize);
715 ScrollStepSize = TILEX;
716 printf("ScrollStepSize == %d (1/1)\n", ScrollStepSize);
721 local_player->dynamite = 1000;
732 for(i=0; i<MAX_PLAYERS; i++)
734 printf("Player %d:\n", i);
735 printf(" jx == %d, jy == %d\n",
736 stored_player[i].jx, stored_player[i].jy);
737 printf(" last_jx == %d, last_jy == %d\n",
738 stored_player[i].last_jx, stored_player[i].last_jy);
759 if (button_status && game_status != PLAYING)
761 HandleButton(0, 0, -button_status);
765 #if defined(PLATFORM_UNIX)
773 static int HandleJoystickForAllPlayers()
778 for (i=0; i<MAX_PLAYERS; i++)
783 if (!setup.input[i].use_joystick)
787 joy_action = Joystick(i);
788 result |= joy_action;
791 if (!setup.input[i].use_joystick)
795 stored_player[i].action = joy_action;
801 void HandleJoystick()
803 int joystick = HandleJoystickForAllPlayers();
804 int keyboard = key_joystick_mapping;
805 int joy = (joystick | keyboard);
806 int left = joy & JOY_LEFT;
807 int right = joy & JOY_RIGHT;
808 int up = joy & JOY_UP;
809 int down = joy & JOY_DOWN;
810 int button = joy & JOY_BUTTON;
811 int newbutton = (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED);
812 int dx = (left ? -1 : right ? 1 : 0);
813 int dy = (up ? -1 : down ? 1 : 0);
822 static unsigned long joystickmove_delay = 0;
824 if (joystick && !button &&
825 !DelayReached(&joystickmove_delay, GADGET_FRAME_DELAY))
826 newbutton = dx = dy = 0;
828 if (game_status==MAINMENU)
829 HandleMainMenu(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
830 else if (game_status==CHOOSELEVEL)
831 HandleChooseLevel(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
832 else if (game_status==SETUP)
833 HandleSetupScreen(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
834 else if (game_status==SETUPINPUT)
835 HandleSetupInputScreen(0,0,dx,dy,
836 newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
841 HandleHallOfFame(0,0, dx,dy, !newbutton);
845 HandleHelpScreen(!newbutton);
849 if (tape.playing || keyboard)
850 newbutton = ((joy & JOY_BUTTON) != 0);
852 if (AllPlayersGone && newbutton)
854 CloseDoor(DOOR_CLOSE_1);
855 game_status = MAINMENU;