1 //**************************************************************************
3 //** ## ## ## ## ## #### #### ### ###
4 //** ## ## ## ## ## ## ## ## ## ## #### ####
5 //** ## ## ## ## ## ## ## ## ## ## ## ## ## ##
6 //** ## ## ######## ## ## ## ## ## ## ## ### ##
7 //** ### ## ## ### ## ## ## ## ## ##
8 //** # ## ## # #### #### ## ##
10 //** Copyright (C) 1999-2006 Jānis Legzdiņš
11 //** Copyright (C) 2018-2023 Ketmar Dark
13 //** This program is free software: you can redistribute it and/or modify
14 //** it under the terms of the GNU General Public License as published by
15 //** the Free Software Foundation, version 3 of the License ONLY.
17 //** This program is distributed in the hope that it will be useful,
18 //** but WITHOUT ANY WARRANTY; without even the implied warranty of
19 //** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 //** GNU General Public License for more details.
22 //** You should have received a copy of the GNU General Public License
23 //** along with this program. If not, see <http://www.gnu.org/licenses/>.
25 //**************************************************************************
29 //** Continuous button event tracking is complicated by the fact that two
30 //** different input sources (say, mouse button 1 and the control key) can
31 //** both press the same button, but the button should only be released
32 //** when both of the pressing key have been released.
34 //** When a key event issues a button command (+forward, +attack, etc),
35 //** it appends its key number as a parameter to the command so it can be
36 //** matched up with the release.
38 //** state bit 0 is the current state of the key
39 //** state bit 1 is edge triggered on the up to down transition
40 //** state bit 2 is edge triggered on the down to up transition
42 //**************************************************************************
43 #include "../gamedefs.h"
44 #include "../host.h" /* host_frametime */
45 #include "p_levelinfo.h"
47 #include "../server/server.h"
49 # include "../client/client.h"
50 # include "../client/cl_local.h"
55 extern VCvarB sv_ignore_nomlook
;
56 extern VCvarB sv_ignore_nojump
;
57 extern VCvarB sv_ignore_nocrouch
;
58 extern VCvarB sv_ignore_nomlook
;
60 extern VCvarB sv_disable_run
;
61 extern VCvarB sv_disable_crouch
;
62 extern VCvarB sv_disable_jump
;
63 extern VCvarB sv_disable_mlook
;
66 #define BUTTON(name) \
67 static TKButton Key ## name; \
68 static TCmdKeyDown name ## Down_f("+" #name, Key ## name); \
69 static TCmdKeyUp name ## Up_f("-" #name, Key ## name);
72 #define ACS_BT_ATTACK 0x00000001
73 #define ACS_BT_USE 0x00000002
74 #define ACS_BT_JUMP 0x00000004
75 #define ACS_BT_CROUCH 0x00000008
76 #define ACS_BT_TURN180 0x00000010
77 #define ACS_BT_ALTATTACK 0x00000020
78 #define ACS_BT_RELOAD 0x00000040
79 #define ACS_BT_ZOOM 0x00000080
80 #define ACS_BT_SPEED 0x00000100
81 #define ACS_BT_STRAFE 0x00000200
82 #define ACS_BT_MOVERIGHT 0x00000400
83 #define ACS_BT_MOVELEFT 0x00000800
84 #define ACS_BT_BACK 0x00001000
85 #define ACS_BT_FORWARD 0x00002000
86 #define ACS_BT_RIGHT 0x00004000
87 #define ACS_BT_LEFT 0x00008000
88 #define ACS_BT_LOOKUP 0x00010000
89 #define ACS_BT_LOOKDOWN 0x00020000
90 #define ACS_BT_MOVEUP 0x00040000
91 #define ACS_BT_MOVEDOWN 0x00080000
92 #define ACS_BT_SHOWSCORES 0x00100000
93 #define ACS_BT_USER1 0x00200000
94 #define ACS_BT_USER2 0x00400000
95 #define ACS_BT_USER3 0x00800000
96 #define ACS_BT_USER4 0x01000000
97 #define ACS_BT_RUN 0x02000000 /* GZDoom specific key, dunno what it is */
103 static const float PressureTbl
[8];
113 TMapNC
<vint32
, bool> down
; // key nums holding it down
114 //int down[2]; // key nums holding it down
115 // current state, and impulses
116 // bit 0: "currently pressed"
117 // bit 1: just pressed
118 // bit 2: just released
124 friend void UnpressAllButtons ();
129 void KeyDown (const char *c
) noexcept
;
130 void KeyUp (const char *c
) noexcept
;
131 float KeyPressure () noexcept
;
133 inline bool IsDown () const noexcept
{ return (state
&BitDown
); }
134 inline bool IsJustDown () const noexcept
{ return (state
&BitJustDown
); }
135 inline bool IsJustUp () const noexcept
{ return (state
&BitJustUp
); }
137 inline void Unpress () noexcept
{ state
= 0; down
.reset(); }
139 inline void ClearEdges () noexcept
{ state
&= BitDown
; }
140 inline void SetDown (bool flag
) noexcept
{ if (flag
) state
|= BitDown
; else state
&= ~BitDown
; }
141 inline void SetJustDown (bool flag
) noexcept
{ if (flag
) state
|= BitJustDown
; else state
&= ~BitJustDown
; }
142 inline void SetJustUp (bool flag
) noexcept
{ if (flag
) state
|= BitJustUp
; else state
&= ~BitJustUp
; }
146 class TCmdKeyDown
: public VCommand
{
151 inline TCmdKeyDown (const char *AName
, TKButton
&AKey
) noexcept
: VCommand(AName
), Key(AKey
) {}
152 virtual void Run () override
;
156 class TCmdKeyUp
: public VCommand
{
161 inline TCmdKeyUp (const char *AName
, TKButton
&AKey
) noexcept
: VCommand(AName
), Key(AKey
) {}
162 virtual void Run () override
;
180 MODINPUT_FORWARDMOVE
,
186 // bit 0: "currently pressed"
187 // bit 1: just pressed
188 // bit 2: just released
189 const float TKButton::PressureTbl
[8] = {
191 0.0f
, // 000: up the entire frame
192 1.0f
, // 001: held the entire frame
193 0.0f
, // 010: Sys_Error() -- pressed, but not held, impossible
194 0.5f
, // 011: pressed and held this frame
195 0.0f
, // 100: released this frame
196 0.0f
, // 101: Sys_Error() -- released, but held, impossible
197 0.25f
, // 110: pressed and released this frame
198 0.75f
, // 111: released and re-pressed this frame
202 // mouse values are used once
203 static float mousex
= 0.0f
; // relative, scaled by sensitivity
204 static float mousey
= 0.0f
; // relative, scaled by sensitivity
205 // joystick values are in [-127..127] range
206 // modern controllers usually have two analog sticks
207 static int joyxmove
[2] = {0, 0};
208 static int joyymove
[2] = {0, 0};
210 static int currImpulse
= 0;
213 static VCvarB
always_run("always_run", false, "Always run?", CVAR_Archive
|CVAR_NoShadow
);
214 static VCvarB
artiskip("artiskip", true, "Should Shift+Enter skip an artifact?", CVAR_Archive
|CVAR_NoShadow
); // whether shift-enter skips an artifact
216 static VCvarB
cl_input_pressure("cl_input_pressure", false, "Try to detect 'key pressure'?", CVAR_Archive
|CVAR_NoShadow
);
219 static VCvarF
cl_forwardspeed("cl_forwardspeed", "200", "Forward speed.", CVAR_Archive
|CVAR_NoShadow
);
220 static VCvarF
cl_backspeed("cl_backspeed", "200", "Backward speed.", CVAR_Archive
|CVAR_NoShadow
);
221 static VCvarF
cl_sidespeed("cl_sidespeed", "200", "Sidestepping speed.", CVAR_Archive
|CVAR_NoShadow
);
222 static VCvarF
cl_flyspeed("cl_flyspeed", "80", "Flying speed.", CVAR_Archive
|CVAR_NoShadow
);
224 static VCvarF
cl_movespeedkey("cl_movespeedkey", "2", "Running multiplier.", CVAR_Archive
|CVAR_NoShadow
);
226 static VCvarF
cl_yawspeed("cl_yawspeed", "140", "Yaw speed.", CVAR_Archive
|CVAR_NoShadow
);
227 static VCvarF
cl_pitchspeed("cl_pitchspeed", "150", "Pitch speed.", CVAR_Archive
|CVAR_NoShadow
);
228 static VCvarF
cl_pitchdriftspeed("cl_pitchdriftspeed", "270", "Pitch drifting speed.", CVAR_Archive
|CVAR_NoShadow
);
230 static VCvarF
cl_anglespeedkey("cl_anglespeedkey", "1.5", "Fast turning multiplier.", CVAR_Archive
|CVAR_NoShadow
);
232 static VCvarB
cl_deathroll_enabled("cl_deathroll_enabled", false, "Enable death roll?", CVAR_Archive
|CVAR_NoShadow
);
233 static VCvarF
cl_deathroll_amount("cl_deathroll_amount", "75", "Deathroll amount.", CVAR_Archive
|CVAR_NoShadow
);
234 static VCvarF
cl_deathroll_speed("cl_deathroll_speed", "80", "Deathroll speed.", CVAR_Archive
|CVAR_NoShadow
);
236 VCvarF
mouse_x_sensitivity("mouse_x_sensitivity", "5.5", "Horizontal mouse sensitivity.", CVAR_Archive
|CVAR_NoShadow
);
237 VCvarF
mouse_y_sensitivity("mouse_y_sensitivity", "5.5", "Vertical mouse sensitivity.", CVAR_Archive
|CVAR_NoShadow
);
238 static VCvarB
mouse_look("mouse_look", true, "Allow mouselook?", CVAR_Archive
|CVAR_NoShadow
);
239 static VCvarB
mouse_look_horisontal("mouse_look_horisontal", true, "Allow horisontal mouselook?", CVAR_Archive
|CVAR_NoShadow
);
240 static VCvarB
mouse_look_vertical("mouse_look_vertical", true, "Allow vertical mouselook?", CVAR_Archive
|CVAR_NoShadow
);
241 static VCvarB
invert_mouse("invert_mouse", false, "Invert mouse?", CVAR_Archive
|CVAR_NoShadow
);
242 static VCvarB
invert_joystick("invert_joystick", false, "Invert joystick?", CVAR_Archive
|CVAR_NoShadow
);
243 static VCvarB
lookstrafe("lookstrafe", false, "Allow lookstrafe?", CVAR_Archive
|CVAR_NoShadow
);
244 static VCvarB
lookspring_mouse("lookspring_mouse", false, "Allow lookspring for mouselook key?", CVAR_Archive
|CVAR_NoShadow
);
245 static VCvarB
lookspring_keyboard("lookspring_keyboard", false, "Allow lookspring for keyboard view keys?", CVAR_Archive
|CVAR_NoShadow
);
247 VCvarF
m_yaw("m_yaw", "0.022", "Mouse yaw speed.", CVAR_Archive
|CVAR_NoShadow
);
248 VCvarF
m_pitch("m_pitch", "0.022", "Mouse pitch speed.", CVAR_Archive
|CVAR_NoShadow
);
249 static VCvarF
m_forward("m_forward", "1", "Mouse forward speed.", CVAR_Archive
|CVAR_NoShadow
);
250 static VCvarF
m_side("m_side", "0.8", "Mouse sidestepping speed.", CVAR_Archive
|CVAR_NoShadow
);
252 static VCvarF
joy_yaw("joy_yaw", "0.022", "Joystick yaw speed.", CVAR_Archive
|CVAR_NoShadow
);
253 static VCvarF
joy_pitch("joy_pitch", "0.022", "Joystick pitch speed.", CVAR_Archive
|CVAR_NoShadow
);
255 //static VCvarF joy_yaw("joy_yaw", "140", "Joystick yaw speed.", CVAR_Archive|CVAR_NoShadow);
257 static VCvarI
joy_axis_rotate("joy_axis_rotate", "0", "Gamepad stick for camera rotation.", CVAR_Archive
|CVAR_NoShadow
);
258 static VCvarI
joy_axis_pitch("joy_axis_pitch", "0", "Gamepad stick for looking up/down.", CVAR_Archive
|CVAR_NoShadow
);
259 static VCvarI
joy_axis_walk("joy_axis_walk", "1", "Gamepad stick for forward/backward movement.", CVAR_Archive
|CVAR_NoShadow
);
260 static VCvarI
joy_axis_strafe("joy_axis_strafe", "1", "Gamepad stick for strafing.", CVAR_Archive
|CVAR_NoShadow
);
262 static VCvarF
joy_rotate_sensitivity("joy_rotate_sensitivity", "5", "Joystick rotation sensitivity.", CVAR_Archive
|CVAR_NoShadow
);
263 static VCvarF
joy_pitch_sensitivity("joy_pitch_sensitivity", "5", "Joystick look up/down sensitivity.", CVAR_Archive
|CVAR_NoShadow
);
264 static VCvarF
joy_walk_sensitivity("joy_walk_sensitivity", "5", "Joystick movement sensitivity.", CVAR_Archive
|CVAR_NoShadow
);
265 static VCvarF
joy_strafe_sensitivity("joy_strafe_sensitivity", "5", "Joystick strafing sensitivity.", CVAR_Archive
|CVAR_NoShadow
);
268 static TKButton
*knownButtons
= nullptr;
300 //==========================================================================
304 //==========================================================================
305 static bool isValidStickIndex (const int stick
) noexcept
{
306 return (stick
>= 0 && stick
<= 1);
310 //==========================================================================
314 // this is called on window activation/deactivation
316 //==========================================================================
317 void UnpressAllButtons () {
318 for (TKButton
*bt
= knownButtons
; bt
; bt
= bt
->next
) bt
->Unpress();
322 //==========================================================================
324 // TKButton::TKButton
326 //==========================================================================
327 TKButton::TKButton () {
335 //==========================================================================
339 //==========================================================================
340 void TKButton::KeyDown (const char *c
) noexcept
{
343 if (c
&& c
[0]) k
= VStr::atoi(c
); // otherwise, typed manually at the console for continuous down
346 if (k == down[0] || k == down[1]) return; // repeating key
348 if (!down[0]) down[0] = k;
349 else if (!down[1]) down[1] = k;
350 else { GCon->Log(NAME_Dev, "Three keys down for a button!"); return; }
352 if (k
> 0) down
.put(k
, true);
354 if (IsDown()) return; // still down
361 //==========================================================================
365 //==========================================================================
366 void TKButton::KeyUp (const char *c
) noexcept
{
368 // typed manually at the console, assume for unsticking, so clear all
369 //down[0] = down[1] = 0;
371 SetJustUp(true); // impulse up
375 int k
= VStr::atoi(c
);
378 if (down[0] == k) down[0] = 0;
379 else if (down[1] == k) down[1] = 0;
380 else return; // key up without coresponding down (menu pass through)
382 if (down[0] || down[1]) return; // some other key is still holding it down
386 if (down
.length() != 0) return; // some other key is still holding it down
388 if (!IsDown()) return; // still up (this should not happen)
395 //==========================================================================
397 // TKButton::KeyPressure
400 // 0.0 if not pressed, or released
401 // 0.25 if the key was pressed and released during the frame
402 // 0.5 if the key was pressed and held
403 // 0.75 if the key was released and then pressed during this frame
404 // 1.0 if the key was held for the entire time
406 //==========================================================================
407 float TKButton::KeyPressure () noexcept
{
408 const float val
= PressureTbl
[state
&7];
410 if (cl_input_pressure
.asBool()) return val
;
411 return (isU32NonZeroF(val
) ? 1.0f
: 0.0f
);
415 //==========================================================================
419 //==========================================================================
420 void TCmdKeyDown::Run () {
421 Key
.KeyDown(Args
.length() > 1 ? *Args
[1] : "");
425 //==========================================================================
429 //==========================================================================
430 void TCmdKeyUp::Run () {
431 Key
.KeyUp(Args
.length() > 1 ? *Args
[1] : "");
435 //==========================================================================
439 //==========================================================================
441 if (Args
.length() < 2) return;
442 currImpulse
= VStr::atoi(*Args
[1]);
443 //GCon->Logf(NAME_Debug, "IMPULSE COMMAND: %d (%s)", currImpulse, *Args[1]);
447 //==========================================================================
449 // COMMAND ToggleAlwaysRun
451 //==========================================================================
452 COMMAND(ToggleAlwaysRun
) {
454 if (MN_Active()) return;
455 if (!cl
|| !GClGame
|| !GGameInfo
|| GClGame
->InIntermission() || GGameInfo
->NetMode
<= NM_TitleMap
) {
456 GCon
->Log(NAME_Warning
, "Cannot toggle autorun while not in game!");
460 if (GGameInfo->IsPaused()) {
461 if (cl) cl->Printf("Cannot toggle autorun while the game is paused!"); else GCon->Log(NAME_Warning, "Cannot toggle autorun while the game is paused!");
466 always_run
= !always_run
;
469 cl
->Printf(always_run
? "Always run on" : "Always run off");
473 GCon
->Log(always_run
? "Always run on" : "Always run off");
478 //==========================================================================
482 //==========================================================================
484 if (Args
.length() < 1) return;
486 if (MN_Active()) return;
487 if (!cl
|| !GClGame
|| !GGameInfo
|| GClGame
->InIntermission() || GGameInfo
->NetMode
<= NM_TitleMap
) {
488 if (cl
) cl
->Printf("Cannot use artifact while not in game!"); else GCon
->Log(NAME_Warning
, "Cannot use artifact while not in game!");
491 //if (GGameInfo->IsPaused()) return;
492 //GCon->Logf(NAME_Debug, "USE: <%s>", *Args[1]);
493 cl
->eventUseInventory(*Args
[1]);
498 //==========================================================================
500 // VBasePlayer::StartPitchDrift
502 //==========================================================================
503 void VBasePlayer::StartPitchDrift () {
504 PlayerFlags
|= PF_Centering
;
508 //==========================================================================
510 // VBasePlayer::StopPitchDrift
512 //==========================================================================
513 void VBasePlayer::StopPitchDrift () {
514 PlayerFlags
&= ~PF_Centering
;
518 //==========================================================================
520 // VBasePlayer::IsRunEnabled
522 //==========================================================================
523 bool VBasePlayer::IsRunEnabled () const noexcept
{
524 if (GGameInfo
->NetMode
== NM_Client
) return !(GGameInfo
->clientFlags
&VGameInfo::CLF_RUN_DISABLED
);
525 return !sv_disable_run
.asBool();
529 //==========================================================================
531 // VBasePlayer::IsMLookEnabled
533 //==========================================================================
534 bool VBasePlayer::IsMLookEnabled () const noexcept
{
535 if (GGameInfo
->NetMode
== NM_Client
) return !(GGameInfo
->clientFlags
&VGameInfo::CLF_MLOOK_DISABLED
);
536 if (sv_disable_mlook
.asBool()) return false;
537 if (!Level
) return true; // no map
538 if (sv_ignore_nomlook
.asBool()) return true; // ignore mapinfo option
539 // dedicated server ignores map flags in DM mode
540 if (GGameInfo
->NetMode
== NM_DedicatedServer
&& svs
.deathmatch
) return true;
541 // don't forget to send this flags to client!
542 return !(Level
->LevelInfoFlags
&VLevelInfo::LIF_NoFreelook
);
546 //==========================================================================
548 // VBasePlayer::IsCrouchEnabled
550 //==========================================================================
551 bool VBasePlayer::IsCrouchEnabled () const noexcept
{
552 if (GGameInfo
->NetMode
== NM_Client
) return !(GGameInfo
->clientFlags
&VGameInfo::CLF_CROUCH_DISABLED
);
553 if (sv_disable_crouch
.asBool()) return false;
554 if (!Level
) return true; // no map
555 if (sv_ignore_nocrouch
.asBool()) return true; // ignore mapinfo option
556 // dedicated server ignores map flags in DM mode
557 if (GGameInfo
->NetMode
== NM_DedicatedServer
&& svs
.deathmatch
) return true;
558 // don't forget to send this flags to client!
559 return !(Level
->LevelInfoFlags2
&VLevelInfo::LIF2_NoCrouch
);
563 //==========================================================================
565 // VBasePlayer::IsJumpEnabled
567 //==========================================================================
568 bool VBasePlayer::IsJumpEnabled () const noexcept
{
569 if (GGameInfo
->NetMode
== NM_Client
) return !(GGameInfo
->clientFlags
&VGameInfo::CLF_JUMP_DISABLED
);
570 if (sv_disable_jump
.asBool()) return false;
571 if (!Level
) return true; // no map
572 if (sv_ignore_nojump
.asBool()) return true; // ignore mapinfo option
573 // dedicated server ignores map flags in DM mode
574 if (GGameInfo
->NetMode
== NM_DedicatedServer
&& svs
.deathmatch
) return true;
575 // don't forget to send this flags to client!
576 return !(Level
->LevelInfoFlags
&VLevelInfo::LIF_NoJump
);
580 //==========================================================================
582 // VBasePlayer::AdjustAngles
584 //==========================================================================
585 void VBasePlayer::AdjustAngles () {
586 const bool isRunning
= (IsRunEnabled() ? KeySpeed
.IsDown() : false);
587 const float speed
= host_frametime
*(isRunning
? cl_anglespeedkey
: 1.0f
);
589 const bool mlookJustUp
= KeyMouseLook
.IsJustUp();
590 bool mlookIsDown
= KeyMouseLook
.IsDown();
591 bool klookAnyDown
= KeyLookUp
.IsDown() || KeyLookDown
.IsDown();
592 const bool klookJustUp
= (!klookAnyDown
&& (KeyLookUp
.IsJustUp() || KeyLookDown
.IsJustUp()));
594 if (lookspring_mouse
) {
595 if (!lookspring_keyboard
) klookAnyDown
= false;
596 if (mlookJustUp
&& !klookAnyDown
) StartPitchDrift();
598 if (lookspring_keyboard
) {
599 if (!lookspring_mouse
) mlookIsDown
= false;
600 if (klookJustUp
&& !mlookIsDown
) StartPitchDrift();
602 KeyMouseLook
.ClearEdges();
605 if (!KeyStrafe
.IsDown()) {
606 ViewAngles
.yaw
-= KeyRight
.KeyPressure()*cl_yawspeed
*speed
;
607 ViewAngles
.yaw
+= KeyLeft
.KeyPressure()*cl_yawspeed
*speed
;
609 //if (joyxmove > 0) ViewAngles.yaw -= joy_yaw*speed;
610 //if (joyxmove < 0) ViewAngles.yaw += joy_yaw*speed;
611 int stick
= joy_axis_rotate
.asInt();
612 if (isValidStickIndex(stick
) && mouse_look_horisontal
&& joyxmove
[stick
]) {
613 //ViewAngles.yaw -= joyxmove[stick]/127.0*joy_yaw*speed;
614 ViewAngles
.yaw
-= joyxmove
[stick
]*joy_yaw
*(joy_rotate_sensitivity
.asFloat()/5.0f
);
617 if (mouse_look_horisontal
&& !KeyStrafe
.IsDown() && (!lookstrafe
|| (!mouse_look
&& !KeyMouseLook
.IsDown()))) ViewAngles
.yaw
-= mousex
*m_yaw
;
618 ViewAngles
.yaw
= AngleMod(ViewAngles
.yaw
);
621 const float up
= KeyLookUp
.KeyPressure();
622 const float down
= KeyLookDown
.KeyPressure();
623 ViewAngles
.pitch
-= cl_pitchspeed
*up
*speed
;
624 ViewAngles
.pitch
+= cl_pitchspeed
*down
*speed
;
625 if (up
|| down
|| KeyMouseLook
.IsDown()) StopPitchDrift();
626 if (mouse_look_vertical
) {
627 if ((mouse_look
|| KeyMouseLook
.IsDown()) && !KeyStrafe
.IsDown()) ViewAngles
.pitch
-= mousey
*m_pitch
;
629 const int stick
= joy_axis_pitch
.asInt();
630 if (isValidStickIndex(stick
) && joyymove
[stick
]) {
631 float val
= joyymove
[stick
]*joy_pitch
*(joy_pitch_sensitivity
.asFloat()/5.0f
);
632 if (invert_joystick
) val
= -val
;
633 ViewAngles
.pitch
+= val
;
637 // reset pitch if mouse look is disabled
638 if (!IsMLookEnabled()) ViewAngles
.pitch
= 0;
641 if (KeyLookCenter
.IsDown() || KeyFlyCenter
.IsDown()) StartPitchDrift();
642 if (PlayerFlags
&PF_Centering
) {
643 float adelta
= cl_pitchdriftspeed
*host_frametime
;
644 if (fabsf(ViewAngles
.pitch
) < adelta
) {
645 ViewAngles
.pitch
= 0;
646 PlayerFlags
&= ~PF_Centering
;
648 if (ViewAngles
.pitch
> 0.0f
) ViewAngles
.pitch
-= adelta
;
649 else if (ViewAngles
.pitch
< 0.0f
) ViewAngles
.pitch
+= adelta
;
655 if (cl_deathroll_enabled
&& cl_deathroll_amount
.asFloat() > 0) {
656 const float drspeed
= cl_deathroll_speed
.asFloat();
657 const float dramount
= min2(180.0f
, cl_deathroll_amount
.asFloat());
658 // use random roll direction
660 (ViewAngles
.roll
== 0 ? (GenRandomBool() ? -1.0f
: 1.0f
) :
661 ViewAngles
.roll
< 0 ? -1.0f
: 1.0f
);
663 ViewAngles
.roll
= dramount
*dir
;
665 ViewAngles
.roll
+= drspeed
*dir
*host_frametime
;
667 ViewAngles
.roll
= clampval(ViewAngles
.roll
, -dramount
, dramount
);
669 ViewAngles
.roll
= 0.0f
;
672 ViewAngles
.roll
= 0.0f
;
676 if (ViewAngles
.pitch
> 80.0f
) ViewAngles
.pitch
= 80.0f
;
677 if (ViewAngles
.pitch
< -80.0f
) ViewAngles
.pitch
= -80.0f
;
679 if (ViewAngles
.roll
> 80.0f
) ViewAngles
.roll
= 80.0f
;
680 if (ViewAngles
.roll
< -80.0f
) ViewAngles
.roll
= -80.0f
;
684 //==========================================================================
686 // VBasePlayer::HandleInput
688 // Creates movement commands from all of the available inputs.
690 //==========================================================================
691 void VBasePlayer::HandleInput () {
692 const bool runEnabled
= IsRunEnabled();
694 float forward
= 0.0f
;
696 float flyheight
= 0.0f
;
698 ViewMouseDeltaX
= mousex
*m_yaw
;
699 ViewMouseDeltaY
= mousey
*m_pitch
;
700 RawMouseDeltaX
= mousex
;
701 RawMouseDeltaY
= mousey
;
703 const float oldMouseX
= mousex
;
704 const float oldMouseY
= mousey
;
705 const TAVec origViewAngles
= ViewAngles
;
706 if (PlayerFlags
&PF_BlockMouseX
) mousex
= 0; else if (PlayerFlags
&PF_InverseMouseX
) mousex
= -mousex
;
707 if (PlayerFlags
&PF_BlockMouseY
) mousey
= 0; else if (PlayerFlags
&PF_InverseMouseY
) mousey
= -mousey
;
711 if (PlayerFlags
&PF_BlockMouseX
) ViewAngles
.yaw
= origViewAngles
.yaw
;
712 if (PlayerFlags
&PF_BlockMouseY
) ViewAngles
.pitch
= origViewAngles
.pitch
;
716 // let movement keys cancel each other out
717 if (KeyStrafe
.IsDown()) {
718 side
+= KeyRight
.KeyPressure()*cl_sidespeed
;
719 side
-= KeyLeft
.KeyPressure()*cl_sidespeed
;
721 //if (joyxmove > 0) side += cl_sidespeed;
722 //if (joyxmove < 0) side -= cl_sidespeed;
726 int stick
= joy_axis_strafe
.asInt();
727 if (isValidStickIndex(stick
) && joyxmove
[stick
]) {
728 side
+= joyxmove
[stick
]/127.0*cl_sidespeed
*(joy_strafe_sensitivity
.asFloat()/5.0f
);
732 forward
+= KeyForward
.KeyPressure()*cl_forwardspeed
;
733 forward
-= KeyBackward
.KeyPressure()*cl_backspeed
;
735 side
+= KeyMoveRight
.KeyPressure()*cl_sidespeed
;
736 side
-= KeyMoveLeft
.KeyPressure()*cl_sidespeed
;
740 //if (joyymove < 0) forward += cl_forwardspeed;
741 //if (joyymove > 0) forward -= cl_backspeed;
742 int stick
= joy_axis_walk
.asInt();
743 if (isValidStickIndex(stick
)) {
744 if (joyymove
[stick
] > 0) forward
-= joyymove
[stick
]/127.0*cl_backspeed
*(joy_walk_sensitivity
.asFloat()/5.0f
);
745 else if (joyymove
[stick
] < 0) forward
-= joyymove
[stick
]/127.0*cl_forwardspeed
*(joy_walk_sensitivity
.asFloat()/5.0f
);
749 // fly up/down/drop keys
750 flyheight
+= KeyFlyUp
.KeyPressure()*cl_flyspeed
; // note that the actual flyheight will be twice this
751 flyheight
-= KeyFlyDown
.KeyPressure()*cl_flyspeed
;
753 if ((!mouse_look
&& !KeyMouseLook
.IsDown()) || KeyStrafe
.IsDown()) {
754 forward
+= m_forward
*mousey
;
757 if (KeyStrafe
.IsDown() || (lookstrafe
&& (mouse_look
|| KeyMouseLook
.IsDown()))) {
758 side
+= m_side
*mousex
;
761 forward
= midval(forward
, -cl_backspeed
, cl_forwardspeed
.asFloat());
762 side
= midval(side
, -cl_sidespeed
, cl_sidespeed
.asFloat());
764 if (runEnabled
&& (always_run
|| KeySpeed
.IsDown())) {
765 forward
*= cl_movespeedkey
;
766 side
*= cl_movespeedkey
;
767 flyheight
*= cl_movespeedkey
;
770 flyheight
= midval(flyheight
, -127.0f
, 127.0f
);
771 if (KeyFlyCenter
.KeyPressure()) flyheight
= TOCENTRE
;
776 if (KeyAttack
.KeyPressure()) Buttons
|= BT_ATTACK
;
777 if (KeyUse
.KeyPressure()) Buttons
|= BT_USE
;
778 if (KeyJump
.KeyPressure()) Buttons
|= BT_JUMP
;
779 if (KeyCrouch
.KeyPressure()) Buttons
|= BT_CROUCH
;
780 if (KeyAltAttack
.KeyPressure()) Buttons
|= BT_ALT_ATTACK
;
781 if (KeyButton5
.KeyPressure()) Buttons
|= BT_BUTTON_5
;
782 if (KeyButton6
.KeyPressure()) Buttons
|= BT_BUTTON_6
;
783 if (KeyButton7
.KeyPressure()) Buttons
|= BT_BUTTON_7
;
784 if (KeyButton8
.KeyPressure()) Buttons
|= BT_BUTTON_8
;
786 if (KeyForward
.KeyPressure()) Buttons
|= BT_FORWARD
;
787 if (KeyBackward
.KeyPressure()) Buttons
|= BT_BACKWARD
;
788 if (KeyLeft
.KeyPressure()) Buttons
|= BT_LEFT
;
789 if (KeyRight
.KeyPressure()) Buttons
|= BT_RIGHT
;
790 if (KeyMoveLeft
.KeyPressure()) Buttons
|= BT_MOVELEFT
;
791 if (KeyMoveRight
.KeyPressure()) Buttons
|= BT_MOVERIGHT
;
792 if (KeyStrafe
.KeyPressure()) Buttons
|= BT_STRAFE
;
793 if (KeySpeed
.KeyPressure()) Buttons
|= BT_SPEED
;
794 if (KeyReload
.KeyPressure()) Buttons
|= BT_RELOAD
;
795 if (KeyFlashlight
.KeyPressure()) Buttons
|= BT_FLASHLIGHT
;
797 if (KeySuperBullet
.KeyPressure()) Buttons
|= BT_SUPERBULLET
;
798 if (KeyZoom
.KeyPressure()) Buttons
|= BT_ZOOM
;
799 //GCon->Logf("VBasePlayer::HandleInput(%p): Buttons=0x%08x", this, Buttons);
801 AcsCurrButtonsPressed
|= Buttons
;
802 AcsCurrButtons
= Buttons
; // scripts can change `Buttons`, but not this
803 //AcsButtons = Buttons; // this logic is handled by `SV_RunClients()`
804 //GCon->Logf("VBasePlayer::HandleInput(%p): %d; Buttons=0x%08x; OldButtons=0x%08x", this, (KeyJump.KeyPressure() ? 1 : 0), Buttons, OldButtons);
808 eventServerImpulse(currImpulse
);
812 ClientForwardMove
= forward
;
813 ClientSideMove
= side
;
816 AcsPrevMouseX
+= mousex
*m_yaw
;
817 AcsPrevMouseY
+= mousey
*m_pitch
;
823 //==========================================================================
825 // VBasePlayer::Responder
827 // Get info needed to make movement commands for the players.
829 //==========================================================================
830 bool VBasePlayer::Responder (event_t
*ev
) {
833 mousex
= ev
->dx
*mouse_x_sensitivity
;
834 mousey
= ev
->dy
*mouse_y_sensitivity
;
835 if (invert_mouse
) mousey
= -mousey
;
836 return true; // eat events
838 if (ev
->joyidx
>= 0 && ev
->joyidx
<= 1) {
839 joyxmove
[ev
->joyidx
] = ev
->dx
;
840 joyymove
[ev
->joyidx
] = ev
->dy
;
842 return true; // eat events
850 //==========================================================================
852 // VBasePlayer::ClearInput
854 //==========================================================================
855 void VBasePlayer::ClearInput () {
856 // clear cmd building stuff
857 joyxmove
[0] = joyymove
[0] = 0;
858 joyxmove
[1] = joyymove
[1] = 0;
864 //==========================================================================
866 // VBasePlayer::AcsGetInput
868 //==========================================================================
869 int VBasePlayer::AcsGetInput (int InputType
) {
872 //float angle0 = 0, angle1 = 0;
875 case INPUT_OLDBUTTONS
: case MODINPUT_OLDBUTTONS
:
876 case INPUT_BUTTONS
: case MODINPUT_BUTTONS
:
877 if (InputType
== INPUT_OLDBUTTONS
|| InputType
== MODINPUT_OLDBUTTONS
) {
879 //k8: hack for DooM:ONE
884 // convert buttons to what ACS expects
885 // /*if (Btn)*/ GCon->Logf("VBasePlayer::AcsGetInput(%p): Buttons: %08x; curr=%08x; old=%08x; Buttons=%08x; OldButtons=%08x", this, (unsigned)Btn, AcsButtons, OldButtons, Buttons, OldButtons);
886 if (Btn
&BT_ATTACK
) Ret
|= ACS_BT_ATTACK
;
887 if (Btn
&BT_USE
) Ret
|= ACS_BT_USE
;
888 if (Btn
&BT_JUMP
) Ret
|= ACS_BT_JUMP
;
889 if (Btn
&BT_CROUCH
) Ret
|= ACS_BT_CROUCH
;
890 if (Btn
&BT_ALT_ATTACK
) Ret
|= ACS_BT_ALTATTACK
;
891 if (Btn
&BT_FORWARD
) Ret
|= ACS_BT_FORWARD
;
892 if (Btn
&BT_BACKWARD
) Ret
|= ACS_BT_BACK
;
893 if (Btn
&BT_LEFT
) Ret
|= ACS_BT_LEFT
;
894 if (Btn
&BT_RIGHT
) Ret
|= ACS_BT_RIGHT
;
895 if (Btn
&BT_MOVELEFT
) Ret
|= ACS_BT_MOVELEFT
;
896 if (Btn
&BT_MOVERIGHT
) Ret
|= ACS_BT_MOVERIGHT
;
897 if (Btn
&BT_STRAFE
) Ret
|= ACS_BT_STRAFE
;
898 if (Btn
&BT_SPEED
) Ret
|= ACS_BT_SPEED
;
899 if (Btn
&BT_RELOAD
) Ret
|= ACS_BT_RELOAD
;
900 if (Btn
&BT_ZOOM
) Ret
|= ACS_BT_ZOOM
;
901 if (Btn
&BT_BUTTON_5
) Ret
|= ACS_BT_USER1
;
902 if (Btn
&BT_BUTTON_6
) Ret
|= ACS_BT_USER2
;
903 if (Btn
&BT_BUTTON_7
) Ret
|= ACS_BT_USER3
;
904 if (Btn
&BT_BUTTON_8
) Ret
|= ACS_BT_USER4
;
907 case INPUT_YAW
: case MODINPUT_YAW
:
908 return (int)(-AcsMouseX
*65536.0f
/360.0f
);
910 case INPUT_PITCH
: case MODINPUT_PITCH
:
911 return (int)(AcsMouseY
*65536.0f
/360.0f
);
913 case INPUT_ROLL
: case MODINPUT_ROLL
:
914 // player cannot do it yet
917 case INPUT_FORWARDMOVE
: return (int)(ClientForwardMove
*0x32/400);
918 case MODINPUT_FORWARDMOVE
: return (int)(ForwardMove
*0x32/400);
920 case INPUT_SIDEMOVE
: return (int)(ClientSideMove
*0x32/400);
921 case MODINPUT_SIDEMOVE
: return (int)(SideMove
*0x32/400);
924 case MODINPUT_UPMOVE
:
925 return (int)(FlyMove
*3*256/80);