libvwad: updated -- vwadwrite: free file buffers on close (otherwise archive creation...
[k8vavoom.git] / source / psim / p_player_input.cpp
blob8a48dd95e6ae791292ac452887656d2e6cda3c9b
1 //**************************************************************************
2 //**
3 //** ## ## ## ## ## #### #### ### ###
4 //** ## ## ## ## ## ## ## ## ## ## #### ####
5 //** ## ## ## ## ## ## ## ## ## ## ## ## ## ##
6 //** ## ## ######## ## ## ## ## ## ## ## ### ##
7 //** ### ## ## ### ## ## ## ## ## ##
8 //** # ## ## # #### #### ## ##
9 //**
10 //** Copyright (C) 1999-2006 Jānis Legzdiņš
11 //** Copyright (C) 2018-2023 Ketmar Dark
12 //**
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.
16 //**
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.
21 //**
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/>.
24 //**
25 //**************************************************************************
26 //**
27 //** KEY BUTTONS
28 //**
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.
33 //**
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.
37 //**
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
41 //**
42 //**************************************************************************
43 #include "../gamedefs.h"
44 #include "../host.h" /* host_frametime */
45 #include "p_levelinfo.h"
46 #include "p_player.h"
47 #include "../server/server.h"
48 #ifdef CLIENT
49 # include "../client/client.h"
50 # include "../client/cl_local.h"
51 #endif
52 #include "../menu.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 */
100 class TKButton {
101 protected:
102 // see below
103 static const float PressureTbl[8];
105 protected:
106 enum {
107 BitDown = 1u<<0,
108 BitJustDown = 1u<<1,
109 BitJustUp = 1u<<2,
112 protected:
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
119 unsigned state;
120 // all known buttons
121 TKButton *next;
123 // fuck
124 friend void UnpressAllButtons ();
126 public:
127 TKButton ();
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 {
147 public:
148 TKButton &Key;
150 public:
151 inline TCmdKeyDown (const char *AName, TKButton &AKey) noexcept : VCommand(AName), Key(AKey) {}
152 virtual void Run () override;
156 class TCmdKeyUp : public VCommand {
157 public:
158 TKButton &Key;
160 public:
161 inline TCmdKeyUp (const char *AName, TKButton &AKey) noexcept : VCommand(AName), Key(AKey) {}
162 virtual void Run () override;
166 enum {
167 INPUT_OLDBUTTONS,
168 INPUT_BUTTONS,
169 INPUT_PITCH,
170 INPUT_YAW,
171 INPUT_ROLL,
172 INPUT_FORWARDMOVE,
173 INPUT_SIDEMOVE,
174 INPUT_UPMOVE,
175 MODINPUT_OLDBUTTONS,
176 MODINPUT_BUTTONS,
177 MODINPUT_PITCH,
178 MODINPUT_YAW,
179 MODINPUT_ROLL,
180 MODINPUT_FORWARDMOVE,
181 MODINPUT_SIDEMOVE,
182 MODINPUT_UPMOVE
186 // bit 0: "currently pressed"
187 // bit 1: just pressed
188 // bit 2: just released
189 const float TKButton::PressureTbl[8] = {
190 // rph
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;
270 BUTTON(Forward)
271 BUTTON(Backward)
272 BUTTON(Left)
273 BUTTON(Right)
274 BUTTON(LookUp)
275 BUTTON(LookDown)
276 BUTTON(LookCenter)
277 BUTTON(MoveLeft)
278 BUTTON(MoveRight)
279 BUTTON(FlyUp)
280 BUTTON(FlyDown)
281 BUTTON(FlyCenter)
282 BUTTON(Attack)
283 BUTTON(Use)
284 BUTTON(Jump)
285 BUTTON(Crouch)
286 BUTTON(AltAttack)
287 BUTTON(Button5)
288 BUTTON(Button6)
289 BUTTON(Button7)
290 BUTTON(Button8)
291 BUTTON(Speed)
292 BUTTON(Strafe)
293 BUTTON(MouseLook)
294 BUTTON(Reload)
295 BUTTON(Flashlight)
296 BUTTON(SuperBullet)
297 BUTTON(Zoom)
300 //==========================================================================
302 // isValidStickIndex
304 //==========================================================================
305 static bool isValidStickIndex (const int stick) noexcept {
306 return (stick >= 0 && stick <= 1);
310 //==========================================================================
312 // UnpressAllButtons
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 () {
328 state = 0;
329 // register in list
330 next = knownButtons;
331 knownButtons = this;
335 //==========================================================================
337 // TKButton::KeyDown
339 //==========================================================================
340 void TKButton::KeyDown (const char *c) noexcept {
341 vint32 k = -1;
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
356 SetDown(true);
357 SetJustDown(true);
361 //==========================================================================
363 // TKButton::KeyUp
365 //==========================================================================
366 void TKButton::KeyUp (const char *c) noexcept {
367 if (!c || !c[0]) {
368 // typed manually at the console, assume for unsticking, so clear all
369 //down[0] = down[1] = 0;
370 Unpress();
371 SetJustUp(true); // impulse up
372 return;
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
385 down.del(k);
386 if (down.length() != 0) return; // some other key is still holding it down
388 if (!IsDown()) return; // still up (this should not happen)
390 SetDown(false);
391 SetJustUp(true);
395 //==========================================================================
397 // TKButton::KeyPressure
399 // returns:
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];
409 ClearEdges();
410 if (cl_input_pressure.asBool()) return val;
411 return (isU32NonZeroF(val) ? 1.0f : 0.0f);
415 //==========================================================================
417 // TCmdKeyDown::Run
419 //==========================================================================
420 void TCmdKeyDown::Run () {
421 Key.KeyDown(Args.length() > 1 ? *Args[1] : "");
425 //==========================================================================
427 // TCmdKeyUp::Run
429 //==========================================================================
430 void TCmdKeyUp::Run () {
431 Key.KeyUp(Args.length() > 1 ? *Args[1] : "");
435 //==========================================================================
437 // COMMAND Impulse
439 //==========================================================================
440 COMMAND(Impulse) {
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) {
453 #ifdef CLIENT
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!");
457 return;
459 /*k8: why?
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!");
462 return;
465 #endif
466 always_run = !always_run;
467 #ifdef CLIENT
468 if (cl) {
469 cl->Printf(always_run ? "Always run on" : "Always run off");
470 } else
471 #endif
473 GCon->Log(always_run ? "Always run on" : "Always run off");
478 //==========================================================================
480 // COMMAND Use
482 //==========================================================================
483 COMMAND(Use) {
484 if (Args.length() < 1) return;
485 #ifdef CLIENT
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!");
489 return;
491 //if (GGameInfo->IsPaused()) return;
492 //GCon->Logf(NAME_Debug, "USE: <%s>", *Args[1]);
493 cl->eventUseInventory(*Args[1]);
494 #endif
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();
604 // yaw
605 if (!KeyStrafe.IsDown()) {
606 ViewAngles.yaw -= KeyRight.KeyPressure()*cl_yawspeed*speed;
607 ViewAngles.yaw += KeyLeft.KeyPressure()*cl_yawspeed*speed;
608 // old code
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);
620 // pitch
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;
628 // added code
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;
640 // center look
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;
647 } else {
648 if (ViewAngles.pitch > 0.0f) ViewAngles.pitch -= adelta;
649 else if (ViewAngles.pitch < 0.0f) ViewAngles.pitch += adelta;
653 // roll
654 if (Health <= 0) {
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
659 const float dir =
660 (ViewAngles.roll == 0 ? (GenRandomBool() ? -1.0f : 1.0f) :
661 ViewAngles.roll < 0 ? -1.0f : 1.0f);
662 if (drspeed <= 0) {
663 ViewAngles.roll = dramount*dir;
664 } else {
665 ViewAngles.roll += drspeed*dir*host_frametime;
667 ViewAngles.roll = clampval(ViewAngles.roll, -dramount, dramount);
668 } else {
669 ViewAngles.roll = 0.0f;
671 } else {
672 ViewAngles.roll = 0.0f;
675 // check angles
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;
695 float side = 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;
709 AdjustAngles();
711 if (PlayerFlags&PF_BlockMouseX) ViewAngles.yaw = origViewAngles.yaw;
712 if (PlayerFlags&PF_BlockMouseY) ViewAngles.pitch = origViewAngles.pitch;
713 mousex = oldMouseX;
714 mousey = oldMouseY;
716 // let movement keys cancel each other out
717 if (KeyStrafe.IsDown()) {
718 side += KeyRight.KeyPressure()*cl_sidespeed;
719 side -= KeyLeft.KeyPressure()*cl_sidespeed;
720 // old code
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;
739 // old code
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;
773 // buttons
774 Buttons = 0;
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);
806 // impulse
807 if (currImpulse) {
808 eventServerImpulse(currImpulse);
809 currImpulse = 0;
812 ClientForwardMove = forward;
813 ClientSideMove = side;
814 FlyMove = flyheight;
816 AcsPrevMouseX += mousex*m_yaw;
817 AcsPrevMouseY += mousey*m_pitch;
819 mousex = mousey = 0;
823 //==========================================================================
825 // VBasePlayer::Responder
827 // Get info needed to make movement commands for the players.
829 //==========================================================================
830 bool VBasePlayer::Responder (event_t *ev) {
831 switch (ev->type) {
832 case ev_mouse:
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
837 case ev_joystick:
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
843 default:
844 break;
846 return false;
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;
859 mousex = mousey = 0;
860 currImpulse = 0;
864 //==========================================================================
866 // VBasePlayer::AcsGetInput
868 //==========================================================================
869 int VBasePlayer::AcsGetInput (int InputType) {
870 int Btn;
871 int Ret = 0;
872 //float angle0 = 0, angle1 = 0;
873 //static int n = 0;
874 switch (InputType) {
875 case INPUT_OLDBUTTONS: case MODINPUT_OLDBUTTONS:
876 case INPUT_BUTTONS: case MODINPUT_BUTTONS:
877 if (InputType == INPUT_OLDBUTTONS || InputType == MODINPUT_OLDBUTTONS) {
878 Btn = OldButtons;
879 //k8: hack for DooM:ONE
880 //Btn &= ~BT_USE;
881 } else {
882 Btn = AcsButtons;
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;
905 return Ret;
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
915 return 0;
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);
923 case INPUT_UPMOVE:
924 case MODINPUT_UPMOVE:
925 return (int)(FlyMove*3*256/80);
927 return 0;