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 (XPending(display)) /* got event from X server */
39 XNextEvent(display, &event);
45 HandleButtonEvent((XButtonEvent *) &event);
49 HandleMotionEvent((XMotionEvent *) &event);
54 HandleKeyEvent((XKeyEvent *) &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)
70 XSync(display, FALSE);
74 /* refresh window contents from drawing buffer, if needed */
77 if (game_status == EXITGAME)
82 void HandleOtherEvents(XEvent *event)
87 HandleExposeEvent((XExposeEvent *) event);
96 HandleFocusEvent((XFocusChangeEvent *) event);
100 HandleClientMessageEvent((XClientMessageEvent *) event);
108 void ClearEventQueue()
110 while(XPending(display))
114 XNextEvent(display, &event);
119 button_status = MB_RELEASED;
123 key_joystick_mapping = 0;
127 HandleOtherEvents(&event);
133 void SleepWhileUnmapped()
135 boolean window_unmapped = TRUE;
137 XAutoRepeatOn(display);
139 while(window_unmapped)
143 XNextEvent(display, &event);
148 button_status = MB_RELEASED;
152 key_joystick_mapping = 0;
156 window_unmapped = FALSE;
160 /* this is only to surely prevent the 'should not happen' case
161 * of recursively looping between 'SleepWhileUnmapped()' and
162 * 'HandleOtherEvents()' which usually calls this funtion.
167 HandleOtherEvents(&event);
172 if (game_status == PLAYING)
173 XAutoRepeatOff(display);
176 void HandleExposeEvent(XExposeEvent *event)
178 int x = event->x, y = event->y;
179 int width = event->width, height = event->height;
181 if (setup.direct_draw && game_status==PLAYING)
184 int x1 = (x-SX)/TILEX, y1 = (y-SY)/TILEY;
185 int x2 = (x-SX+width)/TILEX, y2 = (y-SY+height)/TILEY;
187 SetDrawtoField(DRAW_BACKBUFFER);
189 for(xx=0; xx<SCR_FIELDX; xx++)
190 for(yy=0; yy<SCR_FIELDY; yy++)
191 if (xx>=x1 && xx<=x2 && yy>=y1 && yy<=y2)
192 DrawScreenField(xx,yy);
195 SetDrawtoField(DRAW_DIRECT);
198 if (setup.soft_scrolling && game_status == PLAYING)
200 int fx = FX, fy = FY;
202 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
203 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
205 XCopyArea(display,fieldbuffer,backbuffer,gc,
206 fx,fy, SXSIZE,SYSIZE,
210 XCopyArea(display,drawto,window,gc, x,y, width,height, x,y);
215 void HandleButtonEvent(XButtonEvent *event)
217 motion_status = FALSE;
219 if (event->type == ButtonPress)
220 button_status = event->button;
222 button_status = MB_RELEASED;
224 HandleButton(event->x, event->y, button_status);
227 void HandleMotionEvent(XMotionEvent *event)
234 if (!XQueryPointer(display, window, &root, &child, &root_x, &root_y,
235 &win_x, &win_y, &mask))
238 if (!button_status && game_status != LEVELED)
241 motion_status = TRUE;
243 HandleButton(win_x, win_y, button_status);
246 void HandleKeyEvent(XKeyEvent *event)
248 int key_status = (event->type == KeyPress ? KEY_PRESSED : KEY_RELEASED);
251 if (game_status == PLAYING)
253 /* use '0' instead of 'event->state' to get the key without modifiers */
254 key = XLookupKeysym(event, 0);
258 /* get the key with all modifiers */
260 int buffer_size = 10;
261 XComposeStatus compose;
264 char_count = XLookupString(event, buffer, buffer_size, &key, &compose);
265 buffer[char_count] = '\0';
268 HandleKey(key, key_status);
271 void HandleFocusEvent(XFocusChangeEvent *event)
273 static int old_joystick_status = -1;
275 if (event->type == FocusOut)
279 XAutoRepeatOn(display);
280 old_joystick_status = joystick_status;
281 joystick_status = JOYSTICK_OFF;
283 /* simulate key release events for still pressed keys */
284 key_joystick_mapping = 0;
285 for (i=0; i<MAX_PLAYERS; i++)
286 stored_player[i].action = 0;
288 else if (event->type == FocusIn)
290 /* When there are two Rocks'n'Diamonds windows which overlap and
291 the player moves the pointer from one game window to the other,
292 a 'FocusOut' event is generated for the window the pointer is
293 leaving and a 'FocusIn' event is generated for the window the
294 pointer is entering. In some cases, it can happen that the
295 'FocusIn' event is handled by the one game process before the
296 'FocusOut' event by the other game process. In this case the
297 X11 environment would end up with activated keyboard auto repeat,
298 because unfortunately this is a global setting and not (which
299 would be far better) set for each X11 window individually.
300 The effect would be keyboard auto repeat while playing the game
301 (game_status == PLAYING), which is not desired.
302 To avoid this special case, we just wait 1/10 second before
303 processing the 'FocusIn' event.
306 if (game_status == PLAYING)
309 XAutoRepeatOff(display);
311 if (old_joystick_status != -1)
312 joystick_status = old_joystick_status;
316 void HandleClientMessageEvent(XClientMessageEvent *event)
319 if ((event->window == window) &&
320 (event->data.l[0] == XInternAtom(display, "WM_DELETE_WINDOW", FALSE)))
325 void HandleButton(int mx, int my, int button)
327 static int old_mx = 0, old_my = 0;
341 HandleGadgets(mx, my, button);
346 HandleMainMenu(mx,my, 0,0, button);
350 HandleTypeName(0, XK_Return);
354 HandleChooseLevel(mx,my, 0,0, button);
358 HandleHallOfFame(button);
365 HandleHelpScreen(button);
369 HandleSetupScreen(mx,my, 0,0, button);
373 HandleSetupInputScreen(mx,my, 0,0, button);
378 if (button == MB_RELEASED)
380 int sx = (mx - SX) / TILEX;
381 int sy = (my - SY) / TILEY;
383 if (IN_VIS_FIELD(sx,sy))
388 printf("INFO: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
390 if (!IN_LEV_FIELD(x, y))
393 printf(" Feld[%d][%d] == %d\n", x,y, Feld[x][y]);
394 printf(" Store[%d][%d] == %d\n", x,y, Store[x][y]);
395 printf(" Store2[%d][%d] == %d\n", x,y, Store2[x][y]);
396 printf(" StorePlayer[%d][%d] == %d\n", x,y, StorePlayer[x][y]);
397 printf(" MovPos[%d][%d] == %d\n", x,y, MovPos[x][y]);
398 printf(" MovDir[%d][%d] == %d\n", x,y, MovDir[x][y]);
399 printf(" MovDelay[%d][%d] == %d\n", x,y, MovDelay[x][y]);
411 void HandleKey(KeySym key, int key_status)
414 static struct SetupKeyboardInfo custom_key;
417 KeySym *keysym_custom;
418 KeySym keysym_default;
422 { &custom_key.left, DEFAULT_KEY_LEFT, JOY_LEFT },
423 { &custom_key.right, DEFAULT_KEY_RIGHT, JOY_RIGHT },
424 { &custom_key.up, DEFAULT_KEY_UP, JOY_UP },
425 { &custom_key.down, DEFAULT_KEY_DOWN, JOY_DOWN },
426 { &custom_key.snap, DEFAULT_KEY_SNAP, JOY_BUTTON_1 },
427 { &custom_key.bomb, DEFAULT_KEY_BOMB, JOY_BUTTON_2 }
430 if (game_status == PLAYING)
434 for (pnr=0; pnr<MAX_PLAYERS; pnr++)
439 if (setup.input[pnr].use_joystick)
442 custom_key = setup.input[pnr].key;
445 if (key == *key_info[i].keysym_custom)
446 key_action |= key_info[i].action;
448 if (key_status == KEY_PRESSED)
449 stored_player[pnr].action |= key_action;
451 stored_player[pnr].action &= ~key_action;
459 if (key == key_info[i].keysym_default)
460 joy |= key_info[i].action;
465 if (key_status == KEY_PRESSED)
466 key_joystick_mapping |= joy;
468 key_joystick_mapping &= ~joy;
473 if (game_status != PLAYING)
474 key_joystick_mapping = 0;
476 if (key_status == KEY_RELEASED)
479 if (key == XK_Return && 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);
522 if (game_status == MAINMENU)
523 HandleMainMenu(0,0, 0,0, MB_MENU_CHOICE);
524 else if (game_status == CHOOSELEVEL)
525 HandleChooseLevel(0,0, 0,0, MB_MENU_CHOICE);
526 else if (game_status == SETUP)
527 HandleSetupScreen(0,0, 0,0, MB_MENU_CHOICE);
528 else if (game_status == SETUPINPUT)
529 HandleSetupInputScreen(0,0, 0,0, MB_MENU_CHOICE);
538 HandleHelpScreen(MB_RELEASED);
545 game_status = MAINMENU;
556 HandleLevelEditorKeyInput(key);
577 if (GameFrameDelay == 500)
578 GameFrameDelay = GAME_FRAME_DELAY;
580 GameFrameDelay = 500;
583 GameFrameDelay = (key - XK_0) * 10;
584 printf("Game speed == %d%% (%d ms delay between two frames)\n",
585 GAME_FRAME_DELAY * 100 / GameFrameDelay, GameFrameDelay);
591 if (ScrollStepSize == TILEX/8)
592 ScrollStepSize = TILEX/4;
594 ScrollStepSize = TILEX/8;
595 printf("ScrollStepSize == %d\n", ScrollStepSize);
604 ScrollStepSize = TILEX/4;
609 ScrollStepSize = TILEX/8;
611 printf("MoveSpeed == %d\n", MoveSpeed);
616 ScrollStepSize = TILEX/8;
617 printf("ScrollStepSize == %d (1/8)\n", ScrollStepSize);
621 ScrollStepSize = TILEX/4;
622 printf("ScrollStepSize == %d (1/4)\n", ScrollStepSize);
626 ScrollStepSize = TILEX/2;
627 printf("ScrollStepSize == %d (1/2)\n", ScrollStepSize);
631 ScrollStepSize = TILEX;
632 printf("ScrollStepSize == %d (1/1)\n", ScrollStepSize);
639 local_player->dynamite = 1000;
650 for(i=0; i<MAX_PLAYERS; i++)
652 printf("Player %d:\n", i);
653 printf(" jx == %d, jy == %d\n",
654 stored_player[i].jx, stored_player[i].jy);
655 printf(" last_jx == %d, last_jy == %d\n",
656 stored_player[i].last_jx, stored_player[i].last_jy);
675 void HandleNoXEvent()
677 if (button_status && game_status != PLAYING)
679 HandleButton(0, 0, -button_status);
690 if (game_status == PLAYING)
694 static int HandleJoystickForAllPlayers()
699 for (i=0; i<MAX_PLAYERS; i++)
704 if (!setup.input[i].use_joystick)
708 joy_action = Joystick(i);
709 result |= joy_action;
712 if (!setup.input[i].use_joystick)
716 stored_player[i].action = joy_action;
722 void HandleJoystick()
724 int joystick = HandleJoystickForAllPlayers();
725 int keyboard = key_joystick_mapping;
726 int joy = (joystick | keyboard);
727 int left = joy & JOY_LEFT;
728 int right = joy & JOY_RIGHT;
729 int up = joy & JOY_UP;
730 int down = joy & JOY_DOWN;
731 int button = joy & JOY_BUTTON;
732 int newbutton = (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED);
733 int dx = (left ? -1 : right ? 1 : 0);
734 int dy = (up ? -1 : down ? 1 : 0);
743 static unsigned long joystickmove_delay = 0;
745 if (joystick && !button &&
746 !DelayReached(&joystickmove_delay, GADGET_FRAME_DELAY))
747 newbutton = dx = dy = 0;
749 if (game_status==MAINMENU)
750 HandleMainMenu(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
751 else if (game_status==CHOOSELEVEL)
752 HandleChooseLevel(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
753 else if (game_status==SETUP)
754 HandleSetupScreen(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
755 else if (game_status==SETUPINPUT)
756 HandleSetupInputScreen(0,0,dx,dy,
757 newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
762 HandleHallOfFame(!newbutton);
766 HandleHelpScreen(!newbutton);
770 if (tape.playing || keyboard)
771 newbutton = ((joy & JOY_BUTTON) != 0);
773 if (AllPlayersGone && newbutton)
775 CloseDoor(DOOR_CLOSE_1);
776 game_status = MAINMENU;