1 //**************************************************************************
2 //**
3 //** ## ## ## ## ## #### #### ### ###
4 //** ## ## ## ## ## ## ## ## ## ## #### ####
5 //** ## ## ## ## ## ## ## ## ## ## ## ## ## ##
6 //** ## ## ######## ## ## ## ## ## ## ## ### ##
7 //** ### ## ## ### ## ## ## ## ## ##
8 //** # ## ## # #### #### ## ##
9 //**
10 //** $Id: p_player_input.cpp 4338 2010-12-13 21:09:47Z dj_jl $
11 //**
12 //** Copyright (C) 1999-2006 Jānis Legzdiņš
13 //**
14 //** This program is free software; you can redistribute it and/or
15 //** modify it under the terms of the GNU General Public License
16 //** as published by the Free Software Foundation; either version 2
17 //** of the License, or (at your option) any later version.
18 //**
19 //** This program is distributed in the hope that it will be useful,
20 //** but WITHOUT ANY WARRANTY; without even the implied warranty of
21 //** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 //** GNU General Public License for more details.
23 //**
24 //**************************************************************************
25 //**
26 //** KEY BUTTONS
27 //**
28 //** Continuous button event tracking is complicated by the fact that two
29 //** different input sources (say, mouse button 1 and the control key) can
30 //** both press the same button, but the button should only be released
31 //** when both of the pressing key have been released.
32 //**
33 //** When a key event issues a button command (+forward, +attack, etc),
34 //** it appends its key number as a parameter to the command so it can be
35 //** matched up with the release.
36 //**
37 //** state bit 0 is the current state of the key
38 //** state bit 1 is edge triggered on the up to down transition
39 //** state bit 2 is edge triggered on the down to up transition
40 //**
41 //**************************************************************************
42
43 // HEADER FILES ------------------------------------------------------------
44
45 #include "gamedefs.h"
46
47 // MACROS ------------------------------------------------------------------
48
49 #define BUTTON(name) \
50 static TKButton Key ## name; \
51 static TCmdKeyDown name ## Down_f("+" #name, Key ## name); \
52 static TCmdKeyUp name ## Up_f("-" #name, Key ## name);
53
54 // TYPES -------------------------------------------------------------------
55
56 class TKButton
57 {
58 public:
59 int down[2]; // key nums holding it down
60 int state; // low bit is down state
61
62 void KeyDown(const char* c);
63 void KeyUp(const char* c);
64 float KeyState();
65 };
66
67 class TCmdKeyDown : public VCommand
68 {
69 public:
TCmdKeyDown(const char * AName,TKButton & AKey)70 TCmdKeyDown(const char *AName, TKButton &AKey) : VCommand(AName), Key(AKey) { }
71 void Run();
72
73 TKButton &Key;
74 };
75
76 class TCmdKeyUp : public VCommand
77 {
78 public:
TCmdKeyUp(const char * AName,TKButton & AKey)79 TCmdKeyUp(const char *AName, TKButton &AKey) : VCommand(AName), Key(AKey) { }
80 void Run();
81
82 TKButton &Key;
83 };
84
85 enum
86 {
87 INPUT_OLDBUTTONS,
88 INPUT_BUTTONS,
89 INPUT_PITCH,
90 INPUT_YAW,
91 INPUT_ROLL,
92 INPUT_FORWARDMOVE,
93 INPUT_SIDEMOVE,
94 INPUT_UPMOVE,
95 MODINPUT_OLDBUTTONS,
96 MODINPUT_BUTTONS,
97 MODINPUT_PITCH,
98 MODINPUT_YAW,
99 MODINPUT_ROLL,
100 MODINPUT_FORWARDMOVE,
101 MODINPUT_SIDEMOVE,
102 MODINPUT_UPMOVE
103 };
104
105 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
106
107 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
108
109 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
110
111 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
112
113 // PUBLIC DATA DEFINITIONS -------------------------------------------------
114
115 // PRIVATE DATA DEFINITIONS ------------------------------------------------
116
117 // mouse values are used once
118 static float mousex;
119 static float mousey;
120 // joystick values are repeated
121 static int joyxmove;
122 static int joyymove;
123
124 static int impulse_cmd;
125
126 static VCvarI allways_run("allways_run", "1", CVAR_Archive);
127 static VCvarI artiskip("artiskip", "1", CVAR_Archive); // whether shift-enter skips an artifact
128
129 static VCvarF cl_forwardspeed("cl_forwardspeed", "200", CVAR_Archive);
130 static VCvarF cl_backspeed("cl_backspeed", "200", CVAR_Archive);
131 static VCvarF cl_sidespeed("cl_sidespeed", "200", CVAR_Archive);
132 static VCvarF cl_flyspeed("cl_flyspeed", "80", CVAR_Archive);
133
134 static VCvarF cl_movespeedkey("cl_movespeedkey", "2.0", CVAR_Archive);
135
136 static VCvarF cl_yawspeed("cl_yawspeed", "140", CVAR_Archive);
137 static VCvarF cl_pitchspeed("cl_pitchspeed", "150", CVAR_Archive);
138 static VCvarF cl_pitchdriftspeed("cl_pitchdriftspeed", "270", CVAR_Archive);
139
140 static VCvarF cl_anglespeedkey("cl_anglespeedkey", "1.5", CVAR_Archive);
141
142 static VCvarF cl_deathroll("cl_deathroll", "75", CVAR_Archive);
143 static VCvarF cl_deathrollspeed("cl_deathrollspeed", "80", CVAR_Archive);
144
145 static VCvarF mouse_x_sensitivity("mouse_x_sensitivity", "5.0", CVAR_Archive);
146 static VCvarF mouse_y_sensitivity("mouse_y_sensitivity", "5.0", CVAR_Archive);
147 static VCvarI mouse_look("mouse_look", "1", CVAR_Archive);
148 static VCvarI invert_mouse("invert_mouse", "0", CVAR_Archive);
149 static VCvarI lookstrafe("lookstrafe", "0", CVAR_Archive);
150 static VCvarI lookspring("lookspring", "0", CVAR_Archive);
151
152 static VCvarF m_yaw("m_yaw", "0.022", CVAR_Archive);
153 static VCvarF m_pitch("m_pitch", "0.022", CVAR_Archive);
154 static VCvarF m_forward("m_forward", "1.0", CVAR_Archive);
155 static VCvarF m_side("m_side", "0.8", CVAR_Archive);
156
157 static VCvarF joy_yaw("joy_yaw", "140", CVAR_Archive);
158
159 BUTTON(Forward)
BUTTON(Backward)160 BUTTON(Backward)
161 BUTTON(Left)
162 BUTTON(Right)
163 BUTTON(LookUp)
164 BUTTON(LookDown)
165 BUTTON(LookCentre)
166 BUTTON(MoveLeft)
167 BUTTON(MoveRight)
168 BUTTON(FlyUp)
169 BUTTON(FlyDown)
170 BUTTON(FlyCentre)
171 BUTTON(Attack)
172 BUTTON(Use)
173 BUTTON(Jump)
174 BUTTON(AltAttack)
175 BUTTON(Button5)
176 BUTTON(Button6)
177 BUTTON(Button7)
178 BUTTON(Button8)
179 BUTTON(Speed)
180 BUTTON(Strafe)
181 BUTTON(MouseLook)
182
183 // CODE --------------------------------------------------------------------
184
185 //==========================================================================
186 //
187 // TKButton::KeyDown
188 //
189 //==========================================================================
190
191 void TKButton::KeyDown(const char* c)
192 {
193 guard(TKButton::KeyDown);
194 int k;
195
196 if (c[0])
197 {
198 k = atoi(c);
199 }
200 else
201 {
202 k = -1; // typed manually at the console for continuous down
203 }
204
205 if (k == down[0] || k == down[1])
206 {
207 return; // repeating key
208 }
209
210 if (!down[0])
211 {
212 down[0] = k;
213 }
214 else if (!down[1])
215 {
216 down[1] = k;
217 }
218 else
219 {
220 GCon->Log(NAME_Dev, "Three keys down for a button!");
221 return;
222 }
223
224 if (state & 1)
225 {
226 return; // still down
227 }
228 state |= 1 + 2; // down + impulse down
229 unguard;
230 }
231
232 //==========================================================================
233 //
234 // TKButton::KeyUp
235 //
236 //==========================================================================
237
KeyUp(const char * c)238 void TKButton::KeyUp(const char* c)
239 {
240 guard(TKButton::KeyUp);
241 int k;
242
243 if (c[0])
244 {
245 k = atoi(c);
246 }
247 else
248 { // typed manually at the console, assume for unsticking, so clear all
249 down[0] = down[1] = 0;
250 state = 4; // impulse up
251 return;
252 }
253
254 if (down[0] == k)
255 {
256 down[0] = 0;
257 }
258 else if (down[1] == k)
259 {
260 down[1] = 0;
261 }
262 else
263 {
264 return; // key up without coresponding down (menu pass through)
265 }
266 if (down[0] || down[1])
267 {
268 return; // some other key is still holding it down
269 }
270
271 if (!(state & 1))
272 {
273 return; // still up (this should not happen)
274 }
275 state &= ~1; // now up
276 state |= 4; // impulse up
277 unguard;
278 }
279
280 //==========================================================================
281 //
282 // TKButton::KeyState
283 //
284 // Returns 0.25 if a key was pressed and released during the frame,
285 // 0.5 if it was pressed and held
286 // 0 if held then released, and
287 // 1.0 if held for the entire time
288 //
289 //==========================================================================
290
KeyState()291 float TKButton::KeyState()
292 {
293 guard(TKButton::KeyState);
294 static const float newVal[8] =
295 {
296 0.0f, // up the entire frame
297 1.0f, // held the entire frame
298 0.0f, // Sys_Error();
299 0.5f, // pressed and held this frame
300 0.0f, // released this frame
301 0.0f, // Sys_Error();
302 0.25f, // pressed and released this frame
303 0.75f // released and re-pressed this frame
304 };
305
306 float val = newVal[state & 7];
307 state &= 1; // clear impulses
308
309 return val;
310 unguard;
311 }
312
313 //==========================================================================
314 //
315 // TCmdKeyDown::Run
316 //
317 //==========================================================================
318
Run()319 void TCmdKeyDown::Run()
320 {
321 guard(TCmdKeyDown::Run);
322 Key.KeyDown(Args.Num() > 1 ? *Args[1] : "");
323 unguard;
324 }
325
326 //==========================================================================
327 //
328 // TCmdKeyUp::Run
329 //
330 //==========================================================================
331
Run()332 void TCmdKeyUp::Run()
333 {
334 guard(TCmdKeyUp::Run);
335 Key.KeyUp(Args.Num() > 1 ? *Args[1] : "");
336 unguard;
337 }
338
339 //==========================================================================
340 //
341 // COMMAND Impulse
342 //
343 //==========================================================================
344
COMMAND(Impulse)345 COMMAND(Impulse)
346 {
347 guard(COMMAND Impulse);
348 if (Args.Num() < 2)
349 {
350 return;
351 }
352 impulse_cmd = atoi(*Args[1]);
353 unguard;
354 }
355
356 //==========================================================================
357 //
358 // COMMAND ToggleAlwaysRun
359 //
360 //==========================================================================
361
COMMAND(ToggleAlwaysRun)362 COMMAND(ToggleAlwaysRun)
363 {
364 guard(COMMAND ToggleAlwaysRun);
365 allways_run = !allways_run;
366 #ifdef CLIENT
367 if (cl)
368 {
369 cl->Printf(allways_run ? "Always run on" : "Always run off");
370 }
371 else
372 #endif
373 {
374 GCon->Log(allways_run ? "Always run on" : "Always run off");
375 }
376 unguard;
377 }
378
379 //==========================================================================
380 //
381 // COMMAND Use
382 //
383 //==========================================================================
384
COMMAND(Use)385 COMMAND(Use)
386 {
387 guard(COMMAND Use);
388 if (Args.Num() < 1)
389 {
390 return;
391 }
392 #ifdef CLIENT
393 cl->eventUseInventory(*Args[1]);
394 #endif
395 unguard;
396 }
397
398 //==========================================================================
399 //
400 // VBasePlayer::StartPitchDrift
401 //
402 //==========================================================================
403
StartPitchDrift()404 void VBasePlayer::StartPitchDrift()
405 {
406 PlayerFlags |= PF_Centreing;
407 }
408
409 //==========================================================================
410 //
411 // VBasePlayer::StopPitchDrift
412 //
413 //==========================================================================
414
StopPitchDrift()415 void VBasePlayer::StopPitchDrift()
416 {
417 PlayerFlags &= ~PF_Centreing;
418 }
419
420 //==========================================================================
421 //
422 // VBasePlayer::AdjustAngles
423 //
424 //==========================================================================
425
AdjustAngles()426 void VBasePlayer::AdjustAngles()
427 {
428 guard(VBasePlayer::AdjustAngles);
429 float speed;
430
431 if (KeySpeed.state & 1)
432 {
433 speed = host_frametime * cl_anglespeedkey;
434 }
435 else
436 {
437 speed = host_frametime;
438 }
439
440 if ((KeyMouseLook.state & 4) && lookspring)
441 {
442 StartPitchDrift();
443 }
444 KeyMouseLook.state &= 1;
445
446 // YAW
447 if (!(KeyStrafe.state & 1))
448 {
449 ViewAngles.yaw -= KeyRight.KeyState() * cl_yawspeed * speed;
450 ViewAngles.yaw += KeyLeft.KeyState() * cl_yawspeed * speed;
451 if (joyxmove > 0)
452 {
453 ViewAngles.yaw -= joy_yaw * speed;
454 }
455 if (joyxmove < 0)
456 {
457 ViewAngles.yaw += joy_yaw * speed;
458 }
459 }
460 if (!(KeyStrafe.state & 1) &&
461 (!lookstrafe || (!mouse_look && !(KeyMouseLook.state & 1))))
462 {
463 ViewAngles.yaw -= mousex * m_yaw;
464 }
465 ViewAngles.yaw = AngleMod(ViewAngles.yaw);
466
467 // PITCH
468 float up = KeyLookUp.KeyState();
469 float down = KeyLookDown.KeyState();
470 ViewAngles.pitch -= cl_pitchspeed * up * speed;
471 ViewAngles.pitch += cl_pitchspeed * down * speed;
472 if (up || down || (KeyMouseLook.state & 1))
473 {
474 StopPitchDrift();
475 }
476 if ((mouse_look || (KeyMouseLook.state & 1)) && !(KeyStrafe.state & 1))
477 {
478 ViewAngles.pitch -= mousey * m_pitch;
479 }
480
481 // Centre look
482 if ((KeyLookCentre.state & 1) || (KeyFlyCentre.state & 1))
483 {
484 StartPitchDrift();
485 }
486 if (PlayerFlags & PF_Centreing)
487 {
488 float adelta = cl_pitchdriftspeed * host_frametime;
489 if (fabs(ViewAngles.pitch) < adelta)
490 {
491 ViewAngles.pitch = 0;
492 PlayerFlags &= ~PF_Centreing;
493 }
494 else
495 {
496 if (ViewAngles.pitch > 0.0)
497 {
498 ViewAngles.pitch -= adelta;
499 }
500 else if (ViewAngles.pitch < 0.0)
501 {
502 ViewAngles.pitch += adelta;
503 }
504 }
505 }
506
507 // ROLL
508 if (Health <= 0)
509 {
510 if (ViewAngles.roll >= 0 && ViewAngles.roll < cl_deathroll)
511 {
512 ViewAngles.roll += cl_deathrollspeed * host_frametime;
513 }
514 if (ViewAngles.roll < 0 && ViewAngles.roll > -cl_deathroll)
515 {
516 ViewAngles.roll -= cl_deathrollspeed * host_frametime;
517 }
518 }
519 else
520 {
521 ViewAngles.roll = 0.0;
522 }
523
524 // Check angles
525 if (ViewAngles.pitch > 80.0)
526 {
527 ViewAngles.pitch = 80.0;
528 }
529 if (ViewAngles.pitch < -70.0)
530 {
531 ViewAngles.pitch = -70.0;
532 }
533
534 if (ViewAngles.roll > 80.0)
535 {
536 ViewAngles.roll = 80.0;
537 }
538 if (ViewAngles.roll < -80.0)
539 {
540 ViewAngles.roll = -80.0;
541 }
542
543 if (Level->LevelInfoFlags & VLevelInfo::LIF_NoFreelook)
544 {
545 ViewAngles.pitch = 0;
546 }
547 unguard;
548 }
549
550 //==========================================================================
551 //
552 // VBasePlayer::HandleInput
553 //
554 // Creates movement commands from all of the available inputs.
555 //
556 //==========================================================================
557
HandleInput()558 void VBasePlayer::HandleInput()
559 {
560 guard(VBasePlayer::HandleInput);
561 float forward;
562 float side;
563 float flyheight;
564
565 AdjustAngles();
566
567 forward = side = flyheight = 0;
568
569 // let movement keys cancel each other out
570 if (KeyStrafe.state & 1)
571 {
572 side += KeyRight.KeyState() * cl_sidespeed;
573 side -= KeyLeft.KeyState() * cl_sidespeed;
574 if (joyxmove > 0)
575 {
576 side += cl_sidespeed;
577 }
578 if (joyxmove < 0)
579 {
580 side -= cl_sidespeed;
581 }
582 }
583
584 forward += KeyForward.KeyState() * cl_forwardspeed;
585 forward -= KeyBackward.KeyState() * cl_backspeed;
586
587 side += KeyMoveRight.KeyState() * cl_sidespeed;
588 side -= KeyMoveLeft.KeyState() * cl_sidespeed;
589
590 if (joyymove < 0)
591 {
592 forward += cl_forwardspeed;
593 }
594 if (joyymove > 0)
595 {
596 forward -= cl_backspeed;
597 }
598
599 // Fly up/down/drop keys
600 flyheight += KeyFlyUp.KeyState() * cl_flyspeed; // note that the actual flyheight will be twice this
601 flyheight -= KeyFlyDown.KeyState() * cl_flyspeed;
602
603 if ((!mouse_look && !(KeyMouseLook.state & 1)) || (KeyStrafe.state & 1))
604 {
605 forward += m_forward * mousey;
606 }
607
608 if ((KeyStrafe.state & 1) ||
609 (lookstrafe && (mouse_look || (KeyMouseLook.state & 1))))
610 {
611 side += m_side * mousex;
612 }
613
614 forward = MID(forward, -cl_backspeed, cl_forwardspeed);
615 side = MID(side, -cl_sidespeed, cl_sidespeed);
616
617 if (allways_run || (KeySpeed.state & 1))
618 {
619 forward *= cl_movespeedkey;
620 side *= cl_movespeedkey;
621 flyheight *= cl_movespeedkey;
622 }
623
624 flyheight = MID(flyheight, -127, 127);
625 if (KeyFlyCentre.KeyState())
626 {
627 flyheight = TOCENTRE;
628 }
629
630 //
631 // BUTTONS
632 //
633
634 Buttons = 0;
635
636 // Fire buttons
637 if (KeyAttack.KeyState())
638 {
639 Buttons |= BT_ATTACK;
640 }
641
642 // Use buttons
643 if (KeyUse.KeyState())
644 {
645 Buttons |= BT_USE;
646 }
647
648 // Jumping
649 if (KeyJump.KeyState())
650 {
651 Buttons |= BT_JUMP;
652 }
653
654 if (KeyAltAttack.KeyState())
655 {
656 Buttons |= BT_ALT_ATTACK;
657 }
658
659 if (KeyButton5.KeyState())
660 {
661 Buttons |= 0x10;
662 }
663
664 if (KeyButton6.KeyState())
665 {
666 Buttons |= 0x20;
667 }
668
669 if (KeyButton7.KeyState())
670 {
671 Buttons |= 0x40;
672 }
673
674 if (KeyButton8.KeyState())
675 {
676 Buttons |= 0x80;
677 }
678
679 //
680 // IMPULSE
681 //
682 if (impulse_cmd)
683 {
684 eventServerImpulse(impulse_cmd);
685 impulse_cmd = 0;
686 }
687
688 ClientForwardMove = forward;
689 ClientSideMove = side;
690 FlyMove = flyheight;
691
692 mousex = 0;
693 mousey = 0;
694 unguard;
695 }
696
697 //==========================================================================
698 //
699 // VBasePlayer::Responder
700 //
701 // Get info needed to make movement commands for the players.
702 //
703 //==========================================================================
704
Responder(event_t * ev)705 bool VBasePlayer::Responder(event_t* ev)
706 {
707 guard(VBasePlayer::Responder);
708 switch (ev->type)
709 {
710 case ev_mouse:
711 mousex = ev->data2 * mouse_x_sensitivity;
712 mousey = ev->data3 * mouse_y_sensitivity;
713 if (invert_mouse)
714 {
715 mousey = -mousey;
716 }
717 return true; // eat events
718
719 case ev_joystick:
720 joyxmove = ev->data2;
721 joyymove = ev->data3;
722 return true; // eat events
723
724 default:
725 break;
726 }
727 return false;
728 unguard;
729 }
730
731 //==========================================================================
732 //
733 // VBasePlayer::ClearInput
734 //
735 //==========================================================================
736
ClearInput()737 void VBasePlayer::ClearInput()
738 {
739 guard(VBasePlayer::ClearInput);
740 // clear cmd building stuff
741 joyxmove = joyymove = 0;
742 mousex = mousey = 0;
743 impulse_cmd = 0;
744 unguard;
745 }
746
747 //==========================================================================
748 //
749 // VBasePlayer::AcsGetInput
750 //
751 //==========================================================================
752
AcsGetInput(int InputType)753 int VBasePlayer::AcsGetInput(int InputType)
754 {
755 guard(VBasePlayer::AcsGetInput);
756 int Btn;
757 int Ret = 0;
758 switch (InputType)
759 {
760 case INPUT_OLDBUTTONS:
761 case MODINPUT_OLDBUTTONS:
762 case INPUT_BUTTONS:
763 case MODINPUT_BUTTONS:
764 if (InputType == INPUT_OLDBUTTONS ||
765 InputType == MODINPUT_OLDBUTTONS)
766 {
767 Btn = OldButtons;
768 }
769 else
770 {
771 Btn = Buttons;
772 }
773 // Convert buttons to what ACS expects.
774 if (Btn & BT_ATTACK)
775 {
776 Ret |= 1;
777 }
778 if (Btn & BT_USE)
779 {
780 Ret |= 2;
781 }
782 if (Btn & BT_JUMP)
783 {
784 Ret |= 4;
785 }
786 if (Btn & BT_ALT_ATTACK)
787 {
788 Ret |= 32;
789 }
790 return Ret;
791
792 case INPUT_PITCH:
793 return (int)(AngleMod(OldViewAngles.pitch) * 0x10000 / 360);
794
795 case MODINPUT_PITCH:
796 return (int)(AngleMod(ViewAngles.pitch) * 0x10000 / 360);
797
798 case INPUT_YAW:
799 return (int)(AngleMod(OldViewAngles.yaw) * 0x10000 / 360);
800
801 case MODINPUT_YAW:
802 return (int)(AngleMod(ViewAngles.yaw) * 0x10000 / 360);
803
804 case INPUT_ROLL:
805 return (int)(AngleMod(OldViewAngles.roll) * 0x10000 / 360);
806
807 case MODINPUT_ROLL:
808 return (int)(AngleMod(ViewAngles.roll) * 0x10000 / 360);
809
810 case INPUT_FORWARDMOVE:
811 return (int)(ClientForwardMove * 0x32 / 400);
812
813 case MODINPUT_FORWARDMOVE:
814 return (int)(ForwardMove * 0x32 / 400);
815
816 case INPUT_SIDEMOVE:
817 return (int)(ClientSideMove * 0x32 / 400);
818
819 case MODINPUT_SIDEMOVE:
820 return (int)(SideMove * 0x32 / 400);
821
822 case INPUT_UPMOVE:
823 case MODINPUT_UPMOVE:
824 return (int)(FlyMove * 3 * 256 / 80);
825 }
826 return 0;
827 unguard;
828 }
829