Quake-2

Quake 2 GPL Source Release
Log | Files | Refs

cl_input.c (12968B)


      1 /*
      2 Copyright (C) 1997-2001 Id Software, Inc.
      3 
      4 This program is free software; you can redistribute it and/or
      5 modify it under the terms of the GNU General Public License
      6 as published by the Free Software Foundation; either version 2
      7 of the License, or (at your option) any later version.
      8 
      9 This program is distributed in the hope that it will be useful,
     10 but WITHOUT ANY WARRANTY; without even the implied warranty of
     11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
     12 
     13 See the GNU General Public License for more details.
     14 
     15 You should have received a copy of the GNU General Public License
     16 along with this program; if not, write to the Free Software
     17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
     18 
     19 */
     20 // cl.input.c  -- builds an intended movement command to send to the server
     21 
     22 #include "client.h"
     23 
     24 cvar_t	*cl_nodelta;
     25 
     26 extern	unsigned	sys_frame_time;
     27 unsigned	frame_msec;
     28 unsigned	old_sys_frame_time;
     29 
     30 /*
     31 ===============================================================================
     32 
     33 KEY BUTTONS
     34 
     35 Continuous button event tracking is complicated by the fact that two different
     36 input sources (say, mouse button 1 and the control key) can both press the
     37 same button, but the button should only be released when both of the
     38 pressing key have been released.
     39 
     40 When a key event issues a button command (+forward, +attack, etc), it appends
     41 its key number as a parameter to the command so it can be matched up with
     42 the release.
     43 
     44 state bit 0 is the current state of the key
     45 state bit 1 is edge triggered on the up to down transition
     46 state bit 2 is edge triggered on the down to up transition
     47 
     48 
     49 Key_Event (int key, qboolean down, unsigned time);
     50 
     51   +mlook src time
     52 
     53 ===============================================================================
     54 */
     55 
     56 
     57 kbutton_t	in_klook;
     58 kbutton_t	in_left, in_right, in_forward, in_back;
     59 kbutton_t	in_lookup, in_lookdown, in_moveleft, in_moveright;
     60 kbutton_t	in_strafe, in_speed, in_use, in_attack;
     61 kbutton_t	in_up, in_down;
     62 
     63 int			in_impulse;
     64 
     65 
     66 void KeyDown (kbutton_t *b)
     67 {
     68 	int		k;
     69 	char	*c;
     70 	
     71 	c = Cmd_Argv(1);
     72 	if (c[0])
     73 		k = atoi(c);
     74 	else
     75 		k = -1;		// typed manually at the console for continuous down
     76 
     77 	if (k == b->down[0] || k == b->down[1])
     78 		return;		// repeating key
     79 	
     80 	if (!b->down[0])
     81 		b->down[0] = k;
     82 	else if (!b->down[1])
     83 		b->down[1] = k;
     84 	else
     85 	{
     86 		Com_Printf ("Three keys down for a button!\n");
     87 		return;
     88 	}
     89 	
     90 	if (b->state & 1)
     91 		return;		// still down
     92 
     93 	// save timestamp
     94 	c = Cmd_Argv(2);
     95 	b->downtime = atoi(c);
     96 	if (!b->downtime)
     97 		b->downtime = sys_frame_time - 100;
     98 
     99 	b->state |= 1 + 2;	// down + impulse down
    100 }
    101 
    102 void KeyUp (kbutton_t *b)
    103 {
    104 	int		k;
    105 	char	*c;
    106 	unsigned	uptime;
    107 
    108 	c = Cmd_Argv(1);
    109 	if (c[0])
    110 		k = atoi(c);
    111 	else
    112 	{ // typed manually at the console, assume for unsticking, so clear all
    113 		b->down[0] = b->down[1] = 0;
    114 		b->state = 4;	// impulse up
    115 		return;
    116 	}
    117 
    118 	if (b->down[0] == k)
    119 		b->down[0] = 0;
    120 	else if (b->down[1] == k)
    121 		b->down[1] = 0;
    122 	else
    123 		return;		// key up without coresponding down (menu pass through)
    124 	if (b->down[0] || b->down[1])
    125 		return;		// some other key is still holding it down
    126 
    127 	if (!(b->state & 1))
    128 		return;		// still up (this should not happen)
    129 
    130 	// save timestamp
    131 	c = Cmd_Argv(2);
    132 	uptime = atoi(c);
    133 	if (uptime)
    134 		b->msec += uptime - b->downtime;
    135 	else
    136 		b->msec += 10;
    137 
    138 	b->state &= ~1;		// now up
    139 	b->state |= 4; 		// impulse up
    140 }
    141 
    142 void IN_KLookDown (void) {KeyDown(&in_klook);}
    143 void IN_KLookUp (void) {KeyUp(&in_klook);}
    144 void IN_UpDown(void) {KeyDown(&in_up);}
    145 void IN_UpUp(void) {KeyUp(&in_up);}
    146 void IN_DownDown(void) {KeyDown(&in_down);}
    147 void IN_DownUp(void) {KeyUp(&in_down);}
    148 void IN_LeftDown(void) {KeyDown(&in_left);}
    149 void IN_LeftUp(void) {KeyUp(&in_left);}
    150 void IN_RightDown(void) {KeyDown(&in_right);}
    151 void IN_RightUp(void) {KeyUp(&in_right);}
    152 void IN_ForwardDown(void) {KeyDown(&in_forward);}
    153 void IN_ForwardUp(void) {KeyUp(&in_forward);}
    154 void IN_BackDown(void) {KeyDown(&in_back);}
    155 void IN_BackUp(void) {KeyUp(&in_back);}
    156 void IN_LookupDown(void) {KeyDown(&in_lookup);}
    157 void IN_LookupUp(void) {KeyUp(&in_lookup);}
    158 void IN_LookdownDown(void) {KeyDown(&in_lookdown);}
    159 void IN_LookdownUp(void) {KeyUp(&in_lookdown);}
    160 void IN_MoveleftDown(void) {KeyDown(&in_moveleft);}
    161 void IN_MoveleftUp(void) {KeyUp(&in_moveleft);}
    162 void IN_MoverightDown(void) {KeyDown(&in_moveright);}
    163 void IN_MoverightUp(void) {KeyUp(&in_moveright);}
    164 
    165 void IN_SpeedDown(void) {KeyDown(&in_speed);}
    166 void IN_SpeedUp(void) {KeyUp(&in_speed);}
    167 void IN_StrafeDown(void) {KeyDown(&in_strafe);}
    168 void IN_StrafeUp(void) {KeyUp(&in_strafe);}
    169 
    170 void IN_AttackDown(void) {KeyDown(&in_attack);}
    171 void IN_AttackUp(void) {KeyUp(&in_attack);}
    172 
    173 void IN_UseDown (void) {KeyDown(&in_use);}
    174 void IN_UseUp (void) {KeyUp(&in_use);}
    175 
    176 void IN_Impulse (void) {in_impulse=atoi(Cmd_Argv(1));}
    177 
    178 /*
    179 ===============
    180 CL_KeyState
    181 
    182 Returns the fraction of the frame that the key was down
    183 ===============
    184 */
    185 float CL_KeyState (kbutton_t *key)
    186 {
    187 	float		val;
    188 	int			msec;
    189 
    190 	key->state &= 1;		// clear impulses
    191 
    192 	msec = key->msec;
    193 	key->msec = 0;
    194 
    195 	if (key->state)
    196 	{	// still down
    197 		msec += sys_frame_time - key->downtime;
    198 		key->downtime = sys_frame_time;
    199 	}
    200 
    201 #if 0
    202 	if (msec)
    203 	{
    204 		Com_Printf ("%i ", msec);
    205 	}
    206 #endif
    207 
    208 	val = (float)msec / frame_msec;
    209 	if (val < 0)
    210 		val = 0;
    211 	if (val > 1)
    212 		val = 1;
    213 
    214 	return val;
    215 }
    216 
    217 
    218 
    219 
    220 //==========================================================================
    221 
    222 cvar_t	*cl_upspeed;
    223 cvar_t	*cl_forwardspeed;
    224 cvar_t	*cl_sidespeed;
    225 
    226 cvar_t	*cl_yawspeed;
    227 cvar_t	*cl_pitchspeed;
    228 
    229 cvar_t	*cl_run;
    230 
    231 cvar_t	*cl_anglespeedkey;
    232 
    233 
    234 /*
    235 ================
    236 CL_AdjustAngles
    237 
    238 Moves the local angle positions
    239 ================
    240 */
    241 void CL_AdjustAngles (void)
    242 {
    243 	float	speed;
    244 	float	up, down;
    245 	
    246 	if (in_speed.state & 1)
    247 		speed = cls.frametime * cl_anglespeedkey->value;
    248 	else
    249 		speed = cls.frametime;
    250 
    251 	if (!(in_strafe.state & 1))
    252 	{
    253 		cl.viewangles[YAW] -= speed*cl_yawspeed->value*CL_KeyState (&in_right);
    254 		cl.viewangles[YAW] += speed*cl_yawspeed->value*CL_KeyState (&in_left);
    255 	}
    256 	if (in_klook.state & 1)
    257 	{
    258 		cl.viewangles[PITCH] -= speed*cl_pitchspeed->value * CL_KeyState (&in_forward);
    259 		cl.viewangles[PITCH] += speed*cl_pitchspeed->value * CL_KeyState (&in_back);
    260 	}
    261 	
    262 	up = CL_KeyState (&in_lookup);
    263 	down = CL_KeyState(&in_lookdown);
    264 	
    265 	cl.viewangles[PITCH] -= speed*cl_pitchspeed->value * up;
    266 	cl.viewangles[PITCH] += speed*cl_pitchspeed->value * down;
    267 }
    268 
    269 /*
    270 ================
    271 CL_BaseMove
    272 
    273 Send the intended movement message to the server
    274 ================
    275 */
    276 void CL_BaseMove (usercmd_t *cmd)
    277 {	
    278 	CL_AdjustAngles ();
    279 	
    280 	memset (cmd, 0, sizeof(*cmd));
    281 	
    282 	VectorCopy (cl.viewangles, cmd->angles);
    283 	if (in_strafe.state & 1)
    284 	{
    285 		cmd->sidemove += cl_sidespeed->value * CL_KeyState (&in_right);
    286 		cmd->sidemove -= cl_sidespeed->value * CL_KeyState (&in_left);
    287 	}
    288 
    289 	cmd->sidemove += cl_sidespeed->value * CL_KeyState (&in_moveright);
    290 	cmd->sidemove -= cl_sidespeed->value * CL_KeyState (&in_moveleft);
    291 
    292 	cmd->upmove += cl_upspeed->value * CL_KeyState (&in_up);
    293 	cmd->upmove -= cl_upspeed->value * CL_KeyState (&in_down);
    294 
    295 	if (! (in_klook.state & 1) )
    296 	{	
    297 		cmd->forwardmove += cl_forwardspeed->value * CL_KeyState (&in_forward);
    298 		cmd->forwardmove -= cl_forwardspeed->value * CL_KeyState (&in_back);
    299 	}	
    300 
    301 //
    302 // adjust for speed key / running
    303 //
    304 	if ( (in_speed.state & 1) ^ (int)(cl_run->value) )
    305 	{
    306 		cmd->forwardmove *= 2;
    307 		cmd->sidemove *= 2;
    308 		cmd->upmove *= 2;
    309 	}	
    310 }
    311 
    312 void CL_ClampPitch (void)
    313 {
    314 	float	pitch;
    315 
    316 	pitch = SHORT2ANGLE(cl.frame.playerstate.pmove.delta_angles[PITCH]);
    317 	if (pitch > 180)
    318 		pitch -= 360;
    319 	if (cl.viewangles[PITCH] + pitch > 89)
    320 		cl.viewangles[PITCH] = 89 - pitch;
    321 	if (cl.viewangles[PITCH] + pitch < -89)
    322 		cl.viewangles[PITCH] = -89 - pitch;
    323 }
    324 
    325 /*
    326 ==============
    327 CL_FinishMove
    328 ==============
    329 */
    330 void CL_FinishMove (usercmd_t *cmd)
    331 {
    332 	int		ms;
    333 	int		i;
    334 
    335 //
    336 // figure button bits
    337 //	
    338 	if ( in_attack.state & 3 )
    339 		cmd->buttons |= BUTTON_ATTACK;
    340 	in_attack.state &= ~2;
    341 	
    342 	if (in_use.state & 3)
    343 		cmd->buttons |= BUTTON_USE;
    344 	in_use.state &= ~2;
    345 
    346 	if (anykeydown && cls.key_dest == key_game)
    347 		cmd->buttons |= BUTTON_ANY;
    348 
    349 	// send milliseconds of time to apply the move
    350 	ms = cls.frametime * 1000;
    351 	if (ms > 250)
    352 		ms = 100;		// time was unreasonable
    353 	cmd->msec = ms;
    354 
    355 	CL_ClampPitch ();
    356 	for (i=0 ; i<3 ; i++)
    357 		cmd->angles[i] = ANGLE2SHORT(cl.viewangles[i]);
    358 
    359 	cmd->impulse = in_impulse;
    360 	in_impulse = 0;
    361 
    362 // send the ambient light level at the player's current position
    363 	cmd->lightlevel = (byte)cl_lightlevel->value;
    364 }
    365 
    366 /*
    367 =================
    368 CL_CreateCmd
    369 =================
    370 */
    371 usercmd_t CL_CreateCmd (void)
    372 {
    373 	usercmd_t	cmd;
    374 
    375 	frame_msec = sys_frame_time - old_sys_frame_time;
    376 	if (frame_msec < 1)
    377 		frame_msec = 1;
    378 	if (frame_msec > 200)
    379 		frame_msec = 200;
    380 	
    381 	// get basic movement from keyboard
    382 	CL_BaseMove (&cmd);
    383 
    384 	// allow mice or other external controllers to add to the move
    385 	IN_Move (&cmd);
    386 
    387 	CL_FinishMove (&cmd);
    388 
    389 	old_sys_frame_time = sys_frame_time;
    390 
    391 //cmd.impulse = cls.framecount;
    392 
    393 	return cmd;
    394 }
    395 
    396 
    397 void IN_CenterView (void)
    398 {
    399 	cl.viewangles[PITCH] = -SHORT2ANGLE(cl.frame.playerstate.pmove.delta_angles[PITCH]);
    400 }
    401 
    402 /*
    403 ============
    404 CL_InitInput
    405 ============
    406 */
    407 void CL_InitInput (void)
    408 {
    409 	Cmd_AddCommand ("centerview",IN_CenterView);
    410 
    411 	Cmd_AddCommand ("+moveup",IN_UpDown);
    412 	Cmd_AddCommand ("-moveup",IN_UpUp);
    413 	Cmd_AddCommand ("+movedown",IN_DownDown);
    414 	Cmd_AddCommand ("-movedown",IN_DownUp);
    415 	Cmd_AddCommand ("+left",IN_LeftDown);
    416 	Cmd_AddCommand ("-left",IN_LeftUp);
    417 	Cmd_AddCommand ("+right",IN_RightDown);
    418 	Cmd_AddCommand ("-right",IN_RightUp);
    419 	Cmd_AddCommand ("+forward",IN_ForwardDown);
    420 	Cmd_AddCommand ("-forward",IN_ForwardUp);
    421 	Cmd_AddCommand ("+back",IN_BackDown);
    422 	Cmd_AddCommand ("-back",IN_BackUp);
    423 	Cmd_AddCommand ("+lookup", IN_LookupDown);
    424 	Cmd_AddCommand ("-lookup", IN_LookupUp);
    425 	Cmd_AddCommand ("+lookdown", IN_LookdownDown);
    426 	Cmd_AddCommand ("-lookdown", IN_LookdownUp);
    427 	Cmd_AddCommand ("+strafe", IN_StrafeDown);
    428 	Cmd_AddCommand ("-strafe", IN_StrafeUp);
    429 	Cmd_AddCommand ("+moveleft", IN_MoveleftDown);
    430 	Cmd_AddCommand ("-moveleft", IN_MoveleftUp);
    431 	Cmd_AddCommand ("+moveright", IN_MoverightDown);
    432 	Cmd_AddCommand ("-moveright", IN_MoverightUp);
    433 	Cmd_AddCommand ("+speed", IN_SpeedDown);
    434 	Cmd_AddCommand ("-speed", IN_SpeedUp);
    435 	Cmd_AddCommand ("+attack", IN_AttackDown);
    436 	Cmd_AddCommand ("-attack", IN_AttackUp);
    437 	Cmd_AddCommand ("+use", IN_UseDown);
    438 	Cmd_AddCommand ("-use", IN_UseUp);
    439 	Cmd_AddCommand ("impulse", IN_Impulse);
    440 	Cmd_AddCommand ("+klook", IN_KLookDown);
    441 	Cmd_AddCommand ("-klook", IN_KLookUp);
    442 
    443 	cl_nodelta = Cvar_Get ("cl_nodelta", "0", 0);
    444 }
    445 
    446 
    447 
    448 /*
    449 =================
    450 CL_SendCmd
    451 =================
    452 */
    453 void CL_SendCmd (void)
    454 {
    455 	sizebuf_t	buf;
    456 	byte		data[128];
    457 	int			i;
    458 	usercmd_t	*cmd, *oldcmd;
    459 	usercmd_t	nullcmd;
    460 	int			checksumIndex;
    461 
    462 	// build a command even if not connected
    463 
    464 	// save this command off for prediction
    465 	i = cls.netchan.outgoing_sequence & (CMD_BACKUP-1);
    466 	cmd = &cl.cmds[i];
    467 	cl.cmd_time[i] = cls.realtime;	// for netgraph ping calculation
    468 
    469 	*cmd = CL_CreateCmd ();
    470 
    471 	cl.cmd = *cmd;
    472 
    473 	if (cls.state == ca_disconnected || cls.state == ca_connecting)
    474 		return;
    475 
    476 	if ( cls.state == ca_connected)
    477 	{
    478 		if (cls.netchan.message.cursize	|| curtime - cls.netchan.last_sent > 1000 )
    479 			Netchan_Transmit (&cls.netchan, 0, buf.data);	
    480 		return;
    481 	}
    482 
    483 	// send a userinfo update if needed
    484 	if (userinfo_modified)
    485 	{
    486 		CL_FixUpGender();
    487 		userinfo_modified = false;
    488 		MSG_WriteByte (&cls.netchan.message, clc_userinfo);
    489 		MSG_WriteString (&cls.netchan.message, Cvar_Userinfo() );
    490 	}
    491 
    492 	SZ_Init (&buf, data, sizeof(data));
    493 
    494 	if (cmd->buttons && cl.cinematictime > 0 && !cl.attractloop 
    495 		&& cls.realtime - cl.cinematictime > 1000)
    496 	{	// skip the rest of the cinematic
    497 		SCR_FinishCinematic ();
    498 	}
    499 
    500 	// begin a client move command
    501 	MSG_WriteByte (&buf, clc_move);
    502 
    503 	// save the position for a checksum byte
    504 	checksumIndex = buf.cursize;
    505 	MSG_WriteByte (&buf, 0);
    506 
    507 	// let the server know what the last frame we
    508 	// got was, so the next message can be delta compressed
    509 	if (cl_nodelta->value || !cl.frame.valid || cls.demowaiting)
    510 		MSG_WriteLong (&buf, -1);	// no compression
    511 	else
    512 		MSG_WriteLong (&buf, cl.frame.serverframe);
    513 
    514 	// send this and the previous cmds in the message, so
    515 	// if the last packet was dropped, it can be recovered
    516 	i = (cls.netchan.outgoing_sequence-2) & (CMD_BACKUP-1);
    517 	cmd = &cl.cmds[i];
    518 	memset (&nullcmd, 0, sizeof(nullcmd));
    519 	MSG_WriteDeltaUsercmd (&buf, &nullcmd, cmd);
    520 	oldcmd = cmd;
    521 
    522 	i = (cls.netchan.outgoing_sequence-1) & (CMD_BACKUP-1);
    523 	cmd = &cl.cmds[i];
    524 	MSG_WriteDeltaUsercmd (&buf, oldcmd, cmd);
    525 	oldcmd = cmd;
    526 
    527 	i = (cls.netchan.outgoing_sequence) & (CMD_BACKUP-1);
    528 	cmd = &cl.cmds[i];
    529 	MSG_WriteDeltaUsercmd (&buf, oldcmd, cmd);
    530 
    531 	// calculate a checksum over the move commands
    532 	buf.data[checksumIndex] = COM_BlockSequenceCRCByte(
    533 		buf.data + checksumIndex + 1, buf.cursize - checksumIndex - 1,
    534 		cls.netchan.outgoing_sequence);
    535 
    536 	//
    537 	// deliver the message
    538 	//
    539 	Netchan_Transmit (&cls.netchan, buf.cursize, buf.data);	
    540 }
    541 
    542