Quake-III-Arena

Quake III Arena GPL Source Release
Log | Files | Refs

cl_input.c (23867B)


      1 /*
      2 ===========================================================================
      3 Copyright (C) 1999-2005 Id Software, Inc.
      4 
      5 This file is part of Quake III Arena source code.
      6 
      7 Quake III Arena source code is free software; you can redistribute it
      8 and/or modify it under the terms of the GNU General Public License as
      9 published by the Free Software Foundation; either version 2 of the License,
     10 or (at your option) any later version.
     11 
     12 Quake III Arena source code is distributed in the hope that it will be
     13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 GNU General Public License for more details.
     16 
     17 You should have received a copy of the GNU General Public License
     18 along with Foobar; if not, write to the Free Software
     19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     20 ===========================================================================
     21 */
     22 // cl.input.c  -- builds an intended movement command to send to the server
     23 
     24 #include "client.h"
     25 
     26 unsigned	frame_msec;
     27 int			old_com_frameTime;
     28 
     29 /*
     30 ===============================================================================
     31 
     32 KEY BUTTONS
     33 
     34 Continuous button event tracking is complicated by the fact that two different
     35 input sources (say, mouse button 1 and the control key) can both press the
     36 same button, but the button should only be released when both of the
     37 pressing key have been released.
     38 
     39 When a key event issues a button command (+forward, +attack, etc), it appends
     40 its key number as argv(1) so it can be matched up with the release.
     41 
     42 argv(2) will be set to the time the event happened, which allows exact
     43 control even at low framerates when the down and up events may both get qued
     44 at the same time.
     45 
     46 ===============================================================================
     47 */
     48 
     49 
     50 kbutton_t	in_left, in_right, in_forward, in_back;
     51 kbutton_t	in_lookup, in_lookdown, in_moveleft, in_moveright;
     52 kbutton_t	in_strafe, in_speed;
     53 kbutton_t	in_up, in_down;
     54 
     55 kbutton_t	in_buttons[16];
     56 
     57 
     58 qboolean	in_mlooking;
     59 
     60 
     61 void IN_MLookDown( void ) {
     62 	in_mlooking = qtrue;
     63 }
     64 
     65 void IN_MLookUp( void ) {
     66 	in_mlooking = qfalse;
     67 	if ( !cl_freelook->integer ) {
     68 		IN_CenterView ();
     69 	}
     70 }
     71 
     72 void IN_KeyDown( kbutton_t *b ) {
     73 	int		k;
     74 	char	*c;
     75 	
     76 	c = Cmd_Argv(1);
     77 	if ( c[0] ) {
     78 		k = atoi(c);
     79 	} else {
     80 		k = -1;		// typed manually at the console for continuous down
     81 	}
     82 
     83 	if ( k == b->down[0] || k == b->down[1] ) {
     84 		return;		// repeating key
     85 	}
     86 	
     87 	if ( !b->down[0] ) {
     88 		b->down[0] = k;
     89 	} else if ( !b->down[1] ) {
     90 		b->down[1] = k;
     91 	} else {
     92 		Com_Printf ("Three keys down for a button!\n");
     93 		return;
     94 	}
     95 	
     96 	if ( b->active ) {
     97 		return;		// still down
     98 	}
     99 
    100 	// save timestamp for partial frame summing
    101 	c = Cmd_Argv(2);
    102 	b->downtime = atoi(c);
    103 
    104 	b->active = qtrue;
    105 	b->wasPressed = qtrue;
    106 }
    107 
    108 void IN_KeyUp( kbutton_t *b ) {
    109 	int		k;
    110 	char	*c;
    111 	unsigned	uptime;
    112 
    113 	c = Cmd_Argv(1);
    114 	if ( c[0] ) {
    115 		k = atoi(c);
    116 	} else {
    117 		// typed manually at the console, assume for unsticking, so clear all
    118 		b->down[0] = b->down[1] = 0;
    119 		b->active = qfalse;
    120 		return;
    121 	}
    122 
    123 	if ( b->down[0] == k ) {
    124 		b->down[0] = 0;
    125 	} else if ( b->down[1] == k ) {
    126 		b->down[1] = 0;
    127 	} else {
    128 		return;		// key up without coresponding down (menu pass through)
    129 	}
    130 	if ( b->down[0] || b->down[1] ) {
    131 		return;		// some other key is still holding it down
    132 	}
    133 
    134 	b->active = qfalse;
    135 
    136 	// save timestamp for partial frame summing
    137 	c = Cmd_Argv(2);
    138 	uptime = atoi(c);
    139 	if ( uptime ) {
    140 		b->msec += uptime - b->downtime;
    141 	} else {
    142 		b->msec += frame_msec / 2;
    143 	}
    144 
    145 	b->active = qfalse;
    146 }
    147 
    148 
    149 
    150 /*
    151 ===============
    152 CL_KeyState
    153 
    154 Returns the fraction of the frame that the key was down
    155 ===============
    156 */
    157 float CL_KeyState( kbutton_t *key ) {
    158 	float		val;
    159 	int			msec;
    160 
    161 	msec = key->msec;
    162 	key->msec = 0;
    163 
    164 	if ( key->active ) {
    165 		// still down
    166 		if ( !key->downtime ) {
    167 			msec = com_frameTime;
    168 		} else {
    169 			msec += com_frameTime - key->downtime;
    170 		}
    171 		key->downtime = com_frameTime;
    172 	}
    173 
    174 #if 0
    175 	if (msec) {
    176 		Com_Printf ("%i ", msec);
    177 	}
    178 #endif
    179 
    180 	val = (float)msec / frame_msec;
    181 	if ( val < 0 ) {
    182 		val = 0;
    183 	}
    184 	if ( val > 1 ) {
    185 		val = 1;
    186 	}
    187 
    188 	return val;
    189 }
    190 
    191 
    192 
    193 void IN_UpDown(void) {IN_KeyDown(&in_up);}
    194 void IN_UpUp(void) {IN_KeyUp(&in_up);}
    195 void IN_DownDown(void) {IN_KeyDown(&in_down);}
    196 void IN_DownUp(void) {IN_KeyUp(&in_down);}
    197 void IN_LeftDown(void) {IN_KeyDown(&in_left);}
    198 void IN_LeftUp(void) {IN_KeyUp(&in_left);}
    199 void IN_RightDown(void) {IN_KeyDown(&in_right);}
    200 void IN_RightUp(void) {IN_KeyUp(&in_right);}
    201 void IN_ForwardDown(void) {IN_KeyDown(&in_forward);}
    202 void IN_ForwardUp(void) {IN_KeyUp(&in_forward);}
    203 void IN_BackDown(void) {IN_KeyDown(&in_back);}
    204 void IN_BackUp(void) {IN_KeyUp(&in_back);}
    205 void IN_LookupDown(void) {IN_KeyDown(&in_lookup);}
    206 void IN_LookupUp(void) {IN_KeyUp(&in_lookup);}
    207 void IN_LookdownDown(void) {IN_KeyDown(&in_lookdown);}
    208 void IN_LookdownUp(void) {IN_KeyUp(&in_lookdown);}
    209 void IN_MoveleftDown(void) {IN_KeyDown(&in_moveleft);}
    210 void IN_MoveleftUp(void) {IN_KeyUp(&in_moveleft);}
    211 void IN_MoverightDown(void) {IN_KeyDown(&in_moveright);}
    212 void IN_MoverightUp(void) {IN_KeyUp(&in_moveright);}
    213 
    214 void IN_SpeedDown(void) {IN_KeyDown(&in_speed);}
    215 void IN_SpeedUp(void) {IN_KeyUp(&in_speed);}
    216 void IN_StrafeDown(void) {IN_KeyDown(&in_strafe);}
    217 void IN_StrafeUp(void) {IN_KeyUp(&in_strafe);}
    218 
    219 void IN_Button0Down(void) {IN_KeyDown(&in_buttons[0]);}
    220 void IN_Button0Up(void) {IN_KeyUp(&in_buttons[0]);}
    221 void IN_Button1Down(void) {IN_KeyDown(&in_buttons[1]);}
    222 void IN_Button1Up(void) {IN_KeyUp(&in_buttons[1]);}
    223 void IN_Button2Down(void) {IN_KeyDown(&in_buttons[2]);}
    224 void IN_Button2Up(void) {IN_KeyUp(&in_buttons[2]);}
    225 void IN_Button3Down(void) {IN_KeyDown(&in_buttons[3]);}
    226 void IN_Button3Up(void) {IN_KeyUp(&in_buttons[3]);}
    227 void IN_Button4Down(void) {IN_KeyDown(&in_buttons[4]);}
    228 void IN_Button4Up(void) {IN_KeyUp(&in_buttons[4]);}
    229 void IN_Button5Down(void) {IN_KeyDown(&in_buttons[5]);}
    230 void IN_Button5Up(void) {IN_KeyUp(&in_buttons[5]);}
    231 void IN_Button6Down(void) {IN_KeyDown(&in_buttons[6]);}
    232 void IN_Button6Up(void) {IN_KeyUp(&in_buttons[6]);}
    233 void IN_Button7Down(void) {IN_KeyDown(&in_buttons[7]);}
    234 void IN_Button7Up(void) {IN_KeyUp(&in_buttons[7]);}
    235 void IN_Button8Down(void) {IN_KeyDown(&in_buttons[8]);}
    236 void IN_Button8Up(void) {IN_KeyUp(&in_buttons[8]);}
    237 void IN_Button9Down(void) {IN_KeyDown(&in_buttons[9]);}
    238 void IN_Button9Up(void) {IN_KeyUp(&in_buttons[9]);}
    239 void IN_Button10Down(void) {IN_KeyDown(&in_buttons[10]);}
    240 void IN_Button10Up(void) {IN_KeyUp(&in_buttons[10]);}
    241 void IN_Button11Down(void) {IN_KeyDown(&in_buttons[11]);}
    242 void IN_Button11Up(void) {IN_KeyUp(&in_buttons[11]);}
    243 void IN_Button12Down(void) {IN_KeyDown(&in_buttons[12]);}
    244 void IN_Button12Up(void) {IN_KeyUp(&in_buttons[12]);}
    245 void IN_Button13Down(void) {IN_KeyDown(&in_buttons[13]);}
    246 void IN_Button13Up(void) {IN_KeyUp(&in_buttons[13]);}
    247 void IN_Button14Down(void) {IN_KeyDown(&in_buttons[14]);}
    248 void IN_Button14Up(void) {IN_KeyUp(&in_buttons[14]);}
    249 void IN_Button15Down(void) {IN_KeyDown(&in_buttons[15]);}
    250 void IN_Button15Up(void) {IN_KeyUp(&in_buttons[15]);}
    251 
    252 void IN_ButtonDown (void) {
    253 	IN_KeyDown(&in_buttons[1]);}
    254 void IN_ButtonUp (void) {
    255 	IN_KeyUp(&in_buttons[1]);}
    256 
    257 void IN_CenterView (void) {
    258 	cl.viewangles[PITCH] = -SHORT2ANGLE(cl.snap.ps.delta_angles[PITCH]);
    259 }
    260 
    261 
    262 //==========================================================================
    263 
    264 cvar_t	*cl_upspeed;
    265 cvar_t	*cl_forwardspeed;
    266 cvar_t	*cl_sidespeed;
    267 
    268 cvar_t	*cl_yawspeed;
    269 cvar_t	*cl_pitchspeed;
    270 
    271 cvar_t	*cl_run;
    272 
    273 cvar_t	*cl_anglespeedkey;
    274 
    275 
    276 /*
    277 ================
    278 CL_AdjustAngles
    279 
    280 Moves the local angle positions
    281 ================
    282 */
    283 void CL_AdjustAngles( void ) {
    284 	float	speed;
    285 	
    286 	if ( in_speed.active ) {
    287 		speed = 0.001 * cls.frametime * cl_anglespeedkey->value;
    288 	} else {
    289 		speed = 0.001 * cls.frametime;
    290 	}
    291 
    292 	if ( !in_strafe.active ) {
    293 		cl.viewangles[YAW] -= speed*cl_yawspeed->value*CL_KeyState (&in_right);
    294 		cl.viewangles[YAW] += speed*cl_yawspeed->value*CL_KeyState (&in_left);
    295 	}
    296 
    297 	cl.viewangles[PITCH] -= speed*cl_pitchspeed->value * CL_KeyState (&in_lookup);
    298 	cl.viewangles[PITCH] += speed*cl_pitchspeed->value * CL_KeyState (&in_lookdown);
    299 }
    300 
    301 /*
    302 ================
    303 CL_KeyMove
    304 
    305 Sets the usercmd_t based on key states
    306 ================
    307 */
    308 void CL_KeyMove( usercmd_t *cmd ) {
    309 	int		movespeed;
    310 	int		forward, side, up;
    311 
    312 	//
    313 	// adjust for speed key / running
    314 	// the walking flag is to keep animations consistant
    315 	// even during acceleration and develeration
    316 	//
    317 	if ( in_speed.active ^ cl_run->integer ) {
    318 		movespeed = 127;
    319 		cmd->buttons &= ~BUTTON_WALKING;
    320 	} else {
    321 		cmd->buttons |= BUTTON_WALKING;
    322 		movespeed = 64;
    323 	}
    324 
    325 	forward = 0;
    326 	side = 0;
    327 	up = 0;
    328 	if ( in_strafe.active ) {
    329 		side += movespeed * CL_KeyState (&in_right);
    330 		side -= movespeed * CL_KeyState (&in_left);
    331 	}
    332 
    333 	side += movespeed * CL_KeyState (&in_moveright);
    334 	side -= movespeed * CL_KeyState (&in_moveleft);
    335 
    336 
    337 	up += movespeed * CL_KeyState (&in_up);
    338 	up -= movespeed * CL_KeyState (&in_down);
    339 
    340 	forward += movespeed * CL_KeyState (&in_forward);
    341 	forward -= movespeed * CL_KeyState (&in_back);
    342 
    343 	cmd->forwardmove = ClampChar( forward );
    344 	cmd->rightmove = ClampChar( side );
    345 	cmd->upmove = ClampChar( up );
    346 }
    347 
    348 /*
    349 =================
    350 CL_MouseEvent
    351 =================
    352 */
    353 void CL_MouseEvent( int dx, int dy, int time ) {
    354 	if ( cls.keyCatchers & KEYCATCH_UI ) {
    355 		VM_Call( uivm, UI_MOUSE_EVENT, dx, dy );
    356 	} else if (cls.keyCatchers & KEYCATCH_CGAME) {
    357 		VM_Call (cgvm, CG_MOUSE_EVENT, dx, dy);
    358 	} else {
    359 		cl.mouseDx[cl.mouseIndex] += dx;
    360 		cl.mouseDy[cl.mouseIndex] += dy;
    361 	}
    362 }
    363 
    364 /*
    365 =================
    366 CL_JoystickEvent
    367 
    368 Joystick values stay set until changed
    369 =================
    370 */
    371 void CL_JoystickEvent( int axis, int value, int time ) {
    372 	if ( axis < 0 || axis >= MAX_JOYSTICK_AXIS ) {
    373 		Com_Error( ERR_DROP, "CL_JoystickEvent: bad axis %i", axis );
    374 	}
    375 	cl.joystickAxis[axis] = value;
    376 }
    377 
    378 /*
    379 =================
    380 CL_JoystickMove
    381 =================
    382 */
    383 void CL_JoystickMove( usercmd_t *cmd ) {
    384 	int		movespeed;
    385 	float	anglespeed;
    386 
    387 	if ( in_speed.active ^ cl_run->integer ) {
    388 		movespeed = 2;
    389 	} else {
    390 		movespeed = 1;
    391 		cmd->buttons |= BUTTON_WALKING;
    392 	}
    393 
    394 	if ( in_speed.active ) {
    395 		anglespeed = 0.001 * cls.frametime * cl_anglespeedkey->value;
    396 	} else {
    397 		anglespeed = 0.001 * cls.frametime;
    398 	}
    399 
    400 	if ( !in_strafe.active ) {
    401 		cl.viewangles[YAW] += anglespeed * cl_yawspeed->value * cl.joystickAxis[AXIS_SIDE];
    402 	} else {
    403 		cmd->rightmove = ClampChar( cmd->rightmove + cl.joystickAxis[AXIS_SIDE] );
    404 	}
    405 
    406 	if ( in_mlooking ) {
    407 		cl.viewangles[PITCH] += anglespeed * cl_pitchspeed->value * cl.joystickAxis[AXIS_FORWARD];
    408 	} else {
    409 		cmd->forwardmove = ClampChar( cmd->forwardmove + cl.joystickAxis[AXIS_FORWARD] );
    410 	}
    411 
    412 	cmd->upmove = ClampChar( cmd->upmove + cl.joystickAxis[AXIS_UP] );
    413 }
    414 
    415 /*
    416 =================
    417 CL_MouseMove
    418 =================
    419 */
    420 void CL_MouseMove( usercmd_t *cmd ) {
    421 	float	mx, my;
    422 	float	accelSensitivity;
    423 	float	rate;
    424 
    425 	// allow mouse smoothing
    426 	if ( m_filter->integer ) {
    427 		mx = ( cl.mouseDx[0] + cl.mouseDx[1] ) * 0.5;
    428 		my = ( cl.mouseDy[0] + cl.mouseDy[1] ) * 0.5;
    429 	} else {
    430 		mx = cl.mouseDx[cl.mouseIndex];
    431 		my = cl.mouseDy[cl.mouseIndex];
    432 	}
    433 	cl.mouseIndex ^= 1;
    434 	cl.mouseDx[cl.mouseIndex] = 0;
    435 	cl.mouseDy[cl.mouseIndex] = 0;
    436 
    437 	rate = sqrt( mx * mx + my * my ) / (float)frame_msec;
    438 	accelSensitivity = cl_sensitivity->value + rate * cl_mouseAccel->value;
    439 
    440 	// scale by FOV
    441 	accelSensitivity *= cl.cgameSensitivity;
    442 
    443 	if ( rate && cl_showMouseRate->integer ) {
    444 		Com_Printf( "%f : %f\n", rate, accelSensitivity );
    445 	}
    446 
    447 	mx *= accelSensitivity;
    448 	my *= accelSensitivity;
    449 
    450 	if (!mx && !my) {
    451 		return;
    452 	}
    453 
    454 	// add mouse X/Y movement to cmd
    455 	if ( in_strafe.active ) {
    456 		cmd->rightmove = ClampChar( cmd->rightmove + m_side->value * mx );
    457 	} else {
    458 		cl.viewangles[YAW] -= m_yaw->value * mx;
    459 	}
    460 
    461 	if ( (in_mlooking || cl_freelook->integer) && !in_strafe.active ) {
    462 		cl.viewangles[PITCH] += m_pitch->value * my;
    463 	} else {
    464 		cmd->forwardmove = ClampChar( cmd->forwardmove - m_forward->value * my );
    465 	}
    466 }
    467 
    468 
    469 /*
    470 ==============
    471 CL_CmdButtons
    472 ==============
    473 */
    474 void CL_CmdButtons( usercmd_t *cmd ) {
    475 	int		i;
    476 
    477 	//
    478 	// figure button bits
    479 	// send a button bit even if the key was pressed and released in
    480 	// less than a frame
    481 	//	
    482 	for (i = 0 ; i < 15 ; i++) {
    483 		if ( in_buttons[i].active || in_buttons[i].wasPressed ) {
    484 			cmd->buttons |= 1 << i;
    485 		}
    486 		in_buttons[i].wasPressed = qfalse;
    487 	}
    488 
    489 	if ( cls.keyCatchers ) {
    490 		cmd->buttons |= BUTTON_TALK;
    491 	}
    492 
    493 	// allow the game to know if any key at all is
    494 	// currently pressed, even if it isn't bound to anything
    495 	if ( anykeydown && !cls.keyCatchers ) {
    496 		cmd->buttons |= BUTTON_ANY;
    497 	}
    498 }
    499 
    500 
    501 /*
    502 ==============
    503 CL_FinishMove
    504 ==============
    505 */
    506 void CL_FinishMove( usercmd_t *cmd ) {
    507 	int		i;
    508 
    509 	// copy the state that the cgame is currently sending
    510 	cmd->weapon = cl.cgameUserCmdValue;
    511 
    512 	// send the current server time so the amount of movement
    513 	// can be determined without allowing cheating
    514 	cmd->serverTime = cl.serverTime;
    515 
    516 	for (i=0 ; i<3 ; i++) {
    517 		cmd->angles[i] = ANGLE2SHORT(cl.viewangles[i]);
    518 	}
    519 }
    520 
    521 
    522 /*
    523 =================
    524 CL_CreateCmd
    525 =================
    526 */
    527 usercmd_t CL_CreateCmd( void ) {
    528 	usercmd_t	cmd;
    529 	vec3_t		oldAngles;
    530 
    531 	VectorCopy( cl.viewangles, oldAngles );
    532 
    533 	// keyboard angle adjustment
    534 	CL_AdjustAngles ();
    535 	
    536 	Com_Memset( &cmd, 0, sizeof( cmd ) );
    537 
    538 	CL_CmdButtons( &cmd );
    539 
    540 	// get basic movement from keyboard
    541 	CL_KeyMove( &cmd );
    542 
    543 	// get basic movement from mouse
    544 	CL_MouseMove( &cmd );
    545 
    546 	// get basic movement from joystick
    547 	CL_JoystickMove( &cmd );
    548 
    549 	// check to make sure the angles haven't wrapped
    550 	if ( cl.viewangles[PITCH] - oldAngles[PITCH] > 90 ) {
    551 		cl.viewangles[PITCH] = oldAngles[PITCH] + 90;
    552 	} else if ( oldAngles[PITCH] - cl.viewangles[PITCH] > 90 ) {
    553 		cl.viewangles[PITCH] = oldAngles[PITCH] - 90;
    554 	} 
    555 
    556 	// store out the final values
    557 	CL_FinishMove( &cmd );
    558 
    559 	// draw debug graphs of turning for mouse testing
    560 	if ( cl_debugMove->integer ) {
    561 		if ( cl_debugMove->integer == 1 ) {
    562 			SCR_DebugGraph( abs(cl.viewangles[YAW] - oldAngles[YAW]), 0 );
    563 		}
    564 		if ( cl_debugMove->integer == 2 ) {
    565 			SCR_DebugGraph( abs(cl.viewangles[PITCH] - oldAngles[PITCH]), 0 );
    566 		}
    567 	}
    568 
    569 	return cmd;
    570 }
    571 
    572 
    573 /*
    574 =================
    575 CL_CreateNewCommands
    576 
    577 Create a new usercmd_t structure for this frame
    578 =================
    579 */
    580 void CL_CreateNewCommands( void ) {
    581 	usercmd_t	*cmd;
    582 	int			cmdNum;
    583 
    584 	// no need to create usercmds until we have a gamestate
    585 	if ( cls.state < CA_PRIMED ) {
    586 		return;
    587 	}
    588 
    589 	frame_msec = com_frameTime - old_com_frameTime;
    590 
    591 	// if running less than 5fps, truncate the extra time to prevent
    592 	// unexpected moves after a hitch
    593 	if ( frame_msec > 200 ) {
    594 		frame_msec = 200;
    595 	}
    596 	old_com_frameTime = com_frameTime;
    597 
    598 
    599 	// generate a command for this frame
    600 	cl.cmdNumber++;
    601 	cmdNum = cl.cmdNumber & CMD_MASK;
    602 	cl.cmds[cmdNum] = CL_CreateCmd ();
    603 	cmd = &cl.cmds[cmdNum];
    604 }
    605 
    606 /*
    607 =================
    608 CL_ReadyToSendPacket
    609 
    610 Returns qfalse if we are over the maxpackets limit
    611 and should choke back the bandwidth a bit by not sending
    612 a packet this frame.  All the commands will still get
    613 delivered in the next packet, but saving a header and
    614 getting more delta compression will reduce total bandwidth.
    615 =================
    616 */
    617 qboolean CL_ReadyToSendPacket( void ) {
    618 	int		oldPacketNum;
    619 	int		delta;
    620 
    621 	// don't send anything if playing back a demo
    622 	if ( clc.demoplaying || cls.state == CA_CINEMATIC ) {
    623 		return qfalse;
    624 	}
    625 
    626 	// If we are downloading, we send no less than 50ms between packets
    627 	if ( *clc.downloadTempName &&
    628 		cls.realtime - clc.lastPacketSentTime < 50 ) {
    629 		return qfalse;
    630 	}
    631 
    632 	// if we don't have a valid gamestate yet, only send
    633 	// one packet a second
    634 	if ( cls.state != CA_ACTIVE && 
    635 		cls.state != CA_PRIMED && 
    636 		!*clc.downloadTempName &&
    637 		cls.realtime - clc.lastPacketSentTime < 1000 ) {
    638 		return qfalse;
    639 	}
    640 
    641 	// send every frame for loopbacks
    642 	if ( clc.netchan.remoteAddress.type == NA_LOOPBACK ) {
    643 		return qtrue;
    644 	}
    645 
    646 	// send every frame for LAN
    647 	if ( Sys_IsLANAddress( clc.netchan.remoteAddress ) ) {
    648 		return qtrue;
    649 	}
    650 
    651 	// check for exceeding cl_maxpackets
    652 	if ( cl_maxpackets->integer < 15 ) {
    653 		Cvar_Set( "cl_maxpackets", "15" );
    654 	} else if ( cl_maxpackets->integer > 125 ) {
    655 		Cvar_Set( "cl_maxpackets", "125" );
    656 	}
    657 	oldPacketNum = (clc.netchan.outgoingSequence - 1) & PACKET_MASK;
    658 	delta = cls.realtime -  cl.outPackets[ oldPacketNum ].p_realtime;
    659 	if ( delta < 1000 / cl_maxpackets->integer ) {
    660 		// the accumulated commands will go out in the next packet
    661 		return qfalse;
    662 	}
    663 
    664 	return qtrue;
    665 }
    666 
    667 /*
    668 ===================
    669 CL_WritePacket
    670 
    671 Create and send the command packet to the server
    672 Including both the reliable commands and the usercmds
    673 
    674 During normal gameplay, a client packet will contain something like:
    675 
    676 4	sequence number
    677 2	qport
    678 4	serverid
    679 4	acknowledged sequence number
    680 4	clc.serverCommandSequence
    681 <optional reliable commands>
    682 1	clc_move or clc_moveNoDelta
    683 1	command count
    684 <count * usercmds>
    685 
    686 ===================
    687 */
    688 void CL_WritePacket( void ) {
    689 	msg_t		buf;
    690 	byte		data[MAX_MSGLEN];
    691 	int			i, j;
    692 	usercmd_t	*cmd, *oldcmd;
    693 	usercmd_t	nullcmd;
    694 	int			packetNum;
    695 	int			oldPacketNum;
    696 	int			count, key;
    697 
    698 	// don't send anything if playing back a demo
    699 	if ( clc.demoplaying || cls.state == CA_CINEMATIC ) {
    700 		return;
    701 	}
    702 
    703 	Com_Memset( &nullcmd, 0, sizeof(nullcmd) );
    704 	oldcmd = &nullcmd;
    705 
    706 	MSG_Init( &buf, data, sizeof(data) );
    707 
    708 	MSG_Bitstream( &buf );
    709 	// write the current serverId so the server
    710 	// can tell if this is from the current gameState
    711 	MSG_WriteLong( &buf, cl.serverId );
    712 
    713 	// write the last message we received, which can
    714 	// be used for delta compression, and is also used
    715 	// to tell if we dropped a gamestate
    716 	MSG_WriteLong( &buf, clc.serverMessageSequence );
    717 
    718 	// write the last reliable message we received
    719 	MSG_WriteLong( &buf, clc.serverCommandSequence );
    720 
    721 	// write any unacknowledged clientCommands
    722 	for ( i = clc.reliableAcknowledge + 1 ; i <= clc.reliableSequence ; i++ ) {
    723 		MSG_WriteByte( &buf, clc_clientCommand );
    724 		MSG_WriteLong( &buf, i );
    725 		MSG_WriteString( &buf, clc.reliableCommands[ i & (MAX_RELIABLE_COMMANDS-1) ] );
    726 	}
    727 
    728 	// we want to send all the usercmds that were generated in the last
    729 	// few packet, so even if a couple packets are dropped in a row,
    730 	// all the cmds will make it to the server
    731 	if ( cl_packetdup->integer < 0 ) {
    732 		Cvar_Set( "cl_packetdup", "0" );
    733 	} else if ( cl_packetdup->integer > 5 ) {
    734 		Cvar_Set( "cl_packetdup", "5" );
    735 	}
    736 	oldPacketNum = (clc.netchan.outgoingSequence - 1 - cl_packetdup->integer) & PACKET_MASK;
    737 	count = cl.cmdNumber - cl.outPackets[ oldPacketNum ].p_cmdNumber;
    738 	if ( count > MAX_PACKET_USERCMDS ) {
    739 		count = MAX_PACKET_USERCMDS;
    740 		Com_Printf("MAX_PACKET_USERCMDS\n");
    741 	}
    742 	if ( count >= 1 ) {
    743 		if ( cl_showSend->integer ) {
    744 			Com_Printf( "(%i)", count );
    745 		}
    746 
    747 		// begin a client move command
    748 		if ( cl_nodelta->integer || !cl.snap.valid || clc.demowaiting
    749 			|| clc.serverMessageSequence != cl.snap.messageNum ) {
    750 			MSG_WriteByte (&buf, clc_moveNoDelta);
    751 		} else {
    752 			MSG_WriteByte (&buf, clc_move);
    753 		}
    754 
    755 		// write the command count
    756 		MSG_WriteByte( &buf, count );
    757 
    758 		// use the checksum feed in the key
    759 		key = clc.checksumFeed;
    760 		// also use the message acknowledge
    761 		key ^= clc.serverMessageSequence;
    762 		// also use the last acknowledged server command in the key
    763 		key ^= Com_HashKey(clc.serverCommands[ clc.serverCommandSequence & (MAX_RELIABLE_COMMANDS-1) ], 32);
    764 
    765 		// write all the commands, including the predicted command
    766 		for ( i = 0 ; i < count ; i++ ) {
    767 			j = (cl.cmdNumber - count + i + 1) & CMD_MASK;
    768 			cmd = &cl.cmds[j];
    769 			MSG_WriteDeltaUsercmdKey (&buf, key, oldcmd, cmd);
    770 			oldcmd = cmd;
    771 		}
    772 	}
    773 
    774 	//
    775 	// deliver the message
    776 	//
    777 	packetNum = clc.netchan.outgoingSequence & PACKET_MASK;
    778 	cl.outPackets[ packetNum ].p_realtime = cls.realtime;
    779 	cl.outPackets[ packetNum ].p_serverTime = oldcmd->serverTime;
    780 	cl.outPackets[ packetNum ].p_cmdNumber = cl.cmdNumber;
    781 	clc.lastPacketSentTime = cls.realtime;
    782 
    783 	if ( cl_showSend->integer ) {
    784 		Com_Printf( "%i ", buf.cursize );
    785 	}
    786 
    787 	CL_Netchan_Transmit (&clc.netchan, &buf);	
    788 
    789 	// clients never really should have messages large enough
    790 	// to fragment, but in case they do, fire them all off
    791 	// at once
    792 	// TTimo: this causes a packet burst, which is bad karma for winsock
    793 	// added a WARNING message, we'll see if there are legit situations where this happens
    794 	while ( clc.netchan.unsentFragments ) {
    795 		Com_DPrintf( "WARNING: #462 unsent fragments (not supposed to happen!)\n" );
    796 		CL_Netchan_TransmitNextFragment( &clc.netchan );
    797 	}
    798 }
    799 
    800 /*
    801 =================
    802 CL_SendCmd
    803 
    804 Called every frame to builds and sends a command packet to the server.
    805 =================
    806 */
    807 void CL_SendCmd( void ) {
    808 	// don't send any message if not connected
    809 	if ( cls.state < CA_CONNECTED ) {
    810 		return;
    811 	}
    812 
    813 	// don't send commands if paused
    814 	if ( com_sv_running->integer && sv_paused->integer && cl_paused->integer ) {
    815 		return;
    816 	}
    817 
    818 	// we create commands even if a demo is playing,
    819 	CL_CreateNewCommands();
    820 
    821 	// don't send a packet if the last packet was sent too recently
    822 	if ( !CL_ReadyToSendPacket() ) {
    823 		if ( cl_showSend->integer ) {
    824 			Com_Printf( ". " );
    825 		}
    826 		return;
    827 	}
    828 
    829 	CL_WritePacket();
    830 }
    831 
    832 /*
    833 ============
    834 CL_InitInput
    835 ============
    836 */
    837 void CL_InitInput( void ) {
    838 	Cmd_AddCommand ("centerview",IN_CenterView);
    839 
    840 	Cmd_AddCommand ("+moveup",IN_UpDown);
    841 	Cmd_AddCommand ("-moveup",IN_UpUp);
    842 	Cmd_AddCommand ("+movedown",IN_DownDown);
    843 	Cmd_AddCommand ("-movedown",IN_DownUp);
    844 	Cmd_AddCommand ("+left",IN_LeftDown);
    845 	Cmd_AddCommand ("-left",IN_LeftUp);
    846 	Cmd_AddCommand ("+right",IN_RightDown);
    847 	Cmd_AddCommand ("-right",IN_RightUp);
    848 	Cmd_AddCommand ("+forward",IN_ForwardDown);
    849 	Cmd_AddCommand ("-forward",IN_ForwardUp);
    850 	Cmd_AddCommand ("+back",IN_BackDown);
    851 	Cmd_AddCommand ("-back",IN_BackUp);
    852 	Cmd_AddCommand ("+lookup", IN_LookupDown);
    853 	Cmd_AddCommand ("-lookup", IN_LookupUp);
    854 	Cmd_AddCommand ("+lookdown", IN_LookdownDown);
    855 	Cmd_AddCommand ("-lookdown", IN_LookdownUp);
    856 	Cmd_AddCommand ("+strafe", IN_StrafeDown);
    857 	Cmd_AddCommand ("-strafe", IN_StrafeUp);
    858 	Cmd_AddCommand ("+moveleft", IN_MoveleftDown);
    859 	Cmd_AddCommand ("-moveleft", IN_MoveleftUp);
    860 	Cmd_AddCommand ("+moveright", IN_MoverightDown);
    861 	Cmd_AddCommand ("-moveright", IN_MoverightUp);
    862 	Cmd_AddCommand ("+speed", IN_SpeedDown);
    863 	Cmd_AddCommand ("-speed", IN_SpeedUp);
    864 	Cmd_AddCommand ("+attack", IN_Button0Down);
    865 	Cmd_AddCommand ("-attack", IN_Button0Up);
    866 	Cmd_AddCommand ("+button0", IN_Button0Down);
    867 	Cmd_AddCommand ("-button0", IN_Button0Up);
    868 	Cmd_AddCommand ("+button1", IN_Button1Down);
    869 	Cmd_AddCommand ("-button1", IN_Button1Up);
    870 	Cmd_AddCommand ("+button2", IN_Button2Down);
    871 	Cmd_AddCommand ("-button2", IN_Button2Up);
    872 	Cmd_AddCommand ("+button3", IN_Button3Down);
    873 	Cmd_AddCommand ("-button3", IN_Button3Up);
    874 	Cmd_AddCommand ("+button4", IN_Button4Down);
    875 	Cmd_AddCommand ("-button4", IN_Button4Up);
    876 	Cmd_AddCommand ("+button5", IN_Button5Down);
    877 	Cmd_AddCommand ("-button5", IN_Button5Up);
    878 	Cmd_AddCommand ("+button6", IN_Button6Down);
    879 	Cmd_AddCommand ("-button6", IN_Button6Up);
    880 	Cmd_AddCommand ("+button7", IN_Button7Down);
    881 	Cmd_AddCommand ("-button7", IN_Button7Up);
    882 	Cmd_AddCommand ("+button8", IN_Button8Down);
    883 	Cmd_AddCommand ("-button8", IN_Button8Up);
    884 	Cmd_AddCommand ("+button9", IN_Button9Down);
    885 	Cmd_AddCommand ("-button9", IN_Button9Up);
    886 	Cmd_AddCommand ("+button10", IN_Button10Down);
    887 	Cmd_AddCommand ("-button10", IN_Button10Up);
    888 	Cmd_AddCommand ("+button11", IN_Button11Down);
    889 	Cmd_AddCommand ("-button11", IN_Button11Up);
    890 	Cmd_AddCommand ("+button12", IN_Button12Down);
    891 	Cmd_AddCommand ("-button12", IN_Button12Up);
    892 	Cmd_AddCommand ("+button13", IN_Button13Down);
    893 	Cmd_AddCommand ("-button13", IN_Button13Up);
    894 	Cmd_AddCommand ("+button14", IN_Button14Down);
    895 	Cmd_AddCommand ("-button14", IN_Button14Up);
    896 	Cmd_AddCommand ("+mlook", IN_MLookDown);
    897 	Cmd_AddCommand ("-mlook", IN_MLookUp);
    898 
    899 	cl_nodelta = Cvar_Get ("cl_nodelta", "0", 0);
    900 	cl_debugMove = Cvar_Get ("cl_debugMove", "0", 0);
    901 }