/***********************************************************
-* Rocks'n'Diamonds -- McDuffin Strikes Back! *
+* Rocks'n'Diamonds -- McDuffin Strikes Back! *
*----------------------------------------------------------*
-* (c) 1995-98 Artsoft Entertainment *
-* Holger Schemel *
-* Oststrasse 11a *
-* 33604 Bielefeld *
-* phone: ++49 +521 290471 *
-* email: aeglos@valinor.owl.de *
+* (c) 1995-2001 Artsoft Entertainment *
+* Holger Schemel *
+* Detmolder Strasse 189 *
+* 33604 Bielefeld *
+* Germany *
+* e-mail: info@artsoft.org *
*----------------------------------------------------------*
-* events.c *
+* events.c *
***********************************************************/
+#include "libgame/libgame.h"
+
#include "events.h"
#include "init.h"
#include "screens.h"
#include "tools.h"
#include "game.h"
#include "editor.h"
-#include "misc.h"
+#include "files.h"
#include "tape.h"
-#include "joystick.h"
-#include "buttons.h"
#include "network.h"
/* values for key_status */
#define KEY_RELEASED FALSE
#define KEY_PRESSED TRUE
+
+/* event filter especially needed for SDL event filtering due to
+ delay problems with lots of mouse motion events when mouse
+ button not pressed */
+
+int FilterMouseMotionEvents(const Event *event)
+{
+ if (event->type != EVENT_MOTIONNOTIFY)
+ return 1;
+
+ /* get mouse motion events without pressed button only in level editor */
+ if (button_status == MB_RELEASED && game_status != LEVELED)
+ return 0;
+ else
+ return 1;
+}
+
+/* this is only really needed for non-SDL targets to filter unwanted events;
+ when using SDL with properly installed event filter, this function can be
+ replaced with a simple "NextEvent()" call, but it doesn't hurt either */
+
+static boolean NextValidEvent(Event *event)
+{
+ while (PendingEvent())
+ {
+ NextEvent(event);
+
+ if (FilterMouseMotionEvents(event))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
void EventLoop(void)
{
while(1)
{
- if (XPending(display)) /* got event from X server */
+ if (PendingEvent()) /* got event */
{
- XEvent event;
-
- XNextEvent(display, &event);
+ Event event;
- switch(event.type)
+ if (NextValidEvent(&event))
{
- case ButtonPress:
- case ButtonRelease:
- HandleButtonEvent((XButtonEvent *) &event);
- break;
-
- case MotionNotify:
- HandleMotionEvent((XMotionEvent *) &event);
- break;
-
- case KeyPress:
- case KeyRelease:
- HandleKeyEvent((XKeyEvent *) &event);
- break;
-
- default:
- HandleOtherEvents(&event);
- break;
+ switch(event.type)
+ {
+ case EVENT_BUTTONPRESS:
+ case EVENT_BUTTONRELEASE:
+ HandleButtonEvent((ButtonEvent *) &event);
+ break;
+
+ case EVENT_MOTIONNOTIFY:
+ HandleMotionEvent((MotionEvent *) &event);
+ break;
+
+ case EVENT_KEYPRESS:
+ case EVENT_KEYRELEASE:
+ HandleKeyEvent((KeyEvent *) &event);
+ break;
+
+ default:
+ HandleOtherEvents(&event);
+ break;
+ }
}
}
-
- HandleNoXEvent();
+ else
+ HandleNoEvent();
/* don't use all CPU time when idle; the main loop while playing
has its own synchronization and is CPU friendly, too */
- if (game_status != PLAYING)
+ if (game_status == PLAYING)
+ HandleGameActions();
+ else
{
- XSync(display, FALSE);
- Delay(10);
+ SyncDisplay();
+ if (!PendingEvent()) /* delay only if no pending events */
+ Delay(10);
}
/* refresh window contents from drawing buffer, if needed */
}
}
-void HandleOtherEvents(XEvent *event)
+void HandleOtherEvents(Event *event)
{
switch(event->type)
{
- case Expose:
- HandleExposeEvent((XExposeEvent *) event);
+ case EVENT_EXPOSE:
+ HandleExposeEvent((ExposeEvent *) event);
break;
- case UnmapNotify:
+ case EVENT_UNMAPNOTIFY:
SleepWhileUnmapped();
break;
- case FocusIn:
- case FocusOut:
- HandleFocusEvent((XFocusChangeEvent *) event);
+ case EVENT_FOCUSIN:
+ case EVENT_FOCUSOUT:
+ HandleFocusEvent((FocusChangeEvent *) event);
break;
- case ClientMessage:
- HandleClientMessageEvent((XClientMessageEvent *) event);
+ case EVENT_CLIENTMESSAGE:
+ HandleClientMessageEvent((ClientMessageEvent *) event);
break;
+#if defined(TARGET_SDL)
+ case SDL_JOYAXISMOTION:
+ case SDL_JOYBUTTONDOWN:
+ case SDL_JOYBUTTONUP:
+ HandleJoystickEvent(event);
+ break;
+#endif
+
default:
break;
}
void ClearEventQueue()
{
- while(XPending(display))
+ while (PendingEvent())
{
- XEvent event;
+ Event event;
- XNextEvent(display, &event);
+ NextEvent(&event);
switch(event.type)
{
- case ButtonRelease:
+ case EVENT_BUTTONRELEASE:
button_status = MB_RELEASED;
break;
- case KeyRelease:
+ case EVENT_KEYRELEASE:
key_joystick_mapping = 0;
break;
{
boolean window_unmapped = TRUE;
- XAutoRepeatOn(display);
+ KeyboardAutoRepeatOn();
while(window_unmapped)
{
- XEvent event;
+ Event event;
- XNextEvent(display, &event);
+ NextEvent(&event);
switch(event.type)
{
- case ButtonRelease:
+ case EVENT_BUTTONRELEASE:
button_status = MB_RELEASED;
break;
- case KeyRelease:
+ case EVENT_KEYRELEASE:
key_joystick_mapping = 0;
break;
- case MapNotify:
+ case EVENT_MAPNOTIFY:
window_unmapped = FALSE;
break;
- case UnmapNotify:
+ case EVENT_UNMAPNOTIFY:
/* this is only to surely prevent the 'should not happen' case
* of recursively looping between 'SleepWhileUnmapped()' and
* 'HandleOtherEvents()' which usually calls this funtion.
}
}
- if (game_status==PLAYING)
- XAutoRepeatOff(display);
+ if (game_status == PLAYING)
+ KeyboardAutoRepeatOff();
}
-void HandleExposeEvent(XExposeEvent *event)
+void HandleExposeEvent(ExposeEvent *event)
{
+#ifndef TARGET_SDL
int x = event->x, y = event->y;
int width = event->width, height = event->height;
fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
- XCopyArea(display,fieldbuffer,backbuffer,gc,
- fx,fy, SXSIZE,SYSIZE,
- SX,SY);
+ BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
}
- XCopyArea(display,drawto,window,gc, x,y, width,height, x,y);
+ BlitBitmap(drawto, window, x,y, width,height, x,y);
- XFlush(display);
+ FlushDisplay();
+#endif
}
-void HandleButtonEvent(XButtonEvent *event)
+void HandleButtonEvent(ButtonEvent *event)
{
motion_status = FALSE;
- if (event->type==ButtonPress)
+ if (event->type == EVENT_BUTTONPRESS)
button_status = event->button;
else
button_status = MB_RELEASED;
HandleButton(event->x, event->y, button_status);
}
-void HandleMotionEvent(XMotionEvent *event)
+void HandleMotionEvent(MotionEvent *event)
{
+ if (!PointerInWindow(window))
+ return; /* window and pointer are on different screens */
+
+#if 1
+ if (button_status == MB_RELEASED && game_status != LEVELED)
+ return;
+#endif
+
motion_status = TRUE;
HandleButton(event->x, event->y, button_status);
}
-void HandleKeyEvent(XKeyEvent *event)
+void HandleKeyEvent(KeyEvent *event)
{
- int key_status = (event->type == KeyPress ? KEY_PRESSED : KEY_RELEASED);
- unsigned int event_state = (game_status != PLAYING ? event->state : 0);
- KeySym key = XLookupKeysym(event, event_state);
+ int key_status = (event->type==EVENT_KEYPRESS ? KEY_PRESSED : KEY_RELEASED);
+ boolean with_modifiers = (game_status == PLAYING ? FALSE : TRUE);
+ Key key = GetEventKey(event, with_modifiers);
HandleKey(key, key_status);
}
-void HandleFocusEvent(XFocusChangeEvent *event)
+void HandleFocusEvent(FocusChangeEvent *event)
{
static int old_joystick_status = -1;
- if (event->type == FocusOut)
+ if (event->type == EVENT_FOCUSOUT)
{
- XAutoRepeatOn(display);
- old_joystick_status = joystick_status;
- joystick_status = JOYSTICK_OFF;
+ int i;
+
+ KeyboardAutoRepeatOn();
+ old_joystick_status = joystick.status;
+ joystick.status = JOYSTICK_NOT_AVAILABLE;
+
+ /* simulate key release events for still pressed keys */
key_joystick_mapping = 0;
+ for (i=0; i<MAX_PLAYERS; i++)
+ stored_player[i].action = 0;
}
- else if (event->type == FocusIn)
+ else if (event->type == EVENT_FOCUSIN)
{
+ /* When there are two Rocks'n'Diamonds windows which overlap and
+ the player moves the pointer from one game window to the other,
+ a 'FocusOut' event is generated for the window the pointer is
+ leaving and a 'FocusIn' event is generated for the window the
+ pointer is entering. In some cases, it can happen that the
+ 'FocusIn' event is handled by the one game process before the
+ 'FocusOut' event by the other game process. In this case the
+ X11 environment would end up with activated keyboard auto repeat,
+ because unfortunately this is a global setting and not (which
+ would be far better) set for each X11 window individually.
+ The effect would be keyboard auto repeat while playing the game
+ (game_status == PLAYING), which is not desired.
+ To avoid this special case, we just wait 1/10 second before
+ processing the 'FocusIn' event.
+ */
+
if (game_status == PLAYING)
- XAutoRepeatOff(display);
+ {
+ Delay(100);
+ KeyboardAutoRepeatOff();
+ }
if (old_joystick_status != -1)
- joystick_status = old_joystick_status;
+ joystick.status = old_joystick_status;
}
}
-void HandleClientMessageEvent(XClientMessageEvent *event)
+void HandleClientMessageEvent(ClientMessageEvent *event)
{
-#ifndef MSDOS
- if ((event->window == window) &&
- (event->data.l[0] == XInternAtom(display, "WM_DELETE_WINDOW", FALSE)))
+ if (CheckCloseWindowEvent(event))
CloseAllAndExit(0);
-#endif
}
void HandleButton(int mx, int my, int button)
{
old_mx = mx;
old_my = my;
-
- HandleVideoButtons(mx,my, button);
- HandleSoundButtons(mx,my, button);
- HandleGameButtons(mx,my, button);
}
HandleGadgets(mx, my, button);
break;
case TYPENAME:
- HandleTypeName(0, XK_Return);
+ HandleTypeName(0, KSYM_Return);
break;
case CHOOSELEVEL:
break;
case HALLOFFAME:
- HandleHallOfFame(button);
+ HandleHallOfFame(0,0, 0,0, button);
break;
case LEVELED:
- LevelEd(mx,my, button);
break;
case HELPSCREEN:
HandleSetupScreen(mx,my, 0,0, button);
break;
- case SETUPINPUT:
- HandleSetupInputScreen(mx,my, 0,0, button);
- break;
-
case PLAYING:
#ifdef DEBUG
if (button == MB_RELEASED)
}
}
-void HandleKey(KeySym key, int key_status)
+void HandleKey(Key key, int key_status)
{
int joy = 0;
+ boolean anyTextGadgetActiveOrJustFinished = anyTextGadgetActive();
static struct SetupKeyboardInfo custom_key;
static struct
{
- KeySym *keysym_custom;
- KeySym keysym_default;
+ Key *key_custom;
+ Key key_default;
byte action;
} key_info[] =
{
custom_key = setup.input[pnr].key;
for (i=0; i<6; i++)
- if (key == *key_info[i].keysym_custom)
+ if (key == *key_info[i].key_custom)
key_action |= key_info[i].action;
if (key_status == KEY_PRESSED)
int i;
for (i=0; i<6; i++)
- if (key == key_info[i].keysym_default)
+ if (key == key_info[i].key_default)
joy |= key_info[i].action;
}
if (key_status == KEY_RELEASED)
return;
- if (key == XK_Return && game_status == PLAYING && AllPlayersGone)
+ if ((key == KSYM_Return || key == KSYM_space) &&
+ game_status == PLAYING && AllPlayersGone)
{
CloseDoor(DOOR_CLOSE_1);
game_status = MAINMENU;
}
/* allow quick escape to the main menu with the Escape key */
- if (key == XK_Escape && game_status != MAINMENU)
+ if (key == KSYM_Escape &&
+ game_status != MAINMENU &&
+ game_status != LEVELED &&
+ game_status != CHOOSELEVEL &&
+ game_status != SETUP)
{
- if (game_status == LEVELED)
- {
- /* draw smaller door */
- XCopyArea(display, pix[PIX_DOOR], drawto, gc,
- DOOR_GFX_PAGEX7, 64,
- 108, 64,
- EX - 4, EY - 12);
- redraw_mask |= REDRAW_ALL;
- }
-
- CloseDoor(DOOR_CLOSE_1 | DOOR_OPEN_2 | DOOR_NO_DELAY);
game_status = MAINMENU;
DrawMainMenu();
return;
case MAINMENU:
case CHOOSELEVEL:
case SETUP:
- case SETUPINPUT:
switch(key)
{
- case XK_Return:
+ case KSYM_Return:
+ case KSYM_space:
if (game_status == MAINMENU)
HandleMainMenu(0,0, 0,0, MB_MENU_CHOICE);
else if (game_status == CHOOSELEVEL)
HandleChooseLevel(0,0, 0,0, MB_MENU_CHOICE);
else if (game_status == SETUP)
HandleSetupScreen(0,0, 0,0, MB_MENU_CHOICE);
- else if (game_status == SETUPINPUT)
- HandleSetupInputScreen(0,0, 0,0, MB_MENU_CHOICE);
break;
+ case KSYM_Escape:
+ if (game_status == CHOOSELEVEL)
+ HandleChooseLevel(0,0, 0,0, MB_MENU_LEAVE);
+ else if (game_status == SETUP)
+ HandleSetupScreen(0,0, 0,0, MB_MENU_LEAVE);
+ break;
+
+ case KSYM_Page_Up:
+ if (game_status == CHOOSELEVEL)
+ HandleChooseLevel(0,0, 0,-SCR_FIELDY, MB_MENU_MARK);
+ break;
+
+ case KSYM_Page_Down:
+ if (game_status == CHOOSELEVEL)
+ HandleChooseLevel(0,0, 0,SCR_FIELDY, MB_MENU_MARK);
+ break;
+
+#ifdef DEBUG
+ case KSYM_t:
+ DumpTape(&tape);
+ break;
+#endif
+
default:
break;
}
case HALLOFFAME:
switch(key)
{
- case XK_Return:
+ case KSYM_Return:
+ case KSYM_space:
game_status = MAINMENU;
DrawMainMenu();
BackToFront();
break;
+ case KSYM_Page_Up:
+ HandleHallOfFame(0,0, 0,-SCR_FIELDY, MB_MENU_MARK);
+ break;
+
+ case KSYM_Page_Down:
+ HandleHallOfFame(0,0, 0,SCR_FIELDY, MB_MENU_MARK);
+ break;
+
default:
break;
}
break;
case LEVELED:
- HandleLevelEditorKeyInput(key);
- LevelNameTyping(key);
+ if (!anyTextGadgetActiveOrJustFinished || key == KSYM_Escape)
+ HandleLevelEditorKeyInput(key);
break;
case PLAYING:
{
#ifdef DEBUG
- case XK_0:
- case XK_1:
- case XK_2:
- case XK_3:
- case XK_4:
- case XK_5:
- case XK_6:
- case XK_7:
- case XK_8:
- case XK_9:
- if (key == XK_0)
+ case KSYM_0:
+ case KSYM_1:
+ case KSYM_2:
+ case KSYM_3:
+ case KSYM_4:
+ case KSYM_5:
+ case KSYM_6:
+ case KSYM_7:
+ case KSYM_8:
+ case KSYM_9:
+ if (key == KSYM_0)
{
if (GameFrameDelay == 500)
GameFrameDelay = GAME_FRAME_DELAY;
GameFrameDelay = 500;
}
else
- GameFrameDelay = (key - XK_0) * 10;
+ GameFrameDelay = (key - KSYM_0) * 10;
printf("Game speed == %d%% (%d ms delay between two frames)\n",
GAME_FRAME_DELAY * 100 / GameFrameDelay, GameFrameDelay);
break;
+ case KSYM_d:
+ if (options.debug)
+ {
+ options.debug = FALSE;
+ printf("debug mode disabled\n");
+ }
+ else
+ {
+ options.debug = TRUE;
+ printf("debug mode enabled\n");
+ }
+ break;
+
+ case KSYM_s:
+ if (!global.fps_slowdown)
+ {
+ global.fps_slowdown = TRUE;
+ global.fps_slowdown_factor = 2;
+ printf("fps slowdown enabled -- display only every 2nd frame\n");
+ }
+ else if (global.fps_slowdown_factor == 2)
+ {
+ global.fps_slowdown_factor = 4;
+ printf("fps slowdown enabled -- display only every 4th frame\n");
+ }
+ else
+ {
+ global.fps_slowdown = FALSE;
+ global.fps_slowdown_factor = 1;
+ printf("fps slowdown disabled\n");
+ }
+ break;
#if 0
- case XK_a:
+ case KSYM_a:
if (ScrollStepSize == TILEX/8)
ScrollStepSize = TILEX/4;
else
break;
#endif
-#if 1
- case XK_m:
+#if 0
+ case KSYM_m:
if (MoveSpeed == 8)
{
MoveSpeed = 4;
break;
#endif
- case XK_f:
+ case KSYM_f:
ScrollStepSize = TILEX/8;
printf("ScrollStepSize == %d (1/8)\n", ScrollStepSize);
break;
- case XK_g:
+ case KSYM_g:
ScrollStepSize = TILEX/4;
printf("ScrollStepSize == %d (1/4)\n", ScrollStepSize);
break;
- case XK_h:
+ case KSYM_h:
ScrollStepSize = TILEX/2;
printf("ScrollStepSize == %d (1/2)\n", ScrollStepSize);
break;
- case XK_l:
+ case KSYM_l:
ScrollStepSize = TILEX;
printf("ScrollStepSize == %d (1/1)\n", ScrollStepSize);
break;
-#ifndef MSDOS
- case XK_Q:
-#endif
- case XK_q:
+ case KSYM_Q:
+ case KSYM_q:
local_player->dynamite = 1000;
break;
#if 0
- case XK_z:
+ case KSYM_z:
{
int i;
}
}
-void HandleNoXEvent()
+void HandleNoEvent()
{
if (button_status && game_status != PLAYING)
{
return;
}
-#ifndef MSDOS
+#if defined(PLATFORM_UNIX)
if (options.network)
HandleNetworking();
#endif
HandleJoystick();
-
- if (game_status == PLAYING)
- HandleGameActions();
}
static int HandleJoystickForAllPlayers()
case MAINMENU:
case CHOOSELEVEL:
case SETUP:
- case SETUPINPUT:
{
static unsigned long joystickmove_delay = 0;
HandleChooseLevel(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
else if (game_status==SETUP)
HandleSetupScreen(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
- else if (game_status==SETUPINPUT)
- HandleSetupInputScreen(0,0,dx,dy,
- newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
break;
}
case HALLOFFAME:
- HandleHallOfFame(!newbutton);
+ HandleHallOfFame(0,0, dx,dy, !newbutton);
break;
case HELPSCREEN: