mirror of
https://github.com/dhewm/dhewm3.git
synced 2024-11-26 14:21:18 +00:00
50d7129b1c
in_allowAlwaysRunInSP allows using in_alwaysRun and in_toggleRun in Single Player (it'll still drain your stamina!) m_invertLook allows inverting mouse look, both for up/down and left/right, if you're into that kind of thing
1404 lines
37 KiB
C++
1404 lines
37 KiB
C++
/*
|
|
===========================================================================
|
|
|
|
Doom 3 GPL Source Code
|
|
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
|
|
|
This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code").
|
|
|
|
Doom 3 Source Code is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
Doom 3 Source Code is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
|
|
|
|
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
|
|
|
===========================================================================
|
|
*/
|
|
|
|
#include "sys/platform.h"
|
|
#include "idlib/math/Vector.h"
|
|
#include "idlib/Lib.h"
|
|
#include "framework/CVarSystem.h"
|
|
#include "framework/KeyInput.h"
|
|
#include "framework/async/AsyncNetwork.h"
|
|
|
|
#include "framework/UsercmdGen.h"
|
|
|
|
/*
|
|
================
|
|
usercmd_t::ByteSwap
|
|
================
|
|
*/
|
|
void usercmd_t::ByteSwap( void ) {
|
|
angles[0] = LittleShort( angles[0] );
|
|
angles[1] = LittleShort( angles[1] );
|
|
angles[2] = LittleShort( angles[2] );
|
|
sequence = LittleInt( sequence );
|
|
}
|
|
|
|
/*
|
|
================
|
|
usercmd_t::operator==
|
|
================
|
|
*/
|
|
bool usercmd_t::operator==( const usercmd_t &rhs ) const {
|
|
return ( buttons == rhs.buttons &&
|
|
forwardmove == rhs.forwardmove &&
|
|
rightmove == rhs.rightmove &&
|
|
upmove == rhs.upmove &&
|
|
angles[0] == rhs.angles[0] &&
|
|
angles[1] == rhs.angles[1] &&
|
|
angles[2] == rhs.angles[2] &&
|
|
impulse == rhs.impulse &&
|
|
flags == rhs.flags &&
|
|
mx == rhs.mx &&
|
|
my == rhs.my );
|
|
}
|
|
|
|
|
|
const int KEY_MOVESPEED = 127;
|
|
|
|
typedef enum {
|
|
UB_NONE,
|
|
|
|
UB_UP,
|
|
UB_DOWN,
|
|
UB_LEFT,
|
|
UB_RIGHT,
|
|
UB_FORWARD,
|
|
UB_BACK,
|
|
UB_LOOKUP,
|
|
UB_LOOKDOWN,
|
|
UB_STRAFE,
|
|
UB_MOVELEFT,
|
|
UB_MOVERIGHT,
|
|
|
|
UB_BUTTON0,
|
|
UB_BUTTON1,
|
|
UB_BUTTON2,
|
|
UB_BUTTON3,
|
|
UB_BUTTON4,
|
|
UB_BUTTON5,
|
|
UB_BUTTON6,
|
|
UB_BUTTON7,
|
|
|
|
UB_ATTACK, // NOTE: this value (20) is hardcoded in idUserInterfaceLocal::HandleEvent() !
|
|
UB_SPEED,
|
|
UB_ZOOM,
|
|
UB_SHOWSCORES,
|
|
UB_MLOOK,
|
|
|
|
UB_IMPULSE0,
|
|
UB_IMPULSE1,
|
|
UB_IMPULSE2,
|
|
UB_IMPULSE3,
|
|
UB_IMPULSE4,
|
|
UB_IMPULSE5,
|
|
UB_IMPULSE6,
|
|
UB_IMPULSE7,
|
|
UB_IMPULSE8,
|
|
UB_IMPULSE9,
|
|
UB_IMPULSE10,
|
|
UB_IMPULSE11,
|
|
UB_IMPULSE12,
|
|
UB_IMPULSE13,
|
|
UB_IMPULSE14,
|
|
UB_IMPULSE15,
|
|
UB_IMPULSE16,
|
|
UB_IMPULSE17,
|
|
UB_IMPULSE18,
|
|
UB_IMPULSE19,
|
|
UB_IMPULSE20,
|
|
UB_IMPULSE21,
|
|
UB_IMPULSE22,
|
|
UB_IMPULSE23,
|
|
UB_IMPULSE24,
|
|
UB_IMPULSE25,
|
|
UB_IMPULSE26,
|
|
UB_IMPULSE27,
|
|
UB_IMPULSE28,
|
|
UB_IMPULSE29,
|
|
UB_IMPULSE30,
|
|
UB_IMPULSE31,
|
|
UB_IMPULSE32,
|
|
UB_IMPULSE33,
|
|
UB_IMPULSE34,
|
|
UB_IMPULSE35,
|
|
UB_IMPULSE36,
|
|
UB_IMPULSE37,
|
|
UB_IMPULSE38,
|
|
UB_IMPULSE39,
|
|
UB_IMPULSE40,
|
|
UB_IMPULSE41,
|
|
UB_IMPULSE42,
|
|
UB_IMPULSE43,
|
|
UB_IMPULSE44,
|
|
UB_IMPULSE45,
|
|
UB_IMPULSE46,
|
|
UB_IMPULSE47,
|
|
UB_IMPULSE48,
|
|
UB_IMPULSE49,
|
|
UB_IMPULSE50,
|
|
UB_IMPULSE51,
|
|
UB_IMPULSE52,
|
|
UB_IMPULSE53,
|
|
UB_IMPULSE54,
|
|
UB_IMPULSE55,
|
|
UB_IMPULSE56,
|
|
UB_IMPULSE57,
|
|
UB_IMPULSE58,
|
|
UB_IMPULSE59,
|
|
UB_IMPULSE60,
|
|
UB_IMPULSE61,
|
|
UB_IMPULSE62,
|
|
UB_IMPULSE63,
|
|
|
|
UB_MAX_BUTTONS
|
|
} usercmdButton_t;
|
|
|
|
typedef struct {
|
|
const char *string;
|
|
usercmdButton_t button;
|
|
} userCmdString_t;
|
|
|
|
userCmdString_t userCmdStrings[] = {
|
|
{ "_moveUp", UB_UP },
|
|
{ "_moveDown", UB_DOWN },
|
|
{ "_left", UB_LEFT },
|
|
{ "_right", UB_RIGHT },
|
|
{ "_forward", UB_FORWARD },
|
|
{ "_back", UB_BACK },
|
|
{ "_lookUp", UB_LOOKUP },
|
|
{ "_lookDown", UB_LOOKDOWN },
|
|
{ "_strafe", UB_STRAFE },
|
|
{ "_moveLeft", UB_MOVELEFT },
|
|
{ "_moveRight", UB_MOVERIGHT },
|
|
|
|
{ "_attack", UB_ATTACK },
|
|
{ "_speed", UB_SPEED },
|
|
{ "_zoom", UB_ZOOM },
|
|
{ "_showScores", UB_SHOWSCORES },
|
|
{ "_mlook", UB_MLOOK },
|
|
|
|
{ "_button0", UB_BUTTON0 },
|
|
{ "_button1", UB_BUTTON1 },
|
|
{ "_button2", UB_BUTTON2 },
|
|
{ "_button3", UB_BUTTON3 },
|
|
{ "_button4", UB_BUTTON4 },
|
|
{ "_button5", UB_BUTTON5 },
|
|
{ "_button6", UB_BUTTON6 },
|
|
{ "_button7", UB_BUTTON7 },
|
|
|
|
{ "_impulse0", UB_IMPULSE0 },
|
|
{ "_impulse1", UB_IMPULSE1 },
|
|
{ "_impulse2", UB_IMPULSE2 },
|
|
{ "_impulse3", UB_IMPULSE3 },
|
|
{ "_impulse4", UB_IMPULSE4 },
|
|
{ "_impulse5", UB_IMPULSE5 },
|
|
{ "_impulse6", UB_IMPULSE6 },
|
|
{ "_impulse7", UB_IMPULSE7 },
|
|
{ "_impulse8", UB_IMPULSE8 },
|
|
{ "_impulse9", UB_IMPULSE9 },
|
|
{ "_impulse10", UB_IMPULSE10 },
|
|
{ "_impulse11", UB_IMPULSE11 },
|
|
{ "_impulse12", UB_IMPULSE12 },
|
|
{ "_impulse13", UB_IMPULSE13 },
|
|
{ "_impulse14", UB_IMPULSE14 },
|
|
{ "_impulse15", UB_IMPULSE15 },
|
|
{ "_impulse16", UB_IMPULSE16 },
|
|
{ "_impulse17", UB_IMPULSE17 },
|
|
{ "_impulse18", UB_IMPULSE18 },
|
|
{ "_impulse19", UB_IMPULSE19 },
|
|
{ "_impulse20", UB_IMPULSE20 },
|
|
{ "_impulse21", UB_IMPULSE21 },
|
|
{ "_impulse22", UB_IMPULSE22 },
|
|
{ "_impulse23", UB_IMPULSE23 },
|
|
{ "_impulse24", UB_IMPULSE24 },
|
|
{ "_impulse25", UB_IMPULSE25 },
|
|
{ "_impulse26", UB_IMPULSE26 },
|
|
{ "_impulse27", UB_IMPULSE27 },
|
|
{ "_impulse28", UB_IMPULSE28 },
|
|
{ "_impulse29", UB_IMPULSE29 },
|
|
{ "_impulse30", UB_IMPULSE30 },
|
|
{ "_impulse31", UB_IMPULSE31 },
|
|
{ "_impulse32", UB_IMPULSE32 },
|
|
{ "_impulse33", UB_IMPULSE33 },
|
|
{ "_impulse34", UB_IMPULSE34 },
|
|
{ "_impulse35", UB_IMPULSE35 },
|
|
{ "_impulse36", UB_IMPULSE36 },
|
|
{ "_impulse37", UB_IMPULSE37 },
|
|
{ "_impulse38", UB_IMPULSE38 },
|
|
{ "_impulse39", UB_IMPULSE39 },
|
|
{ "_impulse40", UB_IMPULSE40 },
|
|
{ "_impulse41", UB_IMPULSE41 },
|
|
{ "_impulse42", UB_IMPULSE42 },
|
|
{ "_impulse43", UB_IMPULSE43 },
|
|
{ "_impulse44", UB_IMPULSE44 },
|
|
{ "_impulse45", UB_IMPULSE45 },
|
|
{ "_impulse46", UB_IMPULSE46 },
|
|
{ "_impulse47", UB_IMPULSE47 },
|
|
{ "_impulse48", UB_IMPULSE48 },
|
|
{ "_impulse49", UB_IMPULSE49 },
|
|
{ "_impulse50", UB_IMPULSE50 },
|
|
{ "_impulse51", UB_IMPULSE51 },
|
|
{ "_impulse52", UB_IMPULSE52 },
|
|
{ "_impulse53", UB_IMPULSE53 },
|
|
{ "_impulse54", UB_IMPULSE54 },
|
|
{ "_impulse55", UB_IMPULSE55 },
|
|
{ "_impulse56", UB_IMPULSE56 },
|
|
{ "_impulse57", UB_IMPULSE57 },
|
|
{ "_impulse58", UB_IMPULSE58 },
|
|
{ "_impulse59", UB_IMPULSE59 },
|
|
{ "_impulse60", UB_IMPULSE60 },
|
|
{ "_impulse61", UB_IMPULSE61 },
|
|
{ "_impulse62", UB_IMPULSE62 },
|
|
{ "_impulse63", UB_IMPULSE63 },
|
|
|
|
{ NULL, UB_NONE },
|
|
};
|
|
|
|
class buttonState_t {
|
|
public:
|
|
int on;
|
|
bool held;
|
|
|
|
buttonState_t() { Clear(); };
|
|
void Clear( void );
|
|
void SetKeyState( int keystate, bool toggle );
|
|
};
|
|
|
|
/*
|
|
================
|
|
buttonState_t::Clear
|
|
================
|
|
*/
|
|
void buttonState_t::Clear( void ) {
|
|
held = false;
|
|
on = 0;
|
|
}
|
|
|
|
/*
|
|
================
|
|
buttonState_t::SetKeyState
|
|
================
|
|
*/
|
|
void buttonState_t::SetKeyState( int keystate, bool toggle ) {
|
|
if ( !toggle ) {
|
|
held = false;
|
|
on = keystate;
|
|
} else if ( !keystate ) {
|
|
held = false;
|
|
} else if ( !held ) {
|
|
held = true;
|
|
on ^= 1;
|
|
}
|
|
}
|
|
|
|
|
|
const int NUM_USER_COMMANDS = sizeof(userCmdStrings) / sizeof(userCmdString_t);
|
|
|
|
const int MAX_CHAT_BUFFER = 127;
|
|
|
|
class idUsercmdGenLocal : public idUsercmdGen {
|
|
public:
|
|
idUsercmdGenLocal( void );
|
|
|
|
void Init( void );
|
|
|
|
void InitForNewMap( void );
|
|
|
|
void Shutdown( void );
|
|
|
|
void Clear( void );
|
|
|
|
void ClearAngles( void );
|
|
|
|
usercmd_t TicCmd( int ticNumber );
|
|
|
|
void InhibitUsercmd( inhibit_t subsystem, bool inhibit );
|
|
|
|
void UsercmdInterrupt( void );
|
|
|
|
int CommandStringUsercmdData( const char *cmdString );
|
|
|
|
int GetNumUserCommands( void );
|
|
|
|
const char * GetUserCommandName( int index );
|
|
|
|
void MouseState( int *x, int *y, int *button, bool *down );
|
|
|
|
int ButtonState( int key );
|
|
int KeyState( int key );
|
|
|
|
usercmd_t GetDirectUsercmd( void );
|
|
|
|
private:
|
|
void MakeCurrent( void );
|
|
void InitCurrent( void );
|
|
|
|
bool Inhibited( void );
|
|
void AdjustAngles( void );
|
|
void KeyMove( void );
|
|
void CircleToSquare( float & axis_x, float & axis_y ) const;
|
|
void HandleJoystickAxis( int keyNum, float unclampedValue, float threshold, bool positive );
|
|
void JoystickMove( void );
|
|
void JoystickFakeMouse(float axis_x, float axis_y, float deadzone);
|
|
void MouseMove( void );
|
|
void CmdButtons( void );
|
|
|
|
void Mouse( void );
|
|
void Keyboard( void );
|
|
void Joystick( void );
|
|
|
|
void Key( int keyNum, bool down );
|
|
|
|
// DG: if in_allowAlwaysRunInSP is set, you can use always run or toggle run even in SP.
|
|
// Why not, we're all adults here, if you run out of stamina it's your problem
|
|
// (though I'll probably add another CVar to disable stamina in SP)
|
|
inline bool AlwaysRunAllowed() const
|
|
{
|
|
return in_allowAlwaysRunInSP.GetBool() || idAsyncNetwork::IsActive();
|
|
}
|
|
|
|
idVec3 viewangles;
|
|
int flags;
|
|
int impulse;
|
|
|
|
buttonState_t toggled_crouch;
|
|
buttonState_t toggled_run;
|
|
buttonState_t toggled_zoom;
|
|
|
|
int buttonState[UB_MAX_BUTTONS];
|
|
bool keyState[K_LAST_KEY];
|
|
|
|
int inhibitCommands; // true when in console or menu locally
|
|
int lastCommandTime;
|
|
|
|
bool initialized;
|
|
|
|
usercmd_t cmd; // the current cmd being built
|
|
usercmd_t buffered[MAX_BUFFERED_USERCMD];
|
|
|
|
int continuousMouseX, continuousMouseY; // for gui event generatioin, never zerod
|
|
int mouseButton; // for gui event generatioin
|
|
bool mouseDown;
|
|
|
|
int mouseDx, mouseDy; // added to by mouse events
|
|
float joystickAxis[MAX_JOYSTICK_AXIS]; // set by joystick events
|
|
|
|
int pollTime;
|
|
int lastPollTime;
|
|
float lastLookValuePitch;
|
|
float lastLookValueYaw;
|
|
|
|
bool heldJump; // TODO: ???
|
|
|
|
static idCVar in_yawSpeed;
|
|
static idCVar in_pitchSpeed;
|
|
static idCVar in_angleSpeedKey;
|
|
static idCVar in_freeLook;
|
|
static idCVar in_allowAlwaysRunInSP; // DG: I don't care, I'm not a cop
|
|
static idCVar in_alwaysRun;
|
|
static idCVar in_toggleRun;
|
|
static idCVar in_toggleCrouch;
|
|
static idCVar in_toggleZoom;
|
|
static idCVar sensitivity;
|
|
static idCVar m_pitch;
|
|
static idCVar m_yaw;
|
|
static idCVar m_strafeScale;
|
|
static idCVar m_smooth;
|
|
static idCVar m_strafeSmooth;
|
|
static idCVar m_showMouseRate;
|
|
static idCVar m_invertLook; // DG: added this
|
|
};
|
|
|
|
idCVar idUsercmdGenLocal::in_yawSpeed( "in_yawspeed", "140", CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_FLOAT, "yaw change speed when holding down _left or _right button" );
|
|
idCVar idUsercmdGenLocal::in_pitchSpeed( "in_pitchspeed", "140", CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_FLOAT, "pitch change speed when holding down look _lookUp or _lookDown button" );
|
|
idCVar idUsercmdGenLocal::in_angleSpeedKey( "in_anglespeedkey", "1.5", CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_FLOAT, "angle change scale when holding down _speed button" );
|
|
idCVar idUsercmdGenLocal::in_freeLook( "in_freeLook", "1", CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_BOOL, "look around with mouse (reverse _mlook button)" );
|
|
idCVar idUsercmdGenLocal::in_allowAlwaysRunInSP ( "in_allowAlwaysRunInSP", "0", CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_BOOL, "Allow always run and toggle run in Single Player as well - keep in mind you may run out of stamina!" );
|
|
idCVar idUsercmdGenLocal::in_alwaysRun( "in_alwaysRun", "0", CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_BOOL, "always run (reverse _speed button) - only in MP, unless in_allowAlwaysRunInSP is set" );
|
|
idCVar idUsercmdGenLocal::in_toggleRun( "in_toggleRun", "0", CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_BOOL, "pressing _speed button toggles run on/off - only in MP, unless in_allowAlwaysRunInSP is set" );
|
|
idCVar idUsercmdGenLocal::in_toggleCrouch( "in_toggleCrouch", "0", CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_BOOL, "pressing _movedown button toggles player crouching/standing" );
|
|
idCVar idUsercmdGenLocal::in_toggleZoom( "in_toggleZoom", "0", CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_BOOL, "pressing _zoom button toggles zoom on/off" );
|
|
idCVar idUsercmdGenLocal::sensitivity( "sensitivity", "5", CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_FLOAT, "mouse view sensitivity" );
|
|
idCVar idUsercmdGenLocal::m_pitch( "m_pitch", "0.022", CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_FLOAT, "mouse pitch scale" );
|
|
idCVar idUsercmdGenLocal::m_yaw( "m_yaw", "0.022", CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_FLOAT, "mouse yaw scale" );
|
|
idCVar idUsercmdGenLocal::m_strafeScale( "m_strafeScale", "6.25", CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_FLOAT, "mouse strafe movement scale" );
|
|
idCVar idUsercmdGenLocal::m_smooth( "m_smooth", "1", CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_INTEGER, "number of samples blended for mouse viewing", 1, 8, idCmdSystem::ArgCompletion_Integer<1,8> );
|
|
idCVar idUsercmdGenLocal::m_strafeSmooth( "m_strafeSmooth", "4", CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_INTEGER, "number of samples blended for mouse moving", 1, 8, idCmdSystem::ArgCompletion_Integer<1,8> );
|
|
idCVar idUsercmdGenLocal::m_showMouseRate( "m_showMouseRate", "0", CVAR_SYSTEM | CVAR_BOOL, "shows mouse movement" );
|
|
idCVar idUsercmdGenLocal::m_invertLook( "m_invertLook", "0", CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_INTEGER, "invert mouse look 0: don't invert, 1: invert up/down (flight controls), 2: invert left/right, 3: invert both", 0, 3, idCmdSystem::ArgCompletion_Integer<0,3> );
|
|
|
|
idCVar joy_triggerThreshold( "joy_triggerThreshold", "0.05", CVAR_FLOAT | CVAR_ARCHIVE, "how far the joystick triggers have to be pressed before they register as down" );
|
|
idCVar joy_deadZone( "joy_deadZone", "0.25", CVAR_FLOAT | CVAR_ARCHIVE, "specifies how large the dead-zone is on the joystick" );
|
|
idCVar joy_gammaLook( "joy_gammaLook", "1", CVAR_INTEGER | CVAR_ARCHIVE, "use a log curve instead of a power curve for movement" );
|
|
idCVar joy_powerScale( "joy_powerScale", "2", CVAR_FLOAT | CVAR_ARCHIVE, "Raise joystick values to this power" );
|
|
idCVar joy_pitchSpeed( "joy_pitchSpeed", "130", CVAR_ARCHIVE | CVAR_FLOAT, "pitch speed when pressing up or down on the joystick", 60, 600 );
|
|
idCVar joy_yawSpeed( "joy_yawSpeed", "240", CVAR_ARCHIVE | CVAR_FLOAT, "pitch speed when pressing left or right on the joystick", 60, 600 );
|
|
idCVar joy_invertLook( "joy_invertLook", "0", CVAR_ARCHIVE | CVAR_BOOL, "inverts the look controls so the forward looks up (flight controls) - the proper way to play games!" );
|
|
|
|
// these were a bad idea!
|
|
idCVar joy_dampenLook( "joy_dampenLook", "1", CVAR_BOOL | CVAR_ARCHIVE, "Do not allow full acceleration on look" );
|
|
idCVar joy_deltaPerMSLook( "joy_deltaPerMSLook", "0.003", CVAR_FLOAT | CVAR_ARCHIVE, "Max amount to be added on look per MS" );
|
|
|
|
idCVar in_useGamepad( "in_useGamepad", "1", CVAR_ARCHIVE | CVAR_BOOL, "enables/disables the gamepad for PC use" );
|
|
|
|
// TODO idCVar in_mouseInvertLook( "in_mouseInvertLook", "0", CVAR_ARCHIVE | CVAR_BOOL, "inverts the look controls so the forward looks up (flight controls) - the proper way to play games!" );
|
|
|
|
static idUsercmdGenLocal localUsercmdGen;
|
|
idUsercmdGen *usercmdGen = &localUsercmdGen;
|
|
|
|
/*
|
|
================
|
|
idUsercmdGenLocal::idUsercmdGenLocal
|
|
================
|
|
*/
|
|
idUsercmdGenLocal::idUsercmdGenLocal( void ) {
|
|
lastCommandTime = 0;
|
|
initialized = false;
|
|
|
|
flags = 0;
|
|
impulse = 0;
|
|
|
|
toggled_crouch.Clear();
|
|
toggled_run.Clear();
|
|
toggled_zoom.Clear();
|
|
toggled_run.on = in_alwaysRun.GetBool();
|
|
|
|
lastLookValuePitch = lastLookValueYaw = 0.0f;
|
|
|
|
ClearAngles();
|
|
Clear();
|
|
}
|
|
|
|
/*
|
|
================
|
|
idUsercmdGenLocal::InhibitUsercmd
|
|
================
|
|
*/
|
|
void idUsercmdGenLocal::InhibitUsercmd( inhibit_t subsystem, bool inhibit ) {
|
|
if ( inhibit ) {
|
|
inhibitCommands |= 1 << subsystem;
|
|
} else {
|
|
inhibitCommands &= ( 0xffffffff ^ ( 1 << subsystem ) );
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============
|
|
idUsercmdGenLocal::ButtonState
|
|
|
|
Returns (the fraction of the frame) that the key was down
|
|
===============
|
|
*/
|
|
int idUsercmdGenLocal::ButtonState( int key ) {
|
|
if ( key<0 || key>=UB_MAX_BUTTONS ) {
|
|
return -1;
|
|
}
|
|
return ( buttonState[key] > 0 ) ? 1 : 0;
|
|
}
|
|
|
|
/*
|
|
===============
|
|
idUsercmdGenLocal::KeyState
|
|
|
|
Returns (the fraction of the frame) that the key was down
|
|
bk20060111
|
|
===============
|
|
*/
|
|
int idUsercmdGenLocal::KeyState( int key ) {
|
|
if ( key<0 || key>=K_LAST_KEY ) {
|
|
return -1;
|
|
}
|
|
return ( keyState[key] ) ? 1 : 0;
|
|
}
|
|
|
|
|
|
//=====================================================================
|
|
|
|
|
|
/*
|
|
================
|
|
idUsercmdGenLocal::GetNumUserCommands
|
|
================
|
|
*/
|
|
int idUsercmdGenLocal::GetNumUserCommands( void ) {
|
|
return NUM_USER_COMMANDS;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idUsercmdGenLocal::GetNumUserCommands
|
|
================
|
|
*/
|
|
const char *idUsercmdGenLocal::GetUserCommandName( int index ) {
|
|
if (index >= 0 && index < NUM_USER_COMMANDS) {
|
|
return userCmdStrings[index].string;
|
|
}
|
|
return "";
|
|
}
|
|
|
|
/*
|
|
================
|
|
idUsercmdGenLocal::Inhibited
|
|
|
|
is user cmd generation inhibited
|
|
================
|
|
*/
|
|
bool idUsercmdGenLocal::Inhibited( void ) {
|
|
return ( inhibitCommands != 0);
|
|
}
|
|
|
|
/*
|
|
================
|
|
idUsercmdGenLocal::AdjustAngles
|
|
|
|
Moves the local angle positions
|
|
================
|
|
*/
|
|
void idUsercmdGenLocal::AdjustAngles( void ) {
|
|
float speed;
|
|
|
|
if ( toggled_run.on ^ ( in_alwaysRun.GetBool() && AlwaysRunAllowed() ) ) { // DG: always run in SP
|
|
speed = idMath::M_MS2SEC * USERCMD_MSEC * in_angleSpeedKey.GetFloat();
|
|
} else {
|
|
speed = idMath::M_MS2SEC * USERCMD_MSEC;
|
|
}
|
|
|
|
if ( !ButtonState( UB_STRAFE ) ) {
|
|
viewangles[YAW] -= speed * in_yawSpeed.GetFloat() * ButtonState( UB_RIGHT );
|
|
viewangles[YAW] += speed * in_yawSpeed.GetFloat() * ButtonState( UB_LEFT );
|
|
}
|
|
|
|
viewangles[PITCH] -= speed * in_pitchSpeed.GetFloat() * ButtonState( UB_LOOKUP );
|
|
viewangles[PITCH] += speed * in_pitchSpeed.GetFloat() * ButtonState( UB_LOOKDOWN );
|
|
}
|
|
|
|
/*
|
|
================
|
|
idUsercmdGenLocal::KeyMove
|
|
|
|
Sets the usercmd_t based on key states
|
|
================
|
|
*/
|
|
void idUsercmdGenLocal::KeyMove( void ) {
|
|
int forward, side, up;
|
|
|
|
forward = 0;
|
|
side = 0;
|
|
up = 0;
|
|
if ( ButtonState( UB_STRAFE ) ) {
|
|
side += KEY_MOVESPEED * ButtonState( UB_RIGHT );
|
|
side -= KEY_MOVESPEED * ButtonState( UB_LEFT );
|
|
}
|
|
|
|
side += KEY_MOVESPEED * ButtonState( UB_MOVERIGHT );
|
|
side -= KEY_MOVESPEED * ButtonState( UB_MOVELEFT );
|
|
|
|
up -= KEY_MOVESPEED * toggled_crouch.on;
|
|
up += KEY_MOVESPEED * ButtonState( UB_UP );
|
|
|
|
forward += KEY_MOVESPEED * ButtonState( UB_FORWARD );
|
|
forward -= KEY_MOVESPEED * ButtonState( UB_BACK );
|
|
|
|
// only set each movement variable if its unset at this point.
|
|
// NOTE: joystick input happens before this.
|
|
if (cmd.forwardmove == 0) {
|
|
cmd.forwardmove = idMath::ClampChar( forward );
|
|
}
|
|
if (cmd.rightmove == 0) {
|
|
cmd.rightmove = idMath::ClampChar( side );
|
|
}
|
|
if (cmd.upmove == 0) {
|
|
cmd.upmove = idMath::ClampChar( up );
|
|
}
|
|
}
|
|
|
|
/*
|
|
=================
|
|
idUsercmdGenLocal::MouseMove
|
|
=================
|
|
*/
|
|
void idUsercmdGenLocal::MouseMove( void ) {
|
|
float mx, my, strafeMx, strafeMy;
|
|
static int history[8][2];
|
|
static int historyCounter;
|
|
int i;
|
|
|
|
history[historyCounter&7][0] = mouseDx;
|
|
history[historyCounter&7][1] = mouseDy;
|
|
|
|
// allow mouse movement to be smoothed together
|
|
int smooth = m_smooth.GetInteger();
|
|
if ( smooth < 1 ) {
|
|
smooth = 1;
|
|
}
|
|
if ( smooth > 8 ) {
|
|
smooth = 8;
|
|
}
|
|
mx = 0;
|
|
my = 0;
|
|
for ( i = 0 ; i < smooth ; i++ ) {
|
|
mx += history[ ( historyCounter - i + 8 ) & 7 ][0];
|
|
my += history[ ( historyCounter - i + 8 ) & 7 ][1];
|
|
}
|
|
mx /= smooth;
|
|
my /= smooth;
|
|
|
|
// use a larger smoothing for strafing
|
|
smooth = m_strafeSmooth.GetInteger();
|
|
if ( smooth < 1 ) {
|
|
smooth = 1;
|
|
}
|
|
if ( smooth > 8 ) {
|
|
smooth = 8;
|
|
}
|
|
strafeMx = 0;
|
|
strafeMy = 0;
|
|
for ( i = 0 ; i < smooth ; i++ ) {
|
|
strafeMx += history[ ( historyCounter - i + 8 ) & 7 ][0];
|
|
strafeMy += history[ ( historyCounter - i + 8 ) & 7 ][1];
|
|
}
|
|
strafeMx /= smooth;
|
|
strafeMy /= smooth;
|
|
|
|
historyCounter++;
|
|
|
|
if ( idMath::Fabs( mx ) > 1000 || idMath::Fabs( my ) > 1000 ) {
|
|
Sys_DebugPrintf( "idUsercmdGenLocal::MouseMove: Ignoring ridiculous mouse delta.\n" );
|
|
mx = my = 0;
|
|
}
|
|
|
|
mx *= sensitivity.GetFloat();
|
|
my *= sensitivity.GetFloat();
|
|
|
|
if ( m_showMouseRate.GetBool() ) {
|
|
Sys_DebugPrintf( "[%3i %3i = %5.1f %5.1f = %5.1f %5.1f] ", mouseDx, mouseDy, mx, my, strafeMx, strafeMy );
|
|
}
|
|
|
|
mouseDx = 0;
|
|
mouseDy = 0;
|
|
|
|
if ( !strafeMx && !strafeMy ) {
|
|
return;
|
|
}
|
|
|
|
if ( ButtonState( UB_STRAFE ) || !( cmd.buttons & BUTTON_MLOOK ) ) {
|
|
// add mouse X/Y movement to cmd
|
|
strafeMx *= m_strafeScale.GetFloat();
|
|
strafeMy *= m_strafeScale.GetFloat();
|
|
// clamp as a vector, instead of separate floats
|
|
float len = sqrt( strafeMx * strafeMx + strafeMy * strafeMy );
|
|
if ( len > 127 ) {
|
|
strafeMx = strafeMx * 127 / len;
|
|
strafeMy = strafeMy * 127 / len;
|
|
}
|
|
}
|
|
|
|
if ( !ButtonState( UB_STRAFE ) ) {
|
|
// m_invertLook 2 and 3 invert looking left/right
|
|
float invYaw = ( m_invertLook.GetInteger() & 2 ) ? -1.0f : 1.0f;
|
|
viewangles[YAW] -= m_yaw.GetFloat() * mx * invYaw;
|
|
} else {
|
|
cmd.rightmove = idMath::ClampChar( (int)(cmd.rightmove + strafeMx) );
|
|
}
|
|
|
|
if ( !ButtonState( UB_STRAFE ) && ( cmd.buttons & BUTTON_MLOOK ) ) {
|
|
// m_invertLook 1 and 3 invert looking up/down
|
|
float invPitch = ( m_invertLook.GetInteger() & 1 ) ? -1.0f : 1.0f;
|
|
viewangles[PITCH] += m_pitch.GetFloat() * my * invPitch;
|
|
} else {
|
|
cmd.forwardmove = idMath::ClampChar( (int)(cmd.forwardmove - strafeMy) );
|
|
}
|
|
}
|
|
|
|
/*
|
|
========================
|
|
idUsercmdGenLocal::CircleToSquare
|
|
========================
|
|
*/
|
|
void idUsercmdGenLocal::CircleToSquare( float & axis_x, float & axis_y ) const {
|
|
// bring everything in the first quadrant
|
|
bool flip_x = false;
|
|
if ( axis_x < 0.0f ) {
|
|
flip_x = true;
|
|
axis_x *= -1.0f;
|
|
}
|
|
bool flip_y = false;
|
|
if ( axis_y < 0.0f ) {
|
|
flip_y = true;
|
|
axis_y *= -1.0f;
|
|
}
|
|
|
|
// swap the two axes so we project against the vertical line X = 1
|
|
bool swap = false;
|
|
if ( axis_y > axis_x ) {
|
|
float tmp = axis_x;
|
|
axis_x = axis_y;
|
|
axis_y = tmp;
|
|
swap = true;
|
|
}
|
|
|
|
if ( axis_x < 0.001f ) {
|
|
// on one of the axes where no correction is needed
|
|
return;
|
|
}
|
|
|
|
// length (max 1.0f at the unit circle)
|
|
float len = idMath::Sqrt( axis_x * axis_x + axis_y * axis_y );
|
|
if ( len > 1.0f ) {
|
|
len = 1.0f;
|
|
}
|
|
// thales
|
|
float axis_y_us = axis_y / axis_x;
|
|
|
|
// use a power curve to shift the correction to happen closer to the unit circle
|
|
float correctionRatio = Square( len );
|
|
axis_x += correctionRatio * ( len - axis_x );
|
|
axis_y += correctionRatio * ( axis_y_us - axis_y );
|
|
|
|
// go back through the symmetries
|
|
if ( swap ) {
|
|
float tmp = axis_x;
|
|
axis_x = axis_y;
|
|
axis_y = tmp;
|
|
}
|
|
if ( flip_x ) {
|
|
axis_x *= -1.0f;
|
|
}
|
|
if ( flip_y ) {
|
|
axis_y *= -1.0f;
|
|
}
|
|
}
|
|
|
|
/*
|
|
========================
|
|
idUsercmdGenLocal::HandleJoystickAxis
|
|
========================
|
|
*/
|
|
void idUsercmdGenLocal::HandleJoystickAxis( int keyNum, float unclampedValue, float threshold, bool positive ) {
|
|
if ( ( unclampedValue > 0.0f ) && !positive ) {
|
|
return;
|
|
}
|
|
if ( ( unclampedValue < 0.0f ) && positive ) {
|
|
return;
|
|
}
|
|
float value = 0.0f;
|
|
bool pressed = false;
|
|
if ( unclampedValue > threshold ) {
|
|
value = idMath::Fabs( ( unclampedValue - threshold ) / ( 1.0f - threshold ) );
|
|
pressed = true;
|
|
} else if ( unclampedValue < -threshold ) {
|
|
value = idMath::Fabs( ( unclampedValue + threshold ) / ( 1.0f - threshold ) );
|
|
pressed = true;
|
|
}
|
|
|
|
int action = idKeyInput::GetUsercmdAction( keyNum );
|
|
if ( action >= UB_ATTACK ) {
|
|
Key( keyNum, pressed );
|
|
return;
|
|
}
|
|
if ( !pressed ) {
|
|
return;
|
|
}
|
|
|
|
float lookValue = 0.0f;
|
|
if ( joy_gammaLook.GetBool() ) {
|
|
lookValue = idMath::Pow( 1.04712854805f, value * 100.0f ) * 0.01f;
|
|
} else {
|
|
lookValue = idMath::Pow( value, joy_powerScale.GetFloat() );
|
|
}
|
|
|
|
#if 0 // TODO: aim assist maybe.
|
|
idGame * game = common->Game();
|
|
if ( game != NULL ) {
|
|
lookValue *= game->GetAimAssistSensitivity();
|
|
}
|
|
#endif
|
|
|
|
switch ( action ) {
|
|
case UB_FORWARD: {
|
|
float move = (float)cmd.forwardmove + ( KEY_MOVESPEED * value );
|
|
cmd.forwardmove = idMath::ClampChar( idMath::Ftoi( move ) );
|
|
break;
|
|
}
|
|
case UB_BACK: {
|
|
float move = (float)cmd.forwardmove - ( KEY_MOVESPEED * value );
|
|
cmd.forwardmove = idMath::ClampChar( idMath::Ftoi( move ) );
|
|
break;
|
|
}
|
|
case UB_MOVELEFT: {
|
|
float move = (float)cmd.rightmove - ( KEY_MOVESPEED * value );
|
|
cmd.rightmove = idMath::ClampChar( idMath::Ftoi( move ) );
|
|
break;
|
|
}
|
|
case UB_MOVERIGHT: {
|
|
float move = (float)cmd.rightmove + ( KEY_MOVESPEED * value );
|
|
cmd.rightmove = idMath::ClampChar( idMath::Ftoi( move ) );
|
|
break;
|
|
}
|
|
case UB_LOOKUP: {
|
|
if ( joy_dampenLook.GetBool() ) {
|
|
lookValue = Min( lookValue, ( pollTime - lastPollTime ) * joy_deltaPerMSLook.GetFloat() + lastLookValuePitch );
|
|
lastLookValuePitch = lookValue;
|
|
}
|
|
|
|
float invertPitch = joy_invertLook.GetBool() ? -1.0f : 1.0f;
|
|
viewangles[PITCH] -= MS2SEC( pollTime - lastPollTime ) * lookValue * joy_pitchSpeed.GetFloat() * invertPitch;
|
|
break;
|
|
}
|
|
case UB_LOOKDOWN: {
|
|
if ( joy_dampenLook.GetBool() ) {
|
|
lookValue = Min( lookValue, ( pollTime - lastPollTime ) * joy_deltaPerMSLook.GetFloat() + lastLookValuePitch );
|
|
lastLookValuePitch = lookValue;
|
|
}
|
|
|
|
float invertPitch = joy_invertLook.GetBool() ? -1.0f : 1.0f;
|
|
viewangles[PITCH] += MS2SEC( pollTime - lastPollTime ) * lookValue * joy_pitchSpeed.GetFloat() * invertPitch;
|
|
break;
|
|
}
|
|
case UB_LEFT: {
|
|
if ( joy_dampenLook.GetBool() ) {
|
|
lookValue = Min( lookValue, ( pollTime - lastPollTime ) * joy_deltaPerMSLook.GetFloat() + lastLookValueYaw );
|
|
lastLookValueYaw = lookValue;
|
|
}
|
|
viewangles[YAW] += MS2SEC( pollTime - lastPollTime ) * lookValue * joy_yawSpeed.GetFloat();
|
|
break;
|
|
}
|
|
case UB_RIGHT: {
|
|
if ( joy_dampenLook.GetBool() ) {
|
|
lookValue = Min( lookValue, ( pollTime - lastPollTime ) * joy_deltaPerMSLook.GetFloat() + lastLookValueYaw );
|
|
lastLookValueYaw = lookValue;
|
|
}
|
|
viewangles[YAW] -= MS2SEC( pollTime - lastPollTime ) * lookValue * joy_yawSpeed.GetFloat();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static float joyAxisToMouseDelta(float axis, float deadzone)
|
|
{
|
|
float ret = 0.0f;
|
|
float val = fabsf(axis); // calculations below require a positive value
|
|
if(val > deadzone) {
|
|
// from deadzone .. 1 to 0 .. 1-deadzone
|
|
val -= deadzone;
|
|
// and then to 0..1
|
|
val = val * (1.0f / (1.0f - deadzone));
|
|
|
|
// make it exponential curve - exp(val*3) should return sth between 1 and 20;
|
|
// then turning that into 0.5 .. 10
|
|
ret = expf( val * 3.0f ) * 0.5f;
|
|
if(axis < 0.0f) // restore sign
|
|
ret = -ret;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
extern bool D3_IN_interactiveIngameGuiActive; // from sys/events.cpp
|
|
void idUsercmdGenLocal::JoystickFakeMouse(float axis_x, float axis_y, float deadzone)
|
|
{
|
|
if ( D3_IN_interactiveIngameGuiActive ) {
|
|
float x = joyAxisToMouseDelta(axis_x, deadzone);
|
|
float y = joyAxisToMouseDelta(axis_y, deadzone);
|
|
continuousMouseX += x;
|
|
continuousMouseY += y;
|
|
}
|
|
}
|
|
|
|
/*
|
|
=================
|
|
idUsercmdGenLocal::JoystickMove
|
|
=================
|
|
*/
|
|
void idUsercmdGenLocal::JoystickMove() {
|
|
float threshold = joy_deadZone.GetFloat();
|
|
float triggerThreshold = joy_triggerThreshold.GetFloat();
|
|
|
|
float axis_y = joystickAxis[ AXIS_LEFT_Y ];
|
|
float axis_x = joystickAxis[ AXIS_LEFT_X ];
|
|
CircleToSquare( axis_x, axis_y );
|
|
|
|
HandleJoystickAxis( K_JOY_STICK1_UP, axis_y, threshold, false );
|
|
HandleJoystickAxis( K_JOY_STICK1_DOWN, axis_y, threshold, true );
|
|
HandleJoystickAxis( K_JOY_STICK1_LEFT, axis_x, threshold, false );
|
|
HandleJoystickAxis( K_JOY_STICK1_RIGHT, axis_x, threshold, true );
|
|
|
|
JoystickFakeMouse( axis_x, axis_y, threshold );
|
|
|
|
axis_y = joystickAxis[ AXIS_RIGHT_Y ];
|
|
axis_x = joystickAxis[ AXIS_RIGHT_X ];
|
|
CircleToSquare( axis_x, axis_y );
|
|
|
|
HandleJoystickAxis( K_JOY_STICK2_UP, axis_y, threshold, false );
|
|
HandleJoystickAxis( K_JOY_STICK2_DOWN, axis_y, threshold, true );
|
|
HandleJoystickAxis( K_JOY_STICK2_LEFT, axis_x, threshold, false );
|
|
HandleJoystickAxis( K_JOY_STICK2_RIGHT, axis_x, threshold, true );
|
|
|
|
JoystickFakeMouse( axis_x, axis_y, threshold );
|
|
|
|
HandleJoystickAxis( K_JOY_TRIGGER1, joystickAxis[ AXIS_LEFT_TRIG ], triggerThreshold, true );
|
|
HandleJoystickAxis( K_JOY_TRIGGER2, joystickAxis[ AXIS_RIGHT_TRIG ], triggerThreshold, true );
|
|
}
|
|
|
|
/*
|
|
==============
|
|
idUsercmdGenLocal::CmdButtons
|
|
==============
|
|
*/
|
|
void idUsercmdGenLocal::CmdButtons( void ) {
|
|
int i;
|
|
|
|
cmd.buttons = 0;
|
|
|
|
// figure button bits
|
|
for (i = 0 ; i <= 7 ; i++) {
|
|
if ( ButtonState( (usercmdButton_t)( UB_BUTTON0 + i ) ) ) {
|
|
cmd.buttons |= 1 << i;
|
|
}
|
|
}
|
|
|
|
// check the attack button
|
|
if ( ButtonState( UB_ATTACK ) ) {
|
|
cmd.buttons |= BUTTON_ATTACK;
|
|
}
|
|
|
|
// check the run button
|
|
if ( toggled_run.on ^ ( in_alwaysRun.GetBool() && AlwaysRunAllowed() ) ) { // DG: always run in SP
|
|
cmd.buttons |= BUTTON_RUN;
|
|
}
|
|
|
|
// check the zoom button
|
|
if ( toggled_zoom.on ) {
|
|
cmd.buttons |= BUTTON_ZOOM;
|
|
}
|
|
|
|
// check the scoreboard button
|
|
if ( ButtonState( UB_SHOWSCORES ) || ButtonState( UB_IMPULSE19 ) ) {
|
|
// the button is toggled in SP mode as well but without effect
|
|
cmd.buttons |= BUTTON_SCORES;
|
|
}
|
|
|
|
// check the mouse look button
|
|
if ( ButtonState( UB_MLOOK ) ^ in_freeLook.GetInteger() ) {
|
|
cmd.buttons |= BUTTON_MLOOK;
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
idUsercmdGenLocal::InitCurrent
|
|
|
|
inits the current command for this frame
|
|
================
|
|
*/
|
|
void idUsercmdGenLocal::InitCurrent( void ) {
|
|
memset( &cmd, 0, sizeof( cmd ) );
|
|
cmd.flags = flags;
|
|
cmd.impulse = impulse;
|
|
cmd.buttons |= ( in_alwaysRun.GetBool() && AlwaysRunAllowed() ) ? BUTTON_RUN : 0; // DG: always run in SP
|
|
cmd.buttons |= in_freeLook.GetBool() ? BUTTON_MLOOK : 0;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idUsercmdGenLocal::MakeCurrent
|
|
|
|
creates the current command for this frame
|
|
================
|
|
*/
|
|
void idUsercmdGenLocal::MakeCurrent( void ) {
|
|
idVec3 oldAngles;
|
|
int i;
|
|
|
|
oldAngles = viewangles;
|
|
|
|
if ( !Inhibited() ) {
|
|
// update toggled key states
|
|
toggled_crouch.SetKeyState( ButtonState( UB_DOWN ), in_toggleCrouch.GetBool() );
|
|
// DG: allow toggle run in SP (of in_allowAlwaysRun is set)
|
|
toggled_run.SetKeyState( ButtonState( UB_SPEED ), in_toggleRun.GetBool() && AlwaysRunAllowed() );
|
|
toggled_zoom.SetKeyState( ButtonState( UB_ZOOM ), in_toggleZoom.GetBool() );
|
|
|
|
// keyboard angle adjustment
|
|
AdjustAngles();
|
|
|
|
// get basic movement from joystick
|
|
JoystickMove();
|
|
|
|
// set button bits
|
|
CmdButtons();
|
|
|
|
// get basic movement from keyboard
|
|
KeyMove();
|
|
|
|
// get basic movement from mouse
|
|
MouseMove();
|
|
|
|
// check to make sure the angles haven't wrapped
|
|
if ( viewangles[PITCH] - oldAngles[PITCH] > 90 ) {
|
|
viewangles[PITCH] = oldAngles[PITCH] + 90;
|
|
} else if ( oldAngles[PITCH] - viewangles[PITCH] > 90 ) {
|
|
viewangles[PITCH] = oldAngles[PITCH] - 90;
|
|
}
|
|
} else {
|
|
mouseDx = 0;
|
|
mouseDy = 0;
|
|
}
|
|
|
|
for ( i = 0; i < 3; i++ ) {
|
|
cmd.angles[i] = ANGLE2SHORT( viewangles[i] );
|
|
}
|
|
|
|
cmd.mx = continuousMouseX;
|
|
cmd.my = continuousMouseY;
|
|
|
|
flags = cmd.flags;
|
|
impulse = cmd.impulse;
|
|
|
|
}
|
|
|
|
//=====================================================================
|
|
|
|
|
|
/*
|
|
================
|
|
idUsercmdGenLocal::CommandStringUsercmdData
|
|
|
|
Returns the button if the command string is used by the async usercmd generator.
|
|
================
|
|
*/
|
|
int idUsercmdGenLocal::CommandStringUsercmdData( const char *cmdString ) {
|
|
for ( userCmdString_t *ucs = userCmdStrings ; ucs->string ; ucs++ ) {
|
|
if ( idStr::Icmp( cmdString, ucs->string ) == 0 ) {
|
|
return ucs->button;
|
|
}
|
|
}
|
|
return UB_NONE;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idUsercmdGenLocal::Init
|
|
================
|
|
*/
|
|
void idUsercmdGenLocal::Init( void ) {
|
|
initialized = true;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idUsercmdGenLocal::InitForNewMap
|
|
================
|
|
*/
|
|
void idUsercmdGenLocal::InitForNewMap( void ) {
|
|
flags = 0;
|
|
impulse = 0;
|
|
|
|
toggled_crouch.Clear();
|
|
toggled_run.Clear();
|
|
toggled_zoom.Clear();
|
|
toggled_run.on = in_alwaysRun.GetBool();
|
|
|
|
Clear();
|
|
ClearAngles();
|
|
}
|
|
|
|
/*
|
|
================
|
|
idUsercmdGenLocal::Shutdown
|
|
================
|
|
*/
|
|
void idUsercmdGenLocal::Shutdown( void ) {
|
|
initialized = false;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idUsercmdGenLocal::Clear
|
|
================
|
|
*/
|
|
void idUsercmdGenLocal::Clear( void ) {
|
|
// clears all key states
|
|
memset( buttonState, 0, sizeof( buttonState ) );
|
|
memset( keyState, false, sizeof( keyState ) );
|
|
memset( joystickAxis, 0, sizeof( joystickAxis ) );
|
|
|
|
inhibitCommands = false;
|
|
|
|
mouseDx = mouseDy = 0;
|
|
mouseButton = 0;
|
|
mouseDown = false;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idUsercmdGenLocal::ClearAngles
|
|
================
|
|
*/
|
|
void idUsercmdGenLocal::ClearAngles( void ) {
|
|
viewangles.Zero();
|
|
}
|
|
|
|
/*
|
|
================
|
|
idUsercmdGenLocal::TicCmd
|
|
|
|
Returns a buffered usercmd
|
|
================
|
|
*/
|
|
usercmd_t idUsercmdGenLocal::TicCmd( int ticNumber ) {
|
|
|
|
// the packetClient code can legally ask for com_ticNumber+1, because
|
|
// it is in the async code and com_ticNumber hasn't been updated yet,
|
|
// but all other code should never ask for anything > com_ticNumber
|
|
if ( ticNumber > com_ticNumber+1 ) {
|
|
common->Error( "idUsercmdGenLocal::TicCmd ticNumber > com_ticNumber" );
|
|
}
|
|
|
|
if ( ticNumber <= com_ticNumber - MAX_BUFFERED_USERCMD ) {
|
|
// this can happen when something in the game code hitches badly, allowing the
|
|
// async code to overflow the buffers
|
|
//common->Printf( "warning: idUsercmdGenLocal::TicCmd ticNumber <= com_ticNumber - MAX_BUFFERED_USERCMD\n" );
|
|
}
|
|
|
|
return buffered[ ticNumber & (MAX_BUFFERED_USERCMD-1) ];
|
|
}
|
|
|
|
//======================================================================
|
|
|
|
|
|
/*
|
|
===================
|
|
idUsercmdGenLocal::Key
|
|
|
|
Handles async mouse/keyboard button actions
|
|
===================
|
|
*/
|
|
void idUsercmdGenLocal::Key( int keyNum, bool down ) {
|
|
|
|
// Sanity check, sometimes we get double message :(
|
|
if ( keyState[ keyNum ] == down ) {
|
|
return;
|
|
}
|
|
keyState[ keyNum ] = down;
|
|
|
|
int action = idKeyInput::GetUsercmdAction( keyNum );
|
|
|
|
// TODO: if action == 0 return ?
|
|
|
|
if ( down ) {
|
|
|
|
buttonState[ action ]++;
|
|
|
|
if ( !Inhibited() ) {
|
|
if ( action >= UB_IMPULSE0 && action <= UB_IMPULSE61 ) {
|
|
cmd.impulse = action - UB_IMPULSE0;
|
|
cmd.flags ^= UCF_IMPULSE_SEQUENCE;
|
|
}
|
|
}
|
|
} else {
|
|
buttonState[ action ]--;
|
|
// we might have one held down across an app active transition
|
|
if ( buttonState[ action ] < 0 ) {
|
|
buttonState[ action ] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
===================
|
|
idUsercmdGenLocal::Mouse
|
|
===================
|
|
*/
|
|
void idUsercmdGenLocal::Mouse( void ) {
|
|
int i, numEvents;
|
|
|
|
numEvents = Sys_PollMouseInputEvents();
|
|
|
|
if ( numEvents ) {
|
|
//
|
|
// Study each of the buffer elements and process them.
|
|
//
|
|
for( i = 0; i < numEvents; i++ ) {
|
|
int action, value;
|
|
if ( Sys_ReturnMouseInputEvent( i, action, value ) ) {
|
|
if ( action >= M_ACTION1 && action <= M_ACTION8 ) {
|
|
mouseButton = K_MOUSE1 + ( action - M_ACTION1 );
|
|
mouseDown = ( value != 0 );
|
|
Key( mouseButton, mouseDown );
|
|
} else {
|
|
switch ( action ) {
|
|
case M_DELTAX:
|
|
mouseDx += value;
|
|
continuousMouseX += value;
|
|
break;
|
|
case M_DELTAY:
|
|
mouseDy += value;
|
|
continuousMouseY += value;
|
|
break;
|
|
case M_DELTAZ:
|
|
int key = value < 0 ? K_MWHEELDOWN : K_MWHEELUP;
|
|
value = abs( value );
|
|
while( value-- > 0 ) {
|
|
Key( key, true );
|
|
Key( key, false );
|
|
mouseButton = key;
|
|
mouseDown = true;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Sys_EndMouseInputEvents();
|
|
}
|
|
|
|
/*
|
|
===============
|
|
idUsercmdGenLocal::Keyboard
|
|
===============
|
|
*/
|
|
void idUsercmdGenLocal::Keyboard( void ) {
|
|
|
|
int numEvents = Sys_PollKeyboardInputEvents();
|
|
|
|
if ( numEvents ) {
|
|
//
|
|
// Study each of the buffer elements and process them.
|
|
//
|
|
int key;
|
|
bool state;
|
|
for( int i = 0; i < numEvents; i++ ) {
|
|
if (Sys_ReturnKeyboardInputEvent( i, key, state )) {
|
|
Key ( key, state );
|
|
}
|
|
}
|
|
}
|
|
|
|
Sys_EndKeyboardInputEvents();
|
|
}
|
|
|
|
/*
|
|
===============
|
|
idUsercmdGenLocal::Joystick
|
|
===============
|
|
*/
|
|
void idUsercmdGenLocal::Joystick( void ) {
|
|
int numEvents = Sys_PollJoystickInputEvents( 0 );
|
|
|
|
// Study each of the buffer elements and process them.
|
|
for ( int i = 0; i < numEvents; i++ ) {
|
|
int action;
|
|
int value;
|
|
if ( Sys_ReturnJoystickInputEvent( i, action, value ) ) {
|
|
if ( action >= J_ACTION_FIRST && action <= J_ACTION_MAX ) {
|
|
int joyButton = K_FIRST_JOY + ( action - J_ACTION_FIRST );
|
|
Key( joyButton, ( value != 0 ) );
|
|
} else if ( ( action >= J_AXIS_MIN ) && ( action <= J_AXIS_MAX ) ) {
|
|
joystickAxis[ action - J_AXIS_MIN ] = static_cast<float>( value ) / 32767.0f;
|
|
} else {
|
|
//assert( !"Unknown joystick event" );
|
|
}
|
|
}
|
|
}
|
|
|
|
Sys_EndJoystickInputEvents();
|
|
}
|
|
|
|
/*
|
|
================
|
|
idUsercmdGenLocal::UsercmdInterrupt
|
|
|
|
Called asyncronously
|
|
================
|
|
*/
|
|
void idUsercmdGenLocal::UsercmdInterrupt( void ) {
|
|
// dedicated servers won't create usercmds
|
|
if ( !initialized ) {
|
|
return;
|
|
}
|
|
|
|
// init the usercmd for com_ticNumber+1
|
|
InitCurrent();
|
|
|
|
// process the system mouse events
|
|
Mouse();
|
|
|
|
// process the system keyboard events
|
|
Keyboard();
|
|
|
|
// process the system joystick events
|
|
if ( in_useGamepad.GetBool() ) {
|
|
Joystick();
|
|
}
|
|
|
|
// create the usercmd for com_ticNumber+1
|
|
MakeCurrent();
|
|
|
|
// save a number for debugging cmdDemos and networking
|
|
cmd.sequence = com_ticNumber+1;
|
|
|
|
buffered[(com_ticNumber+1) & (MAX_BUFFERED_USERCMD-1)] = cmd;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idUsercmdGenLocal::MouseState
|
|
================
|
|
*/
|
|
void idUsercmdGenLocal::MouseState( int *x, int *y, int *button, bool *down ) {
|
|
*x = continuousMouseX;
|
|
*y = continuousMouseY;
|
|
*button = mouseButton;
|
|
*down = mouseDown;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idUsercmdGenLocal::GetDirectUsercmd
|
|
================
|
|
*/
|
|
usercmd_t idUsercmdGenLocal::GetDirectUsercmd( void ) {
|
|
|
|
pollTime = Sys_Milliseconds();
|
|
if ( pollTime - lastPollTime > 100 ) {
|
|
lastPollTime = pollTime - 100;
|
|
}
|
|
|
|
// initialize current usercmd
|
|
InitCurrent();
|
|
|
|
// process the system mouse events
|
|
Mouse();
|
|
|
|
// process the system keyboard events
|
|
Keyboard();
|
|
|
|
// process the system joystick events
|
|
if ( in_useGamepad.GetBool() ) {
|
|
Joystick();
|
|
}
|
|
// create the usercmd
|
|
MakeCurrent();
|
|
|
|
cmd.duplicateCount = 0;
|
|
|
|
lastPollTime = pollTime;
|
|
|
|
return cmd;
|
|
}
|