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 #ifdef 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 #ifdef USE_VOIP
IN_VoipRecordDown(void)224 void IN_VoipRecordDown(void)
225 {
226 	IN_KeyDown(&in_voiprecord);
227 	Cvar_Set("cl_voipSend", "1");
228 }
229 
IN_VoipRecordUp(void)230 void IN_VoipRecordUp(void)
231 {
232 	IN_KeyUp(&in_voiprecord);
233 	Cvar_Set("cl_voipSend", "0");
234 }
235 #endif
236 
IN_Button0Down(void)237 void IN_Button0Down(void) {IN_KeyDown(&in_buttons[0]);}
IN_Button0Up(void)238 void IN_Button0Up(void) {IN_KeyUp(&in_buttons[0]);}
IN_Button1Down(void)239 void IN_Button1Down(void) {IN_KeyDown(&in_buttons[1]);}
IN_Button1Up(void)240 void IN_Button1Up(void) {IN_KeyUp(&in_buttons[1]);}
IN_Button2Down(void)241 void IN_Button2Down(void) {IN_KeyDown(&in_buttons[2]);}
IN_Button2Up(void)242 void IN_Button2Up(void) {IN_KeyUp(&in_buttons[2]);}
IN_Button3Down(void)243 void IN_Button3Down(void) {IN_KeyDown(&in_buttons[3]);}
IN_Button3Up(void)244 void IN_Button3Up(void) {IN_KeyUp(&in_buttons[3]);}
IN_Button4Down(void)245 void IN_Button4Down(void) {IN_KeyDown(&in_buttons[4]);}
IN_Button4Up(void)246 void IN_Button4Up(void) {IN_KeyUp(&in_buttons[4]);}
IN_Button5Down(void)247 void IN_Button5Down(void) {IN_KeyDown(&in_buttons[5]);}
IN_Button5Up(void)248 void IN_Button5Up(void) {IN_KeyUp(&in_buttons[5]);}
IN_Button6Down(void)249 void IN_Button6Down(void) {IN_KeyDown(&in_buttons[6]);}
IN_Button6Up(void)250 void IN_Button6Up(void) {IN_KeyUp(&in_buttons[6]);}
IN_Button7Down(void)251 void IN_Button7Down(void) {IN_KeyDown(&in_buttons[7]);}
IN_Button7Up(void)252 void IN_Button7Up(void) {IN_KeyUp(&in_buttons[7]);}
IN_Button8Down(void)253 void IN_Button8Down(void) {IN_KeyDown(&in_buttons[8]);}
IN_Button8Up(void)254 void IN_Button8Up(void) {IN_KeyUp(&in_buttons[8]);}
IN_Button9Down(void)255 void IN_Button9Down(void) {IN_KeyDown(&in_buttons[9]);}
IN_Button9Up(void)256 void IN_Button9Up(void) {IN_KeyUp(&in_buttons[9]);}
IN_Button10Down(void)257 void IN_Button10Down(void) {IN_KeyDown(&in_buttons[10]);}
IN_Button10Up(void)258 void IN_Button10Up(void) {IN_KeyUp(&in_buttons[10]);}
IN_Button11Down(void)259 void IN_Button11Down(void) {IN_KeyDown(&in_buttons[11]);}
IN_Button11Up(void)260 void IN_Button11Up(void) {IN_KeyUp(&in_buttons[11]);}
IN_Button12Down(void)261 void IN_Button12Down(void) {IN_KeyDown(&in_buttons[12]);}
IN_Button12Up(void)262 void IN_Button12Up(void) {IN_KeyUp(&in_buttons[12]);}
IN_Button13Down(void)263 void IN_Button13Down(void) {IN_KeyDown(&in_buttons[13]);}
IN_Button13Up(void)264 void IN_Button13Up(void) {IN_KeyUp(&in_buttons[13]);}
IN_Button14Down(void)265 void IN_Button14Down(void) {IN_KeyDown(&in_buttons[14]);}
IN_Button14Up(void)266 void IN_Button14Up(void) {IN_KeyUp(&in_buttons[14]);}
IN_Button15Down(void)267 void IN_Button15Down(void) {IN_KeyDown(&in_buttons[15]);}
IN_Button15Up(void)268 void IN_Button15Up(void) {IN_KeyUp(&in_buttons[15]);}
269 
IN_ButtonDown(void)270 void IN_ButtonDown (void) {
271 	IN_KeyDown(&in_buttons[1]);}
IN_ButtonUp(void)272 void IN_ButtonUp (void) {
273 	IN_KeyUp(&in_buttons[1]);}
274 
IN_CenterView(void)275 void IN_CenterView (void) {
276 	cl.viewangles[PITCH] = -SHORT2ANGLE(cl.snap.ps.delta_angles[PITCH]);
277 }
278 
279 
280 //==========================================================================
281 
282 cvar_t	*cl_upspeed;
283 cvar_t	*cl_forwardspeed;
284 cvar_t	*cl_sidespeed;
285 
286 cvar_t	*cl_yawspeed;
287 cvar_t	*cl_pitchspeed;
288 
289 cvar_t	*cl_run;
290 
291 cvar_t	*cl_anglespeedkey;
292 
293 
294 /*
295 ================
296 CL_AdjustAngles
297 
298 Moves the local angle positions
299 ================
300 */
CL_AdjustAngles(void)301 void CL_AdjustAngles( void ) {
302 	float	speed;
303 
304 	if ( in_speed.active ) {
305 		speed = 0.001 * cls.frametime * cl_anglespeedkey->value;
306 	} else {
307 		speed = 0.001 * cls.frametime;
308 	}
309 
310 	if ( !in_strafe.active ) {
311 		cl.viewangles[YAW] -= speed*cl_yawspeed->value*CL_KeyState (&in_right);
312 		cl.viewangles[YAW] += speed*cl_yawspeed->value*CL_KeyState (&in_left);
313 	}
314 
315 	cl.viewangles[PITCH] -= speed*cl_pitchspeed->value * CL_KeyState (&in_lookup);
316 	cl.viewangles[PITCH] += speed*cl_pitchspeed->value * CL_KeyState (&in_lookdown);
317 }
318 
319 /*
320 ================
321 CL_KeyMove
322 
323 Sets the usercmd_t based on key states
324 ================
325 */
CL_KeyMove(usercmd_t * cmd)326 void CL_KeyMove( usercmd_t *cmd ) {
327 	int		movespeed;
328 	int		forward, side, up;
329 
330 	//
331 	// adjust for speed key / running
332 	// the walking flag is to keep animations consistant
333 	// even during acceleration and develeration
334 	//
335 	if ( in_speed.active ^ cl_run->integer ) {
336 		movespeed = 127;
337 		cmd->buttons &= ~BUTTON_WALKING;
338 	} else {
339 		cmd->buttons |= BUTTON_WALKING;
340 		movespeed = 64;
341 	}
342 
343 	forward = 0;
344 	side = 0;
345 	up = 0;
346 	if ( in_strafe.active ) {
347 		side += movespeed * CL_KeyState (&in_right);
348 		side -= movespeed * CL_KeyState (&in_left);
349 	}
350 
351 	side += movespeed * CL_KeyState (&in_moveright);
352 	side -= movespeed * CL_KeyState (&in_moveleft);
353 
354 
355 	up += movespeed * CL_KeyState (&in_up);
356 	up -= movespeed * CL_KeyState (&in_down);
357 
358 	forward += movespeed * CL_KeyState (&in_forward);
359 	forward -= movespeed * CL_KeyState (&in_back);
360 
361 	cmd->forwardmove = ClampChar( forward );
362 	cmd->rightmove = ClampChar( side );
363 	cmd->upmove = ClampChar( up );
364 }
365 
366 /*
367 =================
368 CL_MouseEvent
369 =================
370 */
CL_MouseEvent(int dx,int dy,int time)371 void CL_MouseEvent( int dx, int dy, int time ) {
372 	if ( Key_GetCatcher( ) & KEYCATCH_UI ) {
373 		VM_Call( uivm, UI_MOUSE_EVENT, dx, dy );
374 	} else if (Key_GetCatcher( ) & KEYCATCH_CGAME) {
375 		VM_Call (cgvm, CG_MOUSE_EVENT, dx, dy);
376 	} else {
377 		cl.mouseDx[cl.mouseIndex] += dx;
378 		cl.mouseDy[cl.mouseIndex] += dy;
379 	}
380 }
381 
382 /*
383 =================
384 CL_JoystickEvent
385 
386 Joystick values stay set until changed
387 =================
388 */
CL_JoystickEvent(int axis,int value,int time)389 void CL_JoystickEvent( int axis, int value, int time ) {
390 	if ( axis < 0 || axis >= MAX_JOYSTICK_AXIS ) {
391 		Com_Error( ERR_DROP, "CL_JoystickEvent: bad axis %i", axis );
392 	}
393 	cl.joystickAxis[axis] = value;
394 }
395 
396 /*
397 =================
398 CL_JoystickMove
399 =================
400 */
CL_JoystickMove(usercmd_t * cmd)401 void CL_JoystickMove( usercmd_t *cmd ) {
402 	int		movespeed;
403 	float	anglespeed;
404 
405 	if ( in_speed.active ^ cl_run->integer ) {
406 		movespeed = 2;
407 	} else {
408 		movespeed = 1;
409 		cmd->buttons |= BUTTON_WALKING;
410 	}
411 
412 	if ( in_speed.active ) {
413 		anglespeed = 0.001 * cls.frametime * cl_anglespeedkey->value;
414 	} else {
415 		anglespeed = 0.001 * cls.frametime;
416 	}
417 
418 	if ( !in_strafe.active ) {
419 		cl.viewangles[YAW] += anglespeed * cl_yawspeed->value * cl.joystickAxis[AXIS_SIDE];
420 	} else {
421 		cmd->rightmove = ClampChar( cmd->rightmove + cl.joystickAxis[AXIS_SIDE] );
422 	}
423 
424 	if ( in_mlooking ) {
425 		cl.viewangles[PITCH] += anglespeed * cl_pitchspeed->value * cl.joystickAxis[AXIS_FORWARD];
426 	} else {
427 		cmd->forwardmove = ClampChar( cmd->forwardmove + cl.joystickAxis[AXIS_FORWARD] );
428 	}
429 
430 	cmd->upmove = ClampChar( cmd->upmove + cl.joystickAxis[AXIS_UP] );
431 }
432 
433 /*
434 =================
435 CL_MouseMove
436 =================
437 */
CL_MouseMove(usercmd_t * cmd)438 void CL_MouseMove( usercmd_t *cmd ) {
439 	float	mx, my;
440 	float	accelSensitivity;
441 	float	rate;
442 
443 	// allow mouse smoothing
444 	if ( m_filter->integer ) {
445 		mx = ( cl.mouseDx[0] + cl.mouseDx[1] ) * 0.5;
446 		my = ( cl.mouseDy[0] + cl.mouseDy[1] ) * 0.5;
447 	} else {
448 		mx = cl.mouseDx[cl.mouseIndex];
449 		my = cl.mouseDy[cl.mouseIndex];
450 	}
451 	cl.mouseIndex ^= 1;
452 	cl.mouseDx[cl.mouseIndex] = 0;
453 	cl.mouseDy[cl.mouseIndex] = 0;
454 
455 	rate = sqrt( mx * mx + my * my ) / (float)frame_msec;
456 	accelSensitivity = cl_sensitivity->value + rate * cl_mouseAccel->value;
457 
458 	// scale by FOV
459 	accelSensitivity *= cl.cgameSensitivity;
460 
461 	if ( rate && cl_showMouseRate->integer ) {
462 		Com_Printf( "%f : %f\n", rate, accelSensitivity );
463 	}
464 
465 	mx *= accelSensitivity;
466 	my *= accelSensitivity;
467 
468 	if (!mx && !my) {
469 		return;
470 	}
471 
472 	// add mouse X/Y movement to cmd
473 	if ( in_strafe.active ) {
474 		cmd->rightmove = ClampChar( cmd->rightmove + m_side->value * mx );
475 	} else {
476 		cl.viewangles[YAW] -= m_yaw->value * mx;
477 	}
478 
479 	if ( (in_mlooking || cl_freelook->integer) && !in_strafe.active ) {
480 		cl.viewangles[PITCH] += m_pitch->value * my;
481 	} else {
482 		cmd->forwardmove = ClampChar( cmd->forwardmove - m_forward->value * my );
483 	}
484 }
485 
486 
487 /*
488 ==============
489 CL_CmdButtons
490 ==============
491 */
CL_CmdButtons(usercmd_t * cmd)492 void CL_CmdButtons( usercmd_t *cmd ) {
493 	int		i;
494 
495 	//
496 	// figure button bits
497 	// send a button bit even if the key was pressed and released in
498 	// less than a frame
499 	//
500 	for (i = 0 ; i < 15 ; i++) {
501 		if ( in_buttons[i].active || in_buttons[i].wasPressed ) {
502 			cmd->buttons |= 1 << i;
503 		}
504 		in_buttons[i].wasPressed = qfalse;
505 	}
506 
507 	if ( Key_GetCatcher( ) ) {
508 		cmd->buttons |= BUTTON_TALK;
509 	}
510 
511 	// allow the game to know if any key at all is
512 	// currently pressed, even if it isn't bound to anything
513 	if ( anykeydown && Key_GetCatcher( ) == 0 ) {
514 		cmd->buttons |= BUTTON_ANY;
515 	}
516 }
517 
518 
519 /*
520 ==============
521 CL_FinishMove
522 ==============
523 */
CL_FinishMove(usercmd_t * cmd)524 void CL_FinishMove( usercmd_t *cmd ) {
525 	int		i;
526 
527 	// copy the state that the cgame is currently sending
528 	cmd->weapon = cl.cgameUserCmdValue;
529 
530 	// send the current server time so the amount of movement
531 	// can be determined without allowing cheating
532 	cmd->serverTime = cl.serverTime;
533 
534 	for (i=0 ; i<3 ; i++) {
535 		cmd->angles[i] = ANGLE2SHORT(cl.viewangles[i]);
536 	}
537 }
538 
539 
540 /*
541 =================
542 CL_CreateCmd
543 =================
544 */
CL_CreateCmd(void)545 usercmd_t CL_CreateCmd( void ) {
546 	usercmd_t	cmd;
547 	vec3_t		oldAngles;
548 
549 	VectorCopy( cl.viewangles, oldAngles );
550 
551 	// keyboard angle adjustment
552 	CL_AdjustAngles ();
553 
554 	Com_Memset( &cmd, 0, sizeof( cmd ) );
555 
556 	CL_CmdButtons( &cmd );
557 
558 	// get basic movement from keyboard
559 	CL_KeyMove( &cmd );
560 
561 	// get basic movement from mouse
562 	CL_MouseMove( &cmd );
563 
564 	// get basic movement from joystick
565 	CL_JoystickMove( &cmd );
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 #ifdef USE_VOIP
762 	if (clc.voipOutgoingDataSize > 0) {  // only send if data.
763 		// Move cl_voipSendTarget from a string to the bitmasks if needed.
764 		if (cl_voipSendTarget->modified) {
765 			char buffer[32];
766 			const char *target = cl_voipSendTarget->string;
767 
768 			if (Q_stricmp(target, "attacker") == 0) {
769 				int player = VM_Call( cgvm, CG_LAST_ATTACKER );
770 				Com_sprintf(buffer, sizeof (buffer), "%d", player);
771 				target = buffer;
772 			} else if (Q_stricmp(target, "crosshair") == 0) {
773 				int player = VM_Call( cgvm, CG_CROSSHAIR_PLAYER );
774 				Com_sprintf(buffer, sizeof (buffer), "%d", player);
775 				target = buffer;
776 			}
777 
778 			if ((*target == '\0') || (Q_stricmp(target, "all") == 0)) {
779 				const int all = 0x7FFFFFFF;
780 				clc.voipTarget1 = clc.voipTarget2 = clc.voipTarget3 = all;
781 			} else if (Q_stricmp(target, "none") == 0) {
782 				clc.voipTarget1 = clc.voipTarget2 = clc.voipTarget3 = 0;
783 			} else {
784 				const char *ptr = target;
785 				clc.voipTarget1 = clc.voipTarget2 = clc.voipTarget3 = 0;
786 				do {
787 					if ((*ptr == ',') || (*ptr == '\0')) {
788 						const int val = atoi(target);
789 						target = ptr + 1;
790 						if ((val >= 0) && (val < 31)) {
791 							clc.voipTarget1 |= (1 << (val-0));
792 						} else if ((val >= 31) && (val < 62)) {
793 							clc.voipTarget2 |= (1 << (val-31));
794 						} else if ((val >= 62) && (val < 93)) {
795 							clc.voipTarget3 |= (1 << (val-62));
796 						}
797 					}
798 				} while (*(ptr++));
799 			}
800 			cl_voipSendTarget->modified = qfalse;
801 		}
802 
803 		MSG_WriteByte (&buf, clc_EOF);  // placate legacy servers.
804 		MSG_WriteByte (&buf, clc_extension);
805 		MSG_WriteByte (&buf, clc_voip);
806 		MSG_WriteByte (&buf, clc.voipOutgoingGeneration);
807 		MSG_WriteLong (&buf, clc.voipOutgoingSequence);
808 		MSG_WriteByte (&buf, clc.voipOutgoingDataFrames);
809 		MSG_WriteLong (&buf, clc.voipTarget1);
810 		MSG_WriteLong (&buf, clc.voipTarget2);
811 		MSG_WriteLong (&buf, clc.voipTarget3);
812 		MSG_WriteShort (&buf, clc.voipOutgoingDataSize);
813 		MSG_WriteData (&buf, clc.voipOutgoingData, clc.voipOutgoingDataSize);
814 
815 		// If we're recording a demo, we have to fake a server packet with
816 		//  this VoIP data so it gets to disk; the server doesn't send it
817 		//  back to us, and we might as well eliminate concerns about dropped
818 		//  and misordered packets here.
819 		if ( clc.demorecording && !clc.demowaiting ) {
820 			const int voipSize = clc.voipOutgoingDataSize;
821 			msg_t fakemsg;
822 			byte fakedata[MAX_MSGLEN];
823 			MSG_Init (&fakemsg, fakedata, sizeof (fakedata));
824 			MSG_Bitstream (&fakemsg);
825 			MSG_WriteLong (&fakemsg, clc.reliableAcknowledge);
826 			MSG_WriteByte (&fakemsg, svc_EOF);
827 			MSG_WriteByte (&fakemsg, svc_extension);
828 			MSG_WriteByte (&fakemsg, svc_voip);
829 			MSG_WriteShort (&fakemsg, clc.clientNum);
830 			MSG_WriteByte (&fakemsg, clc.voipOutgoingGeneration);
831 			MSG_WriteLong (&fakemsg, clc.voipOutgoingSequence);
832 			MSG_WriteByte (&fakemsg, clc.voipOutgoingDataFrames);
833 			MSG_WriteShort (&fakemsg, clc.voipOutgoingDataSize );
834 			MSG_WriteData (&fakemsg, clc.voipOutgoingData, voipSize);
835 			MSG_WriteByte (&fakemsg, svc_EOF);
836 			CL_WriteDemoMessage (&fakemsg, 0);
837 		}
838 
839 		clc.voipOutgoingSequence += clc.voipOutgoingDataFrames;
840 		clc.voipOutgoingDataSize = 0;
841 		clc.voipOutgoingDataFrames = 0;
842 	} else
843 #endif
844 
845 	if ( count >= 1 ) {
846 		if ( cl_showSend->integer ) {
847 			Com_Printf( "(%i)", count );
848 		}
849 
850 		// begin a client move command
851 		if ( cl_nodelta->integer || !cl.snap.valid || clc.demowaiting
852 			|| clc.serverMessageSequence != cl.snap.messageNum ) {
853 			MSG_WriteByte (&buf, clc_moveNoDelta);
854 		} else {
855 			MSG_WriteByte (&buf, clc_move);
856 		}
857 
858 		// write the command count
859 		MSG_WriteByte( &buf, count );
860 
861 		// use the checksum feed in the key
862 		key = clc.checksumFeed;
863 		// also use the message acknowledge
864 		key ^= clc.serverMessageSequence;
865 		// also use the last acknowledged server command in the key
866 		key ^= Com_HashKey(clc.serverCommands[ clc.serverCommandSequence & (MAX_RELIABLE_COMMANDS-1) ], 32);
867 
868 		// write all the commands, including the predicted command
869 		for ( i = 0 ; i < count ; i++ ) {
870 			j = (cl.cmdNumber - count + i + 1) & CMD_MASK;
871 			cmd = &cl.cmds[j];
872 			MSG_WriteDeltaUsercmdKey (&buf, key, oldcmd, cmd);
873 			oldcmd = cmd;
874 		}
875 	}
876 
877 	//
878 	// deliver the message
879 	//
880 	packetNum = clc.netchan.outgoingSequence & PACKET_MASK;
881 	cl.outPackets[ packetNum ].p_realtime = cls.realtime;
882 	cl.outPackets[ packetNum ].p_serverTime = oldcmd->serverTime;
883 	cl.outPackets[ packetNum ].p_cmdNumber = cl.cmdNumber;
884 	clc.lastPacketSentTime = cls.realtime;
885 
886 	if ( cl_showSend->integer ) {
887 		Com_Printf( "%i ", buf.cursize );
888 	}
889 
890 	CL_Netchan_Transmit (&clc.netchan, &buf);
891 
892 	// clients never really should have messages large enough
893 	// to fragment, but in case they do, fire them all off
894 	// at once
895 	// TTimo: this causes a packet burst, which is bad karma for winsock
896 	// added a WARNING message, we'll see if there are legit situations where this happens
897 	while ( clc.netchan.unsentFragments ) {
898 		Com_DPrintf( "WARNING: #462 unsent fragments (not supposed to happen!)\n" );
899 		CL_Netchan_TransmitNextFragment( &clc.netchan );
900 	}
901 }
902 
903 /*
904 =================
905 CL_SendCmd
906 
907 Called every frame to builds and sends a command packet to the server.
908 =================
909 */
CL_SendCmd(void)910 void CL_SendCmd( void ) {
911 	// don't send any message if not connected
912 	if ( cls.state < CA_CONNECTED ) {
913 		return;
914 	}
915 
916 	// don't send commands if paused
917 	if ( com_sv_running->integer && sv_paused->integer && cl_paused->integer ) {
918 		return;
919 	}
920 
921 	// we create commands even if a demo is playing,
922 	CL_CreateNewCommands();
923 
924 	// don't send a packet if the last packet was sent too recently
925 	if ( !CL_ReadyToSendPacket() ) {
926 		if ( cl_showSend->integer ) {
927 			Com_Printf( ". " );
928 		}
929 		return;
930 	}
931 
932 	CL_WritePacket();
933 }
934 
935 /*
936 ============
937 CL_InitInput
938 ============
939 */
CL_InitInput(void)940 void CL_InitInput( void ) {
941 	Cmd_AddCommand ("centerview",IN_CenterView);
942 
943 	Cmd_AddCommand ("+moveup",IN_UpDown);
944 	Cmd_AddCommand ("-moveup",IN_UpUp);
945 	Cmd_AddCommand ("+movedown",IN_DownDown);
946 	Cmd_AddCommand ("-movedown",IN_DownUp);
947 	Cmd_AddCommand ("+left",IN_LeftDown);
948 	Cmd_AddCommand ("-left",IN_LeftUp);
949 	Cmd_AddCommand ("+right",IN_RightDown);
950 	Cmd_AddCommand ("-right",IN_RightUp);
951 	Cmd_AddCommand ("+forward",IN_ForwardDown);
952 	Cmd_AddCommand ("-forward",IN_ForwardUp);
953 	Cmd_AddCommand ("+back",IN_BackDown);
954 	Cmd_AddCommand ("-back",IN_BackUp);
955 	Cmd_AddCommand ("+lookup", IN_LookupDown);
956 	Cmd_AddCommand ("-lookup", IN_LookupUp);
957 	Cmd_AddCommand ("+lookdown", IN_LookdownDown);
958 	Cmd_AddCommand ("-lookdown", IN_LookdownUp);
959 	Cmd_AddCommand ("+strafe", IN_StrafeDown);
960 	Cmd_AddCommand ("-strafe", IN_StrafeUp);
961 	Cmd_AddCommand ("+moveleft", IN_MoveleftDown);
962 	Cmd_AddCommand ("-moveleft", IN_MoveleftUp);
963 	Cmd_AddCommand ("+moveright", IN_MoverightDown);
964 	Cmd_AddCommand ("-moveright", IN_MoverightUp);
965 	Cmd_AddCommand ("+speed", IN_SpeedDown);
966 	Cmd_AddCommand ("-speed", IN_SpeedUp);
967 	Cmd_AddCommand ("+attack", IN_Button0Down);
968 	Cmd_AddCommand ("-attack", IN_Button0Up);
969 	Cmd_AddCommand ("+button0", IN_Button0Down);
970 	Cmd_AddCommand ("-button0", IN_Button0Up);
971 	Cmd_AddCommand ("+button1", IN_Button1Down);
972 	Cmd_AddCommand ("-button1", IN_Button1Up);
973 	Cmd_AddCommand ("+button2", IN_Button2Down);
974 	Cmd_AddCommand ("-button2", IN_Button2Up);
975 	Cmd_AddCommand ("+button3", IN_Button3Down);
976 	Cmd_AddCommand ("-button3", IN_Button3Up);
977 	Cmd_AddCommand ("+button4", IN_Button4Down);
978 	Cmd_AddCommand ("-button4", IN_Button4Up);
979 	Cmd_AddCommand ("+button5", IN_Button5Down);
980 	Cmd_AddCommand ("-button5", IN_Button5Up);
981 	Cmd_AddCommand ("+button6", IN_Button6Down);
982 	Cmd_AddCommand ("-button6", IN_Button6Up);
983 	Cmd_AddCommand ("+button7", IN_Button7Down);
984 	Cmd_AddCommand ("-button7", IN_Button7Up);
985 	Cmd_AddCommand ("+button8", IN_Button8Down);
986 	Cmd_AddCommand ("-button8", IN_Button8Up);
987 	Cmd_AddCommand ("+button9", IN_Button9Down);
988 	Cmd_AddCommand ("-button9", IN_Button9Up);
989 	Cmd_AddCommand ("+button10", IN_Button10Down);
990 	Cmd_AddCommand ("-button10", IN_Button10Up);
991 	Cmd_AddCommand ("+button11", IN_Button11Down);
992 	Cmd_AddCommand ("-button11", IN_Button11Up);
993 	Cmd_AddCommand ("+button12", IN_Button12Down);
994 	Cmd_AddCommand ("-button12", IN_Button12Up);
995 	Cmd_AddCommand ("+button13", IN_Button13Down);
996 	Cmd_AddCommand ("-button13", IN_Button13Up);
997 	Cmd_AddCommand ("+button14", IN_Button14Down);
998 	Cmd_AddCommand ("-button14", IN_Button14Up);
999 	Cmd_AddCommand ("+mlook", IN_MLookDown);
1000 	Cmd_AddCommand ("-mlook", IN_MLookUp);
1001 
1002 #ifdef USE_VOIP
1003 	Cmd_AddCommand ("+voiprecord", IN_VoipRecordDown);
1004 	Cmd_AddCommand ("-voiprecord", IN_VoipRecordUp);
1005 #endif
1006 
1007 	cl_nodelta = Cvar_Get ("cl_nodelta", "0", 0);
1008 	cl_debugMove = Cvar_Get ("cl_debugMove", "0", 0);
1009 }
1010