1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-98 Artsoft Entertainment *
8 * phone: ++49 +521 290471 *
9 * email: aeglos@valinor.owl.de *
10 *----------------------------------------------------------*
12 ***********************************************************/
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 EventFilter(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)
52 if (PendingEvent()) /* got event */
58 if (EventFilter(&event))
62 case EVENT_BUTTONPRESS:
63 case EVENT_BUTTONRELEASE:
64 HandleButtonEvent((ButtonEvent *) &event);
67 case EVENT_MOTIONNOTIFY:
68 HandleMotionEvent((MotionEvent *) &event);
72 case EVENT_KEYRELEASE:
73 HandleKeyEvent((KeyEvent *) &event);
77 HandleOtherEvents(&event);
85 /* don't use all CPU time when idle; the main loop while playing
86 has its own synchronization and is CPU friendly, too */
88 if (game_status != PLAYING)
91 if (!PendingEvent()) /* delay only if no pending events */
95 /* refresh window contents from drawing buffer, if needed */
98 if (game_status == EXITGAME)
103 void HandleOtherEvents(Event *event)
108 HandleExposeEvent((ExposeEvent *) event);
111 case EVENT_UNMAPNOTIFY:
112 SleepWhileUnmapped();
117 HandleFocusEvent((FocusChangeEvent *) event);
120 case EVENT_CLIENTMESSAGE:
121 HandleClientMessageEvent((ClientMessageEvent *) event);
124 #ifdef USE_SDL_LIBRARY
125 case SDL_JOYAXISMOTION:
126 case SDL_JOYBUTTONDOWN:
127 case SDL_JOYBUTTONUP:
128 HandleJoystickEvent(event);
137 void ClearEventQueue()
139 while (PendingEvent())
147 case EVENT_BUTTONRELEASE:
148 button_status = MB_RELEASED;
151 case EVENT_KEYRELEASE:
152 key_joystick_mapping = 0;
156 HandleOtherEvents(&event);
162 void SleepWhileUnmapped()
164 boolean window_unmapped = TRUE;
166 KeyboardAutoRepeatOn();
168 while(window_unmapped)
176 case EVENT_BUTTONRELEASE:
177 button_status = MB_RELEASED;
180 case EVENT_KEYRELEASE:
181 key_joystick_mapping = 0;
184 case EVENT_MAPNOTIFY:
185 window_unmapped = FALSE;
188 case EVENT_UNMAPNOTIFY:
189 /* this is only to surely prevent the 'should not happen' case
190 * of recursively looping between 'SleepWhileUnmapped()' and
191 * 'HandleOtherEvents()' which usually calls this funtion.
196 HandleOtherEvents(&event);
201 if (game_status == PLAYING)
202 KeyboardAutoRepeatOff();
205 void HandleExposeEvent(ExposeEvent *event)
207 #ifndef USE_SDL_LIBRARY
208 int x = event->x, y = event->y;
209 int width = event->width, height = event->height;
211 if (setup.direct_draw && game_status==PLAYING)
214 int x1 = (x-SX)/TILEX, y1 = (y-SY)/TILEY;
215 int x2 = (x-SX+width)/TILEX, y2 = (y-SY+height)/TILEY;
217 SetDrawtoField(DRAW_BACKBUFFER);
219 for(xx=0; xx<SCR_FIELDX; xx++)
220 for(yy=0; yy<SCR_FIELDY; yy++)
221 if (xx>=x1 && xx<=x2 && yy>=y1 && yy<=y2)
222 DrawScreenField(xx,yy);
225 SetDrawtoField(DRAW_DIRECT);
228 if (setup.soft_scrolling && game_status == PLAYING)
230 int fx = FX, fy = FY;
232 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
233 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
235 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
238 BlitBitmap(drawto, window, x,y, width,height, x,y);
244 void HandleButtonEvent(ButtonEvent *event)
246 motion_status = FALSE;
248 if (event->type == EVENT_BUTTONPRESS)
249 button_status = event->button;
251 button_status = MB_RELEASED;
253 HandleButton(event->x, event->y, button_status);
256 void HandleMotionEvent(MotionEvent *event)
258 if (!PointerInWindow(window))
259 return; /* window and pointer are on different screens */
262 if (button_status == MB_RELEASED && game_status != LEVELED)
266 motion_status = TRUE;
268 HandleButton(event->x, event->y, button_status);
271 void HandleKeyEvent(KeyEvent *event)
273 int key_status = (event->type==EVENT_KEYPRESS ? KEY_PRESSED : KEY_RELEASED);
274 boolean with_modifiers = (game_status == PLAYING ? FALSE : TRUE);
275 Key key = GetEventKey(event, with_modifiers);
277 HandleKey(key, key_status);
280 void HandleFocusEvent(FocusChangeEvent *event)
282 static int old_joystick_status = -1;
284 if (event->type == EVENT_FOCUSOUT)
288 KeyboardAutoRepeatOn();
289 old_joystick_status = joystick_status;
290 joystick_status = JOYSTICK_OFF;
292 /* simulate key release events for still pressed keys */
293 key_joystick_mapping = 0;
294 for (i=0; i<MAX_PLAYERS; i++)
295 stored_player[i].action = 0;
297 else if (event->type == EVENT_FOCUSIN)
299 /* When there are two Rocks'n'Diamonds windows which overlap and
300 the player moves the pointer from one game window to the other,
301 a 'FocusOut' event is generated for the window the pointer is
302 leaving and a 'FocusIn' event is generated for the window the
303 pointer is entering. In some cases, it can happen that the
304 'FocusIn' event is handled by the one game process before the
305 'FocusOut' event by the other game process. In this case the
306 X11 environment would end up with activated keyboard auto repeat,
307 because unfortunately this is a global setting and not (which
308 would be far better) set for each X11 window individually.
309 The effect would be keyboard auto repeat while playing the game
310 (game_status == PLAYING), which is not desired.
311 To avoid this special case, we just wait 1/10 second before
312 processing the 'FocusIn' event.
315 if (game_status == PLAYING)
318 KeyboardAutoRepeatOff();
320 if (old_joystick_status != -1)
321 joystick_status = old_joystick_status;
325 void HandleClientMessageEvent(ClientMessageEvent *event)
327 #ifdef USE_SDL_LIBRARY
328 CloseAllAndExit(0); /* the only possible message here is SDL_QUIT */
331 if ((event->window == window) &&
332 (event->data.l[0] == XInternAtom(display, "WM_DELETE_WINDOW", FALSE)))
338 void HandleButton(int mx, int my, int button)
340 static int old_mx = 0, old_my = 0;
354 HandleGadgets(mx, my, button);
359 HandleMainMenu(mx,my, 0,0, button);
363 HandleTypeName(0, KEY_Return);
367 HandleChooseLevel(mx,my, 0,0, button);
371 HandleHallOfFame(0,0, 0,0, button);
378 HandleHelpScreen(button);
382 HandleSetupScreen(mx,my, 0,0, button);
386 HandleSetupInputScreen(mx,my, 0,0, button);
391 if (button == MB_RELEASED)
393 int sx = (mx - SX) / TILEX;
394 int sy = (my - SY) / TILEY;
396 if (IN_VIS_FIELD(sx,sy))
401 printf("INFO: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
403 if (!IN_LEV_FIELD(x, y))
406 printf(" Feld[%d][%d] == %d\n", x,y, Feld[x][y]);
407 printf(" Store[%d][%d] == %d\n", x,y, Store[x][y]);
408 printf(" Store2[%d][%d] == %d\n", x,y, Store2[x][y]);
409 printf(" StorePlayer[%d][%d] == %d\n", x,y, StorePlayer[x][y]);
410 printf(" MovPos[%d][%d] == %d\n", x,y, MovPos[x][y]);
411 printf(" MovDir[%d][%d] == %d\n", x,y, MovDir[x][y]);
412 printf(" MovDelay[%d][%d] == %d\n", x,y, MovDelay[x][y]);
424 void HandleKey(Key key, int key_status)
427 static struct SetupKeyboardInfo custom_key;
435 { &custom_key.left, DEFAULT_KEY_LEFT, JOY_LEFT },
436 { &custom_key.right, DEFAULT_KEY_RIGHT, JOY_RIGHT },
437 { &custom_key.up, DEFAULT_KEY_UP, JOY_UP },
438 { &custom_key.down, DEFAULT_KEY_DOWN, JOY_DOWN },
439 { &custom_key.snap, DEFAULT_KEY_SNAP, JOY_BUTTON_1 },
440 { &custom_key.bomb, DEFAULT_KEY_BOMB, JOY_BUTTON_2 }
443 if (game_status == PLAYING)
447 for (pnr=0; pnr<MAX_PLAYERS; pnr++)
452 if (setup.input[pnr].use_joystick)
455 custom_key = setup.input[pnr].key;
458 if (key == *key_info[i].key_custom)
459 key_action |= key_info[i].action;
461 if (key_status == KEY_PRESSED)
462 stored_player[pnr].action |= key_action;
464 stored_player[pnr].action &= ~key_action;
472 if (key == key_info[i].key_default)
473 joy |= key_info[i].action;
478 if (key_status == KEY_PRESSED)
479 key_joystick_mapping |= joy;
481 key_joystick_mapping &= ~joy;
486 if (game_status != PLAYING)
487 key_joystick_mapping = 0;
489 if (key_status == KEY_RELEASED)
492 if ((key == KEY_Return || key == KEY_space) &&
493 game_status == PLAYING && AllPlayersGone)
495 CloseDoor(DOOR_CLOSE_1);
496 game_status = MAINMENU;
501 /* allow quick escape to the main menu with the Escape key */
502 if (key == KEY_Escape && game_status != MAINMENU)
504 CloseDoor(DOOR_CLOSE_1 | DOOR_OPEN_2 | DOOR_NO_DELAY);
505 game_status = MAINMENU;
514 if (game_status == PLAYING && (tape.playing || tape.pausing))
521 HandleGadgetsKeyInput(key);
526 HandleTypeName(0, key);
537 if (game_status == MAINMENU)
538 HandleMainMenu(0,0, 0,0, MB_MENU_CHOICE);
539 else if (game_status == CHOOSELEVEL)
540 HandleChooseLevel(0,0, 0,0, MB_MENU_CHOICE);
541 else if (game_status == SETUP)
542 HandleSetupScreen(0,0, 0,0, MB_MENU_CHOICE);
543 else if (game_status == SETUPINPUT)
544 HandleSetupInputScreen(0,0, 0,0, MB_MENU_CHOICE);
548 if (game_status == CHOOSELEVEL)
549 HandleChooseLevel(0,0, 0,-SCR_FIELDY, MB_MENU_MARK);
553 if (game_status == CHOOSELEVEL)
554 HandleChooseLevel(0,0, 0,SCR_FIELDY, MB_MENU_MARK);
563 HandleHelpScreen(MB_RELEASED);
571 game_status = MAINMENU;
577 HandleHallOfFame(0,0, 0,-SCR_FIELDY, MB_MENU_MARK);
581 HandleHallOfFame(0,0, 0,SCR_FIELDY, MB_MENU_MARK);
590 HandleLevelEditorKeyInput(key);
611 if (GameFrameDelay == 500)
612 GameFrameDelay = GAME_FRAME_DELAY;
614 GameFrameDelay = 500;
617 GameFrameDelay = (key - KEY_0) * 10;
618 printf("Game speed == %d%% (%d ms delay between two frames)\n",
619 GAME_FRAME_DELAY * 100 / GameFrameDelay, GameFrameDelay);
625 if (ScrollStepSize == TILEX/8)
626 ScrollStepSize = TILEX/4;
628 ScrollStepSize = TILEX/8;
629 printf("ScrollStepSize == %d\n", ScrollStepSize);
638 ScrollStepSize = TILEX/4;
643 ScrollStepSize = TILEX/8;
645 printf("MoveSpeed == %d\n", MoveSpeed);
650 ScrollStepSize = TILEX/8;
651 printf("ScrollStepSize == %d (1/8)\n", ScrollStepSize);
655 ScrollStepSize = TILEX/4;
656 printf("ScrollStepSize == %d (1/4)\n", ScrollStepSize);
660 ScrollStepSize = TILEX/2;
661 printf("ScrollStepSize == %d (1/2)\n", ScrollStepSize);
665 ScrollStepSize = TILEX;
666 printf("ScrollStepSize == %d (1/1)\n", ScrollStepSize);
673 local_player->dynamite = 1000;
684 for(i=0; i<MAX_PLAYERS; i++)
686 printf("Player %d:\n", i);
687 printf(" jx == %d, jy == %d\n",
688 stored_player[i].jx, stored_player[i].jy);
689 printf(" last_jx == %d, last_jy == %d\n",
690 stored_player[i].last_jx, stored_player[i].last_jy);
709 void HandleNoXEvent()
711 if (button_status && game_status != PLAYING)
713 HandleButton(0, 0, -button_status);
724 if (game_status == PLAYING)
728 static int HandleJoystickForAllPlayers()
733 for (i=0; i<MAX_PLAYERS; i++)
738 if (!setup.input[i].use_joystick)
742 joy_action = Joystick(i);
743 result |= joy_action;
746 if (!setup.input[i].use_joystick)
750 stored_player[i].action = joy_action;
756 void HandleJoystick()
758 int joystick = HandleJoystickForAllPlayers();
759 int keyboard = key_joystick_mapping;
760 int joy = (joystick | keyboard);
761 int left = joy & JOY_LEFT;
762 int right = joy & JOY_RIGHT;
763 int up = joy & JOY_UP;
764 int down = joy & JOY_DOWN;
765 int button = joy & JOY_BUTTON;
766 int newbutton = (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED);
767 int dx = (left ? -1 : right ? 1 : 0);
768 int dy = (up ? -1 : down ? 1 : 0);
777 static unsigned long joystickmove_delay = 0;
779 if (joystick && !button &&
780 !DelayReached(&joystickmove_delay, GADGET_FRAME_DELAY))
781 newbutton = dx = dy = 0;
783 if (game_status==MAINMENU)
784 HandleMainMenu(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
785 else if (game_status==CHOOSELEVEL)
786 HandleChooseLevel(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
787 else if (game_status==SETUP)
788 HandleSetupScreen(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
789 else if (game_status==SETUPINPUT)
790 HandleSetupInputScreen(0,0,dx,dy,
791 newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
796 HandleHallOfFame(0,0, dx,dy, !newbutton);
800 HandleHelpScreen(!newbutton);
804 if (tape.playing || keyboard)
805 newbutton = ((joy & JOY_BUTTON) != 0);
807 if (AllPlayersGone && newbutton)
809 CloseDoor(DOOR_CLOSE_1);
810 game_status = MAINMENU;