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