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)
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 boolean anyTextGadgetActiveOrJustFinished = anyTextGadgetActive();
430 static struct SetupKeyboardInfo custom_key;
438 { &custom_key.left, DEFAULT_KEY_LEFT, JOY_LEFT },
439 { &custom_key.right, DEFAULT_KEY_RIGHT, JOY_RIGHT },
440 { &custom_key.up, DEFAULT_KEY_UP, JOY_UP },
441 { &custom_key.down, DEFAULT_KEY_DOWN, JOY_DOWN },
442 { &custom_key.snap, DEFAULT_KEY_SNAP, JOY_BUTTON_1 },
443 { &custom_key.bomb, DEFAULT_KEY_BOMB, JOY_BUTTON_2 }
446 if (game_status == PLAYING)
450 for (pnr=0; pnr<MAX_PLAYERS; pnr++)
455 if (setup.input[pnr].use_joystick)
458 custom_key = setup.input[pnr].key;
461 if (key == *key_info[i].key_custom)
462 key_action |= key_info[i].action;
464 if (key_status == KEY_PRESSED)
465 stored_player[pnr].action |= key_action;
467 stored_player[pnr].action &= ~key_action;
475 if (key == key_info[i].key_default)
476 joy |= key_info[i].action;
481 if (key_status == KEY_PRESSED)
482 key_joystick_mapping |= joy;
484 key_joystick_mapping &= ~joy;
489 if (game_status != PLAYING)
490 key_joystick_mapping = 0;
492 if (key_status == KEY_RELEASED)
495 if ((key == KEY_Return || key == KEY_space) &&
496 game_status == PLAYING && AllPlayersGone)
498 CloseDoor(DOOR_CLOSE_1);
499 game_status = MAINMENU;
504 /* allow quick escape to the main menu with the Escape key */
505 if (key == KEY_Escape && game_status != MAINMENU)
507 CloseDoor(DOOR_CLOSE_1 | DOOR_OPEN_2 | DOOR_NO_DELAY);
508 game_status = MAINMENU;
517 if (game_status == PLAYING && (tape.playing || tape.pausing))
524 HandleGadgetsKeyInput(key);
529 HandleTypeName(0, key);
540 if (game_status == MAINMENU)
541 HandleMainMenu(0,0, 0,0, MB_MENU_CHOICE);
542 else if (game_status == CHOOSELEVEL)
543 HandleChooseLevel(0,0, 0,0, MB_MENU_CHOICE);
544 else if (game_status == SETUP)
545 HandleSetupScreen(0,0, 0,0, MB_MENU_CHOICE);
546 else if (game_status == SETUPINPUT)
547 HandleSetupInputScreen(0,0, 0,0, MB_MENU_CHOICE);
551 if (game_status == CHOOSELEVEL)
552 HandleChooseLevel(0,0, 0,-SCR_FIELDY, MB_MENU_MARK);
556 if (game_status == CHOOSELEVEL)
557 HandleChooseLevel(0,0, 0,SCR_FIELDY, MB_MENU_MARK);
566 HandleHelpScreen(MB_RELEASED);
574 game_status = MAINMENU;
580 HandleHallOfFame(0,0, 0,-SCR_FIELDY, MB_MENU_MARK);
584 HandleHallOfFame(0,0, 0,SCR_FIELDY, MB_MENU_MARK);
593 if (!anyTextGadgetActiveOrJustFinished)
594 HandleLevelEditorKeyInput(key);
615 if (GameFrameDelay == 500)
616 GameFrameDelay = GAME_FRAME_DELAY;
618 GameFrameDelay = 500;
621 GameFrameDelay = (key - KEY_0) * 10;
622 printf("Game speed == %d%% (%d ms delay between two frames)\n",
623 GAME_FRAME_DELAY * 100 / GameFrameDelay, GameFrameDelay);
629 options.debug = FALSE;
630 printf("debug mode disabled\n");
634 options.debug = TRUE;
635 printf("debug mode enabled\n");
640 if (!global.fps_slowdown)
642 global.fps_slowdown = TRUE;
643 global.fps_slowdown_factor = 2;
644 printf("fps slowdown enabled -- display only every 2nd frame\n");
646 else if (global.fps_slowdown_factor == 2)
648 global.fps_slowdown_factor = 4;
649 printf("fps slowdown enabled -- display only every 4th frame\n");
653 global.fps_slowdown = FALSE;
654 global.fps_slowdown_factor = 1;
655 printf("fps slowdown disabled\n");
661 if (ScrollStepSize == TILEX/8)
662 ScrollStepSize = TILEX/4;
664 ScrollStepSize = TILEX/8;
665 printf("ScrollStepSize == %d\n", ScrollStepSize);
674 ScrollStepSize = TILEX/4;
679 ScrollStepSize = TILEX/8;
681 printf("MoveSpeed == %d\n", MoveSpeed);
686 ScrollStepSize = TILEX/8;
687 printf("ScrollStepSize == %d (1/8)\n", ScrollStepSize);
691 ScrollStepSize = TILEX/4;
692 printf("ScrollStepSize == %d (1/4)\n", ScrollStepSize);
696 ScrollStepSize = TILEX/2;
697 printf("ScrollStepSize == %d (1/2)\n", ScrollStepSize);
701 ScrollStepSize = TILEX;
702 printf("ScrollStepSize == %d (1/1)\n", ScrollStepSize);
709 local_player->dynamite = 1000;
720 for(i=0; i<MAX_PLAYERS; i++)
722 printf("Player %d:\n", i);
723 printf(" jx == %d, jy == %d\n",
724 stored_player[i].jx, stored_player[i].jy);
725 printf(" last_jx == %d, last_jy == %d\n",
726 stored_player[i].last_jx, stored_player[i].last_jy);
747 if (button_status && game_status != PLAYING)
749 HandleButton(0, 0, -button_status);
753 #if !defined(MSDOS) && !defined(WIN32)
761 static int HandleJoystickForAllPlayers()
766 for (i=0; i<MAX_PLAYERS; i++)
771 if (!setup.input[i].use_joystick)
775 joy_action = Joystick(i);
776 result |= joy_action;
779 if (!setup.input[i].use_joystick)
783 stored_player[i].action = joy_action;
789 void HandleJoystick()
791 int joystick = HandleJoystickForAllPlayers();
792 int keyboard = key_joystick_mapping;
793 int joy = (joystick | keyboard);
794 int left = joy & JOY_LEFT;
795 int right = joy & JOY_RIGHT;
796 int up = joy & JOY_UP;
797 int down = joy & JOY_DOWN;
798 int button = joy & JOY_BUTTON;
799 int newbutton = (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED);
800 int dx = (left ? -1 : right ? 1 : 0);
801 int dy = (up ? -1 : down ? 1 : 0);
810 static unsigned long joystickmove_delay = 0;
812 if (joystick && !button &&
813 !DelayReached(&joystickmove_delay, GADGET_FRAME_DELAY))
814 newbutton = dx = dy = 0;
816 if (game_status==MAINMENU)
817 HandleMainMenu(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
818 else if (game_status==CHOOSELEVEL)
819 HandleChooseLevel(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
820 else if (game_status==SETUP)
821 HandleSetupScreen(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
822 else if (game_status==SETUPINPUT)
823 HandleSetupInputScreen(0,0,dx,dy,
824 newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
829 HandleHallOfFame(0,0, dx,dy, !newbutton);
833 HandleHelpScreen(!newbutton);
837 if (tape.playing || keyboard)
838 newbutton = ((joy & JOY_BUTTON) != 0);
840 if (AllPlayersGone && newbutton)
842 CloseDoor(DOOR_CLOSE_1);
843 game_status = MAINMENU;