1 /*
2 ===========================================================================
3 Copyright (C) 1999 - 2005, Id Software, Inc.
4 Copyright (C) 2000 - 2013, Raven Software, Inc.
5 Copyright (C) 2001 - 2013, Activision, Inc.
6 Copyright (C) 2013 - 2015, OpenJK contributors
7 
8 This file is part of the OpenJK source code.
9 
10 OpenJK is free software; you can redistribute it and/or modify it
11 under the terms of the GNU General Public License version 2 as
12 published by the Free Software Foundation.
13 
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, see <http://www.gnu.org/licenses/>.
21 ===========================================================================
22 */
23 
24 // cl.input.c  -- builds an intended movement command to send to the server
25 
26 #include "client.h"
27 #include "cl_cgameapi.h"
28 #include "cl_uiapi.h"
29 #ifndef _WIN32
30 #include <cmath>
31 #endif
32 unsigned	frame_msec;
33 int			old_com_frameTime;
34 
35 float cl_mPitchOverride = 0.0f;
36 float cl_mYawOverride = 0.0f;
37 float cl_mSensitivityOverride = 0.0f;
38 qboolean cl_bUseFighterPitch = qfalse;
39 qboolean cl_crazyShipControls = qfalse;
40 
41 #ifdef VEH_CONTROL_SCHEME_4
42 #define	OVERRIDE_MOUSE_SENSITIVITY 5.0f//20.0f = 180 degree turn in one mouse swipe across keyboard
43 #else// VEH_CONTROL_SCHEME_4
44 #define	OVERRIDE_MOUSE_SENSITIVITY 10.0f//20.0f = 180 degree turn in one mouse swipe across keyboard
45 #endif// VEH_CONTROL_SCHEME_4
46 /*
47 ===============================================================================
48 
49 KEY BUTTONS
50 
51 Continuous button event tracking is complicated by the fact that two different
52 input sources (say, mouse button 1 and the control key) can both press the
53 same button, but the button should only be released when both of the
54 pressing key have been released.
55 
56 When a key event issues a button command (+forward, +attack, etc), it appends
57 its key number as argv(1) so it can be matched up with the release.
58 
59 argv(2) will be set to the time the event happened, which allows exact
60 control even at low framerates when the down and up events may both get qued
61 at the same time.
62 
63 ===============================================================================
64 */
65 
66 
67 kbutton_t	in_left, in_right, in_forward, in_back;
68 kbutton_t	in_lookup, in_lookdown, in_moveleft, in_moveright;
69 kbutton_t	in_strafe, in_speed;
70 kbutton_t	in_up, in_down;
71 
72 #define MAX_KBUTTONS 16
73 
74 kbutton_t	in_buttons[MAX_KBUTTONS];
75 
76 
77 qboolean	in_mlooking;
78 
79 void IN_Button11Down(void);
80 void IN_Button11Up(void);
81 void IN_Button10Down(void);
82 void IN_Button10Up(void);
83 void IN_Button6Down(void);
84 void IN_Button6Up(void);
IN_UseGivenForce(void)85 void IN_UseGivenForce(void)
86 {
87 	char *c = Cmd_Argv(1);
88 	int forceNum =-1;
89 	int genCmdNum = 0;
90 
91 	if(c) {
92 		forceNum = atoi(c);
93 	} else {
94 		return;
95 	}
96 
97 	switch(forceNum) {
98 	case FP_DRAIN:
99 		IN_Button11Down();
100 		IN_Button11Up();
101 		break;
102 	case FP_PUSH:
103 		genCmdNum = GENCMD_FORCE_THROW;
104 		break;
105 	case FP_SPEED:
106 		genCmdNum = GENCMD_FORCE_SPEED;
107 		break;
108 	case FP_PULL:
109 		genCmdNum = GENCMD_FORCE_PULL;
110 		break;
111 	case FP_TELEPATHY:
112 		genCmdNum = GENCMD_FORCE_DISTRACT;
113 		break;
114 	case FP_GRIP:
115 		IN_Button6Down();
116 		IN_Button6Up();
117 		break;
118 	case FP_LIGHTNING:
119 		IN_Button10Down();
120 		IN_Button10Up();
121 		break;
122 	case FP_RAGE:
123 		genCmdNum = GENCMD_FORCE_RAGE;
124 		break;
125 	case FP_PROTECT:
126 		genCmdNum = GENCMD_FORCE_PROTECT;
127 		break;
128 	case FP_ABSORB:
129 		genCmdNum = GENCMD_FORCE_ABSORB;
130 		break;
131 	case FP_SEE:
132 		genCmdNum = GENCMD_FORCE_SEEING;
133 		break;
134 	case FP_HEAL:
135 		genCmdNum = GENCMD_FORCE_HEAL;
136 		break;
137 	case FP_TEAM_HEAL:
138 		genCmdNum = GENCMD_FORCE_HEALOTHER;
139 		break;
140 	case FP_TEAM_FORCE:
141 		genCmdNum = GENCMD_FORCE_FORCEPOWEROTHER;
142 		break;
143 	default:
144 		assert(0);
145 		break;
146 	}
147 
148 	if(genCmdNum != 0) {
149 		cl.gcmdSendValue = qtrue;
150 		cl.gcmdValue = genCmdNum;
151 	}
152 }
153 
IN_MLookDown(void)154 void IN_MLookDown( void ) {
155 	in_mlooking = qtrue;
156 }
157 
158 void IN_CenterView( void );
IN_MLookUp(void)159 void IN_MLookUp( void ) {
160 	in_mlooking = qfalse;
161 	if ( !cl_freelook->integer ) {
162 		IN_CenterView ();
163 	}
164 }
165 
IN_GenCMD1(void)166 void IN_GenCMD1( void )
167 {
168 	cl.gcmdSendValue = qtrue;
169 	cl.gcmdValue = GENCMD_SABERSWITCH;
170 }
171 
IN_GenCMD2(void)172 void IN_GenCMD2( void )
173 {
174 	cl.gcmdSendValue = qtrue;
175 	cl.gcmdValue = GENCMD_ENGAGE_DUEL;
176 }
177 
IN_GenCMD3(void)178 void IN_GenCMD3( void )
179 {
180 	cl.gcmdSendValue = qtrue;
181 	cl.gcmdValue = GENCMD_FORCE_HEAL;
182 }
183 
IN_GenCMD4(void)184 void IN_GenCMD4( void )
185 {
186 	cl.gcmdSendValue = qtrue;
187 	cl.gcmdValue = GENCMD_FORCE_SPEED;
188 }
189 
IN_GenCMD5(void)190 void IN_GenCMD5( void )
191 {
192 	cl.gcmdSendValue = qtrue;
193 	cl.gcmdValue = GENCMD_FORCE_PULL;
194 }
195 
IN_GenCMD6(void)196 void IN_GenCMD6( void )
197 {
198 	cl.gcmdSendValue = qtrue;
199 	cl.gcmdValue = GENCMD_FORCE_DISTRACT;
200 }
201 
IN_GenCMD7(void)202 void IN_GenCMD7( void )
203 {
204 	cl.gcmdSendValue = qtrue;
205 	cl.gcmdValue = GENCMD_FORCE_RAGE;
206 }
207 
IN_GenCMD8(void)208 void IN_GenCMD8( void )
209 {
210 	cl.gcmdSendValue = qtrue;
211 	cl.gcmdValue = GENCMD_FORCE_PROTECT;
212 }
213 
IN_GenCMD9(void)214 void IN_GenCMD9( void )
215 {
216 	cl.gcmdSendValue = qtrue;
217 	cl.gcmdValue = GENCMD_FORCE_ABSORB;
218 }
219 
IN_GenCMD10(void)220 void IN_GenCMD10( void )
221 {
222 	cl.gcmdSendValue = qtrue;
223 	cl.gcmdValue = GENCMD_FORCE_HEALOTHER;
224 }
225 
IN_GenCMD11(void)226 void IN_GenCMD11( void )
227 {
228 	cl.gcmdSendValue = qtrue;
229 	cl.gcmdValue = GENCMD_FORCE_FORCEPOWEROTHER;
230 }
231 
IN_GenCMD12(void)232 void IN_GenCMD12( void )
233 {
234 	cl.gcmdSendValue = qtrue;
235 	cl.gcmdValue = GENCMD_FORCE_SEEING;
236 }
237 
IN_GenCMD13(void)238 void IN_GenCMD13( void )
239 {
240 	cl.gcmdSendValue = qtrue;
241 	cl.gcmdValue = GENCMD_USE_SEEKER;
242 }
243 
IN_GenCMD14(void)244 void IN_GenCMD14( void )
245 {
246 	cl.gcmdSendValue = qtrue;
247 	cl.gcmdValue = GENCMD_USE_FIELD;
248 }
249 
IN_GenCMD15(void)250 void IN_GenCMD15( void )
251 {
252 	cl.gcmdSendValue = qtrue;
253 	cl.gcmdValue = GENCMD_USE_BACTA;
254 }
255 
IN_GenCMD16(void)256 void IN_GenCMD16( void )
257 {
258 	cl.gcmdSendValue = qtrue;
259 	cl.gcmdValue = GENCMD_USE_ELECTROBINOCULARS;
260 }
261 
IN_GenCMD17(void)262 void IN_GenCMD17( void )
263 {
264 	cl.gcmdSendValue = qtrue;
265 	cl.gcmdValue = GENCMD_ZOOM;
266 }
267 
IN_GenCMD18(void)268 void IN_GenCMD18( void )
269 {
270 	cl.gcmdSendValue = qtrue;
271 	cl.gcmdValue = GENCMD_USE_SENTRY;
272 }
273 
IN_GenCMD19(void)274 void IN_GenCMD19( void )
275 {
276 	if (Cvar_VariableIntegerValue("d_saberStanceDebug"))
277 	{
278 		Com_Printf("SABERSTANCEDEBUG: Gencmd on client set successfully.\n");
279 	}
280 	cl.gcmdSendValue = qtrue;
281 	cl.gcmdValue = GENCMD_SABERATTACKCYCLE;
282 }
283 
IN_GenCMD20(void)284 void IN_GenCMD20( void )
285 {
286 	cl.gcmdSendValue = qtrue;
287 	cl.gcmdValue = GENCMD_FORCE_THROW;
288 }
289 
IN_GenCMD21(void)290 void IN_GenCMD21( void )
291 {
292 	cl.gcmdSendValue = qtrue;
293 	cl.gcmdValue = GENCMD_USE_JETPACK;
294 }
295 
IN_GenCMD22(void)296 void IN_GenCMD22( void )
297 {
298 	cl.gcmdSendValue = qtrue;
299 	cl.gcmdValue = GENCMD_USE_BACTABIG;
300 }
301 
IN_GenCMD23(void)302 void IN_GenCMD23( void )
303 {
304 	cl.gcmdSendValue = qtrue;
305 	cl.gcmdValue = GENCMD_USE_HEALTHDISP;
306 }
307 
IN_GenCMD24(void)308 void IN_GenCMD24( void )
309 {
310 	cl.gcmdSendValue = qtrue;
311 	cl.gcmdValue = GENCMD_USE_AMMODISP;
312 }
313 
IN_GenCMD25(void)314 void IN_GenCMD25( void )
315 {
316 	cl.gcmdSendValue = qtrue;
317 	cl.gcmdValue = GENCMD_USE_EWEB;
318 }
319 
IN_GenCMD26(void)320 void IN_GenCMD26( void )
321 {
322 	cl.gcmdSendValue = qtrue;
323 	cl.gcmdValue = GENCMD_USE_CLOAK;
324 }
325 
IN_GenCMD27(void)326 void IN_GenCMD27( void )
327 {
328 	cl.gcmdSendValue = qtrue;
329 	cl.gcmdValue = GENCMD_TAUNT;
330 }
331 
IN_GenCMD28(void)332 void IN_GenCMD28( void )
333 {
334 	cl.gcmdSendValue = qtrue;
335 	cl.gcmdValue = GENCMD_BOW;
336 }
337 
IN_GenCMD29(void)338 void IN_GenCMD29( void )
339 {
340 	cl.gcmdSendValue = qtrue;
341 	cl.gcmdValue = GENCMD_MEDITATE;
342 }
343 
IN_GenCMD30(void)344 void IN_GenCMD30( void )
345 {
346 	cl.gcmdSendValue = qtrue;
347 	cl.gcmdValue = GENCMD_FLOURISH;
348 }
349 
IN_GenCMD31(void)350 void IN_GenCMD31( void )
351 {
352 	cl.gcmdSendValue = qtrue;
353 	cl.gcmdValue = GENCMD_GLOAT;
354 }
355 
356 
357 //toggle automap view mode
358 static bool g_clAutoMapMode = false;
IN_AutoMapButton(void)359 void IN_AutoMapButton(void)
360 {
361 	g_clAutoMapMode = !g_clAutoMapMode;
362 }
363 
364 //toggle between automap, radar, nothing
365 extern cvar_t *r_autoMap;
IN_AutoMapToggle(void)366 void IN_AutoMapToggle(void)
367 {
368 	Cvar_User_SetValue("cg_drawRadar", !Cvar_VariableValue("cg_drawRadar"));
369 	/*
370 	if (r_autoMap && r_autoMap->integer)
371 	{ //automap off, radar on
372 		Cvar_Set("r_autoMap", "0");
373 		Cvar_Set("cg_drawRadar", "1");
374 	}
375 	else if (Cvar_VariableIntegerValue("cg_drawRadar"))
376 	{ //radar off, automap should be off too
377 		Cvar_Set("cg_drawRadar", "0");
378 	}
379 	else
380 	{ //turn automap on
381 		Cvar_Set("r_autoMap", "1");
382 	}
383 	*/
384 }
385 
IN_VoiceChatButton(void)386 void IN_VoiceChatButton(void)
387 {
388 	if (!cls.uiStarted)
389 	{ //ui not loaded so this command is useless
390 		return;
391 	}
392 	UIVM_SetActiveMenu( UIMENU_VOICECHAT );
393 }
394 
IN_KeyDown(kbutton_t * b)395 void IN_KeyDown( kbutton_t *b ) {
396 	int		k;
397 	char	*c;
398 
399 	c = Cmd_Argv(1);
400 	if ( c[0] ) {
401 		k = atoi(c);
402 	} else {
403 		k = -1;		// typed manually at the console for continuous down
404 	}
405 
406 	if ( k == b->down[0] || k == b->down[1] ) {
407 		return;		// repeating key
408 	}
409 
410 	if ( !b->down[0] ) {
411 		b->down[0] = k;
412 	} else if ( !b->down[1] ) {
413 		b->down[1] = k;
414 	} else {
415 		Com_Printf ("Three keys down for a button!\n");
416 		return;
417 	}
418 
419 	if ( b->active ) {
420 		return;		// still down
421 	}
422 
423 	// save timestamp for partial frame summing
424 	c = Cmd_Argv(2);
425 	b->downtime = atoi(c);
426 
427 	b->active = qtrue;
428 	b->wasPressed = qtrue;
429 }
430 
IN_KeyUp(kbutton_t * b)431 void IN_KeyUp( kbutton_t *b ) {
432 	int		k;
433 	char	*c;
434 	unsigned	uptime;
435 
436 	c = Cmd_Argv(1);
437 	if ( c[0] ) {
438 		k = atoi(c);
439 	} else {
440 		// typed manually at the console, assume for unsticking, so clear all
441 		b->down[0] = b->down[1] = 0;
442 		b->active = qfalse;
443 		return;
444 	}
445 
446 	if ( b->down[0] == k ) {
447 		b->down[0] = 0;
448 	} else if ( b->down[1] == k ) {
449 		b->down[1] = 0;
450 	} else {
451 		return;		// key up without coresponding down (menu pass through)
452 	}
453 	if ( b->down[0] || b->down[1] ) {
454 		return;		// some other key is still holding it down
455 	}
456 
457 	b->active = qfalse;
458 
459 	// save timestamp for partial frame summing
460 	c = Cmd_Argv(2);
461 	uptime = atoi(c);
462 	if ( uptime ) {
463 		b->msec += uptime - b->downtime;
464 	} else {
465 		b->msec += frame_msec / 2;
466 	}
467 
468 	b->active = qfalse;
469 }
470 
471 
472 
473 /*
474 ===============
475 CL_KeyState
476 
477 Returns the fraction of the frame that the key was down
478 ===============
479 */
CL_KeyState(kbutton_t * key)480 float CL_KeyState( kbutton_t *key ) {
481 	float		val;
482 	int			msec;
483 
484 	msec = key->msec;
485 	key->msec = 0;
486 
487 	if ( key->active ) {
488 		// still down
489 		if ( !key->downtime ) {
490 			msec = com_frameTime;
491 		} else {
492 			msec += com_frameTime - key->downtime;
493 		}
494 		key->downtime = com_frameTime;
495 	}
496 
497 #if 0
498 	if (msec) {
499 		Com_Printf ("%i ", msec);
500 	}
501 #endif
502 
503 	val = (float)msec / frame_msec;
504 	if ( val < 0 ) {
505 		val = 0;
506 	}
507 	if ( val > 1 ) {
508 		val = 1;
509 	}
510 
511 	return val;
512 }
513 
514 #define		AUTOMAP_KEY_FORWARD			1
515 #define		AUTOMAP_KEY_BACK			2
516 #define		AUTOMAP_KEY_YAWLEFT			3
517 #define		AUTOMAP_KEY_YAWRIGHT		4
518 #define		AUTOMAP_KEY_PITCHUP			5
519 #define		AUTOMAP_KEY_PITCHDOWN		6
520 #define		AUTOMAP_KEY_DEFAULTVIEW		7
521 static autoMapInput_t			g_clAutoMapInput;
522 //intercept certain keys during automap mode
CL_AutoMapKey(int autoMapKey,qboolean up)523 static void CL_AutoMapKey(int autoMapKey, qboolean up)
524 {
525 	autoMapInput_t *data = (autoMapInput_t *)cl.mSharedMemory;
526 
527 	switch (autoMapKey)
528 	{
529 	case AUTOMAP_KEY_FORWARD:
530         if (up)
531 		{
532 			g_clAutoMapInput.up = 0.0f;
533 		}
534 		else
535 		{
536 			g_clAutoMapInput.up = 16.0f;
537 		}
538 		break;
539 	case AUTOMAP_KEY_BACK:
540         if (up)
541 		{
542 			g_clAutoMapInput.down = 0.0f;
543 		}
544 		else
545 		{
546 			g_clAutoMapInput.down = 16.0f;
547 		}
548 		break;
549 	case AUTOMAP_KEY_YAWLEFT:
550 		if (up)
551 		{
552 			g_clAutoMapInput.yaw = 0.0f;
553 		}
554 		else
555 		{
556 			g_clAutoMapInput.yaw = -4.0f;
557 		}
558 		break;
559 	case AUTOMAP_KEY_YAWRIGHT:
560 		if (up)
561 		{
562 			g_clAutoMapInput.yaw = 0.0f;
563 		}
564 		else
565 		{
566 			g_clAutoMapInput.yaw = 4.0f;
567 		}
568 		break;
569 	case AUTOMAP_KEY_PITCHUP:
570 		if (up)
571 		{
572 			g_clAutoMapInput.pitch = 0.0f;
573 		}
574 		else
575 		{
576 			g_clAutoMapInput.pitch = -4.0f;
577 		}
578 		break;
579 	case AUTOMAP_KEY_PITCHDOWN:
580 		if (up)
581 		{
582 			g_clAutoMapInput.pitch = 0.0f;
583 		}
584 		else
585 		{
586 			g_clAutoMapInput.pitch = 4.0f;
587 		}
588 		break;
589 	case AUTOMAP_KEY_DEFAULTVIEW:
590 		memset(&g_clAutoMapInput, 0, sizeof(autoMapInput_t));
591 		g_clAutoMapInput.goToDefaults = qtrue;
592 		break;
593 	default:
594 		break;
595 	}
596 
597 	memcpy(data, &g_clAutoMapInput, sizeof(autoMapInput_t));
598 
599 	if (cls.cgameStarted)
600 	{
601 		CGVM_AutomapInput();
602 	}
603 
604 	g_clAutoMapInput.goToDefaults = qfalse;
605 }
606 
607 
IN_UpDown(void)608 void IN_UpDown(void)
609 {
610 	if (g_clAutoMapMode)
611 	{
612 		CL_AutoMapKey(AUTOMAP_KEY_PITCHUP, qfalse);
613 	}
614 	else
615 	{
616 		IN_KeyDown(&in_up);
617 	}
618 }
IN_UpUp(void)619 void IN_UpUp(void)
620 {
621 	if (g_clAutoMapMode)
622 	{
623 		CL_AutoMapKey(AUTOMAP_KEY_PITCHUP, qtrue);
624 	}
625 	else
626 	{
627 		IN_KeyUp(&in_up);
628 	}
629 }
IN_DownDown(void)630 void IN_DownDown(void)
631 {
632 	if (g_clAutoMapMode)
633 	{
634 		CL_AutoMapKey(AUTOMAP_KEY_PITCHDOWN, qfalse);
635 	}
636 	else
637 	{
638 		IN_KeyDown(&in_down);
639 	}
640 }
IN_DownUp(void)641 void IN_DownUp(void)
642 {
643 	if (g_clAutoMapMode)
644 	{
645 		CL_AutoMapKey(AUTOMAP_KEY_PITCHDOWN, qtrue);
646 	}
647 	else
648 	{
649 		IN_KeyUp(&in_down);
650 	}
651 }
IN_LeftDown(void)652 void IN_LeftDown(void) {IN_KeyDown(&in_left);}
IN_LeftUp(void)653 void IN_LeftUp(void) {IN_KeyUp(&in_left);}
IN_RightDown(void)654 void IN_RightDown(void) {IN_KeyDown(&in_right);}
IN_RightUp(void)655 void IN_RightUp(void) {IN_KeyUp(&in_right);}
IN_ForwardDown(void)656 void IN_ForwardDown(void)
657 {
658 	if (g_clAutoMapMode)
659 	{
660 		CL_AutoMapKey(AUTOMAP_KEY_FORWARD, qfalse);
661 	}
662 	else
663 	{
664 		IN_KeyDown(&in_forward);
665 	}
666 }
IN_ForwardUp(void)667 void IN_ForwardUp(void)
668 {
669 	if (g_clAutoMapMode)
670 	{
671 		CL_AutoMapKey(AUTOMAP_KEY_FORWARD, qtrue);
672 	}
673 	else
674 	{
675 		IN_KeyUp(&in_forward);
676 	}
677 }
IN_BackDown(void)678 void IN_BackDown(void)
679 {
680 	if (g_clAutoMapMode)
681 	{
682 		CL_AutoMapKey(AUTOMAP_KEY_BACK, qfalse);
683 	}
684 	else
685 	{
686 		IN_KeyDown(&in_back);
687 	}
688 }
IN_BackUp(void)689 void IN_BackUp(void)
690 {
691 	if (g_clAutoMapMode)
692 	{
693 		CL_AutoMapKey(AUTOMAP_KEY_BACK, qtrue);
694 	}
695 	else
696 	{
697 		IN_KeyUp(&in_back);
698 	}
699 }
IN_LookupDown(void)700 void IN_LookupDown(void) {IN_KeyDown(&in_lookup);}
IN_LookupUp(void)701 void IN_LookupUp(void) {IN_KeyUp(&in_lookup);}
IN_LookdownDown(void)702 void IN_LookdownDown(void) {IN_KeyDown(&in_lookdown);}
IN_LookdownUp(void)703 void IN_LookdownUp(void) {IN_KeyUp(&in_lookdown);}
IN_MoveleftDown(void)704 void IN_MoveleftDown(void)
705 {
706 	if (g_clAutoMapMode)
707 	{
708 		CL_AutoMapKey(AUTOMAP_KEY_YAWLEFT, qfalse);
709 	}
710 	else
711 	{
712 		IN_KeyDown(&in_moveleft);
713 	}
714 }
IN_MoveleftUp(void)715 void IN_MoveleftUp(void)
716 {
717 	if (g_clAutoMapMode)
718 	{
719 		CL_AutoMapKey(AUTOMAP_KEY_YAWLEFT, qtrue);
720 	}
721 	else
722 	{
723 		IN_KeyUp(&in_moveleft);
724 	}
725 }
IN_MoverightDown(void)726 void IN_MoverightDown(void)
727 {
728 	if (g_clAutoMapMode)
729 	{
730 		CL_AutoMapKey(AUTOMAP_KEY_YAWRIGHT, qfalse);
731 	}
732 	else
733 	{
734 		IN_KeyDown(&in_moveright);
735 	}
736 }
IN_MoverightUp(void)737 void IN_MoverightUp(void)
738 {
739 	if (g_clAutoMapMode)
740 	{
741 		CL_AutoMapKey(AUTOMAP_KEY_YAWRIGHT, qtrue);
742 	}
743 	else
744 	{
745 		IN_KeyUp(&in_moveright);
746 	}
747 }
748 
IN_SpeedDown(void)749 void IN_SpeedDown(void) {IN_KeyDown(&in_speed);}
IN_SpeedUp(void)750 void IN_SpeedUp(void) {IN_KeyUp(&in_speed);}
IN_StrafeDown(void)751 void IN_StrafeDown(void) {IN_KeyDown(&in_strafe);}
IN_StrafeUp(void)752 void IN_StrafeUp(void) {IN_KeyUp(&in_strafe);}
753 
IN_Button0Down(void)754 void IN_Button0Down(void) {IN_KeyDown(&in_buttons[0]);}
IN_Button0Up(void)755 void IN_Button0Up(void) {IN_KeyUp(&in_buttons[0]);}
IN_Button1Down(void)756 void IN_Button1Down(void) {IN_KeyDown(&in_buttons[1]);}
IN_Button1Up(void)757 void IN_Button1Up(void) {IN_KeyUp(&in_buttons[1]);}
IN_Button2Down(void)758 void IN_Button2Down(void) {IN_KeyDown(&in_buttons[2]);}
IN_Button2Up(void)759 void IN_Button2Up(void) {IN_KeyUp(&in_buttons[2]);}
IN_Button3Down(void)760 void IN_Button3Down(void) {IN_KeyDown(&in_buttons[3]);}
IN_Button3Up(void)761 void IN_Button3Up(void) {IN_KeyUp(&in_buttons[3]);}
IN_Button4Down(void)762 void IN_Button4Down(void) {IN_KeyDown(&in_buttons[4]);}
IN_Button4Up(void)763 void IN_Button4Up(void) {IN_KeyUp(&in_buttons[4]);}
IN_Button5Down(void)764 void IN_Button5Down(void) //use key
765 {
766 	if (g_clAutoMapMode)
767 	{
768 		CL_AutoMapKey(AUTOMAP_KEY_DEFAULTVIEW, qfalse);
769 	}
770 	else
771 	{
772 		IN_KeyDown(&in_buttons[5]);
773 	}
774 }
IN_Button5Up(void)775 void IN_Button5Up(void) {IN_KeyUp(&in_buttons[5]);}
IN_Button6Down(void)776 void IN_Button6Down(void) {IN_KeyDown(&in_buttons[6]);}
IN_Button6Up(void)777 void IN_Button6Up(void) {IN_KeyUp(&in_buttons[6]);}
IN_Button7Down(void)778 void IN_Button7Down(void) {IN_KeyDown(&in_buttons[7]);}
IN_Button7Up(void)779 void IN_Button7Up(void){IN_KeyUp(&in_buttons[7]);}
IN_Button8Down(void)780 void IN_Button8Down(void) {IN_KeyDown(&in_buttons[8]);}
IN_Button8Up(void)781 void IN_Button8Up(void) {IN_KeyUp(&in_buttons[8]);}
IN_Button9Down(void)782 void IN_Button9Down(void) {IN_KeyDown(&in_buttons[9]);}
IN_Button9Up(void)783 void IN_Button9Up(void) {IN_KeyUp(&in_buttons[9]);}
IN_Button10Down(void)784 void IN_Button10Down(void) {IN_KeyDown(&in_buttons[10]);}
IN_Button10Up(void)785 void IN_Button10Up(void) {IN_KeyUp(&in_buttons[10]);}
IN_Button11Down(void)786 void IN_Button11Down(void) {IN_KeyDown(&in_buttons[11]);}
IN_Button11Up(void)787 void IN_Button11Up(void) {IN_KeyUp(&in_buttons[11]);}
IN_Button12Down(void)788 void IN_Button12Down(void) {IN_KeyDown(&in_buttons[12]);}
IN_Button12Up(void)789 void IN_Button12Up(void) {IN_KeyUp(&in_buttons[12]);}
IN_Button13Down(void)790 void IN_Button13Down(void) {IN_KeyDown(&in_buttons[13]);}
IN_Button13Up(void)791 void IN_Button13Up(void) {IN_KeyUp(&in_buttons[13]);}
IN_Button14Down(void)792 void IN_Button14Down(void) {IN_KeyDown(&in_buttons[14]);}
IN_Button14Up(void)793 void IN_Button14Up(void) {IN_KeyUp(&in_buttons[14]);}
IN_Button15Down(void)794 void IN_Button15Down(void) {IN_KeyDown(&in_buttons[15]);}
IN_Button15Up(void)795 void IN_Button15Up(void) {IN_KeyUp(&in_buttons[15]);}
796 
IN_CenterView(void)797 void IN_CenterView (void) {
798 	cl.viewangles[PITCH] = -SHORT2ANGLE(cl.snap.ps.delta_angles[PITCH]);
799 }
800 
801 //==========================================================================
802 
803 cvar_t	*cl_upspeed;
804 cvar_t	*cl_forwardspeed;
805 cvar_t	*cl_sidespeed;
806 
807 cvar_t	*cl_yawspeed;
808 cvar_t	*cl_pitchspeed;
809 
810 cvar_t	*cl_run;
811 
812 cvar_t	*cl_anglespeedkey;
813 
814 
815 /*
816 ================
817 CL_AdjustAngles
818 
819 Moves the local angle positions
820 ================
821 */
CL_AdjustAngles(void)822 void CL_AdjustAngles( void ) {
823 	float	speed;
824 
825 	if ( in_speed.active ) {
826 		speed = 0.001 * cls.frametime * cl_anglespeedkey->value;
827 	} else {
828 		speed = 0.001 * cls.frametime;
829 	}
830 
831 	if ( !in_strafe.active ) {
832 		if ( cl_mYawOverride )
833 		{
834 			if ( cl_mSensitivityOverride )
835 			{
836 				cl.viewangles[YAW] -= cl_mYawOverride*cl_mSensitivityOverride*speed*cl_yawspeed->value*CL_KeyState (&in_right);
837 				cl.viewangles[YAW] += cl_mYawOverride*cl_mSensitivityOverride*speed*cl_yawspeed->value*CL_KeyState (&in_left);
838 			}
839 			else
840 			{
841 				cl.viewangles[YAW] -= cl_mYawOverride*OVERRIDE_MOUSE_SENSITIVITY*speed*cl_yawspeed->value*CL_KeyState (&in_right);
842 				cl.viewangles[YAW] += cl_mYawOverride*OVERRIDE_MOUSE_SENSITIVITY*speed*cl_yawspeed->value*CL_KeyState (&in_left);
843 			}
844 		}
845 		else
846 		{
847 			cl.viewangles[YAW] -= speed*cl_yawspeed->value*CL_KeyState (&in_right);
848 			cl.viewangles[YAW] += speed*cl_yawspeed->value*CL_KeyState (&in_left);
849 		}
850 	}
851 
852 	if ( cl_mPitchOverride )
853 	{
854 		if ( cl_mSensitivityOverride )
855 		{
856 			cl.viewangles[PITCH] -= cl_mPitchOverride*cl_mSensitivityOverride*speed*cl_pitchspeed->value * CL_KeyState (&in_lookup);
857 			cl.viewangles[PITCH] += cl_mPitchOverride*cl_mSensitivityOverride*speed*cl_pitchspeed->value * CL_KeyState (&in_lookdown);
858 		}
859 		else
860 		{
861 			cl.viewangles[PITCH] -= cl_mPitchOverride*OVERRIDE_MOUSE_SENSITIVITY*speed*cl_pitchspeed->value * CL_KeyState (&in_lookup);
862 			cl.viewangles[PITCH] += cl_mPitchOverride*OVERRIDE_MOUSE_SENSITIVITY*speed*cl_pitchspeed->value * CL_KeyState (&in_lookdown);
863 		}
864 	}
865 	else
866 	{
867 		cl.viewangles[PITCH] -= speed*cl_pitchspeed->value * CL_KeyState (&in_lookup);
868 		cl.viewangles[PITCH] += speed*cl_pitchspeed->value * CL_KeyState (&in_lookdown);
869 	}
870 }
871 
872 /*
873 ================
874 CL_KeyMove
875 
876 Sets the usercmd_t based on key states
877 ================
878 */
CL_KeyMove(usercmd_t * cmd)879 void CL_KeyMove( usercmd_t *cmd ) {
880 	int		movespeed;
881 	int		forward, side, up;
882 
883 	//
884 	// adjust for speed key / running
885 	// the walking flag is to keep animations consistant
886 	// even during acceleration and develeration
887 	//
888 	if ( in_speed.active ^ cl_run->integer ) {
889 		movespeed = 127;
890 		cmd->buttons &= ~BUTTON_WALKING;
891 	} else {
892 		cmd->buttons |= BUTTON_WALKING;
893 		movespeed = 46;
894 	}
895 
896 	forward = 0;
897 	side = 0;
898 	up = 0;
899 	if ( in_strafe.active ) {
900 		side += movespeed * CL_KeyState (&in_right);
901 		side -= movespeed * CL_KeyState (&in_left);
902 	}
903 
904 	side += movespeed * CL_KeyState (&in_moveright);
905 	side -= movespeed * CL_KeyState (&in_moveleft);
906 
907 
908 	up += movespeed * CL_KeyState (&in_up);
909 	up -= movespeed * CL_KeyState (&in_down);
910 
911 	forward += movespeed * CL_KeyState (&in_forward);
912 	forward -= movespeed * CL_KeyState (&in_back);
913 
914 	cmd->forwardmove = ClampChar( forward );
915 	cmd->rightmove = ClampChar( side );
916 	cmd->upmove = ClampChar( up );
917 }
918 
919 /*
920 =================
921 CL_MouseEvent
922 =================
923 */
CL_MouseEvent(int dx,int dy,int time)924 void CL_MouseEvent( int dx, int dy, int time ) {
925 	if (g_clAutoMapMode && cls.cgameStarted)
926 	{ //automap input
927 		autoMapInput_t *data = (autoMapInput_t *)cl.mSharedMemory;
928 
929 		g_clAutoMapInput.yaw = dx;
930 		g_clAutoMapInput.pitch = dy;
931 		memcpy(data, &g_clAutoMapInput, sizeof(autoMapInput_t));
932 		CGVM_AutomapInput();
933 
934 		g_clAutoMapInput.yaw = 0.0f;
935 		g_clAutoMapInput.pitch = 0.0f;
936 	}
937 	else if ( Key_GetCatcher( ) & KEYCATCH_UI ) {
938 		UIVM_MouseEvent( dx, dy );
939 	} else if ( Key_GetCatcher( ) & KEYCATCH_CGAME ) {
940 		CGVM_MouseEvent( dx, dy );
941 	} else {
942 		cl.mouseDx[cl.mouseIndex] += dx;
943 		cl.mouseDy[cl.mouseIndex] += dy;
944 	}
945 }
946 
947 /*
948 =================
949 CL_JoystickEvent
950 
951 Joystick values stay set until changed
952 =================
953 */
CL_JoystickEvent(int axis,int value,int time)954 void CL_JoystickEvent( int axis, int value, int time ) {
955 	if ( axis < 0 || axis >= MAX_JOYSTICK_AXIS ) {
956 		Com_Error( ERR_DROP, "CL_JoystickEvent: bad axis %i", axis );
957 	}
958 	cl.joystickAxis[axis] = value;
959 }
960 
961 /*
962 =================
963 CL_JoystickMove
964 =================
965 */
966 extern cvar_t *in_joystick;
CL_JoystickMove(usercmd_t * cmd)967 void CL_JoystickMove( usercmd_t *cmd ) {
968 	float	anglespeed;
969 
970 	if ( !in_joystick->integer )
971 	{
972 		return;
973 	}
974 
975 	if ( !(in_speed.active ^ cl_run->integer) ) {
976 		cmd->buttons |= BUTTON_WALKING;
977 	}
978 
979 	if ( in_speed.active ) {
980 		anglespeed = 0.001 * cls.frametime * cl_anglespeedkey->value;
981 	} else {
982 		anglespeed = 0.001 * cls.frametime;
983 	}
984 
985 	if ( !in_strafe.active ) {
986 		if ( cl_mYawOverride )
987 		{
988 			if ( cl_mSensitivityOverride )
989 			{
990 				cl.viewangles[YAW] += cl_mYawOverride * cl_mSensitivityOverride * cl.joystickAxis[AXIS_SIDE]/2.0f;
991 			}
992 			else
993 			{
994 				cl.viewangles[YAW] += cl_mYawOverride * OVERRIDE_MOUSE_SENSITIVITY * cl.joystickAxis[AXIS_SIDE]/2.0f;
995 			}
996 		}
997 		else
998 		{
999 			cl.viewangles[YAW] += anglespeed * (cl_yawspeed->value / 100.0f) * cl.joystickAxis[AXIS_SIDE];
1000 		}
1001 	}
1002 	else
1003 	{
1004 		cmd->rightmove = ClampChar( cmd->rightmove + cl.joystickAxis[AXIS_SIDE] );
1005 	}
1006 
1007 	if ( in_mlooking || cl_freelook->integer ) {
1008 		if ( cl_mPitchOverride )
1009 		{
1010 			if ( cl_mSensitivityOverride )
1011 			{
1012 				cl.viewangles[PITCH] += cl_mPitchOverride * cl_mSensitivityOverride * cl.joystickAxis[AXIS_FORWARD]/2.0f;
1013 			}
1014 			else
1015 			{
1016 				cl.viewangles[PITCH] += cl_mPitchOverride * OVERRIDE_MOUSE_SENSITIVITY * cl.joystickAxis[AXIS_FORWARD]/2.0f;
1017 			}
1018 		}
1019 		else
1020 		{
1021 			cl.viewangles[PITCH] += anglespeed * (cl_pitchspeed->value / 100.0f) * cl.joystickAxis[AXIS_FORWARD];
1022 		}
1023 	} else
1024 	{
1025 		cmd->forwardmove = ClampChar( cmd->forwardmove + cl.joystickAxis[AXIS_FORWARD] );
1026 	}
1027 
1028 	cmd->upmove = ClampChar( cmd->upmove + cl.joystickAxis[AXIS_UP] );
1029 }
1030 
1031 /*
1032 =================
1033 CL_MouseMove
1034 =================
1035 */
CL_MouseMove(usercmd_t * cmd)1036 void CL_MouseMove( usercmd_t *cmd ) {
1037 	float	mx, my;
1038 	const float	speed = static_cast<float>(frame_msec);
1039 
1040 	// allow mouse smoothing
1041 	if ( m_filter->integer ) {
1042 		mx = ( cl.mouseDx[0] + cl.mouseDx[1] ) * 0.5;
1043 		my = ( cl.mouseDy[0] + cl.mouseDy[1] ) * 0.5;
1044 	} else {
1045 		mx = cl.mouseDx[cl.mouseIndex];
1046 		my = cl.mouseDy[cl.mouseIndex];
1047 	}
1048 
1049 	cl.mouseIndex ^= 1;
1050 	cl.mouseDx[cl.mouseIndex] = 0;
1051 	cl.mouseDy[cl.mouseIndex] = 0;
1052 
1053 	if ( mx == 0.0f && my == 0.0f )
1054 		return;
1055 
1056 	if ( cl_mouseAccel->value != 0.0f )
1057 	{
1058 		if ( cl_mouseAccelStyle->integer == 0 )
1059 		{
1060 			float accelSensitivity;
1061 			float rate;
1062 
1063 			rate = SQRTFAST( mx * mx + my * my ) / speed;
1064 
1065 			if ( cl_mYawOverride || cl_mPitchOverride )
1066 			{//FIXME: different people have different speed mouses,
1067 				if ( cl_mSensitivityOverride )
1068 				{
1069 					//this will fuck things up for them, need to clamp
1070 					//max input?
1071 					accelSensitivity = cl_mSensitivityOverride;
1072 				}
1073 				else
1074 				{
1075 					accelSensitivity = cl_sensitivity->value + rate * cl_mouseAccel->value;
1076 				}
1077 			}
1078 			else
1079 			{
1080 				accelSensitivity = cl_sensitivity->value + rate * cl_mouseAccel->value;
1081 			}
1082 			mx *= accelSensitivity;
1083 			my *= accelSensitivity;
1084 
1085 			if ( cl_showMouseRate->integer )
1086 				Com_Printf( "rate: %f, accelSensitivity: %f\n", rate, accelSensitivity );
1087 		}
1088 		else
1089 		{
1090 			float rate[2];
1091 			float power[2];
1092 
1093 			// sensitivity remains pretty much unchanged at low speeds
1094 			// cl_mouseAccel is a power value to how the acceleration is shaped
1095 			// cl_mouseAccelOffset is the rate for which the acceleration will have doubled the non accelerated amplification
1096 			// NOTE: decouple the config cvars for independent acceleration setup along X and Y?
1097 
1098 			rate[0] = fabs( mx ) / speed;
1099 			rate[1] = fabs( my ) / speed;
1100 			power[0] = powf( rate[0] / cl_mouseAccelOffset->value, cl_mouseAccel->value );
1101 			power[1] = powf( rate[1] / cl_mouseAccelOffset->value, cl_mouseAccel->value );
1102 
1103 			if ( cl_mYawOverride || cl_mPitchOverride )
1104 			{//FIXME: different people have different speed mouses,
1105 				if ( cl_mSensitivityOverride )
1106 				{
1107 					//this will fuck things up for them, need to clamp
1108 					//max input?
1109 					mx = cl_mSensitivityOverride * (mx + ((mx < 0) ? -power[0] : power[0]) * cl_mouseAccelOffset->value);
1110 					my = cl_mSensitivityOverride * (my + ((my < 0) ? -power[1] : power[1]) * cl_mouseAccelOffset->value);
1111 				}
1112 				else
1113 				{
1114 					mx = cl_sensitivity->value * (mx + ((mx < 0) ? -power[0] : power[0]) * cl_mouseAccelOffset->value);
1115 					my = cl_sensitivity->value * (my + ((my < 0) ? -power[1] : power[1]) * cl_mouseAccelOffset->value);
1116 				}
1117 			}
1118 			else
1119 			{
1120 				mx = cl_sensitivity->value * (mx + ((mx < 0) ? -power[0] : power[0]) * cl_mouseAccelOffset->value);
1121 				my = cl_sensitivity->value * (my + ((my < 0) ? -power[1] : power[1]) * cl_mouseAccelOffset->value);
1122 			}
1123 
1124 			if ( cl_showMouseRate->integer )
1125 				Com_Printf( "ratex: %f, ratey: %f, powx: %f, powy: %f\n", rate[0], rate[1], power[0], power[1] );
1126 		}
1127 	}
1128 	else
1129 	{
1130 		if ( cl_mYawOverride || cl_mPitchOverride )
1131 		{//FIXME: different people have different speed mouses,
1132 			if ( cl_mSensitivityOverride )
1133 			{
1134 				//this will fuck things up for them, need to clamp
1135 				//max input?
1136 				mx *= cl_mSensitivityOverride;
1137 				my *= cl_mSensitivityOverride;
1138 			}
1139 			else
1140 			{
1141 				mx *= cl_sensitivity->value;
1142 				my *= cl_sensitivity->value;
1143 			}
1144 		}
1145 		else
1146 		{
1147 			mx *= cl_sensitivity->value;
1148 			my *= cl_sensitivity->value;
1149 		}
1150 	}
1151 
1152 	// ingame FOV
1153 	mx *= cl.cgameSensitivity;
1154 	my *= cl.cgameSensitivity;
1155 
1156 	// add mouse X/Y movement to cmd
1157 	if ( in_strafe.active )
1158 		cmd->rightmove = ClampChar( cmd->rightmove + m_side->value * mx );
1159 	else {
1160 		if ( cl_mYawOverride )
1161 			cl.viewangles[YAW] -= cl_mYawOverride * mx;
1162 		else
1163 			cl.viewangles[YAW] -= m_yaw->value * mx;
1164 	}
1165 
1166 	if ( (in_mlooking || cl_freelook->integer) && !in_strafe.active ) {
1167 		// VVFIXME - This is supposed to be a CVAR
1168 		const float cl_pitchSensitivity = 1.0f;
1169 		const float pitch = cl_bUseFighterPitch ? m_pitchVeh->value : m_pitch->value;
1170 		if ( cl_mPitchOverride ) {
1171 			if ( pitch > 0 )
1172 				cl.viewangles[PITCH] += cl_mPitchOverride * my * cl_pitchSensitivity;
1173 			else
1174 				cl.viewangles[PITCH] -= cl_mPitchOverride * my * cl_pitchSensitivity;
1175 		}
1176 		else
1177 			cl.viewangles[PITCH] += pitch * my * cl_pitchSensitivity;
1178 	}
1179 	else
1180 		cmd->forwardmove = ClampChar( cmd->forwardmove - m_forward->value * my );
1181 }
1182 
CL_NoUseableForce(void)1183 qboolean CL_NoUseableForce(void)
1184 {
1185 	if (!cls.cgameStarted)
1186 	{ //ahh, no cgame loaded
1187 		return qfalse;
1188 	}
1189 
1190 	return CGVM_NoUseableForce();
1191 }
1192 
1193 /*
1194 ==============
1195 CL_CmdButtons
1196 ==============
1197 */
CL_CmdButtons(usercmd_t * cmd)1198 void CL_CmdButtons( usercmd_t *cmd ) {
1199 	int		i;
1200 
1201 	//
1202 	// figure button bits
1203 	// send a button bit even if the key was pressed and released in
1204 	// less than a frame
1205 	//
1206 	for (i = 0 ; i < MAX_KBUTTONS ; i++) {
1207 		if ( in_buttons[i].active || in_buttons[i].wasPressed ) {
1208 			cmd->buttons |= 1 << i;
1209 		}
1210 		in_buttons[i].wasPressed = qfalse;
1211 	}
1212 
1213 	if (cmd->buttons & BUTTON_FORCEPOWER)
1214 	{ //check for transferring a use force to a use inventory...
1215 		if ((cmd->buttons & BUTTON_USE) || CL_NoUseableForce())
1216 		{ //it's pushed, remap it!
1217 			cmd->buttons &= ~BUTTON_FORCEPOWER;
1218 			cmd->buttons |= BUTTON_USE_HOLDABLE;
1219 		}
1220 	}
1221 
1222 	if ( Key_GetCatcher( ) ) {
1223 		cmd->buttons |= BUTTON_TALK;
1224 	}
1225 
1226 	// allow the game to know if any key at all is
1227 	// currently pressed, even if it isn't bound to anything
1228 	if ( kg.anykeydown && Key_GetCatcher( ) == 0 ) {
1229 		cmd->buttons |= BUTTON_ANY;
1230 	}
1231 }
1232 
1233 
1234 /*
1235 ==============
1236 CL_FinishMove
1237 ==============
1238 */
1239 vec3_t cl_sendAngles={0};
1240 vec3_t cl_lastViewAngles={0};
CL_FinishMove(usercmd_t * cmd)1241 void CL_FinishMove( usercmd_t *cmd ) {
1242 	int		i;
1243 
1244 	// copy the state that the cgame is currently sending
1245 	cmd->weapon = cl.cgameUserCmdValue;
1246 	cmd->forcesel = cl.cgameForceSelection;
1247 	cmd->invensel = cl.cgameInvenSelection;
1248 
1249 	if (cl.gcmdSendValue)
1250 	{
1251 		cmd->generic_cmd = cl.gcmdValue;
1252 		//cl.gcmdSendValue = qfalse;
1253 		cl.gcmdSentValue = qtrue;
1254 	}
1255 	else
1256 	{
1257 		cmd->generic_cmd = 0;
1258 	}
1259 
1260 	// send the current server time so the amount of movement
1261 	// can be determined without allowing cheating
1262 	cmd->serverTime = cl.serverTime;
1263 
1264 	if (cl.cgameViewAngleForceTime > cl.serverTime)
1265 	{
1266 		cl.cgameViewAngleForce[YAW] -= SHORT2ANGLE(cl.snap.ps.delta_angles[YAW]);
1267 
1268 		cl.viewangles[YAW] = cl.cgameViewAngleForce[YAW];
1269 		cl.cgameViewAngleForceTime = 0;
1270 	}
1271 
1272 	if ( cl_crazyShipControls )
1273 	{
1274 		float pitchSubtract, pitchDelta, yawDelta;
1275 
1276 		yawDelta = AngleSubtract(cl.viewangles[YAW],cl_lastViewAngles[YAW]);
1277 		//yawDelta *= (4.0f*pVeh->m_fTimeModifier);
1278 		cl_sendAngles[ROLL] -= yawDelta;
1279 
1280 		float nRoll = fabs(cl_sendAngles[ROLL]);
1281 
1282 		pitchDelta = AngleSubtract(cl.viewangles[PITCH],cl_lastViewAngles[PITCH]);
1283 		//pitchDelta *= (2.0f*pVeh->m_fTimeModifier);
1284 		pitchSubtract = pitchDelta * (nRoll/90.0f);
1285 		cl_sendAngles[PITCH] += pitchDelta-pitchSubtract;
1286 
1287 		//yaw-roll calc should be different
1288 		if (nRoll > 90.0f)
1289 		{
1290 			nRoll -= 180.0f;
1291 		}
1292 		if (nRoll < 0.0f)
1293 		{
1294 			nRoll = -nRoll;
1295 		}
1296 		pitchSubtract = pitchDelta * (nRoll/90.0f);
1297 		if ( cl_sendAngles[ROLL] > 0.0f )
1298 		{
1299 			cl_sendAngles[YAW] += pitchSubtract;
1300 		}
1301 		else
1302 		{
1303 			cl_sendAngles[YAW] -= pitchSubtract;
1304 		}
1305 
1306 		cl_sendAngles[PITCH] = AngleNormalize180( cl_sendAngles[PITCH] );
1307 		cl_sendAngles[YAW] = AngleNormalize360( cl_sendAngles[YAW] );
1308 		cl_sendAngles[ROLL] = AngleNormalize180( cl_sendAngles[ROLL] );
1309 
1310 		for (i=0 ; i<3 ; i++) {
1311 			cmd->angles[i] = ANGLE2SHORT(cl_sendAngles[i]);
1312 		}
1313 	}
1314 	else
1315 	{
1316 		for (i=0 ; i<3 ; i++) {
1317 			cmd->angles[i] = ANGLE2SHORT(cl.viewangles[i]);
1318 		}
1319 		//in case we switch to the cl_crazyShipControls
1320 		VectorCopy( cl.viewangles, cl_sendAngles );
1321 	}
1322 	//always needed in for the cl_crazyShipControls
1323 	VectorCopy( cl.viewangles, cl_lastViewAngles );
1324 }
1325 
1326 /*
1327 =================
1328 CL_CreateCmd
1329 =================
1330 */
CL_CreateCmd(void)1331 usercmd_t CL_CreateCmd( void ) {
1332 	usercmd_t	cmd;
1333 	vec3_t		oldAngles;
1334 
1335 	VectorCopy( cl.viewangles, oldAngles );
1336 
1337 	// keyboard angle adjustment
1338 	CL_AdjustAngles ();
1339 
1340 	Com_Memset( &cmd, 0, sizeof( cmd ) );
1341 
1342 	CL_CmdButtons( &cmd );
1343 
1344 	// get basic movement from keyboard
1345 	CL_KeyMove( &cmd );
1346 
1347 	// get basic movement from mouse
1348 	CL_MouseMove( &cmd );
1349 
1350 	// get basic movement from joystick
1351 	CL_JoystickMove( &cmd );
1352 
1353 	// check to make sure the angles haven't wrapped
1354 	if ( cl.viewangles[PITCH] - oldAngles[PITCH] > 90 ) {
1355 		cl.viewangles[PITCH] = oldAngles[PITCH] + 90;
1356 	} else if ( oldAngles[PITCH] - cl.viewangles[PITCH] > 90 ) {
1357 		cl.viewangles[PITCH] = oldAngles[PITCH] - 90;
1358 	}
1359 
1360 	// store out the final values
1361 	CL_FinishMove( &cmd );
1362 
1363 	// draw debug graphs of turning for mouse testing
1364 	if ( cl_debugMove->integer ) {
1365 		if ( cl_debugMove->integer == 1 ) {
1366 			SCR_DebugGraph( abs(cl.viewangles[YAW] - oldAngles[YAW]), 0 );
1367 		}
1368 		if ( cl_debugMove->integer == 2 ) {
1369 			SCR_DebugGraph( abs(cl.viewangles[PITCH] - oldAngles[PITCH]), 0 );
1370 		}
1371 	}
1372 
1373 	return cmd;
1374 }
1375 
1376 
1377 /*
1378 =================
1379 CL_CreateNewCommands
1380 
1381 Create a new usercmd_t structure for this frame
1382 =================
1383 */
CL_CreateNewCommands(void)1384 void CL_CreateNewCommands( void ) {
1385 	int			cmdNum;
1386 
1387 	// no need to create usercmds until we have a gamestate
1388 	if ( cls.state < CA_PRIMED )
1389 		return;
1390 
1391 	frame_msec = com_frameTime - old_com_frameTime;
1392 
1393 	// if running over 1000fps, act as if each frame is 1ms
1394 	// prevents divisions by zero
1395 	if ( frame_msec < 1 )
1396 		frame_msec = 1;
1397 
1398 	// if running less than 5fps, truncate the extra time to prevent
1399 	// unexpected moves after a hitch
1400 	if ( frame_msec > 200 )
1401 		frame_msec = 200;
1402 
1403 	old_com_frameTime = com_frameTime;
1404 
1405 	// generate a command for this frame
1406 	cl.cmdNumber++;
1407 	cmdNum = cl.cmdNumber & CMD_MASK;
1408 	cl.cmds[cmdNum] = CL_CreateCmd();
1409 }
1410 
1411 /*
1412 =================
1413 CL_ReadyToSendPacket
1414 
1415 Returns qfalse if we are over the maxpackets limit
1416 and should choke back the bandwidth a bit by not sending
1417 a packet this frame.  All the commands will still get
1418 delivered in the next packet, but saving a header and
1419 getting more delta compression will reduce total bandwidth.
1420 =================
1421 */
CL_ReadyToSendPacket(void)1422 qboolean CL_ReadyToSendPacket( void ) {
1423 	int		oldPacketNum;
1424 	int		delta;
1425 
1426 	// don't send anything if playing back a demo
1427 	if ( clc.demoplaying || cls.state == CA_CINEMATIC ) {
1428 		return qfalse;
1429 	}
1430 
1431 	// If we are downloading, we send no less than 50ms between packets
1432 	if ( *clc.downloadTempName &&
1433 		cls.realtime - clc.lastPacketSentTime < 50 ) {
1434 		return qfalse;
1435 	}
1436 
1437 	// if we don't have a valid gamestate yet, only send
1438 	// one packet a second
1439 	if ( cls.state != CA_ACTIVE &&
1440 		cls.state != CA_PRIMED &&
1441 		!*clc.downloadTempName &&
1442 		cls.realtime - clc.lastPacketSentTime < 1000 ) {
1443 		return qfalse;
1444 	}
1445 
1446 	// send every frame for loopbacks
1447 	if ( clc.netchan.remoteAddress.type == NA_LOOPBACK ) {
1448 		return qtrue;
1449 	}
1450 
1451 	// send every frame for LAN
1452 	if ( cl_lanForcePackets->integer && Sys_IsLANAddress( clc.netchan.remoteAddress ) ) {
1453 		return qtrue;
1454 	}
1455 
1456 	// check for exceeding cl_maxpackets
1457 	if ( cl_maxpackets->integer < 20 ) {
1458 		Cvar_Set( "cl_maxpackets", "20" );
1459 	}
1460 	else if ( cl_maxpackets->integer > 1000 ) {
1461 		Cvar_Set( "cl_maxpackets", "1000" );
1462 	}
1463 	oldPacketNum = (clc.netchan.outgoingSequence - 1) & PACKET_MASK;
1464 	delta = cls.realtime -  cl.outPackets[ oldPacketNum ].p_realtime;
1465 	if ( delta < 1000 / cl_maxpackets->integer ) {
1466 		// the accumulated commands will go out in the next packet
1467 		return qfalse;
1468 	}
1469 
1470 	return qtrue;
1471 }
1472 
1473 /*
1474 ===================
1475 CL_WritePacket
1476 
1477 Create and send the command packet to the server
1478 Including both the reliable commands and the usercmds
1479 
1480 During normal gameplay, a client packet will contain something like:
1481 
1482 4	sequence number
1483 2	qport
1484 4	serverid
1485 4	acknowledged sequence number
1486 4	clc.serverCommandSequence
1487 <optional reliable commands>
1488 1	clc_move or clc_moveNoDelta
1489 1	command count
1490 <count * usercmds>
1491 
1492 ===================
1493 */
CL_WritePacket(void)1494 void CL_WritePacket( void ) {
1495 	msg_t		buf;
1496 	byte		data[MAX_MSGLEN];
1497 	int			i, j;
1498 	usercmd_t	*cmd, *oldcmd;
1499 	usercmd_t	nullcmd;
1500 	int			packetNum;
1501 	int			oldPacketNum;
1502 	int			count, key;
1503 
1504 	// don't send anything if playing back a demo
1505 	if ( clc.demoplaying || cls.state == CA_CINEMATIC ) {
1506 		return;
1507 	}
1508 
1509 	Com_Memset( &nullcmd, 0, sizeof(nullcmd) );
1510 	oldcmd = &nullcmd;
1511 
1512 	MSG_Init( &buf, data, sizeof(data) );
1513 
1514 	MSG_Bitstream( &buf );
1515 	// write the current serverId so the server
1516 	// can tell if this is from the current gameState
1517 	MSG_WriteLong( &buf, cl.serverId );
1518 
1519 	// write the last message we received, which can
1520 	// be used for delta compression, and is also used
1521 	// to tell if we dropped a gamestate
1522 	MSG_WriteLong( &buf, clc.serverMessageSequence );
1523 
1524 	// write the last reliable message we received
1525 	MSG_WriteLong( &buf, clc.serverCommandSequence );
1526 
1527 	// write any unacknowledged clientCommands
1528 	for ( i = clc.reliableAcknowledge + 1 ; i <= clc.reliableSequence ; i++ ) {
1529 		MSG_WriteByte( &buf, clc_clientCommand );
1530 		MSG_WriteLong( &buf, i );
1531 		MSG_WriteString( &buf, clc.reliableCommands[ i & (MAX_RELIABLE_COMMANDS-1) ] );
1532 	}
1533 
1534 	// we want to send all the usercmds that were generated in the last
1535 	// few packet, so even if a couple packets are dropped in a row,
1536 	// all the cmds will make it to the server
1537 	if ( cl_packetdup->integer < 0 ) {
1538 		Cvar_Set( "cl_packetdup", "0" );
1539 	} else if ( cl_packetdup->integer > 5 ) {
1540 		Cvar_Set( "cl_packetdup", "5" );
1541 	}
1542 	oldPacketNum = (clc.netchan.outgoingSequence - 1 - cl_packetdup->integer) & PACKET_MASK;
1543 	count = cl.cmdNumber - cl.outPackets[ oldPacketNum ].p_cmdNumber;
1544 	if ( count > MAX_PACKET_USERCMDS ) {
1545 		count = MAX_PACKET_USERCMDS;
1546 		Com_Printf("MAX_PACKET_USERCMDS\n");
1547 	}
1548 	if ( count >= 1 ) {
1549 		if ( cl_showSend->integer ) {
1550 			Com_Printf( "(%i)", count );
1551 		}
1552 
1553 		// begin a client move command
1554 		if ( cl_nodelta->integer || !cl.snap.valid
1555 			|| clc.demowaiting
1556 			|| clc.serverMessageSequence != cl.snap.messageNum ) {
1557 			MSG_WriteByte (&buf, clc_moveNoDelta);
1558 		} else {
1559 			MSG_WriteByte (&buf, clc_move);
1560 		}
1561 
1562 		// write the command count
1563 		MSG_WriteByte( &buf, count );
1564 
1565 		// use the checksum feed in the key
1566 		key = clc.checksumFeed;
1567 		// also use the message acknowledge
1568 		key ^= clc.serverMessageSequence;
1569 		// also use the last acknowledged server command in the key
1570 		key ^= Com_HashKey(clc.serverCommands[ clc.serverCommandSequence & (MAX_RELIABLE_COMMANDS-1) ], 32);
1571 
1572 		// write all the commands, including the predicted command
1573 		for ( i = 0 ; i < count ; i++ ) {
1574 			j = (cl.cmdNumber - count + i + 1) & CMD_MASK;
1575 			cmd = &cl.cmds[j];
1576 			MSG_WriteDeltaUsercmdKey (&buf, key, oldcmd, cmd);
1577 			oldcmd = cmd;
1578 		}
1579 
1580 		if (cl.gcmdSentValue)
1581 		{ //hmm, just clear here, I guess.. hoping it will resolve issues with gencmd values sometimes not going through.
1582 			cl.gcmdSendValue = qfalse;
1583 			cl.gcmdSentValue = qfalse;
1584 			cl.gcmdValue = 0;
1585 		}
1586 	}
1587 
1588 	//
1589 	// deliver the message
1590 	//
1591 	packetNum = clc.netchan.outgoingSequence & PACKET_MASK;
1592 	cl.outPackets[ packetNum ].p_realtime = cls.realtime;
1593 	cl.outPackets[ packetNum ].p_serverTime = oldcmd->serverTime;
1594 	cl.outPackets[ packetNum ].p_cmdNumber = cl.cmdNumber;
1595 	clc.lastPacketSentTime = cls.realtime;
1596 
1597 	if ( cl_showSend->integer ) {
1598 		Com_Printf( "%i ", buf.cursize );
1599 	}
1600 
1601 	CL_Netchan_Transmit (&clc.netchan, &buf);
1602 
1603 	// clients never really should have messages large enough
1604 	// to fragment, but in case they do, fire them all off
1605 	// at once
1606 	while ( clc.netchan.unsentFragments ) {
1607 		CL_Netchan_TransmitNextFragment( &clc.netchan );
1608 	}
1609 }
1610 
1611 /*
1612 =================
1613 CL_SendCmd
1614 
1615 Called every frame to builds and sends a command packet to the server.
1616 =================
1617 */
CL_SendCmd(void)1618 void CL_SendCmd( void ) {
1619 	// don't send any message if not connected
1620 	if ( cls.state < CA_CONNECTED ) {
1621 		return;
1622 	}
1623 
1624 	// don't send commands if paused
1625 	if ( com_sv_running->integer && sv_paused->integer && cl_paused->integer ) {
1626 		return;
1627 	}
1628 
1629 	// we create commands even if a demo is playing,
1630 	CL_CreateNewCommands();
1631 
1632 	// don't send a packet if the last packet was sent too recently
1633 	if ( !CL_ReadyToSendPacket() ) {
1634 		if ( cl_showSend->integer ) {
1635 			Com_Printf( ". " );
1636 		}
1637 		return;
1638 	}
1639 
1640 	CL_WritePacket();
1641 }
1642 
1643 static const cmdList_t inputCmds[] =
1644 {
1645 	{ "centerview", "Centers view on screen", IN_CenterView, NULL },
1646 	{ "+moveup", "Jump", IN_UpDown, NULL },
1647 	{ "-moveup", NULL, IN_UpUp, NULL },
1648 	{ "+movedown", "Crouch", IN_DownDown, NULL },
1649 	{ "-movedown", NULL, IN_DownUp, NULL },
1650 	{ "+left", "Rotate camera left", IN_LeftDown, NULL },
1651 	{ "-left", NULL, IN_LeftUp, NULL },
1652 	{ "+right", "Rotate camera right", IN_RightDown, NULL },
1653 	{ "-right", NULL, IN_RightUp, NULL },
1654 	{ "+forward", "Move forward", IN_ForwardDown, NULL },
1655 	{ "-forward", NULL, IN_ForwardUp, NULL },
1656 	{ "+back", "Move backward", IN_BackDown, NULL },
1657 	{ "-back", NULL, IN_BackUp, NULL },
1658 	{ "+lookup", "Tilt camera up", IN_LookupDown, NULL },
1659 	{ "-lookup", NULL, IN_LookupUp, NULL },
1660 	{ "+lookdown", "Tilt camera down", IN_LookdownDown, NULL },
1661 	{ "-lookdown", NULL, IN_LookdownUp, NULL },
1662 	{ "+strafe", "Hold to strafe", IN_StrafeDown, NULL },
1663 	{ "-strafe", NULL, IN_StrafeUp, NULL },
1664 	{ "+moveleft", "Strafe left", IN_MoveleftDown, NULL },
1665 	{ "-moveleft", NULL, IN_MoveleftUp, NULL },
1666 	{ "+moveright", "Strafe right", IN_MoverightDown, NULL },
1667 	{ "-moveright", NULL, IN_MoverightUp, NULL },
1668 	{ "+speed", "Walk or run", IN_SpeedDown, NULL },
1669 	{ "-speed", NULL, IN_SpeedUp, NULL },
1670 	{ "+attack", "Primary Attack", IN_Button0Down, NULL },
1671 	{ "-attack", NULL, IN_Button0Up, NULL },
1672 	{ "+use", "Use item", IN_Button5Down, NULL },
1673 	{ "-use", NULL, IN_Button5Up, NULL },
1674 	{ "+force_grip", "Hold to use grip force power", IN_Button6Down, NULL },
1675 	{ "-force_grip", NULL, IN_Button6Up, NULL },
1676 	{ "+altattack", "Alternate Attack", IN_Button7Down, NULL },
1677 	{ "-altattack", NULL, IN_Button7Up, NULL },
1678 	{ "+useforce", "Use selected force power", IN_Button9Down, NULL },
1679 	{ "-useforce", NULL, IN_Button9Up, NULL },
1680 	{ "+force_lightning", "Hold to use lightning force power", IN_Button10Down, NULL },
1681 	{ "-force_lightning", NULL, IN_Button10Up, NULL },
1682 	{ "+force_drain", "Hold to use drain force power", IN_Button11Down, NULL },
1683 	{ "-force_drain", NULL, IN_Button11Up, NULL },
1684 	{ "+button0", "Button 0", IN_Button0Down, NULL },
1685 	{ "-button0", NULL, IN_Button0Up, NULL },
1686 	{ "+button1", "Button 1", IN_Button1Down, NULL },
1687 	{ "-button1", NULL, IN_Button1Up, NULL },
1688 	{ "+button2", "Button 2", IN_Button2Down, NULL },
1689 	{ "-button2", NULL, IN_Button2Up, NULL },
1690 	{ "+button3", "Button 3", IN_Button3Down, NULL },
1691 	{ "-button3", NULL, IN_Button3Up, NULL },
1692 	{ "+button4", "Button 4", IN_Button4Down, NULL },
1693 	{ "-button4", NULL, IN_Button4Up, NULL },
1694 	{ "+button5", "Button 5", IN_Button5Down, NULL },
1695 	{ "-button5", NULL, IN_Button5Up, NULL },
1696 	{ "+button6", "Button 6", IN_Button6Down, NULL },
1697 	{ "-button6", NULL, IN_Button6Up, NULL },
1698 	{ "+button7", "Button 7", IN_Button7Down, NULL },
1699 	{ "-button7", NULL, IN_Button7Up, NULL },
1700 	{ "+button8", "Button 8", IN_Button8Down, NULL },
1701 	{ "-button8", NULL, IN_Button8Up, NULL },
1702 	{ "+button9", "Button 9", IN_Button9Down, NULL },
1703 	{ "-button9", NULL, IN_Button9Up, NULL },
1704 	{ "+button10", "Button 10", IN_Button10Down, NULL },
1705 	{ "-button10", NULL, IN_Button10Up, NULL },
1706 	{ "+button11", "Button 11", IN_Button11Down, NULL },
1707 	{ "-button11", NULL, IN_Button11Up, NULL },
1708 	{ "+button12", "Button 12", IN_Button12Down, NULL },
1709 	{ "-button12", NULL, IN_Button12Up, NULL },
1710 	{ "+button13", "Button 13", IN_Button13Down, NULL },
1711 	{ "-button13", NULL, IN_Button13Up, NULL },
1712 	{ "+button14", "Button 14", IN_Button14Down, NULL },
1713 	{ "-button14", NULL, IN_Button14Up, NULL },
1714 	{ "+button15", "Button 15", IN_Button15Down, NULL },
1715 	{ "-button15", NULL, IN_Button15Up, NULL },
1716 	{ "+mlook", "Hold to use mouse look", IN_MLookDown, NULL },
1717 	{ "-mlook", NULL, IN_MLookUp, NULL },
1718 	{ "sv_saberswitch", "Holster/activate lightsaber", IN_GenCMD1, NULL },
1719 	{ "engage_duel", "Engage private duel", IN_GenCMD2, NULL },
1720 	{ "force_heal", "Use heal force power", IN_GenCMD3, NULL },
1721 	{ "force_speed", "Activate speed force power", IN_GenCMD4, NULL },
1722 	{ "force_pull", "Use pull force power", IN_GenCMD5, NULL },
1723 	{ "force_distract", "Activate mind trick force power", IN_GenCMD6, NULL },
1724 	{ "force_rage", "Activate rage force power", IN_GenCMD7, NULL },
1725 	{ "force_protect", "Activate protect force power", IN_GenCMD8, NULL },
1726 	{ "force_absorb", "Activate absorb force power", IN_GenCMD9, NULL },
1727 	{ "force_healother", "Use team heal force power", IN_GenCMD10, NULL },
1728 	{ "force_forcepowerother", "Use team energize force power", IN_GenCMD11, NULL },
1729 	{ "force_seeing", "Activate seeing force power", IN_GenCMD12, NULL },
1730 	{ "use_seeker", "Use seeker drone item", IN_GenCMD13, NULL },
1731 	{ "use_field", "Use forcefield item", IN_GenCMD14, NULL },
1732 	{ "use_bacta", "Use bacta item", IN_GenCMD15, NULL },
1733 	{ "use_electrobinoculars", "Use electro binoculars item", IN_GenCMD16, NULL },
1734 	{ "zoom", "Use binoculars item", IN_GenCMD17, NULL },
1735 	{ "use_sentry", "Use sentry gun item", IN_GenCMD18, NULL },
1736 	{ "saberAttackCycle", "Switch lightsaber attack styles", IN_GenCMD19, NULL },
1737 	{ "force_throw", "Use push force power", IN_GenCMD20, NULL },
1738 	{ "use_jetpack", "Use jetpack item", IN_GenCMD21, NULL },
1739 	{ "use_bactabig", "Use big bacta item", IN_GenCMD22, NULL },
1740 	{ "use_healthdisp", "Use health dispenser item", IN_GenCMD23, NULL },
1741 	{ "use_ammodisp", "Use ammo dispenser item", IN_GenCMD24, NULL },
1742 	{ "use_eweb", "Use e-web item", IN_GenCMD25, NULL },
1743 	{ "use_cloak", "Use cloaking item", IN_GenCMD26, NULL },
1744 	{ "taunt", "Taunt", IN_GenCMD27, NULL },
1745 	{ "bow", "Bow", IN_GenCMD28, NULL },
1746 	{ "meditate", "Meditate", IN_GenCMD29, NULL },
1747 	{ "flourish", "Flourish", IN_GenCMD30, NULL },
1748 	{ "gloat", "Gloat", IN_GenCMD31, NULL },
1749 	{ "useGivenForce", "Use specified force power", IN_UseGivenForce, NULL },
1750 	{ "automap_button", "Show/hide automap", IN_AutoMapButton, NULL },
1751 	{ "automap_toggle", "Show/hide radar", IN_AutoMapToggle, NULL },
1752 	{ "voicechat", "Open voice chat menu", IN_VoiceChatButton, NULL },
1753 	{ NULL, NULL, NULL, NULL }
1754 };
1755 
1756 /*
1757 ============
1758 CL_InitInput
1759 ============
1760 */
CL_InitInput(void)1761 void CL_InitInput( void ) {
1762 	Cmd_AddCommandList( inputCmds );
1763 
1764 	cl_nodelta = Cvar_Get ("cl_nodelta", "0", 0);
1765 	cl_debugMove = Cvar_Get ("cl_debugMove", "0", 0);
1766 }
1767 
1768 /*
1769 ============
1770 CL_ShutdownInput
1771 ============
1772 */
CL_ShutdownInput(void)1773 void CL_ShutdownInput( void ) {
1774 	Cmd_RemoveCommandList( inputCmds );
1775 }
1776