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 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)
52 if (PendingEvent()) /* got event */
58 if (FilterMouseMotionEvents(&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)
93 if (!PendingEvent()) /* delay only if no pending events */
97 /* refresh window contents from drawing buffer, if needed */
100 if (game_status == EXITGAME)
105 void HandleOtherEvents(Event *event)
110 HandleExposeEvent((ExposeEvent *) event);
113 case EVENT_UNMAPNOTIFY:
114 SleepWhileUnmapped();
119 HandleFocusEvent((FocusChangeEvent *) event);
122 case EVENT_CLIENTMESSAGE:
123 HandleClientMessageEvent((ClientMessageEvent *) event);
126 #ifdef USE_SDL_JOYSTICK
127 case SDL_JOYAXISMOTION:
128 case SDL_JOYBUTTONDOWN:
129 case SDL_JOYBUTTONUP:
130 HandleJoystickEvent(event);
139 void ClearEventQueue()
141 while (PendingEvent())
149 case EVENT_BUTTONRELEASE:
150 button_status = MB_RELEASED;
153 case EVENT_KEYRELEASE:
154 key_joystick_mapping = 0;
158 HandleOtherEvents(&event);
164 void SleepWhileUnmapped()
166 boolean window_unmapped = TRUE;
168 KeyboardAutoRepeatOn();
170 while(window_unmapped)
178 case EVENT_BUTTONRELEASE:
179 button_status = MB_RELEASED;
182 case EVENT_KEYRELEASE:
183 key_joystick_mapping = 0;
186 case EVENT_MAPNOTIFY:
187 window_unmapped = FALSE;
190 case EVENT_UNMAPNOTIFY:
191 /* this is only to surely prevent the 'should not happen' case
192 * of recursively looping between 'SleepWhileUnmapped()' and
193 * 'HandleOtherEvents()' which usually calls this funtion.
198 HandleOtherEvents(&event);
203 if (game_status == PLAYING)
204 KeyboardAutoRepeatOff();
207 void HandleExposeEvent(ExposeEvent *event)
210 int x = event->x, y = event->y;
211 int width = event->width, height = event->height;
213 if (setup.direct_draw && game_status==PLAYING)
216 int x1 = (x-SX)/TILEX, y1 = (y-SY)/TILEY;
217 int x2 = (x-SX+width)/TILEX, y2 = (y-SY+height)/TILEY;
219 SetDrawtoField(DRAW_BACKBUFFER);
221 for(xx=0; xx<SCR_FIELDX; xx++)
222 for(yy=0; yy<SCR_FIELDY; yy++)
223 if (xx>=x1 && xx<=x2 && yy>=y1 && yy<=y2)
224 DrawScreenField(xx,yy);
227 SetDrawtoField(DRAW_DIRECT);
230 if (setup.soft_scrolling && game_status == PLAYING)
232 int fx = FX, fy = FY;
234 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
235 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
237 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
240 BlitBitmap(drawto, window, x,y, width,height, x,y);
246 void HandleButtonEvent(ButtonEvent *event)
248 motion_status = FALSE;
250 if (event->type == EVENT_BUTTONPRESS)
251 button_status = event->button;
253 button_status = MB_RELEASED;
255 HandleButton(event->x, event->y, button_status);
258 void HandleMotionEvent(MotionEvent *event)
260 if (!PointerInWindow(window))
261 return; /* window and pointer are on different screens */
264 if (button_status == MB_RELEASED && game_status != LEVELED)
268 motion_status = TRUE;
270 HandleButton(event->x, event->y, button_status);
273 void HandleKeyEvent(KeyEvent *event)
275 int key_status = (event->type==EVENT_KEYPRESS ? KEY_PRESSED : KEY_RELEASED);
276 boolean with_modifiers = (game_status == PLAYING ? FALSE : TRUE);
277 Key key = GetEventKey(event, with_modifiers);
279 HandleKey(key, key_status);
282 void HandleFocusEvent(FocusChangeEvent *event)
284 static int old_joystick_status = -1;
286 if (event->type == EVENT_FOCUSOUT)
290 KeyboardAutoRepeatOn();
291 old_joystick_status = joystick_status;
292 joystick_status = JOYSTICK_OFF;
294 /* simulate key release events for still pressed keys */
295 key_joystick_mapping = 0;
296 for (i=0; i<MAX_PLAYERS; i++)
297 stored_player[i].action = 0;
299 else if (event->type == EVENT_FOCUSIN)
301 /* When there are two Rocks'n'Diamonds windows which overlap and
302 the player moves the pointer from one game window to the other,
303 a 'FocusOut' event is generated for the window the pointer is
304 leaving and a 'FocusIn' event is generated for the window the
305 pointer is entering. In some cases, it can happen that the
306 'FocusIn' event is handled by the one game process before the
307 'FocusOut' event by the other game process. In this case the
308 X11 environment would end up with activated keyboard auto repeat,
309 because unfortunately this is a global setting and not (which
310 would be far better) set for each X11 window individually.
311 The effect would be keyboard auto repeat while playing the game
312 (game_status == PLAYING), which is not desired.
313 To avoid this special case, we just wait 1/10 second before
314 processing the 'FocusIn' event.
317 if (game_status == PLAYING)
320 KeyboardAutoRepeatOff();
322 if (old_joystick_status != -1)
323 joystick_status = old_joystick_status;
327 void HandleClientMessageEvent(ClientMessageEvent *event)
329 if (CheckCloseWindowEvent(event))
333 void HandleButton(int mx, int my, int button)
335 static int old_mx = 0, old_my = 0;
349 HandleGadgets(mx, my, button);
354 HandleMainMenu(mx,my, 0,0, button);
358 HandleTypeName(0, KEY_Return);
362 HandleChooseLevel(mx,my, 0,0, button);
366 HandleHallOfFame(0,0, 0,0, button);
373 HandleHelpScreen(button);
377 HandleSetupScreen(mx,my, 0,0, button);
381 HandleSetupInputScreen(mx,my, 0,0, button);
386 if (button == MB_RELEASED)
388 int sx = (mx - SX) / TILEX;
389 int sy = (my - SY) / TILEY;
391 if (IN_VIS_FIELD(sx,sy))
396 printf("INFO: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
398 if (!IN_LEV_FIELD(x, y))
401 printf(" Feld[%d][%d] == %d\n", x,y, Feld[x][y]);
402 printf(" Store[%d][%d] == %d\n", x,y, Store[x][y]);
403 printf(" Store2[%d][%d] == %d\n", x,y, Store2[x][y]);
404 printf(" StorePlayer[%d][%d] == %d\n", x,y, StorePlayer[x][y]);
405 printf(" MovPos[%d][%d] == %d\n", x,y, MovPos[x][y]);
406 printf(" MovDir[%d][%d] == %d\n", x,y, MovDir[x][y]);
407 printf(" MovDelay[%d][%d] == %d\n", x,y, MovDelay[x][y]);
419 void HandleKey(Key key, int key_status)
422 boolean anyTextGadgetActiveOrJustFinished = anyTextGadgetActive();
423 static struct SetupKeyboardInfo custom_key;
431 { &custom_key.left, DEFAULT_KEY_LEFT, JOY_LEFT },
432 { &custom_key.right, DEFAULT_KEY_RIGHT, JOY_RIGHT },
433 { &custom_key.up, DEFAULT_KEY_UP, JOY_UP },
434 { &custom_key.down, DEFAULT_KEY_DOWN, JOY_DOWN },
435 { &custom_key.snap, DEFAULT_KEY_SNAP, JOY_BUTTON_1 },
436 { &custom_key.bomb, DEFAULT_KEY_BOMB, JOY_BUTTON_2 }
439 if (game_status == PLAYING)
443 for (pnr=0; pnr<MAX_PLAYERS; pnr++)
448 if (setup.input[pnr].use_joystick)
451 custom_key = setup.input[pnr].key;
454 if (key == *key_info[i].key_custom)
455 key_action |= key_info[i].action;
457 if (key_status == KEY_PRESSED)
458 stored_player[pnr].action |= key_action;
460 stored_player[pnr].action &= ~key_action;
468 if (key == key_info[i].key_default)
469 joy |= key_info[i].action;
474 if (key_status == KEY_PRESSED)
475 key_joystick_mapping |= joy;
477 key_joystick_mapping &= ~joy;
482 if (game_status != PLAYING)
483 key_joystick_mapping = 0;
485 if (key_status == KEY_RELEASED)
488 if ((key == KEY_Return || key == KEY_space) &&
489 game_status == PLAYING && AllPlayersGone)
491 CloseDoor(DOOR_CLOSE_1);
492 game_status = MAINMENU;
497 /* allow quick escape to the main menu with the Escape key */
498 if (key == KEY_Escape && game_status != MAINMENU)
500 CloseDoor(DOOR_CLOSE_1 | DOOR_OPEN_2 | DOOR_NO_DELAY);
501 game_status = MAINMENU;
510 if (game_status == PLAYING && (tape.playing || tape.pausing))
517 HandleGadgetsKeyInput(key);
522 HandleTypeName(0, key);
533 if (game_status == MAINMENU)
534 HandleMainMenu(0,0, 0,0, MB_MENU_CHOICE);
535 else if (game_status == CHOOSELEVEL)
536 HandleChooseLevel(0,0, 0,0, MB_MENU_CHOICE);
537 else if (game_status == SETUP)
538 HandleSetupScreen(0,0, 0,0, MB_MENU_CHOICE);
539 else if (game_status == SETUPINPUT)
540 HandleSetupInputScreen(0,0, 0,0, MB_MENU_CHOICE);
544 if (game_status == CHOOSELEVEL)
545 HandleChooseLevel(0,0, 0,-SCR_FIELDY, MB_MENU_MARK);
549 if (game_status == CHOOSELEVEL)
550 HandleChooseLevel(0,0, 0,SCR_FIELDY, MB_MENU_MARK);
559 HandleHelpScreen(MB_RELEASED);
567 game_status = MAINMENU;
573 HandleHallOfFame(0,0, 0,-SCR_FIELDY, MB_MENU_MARK);
577 HandleHallOfFame(0,0, 0,SCR_FIELDY, MB_MENU_MARK);
586 if (!anyTextGadgetActiveOrJustFinished)
587 HandleLevelEditorKeyInput(key);
608 if (GameFrameDelay == 500)
609 GameFrameDelay = GAME_FRAME_DELAY;
611 GameFrameDelay = 500;
614 GameFrameDelay = (key - KEY_0) * 10;
615 printf("Game speed == %d%% (%d ms delay between two frames)\n",
616 GAME_FRAME_DELAY * 100 / GameFrameDelay, GameFrameDelay);
622 options.debug = FALSE;
623 printf("debug mode disabled\n");
627 options.debug = TRUE;
628 printf("debug mode enabled\n");
633 if (!global.fps_slowdown)
635 global.fps_slowdown = TRUE;
636 global.fps_slowdown_factor = 2;
637 printf("fps slowdown enabled -- display only every 2nd frame\n");
639 else if (global.fps_slowdown_factor == 2)
641 global.fps_slowdown_factor = 4;
642 printf("fps slowdown enabled -- display only every 4th frame\n");
646 global.fps_slowdown = FALSE;
647 global.fps_slowdown_factor = 1;
648 printf("fps slowdown disabled\n");
654 if (ScrollStepSize == TILEX/8)
655 ScrollStepSize = TILEX/4;
657 ScrollStepSize = TILEX/8;
658 printf("ScrollStepSize == %d\n", ScrollStepSize);
667 ScrollStepSize = TILEX/4;
672 ScrollStepSize = TILEX/8;
674 printf("MoveSpeed == %d\n", MoveSpeed);
679 ScrollStepSize = TILEX/8;
680 printf("ScrollStepSize == %d (1/8)\n", ScrollStepSize);
684 ScrollStepSize = TILEX/4;
685 printf("ScrollStepSize == %d (1/4)\n", ScrollStepSize);
689 ScrollStepSize = TILEX/2;
690 printf("ScrollStepSize == %d (1/2)\n", ScrollStepSize);
694 ScrollStepSize = TILEX;
695 printf("ScrollStepSize == %d (1/1)\n", ScrollStepSize);
699 local_player->dynamite = 1000;
710 for(i=0; i<MAX_PLAYERS; i++)
712 printf("Player %d:\n", i);
713 printf(" jx == %d, jy == %d\n",
714 stored_player[i].jx, stored_player[i].jy);
715 printf(" last_jx == %d, last_jy == %d\n",
716 stored_player[i].last_jx, stored_player[i].last_jy);
737 if (button_status && game_status != PLAYING)
739 HandleButton(0, 0, -button_status);
743 #if !defined(MSDOS) && !defined(WIN32)
751 static int HandleJoystickForAllPlayers()
756 for (i=0; i<MAX_PLAYERS; i++)
761 if (!setup.input[i].use_joystick)
765 joy_action = Joystick(i);
766 result |= joy_action;
769 if (!setup.input[i].use_joystick)
773 stored_player[i].action = joy_action;
779 void HandleJoystick()
781 int joystick = HandleJoystickForAllPlayers();
782 int keyboard = key_joystick_mapping;
783 int joy = (joystick | keyboard);
784 int left = joy & JOY_LEFT;
785 int right = joy & JOY_RIGHT;
786 int up = joy & JOY_UP;
787 int down = joy & JOY_DOWN;
788 int button = joy & JOY_BUTTON;
789 int newbutton = (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED);
790 int dx = (left ? -1 : right ? 1 : 0);
791 int dy = (up ? -1 : down ? 1 : 0);
800 static unsigned long joystickmove_delay = 0;
802 if (joystick && !button &&
803 !DelayReached(&joystickmove_delay, GADGET_FRAME_DELAY))
804 newbutton = dx = dy = 0;
806 if (game_status==MAINMENU)
807 HandleMainMenu(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
808 else if (game_status==CHOOSELEVEL)
809 HandleChooseLevel(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
810 else if (game_status==SETUP)
811 HandleSetupScreen(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
812 else if (game_status==SETUPINPUT)
813 HandleSetupInputScreen(0,0,dx,dy,
814 newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
819 HandleHallOfFame(0,0, dx,dy, !newbutton);
823 HandleHelpScreen(!newbutton);
827 if (tape.playing || keyboard)
828 newbutton = ((joy & JOY_BUTTON) != 0);
830 if (AllPlayersGone && newbutton)
832 CloseDoor(DOOR_CLOSE_1);
833 game_status = MAINMENU;