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