//========= Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: builds an intended movement command to send to the server // // $Workfile: $ // $Date: $ // $NoKeywords: $ //=======================================================================================// #include "cbase.h" #include "kbutton.h" #include "usercmd.h" #include "in_buttons.h" #include "input.h" #include "iviewrender.h" #include "iclientmode.h" #include "prediction.h" #include "bitbuf.h" #include "checksum_md5.h" #include "hltvcamera.h" #if defined( REPLAY_ENABLED ) #include "replaycamera.h" #endif #include "ivieweffects.h" #include "inputsystem/iinputsystem.h" #include // isalnum() #include #ifdef SIXENSE #include "sixense/in_sixense.h" #endif extern ConVar cam_idealpitch; extern ConVar cam_idealyaw; #ifdef INFESTED_DLL extern ConVar asw_cam_marine_yaw; #endif // For showing/hiding the scoreboard #include // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" int in_impulse[ MAX_SPLITSCREEN_PLAYERS ]; static int in_cancel[ MAX_SPLITSCREEN_PLAYERS ]; ConVar cl_anglespeedkey( "cl_anglespeedkey", "0.67", 0 ); ConVar cl_yawspeed( "cl_yawspeed", "210", 0 ); ConVar cl_pitchspeed( "cl_pitchspeed", "225", 0 ); ConVar cl_pitchdown( "cl_pitchdown", "89", FCVAR_CHEAT ); ConVar cl_pitchup( "cl_pitchup", "89", FCVAR_CHEAT ); ConVar cl_upspeed( "cl_upspeed", "320", FCVAR_CHEAT ); ConVar lookspring( "lookspring", "0", FCVAR_ARCHIVE ); ConVar lookstrafe( "lookstrafe", "0", FCVAR_ARCHIVE ); #ifdef PORTAL2 #define MAX_LINEAR_SPEED "175" #else #define MAX_LINEAR_SPEED "450" #endif ConVar cl_sidespeed( "cl_sidespeed", MAX_LINEAR_SPEED, FCVAR_CHEAT ); ConVar cl_forwardspeed( "cl_forwardspeed", MAX_LINEAR_SPEED, FCVAR_CHEAT ); ConVar cl_backspeed( "cl_backspeed", MAX_LINEAR_SPEED, FCVAR_CHEAT ); void IN_JoystickChangedCallback_f( IConVar *pConVar, const char *pOldString, float flOldValue ); ConVar in_joystick( "joystick", "1", FCVAR_ARCHIVE, "True if the joystick is enabled, false otherwise.", true, 0.0f, true, 1.0f, IN_JoystickChangedCallback_f ); ConVar thirdperson_platformer( "thirdperson_platformer", "0", 0, "Player will aim in the direction they are moving." ); ConVar thirdperson_screenspace( "thirdperson_screenspace", "0", 0, "Movement will be relative to the camera, eg: left means screen-left" ); ConVar sv_noclipduringpause( "sv_noclipduringpause", "0", FCVAR_REPLICATED | FCVAR_CHEAT, "If cheats are enabled, then you can noclip with the game paused (for doing screenshots, etc.)." ); static ConVar cl_lagcomp_errorcheck( "cl_lagcomp_errorcheck", "0", 0, "Player index of other player to check for position errors." ); static ConVar option_duck_method( "option_duck_method", "0", FCVAR_ARCHIVE | FCVAR_SS );// 0 = HOLD to duck, 1 = Duck is a toggle static ConVar option_speed_method( "option_speed_method", "0", FCVAR_ARCHIVE | FCVAR_SS );// 0 = HOLD to go slow speed, 1 = speed is a toggle static ConVar round_start_reset_duck( "round_start_reset_duck", "0", 0 ); static ConVar round_start_reset_speed( "round_start_reset_speed", "0", 0 ); bool UsingMouselook( int nSlot ) { static SplitScreenConVarRef s_MouseLook( "cl_mouselook" ); return s_MouseLook.GetBool( nSlot ); } ConVar in_forceuser( "in_forceuser", "0", FCVAR_CHEAT | FCVAR_DEVELOPMENTONLY, "Force user input to this split screen player." ); static ConVar ss_mimic( "ss_mimic", "0", FCVAR_CHEAT | FCVAR_DEVELOPMENTONLY, "Split screen users mimic base player's CUserCmds" ); static void SplitScreenTeleport( int nSlot ) { C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer( nSlot ); if ( !pPlayer ) return; Vector vecOrigin = pPlayer->GetAbsOrigin(); QAngle angles = pPlayer->GetAbsAngles(); int nOther = ( nSlot + 1 ) % MAX_SPLITSCREEN_PLAYERS; if ( C_BasePlayer::GetLocalPlayer( nOther ) ) { char cmd[ 256 ]; Q_snprintf( cmd, sizeof( cmd ), "cmd%d setpos %f %f %f;setang %f %f %f\n", nOther + 1, VectorExpand( vecOrigin ), VectorExpand( angles ) ); engine->ClientCmd( cmd ); } } CON_COMMAND_F( ss_teleport, "Teleport other splitscreen player to my location.", FCVAR_CHEAT | FCVAR_DEVELOPMENTONLY ) { SplitScreenTeleport( GET_ACTIVE_SPLITSCREEN_SLOT() ); } /* =============================================================================== KEY BUTTONS Continuous button event tracking is complicated by the fact that two different input sources (say, mouse button 1 and the control key) can both press the same button, but the button should only be released when both of the pressing key have been released. When a key event issues a button command (+forward, +attack, etc), it appends its key number as a parameter to the command so it can be matched up with the release. state bit 0 is the current state of the key state bit 1 is edge triggered on the up to down transition state bit 2 is edge triggered on the down to up transition =============================================================================== */ kbutton_t in_speed; kbutton_t in_walk; kbutton_t in_jlook; kbutton_t in_strafe; kbutton_t in_commandermousemove; kbutton_t in_forward; kbutton_t in_back; kbutton_t in_moveleft; kbutton_t in_moveright; // Display the netgraph kbutton_t in_graph; kbutton_t in_joyspeed; // auto-speed key from the joystick (only works for player movement, not vehicles) kbutton_t in_ducktoggle; kbutton_t in_speedtoggle; kbutton_t in_lookspin; kbutton_t in_attack; kbutton_t in_attack2; kbutton_t in_zoom; static kbutton_t in_klook; static kbutton_t in_left; static kbutton_t in_right; static kbutton_t in_lookup; static kbutton_t in_lookdown; static kbutton_t in_use; static kbutton_t in_jump; static kbutton_t in_up; static kbutton_t in_down; static kbutton_t in_duck; static kbutton_t in_reload; static kbutton_t in_alt1; static kbutton_t in_alt2; static kbutton_t in_score; static kbutton_t in_break; static kbutton_t in_grenade1; static kbutton_t in_grenade2; #ifdef INFESTED_DLL static kbutton_t in_currentability; static kbutton_t in_prevability; static kbutton_t in_nextability; static kbutton_t in_ability1; static kbutton_t in_ability2; static kbutton_t in_ability3; static kbutton_t in_ability4; static kbutton_t in_ability5; #endif bool joystick_forced_speed = false; /* =========== IN_CenterView_f =========== */ void IN_CenterView_f (void) { QAngle viewangles; if ( UsingMouselook( GET_ACTIVE_SPLITSCREEN_SLOT() ) == false ) { if ( !::input->CAM_InterceptingMouse() ) { engine->GetViewAngles( viewangles ); viewangles[PITCH] = 0; engine->SetViewAngles( viewangles ); } } } /* =========== IN_Joystick_Advanced_f =========== */ void IN_Joystick_Advanced_f (const CCommand& args) { ::input->Joystick_Advanced( args.ArgC() == 2 ); } void IN_JoystickChangedCallback_f( IConVar *pConVar, const char *pOldString, float flOldValue ) { ::input->Joystick_Advanced( true ); } /* ============ KB_ConvertString Removes references to +use and replaces them with the keyname in the output string. If a binding is unfound, then the original text is retained. NOTE: Only works for text with +word in it. ============ */ int KB_ConvertString( char *in, char **ppout ) { char sz[ 4096 ]; char binding[ 64 ]; char *p; char *pOut; char *pEnd; const char *pBinding; if ( !ppout ) return 0; *ppout = NULL; p = in; pOut = sz; while ( *p ) { if ( *p == '+' ) { pEnd = binding; while ( *p && ( V_isalnum( *p ) || ( pEnd == binding ) ) && ( ( pEnd - binding ) < 63 ) ) { *pEnd++ = *p++; } *pEnd = '\0'; pBinding = NULL; if ( strlen( binding + 1 ) > 0 ) { // See if there is a binding for binding? pBinding = engine->Key_LookupBinding( binding + 1 ); } if ( pBinding ) { *pOut++ = '['; pEnd = (char *)pBinding; } else { pEnd = binding; } while ( *pEnd ) { *pOut++ = *pEnd++; } if ( pBinding ) { *pOut++ = ']'; } } else { *pOut++ = *p++; } } *pOut = '\0'; int maxlen = strlen( sz ) + 1; pOut = ( char * )malloc( maxlen ); Q_strncpy( pOut, sz, maxlen ); *ppout = pOut; return 1; } /* ============================== FindKey Allows the engine to request a kbutton handler by name, if the key exists. ============================== */ kbutton_t *CInput::FindKey( const char *name ) { CKeyboardKey *p; p = m_pKeys; while ( p ) { if ( !Q_stricmp( name, p->name ) ) { return p->pkey; } p = p->next; } return NULL; } /* ============ AddKeyButton Add a kbutton_t * to the list of pointers the engine can retrieve via KB_Find ============ */ void CInput::AddKeyButton( const char *name, kbutton_t *pkb ) { CKeyboardKey *p; kbutton_t *kb; kb = FindKey( name ); if ( kb ) return; p = new CKeyboardKey; Q_strncpy( p->name, name, sizeof( p->name ) ); p->pkey = pkb; p->next = m_pKeys; m_pKeys = p; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CInput::CInput( void ) { for ( int i = 0; i < MAX_SPLITSCREEN_PLAYERS; ++i ) { m_PerUser[ i ].m_pCommands = NULL; m_PerUser[ i ].m_pCameraThirdData = NULL; m_PerUser[ i ].m_pVerifiedCommands = NULL; } m_lastAutoAimValue = 1.0f; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CInput::~CInput( void ) { } /* ============ Init_Keyboard Add kbutton_t definitions that the engine can query if needed ============ */ void CInput::Init_Keyboard( void ) { m_pKeys = NULL; AddKeyButton( "in_graph", &in_graph ); AddKeyButton( "in_jlook", &in_jlook ); AddKeyButton( "in_reload", &in_reload ); } /* ============ Shutdown_Keyboard Clear kblist ============ */ void CInput::Shutdown_Keyboard( void ) { CKeyboardKey *p, *n; p = m_pKeys; while ( p ) { n = p->next; delete p; p = n; } m_pKeys = NULL; } kbutton_t::Split_t &kbutton_t::GetPerUser( int nSlot /*=-1*/ ) { if ( nSlot == -1 ) { ASSERT_LOCAL_PLAYER_RESOLVABLE(); nSlot = GET_ACTIVE_SPLITSCREEN_SLOT(); } return m_PerUser[ nSlot ]; } /* ============ KeyDown ============ */ void KeyDown( kbutton_t *b, const char *c ) { kbutton_t::Split_t &data = b->GetPerUser(); int k = -1; if ( c && c[0] ) { k = atoi(c); } if (k == data.down[0] || k == data.down[1]) return; // repeating key if (!data.down[0]) data.down[0] = k; else if (!data.down[1]) data.down[1] = k; else { if ( c[0] ) { DevMsg( 1,"Three keys down for a button '%c' '%c' '%c'!\n", data.down[0], data.down[1], c[0]); } return; } if (data.state & 1) return; // still down data.state |= 1 + 2; // down + impulse down } /* ============ KeyUp ============ */ void KeyUp( kbutton_t *b, const char *c ) { kbutton_t::Split_t &data = b->GetPerUser(); if ( !c || !c[0] ) { data.down[0] = data.down[1] = 0; data.state = 4; // impulse up return; } int k = atoi(c); if (data.down[0] == k) data.down[0] = 0; else if (data.down[1] == k) data.down[1] = 0; else return; // key up without coresponding down (menu pass through) if (data.down[0] || data.down[1]) { //Msg ("Keys down for button: '%c' '%c' '%c' (%d,%d,%d)!\n", data.down[0], data.down[1], c, data.down[0], data.down[1], c); return; // some other key is still holding it down } if (!(data.state & 1)) return; // still up (this should not happen) data.state &= ~1; // now up data.state |= 4; // impulse up } void IN_ClearDuckToggle() { if ( ::input->KeyState( &in_ducktoggle ) ) { KeyUp( &in_ducktoggle, NULL ); } } void IN_ClearSpeedToggle() { if ( ::input->KeyState( &in_speedtoggle ) ) { KeyUp( &in_speedtoggle, NULL ); } } void IN_ForceSpeedDown( ) {joystick_forced_speed = true;} void IN_ForceSpeedUp( ) {joystick_forced_speed = false;} void IN_CommanderMouseMoveDown( const CCommand &args ) {KeyDown(&in_commandermousemove, args[1] );} void IN_CommanderMouseMoveUp( const CCommand &args ) {KeyUp(&in_commandermousemove, args[1] );} void IN_BreakDown( const CCommand &args ) { KeyDown( &in_break , args[1] );} void IN_BreakUp( const CCommand &args ) { KeyUp( &in_break, args[1] ); #if defined( _DEBUG ) DebuggerBreak(); #endif }; void IN_KLookDown ( const CCommand &args ) {KeyDown(&in_klook, args[1] );} void IN_KLookUp ( const CCommand &args ) {KeyUp(&in_klook, args[1] );} void IN_JLookDown ( const CCommand &args ) {KeyDown(&in_jlook, args[1] );} void IN_JLookUp ( const CCommand &args ) {KeyUp(&in_jlook, args[1] );} void IN_UpDown( const CCommand &args ) {KeyDown(&in_up, args[1] );} void IN_UpUp( const CCommand &args ) {KeyUp(&in_up, args[1] );} void IN_DownDown( const CCommand &args ) {KeyDown(&in_down, args[1] );} void IN_DownUp( const CCommand &args ) {KeyUp(&in_down, args[1] );} void IN_LeftDown( const CCommand &args ) {KeyDown(&in_left, args[1] );} void IN_LeftUp( const CCommand &args ) {KeyUp(&in_left, args[1] );} void IN_RightDown( const CCommand &args ) {KeyDown(&in_right, args[1] );} void IN_RightUp( const CCommand &args ) {KeyUp(&in_right, args[1] );} void IN_ForwardDown( const CCommand &args ) {KeyDown(&in_forward, args[1] );} void IN_ForwardUp( const CCommand &args ) {KeyUp(&in_forward, args[1] );} void IN_BackDown( const CCommand &args ) {KeyDown(&in_back, args[1] );} void IN_BackUp( const CCommand &args ) {KeyUp(&in_back, args[1] );} void IN_LookupDown( const CCommand &args ) {KeyDown(&in_lookup, args[1] );} void IN_LookupUp( const CCommand &args ) {KeyUp(&in_lookup, args[1] );} void IN_LookdownDown( const CCommand &args ) {KeyDown(&in_lookdown, args[1] );} void IN_LookdownUp( const CCommand &args ) {KeyUp(&in_lookdown, args[1] );} void IN_MoveleftDown( const CCommand &args ) {KeyDown(&in_moveleft, args[1] );} void IN_MoveleftUp( const CCommand &args ) {KeyUp(&in_moveleft, args[1] );} void IN_MoverightDown( const CCommand &args ) {KeyDown(&in_moveright, args[1] );} void IN_MoverightUp( const CCommand &args ) {KeyUp(&in_moveright, args[1] );} void IN_StrafeDown( const CCommand &args ) {KeyDown(&in_strafe, args[1] );} void IN_StrafeUp( const CCommand &args ) {KeyUp(&in_strafe, args[1] );} void IN_Attack2Down( const CCommand &args ) { KeyDown(&in_attack2, args[1] );} void IN_Attack2Up( const CCommand &args ) {KeyUp(&in_attack2, args[1] );} void IN_UseDown ( const CCommand &args ) {KeyDown(&in_use, args[1] );} void IN_UseUp ( const CCommand &args ) {KeyUp(&in_use, args[1] );} void IN_JumpDown ( const CCommand &args ) {KeyDown(&in_jump, args[1] );} void IN_JumpUp ( const CCommand &args ) { KeyUp(&in_jump, args[1] ); } void IN_DuckToggle( const CCommand &args ) { if ( ::input->KeyState(&in_ducktoggle) ) { IN_ClearDuckToggle(); } else { KeyDown( &in_ducktoggle, args[1] ); } } void IN_DuckDown( const CCommand &args ) { SplitScreenConVarRef option_duck_method( "option_duck_method" ); if ( option_duck_method.IsValid() && option_duck_method.GetBool( GET_ACTIVE_SPLITSCREEN_SLOT() ) ) { IN_DuckToggle( args ); } else { KeyDown(&in_duck, args[1] ); IN_ClearDuckToggle(); } } void IN_DuckUp( const CCommand &args ) { SplitScreenConVarRef option_duck_method( "option_duck_method" ); if ( option_duck_method.IsValid() && option_duck_method.GetBool( GET_ACTIVE_SPLITSCREEN_SLOT() ) ) { // intentionally blank } else { KeyUp(&in_duck, args[1] ); IN_ClearDuckToggle(); } } void IN_SpeedToggle( const CCommand &args ) { if ( ::input->KeyState(&in_speedtoggle) ) { IN_ClearSpeedToggle(); } else { KeyDown( &in_speedtoggle, args[1] ); } } void IN_SpeedDown( const CCommand &args ) { SplitScreenConVarRef option_speed_method( "option_speed_method" ); if ( option_speed_method.IsValid() && option_speed_method.GetBool( GET_ACTIVE_SPLITSCREEN_SLOT() ) ) { IN_SpeedToggle( args ); } else { KeyDown(&in_speed, args[1] ); IN_ClearSpeedToggle(); } } void IN_SpeedUp( const CCommand &args ) { SplitScreenConVarRef option_speed_method( "option_speed_method" ); if ( option_speed_method.IsValid() && option_speed_method.GetBool( GET_ACTIVE_SPLITSCREEN_SLOT() ) ) { // intentionally blank } else { KeyUp(&in_speed, args[1] ); IN_ClearSpeedToggle(); } } void IN_WalkDown( const CCommand &args ) {KeyDown(&in_walk, args[1] );} void IN_WalkUp( const CCommand &args ) {KeyUp(&in_walk, args[1] );} void IN_ReloadDown( const CCommand &args ) {KeyDown(&in_reload, args[1] );} void IN_ReloadUp( const CCommand &args ) {KeyUp(&in_reload, args[1] );} void IN_Alt1Down( const CCommand &args ) {KeyDown(&in_alt1, args[1] );} void IN_Alt1Up( const CCommand &args ) {KeyUp(&in_alt1, args[1] );} void IN_Alt2Down( const CCommand &args ) {KeyDown(&in_alt2, args[1] );} void IN_Alt2Up( const CCommand &args ) {KeyUp(&in_alt2, args[1] );} void IN_GraphDown( const CCommand &args ) {KeyDown(&in_graph, args[1] );} void IN_GraphUp( const CCommand &args ) {KeyUp(&in_graph, args[1] );} void IN_ZoomDown( const CCommand &args ) {KeyDown(&in_zoom, args[1] );} void IN_ZoomUp( const CCommand &args ) {KeyUp(&in_zoom, args[1] );} void IN_ZoomInDown( const CCommand &args ) {KeyDown(&in_grenade1, args[1] );} void IN_ZoomInUp( const CCommand &args ) {KeyUp(&in_grenade1, args[1] );} void IN_ZoomOutDown( const CCommand &args ) {KeyDown(&in_grenade2, args[1] );} void IN_ZoomOutUp( const CCommand &args ) {KeyUp(&in_grenade2, args[1] );} void IN_Grenade1Up( const CCommand &args ) { KeyUp( &in_grenade1, args[1] ); } void IN_Grenade1Down( const CCommand &args ) { KeyDown( &in_grenade1, args[1] ); } void IN_Grenade2Up( const CCommand &args ) { KeyUp( &in_grenade2, args[1] ); } void IN_Grenade2Down( const CCommand &args ) { KeyDown( &in_grenade2, args[1] ); } void IN_XboxStub( const CCommand &args ) { /*do nothing*/ } #ifdef PORTAL2 #if USE_SLOWTIME // Slow-time kbutton_t in_slowtoggle; void IN_SlowTimeUp( const CCommand &args ) { KeyUp( &in_slowtoggle, args[1] ); } void IN_SlowTimeDown( const CCommand &args ) { KeyDown( &in_slowtoggle, args[1] ); } static ConCommand startslowtime( "+slowtime", IN_SlowTimeDown ); static ConCommand endslowtime( "-slowtime", IN_SlowTimeUp ); #endif // USE_SLOWTIME kbutton_t in_remote_view_toggle; static bool g_bRemoteViewKeyWasUp = true; void IN_RemoteViewUp( const CCommand &args ) { g_bRemoteViewKeyWasUp = true; KeyUp( &in_remote_view_toggle, args[1] ); } void IN_RemoteViewDown( const CCommand &args ) { if ( g_bRemoteViewKeyWasUp ) { g_bRemoteViewKeyWasUp = false; IGameEvent * event = gameeventmanager->CreateEvent( "remote_view_activated" ); if ( event ) { gameeventmanager->FireEvent( event ); } } KeyDown( &in_remote_view_toggle, args[1] ); } static ConCommand startremoteview( "+remote_view", IN_RemoteViewDown ); static ConCommand endremoteview( "-remote_view", IN_RemoteViewUp ); extern bool g_bShowGhostedPortals; void IN_ShowPortalsUp( const CCommand &args ) { g_bShowGhostedPortals = false; } void IN_ShowPortalsDown( const CCommand &args ) { g_bShowGhostedPortals = true; } static ConCommand showportals( "+showportals", IN_ShowPortalsDown ); static ConCommand hideportals( "-showportals", IN_ShowPortalsUp ); kbutton_t in_coop_ping; void IN_CoopPingUp( const CCommand &args) { KeyUp( &in_coop_ping, args[1] ); } void IN_CoopPingDown( const CCommand &args) { KeyDown( &in_coop_ping, args[1] ); } static ConCommand presscoopping( "+coop_ping", IN_CoopPingDown ); static ConCommand unpresscoopping( "-coop_ping", IN_CoopPingUp ); #endif // PORTAL2 #ifdef INFESTED_DLL void IN_PrevAbilityUp( const CCommand &args ) { KeyUp( &in_prevability, args[1] ); } void IN_PrevAbilityDown( const CCommand &args ) { KeyDown( &in_prevability, args[1] ); } void IN_NextAbilityUp( const CCommand &args ) { KeyUp( &in_nextability, args[1] ); } void IN_NextAbilityDown( const CCommand &args ) { KeyDown( &in_nextability, args[1] ); } void IN_CurrentAbilityUp( const CCommand &args ) { KeyUp( &in_currentability, args[1] ); } void IN_CurrentAbilityDown( const CCommand &args ) { KeyDown( &in_currentability, args[1] ); } void IN_Ability1Up( const CCommand &args ) { KeyUp( &in_ability1, args[1] ); } void IN_Ability1Down( const CCommand &args ) { KeyDown( &in_ability1, args[1] ); } void IN_Ability2Up( const CCommand &args ) { KeyUp( &in_ability2, args[1] ); } void IN_Ability2Down( const CCommand &args ) { KeyDown( &in_ability2, args[1] ); } void IN_Ability3Up( const CCommand &args ) { KeyUp( &in_ability3, args[1] ); } void IN_Ability3Down( const CCommand &args ) { KeyDown( &in_ability3, args[1] ); } void IN_Ability4Up( const CCommand &args ) { KeyUp( &in_ability4, args[1] ); } void IN_Ability4Down( const CCommand &args ) { KeyDown( &in_ability4, args[1] ); } void IN_Ability5Up( const CCommand &args ) { KeyUp( &in_ability5, args[1] ); } void IN_Ability5Down( const CCommand &args ) { KeyDown( &in_ability5, args[1] ); } #endif void IN_AttackDown( const CCommand &args ) { KeyDown( &in_attack, args[1] ); } void IN_AttackUp( const CCommand &args ) { KeyUp( &in_attack, args[1] ); ASSERT_LOCAL_PLAYER_RESOLVABLE(); in_cancel[ GET_ACTIVE_SPLITSCREEN_SLOT() ] = 0; } // Special handling void IN_Cancel( const CCommand &args ) { ASSERT_LOCAL_PLAYER_RESOLVABLE(); in_cancel[ GET_ACTIVE_SPLITSCREEN_SLOT() ] = 1; } void IN_Impulse( const CCommand &args ) { ASSERT_LOCAL_PLAYER_RESOLVABLE(); in_impulse[ GET_ACTIVE_SPLITSCREEN_SLOT() ] = atoi( args[1] ); } void IN_ScoreDown( const CCommand &args ) { KeyDown( &in_score, args[1] ); } void IN_ScoreUp( const CCommand &args ) { KeyUp( &in_score, args[1] ); } void IN_LookSpinDown( const CCommand &args ) {KeyDown( &in_lookspin, args[1] );} void IN_LookSpinUp( const CCommand &args ) {KeyUp( &in_lookspin, args[1] );} /* ============ KeyEvent Return 1 to allow engine to process the key, otherwise, act on it as needed ============ */ int CInput::KeyEvent( int down, ButtonCode_t code, const char *pszCurrentBinding ) { // Deal with camera intercepting the mouse if ( down && ( ( code == MOUSE_LEFT ) || ( code == MOUSE_RIGHT ) || ( code == MOUSE_MIDDLE ) || ( code == MOUSE_WHEEL_UP ) || ( code == MOUSE_WHEEL_DOWN ) ) ) { ConVarRef cl_mouseenable( "cl_mouseenable" ); if ( GetPerUser().m_fCameraInterceptingMouse || !cl_mouseenable.GetBool() ) return 0; } if ( GetClientMode() ) return GetClientMode()->KeyInput(down, code, pszCurrentBinding); return 1; } /* =============== KeyState Returns 0.25 if a key was pressed and released during the frame, 0.5 if it was pressed and held 0 if held then released, and 1.0 if held for the entire time =============== */ float CInput::KeyState ( kbutton_t *key ) { kbutton_t::Split_t &data = key->GetPerUser(); float val = 0.0; int impulsedown, impulseup, down; impulsedown = data.state & 2; impulseup = data.state & 4; down = data.state & 1; if ( impulsedown && !impulseup ) { // pressed and held this frame? val = down ? 0.5 : 0.0; } if ( impulseup && !impulsedown ) { // released this frame? val = down ? 0.0 : 0.0; } if ( !impulsedown && !impulseup ) { // held the entire frame? val = down ? 1.0 : 0.0; } if ( impulsedown && impulseup ) { if ( down ) { // released and re-pressed this frame val = 0.75; } else { // pressed and released this frame val = 0.25; } } // clear impulses data.state &= 1; return val; } void CInput::IN_SetSampleTime( float frametime ) { FOR_EACH_VALID_SPLITSCREEN_PLAYER( i ) { m_PerUser[ i ].m_flKeyboardSampleTime = frametime; } } /* ============================== DetermineKeySpeed ============================== */ static ConVar in_usekeyboardsampletime( "in_usekeyboardsampletime", "1", 0, "Use keyboard sample time smoothing." ); float CInput::DetermineKeySpeed( int nSlot, float frametime ) { if ( in_usekeyboardsampletime.GetBool() ) { PerUserInput_t &user = GetPerUser( nSlot ); if ( user.m_flKeyboardSampleTime <= 0 ) return 0.0f; frametime = MIN( user.m_flKeyboardSampleTime, frametime ); user.m_flKeyboardSampleTime -= frametime; } float speed; speed = frametime; if ( in_speed.GetPerUser( nSlot ).state & 1 ) { speed *= cl_anglespeedkey.GetFloat(); } return speed; } /* ============================== AdjustYaw ============================== */ void CInput::AdjustYaw( int nSlot, float speed, QAngle& viewangles ) { if ( !(in_strafe.GetPerUser( nSlot ).state & 1) ) { viewangles[YAW] -= speed*cl_yawspeed.GetFloat() * KeyState (&in_right); viewangles[YAW] += speed*cl_yawspeed.GetFloat() * KeyState (&in_left); } const PerUserInput_t &user = GetPerUser( nSlot ); // thirdperson platformer mode // use movement keys to aim the player relative to the thirdperson camera if ( CAM_IsThirdPerson() && thirdperson_platformer.GetInt() ) { float side = KeyState(&in_moveleft) - KeyState(&in_moveright); float forward = KeyState(&in_forward) - KeyState(&in_back); if ( side || forward ) { viewangles[YAW] = RAD2DEG(atan2(side, forward)) + user.m_vecCameraOffset[ YAW ]; } if ( side || forward || KeyState (&in_right) || KeyState (&in_left) ) { cam_idealyaw.SetValue( user.m_vecCameraOffset[ YAW ] - viewangles[ YAW ] ); } } } /* ============================== AdjustPitch ============================== */ void CInput::AdjustPitch( int nSlot, float speed, QAngle& viewangles ) { // only allow keyboard looking if mouse look is disabled if ( !UsingMouselook( nSlot ) ) { float up, down; if ( in_klook.GetPerUser( nSlot ).state & 1 ) { view->StopPitchDrift (); viewangles[PITCH] -= speed*cl_pitchspeed.GetFloat() * KeyState (&in_forward); viewangles[PITCH] += speed*cl_pitchspeed.GetFloat() * KeyState (&in_back); } up = KeyState ( &in_lookup ); down = KeyState ( &in_lookdown ); viewangles[PITCH] -= speed*cl_pitchspeed.GetFloat() * up; viewangles[PITCH] += speed*cl_pitchspeed.GetFloat() * down; if ( up || down ) { view->StopPitchDrift (); } } } /* ============================== ClampAngles ============================== */ void CInput::ClampAngles( QAngle& viewangles ) { if ( viewangles[PITCH] > cl_pitchdown.GetFloat() ) { viewangles[PITCH] = cl_pitchdown.GetFloat(); } if ( viewangles[PITCH] < -cl_pitchup.GetFloat() ) { viewangles[PITCH] = -cl_pitchup.GetFloat(); } // Don't constrain Roll in Portal because the player can be upside down! -Jeep #if !defined( PORTAL ) if ( viewangles[ROLL] > 50 ) { viewangles[ROLL] = 50; } if ( viewangles[ROLL] < -50 ) { viewangles[ROLL] = -50; } #endif } /* ================ AdjustAngles Moves the local angle positions ================ */ void CInput::AdjustAngles ( int nSlot, float frametime ) { float speed; QAngle viewangles; // Determine control scaling factor ( multiplies time ) speed = DetermineKeySpeed( nSlot, frametime ); if ( speed <= 0.0f ) { return; } // Retrieve latest view direction from engine engine->GetViewAngles( viewangles ); // Undo tilting from previous frame viewangles -= GetPerUser().m_angPreviousViewAnglesTilt; // Apply tilting effects here (it affects aim) QAngle vecAnglesBeforeTilt = viewangles; GetViewEffects()->CalcTilt(); GetViewEffects()->ApplyTilt( viewangles, 1.0f ); // Remember the tilt delta so we can undo it before applying tilt next frame GetPerUser().m_angPreviousViewAnglesTilt = viewangles - vecAnglesBeforeTilt; // Adjust YAW AdjustYaw( nSlot, speed, viewangles ); // Adjust PITCH if keyboard looking AdjustPitch( nSlot, speed, viewangles ); // Make sure values are legitimate ClampAngles( viewangles ); // Store new view angles into engine view direction engine->SetViewAngles( viewangles ); } /* ============================== ComputeSideMove ============================== */ void CInput::ComputeSideMove( int nSlot, CUserCmd *cmd ) { // thirdperson platformer movement if ( CAM_IsThirdPerson() && thirdperson_platformer.GetInt() ) { // no sideways movement in this mode return; } // thirdperson screenspace movement if ( CAM_IsThirdPerson() && thirdperson_screenspace.GetInt() ) { #ifdef INFESTED_DLL float ideal_yaw = asw_cam_marine_yaw.GetFloat() - 90.0f; #else float ideal_yaw = cam_idealyaw.GetFloat(); #endif float ideal_sin = sin(DEG2RAD(ideal_yaw)); float ideal_cos = cos(DEG2RAD(ideal_yaw)); float movement = ideal_cos*KeyState(&in_moveright) + ideal_sin*KeyState(&in_back) + -ideal_cos*KeyState(&in_moveleft) + -ideal_sin*KeyState(&in_forward); cmd->sidemove += cl_sidespeed.GetFloat() * movement; return; } // If strafing, check left and right keys and act like moveleft and moveright keys if ( in_strafe.GetPerUser( nSlot ).state & 1 ) { cmd->sidemove += cl_sidespeed.GetFloat() * KeyState (&in_right); cmd->sidemove -= cl_sidespeed.GetFloat() * KeyState (&in_left); } // Otherwise, check strafe keys cmd->sidemove += cl_sidespeed.GetFloat() * KeyState (&in_moveright); cmd->sidemove -= cl_sidespeed.GetFloat() * KeyState (&in_moveleft); } /* ============================== ComputeUpwardMove ============================== */ void CInput::ComputeUpwardMove( int nSlot, CUserCmd *cmd ) { cmd->upmove += cl_upspeed.GetFloat() * KeyState (&in_up); cmd->upmove -= cl_upspeed.GetFloat() * KeyState (&in_down); } /* ============================== ComputeForwardMove ============================== */ void CInput::ComputeForwardMove( int nSlot, CUserCmd *cmd ) { // thirdperson platformer movement if ( CAM_IsThirdPerson() && thirdperson_platformer.GetInt() ) { // movement is always forward in this mode float movement = KeyState(&in_forward) || KeyState(&in_moveright) || KeyState(&in_back) || KeyState(&in_moveleft); cmd->forwardmove += cl_forwardspeed.GetFloat() * movement; return; } // thirdperson screenspace movement if ( CAM_IsThirdPerson() && thirdperson_screenspace.GetInt() ) { #ifdef INFESTED_DLL float ideal_yaw = asw_cam_marine_yaw.GetFloat() - 90.0f; #else float ideal_yaw = cam_idealyaw.GetFloat(); #endif float ideal_sin = sin(DEG2RAD(ideal_yaw)); float ideal_cos = cos(DEG2RAD(ideal_yaw)); float movement = ideal_cos*KeyState(&in_forward) + ideal_sin*KeyState(&in_moveright) + -ideal_cos*KeyState(&in_back) + -ideal_sin*KeyState(&in_moveleft); cmd->forwardmove += cl_forwardspeed.GetFloat() * movement; return; } if ( !(in_klook.GetPerUser( nSlot ).state & 1 ) ) { cmd->forwardmove += cl_forwardspeed.GetFloat() * KeyState (&in_forward); cmd->forwardmove -= cl_backspeed.GetFloat() * KeyState (&in_back); } } /* ============================== ScaleMovements ============================== */ void CInput::ScaleMovements( CUserCmd *cmd ) { // float spd; // clip to maxspeed // FIXME FIXME: This doesn't work return; /* spd = engine->GetClientMaxspeed(); if ( spd == 0.0 ) return; // Scale the speed so that the total velocity is not > spd float fmov = sqrt( (cmd->forwardmove*cmd->forwardmove) + (cmd->sidemove*cmd->sidemove) + (cmd->upmove*cmd->upmove) ); if ( fmov > spd && fmov > 0.0 ) { float fratio = spd / fmov; if ( !IsNoClipping() ) { cmd->forwardmove *= fratio; cmd->sidemove *= fratio; cmd->upmove *= fratio; } } */ } /* =========== ControllerMove =========== */ void CInput::ControllerMove( int nSlot, float frametime, CUserCmd *cmd ) { ConVarRef cl_mouseenable( "cl_mouseenable" ); if ( (IsPC() || IsPlatformPS3()) && cl_mouseenable.GetBool() && nSlot == in_forceuser.GetInt() && g_pInputSystem->IsDeviceReadingInput( INPUT_DEVICE_KEYBOARD_MOUSE ) ) { if ( !GetPerUser( nSlot ).m_fCameraInterceptingMouse && m_fMouseActive ) { MouseMove( nSlot, cmd ); } } JoyStickMove( frametime, cmd); SteamControllerMove( frametime, cmd ); } //----------------------------------------------------------------------------- // Purpose: // Input : *weapon - //----------------------------------------------------------------------------- void CInput::MakeWeaponSelection( C_BaseCombatWeapon *weapon ) { GetPerUser().m_hSelectedWeapon = weapon; } CInput::PerUserInput_t &CInput::GetPerUser( int nSlot /*=-1*/ ) { if ( nSlot == -1 ) { ASSERT_LOCAL_PLAYER_RESOLVABLE(); return m_PerUser[ GET_ACTIVE_SPLITSCREEN_SLOT() ]; } return m_PerUser[ nSlot ]; } const CInput::PerUserInput_t &CInput::GetPerUser( int nSlot /*=-1*/ ) const { if ( nSlot == -1 ) { ASSERT_LOCAL_PLAYER_RESOLVABLE(); return m_PerUser[ GET_ACTIVE_SPLITSCREEN_SLOT() ]; } return m_PerUser[ nSlot ]; } void CInput::ExtraMouseSample( float frametime, bool active ) { ASSERT_LOCAL_PLAYER_RESOLVABLE(); int nSlot = GET_ACTIVE_SPLITSCREEN_SLOT(); static CUserCmd dummy[ MAX_SPLITSCREEN_PLAYERS ]; CUserCmd *cmd = &dummy[ nSlot ]; cmd->Reset(); QAngle viewangles; if ( active ) { // Determine view angles AdjustAngles ( nSlot, frametime ); // Determine sideways movement if ( g_pInputSystem->IsDeviceReadingInput( INPUT_DEVICE_KEYBOARD_MOUSE ) ) ComputeSideMove( nSlot, cmd ); // Determine vertical movement ComputeUpwardMove( nSlot, cmd ); // Determine forward movement if ( g_pInputSystem->IsDeviceReadingInput( INPUT_DEVICE_KEYBOARD_MOUSE ) ) ComputeForwardMove( nSlot, cmd ); // Scale based on holding speed key or having too fast of a velocity based on client maximum speed. ScaleMovements( cmd ); // Allow mice and other controllers to add their inputs ControllerMove( nSlot, frametime, cmd ); #ifdef SIXENSE if ( nSlot == in_forceuser.GetInt() ) { g_pSixenseInput->SixenseFrame( frametime, cmd ); if( g_pSixenseInput->IsEnabled() ) { g_pSixenseInput->SetView( frametime, cmd ); } } #endif } // Retrieve view angles from engine ( could have been set in AdjustAngles above ) engine->GetViewAngles( viewangles ); if ( round_start_reset_duck.GetBool( ) == true ) { IN_ClearDuckToggle( ); round_start_reset_duck.SetValue( false ); } if ( round_start_reset_speed.GetBool( ) == true ) { IN_ClearSpeedToggle( ); joystick_forced_speed = false; round_start_reset_speed.SetValue( false ); } // Set button and flag bits, don't blow away state #ifdef SIXENSE if( g_pSixenseInput->IsEnabled() ) { // Some buttons were set in SixenseUpdateKeys, so or in any real keypresses cmd->buttons |= GetButtonBits( false ); } else { cmd->buttons = GetButtonBits( false ); } #else cmd->buttons = GetButtonBits( false ); #endif // Use new view angles if alive, otherwise user last angles we stored off. VectorCopy( viewangles, cmd->viewangles ); VectorCopy( viewangles, GetPerUser().m_angPreviousViewAngles ); // Let the move manager override anything it wants to. if ( GetClientMode()->CreateMove( frametime, cmd ) ) { // Get current view angles after the client mode tweaks with it engine->SetViewAngles( cmd->viewangles ); prediction->SetLocalViewAngles( cmd->viewangles ); } CheckPaused( cmd ); CheckSplitScreenMimic( nSlot, cmd, &dummy[ 0 ] ); } /* ================ CreateMove Send the intended movement message to the server if active == 1 then we are 1) not playing back demos ( where our commands are ignored ) and 2 ) we have finished signing on to server ================ */ void CInput::CreateMove ( int sequence_number, float input_sample_frametime, bool active ) { ASSERT_LOCAL_PLAYER_RESOLVABLE(); int nSlot = GET_ACTIVE_SPLITSCREEN_SLOT(); CUserCmd *cmd = &GetPerUser( nSlot ).m_pCommands[ sequence_number % MULTIPLAYER_BACKUP]; CVerifiedUserCmd *pVerified = &GetPerUser( nSlot ).m_pVerifiedCommands[ sequence_number % MULTIPLAYER_BACKUP]; cmd->Reset(); cmd->command_number = sequence_number; cmd->tick_count = gpGlobals->tickcount; QAngle viewangles; if ( active || sv_noclipduringpause.GetInt() ) { if ( nSlot == in_forceuser.GetInt() ) { // Determine view angles AdjustAngles ( nSlot, input_sample_frametime ); // Determine sideways movement if ( g_pInputSystem->IsDeviceReadingInput( INPUT_DEVICE_KEYBOARD_MOUSE ) ) ComputeSideMove( nSlot, cmd ); // Determine vertical movement ComputeUpwardMove( nSlot, cmd ); // Determine forward movement if ( g_pInputSystem->IsDeviceReadingInput( INPUT_DEVICE_KEYBOARD_MOUSE ) ) ComputeForwardMove( nSlot, cmd ); // Scale based on holding speed key or having too fast of a velocity based on client maximum // speed. ScaleMovements( cmd ); } // Allow mice and other controllers to add their inputs ControllerMove( nSlot, input_sample_frametime, cmd ); #ifdef SIXENSE if ( nSlot == in_forceuser.GetInt() ) { g_pSixenseInput->SixenseFrame( input_sample_frametime, cmd ); if( g_pSixenseInput->IsEnabled() ) { g_pSixenseInput->SetView( input_sample_frametime, cmd ); } } #endif } else { // need to run and reset mouse input so that there is no view pop when unpausing if ( !GetPerUser( nSlot ).m_fCameraInterceptingMouse && m_fMouseActive ) { float mx, my; GetAccumulatedMouseDeltasAndResetAccumulators( nSlot, &mx, &my ); ResetMouse(); } } // Retreive view angles from engine ( could have been set in IN_AdjustAngles above ) engine->GetViewAngles( viewangles ); cmd->impulse = in_impulse[ nSlot ]; in_impulse[ nSlot ] = 0; // Latch and clear weapon selection if ( GetPerUser( nSlot ).m_hSelectedWeapon != NULL ) { C_BaseCombatWeapon *weapon = GetPerUser( nSlot ).m_hSelectedWeapon; cmd->weaponselect = weapon->entindex(); cmd->weaponsubtype = weapon->GetSubType(); // Always clear weapon selection GetPerUser( nSlot ).m_hSelectedWeapon = NULL; } #ifdef SIXENSE if( g_pSixenseInput->IsEnabled() ) { // Some buttons were set in SixenseUpdateKeys, so or in any real keypresses cmd->buttons |= GetButtonBits( true ); } else { cmd->buttons = GetButtonBits( true ); } #else // Set button and flag bits cmd->buttons = GetButtonBits( true ); #endif // Using joystick? #ifdef SIXENSE if ( g_pInputSystem->IsDeviceReadingInput( INPUT_DEVICE_GAMEPAD ) && ( in_joystick.GetInt() || g_pSixenseInput->IsEnabled() ) ) #else if ( ( g_pInputSystem->IsDeviceReadingInput( INPUT_DEVICE_GAMEPAD ) && in_joystick.GetInt() ) || g_pInputSystem->MotionControllerActive() || g_pInputSystem->IsSteamControllerActive() ) #endif { if ( cmd->forwardmove > 0 ) { cmd->buttons |= IN_FORWARD; } else if ( cmd->forwardmove < 0 ) { cmd->buttons |= IN_BACK; } } // Use new view angles if alive, otherwise user last angles we stored off. VectorCopy( viewangles, cmd->viewangles ); VectorCopy( viewangles, GetPerUser( nSlot ).m_angPreviousViewAngles ); // Let the move manager override anything it wants to. if ( GetClientMode()->CreateMove( input_sample_frametime, cmd ) ) { // Get current view angles after the client mode tweaks with it #ifdef SIXENSE // Only set the engine angles if sixense is not enabled. It is done in SixenseInput::SetView otherwise. if( !g_pSixenseInput->IsEnabled() ) { engine->SetViewAngles( cmd->viewangles ); } #else engine->SetViewAngles( cmd->viewangles ); #endif } CheckPaused( cmd ); CUserCmd *pPlayer0Command = &m_PerUser[ 0 ].m_pCommands[ sequence_number % MULTIPLAYER_BACKUP ]; CheckSplitScreenMimic( nSlot, cmd, pPlayer0Command ); GetPerUser( nSlot ).m_flLastForwardMove = cmd->forwardmove; cmd->random_seed = MD5_PseudoRandom( sequence_number ) & 0x7fffffff; HLTVCamera()->CreateMove( cmd ); #if defined( REPLAY_ENABLED ) ReplayCamera()->CreateMove( cmd ); #endif #if defined( HL2_CLIENT_DLL ) // copy backchannel data int i; for (i = 0; i < GetPerUser( nSlot ).m_EntityGroundContact.Count(); i++) { cmd->entitygroundcontact.AddToTail( GetPerUser().m_EntityGroundContact[i] ); } GetPerUser( nSlot ).m_EntityGroundContact.RemoveAll(); #endif pVerified->m_cmd = *cmd; pVerified->m_crc = cmd->GetChecksum(); } void CInput::CheckSplitScreenMimic( int nSlot, CUserCmd *cmd, CUserCmd *pPlayer0Command ) { // ss_mimic 2 is more of a "follow" mode int nMimicMode = ss_mimic.GetInt(); if ( nMimicMode <= 0 || nSlot == 0 ) return; *cmd = *pPlayer0Command; // We can't copy these over, since we send the weapon index it'll make the server attach the weapon to the other split screen player, even // though he doesn't own it!!! cmd->weaponsubtype = 0; cmd->weaponselect = 0; // Get current view angles after the client mode tweaks with it engine->SetViewAngles( cmd->viewangles ); int nLeader = ( nSlot + 1 ) % MAX_SPLITSCREEN_PLAYERS; C_BasePlayer *pLeader = C_BasePlayer::GetLocalPlayer( nLeader ); C_BasePlayer *pFollower = C_BasePlayer::GetLocalPlayer( nSlot ); if ( !pLeader || !pFollower ) return; Vector leaderPos = pLeader->GetAbsOrigin(); Vector followerPos = pFollower->GetAbsOrigin(); float flFarDist = 256.0f * 256.0f; float flNearDist = 64.0f * 64.0f; Vector delta = leaderPos - followerPos; float flLength2DSqr = delta.Length2DSqr(); if ( flLength2DSqr > flFarDist ) { SplitScreenTeleport( nLeader ); } else if ( flLength2DSqr > flNearDist ) { // Run toward other guy cmd->buttons &= ~( IN_FORWARD | IN_BACK | IN_MOVELEFT | IN_MOVERIGHT ); Vector lookDir; Vector rightDir; AngleVectors( cmd->viewangles, &lookDir, &rightDir, NULL ); lookDir.z = 0.0f; lookDir.NormalizeInPlace(); Vector moveDir = delta; moveDir.z = 0.0f; moveDir.NormalizeInPlace(); // This is the cos of the angle between them float fdot = lookDir.Dot( moveDir ); float rdot = rightDir.Dot( moveDir ); cmd->forwardmove = fdot * cl_forwardspeed.GetFloat(); cmd->sidemove = rdot * cl_sidespeed.GetFloat(); // We'll only be moving fwd or sideways cmd->upmove = 0.0f; if ( cmd->forwardmove > 0.0f ) { cmd->buttons |= IN_FORWARD; } else if ( cmd->forwardmove < 0.0f ) { cmd->buttons |= IN_BACK; } if ( cmd->sidemove > 0.0f ) { cmd->buttons |= IN_MOVELEFT; } else if ( cmd->sidemove < 0.0f ) { cmd->buttons |= IN_MOVERIGHT; } } else { // Stop movement buttons cmd->forwardmove = cmd->sidemove = cmd->upmove = 0.0f; cmd->buttons &= ~( IN_FORWARD | IN_BACK | IN_MOVELEFT | IN_MOVERIGHT ); } } void CInput::CheckPaused( CUserCmd *cmd ) { if ( !engine->IsPaused() ) return; cmd->buttons = 0; cmd->forwardmove = 0; cmd->sidemove = 0; cmd->upmove = 0; // Don't allow changing weapons while paused cmd->weaponselect = 0; } //----------------------------------------------------------------------------- // Purpose: // Input : buf - // buffersize - // slot - //----------------------------------------------------------------------------- void CInput::EncodeUserCmdToBuffer( int nSlot, bf_write& buf, int sequence_number ) { CUserCmd nullcmd; CUserCmd *cmd = GetUserCmd( nSlot, sequence_number); WriteUsercmd( &buf, cmd, &nullcmd ); } //----------------------------------------------------------------------------- // Purpose: // Input : buf - // buffersize - // slot - //----------------------------------------------------------------------------- void CInput::DecodeUserCmdFromBuffer( int nSlot, bf_read& buf, int sequence_number ) { CUserCmd nullcmd; CUserCmd *cmd = &GetPerUser( nSlot ).m_pCommands[ sequence_number % MULTIPLAYER_BACKUP ]; ReadUsercmd( &buf, cmd, &nullcmd ); } void CInput::ValidateUserCmd( CUserCmd *usercmd, int sequence_number ) { // Validate that the usercmd hasn't been changed CRC32_t crc = usercmd->GetChecksum(); if ( crc != GetPerUser().m_pVerifiedCommands[ sequence_number % MULTIPLAYER_BACKUP ].m_crc ) { *usercmd = GetPerUser().m_pVerifiedCommands[ sequence_number % MULTIPLAYER_BACKUP ].m_cmd; } } //----------------------------------------------------------------------------- // Purpose: // Input : *buf - // from - // to - //----------------------------------------------------------------------------- bool CInput::WriteUsercmdDeltaToBuffer( int nSlot, bf_write *buf, int from, int to, bool isnewcommand ) { Assert( GetPerUser( nSlot ).m_pCommands ); CUserCmd nullcmd; CUserCmd *f, *t; int startbit; startbit = buf->GetNumBitsWritten(); if ( from == -1 ) { f = &nullcmd; } else { f = GetUserCmd( nSlot, from ); if ( !f ) { // DevMsg( "WARNING! User command delta too old (from %i, to %i)\n", from, to ); f = &nullcmd; } else { ValidateUserCmd( f, from ); } } t = GetUserCmd( nSlot, to ); if ( !t ) { // DevMsg( "WARNING! User command too old (from %i, to %i)\n", from, to ); t = &nullcmd; } else { ValidateUserCmd( t, to ); } // Write it into the buffer WriteUsercmd( buf, t, f ); if ( buf->IsOverflowed() ) { int endbit; endbit = buf->GetNumBitsWritten(); Msg( "WARNING! User command buffer overflow(%i %i), last cmd was %i bits long\n", from, to, endbit - startbit ); return false; } return true; } //----------------------------------------------------------------------------- // Purpose: // Input : slot - // Output : CUserCmd //----------------------------------------------------------------------------- CUserCmd *CInput::GetUserCmd( int nSlot, int sequence_number ) { Assert( GetPerUser( nSlot ).m_pCommands ); CUserCmd *usercmd = &GetPerUser( nSlot ).m_pCommands[ sequence_number % MULTIPLAYER_BACKUP ]; if ( usercmd->command_number != sequence_number ) { return NULL; // usercmd was overwritten by newer command } return usercmd; } //----------------------------------------------------------------------------- // Purpose: // Input : bits - // in_button - // in_ignore - // *button - // reset - // Output : static void //----------------------------------------------------------------------------- static void CalcButtonBits( int nSlot, int& bits, int in_button, int in_ignore, kbutton_t *button, bool reset ) { kbutton_t::Split_t *pButtonState = &button->GetPerUser( nSlot ); // Down or still down? if ( pButtonState->state & 3 ) { bits |= in_button; } int clearmask = ~2; if ( in_ignore & in_button ) { // This gets taken care of below in the GetButtonBits code //bits &= ~in_button; // Remove "still down" as well as "just down" clearmask = ~3; } if ( reset ) { pButtonState->state &= clearmask; } } /* ============ GetButtonBits Returns appropriate button info for keyboard and mouse state Set bResetState to 1 to clear old state info ============ */ int CInput::GetButtonBits( bool bResetState ) { ASSERT_LOCAL_PLAYER_RESOLVABLE(); int nSlot = GET_ACTIVE_SPLITSCREEN_SLOT(); int bits = 0; int ignore = GetPerUser( nSlot ).m_nClearInputState; CalcButtonBits( nSlot, bits, IN_SPEED, ignore, &in_speed, bResetState ); CalcButtonBits( nSlot, bits, IN_WALK, ignore, &in_walk, bResetState ); CalcButtonBits( nSlot, bits, IN_ATTACK, ignore, &in_attack, bResetState ); CalcButtonBits( nSlot, bits, IN_DUCK, ignore, &in_duck, bResetState ); CalcButtonBits( nSlot, bits, IN_JUMP, ignore, &in_jump, bResetState ); CalcButtonBits( nSlot, bits, IN_FORWARD, ignore, &in_forward, bResetState ); CalcButtonBits( nSlot, bits, IN_BACK, ignore, &in_back, bResetState ); CalcButtonBits( nSlot, bits, IN_USE, ignore, &in_use, bResetState ); CalcButtonBits( nSlot, bits, IN_LEFT, ignore, &in_left, bResetState ); CalcButtonBits( nSlot, bits, IN_RIGHT, ignore, &in_right, bResetState ); CalcButtonBits( nSlot, bits, IN_MOVELEFT, ignore, &in_moveleft, bResetState ); CalcButtonBits( nSlot, bits, IN_MOVERIGHT, ignore, &in_moveright, bResetState ); CalcButtonBits( nSlot, bits, IN_ATTACK2, ignore, &in_attack2, bResetState ); CalcButtonBits( nSlot, bits, IN_RELOAD, ignore, &in_reload, bResetState ); CalcButtonBits( nSlot, bits, IN_ALT1, ignore, &in_alt1, bResetState ); CalcButtonBits( nSlot, bits, IN_ALT2, ignore, &in_alt2, bResetState ); CalcButtonBits( nSlot, bits, IN_SCORE, ignore, &in_score, bResetState ); CalcButtonBits( nSlot, bits, IN_ZOOM, ignore, &in_zoom, bResetState ); CalcButtonBits( nSlot, bits, IN_GRENADE1, ignore, &in_grenade1, bResetState ); CalcButtonBits( nSlot, bits, IN_GRENADE2, ignore, &in_grenade2, bResetState ); CalcButtonBits( nSlot, bits, IN_LOOKSPIN, ignore, &in_lookspin, bResetState ); #ifdef PORTAL2 #if USE_SLOWTIME CalcButtonBits( nSlot, bits, IN_SLOWTIME, ignore, &in_slowtoggle, bResetState ); #endif // USE_SLOWTIME CalcButtonBits( nSlot, bits, IN_COOP_PING, ignore, &in_coop_ping, bResetState ); CalcButtonBits( nSlot, bits, IN_REMOTE_VIEW, ignore, &in_remote_view_toggle, bResetState ); #endif // PORTAL2 #ifdef INFESTED_DLL CalcButtonBits( nSlot, bits, IN_PREV_ABILITY, ignore, &in_prevability, bResetState ); CalcButtonBits( nSlot, bits, IN_NEXT_ABILITY, ignore, &in_nextability, bResetState ); CalcButtonBits( nSlot, bits, IN_CURRENT_ABILITY, ignore, &in_currentability, bResetState ); CalcButtonBits( nSlot, bits, IN_ABILITY1, ignore, &in_ability1, bResetState ); CalcButtonBits( nSlot, bits, IN_ABILITY2, ignore, &in_ability2, bResetState ); CalcButtonBits( nSlot, bits, IN_ABILITY3, ignore, &in_ability3, bResetState ); CalcButtonBits( nSlot, bits, IN_ABILITY4, ignore, &in_ability4, bResetState ); CalcButtonBits( nSlot, bits, IN_ABILITY5, ignore, &in_ability5, bResetState ); #endif if ( KeyState(&in_ducktoggle) ) { bits |= IN_DUCK; } // dkorus: handle the toggle OR the joystick feature to force a move speed when going slow if ( KeyState(&in_speedtoggle) || joystick_forced_speed ) { bits |= IN_SPEED; } if ( in_cancel[ nSlot ] ) { bits |= IN_CANCEL; } if ( GetHud( nSlot ).m_iKeyBits & IN_WEAPON1 ) { bits |= IN_WEAPON1; } if ( GetHud( nSlot ).m_iKeyBits & IN_WEAPON2 ) { bits |= IN_WEAPON2; } // Clear out any residual bits &= ~ignore; if ( bResetState ) { GetPerUser( nSlot ).m_nClearInputState = 0; } return bits; } //----------------------------------------------------------------------------- // Causes an input to have to be re-pressed to become active //----------------------------------------------------------------------------- void CInput::ClearInputButton( int bits ) { ASSERT_LOCAL_PLAYER_RESOLVABLE(); if ( GET_ACTIVE_SPLITSCREEN_SLOT() != in_forceuser.GetInt() ) { return; } GetPerUser().m_nClearInputState |= bits; } /* ============================== GetLookSpring ============================== */ float CInput::GetLookSpring( void ) { return lookspring.GetInt(); } //----------------------------------------------------------------------------- // Purpose: // Output : float //----------------------------------------------------------------------------- float CInput::GetLastForwardMove( void ) { return GetPerUser().m_flLastForwardMove; } #if defined( HL2_CLIENT_DLL ) //----------------------------------------------------------------------------- // Purpose: back channel contact info for ground contact // Output : //----------------------------------------------------------------------------- void CInput::AddIKGroundContactInfo( int entindex, float minheight, float maxheight ) { CEntityGroundContact data; data.entindex = entindex; data.minheight = minheight; data.maxheight = maxheight; AUTO_LOCK_FM( m_IKContactPointMutex ); // These all route through the main player's slot!!! ACTIVE_SPLITSCREEN_PLAYER_GUARD( 0 ); if ( m_PerUser[ 0 ].m_EntityGroundContact.Count() >= MAX_EDICTS ) { // some overflow here, probably bogus anyway AssertOnce( "CInput::AddIKGroundContactInfo: Overflow!!!" ); m_PerUser[ 0 ].m_EntityGroundContact.RemoveAll(); return; } m_PerUser[ 0 ].m_EntityGroundContact.AddToTail( data ); } #endif static ConCommand startcommandermousemove("+commandermousemove", IN_CommanderMouseMoveDown); static ConCommand endcommandermousemove("-commandermousemove", IN_CommanderMouseMoveUp); static ConCommand startmoveup("+moveup",IN_UpDown); static ConCommand endmoveup("-moveup",IN_UpUp); static ConCommand startmovedown("+movedown",IN_DownDown); static ConCommand endmovedown("-movedown",IN_DownUp); static ConCommand startleft("+left",IN_LeftDown); static ConCommand endleft("-left",IN_LeftUp); static ConCommand startright("+right",IN_RightDown); static ConCommand endright("-right",IN_RightUp); static ConCommand startforward("+forward",IN_ForwardDown); static ConCommand endforward("-forward",IN_ForwardUp); static ConCommand startback("+back",IN_BackDown); static ConCommand endback("-back",IN_BackUp); static ConCommand startlookup("+lookup", IN_LookupDown); static ConCommand endlookup("-lookup", IN_LookupUp); static ConCommand startlookdown("+lookdown", IN_LookdownDown); static ConCommand lookdown("-lookdown", IN_LookdownUp); static ConCommand startstrafe("+strafe", IN_StrafeDown); static ConCommand endstrafe("-strafe", IN_StrafeUp); static ConCommand startmoveleft("+moveleft", IN_MoveleftDown); static ConCommand endmoveleft("-moveleft", IN_MoveleftUp); static ConCommand startmoveright("+moveright", IN_MoverightDown); static ConCommand endmoveright("-moveright", IN_MoverightUp); static ConCommand startspeed("+speed", IN_SpeedDown); static ConCommand endspeed("-speed", IN_SpeedUp); static ConCommand startwalk("+walk", IN_WalkDown); static ConCommand endwalk("-walk", IN_WalkUp); static ConCommand startattack("+attack", IN_AttackDown); static ConCommand endattack("-attack", IN_AttackUp); static ConCommand startattack2("+attack2", IN_Attack2Down); static ConCommand endattack2("-attack2", IN_Attack2Up); static ConCommand startuse("+use", IN_UseDown); static ConCommand enduse("-use", IN_UseUp); static ConCommand startjump("+jump", IN_JumpDown); static ConCommand endjump("-jump", IN_JumpUp); static ConCommand impulse("impulse", IN_Impulse); static ConCommand startklook("+klook", IN_KLookDown); static ConCommand endklook("-klook", IN_KLookUp); static ConCommand startjlook("+jlook", IN_JLookDown); static ConCommand endjlook("-jlook", IN_JLookUp); static ConCommand startduck("+duck", IN_DuckDown); static ConCommand endduck("-duck", IN_DuckUp); static ConCommand startreload("+reload", IN_ReloadDown); static ConCommand endreload("-reload", IN_ReloadUp); static ConCommand startalt1("+alt1", IN_Alt1Down); static ConCommand endalt1("-alt1", IN_Alt1Up); static ConCommand startalt2("+alt2", IN_Alt2Down); static ConCommand endalt2("-alt2", IN_Alt2Up); static ConCommand startscore("+score", IN_ScoreDown); static ConCommand endscore("-score", IN_ScoreUp); static ConCommand startshowscores("+showscores", IN_ScoreDown); static ConCommand endshowscores("-showscores", IN_ScoreUp); static ConCommand startgraph("+graph", IN_GraphDown); static ConCommand endgraph("-graph", IN_GraphUp); static ConCommand startbreak("+break",IN_BreakDown); static ConCommand endbreak("-break",IN_BreakUp); static ConCommand force_centerview("force_centerview", IN_CenterView_f); static ConCommand joyadvancedupdate("joyadvancedupdate", IN_Joystick_Advanced_f, "", FCVAR_CLIENTCMD_CAN_EXECUTE); static ConCommand startzoom("+zoom", IN_ZoomDown); static ConCommand endzoom("-zoom", IN_ZoomUp); static ConCommand startzoomin("+zoom_in", IN_ZoomInDown); static ConCommand endzoomin("-zoom_in", IN_ZoomInUp); static ConCommand startzoomout("+zoom_out", IN_ZoomOutDown); static ConCommand endzoomout("-zoom_out", IN_ZoomOutUp); static ConCommand endgrenade1( "-grenade1", IN_Grenade1Up ); static ConCommand startgrenade1( "+grenade1", IN_Grenade1Down ); static ConCommand endgrenade2( "-grenade2", IN_Grenade2Up ); static ConCommand startgrenade2( "+grenade2", IN_Grenade2Down ); static ConCommand startlookspin("+lookspin", IN_LookSpinDown); static ConCommand endlookspin("-lookspin", IN_LookSpinUp); static ConCommand toggle_duck( "toggle_duck", IN_DuckToggle ); #ifdef INFESTED_DLL static ConCommand endprevability( "-prevability", IN_PrevAbilityUp ); static ConCommand startprevability( "+prevability", IN_PrevAbilityDown ); static ConCommand endnextability( "-nextability", IN_NextAbilityUp ); static ConCommand startnextability( "+nextability", IN_NextAbilityDown ); static ConCommand endcurrentability( "-currentability", IN_CurrentAbilityUp ); static ConCommand startcurrentability( "+currentability", IN_CurrentAbilityDown ); static ConCommand endability1( "-ability1", IN_Ability1Up ); static ConCommand startability1( "+ability1", IN_Ability1Down ); static ConCommand endability2( "-ability2", IN_Ability2Up ); static ConCommand startability2( "+ability2", IN_Ability2Down ); static ConCommand endability3( "-ability3", IN_Ability3Up ); static ConCommand startability3( "+ability3", IN_Ability3Down ); static ConCommand endability4( "-ability4", IN_Ability4Up ); static ConCommand startability4( "+ability4", IN_Ability4Down ); static ConCommand endability5( "-ability5", IN_Ability5Up ); static ConCommand startability5( "+ability5", IN_Ability5Down ); #endif // Xbox 360 stub commands static ConCommand xboxmove("xmove", IN_XboxStub); static ConCommand xboxlook("xlook", IN_XboxStub); /* ============ Init_All ============ */ void CInput::Init_All (void) { InitMouse( ); m_hInputContext = engine->GetInputContext( ENGINE_INPUT_CONTEXT_GAME ); for ( int i = 0; i < MAX_SPLITSCREEN_PLAYERS; ++i ) { Assert( !m_PerUser[ i ].m_pCommands ); Assert( !m_PerUser[ i ].m_pVerifiedCommands ); m_PerUser[ i ].m_pCommands = new CUserCmd[ MULTIPLAYER_BACKUP ]; m_PerUser[ i ].m_pVerifiedCommands = new CVerifiedUserCmd[ MULTIPLAYER_BACKUP ]; } m_fMouseInitialized = false; m_fRestoreSPI = false; m_fMouseActive = false; Q_memset( m_rgOrigMouseParms, 0, sizeof( m_rgOrigMouseParms ) ); Q_memset( m_rgNewMouseParms, 0, sizeof( m_rgNewMouseParms ) ); Q_memset( m_rgCheckMouseParam, 0, sizeof( m_rgCheckMouseParam ) ); m_rgNewMouseParms[ MOUSE_ACCEL_THRESHHOLD1 ] = 0; // no 2x m_rgNewMouseParms[ MOUSE_ACCEL_THRESHHOLD2 ] = 0; // no 4x m_rgNewMouseParms[ MOUSE_SPEED_FACTOR ] = 1; // 0 = disabled, 1 = threshold 1 enabled, 2 = threshold 2 enabled m_fMouseParmsValid = false; m_fJoystickAdvancedInit = false; m_bControllerMode = !IsPC(); m_fAccumulatedMouseMove = 0.0f; m_lastAutoAimValue = 1.0f; // Initialize inputs if ( IsPC() || IsPlatformPS3() ) { Init_Mouse (); Init_Keyboard(); } // Initialize third person camera controls. Init_Camera(); } /* ============ Shutdown_All ============ */ void CInput::Shutdown_All(void) { DeactivateMouse(); Shutdown_Keyboard(); for ( int i = 0; i < MAX_SPLITSCREEN_PLAYERS; ++i ) { delete[] m_PerUser[ i ].m_pCommands; m_PerUser[ i ].m_pCommands = NULL; delete[] m_PerUser[ i ].m_pVerifiedCommands; m_PerUser[ i ].m_pVerifiedCommands = NULL; } } void CInput::LevelInit( void ) { #if defined( HL2_CLIENT_DLL ) // Remove any IK information for ( int i = 0; i < MAX_SPLITSCREEN_PLAYERS; ++i ) { ACTIVE_SPLITSCREEN_PLAYER_GUARD( i ); GetPerUser().m_EntityGroundContact.RemoveAll(); } #endif }