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)
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)
209 #ifndef USE_SDL_LIBRARY
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 #ifdef USE_SDL_LIBRARY
330 CloseAllAndExit(0); /* the only possible message here is SDL_QUIT */
333 if ((event->window == window) &&
334 (event->data.l[0] == XInternAtom(display, "WM_DELETE_WINDOW", FALSE)))
340 void HandleButton(int mx, int my, int button)
342 static int old_mx = 0, old_my = 0;
356 HandleGadgets(mx, my, button);
361 HandleMainMenu(mx,my, 0,0, button);
365 HandleTypeName(0, KEY_Return);
369 HandleChooseLevel(mx,my, 0,0, button);
373 HandleHallOfFame(0,0, 0,0, button);
380 HandleHelpScreen(button);
384 HandleSetupScreen(mx,my, 0,0, button);
388 HandleSetupInputScreen(mx,my, 0,0, button);
393 if (button == MB_RELEASED)
395 int sx = (mx - SX) / TILEX;
396 int sy = (my - SY) / TILEY;
398 if (IN_VIS_FIELD(sx,sy))
403 printf("INFO: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
405 if (!IN_LEV_FIELD(x, y))
408 printf(" Feld[%d][%d] == %d\n", x,y, Feld[x][y]);
409 printf(" Store[%d][%d] == %d\n", x,y, Store[x][y]);
410 printf(" Store2[%d][%d] == %d\n", x,y, Store2[x][y]);
411 printf(" StorePlayer[%d][%d] == %d\n", x,y, StorePlayer[x][y]);
412 printf(" MovPos[%d][%d] == %d\n", x,y, MovPos[x][y]);
413 printf(" MovDir[%d][%d] == %d\n", x,y, MovDir[x][y]);
414 printf(" MovDelay[%d][%d] == %d\n", x,y, MovDelay[x][y]);
426 void HandleKey(Key key, int key_status)
429 static struct SetupKeyboardInfo custom_key;
437 { &custom_key.left, DEFAULT_KEY_LEFT, JOY_LEFT },
438 { &custom_key.right, DEFAULT_KEY_RIGHT, JOY_RIGHT },
439 { &custom_key.up, DEFAULT_KEY_UP, JOY_UP },
440 { &custom_key.down, DEFAULT_KEY_DOWN, JOY_DOWN },
441 { &custom_key.snap, DEFAULT_KEY_SNAP, JOY_BUTTON_1 },
442 { &custom_key.bomb, DEFAULT_KEY_BOMB, JOY_BUTTON_2 }
445 if (game_status == PLAYING)
449 for (pnr=0; pnr<MAX_PLAYERS; pnr++)
454 if (setup.input[pnr].use_joystick)
457 custom_key = setup.input[pnr].key;
460 if (key == *key_info[i].key_custom)
461 key_action |= key_info[i].action;
463 if (key_status == KEY_PRESSED)
464 stored_player[pnr].action |= key_action;
466 stored_player[pnr].action &= ~key_action;
474 if (key == key_info[i].key_default)
475 joy |= key_info[i].action;
480 if (key_status == KEY_PRESSED)
481 key_joystick_mapping |= joy;
483 key_joystick_mapping &= ~joy;
488 if (game_status != PLAYING)
489 key_joystick_mapping = 0;
491 if (key_status == KEY_RELEASED)
494 if ((key == KEY_Return || key == KEY_space) &&
495 game_status == PLAYING && AllPlayersGone)
497 CloseDoor(DOOR_CLOSE_1);
498 game_status = MAINMENU;
503 /* allow quick escape to the main menu with the Escape key */
504 if (key == KEY_Escape && game_status != MAINMENU)
506 CloseDoor(DOOR_CLOSE_1 | DOOR_OPEN_2 | DOOR_NO_DELAY);
507 game_status = MAINMENU;
516 if (game_status == PLAYING && (tape.playing || tape.pausing))
523 HandleGadgetsKeyInput(key);
528 HandleTypeName(0, key);
539 if (game_status == MAINMENU)
540 HandleMainMenu(0,0, 0,0, MB_MENU_CHOICE);
541 else if (game_status == CHOOSELEVEL)
542 HandleChooseLevel(0,0, 0,0, MB_MENU_CHOICE);
543 else if (game_status == SETUP)
544 HandleSetupScreen(0,0, 0,0, MB_MENU_CHOICE);
545 else if (game_status == SETUPINPUT)
546 HandleSetupInputScreen(0,0, 0,0, MB_MENU_CHOICE);
550 if (game_status == CHOOSELEVEL)
551 HandleChooseLevel(0,0, 0,-SCR_FIELDY, MB_MENU_MARK);
555 if (game_status == CHOOSELEVEL)
556 HandleChooseLevel(0,0, 0,SCR_FIELDY, MB_MENU_MARK);
565 HandleHelpScreen(MB_RELEASED);
573 game_status = MAINMENU;
579 HandleHallOfFame(0,0, 0,-SCR_FIELDY, MB_MENU_MARK);
583 HandleHallOfFame(0,0, 0,SCR_FIELDY, MB_MENU_MARK);
592 HandleLevelEditorKeyInput(key);
613 if (GameFrameDelay == 500)
614 GameFrameDelay = GAME_FRAME_DELAY;
616 GameFrameDelay = 500;
619 GameFrameDelay = (key - KEY_0) * 10;
620 printf("Game speed == %d%% (%d ms delay between two frames)\n",
621 GAME_FRAME_DELAY * 100 / GameFrameDelay, GameFrameDelay);
627 options.debug = FALSE;
628 printf("debug mode disabled\n");
632 options.debug = TRUE;
633 printf("debug mode enabled\n");
638 if (!global.fps_slowdown)
640 global.fps_slowdown = TRUE;
641 global.fps_slowdown_factor = 2;
642 printf("fps slowdown enabled -- display only every 2nd frame\n");
644 else if (global.fps_slowdown_factor == 2)
646 global.fps_slowdown_factor = 4;
647 printf("fps slowdown enabled -- display only every 4th frame\n");
651 global.fps_slowdown = FALSE;
652 global.fps_slowdown_factor = 1;
653 printf("fps slowdown disabled\n");
659 if (ScrollStepSize == TILEX/8)
660 ScrollStepSize = TILEX/4;
662 ScrollStepSize = TILEX/8;
663 printf("ScrollStepSize == %d\n", ScrollStepSize);
672 ScrollStepSize = TILEX/4;
677 ScrollStepSize = TILEX/8;
679 printf("MoveSpeed == %d\n", MoveSpeed);
684 ScrollStepSize = TILEX/8;
685 printf("ScrollStepSize == %d (1/8)\n", ScrollStepSize);
689 ScrollStepSize = TILEX/4;
690 printf("ScrollStepSize == %d (1/4)\n", ScrollStepSize);
694 ScrollStepSize = TILEX/2;
695 printf("ScrollStepSize == %d (1/2)\n", ScrollStepSize);
699 ScrollStepSize = TILEX;
700 printf("ScrollStepSize == %d (1/1)\n", ScrollStepSize);
707 local_player->dynamite = 1000;
718 for(i=0; i<MAX_PLAYERS; i++)
720 printf("Player %d:\n", i);
721 printf(" jx == %d, jy == %d\n",
722 stored_player[i].jx, stored_player[i].jy);
723 printf(" last_jx == %d, last_jy == %d\n",
724 stored_player[i].last_jx, stored_player[i].last_jy);
745 if (button_status && game_status != PLAYING)
747 HandleButton(0, 0, -button_status);
751 #if !defined(MSDOS) && !defined(WIN32)
759 static int HandleJoystickForAllPlayers()
764 for (i=0; i<MAX_PLAYERS; i++)
769 if (!setup.input[i].use_joystick)
773 joy_action = Joystick(i);
774 result |= joy_action;
777 if (!setup.input[i].use_joystick)
781 stored_player[i].action = joy_action;
787 void HandleJoystick()
789 int joystick = HandleJoystickForAllPlayers();
790 int keyboard = key_joystick_mapping;
791 int joy = (joystick | keyboard);
792 int left = joy & JOY_LEFT;
793 int right = joy & JOY_RIGHT;
794 int up = joy & JOY_UP;
795 int down = joy & JOY_DOWN;
796 int button = joy & JOY_BUTTON;
797 int newbutton = (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED);
798 int dx = (left ? -1 : right ? 1 : 0);
799 int dy = (up ? -1 : down ? 1 : 0);
808 static unsigned long joystickmove_delay = 0;
810 if (joystick && !button &&
811 !DelayReached(&joystickmove_delay, GADGET_FRAME_DELAY))
812 newbutton = dx = dy = 0;
814 if (game_status==MAINMENU)
815 HandleMainMenu(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
816 else if (game_status==CHOOSELEVEL)
817 HandleChooseLevel(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
818 else if (game_status==SETUP)
819 HandleSetupScreen(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
820 else if (game_status==SETUPINPUT)
821 HandleSetupInputScreen(0,0,dx,dy,
822 newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
827 HandleHallOfFame(0,0, dx,dy, !newbutton);
831 HandleHelpScreen(!newbutton);
835 if (tape.playing || keyboard)
836 newbutton = ((joy & JOY_BUTTON) != 0);
838 if (AllPlayersGone && newbutton)
840 CloseDoor(DOOR_CLOSE_1);
841 game_status = MAINMENU;