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 Quake III Arena source code; 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 
IN_MLookDown(void)61 void IN_MLookDown( void ) {
62 	in_mlooking = qtrue;
63 }
64 
IN_MLookUp(void)65 void IN_MLookUp( void ) {
66 	in_mlooking = qfalse;
67 	if ( !cl_freelook->integer ) {
68 		IN_CenterView ();
69 	}
70 }
71 
IN_KeyDown(kbutton_t * b)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 
IN_KeyUp(kbutton_t * b)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 */
CL_KeyState(kbutton_t * key)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 
IN_UpDown(void)193 void IN_UpDown(void) {IN_KeyDown(&in_up);}
IN_UpUp(void)194 void IN_UpUp(void) {IN_KeyUp(&in_up);}
IN_DownDown(void)195 void IN_DownDown(void) {IN_KeyDown(&in_down);}
IN_DownUp(void)196 void IN_DownUp(void) {IN_KeyUp(&in_down);}
IN_LeftDown(void)197 void IN_LeftDown(void) {IN_KeyDown(&in_left);}
IN_LeftUp(void)198 void IN_LeftUp(void) {IN_KeyUp(&in_left);}
IN_RightDown(void)199 void IN_RightDown(void) {IN_KeyDown(&in_right);}
IN_RightUp(void)200 void IN_RightUp(void) {IN_KeyUp(&in_right);}
IN_ForwardDown(void)201 void IN_ForwardDown(void) {IN_KeyDown(&in_forward);}
IN_ForwardUp(void)202 void IN_ForwardUp(void) {IN_KeyUp(&in_forward);}
IN_BackDown(void)203 void IN_BackDown(void) {IN_KeyDown(&in_back);}
IN_BackUp(void)204 void IN_BackUp(void) {IN_KeyUp(&in_back);}
IN_LookupDown(void)205 void IN_LookupDown(void) {IN_KeyDown(&in_lookup);}
IN_LookupUp(void)206 void IN_LookupUp(void) {IN_KeyUp(&in_lookup);}
IN_LookdownDown(void)207 void IN_LookdownDown(void) {IN_KeyDown(&in_lookdown);}
IN_LookdownUp(void)208 void IN_LookdownUp(void) {IN_KeyUp(&in_lookdown);}
IN_MoveleftDown(void)209 void IN_MoveleftDown(void) {IN_KeyDown(&in_moveleft);}
IN_MoveleftUp(void)210 void IN_MoveleftUp(void) {IN_KeyUp(&in_moveleft);}
IN_MoverightDown(void)211 void IN_MoverightDown(void) {IN_KeyDown(&in_moveright);}
IN_MoverightUp(void)212 void IN_MoverightUp(void) {IN_KeyUp(&in_moveright);}
213 
IN_SpeedDown(void)214 void IN_SpeedDown(void) {IN_KeyDown(&in_speed);}
IN_SpeedUp(void)215 void IN_SpeedUp(void) {IN_KeyUp(&in_speed);}
IN_StrafeDown(void)216 void IN_StrafeDown(void) {IN_KeyDown(&in_strafe);}
IN_StrafeUp(void)217 void IN_StrafeUp(void) {IN_KeyUp(&in_strafe);}
218 
IN_Button0Down(void)219 void IN_Button0Down(void) {IN_KeyDown(&in_buttons[0]);}
IN_Button0Up(void)220 void IN_Button0Up(void) {IN_KeyUp(&in_buttons[0]);}
IN_Button1Down(void)221 void IN_Button1Down(void) {IN_KeyDown(&in_buttons[1]);}
IN_Button1Up(void)222 void IN_Button1Up(void) {IN_KeyUp(&in_buttons[1]);}
IN_Button2Down(void)223 void IN_Button2Down(void) {IN_KeyDown(&in_buttons[2]);}
IN_Button2Up(void)224 void IN_Button2Up(void) {IN_KeyUp(&in_buttons[2]);}
IN_Button3Down(void)225 void IN_Button3Down(void) {IN_KeyDown(&in_buttons[3]);}
IN_Button3Up(void)226 void IN_Button3Up(void) {IN_KeyUp(&in_buttons[3]);}
IN_Button4Down(void)227 void IN_Button4Down(void) {IN_KeyDown(&in_buttons[4]);}
IN_Button4Up(void)228 void IN_Button4Up(void) {IN_KeyUp(&in_buttons[4]);}
IN_Button5Down(void)229 void IN_Button5Down(void) {IN_KeyDown(&in_buttons[5]);}
IN_Button5Up(void)230 void IN_Button5Up(void) {IN_KeyUp(&in_buttons[5]);}
IN_Button6Down(void)231 void IN_Button6Down(void) {IN_KeyDown(&in_buttons[6]);}
IN_Button6Up(void)232 void IN_Button6Up(void) {IN_KeyUp(&in_buttons[6]);}
IN_Button7Down(void)233 void IN_Button7Down(void) {IN_KeyDown(&in_buttons[7]);}
IN_Button7Up(void)234 void IN_Button7Up(void) {IN_KeyUp(&in_buttons[7]);}
IN_Button8Down(void)235 void IN_Button8Down(void) {IN_KeyDown(&in_buttons[8]);}
IN_Button8Up(void)236 void IN_Button8Up(void) {IN_KeyUp(&in_buttons[8]);}
IN_Button9Down(void)237 void IN_Button9Down(void) {IN_KeyDown(&in_buttons[9]);}
IN_Button9Up(void)238 void IN_Button9Up(void) {IN_KeyUp(&in_buttons[9]);}
IN_Button10Down(void)239 void IN_Button10Down(void) {IN_KeyDown(&in_buttons[10]);}
IN_Button10Up(void)240 void IN_Button10Up(void) {IN_KeyUp(&in_buttons[10]);}
IN_Button11Down(void)241 void IN_Button11Down(void) {IN_KeyDown(&in_buttons[11]);}
IN_Button11Up(void)242 void IN_Button11Up(void) {IN_KeyUp(&in_buttons[11]);}
IN_Button12Down(void)243 void IN_Button12Down(void) {IN_KeyDown(&in_buttons[12]);}
IN_Button12Up(void)244 void IN_Button12Up(void) {IN_KeyUp(&in_buttons[12]);}
IN_Button13Down(void)245 void IN_Button13Down(void) {IN_KeyDown(&in_buttons[13]);}
IN_Button13Up(void)246 void IN_Button13Up(void) {IN_KeyUp(&in_buttons[13]);}
IN_Button14Down(void)247 void IN_Button14Down(void) {IN_KeyDown(&in_buttons[14]);}
IN_Button14Up(void)248 void IN_Button14Up(void) {IN_KeyUp(&in_buttons[14]);}
IN_Button15Down(void)249 void IN_Button15Down(void) {IN_KeyDown(&in_buttons[15]);}
IN_Button15Up(void)250 void IN_Button15Up(void) {IN_KeyUp(&in_buttons[15]);}
251 
IN_ButtonDown(void)252 void IN_ButtonDown (void) {
253 	IN_KeyDown(&in_buttons[1]);}
IN_ButtonUp(void)254 void IN_ButtonUp (void) {
255 	IN_KeyUp(&in_buttons[1]);}
256 
IN_CenterView(void)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 */
CL_AdjustAngles(void)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 */
CL_KeyMove(usercmd_t * cmd)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 */
CL_MouseEvent(int dx,int dy,int time)353 void CL_MouseEvent( int dx, int dy, int time ) {
354 	if ( Key_GetCatcher( ) & KEYCATCH_UI ) {
355 		VM_Call( uivm, UI_MOUSE_EVENT, dx, dy );
356 	} else if (Key_GetCatcher( ) & 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 */
CL_JoystickEvent(int axis,int value,int time)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 */
CL_JoystickMove(usercmd_t * cmd)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 */
CL_MouseMove(usercmd_t * cmd)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 *
439 			cl_platformSensitivity->value ) + rate * cl_mouseAccel->value;
440 
441 	// scale by FOV
442 	accelSensitivity *= cl.cgameSensitivity;
443 
444 	if ( rate && cl_showMouseRate->integer ) {
445 		Com_Printf( "%f : %f\n", rate, accelSensitivity );
446 	}
447 
448 	mx *= accelSensitivity;
449 	my *= accelSensitivity;
450 
451 	if (!mx && !my) {
452 		return;
453 	}
454 
455 	// add mouse X/Y movement to cmd
456 	if ( in_strafe.active ) {
457 		cmd->rightmove = ClampChar( cmd->rightmove + m_side->value * mx );
458 	} else {
459 		cl.viewangles[YAW] -= m_yaw->value * mx;
460 	}
461 
462 	if ( (in_mlooking || cl_freelook->integer) && !in_strafe.active ) {
463 		cl.viewangles[PITCH] += m_pitch->value * my;
464 	} else {
465 		cmd->forwardmove = ClampChar( cmd->forwardmove - m_forward->value * my );
466 	}
467 }
468 
469 
470 /*
471 ==============
472 CL_CmdButtons
473 ==============
474 */
CL_CmdButtons(usercmd_t * cmd)475 void CL_CmdButtons( usercmd_t *cmd ) {
476 	int		i;
477 
478 	//
479 	// figure button bits
480 	// send a button bit even if the key was pressed and released in
481 	// less than a frame
482 	//
483 	for (i = 0 ; i < 15 ; i++) {
484 		if ( in_buttons[i].active || in_buttons[i].wasPressed ) {
485 			cmd->buttons |= 1 << i;
486 		}
487 		in_buttons[i].wasPressed = qfalse;
488 	}
489 
490 	if ( Key_GetCatcher( ) ) {
491 		cmd->buttons |= BUTTON_TALK;
492 	}
493 
494 	// allow the game to know if any key at all is
495 	// currently pressed, even if it isn't bound to anything
496 	if ( anykeydown && Key_GetCatcher( ) == 0 ) {
497 		cmd->buttons |= BUTTON_ANY;
498 	}
499 }
500 
501 
502 /*
503 ==============
504 CL_FinishMove
505 ==============
506 */
CL_FinishMove(usercmd_t * cmd)507 void CL_FinishMove( usercmd_t *cmd ) {
508 	int		i;
509 
510 	// copy the state that the cgame is currently sending
511 	cmd->weapon = cl.cgameUserCmdValue;
512 
513 	// send the current server time so the amount of movement
514 	// can be determined without allowing cheating
515 	cmd->serverTime = cl.serverTime;
516 
517 	for (i=0 ; i<3 ; i++) {
518 		cmd->angles[i] = ANGLE2SHORT(cl.viewangles[i]);
519 	}
520 }
521 
522 
523 /*
524 =================
525 CL_CreateCmd
526 =================
527 */
CL_CreateCmd(void)528 usercmd_t CL_CreateCmd( void ) {
529 	usercmd_t	cmd;
530 	vec3_t		oldAngles;
531 
532 	VectorCopy( cl.viewangles, oldAngles );
533 
534 	// keyboard angle adjustment
535 	CL_AdjustAngles ();
536 
537 	Com_Memset( &cmd, 0, sizeof( cmd ) );
538 
539 	CL_CmdButtons( &cmd );
540 
541 	// get basic movement from keyboard
542 	CL_KeyMove( &cmd );
543 
544 	// get basic movement from mouse
545 	CL_MouseMove( &cmd );
546 
547 	// get basic movement from joystick
548 	CL_JoystickMove( &cmd );
549 
550 	// check to make sure the angles haven't wrapped
551 	if ( cl.viewangles[PITCH] - oldAngles[PITCH] > 90 ) {
552 		cl.viewangles[PITCH] = oldAngles[PITCH] + 90;
553 	} else if ( oldAngles[PITCH] - cl.viewangles[PITCH] > 90 ) {
554 		cl.viewangles[PITCH] = oldAngles[PITCH] - 90;
555 	}
556 
557 	// store out the final values
558 	CL_FinishMove( &cmd );
559 
560 	// draw debug graphs of turning for mouse testing
561 	if ( cl_debugMove->integer ) {
562 		if ( cl_debugMove->integer == 1 ) {
563 			SCR_DebugGraph( abs(cl.viewangles[YAW] - oldAngles[YAW]), 0 );
564 		}
565 		if ( cl_debugMove->integer == 2 ) {
566 			SCR_DebugGraph( abs(cl.viewangles[PITCH] - oldAngles[PITCH]), 0 );
567 		}
568 	}
569 
570 	return cmd;
571 }
572 
573 
574 /*
575 =================
576 CL_CreateNewCommands
577 
578 Create a new usercmd_t structure for this frame
579 =================
580 */
CL_CreateNewCommands(void)581 void CL_CreateNewCommands( void ) {
582 	usercmd_t	*cmd;
583 	int			cmdNum;
584 
585 	// no need to create usercmds until we have a gamestate
586 	if ( cls.state < CA_PRIMED ) {
587 		return;
588 	}
589 
590 	frame_msec = com_frameTime - old_com_frameTime;
591 
592 	// if running less than 5fps, truncate the extra time to prevent
593 	// unexpected moves after a hitch
594 	if ( frame_msec > 200 ) {
595 		frame_msec = 200;
596 	}
597 	old_com_frameTime = com_frameTime;
598 
599 
600 	// generate a command for this frame
601 	cl.cmdNumber++;
602 	cmdNum = cl.cmdNumber & CMD_MASK;
603 	cl.cmds[cmdNum] = CL_CreateCmd ();
604 	cmd = &cl.cmds[cmdNum];
605 }
606 
607 /*
608 =================
609 CL_ReadyToSendPacket
610 
611 Returns qfalse if we are over the maxpackets limit
612 and should choke back the bandwidth a bit by not sending
613 a packet this frame.  All the commands will still get
614 delivered in the next packet, but saving a header and
615 getting more delta compression will reduce total bandwidth.
616 =================
617 */
CL_ReadyToSendPacket(void)618 qboolean CL_ReadyToSendPacket( void ) {
619 	int		oldPacketNum;
620 	int		delta;
621 
622 	// don't send anything if playing back a demo
623 	if ( clc.demoplaying || cls.state == CA_CINEMATIC ) {
624 		return qfalse;
625 	}
626 
627 	// If we are downloading, we send no less than 50ms between packets
628 	if ( *clc.downloadTempName &&
629 		cls.realtime - clc.lastPacketSentTime < 50 ) {
630 		return qfalse;
631 	}
632 
633 	// if we don't have a valid gamestate yet, only send
634 	// one packet a second
635 	if ( cls.state != CA_ACTIVE &&
636 		cls.state != CA_PRIMED &&
637 		!*clc.downloadTempName &&
638 		cls.realtime - clc.lastPacketSentTime < 1000 ) {
639 		return qfalse;
640 	}
641 
642 	// send every frame for loopbacks
643 	if ( clc.netchan.remoteAddress.type == NA_LOOPBACK ) {
644 		return qtrue;
645 	}
646 
647 	// send every frame for LAN
648 	if ( cl_lanForcePackets->integer && Sys_IsLANAddress( clc.netchan.remoteAddress ) ) {
649 		return qtrue;
650 	}
651 
652 	// check for exceeding cl_maxpackets
653 	if ( cl_maxpackets->integer < 15 ) {
654 		Cvar_Set( "cl_maxpackets", "15" );
655 	} else if ( cl_maxpackets->integer > 125 ) {
656 		Cvar_Set( "cl_maxpackets", "125" );
657 	}
658 	oldPacketNum = (clc.netchan.outgoingSequence - 1) & PACKET_MASK;
659 	delta = cls.realtime -  cl.outPackets[ oldPacketNum ].p_realtime;
660 	if ( delta < 1000 / cl_maxpackets->integer ) {
661 		// the accumulated commands will go out in the next packet
662 		return qfalse;
663 	}
664 
665 	return qtrue;
666 }
667 
668 /*
669 ===================
670 CL_WritePacket
671 
672 Create and send the command packet to the server
673 Including both the reliable commands and the usercmds
674 
675 During normal gameplay, a client packet will contain something like:
676 
677 4	sequence number
678 2	qport
679 4	serverid
680 4	acknowledged sequence number
681 4	clc.serverCommandSequence
682 <optional reliable commands>
683 1	clc_move or clc_moveNoDelta
684 1	command count
685 <count * usercmds>
686 
687 ===================
688 */
CL_WritePacket(void)689 void CL_WritePacket( void ) {
690 	msg_t		buf;
691 	byte		data[MAX_MSGLEN];
692 	int			i, j;
693 	usercmd_t	*cmd, *oldcmd;
694 	usercmd_t	nullcmd;
695 	int			packetNum;
696 	int			oldPacketNum;
697 	int			count, key;
698 
699 	// don't send anything if playing back a demo
700 	if ( clc.demoplaying || cls.state == CA_CINEMATIC ) {
701 		return;
702 	}
703 
704 	Com_Memset( &nullcmd, 0, sizeof(nullcmd) );
705 	oldcmd = &nullcmd;
706 
707 	MSG_Init( &buf, data, sizeof(data) );
708 
709 	MSG_Bitstream( &buf );
710 	// write the current serverId so the server
711 	// can tell if this is from the current gameState
712 	MSG_WriteLong( &buf, cl.serverId );
713 
714 	// write the last message we received, which can
715 	// be used for delta compression, and is also used
716 	// to tell if we dropped a gamestate
717 	MSG_WriteLong( &buf, clc.serverMessageSequence );
718 
719 	// write the last reliable message we received
720 	MSG_WriteLong( &buf, clc.serverCommandSequence );
721 
722 	// write any unacknowledged clientCommands
723 	for ( i = clc.reliableAcknowledge + 1 ; i <= clc.reliableSequence ; i++ ) {
724 		MSG_WriteByte( &buf, clc_clientCommand );
725 		MSG_WriteLong( &buf, i );
726 		MSG_WriteString( &buf, clc.reliableCommands[ i & (MAX_RELIABLE_COMMANDS-1) ] );
727 	}
728 
729 	// we want to send all the usercmds that were generated in the last
730 	// few packet, so even if a couple packets are dropped in a row,
731 	// all the cmds will make it to the server
732 	if ( cl_packetdup->integer < 0 ) {
733 		Cvar_Set( "cl_packetdup", "0" );
734 	} else if ( cl_packetdup->integer > 5 ) {
735 		Cvar_Set( "cl_packetdup", "5" );
736 	}
737 	oldPacketNum = (clc.netchan.outgoingSequence - 1 - cl_packetdup->integer) & PACKET_MASK;
738 	count = cl.cmdNumber - cl.outPackets[ oldPacketNum ].p_cmdNumber;
739 	if ( count > MAX_PACKET_USERCMDS ) {
740 		count = MAX_PACKET_USERCMDS;
741 		Com_Printf("MAX_PACKET_USERCMDS\n");
742 	}
743 	if ( count >= 1 ) {
744 		if ( cl_showSend->integer ) {
745 			Com_Printf( "(%i)", count );
746 		}
747 
748 		// begin a client move command
749 		if ( cl_nodelta->integer || !cl.snap.valid || clc.demowaiting
750 			|| clc.serverMessageSequence != cl.snap.messageNum ) {
751 			MSG_WriteByte (&buf, clc_moveNoDelta);
752 		} else {
753 			MSG_WriteByte (&buf, clc_move);
754 		}
755 
756 		// write the command count
757 		MSG_WriteByte( &buf, count );
758 
759 		// use the checksum feed in the key
760 		key = clc.checksumFeed;
761 		// also use the message acknowledge
762 		key ^= clc.serverMessageSequence;
763 		// also use the last acknowledged server command in the key
764 		key ^= Com_HashKey(clc.serverCommands[ clc.serverCommandSequence & (MAX_RELIABLE_COMMANDS-1) ], 32);
765 
766 		// write all the commands, including the predicted command
767 		for ( i = 0 ; i < count ; i++ ) {
768 			j = (cl.cmdNumber - count + i + 1) & CMD_MASK;
769 			cmd = &cl.cmds[j];
770 			MSG_WriteDeltaUsercmdKey (&buf, key, oldcmd, cmd);
771 			oldcmd = cmd;
772 		}
773 	}
774 
775 	//
776 	// deliver the message
777 	//
778 	packetNum = clc.netchan.outgoingSequence & PACKET_MASK;
779 	cl.outPackets[ packetNum ].p_realtime = cls.realtime;
780 	cl.outPackets[ packetNum ].p_serverTime = oldcmd->serverTime;
781 	cl.outPackets[ packetNum ].p_cmdNumber = cl.cmdNumber;
782 	clc.lastPacketSentTime = cls.realtime;
783 
784 	if ( cl_showSend->integer ) {
785 		Com_Printf( "%i ", buf.cursize );
786 	}
787 
788 	CL_Netchan_Transmit (&clc.netchan, &buf);
789 
790 	// clients never really should have messages large enough
791 	// to fragment, but in case they do, fire them all off
792 	// at once
793 	// TTimo: this causes a packet burst, which is bad karma for winsock
794 	// added a WARNING message, we'll see if there are legit situations where this happens
795 	while ( clc.netchan.unsentFragments ) {
796 		Com_DPrintf( "WARNING: #462 unsent fragments (not supposed to happen!)\n" );
797 		CL_Netchan_TransmitNextFragment( &clc.netchan );
798 	}
799 }
800 
801 /*
802 =================
803 CL_SendCmd
804 
805 Called every frame to builds and sends a command packet to the server.
806 =================
807 */
CL_SendCmd(void)808 void CL_SendCmd( void ) {
809 	// don't send any message if not connected
810 	if ( cls.state < CA_CONNECTED ) {
811 		return;
812 	}
813 
814 	// don't send commands if paused
815 	if ( com_sv_running->integer && sv_paused->integer && cl_paused->integer ) {
816 		return;
817 	}
818 
819 	// we create commands even if a demo is playing,
820 	CL_CreateNewCommands();
821 
822 	// don't send a packet if the last packet was sent too recently
823 	if ( !CL_ReadyToSendPacket() ) {
824 		if ( cl_showSend->integer ) {
825 			Com_Printf( ". " );
826 		}
827 		return;
828 	}
829 
830 	CL_WritePacket();
831 }
832 
833 /*
834 ============
835 CL_InitInput
836 ============
837 */
CL_InitInput(void)838 void CL_InitInput( void ) {
839 	Cmd_AddCommand ("centerview",IN_CenterView);
840 
841 	Cmd_AddCommand ("+moveup",IN_UpDown);
842 	Cmd_AddCommand ("-moveup",IN_UpUp);
843 	Cmd_AddCommand ("+movedown",IN_DownDown);
844 	Cmd_AddCommand ("-movedown",IN_DownUp);
845 	Cmd_AddCommand ("+left",IN_LeftDown);
846 	Cmd_AddCommand ("-left",IN_LeftUp);
847 	Cmd_AddCommand ("+right",IN_RightDown);
848 	Cmd_AddCommand ("-right",IN_RightUp);
849 	Cmd_AddCommand ("+forward",IN_ForwardDown);
850 	Cmd_AddCommand ("-forward",IN_ForwardUp);
851 	Cmd_AddCommand ("+back",IN_BackDown);
852 	Cmd_AddCommand ("-back",IN_BackUp);
853 	Cmd_AddCommand ("+lookup", IN_LookupDown);
854 	Cmd_AddCommand ("-lookup", IN_LookupUp);
855 	Cmd_AddCommand ("+lookdown", IN_LookdownDown);
856 	Cmd_AddCommand ("-lookdown", IN_LookdownUp);
857 	Cmd_AddCommand ("+strafe", IN_StrafeDown);
858 	Cmd_AddCommand ("-strafe", IN_StrafeUp);
859 	Cmd_AddCommand ("+moveleft", IN_MoveleftDown);
860 	Cmd_AddCommand ("-moveleft", IN_MoveleftUp);
861 	Cmd_AddCommand ("+moveright", IN_MoverightDown);
862 	Cmd_AddCommand ("-moveright", IN_MoverightUp);
863 	Cmd_AddCommand ("+speed", IN_SpeedDown);
864 	Cmd_AddCommand ("-speed", IN_SpeedUp);
865 	Cmd_AddCommand ("+attack", IN_Button0Down);
866 	Cmd_AddCommand ("-attack", IN_Button0Up);
867 	Cmd_AddCommand ("+button0", IN_Button0Down);
868 	Cmd_AddCommand ("-button0", IN_Button0Up);
869 	Cmd_AddCommand ("+button1", IN_Button1Down);
870 	Cmd_AddCommand ("-button1", IN_Button1Up);
871 	Cmd_AddCommand ("+button2", IN_Button2Down);
872 	Cmd_AddCommand ("-button2", IN_Button2Up);
873 	Cmd_AddCommand ("+button3", IN_Button3Down);
874 	Cmd_AddCommand ("-button3", IN_Button3Up);
875 	Cmd_AddCommand ("+button4", IN_Button4Down);
876 	Cmd_AddCommand ("-button4", IN_Button4Up);
877 	Cmd_AddCommand ("+button5", IN_Button5Down);
878 	Cmd_AddCommand ("-button5", IN_Button5Up);
879 	Cmd_AddCommand ("+button6", IN_Button6Down);
880 	Cmd_AddCommand ("-button6", IN_Button6Up);
881 	Cmd_AddCommand ("+button7", IN_Button7Down);
882 	Cmd_AddCommand ("-button7", IN_Button7Up);
883 	Cmd_AddCommand ("+button8", IN_Button8Down);
884 	Cmd_AddCommand ("-button8", IN_Button8Up);
885 	Cmd_AddCommand ("+button9", IN_Button9Down);
886 	Cmd_AddCommand ("-button9", IN_Button9Up);
887 	Cmd_AddCommand ("+button10", IN_Button10Down);
888 	Cmd_AddCommand ("-button10", IN_Button10Up);
889 	Cmd_AddCommand ("+button11", IN_Button11Down);
890 	Cmd_AddCommand ("-button11", IN_Button11Up);
891 	Cmd_AddCommand ("+button12", IN_Button12Down);
892 	Cmd_AddCommand ("-button12", IN_Button12Up);
893 	Cmd_AddCommand ("+button13", IN_Button13Down);
894 	Cmd_AddCommand ("-button13", IN_Button13Up);
895 	Cmd_AddCommand ("+button14", IN_Button14Down);
896 	Cmd_AddCommand ("-button14", IN_Button14Up);
897 	Cmd_AddCommand ("+mlook", IN_MLookDown);
898 	Cmd_AddCommand ("-mlook", IN_MLookUp);
899 
900 	cl_nodelta = Cvar_Get ("cl_nodelta", "0", 0);
901 	cl_debugMove = Cvar_Get ("cl_debugMove", "0", 0);
902 }
903