#include "quakedef.h" /* * KEY BUTTONS * * Continuous button event tracking is complicated by the fact that two different * input sources (say, mouse button 1 and the control key) can both press the * same button, but the button should only be released when both of the * pressing key have been released. * * When a key event issues a button command (+forward, +attack, etc), it appends * its key number as a parameter to the command so it can be matched up with * the release. * * state bit 0 is the current state of the key * state bit 1 is edge triggered on the up to down transition * state bit 2 is edge triggered on the down to up transition */ cvar_t cl_upspeed = {"cl_upspeed", "200"};cvar_t cl_forwardspeed = {"cl_forwardspeed", "400", true};cvar_t cl_backspeed = {"cl_backspeed", "400", true};cvar_t cl_sidespeed = {"cl_sidespeed", "350"}; cvar_t cl_movespeedkey = {"cl_movespeedkey", "2.0"}; cvar_t cl_yawspeed = {"cl_yawspeed", "140"};cvar_t cl_pitchspeed = {"cl_pitchspeed", "150"}; cvar_t cl_anglespeedkey = {"cl_anglespeedkey", "1.5"}; kbutton_t in_strafe, in_mlook; static kbutton_t in_left, in_right, in_forward, in_back;static kbutton_t in_lookup, in_lookdown, in_moveleft, in_moveright;static kbutton_t in_klook, in_speed;static kbutton_t in_moveup, in_movedown;static kbutton_t in_attack, in_jump, in_button3, in_button4, in_use;static kbutton_t in_button5, in_button6, in_button7, in_button8;static int in_impulse; static voidKeyDown(kbutton_t *b){ int k; const char *c; c = Cmd_Argv(1); if(c[0]) k = atoi(c); else k = -1; // typed manually at the console for continuous down if(k == b->down[0] || k == b->down[1]) return; // repeating key if(!b->down[0]) b->down[0] = k; else if(!b->down[1]) b->down[1] = k; else { Con_Printf("Three keys down for a button!\n"); return; } if(b->state & 1) return; // still down b->state |= 1 + 2; // down + impulse down} static voidKeyUp(kbutton_t *b){ int k; const char *c; c = Cmd_Argv(1); if(c[0]) k = atoi(c); else { // typed manually at the console, assume for unsticking, so clear all b->down[0] = b->down[1] = 0; b->state = 4; // impulse up return; } if(b->down[0] == k) b->down[0] = 0; else if(b->down[1] == k) b->down[1] = 0; else return; // key up without coresponding down (menu pass through) if(b->down[0] || b->down[1]) return; // some other key is still holding it down if((b->state & 1) == 0) return; // still up (this should not happen) b->state &= ~1; // now up b->state |= 4; // impulse up} #define IN_KEY_DOWN(key) \ static void IN_##key##Down(cmd_t *c) \ { \ USED(c); \ KeyDown(&in_##key); \ } #define IN_KEY_UP(key) \ static void IN_##key##Up(cmd_t *c) \ { \ USED(c); \ KeyUp(&in_##key); \ } #define IN_KEY(key) \ IN_KEY_DOWN(key); \ IN_KEY_UP(key); IN_KEY(klook);IN_KEY_DOWN(mlook); static voidIN_mlookUp(cmd_t *c){ KeyUp(&in_mlook); if((in_mlook.state & 1) == 0 && lookspring.value) V_StartPitchDrift(c);} IN_KEY(left);IN_KEY(right);IN_KEY(forward);IN_KEY(back);IN_KEY(lookup);IN_KEY(lookdown);IN_KEY(moveleft);IN_KEY(moveright);IN_KEY(moveup);IN_KEY(movedown);IN_KEY(speed);IN_KEY(strafe);IN_KEY(attack);IN_KEY(jump);IN_KEY(button3);IN_KEY(button4);IN_KEY(button5);IN_KEY(button6);IN_KEY(button7);IN_KEY(button8);IN_KEY(use); static voidIN_Impulse(cmd_t *c){ USED(c); in_impulse = atoi(Cmd_Argv(1));} /*Returns 0.25 if a key was pressed and released during the frame,0.5 if it was pressed and held0 if held then released, and1.0 if held for the entire time*/static floatCL_KeyState(kbutton_t *key){ float val; bool impulsedown, impulseup, down; impulsedown = key->state & 2; impulseup = key->state & 4; down = key->state & 1; val = 0; if(impulsedown && !impulseup) val = down ? 0.5 : 0; else if(impulseup && !impulsedown) val = 0; else if(!impulsedown && !impulseup) val = down ? 1.0 : 0; else if(impulsedown && impulseup) val = down ? 0.75 : 0.25; key->state &= 1; // clear impulses return val;} /* Moves the local angle positions */static voidCL_AdjustAngles(void){ float speed, up, down; if(in_speed.state & 1) speed = scr_frametime * cl_anglespeedkey.value; else speed = scr_frametime; if(!(in_strafe.state & 1)) { cl.viewangles[YAW] -= speed * cl_yawspeed.value * CL_KeyState(&in_right); cl.viewangles[YAW] += speed * cl_yawspeed.value * CL_KeyState(&in_left); cl.viewangles[YAW] = anglemod(cl.viewangles[YAW]); } if(in_klook.state & 1) { V_StopPitchDrift(); cl.viewangles[PITCH] -= speed * cl_pitchspeed.value * CL_KeyState(&in_forward); cl.viewangles[PITCH] += speed * cl_pitchspeed.value * CL_KeyState(&in_back); } up = CL_KeyState(&in_lookup); down = CL_KeyState(&in_lookdown); cl.viewangles[PITCH] -= speed * cl_pitchspeed.value * up; cl.viewangles[PITCH] += speed * cl_pitchspeed.value * down; if(up || down) V_StopPitchDrift(); cl.viewangles[PITCH] = clamp(cl.viewangles[PITCH], -MAX_PITCH, MAX_PITCH); cl.viewangles[ROLL] = clamp(cl.viewangles[ROLL], -MAX_ROLL, MAX_ROLL);} /* Send the intended movement message to the server */voidCL_BaseMove(usercmd_t *cmd){ if(cls.signon != SIGNONS) return; CL_AdjustAngles(); memset(cmd, 0, sizeof(*cmd)); if(in_strafe.state & 1) { cmd->sidemove += cl_sidespeed.value * CL_KeyState(&in_right); cmd->sidemove -= cl_sidespeed.value * CL_KeyState(&in_left); } cmd->sidemove += cl_sidespeed.value * CL_KeyState(&in_moveright); cmd->sidemove -= cl_sidespeed.value * CL_KeyState(&in_moveleft); cmd->upmove += cl_upspeed.value * CL_KeyState(&in_moveup); cmd->upmove -= cl_upspeed.value * CL_KeyState(&in_movedown); if((in_klook.state & 1) == 0) { cmd->forwardmove += cl_forwardspeed.value * CL_KeyState(&in_forward); cmd->forwardmove -= cl_backspeed.value * CL_KeyState(&in_back); } // adjust for speed key if(in_speed.state & 1) { if((cmd->forwardmove > 0 && cl_forwardspeed.value > 200) || (cmd->forwardmove < 0 && cl_backspeed.value > 200)) cmd->forwardmove /= cl_movespeedkey.value; else cmd->forwardmove *= cl_movespeedkey.value; cmd->sidemove *= cl_movespeedkey.value; cmd->upmove *= cl_movespeedkey.value; }} voidCL_SendMove(usercmd_t *cmd){ byte data[128]; sizebuf_t buf; int i, bits; buf.maxsize = 128; buf.cursize = 0; buf.data = data; cl.cmd = *cmd; // send the movement message MSG_WriteByte(&buf, clc_move); MSG_WriteFloat(&buf, cl.mtime[0]); // so server can get ping times for(i = 0; i < 3; i++) cl.protocol.MSG_WriteAngle(&buf, cl.viewangles[i]); MSG_WriteShort(&buf, cmd->forwardmove); MSG_WriteShort(&buf, cmd->sidemove); MSG_WriteShort(&buf, cmd->upmove); // send button bits bits = 0; if(in_attack.state & 3) bits |= 1 << 0; in_attack.state &= ~2; if(in_jump.state & 3) bits |= 1 << 1; in_jump.state &= ~2; if(in_button3.state & 3) bits |= 1 << 2; in_button3.state &= ~2; if(in_button4.state & 3) bits |= 1 << 3; in_button4.state &= ~2; if(in_button5.state & 3) bits |= 1 << 4; in_button5.state &= ~2; if(in_button6.state & 3) bits |= 1 << 5; in_button6.state &= ~2; if(in_button7.state & 3) bits |= 1 << 6; in_button7.state &= ~2; if(in_button8.state & 3) bits |= 1 << 7; in_button8.state &= ~2; /* FIXME if(in_use.state & 3) bits |= 4; in_use.state &= ~2; */ MSG_WriteByte(&buf, bits); MSG_WriteByte(&buf, in_impulse); in_impulse = 0; // deliver the message if(cls.demoplayback) return; // always dump the first two message, because it may contain leftover inputs // from the last level if(++cl.movemessages <= 2) return; if(NET_SendUnreliableMessage(cls.netcon, &buf) == -1) { Con_Printf("CL_SendMove: lost server connection\n"); CL_Disconnect(); }} voidCL_NewMap(void){ memset(&in_strafe, 0, sizeof(kbutton_t)); memset(&in_left, 0, sizeof(kbutton_t)); memset(&in_right, 0, sizeof(kbutton_t)); memset(&in_forward, 0, sizeof(kbutton_t)); memset(&in_back, 0, sizeof(kbutton_t)); memset(&in_lookup, 0, sizeof(kbutton_t)); memset(&in_lookdown, 0, sizeof(kbutton_t)); memset(&in_moveleft, 0, sizeof(kbutton_t)); memset(&in_moveright, 0, sizeof(kbutton_t)); memset(&in_moveup, 0, sizeof(kbutton_t)); memset(&in_movedown, 0, sizeof(kbutton_t)); memset(&in_attack, 0, sizeof(kbutton_t)); memset(&in_jump, 0, sizeof(kbutton_t)); memset(&in_button3, 0, sizeof(kbutton_t)); memset(&in_button4, 0, sizeof(kbutton_t)); memset(&in_button5, 0, sizeof(kbutton_t)); memset(&in_button6, 0, sizeof(kbutton_t)); memset(&in_button7, 0, sizeof(kbutton_t)); memset(&in_button8, 0, sizeof(kbutton_t)); memset(&in_use, 0, sizeof(kbutton_t)); in_impulse = 0;} voidCL_InitInput(void){#define KEY_CMD(key) \ Cmd_AddCommand("+" #key, IN_##key##Down); \ Cmd_AddCommand("-" #key, IN_##key##Up); KEY_CMD(strafe); KEY_CMD(left); KEY_CMD(right); KEY_CMD(forward); KEY_CMD(back); KEY_CMD(lookup); KEY_CMD(lookdown); KEY_CMD(moveleft); KEY_CMD(moveright); KEY_CMD(moveup); KEY_CMD(movedown); KEY_CMD(attack); KEY_CMD(jump); KEY_CMD(button3); KEY_CMD(button4); KEY_CMD(button5); KEY_CMD(button6); KEY_CMD(button7); KEY_CMD(button8); KEY_CMD(use); KEY_CMD(klook); KEY_CMD(mlook); KEY_CMD(speed); Cmd_AddCommand("impulse", IN_Impulse);}
#include "quakedef.h"
/*
* KEY BUTTONS
*
* Continuous button event tracking is complicated by the fact that two different
* input sources (say, mouse button 1 and the control key) can both press the
* same button, but the button should only be released when both of the
* pressing key have been released.
*
* When a key event issues a button command (+forward, +attack, etc), it appends
* its key number as a parameter to the command so it can be matched up with
* the release.
*
* state bit 0 is the current state of the key
* state bit 1 is edge triggered on the up to down transition
* state bit 2 is edge triggered on the down to up transition
*/
cvar_t cl_upspeed = {"cl_upspeed", "200"};
cvar_t cl_forwardspeed = {"cl_forwardspeed", "400", true};
cvar_t cl_backspeed = {"cl_backspeed", "400", true};
cvar_t cl_sidespeed = {"cl_sidespeed", "350"};
cvar_t cl_movespeedkey = {"cl_movespeedkey", "2.0"};
cvar_t cl_yawspeed = {"cl_yawspeed", "140"};
cvar_t cl_pitchspeed = {"cl_pitchspeed", "150"};
cvar_t cl_anglespeedkey = {"cl_anglespeedkey", "1.5"};
kbutton_t in_strafe, in_mlook;
static kbutton_t in_left, in_right, in_forward, in_back;
static kbutton_t in_lookup, in_lookdown, in_moveleft, in_moveright;
static kbutton_t in_klook, in_speed;
static kbutton_t in_moveup, in_movedown;
static kbutton_t in_attack, in_jump, in_button3, in_button4, in_use;
static kbutton_t in_button5, in_button6, in_button7, in_button8;
static int in_impulse;
static void
KeyDown(kbutton_t *b)
{
int k;
const char *c;
c = Cmd_Argv(1);
if(c[0])
k = atoi(c);
else
k = -1; // typed manually at the console for continuous down
if(k == b->down[0] || k == b->down[1])
return; // repeating key
if(!b->down[0])
b->down[0] = k;
else if(!b->down[1])
b->down[1] = k;
else {
Con_Printf("Three keys down for a button!\n");
return;
}
if(b->state & 1)
return; // still down
b->state |= 1 + 2; // down + impulse down
}
static void
KeyUp(kbutton_t *b)
{
int k;
const char *c;
c = Cmd_Argv(1);
if(c[0])
k = atoi(c);
else { // typed manually at the console, assume for unsticking, so clear all
b->down[0] = b->down[1] = 0;
b->state = 4; // impulse up
return;
}
if(b->down[0] == k)
b->down[0] = 0;
else if(b->down[1] == k)
b->down[1] = 0;
else
return; // key up without coresponding down (menu pass through)
if(b->down[0] || b->down[1])
return; // some other key is still holding it down
if((b->state & 1) == 0)
return; // still up (this should not happen)
b->state &= ~1; // now up
b->state |= 4; // impulse up
}
#define IN_KEY_DOWN(key) \
static void IN_##key##Down(cmd_t *c) \
{ \
USED(c); \
KeyDown(&in_##key); \
}
#define IN_KEY_UP(key) \
static void IN_##key##Up(cmd_t *c) \
{ \
USED(c); \
KeyUp(&in_##key); \
}
#define IN_KEY(key) \
IN_KEY_DOWN(key); \
IN_KEY_UP(key);
IN_KEY(klook);
IN_KEY_DOWN(mlook);
static void
IN_mlookUp(cmd_t *c)
{
KeyUp(&in_mlook);
if((in_mlook.state & 1) == 0 && lookspring.value)
V_StartPitchDrift(c);
}
IN_KEY(left);
IN_KEY(right);
IN_KEY(forward);
IN_KEY(back);
IN_KEY(lookup);
IN_KEY(lookdown);
IN_KEY(moveleft);
IN_KEY(moveright);
IN_KEY(moveup);
IN_KEY(movedown);
IN_KEY(speed);
IN_KEY(strafe);
IN_KEY(attack);
IN_KEY(jump);
IN_KEY(button3);
IN_KEY(button4);
IN_KEY(button5);
IN_KEY(button6);
IN_KEY(button7);
IN_KEY(button8);
IN_KEY(use);
static void
IN_Impulse(cmd_t *c)
{
USED(c);
in_impulse = atoi(Cmd_Argv(1));
}
/*
Returns 0.25 if a key was pressed and released during the frame,
0.5 if it was pressed and held
0 if held then released, and
1.0 if held for the entire time
*/
static float
CL_KeyState(kbutton_t *key)
{
float val;
bool impulsedown, impulseup, down;
impulsedown = key->state & 2;
impulseup = key->state & 4;
down = key->state & 1;
val = 0;
if(impulsedown && !impulseup)
val = down ? 0.5 : 0;
else if(impulseup && !impulsedown)
val = 0;
else if(!impulsedown && !impulseup)
val = down ? 1.0 : 0;
else if(impulsedown && impulseup)
val = down ? 0.75 : 0.25;
key->state &= 1; // clear impulses
return val;
}
/* Moves the local angle positions */
static void
CL_AdjustAngles(void)
{
float speed, up, down;
if(in_speed.state & 1)
speed = scr_frametime * cl_anglespeedkey.value;
else
speed = scr_frametime;
if(!(in_strafe.state & 1)) {
cl.viewangles[YAW] -= speed * cl_yawspeed.value * CL_KeyState(&in_right);
cl.viewangles[YAW] += speed * cl_yawspeed.value * CL_KeyState(&in_left);
cl.viewangles[YAW] = anglemod(cl.viewangles[YAW]);
}
if(in_klook.state & 1) {
V_StopPitchDrift();
cl.viewangles[PITCH] -= speed * cl_pitchspeed.value * CL_KeyState(&in_forward);
cl.viewangles[PITCH] += speed * cl_pitchspeed.value * CL_KeyState(&in_back);
}
up = CL_KeyState(&in_lookup);
down = CL_KeyState(&in_lookdown);
cl.viewangles[PITCH] -= speed * cl_pitchspeed.value * up;
cl.viewangles[PITCH] += speed * cl_pitchspeed.value * down;
if(up || down)
V_StopPitchDrift();
cl.viewangles[PITCH] = clamp(cl.viewangles[PITCH], -MAX_PITCH, MAX_PITCH);
cl.viewangles[ROLL] = clamp(cl.viewangles[ROLL], -MAX_ROLL, MAX_ROLL);
}
/* Send the intended movement message to the server */
void
CL_BaseMove(usercmd_t *cmd)
{
if(cls.signon != SIGNONS)
return;
CL_AdjustAngles();
memset(cmd, 0, sizeof(*cmd));
if(in_strafe.state & 1) {
cmd->sidemove += cl_sidespeed.value * CL_KeyState(&in_right);
cmd->sidemove -= cl_sidespeed.value * CL_KeyState(&in_left);
}
cmd->sidemove += cl_sidespeed.value * CL_KeyState(&in_moveright);
cmd->sidemove -= cl_sidespeed.value * CL_KeyState(&in_moveleft);
cmd->upmove += cl_upspeed.value * CL_KeyState(&in_moveup);
cmd->upmove -= cl_upspeed.value * CL_KeyState(&in_movedown);
if((in_klook.state & 1) == 0) {
cmd->forwardmove += cl_forwardspeed.value * CL_KeyState(&in_forward);
cmd->forwardmove -= cl_backspeed.value * CL_KeyState(&in_back);
}
// adjust for speed key
if(in_speed.state & 1) {
if((cmd->forwardmove > 0 && cl_forwardspeed.value > 200) ||
(cmd->forwardmove < 0 && cl_backspeed.value > 200))
cmd->forwardmove /= cl_movespeedkey.value;
else
cmd->forwardmove *= cl_movespeedkey.value;
cmd->sidemove *= cl_movespeedkey.value;
cmd->upmove *= cl_movespeedkey.value;
}
}
void
CL_SendMove(usercmd_t *cmd)
{
byte data[128];
sizebuf_t buf;
int i, bits;
buf.maxsize = 128;
buf.cursize = 0;
buf.data = data;
cl.cmd = *cmd;
// send the movement message
MSG_WriteByte(&buf, clc_move);
MSG_WriteFloat(&buf, cl.mtime[0]); // so server can get ping times
for(i = 0; i < 3; i++)
cl.protocol.MSG_WriteAngle(&buf, cl.viewangles[i]);
MSG_WriteShort(&buf, cmd->forwardmove);
MSG_WriteShort(&buf, cmd->sidemove);
MSG_WriteShort(&buf, cmd->upmove);
// send button bits
bits = 0;
if(in_attack.state & 3)
bits |= 1 << 0;
in_attack.state &= ~2;
if(in_jump.state & 3)
bits |= 1 << 1;
in_jump.state &= ~2;
if(in_button3.state & 3)
bits |= 1 << 2;
in_button3.state &= ~2;
if(in_button4.state & 3)
bits |= 1 << 3;
in_button4.state &= ~2;
if(in_button5.state & 3)
bits |= 1 << 4;
in_button5.state &= ~2;
if(in_button6.state & 3)
bits |= 1 << 5;
in_button6.state &= ~2;
if(in_button7.state & 3)
bits |= 1 << 6;
in_button7.state &= ~2;
if(in_button8.state & 3)
bits |= 1 << 7;
in_button8.state &= ~2;
/* FIXME
if(in_use.state & 3)
bits |= 4;
in_use.state &= ~2;
*/
MSG_WriteByte(&buf, bits);
MSG_WriteByte(&buf, in_impulse);
in_impulse = 0;
// deliver the message
if(cls.demoplayback)
return;
// always dump the first two message, because it may contain leftover inputs
// from the last level
if(++cl.movemessages <= 2)
return;
if(NET_SendUnreliableMessage(cls.netcon, &buf) == -1) {
Con_Printf("CL_SendMove: lost server connection\n");
CL_Disconnect();
}
}
void
CL_NewMap(void)
{
memset(&in_strafe, 0, sizeof(kbutton_t));
memset(&in_left, 0, sizeof(kbutton_t));
memset(&in_right, 0, sizeof(kbutton_t));
memset(&in_forward, 0, sizeof(kbutton_t));
memset(&in_back, 0, sizeof(kbutton_t));
memset(&in_lookup, 0, sizeof(kbutton_t));
memset(&in_lookdown, 0, sizeof(kbutton_t));
memset(&in_moveleft, 0, sizeof(kbutton_t));
memset(&in_moveright, 0, sizeof(kbutton_t));
memset(&in_moveup, 0, sizeof(kbutton_t));
memset(&in_movedown, 0, sizeof(kbutton_t));
memset(&in_attack, 0, sizeof(kbutton_t));
memset(&in_jump, 0, sizeof(kbutton_t));
memset(&in_button3, 0, sizeof(kbutton_t));
memset(&in_button4, 0, sizeof(kbutton_t));
memset(&in_button5, 0, sizeof(kbutton_t));
memset(&in_button6, 0, sizeof(kbutton_t));
memset(&in_button7, 0, sizeof(kbutton_t));
memset(&in_button8, 0, sizeof(kbutton_t));
memset(&in_use, 0, sizeof(kbutton_t));
in_impulse = 0;
}
void
CL_InitInput(void)
{
#define KEY_CMD(key) \
Cmd_AddCommand("+" #key, IN_##key##Down); \
Cmd_AddCommand("-" #key, IN_##key##Up);
KEY_CMD(strafe);
KEY_CMD(left);
KEY_CMD(right);
KEY_CMD(forward);
KEY_CMD(back);
KEY_CMD(lookup);
KEY_CMD(lookdown);
KEY_CMD(moveleft);
KEY_CMD(moveright);
KEY_CMD(moveup);
KEY_CMD(movedown);
KEY_CMD(attack);
KEY_CMD(jump);
KEY_CMD(button3);
KEY_CMD(button4);
KEY_CMD(button5);
KEY_CMD(button6);
KEY_CMD(button7);
KEY_CMD(button8);
KEY_CMD(use);
KEY_CMD(klook);
KEY_CMD(mlook);
KEY_CMD(speed);
Cmd_AddCommand("impulse", IN_Impulse);
}