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