mirror of
https://github.com/dhewm/dhewm3.git
synced 2024-11-27 06:32:27 +00:00
736ec20d4d
Don't include the lazy precompiled.h everywhere, only what's required for the compilation unit. platform.h needs to be included instead to provide all essential defines and types. All includes use the relative path to the neo or the game specific root. Move all idlib related includes from idlib/Lib.h to precompiled.h. precompiled.h still exists for the MFC stuff in tools/. Add some missing header guards.
1116 lines
27 KiB
C++
1116 lines
27 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 = LittleLong( 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,
|
|
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 JoystickMove( void );
|
|
void MouseMove( void );
|
|
void CmdButtons( void );
|
|
|
|
void Mouse( void );
|
|
void Keyboard( void );
|
|
void Joystick( void );
|
|
|
|
void Key( int keyNum, bool down );
|
|
|
|
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
|
|
int joystickAxis[MAX_JOYSTICK_AXIS]; // set by joystick events
|
|
|
|
static idCVar in_yawSpeed;
|
|
static idCVar in_pitchSpeed;
|
|
static idCVar in_angleSpeedKey;
|
|
static idCVar in_freeLook;
|
|
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;
|
|
};
|
|
|
|
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_alwaysRun( "in_alwaysRun", "0", CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_BOOL, "always run (reverse _speed button) - only in MP" );
|
|
idCVar idUsercmdGenLocal::in_toggleRun( "in_toggleRun", "0", CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_BOOL, "pressing _speed button toggles run on/off - only in MP" );
|
|
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" );
|
|
|
|
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();
|
|
|
|
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() && idAsyncNetwork::IsActive() ) ) {
|
|
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 );
|
|
|
|
cmd.forwardmove = idMath::ClampChar( forward );
|
|
cmd.rightmove = idMath::ClampChar( side );
|
|
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 ) ) {
|
|
viewangles[YAW] -= m_yaw.GetFloat() * mx;
|
|
} else {
|
|
cmd.rightmove = idMath::ClampChar( (int)(cmd.rightmove + strafeMx) );
|
|
}
|
|
|
|
if ( !ButtonState( UB_STRAFE ) && ( cmd.buttons & BUTTON_MLOOK ) ) {
|
|
viewangles[PITCH] += m_pitch.GetFloat() * my;
|
|
} else {
|
|
cmd.forwardmove = idMath::ClampChar( (int)(cmd.forwardmove - strafeMy) );
|
|
}
|
|
}
|
|
|
|
/*
|
|
=================
|
|
idUsercmdGenLocal::JoystickMove
|
|
=================
|
|
*/
|
|
void idUsercmdGenLocal::JoystickMove( void ) {
|
|
float anglespeed;
|
|
|
|
if ( toggled_run.on ^ ( in_alwaysRun.GetBool() && idAsyncNetwork::IsActive() ) ) {
|
|
anglespeed = idMath::M_MS2SEC * USERCMD_MSEC * in_angleSpeedKey.GetFloat();
|
|
} else {
|
|
anglespeed = idMath::M_MS2SEC * USERCMD_MSEC;
|
|
}
|
|
|
|
if ( !ButtonState( UB_STRAFE ) ) {
|
|
viewangles[YAW] += anglespeed * in_yawSpeed.GetFloat() * joystickAxis[AXIS_SIDE];
|
|
viewangles[PITCH] += anglespeed * in_pitchSpeed.GetFloat() * joystickAxis[AXIS_FORWARD];
|
|
} else {
|
|
cmd.rightmove = idMath::ClampChar( cmd.rightmove + joystickAxis[AXIS_SIDE] );
|
|
cmd.forwardmove = idMath::ClampChar( cmd.forwardmove + joystickAxis[AXIS_FORWARD] );
|
|
}
|
|
|
|
cmd.upmove = idMath::ClampChar( cmd.upmove + joystickAxis[AXIS_UP] );
|
|
}
|
|
|
|
/*
|
|
==============
|
|
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() && idAsyncNetwork::IsActive() ) ) {
|
|
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() && idAsyncNetwork::IsActive() ) ? BUTTON_RUN : 0;
|
|
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() );
|
|
toggled_run.SetKeyState( ButtonState( UB_SPEED ), in_toggleRun.GetBool() && idAsyncNetwork::IsActive() );
|
|
toggled_zoom.SetKeyState( ButtonState( UB_ZOOM ), in_toggleZoom.GetBool() );
|
|
|
|
// keyboard angle adjustment
|
|
AdjustAngles();
|
|
|
|
// set button bits
|
|
CmdButtons();
|
|
|
|
// get basic movement from keyboard
|
|
KeyMove();
|
|
|
|
// get basic movement from mouse
|
|
MouseMove();
|
|
|
|
// get basic movement from joystick
|
|
JoystickMove();
|
|
|
|
// 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 ) );
|
|
|
|
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 );
|
|
|
|
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 ) {
|
|
memset( joystickAxis, 0, sizeof( joystickAxis ) );
|
|
}
|
|
|
|
/*
|
|
================
|
|
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
|
|
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 ) {
|
|
|
|
// initialize current usercmd
|
|
InitCurrent();
|
|
|
|
// process the system mouse events
|
|
Mouse();
|
|
|
|
// process the system keyboard events
|
|
Keyboard();
|
|
|
|
// process the system joystick events
|
|
Joystick();
|
|
|
|
// create the usercmd
|
|
MakeCurrent();
|
|
|
|
cmd.duplicateCount = 0;
|
|
|
|
return cmd;
|
|
}
|