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
35 if (PendingEvent()) /* got event */
43 case EVENT_BUTTONPRESS:
44 case EVENT_BUTTONRELEASE:
45 HandleButtonEvent((ButtonEvent *) &event);
48 case EVENT_MOTIONNOTIFY:
49 HandleMotionEvent((MotionEvent *) &event);
53 case EVENT_KEYRELEASE:
54 HandleKeyEvent((KeyEvent *) &event);
58 HandleOtherEvents(&event);
65 /* don't use all CPU time when idle; the main loop while playing
66 has its own synchronization and is CPU friendly, too */
68 if (game_status != PLAYING)
71 if (!PendingEvent()) /* delay only if no pending events */
75 /* refresh window contents from drawing buffer, if needed */
78 if (game_status == EXITGAME)
83 void HandleOtherEvents(Event *event)
88 HandleExposeEvent((ExposeEvent *) event);
91 case EVENT_UNMAPNOTIFY:
97 HandleFocusEvent((FocusChangeEvent *) event);
100 case EVENT_CLIENTMESSAGE:
101 HandleClientMessageEvent((ClientMessageEvent *) event);
109 void ClearEventQueue()
111 while (PendingEvent())
119 case EVENT_BUTTONRELEASE:
120 button_status = MB_RELEASED;
123 case EVENT_KEYRELEASE:
124 key_joystick_mapping = 0;
128 HandleOtherEvents(&event);
134 void SleepWhileUnmapped()
136 boolean window_unmapped = TRUE;
138 KeyboardAutoRepeatOn();
140 while(window_unmapped)
148 case EVENT_BUTTONRELEASE:
149 button_status = MB_RELEASED;
152 case EVENT_KEYRELEASE:
153 key_joystick_mapping = 0;
156 case EVENT_MAPNOTIFY:
157 window_unmapped = FALSE;
160 case EVENT_UNMAPNOTIFY:
161 /* this is only to surely prevent the 'should not happen' case
162 * of recursively looping between 'SleepWhileUnmapped()' and
163 * 'HandleOtherEvents()' which usually calls this funtion.
168 HandleOtherEvents(&event);
173 if (game_status == PLAYING)
174 KeyboardAutoRepeatOff();
177 void HandleExposeEvent(ExposeEvent *event)
179 int x = event->x, y = event->y;
180 int width = event->width, height = event->height;
182 if (setup.direct_draw && game_status==PLAYING)
185 int x1 = (x-SX)/TILEX, y1 = (y-SY)/TILEY;
186 int x2 = (x-SX+width)/TILEX, y2 = (y-SY+height)/TILEY;
188 SetDrawtoField(DRAW_BACKBUFFER);
190 for(xx=0; xx<SCR_FIELDX; xx++)
191 for(yy=0; yy<SCR_FIELDY; yy++)
192 if (xx>=x1 && xx<=x2 && yy>=y1 && yy<=y2)
193 DrawScreenField(xx,yy);
196 SetDrawtoField(DRAW_DIRECT);
199 if (setup.soft_scrolling && game_status == PLAYING)
201 int fx = FX, fy = FY;
203 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
204 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
206 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
209 BlitBitmap(drawto, window, x,y, width,height, x,y);
214 void HandleButtonEvent(ButtonEvent *event)
216 motion_status = FALSE;
218 if (event->type == EVENT_BUTTONPRESS)
219 button_status = event->button;
221 button_status = MB_RELEASED;
223 HandleButton(event->x, event->y, button_status);
226 void HandleMotionEvent(MotionEvent *event)
230 if (!QueryPointer(window, &win_x, &win_y))
231 return; /* window and pointer are on different screens */
233 if (!button_status && game_status != LEVELED)
236 motion_status = TRUE;
238 HandleButton(win_x, win_y, button_status);
241 void HandleKeyEvent(KeyEvent *event)
243 int key_status = (event->type==EVENT_KEYPRESS ? KEY_PRESSED : KEY_RELEASED);
246 if (game_status == PLAYING)
248 /* use '0' instead of 'event->state' to get the key without modifiers */
249 key = XLookupKeysym(event, 0);
253 /* get the key with all modifiers */
255 int buffer_size = 10;
256 XComposeStatus compose;
259 char_count = XLookupString(event, buffer, buffer_size, &key, &compose);
260 buffer[char_count] = '\0';
263 HandleKey(key, key_status);
266 void HandleFocusEvent(FocusChangeEvent *event)
268 static int old_joystick_status = -1;
270 if (event->type == EVENT_FOCUSOUT)
274 KeyboardAutoRepeatOn();
275 old_joystick_status = joystick_status;
276 joystick_status = JOYSTICK_OFF;
278 /* simulate key release events for still pressed keys */
279 key_joystick_mapping = 0;
280 for (i=0; i<MAX_PLAYERS; i++)
281 stored_player[i].action = 0;
283 else if (event->type == EVENT_FOCUSIN)
285 /* When there are two Rocks'n'Diamonds windows which overlap and
286 the player moves the pointer from one game window to the other,
287 a 'FocusOut' event is generated for the window the pointer is
288 leaving and a 'FocusIn' event is generated for the window the
289 pointer is entering. In some cases, it can happen that the
290 'FocusIn' event is handled by the one game process before the
291 'FocusOut' event by the other game process. In this case the
292 X11 environment would end up with activated keyboard auto repeat,
293 because unfortunately this is a global setting and not (which
294 would be far better) set for each X11 window individually.
295 The effect would be keyboard auto repeat while playing the game
296 (game_status == PLAYING), which is not desired.
297 To avoid this special case, we just wait 1/10 second before
298 processing the 'FocusIn' event.
301 if (game_status == PLAYING)
304 KeyboardAutoRepeatOff();
306 if (old_joystick_status != -1)
307 joystick_status = old_joystick_status;
311 void HandleClientMessageEvent(ClientMessageEvent *event)
313 #ifdef USE_SDL_LIBRARY
314 CloseAllAndExit(0); /* the only possible message here is SDL_QUIT */
317 if ((event->window == window) &&
318 (event->data.l[0] == XInternAtom(display, "WM_DELETE_WINDOW", FALSE)))
324 void HandleButton(int mx, int my, int button)
326 static int old_mx = 0, old_my = 0;
340 HandleGadgets(mx, my, button);
345 HandleMainMenu(mx,my, 0,0, button);
349 HandleTypeName(0, XK_Return);
353 HandleChooseLevel(mx,my, 0,0, button);
357 HandleHallOfFame(0,0, 0,0, button);
364 HandleHelpScreen(button);
368 HandleSetupScreen(mx,my, 0,0, button);
372 HandleSetupInputScreen(mx,my, 0,0, button);
377 if (button == MB_RELEASED)
379 int sx = (mx - SX) / TILEX;
380 int sy = (my - SY) / TILEY;
382 if (IN_VIS_FIELD(sx,sy))
387 printf("INFO: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
389 if (!IN_LEV_FIELD(x, y))
392 printf(" Feld[%d][%d] == %d\n", x,y, Feld[x][y]);
393 printf(" Store[%d][%d] == %d\n", x,y, Store[x][y]);
394 printf(" Store2[%d][%d] == %d\n", x,y, Store2[x][y]);
395 printf(" StorePlayer[%d][%d] == %d\n", x,y, StorePlayer[x][y]);
396 printf(" MovPos[%d][%d] == %d\n", x,y, MovPos[x][y]);
397 printf(" MovDir[%d][%d] == %d\n", x,y, MovDir[x][y]);
398 printf(" MovDelay[%d][%d] == %d\n", x,y, MovDelay[x][y]);
410 void HandleKey(KeySym key, int key_status)
413 static struct SetupKeyboardInfo custom_key;
416 KeySym *keysym_custom;
417 KeySym keysym_default;
421 { &custom_key.left, DEFAULT_KEY_LEFT, JOY_LEFT },
422 { &custom_key.right, DEFAULT_KEY_RIGHT, JOY_RIGHT },
423 { &custom_key.up, DEFAULT_KEY_UP, JOY_UP },
424 { &custom_key.down, DEFAULT_KEY_DOWN, JOY_DOWN },
425 { &custom_key.snap, DEFAULT_KEY_SNAP, JOY_BUTTON_1 },
426 { &custom_key.bomb, DEFAULT_KEY_BOMB, JOY_BUTTON_2 }
429 if (game_status == PLAYING)
433 for (pnr=0; pnr<MAX_PLAYERS; pnr++)
438 if (setup.input[pnr].use_joystick)
441 custom_key = setup.input[pnr].key;
444 if (key == *key_info[i].keysym_custom)
445 key_action |= key_info[i].action;
447 if (key_status == KEY_PRESSED)
448 stored_player[pnr].action |= key_action;
450 stored_player[pnr].action &= ~key_action;
458 if (key == key_info[i].keysym_default)
459 joy |= key_info[i].action;
464 if (key_status == KEY_PRESSED)
465 key_joystick_mapping |= joy;
467 key_joystick_mapping &= ~joy;
472 if (game_status != PLAYING)
473 key_joystick_mapping = 0;
475 if (key_status == KEY_RELEASED)
478 if ((key == XK_Return || key == XK_space) &&
479 game_status == PLAYING && AllPlayersGone)
481 CloseDoor(DOOR_CLOSE_1);
482 game_status = MAINMENU;
487 /* allow quick escape to the main menu with the Escape key */
488 if (key == XK_Escape && game_status != MAINMENU)
490 CloseDoor(DOOR_CLOSE_1 | DOOR_OPEN_2 | DOOR_NO_DELAY);
491 game_status = MAINMENU;
500 if (game_status == PLAYING && (tape.playing || tape.pausing))
507 HandleGadgetsKeyInput(key);
512 HandleTypeName(0, key);
523 if (game_status == MAINMENU)
524 HandleMainMenu(0,0, 0,0, MB_MENU_CHOICE);
525 else if (game_status == CHOOSELEVEL)
526 HandleChooseLevel(0,0, 0,0, MB_MENU_CHOICE);
527 else if (game_status == SETUP)
528 HandleSetupScreen(0,0, 0,0, MB_MENU_CHOICE);
529 else if (game_status == SETUPINPUT)
530 HandleSetupInputScreen(0,0, 0,0, MB_MENU_CHOICE);
534 if (game_status == CHOOSELEVEL)
535 HandleChooseLevel(0,0, 0,-SCR_FIELDY, MB_MENU_MARK);
539 if (game_status == CHOOSELEVEL)
540 HandleChooseLevel(0,0, 0,SCR_FIELDY, MB_MENU_MARK);
549 HandleHelpScreen(MB_RELEASED);
557 game_status = MAINMENU;
563 HandleHallOfFame(0,0, 0,-SCR_FIELDY, MB_MENU_MARK);
567 HandleHallOfFame(0,0, 0,SCR_FIELDY, MB_MENU_MARK);
576 HandleLevelEditorKeyInput(key);
597 if (GameFrameDelay == 500)
598 GameFrameDelay = GAME_FRAME_DELAY;
600 GameFrameDelay = 500;
603 GameFrameDelay = (key - XK_0) * 10;
604 printf("Game speed == %d%% (%d ms delay between two frames)\n",
605 GAME_FRAME_DELAY * 100 / GameFrameDelay, GameFrameDelay);
611 if (ScrollStepSize == TILEX/8)
612 ScrollStepSize = TILEX/4;
614 ScrollStepSize = TILEX/8;
615 printf("ScrollStepSize == %d\n", ScrollStepSize);
624 ScrollStepSize = TILEX/4;
629 ScrollStepSize = TILEX/8;
631 printf("MoveSpeed == %d\n", MoveSpeed);
636 ScrollStepSize = TILEX/8;
637 printf("ScrollStepSize == %d (1/8)\n", ScrollStepSize);
641 ScrollStepSize = TILEX/4;
642 printf("ScrollStepSize == %d (1/4)\n", ScrollStepSize);
646 ScrollStepSize = TILEX/2;
647 printf("ScrollStepSize == %d (1/2)\n", ScrollStepSize);
651 ScrollStepSize = TILEX;
652 printf("ScrollStepSize == %d (1/1)\n", ScrollStepSize);
659 local_player->dynamite = 1000;
670 for(i=0; i<MAX_PLAYERS; i++)
672 printf("Player %d:\n", i);
673 printf(" jx == %d, jy == %d\n",
674 stored_player[i].jx, stored_player[i].jy);
675 printf(" last_jx == %d, last_jy == %d\n",
676 stored_player[i].last_jx, stored_player[i].last_jy);
695 void HandleNoXEvent()
697 if (button_status && game_status != PLAYING)
699 HandleButton(0, 0, -button_status);
710 if (game_status == PLAYING)
714 static int HandleJoystickForAllPlayers()
719 for (i=0; i<MAX_PLAYERS; i++)
724 if (!setup.input[i].use_joystick)
728 joy_action = Joystick(i);
729 result |= joy_action;
732 if (!setup.input[i].use_joystick)
736 stored_player[i].action = joy_action;
742 void HandleJoystick()
744 int joystick = HandleJoystickForAllPlayers();
745 int keyboard = key_joystick_mapping;
746 int joy = (joystick | keyboard);
747 int left = joy & JOY_LEFT;
748 int right = joy & JOY_RIGHT;
749 int up = joy & JOY_UP;
750 int down = joy & JOY_DOWN;
751 int button = joy & JOY_BUTTON;
752 int newbutton = (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED);
753 int dx = (left ? -1 : right ? 1 : 0);
754 int dy = (up ? -1 : down ? 1 : 0);
763 static unsigned long joystickmove_delay = 0;
765 if (joystick && !button &&
766 !DelayReached(&joystickmove_delay, GADGET_FRAME_DELAY))
767 newbutton = dx = dy = 0;
769 if (game_status==MAINMENU)
770 HandleMainMenu(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
771 else if (game_status==CHOOSELEVEL)
772 HandleChooseLevel(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
773 else if (game_status==SETUP)
774 HandleSetupScreen(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
775 else if (game_status==SETUPINPUT)
776 HandleSetupInputScreen(0,0,dx,dy,
777 newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
782 HandleHallOfFame(0,0, dx,dy, !newbutton);
786 HandleHelpScreen(!newbutton);
790 if (tape.playing || keyboard)
791 newbutton = ((joy & JOY_BUTTON) != 0);
793 if (AllPlayersGone && newbutton)
795 CloseDoor(DOOR_CLOSE_1);
796 game_status = MAINMENU;