diff options
| author | Jørgen P. Tjernø <[email protected]> | 2013-12-02 19:31:46 -0800 |
|---|---|---|
| committer | Jørgen P. Tjernø <[email protected]> | 2013-12-02 19:46:31 -0800 |
| commit | f56bb35301836e56582a575a75864392a0177875 (patch) | |
| tree | de61ddd39de3e7df52759711950b4c288592f0dc /mp/src/game/client/c_baseplayer.cpp | |
| parent | Mark some more files as text. (diff) | |
| download | source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.tar.xz source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.zip | |
Fix line endings. WHAMMY.
Diffstat (limited to 'mp/src/game/client/c_baseplayer.cpp')
| -rw-r--r-- | mp/src/game/client/c_baseplayer.cpp | 5968 |
1 files changed, 2984 insertions, 2984 deletions
diff --git a/mp/src/game/client/c_baseplayer.cpp b/mp/src/game/client/c_baseplayer.cpp index 74c12bbc..3b1ac003 100644 --- a/mp/src/game/client/c_baseplayer.cpp +++ b/mp/src/game/client/c_baseplayer.cpp @@ -1,2984 +1,2984 @@ -//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose: Client-side CBasePlayer.
-//
-// - Manages the player's flashlight effect.
-//
-//===========================================================================//
-#include "cbase.h"
-#include "c_baseplayer.h"
-#include "flashlighteffect.h"
-#include "weapon_selection.h"
-#include "history_resource.h"
-#include "iinput.h"
-#include "input.h"
-#include "view.h"
-#include "iviewrender.h"
-#include "iclientmode.h"
-#include "in_buttons.h"
-#include "engine/IEngineSound.h"
-#include "c_soundscape.h"
-#include "usercmd.h"
-#include "c_playerresource.h"
-#include "iclientvehicle.h"
-#include "view_shared.h"
-#include "movevars_shared.h"
-#include "prediction.h"
-#include "tier0/vprof.h"
-#include "filesystem.h"
-#include "bitbuf.h"
-#include "KeyValues.h"
-#include "particles_simple.h"
-#include "fx_water.h"
-#include "hltvcamera.h"
-#include "toolframework/itoolframework.h"
-#include "toolframework_client.h"
-#include "view_scene.h"
-#include "c_vguiscreen.h"
-#include "datacache/imdlcache.h"
-#include "vgui/ISurface.h"
-#include "voice_status.h"
-#include "fx.h"
-#include "dt_utlvector_recv.h"
-#include "cam_thirdperson.h"
-#if defined( REPLAY_ENABLED )
-#include "replay/replaycamera.h"
-#include "replay/ireplaysystem.h"
-#include "replay/ienginereplay.h"
-#endif
-#include "steam/steam_api.h"
-#include "headtrack/isourcevirtualreality.h"
-#include "client_virtualreality.h"
-
-#if defined USES_ECON_ITEMS
-#include "econ_wearable.h"
-#endif
-
-// NVNT haptics system interface
-#include "haptics/ihaptics.h"
-
-// memdbgon must be the last include file in a .cpp file!!!
-#include "tier0/memdbgon.h"
-
-// Don't alias here
-#if defined( CBasePlayer )
-#undef CBasePlayer
-#endif
-
-int g_nKillCamMode = OBS_MODE_NONE;
-int g_nKillCamTarget1 = 0;
-int g_nKillCamTarget2 = 0;
-
-extern ConVar mp_forcecamera; // in gamevars_shared.h
-
-#define FLASHLIGHT_DISTANCE 1000
-#define MAX_VGUI_INPUT_MODE_SPEED 30
-#define MAX_VGUI_INPUT_MODE_SPEED_SQ (MAX_VGUI_INPUT_MODE_SPEED*MAX_VGUI_INPUT_MODE_SPEED)
-
-static Vector WALL_MIN(-WALL_OFFSET,-WALL_OFFSET,-WALL_OFFSET);
-static Vector WALL_MAX(WALL_OFFSET,WALL_OFFSET,WALL_OFFSET);
-
-bool CommentaryModeShouldSwallowInput( C_BasePlayer *pPlayer );
-
-extern ConVar default_fov;
-#ifndef _XBOX
-extern ConVar sensitivity;
-#endif
-
-static C_BasePlayer *s_pLocalPlayer = NULL;
-
-static ConVar cl_customsounds ( "cl_customsounds", "0", 0, "Enable customized player sound playback" );
-static ConVar spec_track ( "spec_track", "0", 0, "Tracks an entity in spec mode" );
-static ConVar cl_smooth ( "cl_smooth", "1", 0, "Smooth view/eye origin after prediction errors" );
-static ConVar cl_smoothtime (
- "cl_smoothtime",
- "0.1",
- 0,
- "Smooth client's view after prediction error over this many seconds",
- true, 0.01, // min/max is 0.01/2.0
- true, 2.0
- );
-
-#ifdef CSTRIKE_DLL
-ConVar spec_freeze_time( "spec_freeze_time", "5.0", FCVAR_CHEAT | FCVAR_REPLICATED, "Time spend frozen in observer freeze cam." );
-ConVar spec_freeze_traveltime( "spec_freeze_traveltime", "0.7", FCVAR_CHEAT | FCVAR_REPLICATED, "Time taken to zoom in to frame a target in observer freeze cam.", true, 0.01, false, 0 );
-ConVar spec_freeze_distance_min( "spec_freeze_distance_min", "80", FCVAR_CHEAT, "Minimum random distance from the target to stop when framing them in observer freeze cam." );
-ConVar spec_freeze_distance_max( "spec_freeze_distance_max", "90", FCVAR_CHEAT, "Maximum random distance from the target to stop when framing them in observer freeze cam." );
-#else
-ConVar spec_freeze_time( "spec_freeze_time", "4.0", FCVAR_CHEAT | FCVAR_REPLICATED, "Time spend frozen in observer freeze cam." );
-ConVar spec_freeze_traveltime( "spec_freeze_traveltime", "0.4", FCVAR_CHEAT | FCVAR_REPLICATED, "Time taken to zoom in to frame a target in observer freeze cam.", true, 0.01, false, 0 );
-ConVar spec_freeze_distance_min( "spec_freeze_distance_min", "96", FCVAR_CHEAT, "Minimum random distance from the target to stop when framing them in observer freeze cam." );
-ConVar spec_freeze_distance_max( "spec_freeze_distance_max", "200", FCVAR_CHEAT, "Maximum random distance from the target to stop when framing them in observer freeze cam." );
-#endif
-
-static ConVar cl_first_person_uses_world_model ( "cl_first_person_uses_world_model", "0", FCVAR_ARCHIVE, "Causes the third person model to be drawn instead of the view model" );
-
-ConVar demo_fov_override( "demo_fov_override", "0", FCVAR_CLIENTDLL | FCVAR_DONTRECORD, "If nonzero, this value will be used to override FOV during demo playback." );
-
-void RecvProxy_LocalVelocityX( const CRecvProxyData *pData, void *pStruct, void *pOut );
-void RecvProxy_LocalVelocityY( const CRecvProxyData *pData, void *pStruct, void *pOut );
-void RecvProxy_LocalVelocityZ( const CRecvProxyData *pData, void *pStruct, void *pOut );
-
-void RecvProxy_ObserverTarget( const CRecvProxyData *pData, void *pStruct, void *pOut );
-void RecvProxy_ObserverMode ( const CRecvProxyData *pData, void *pStruct, void *pOut );
-
-// -------------------------------------------------------------------------------- //
-// RecvTable for CPlayerState.
-// -------------------------------------------------------------------------------- //
-
- BEGIN_RECV_TABLE_NOBASE(CPlayerState, DT_PlayerState)
- RecvPropInt (RECVINFO(deadflag)),
- END_RECV_TABLE()
-
-
-BEGIN_RECV_TABLE_NOBASE( CPlayerLocalData, DT_Local )
- RecvPropArray3( RECVINFO_ARRAY(m_chAreaBits), RecvPropInt(RECVINFO(m_chAreaBits[0]))),
- RecvPropArray3( RECVINFO_ARRAY(m_chAreaPortalBits), RecvPropInt(RECVINFO(m_chAreaPortalBits[0]))),
- RecvPropInt(RECVINFO(m_iHideHUD)),
-
- // View
-
- RecvPropFloat(RECVINFO(m_flFOVRate)),
-
- RecvPropInt (RECVINFO(m_bDucked)),
- RecvPropInt (RECVINFO(m_bDucking)),
- RecvPropInt (RECVINFO(m_bInDuckJump)),
- RecvPropFloat (RECVINFO(m_flDucktime)),
- RecvPropFloat (RECVINFO(m_flDuckJumpTime)),
- RecvPropFloat (RECVINFO(m_flJumpTime)),
- RecvPropFloat (RECVINFO(m_flFallVelocity)),
-
-#if PREDICTION_ERROR_CHECK_LEVEL > 1
- RecvPropFloat (RECVINFO_NAME( m_vecPunchAngle.m_Value[0], m_vecPunchAngle[0])),
- RecvPropFloat (RECVINFO_NAME( m_vecPunchAngle.m_Value[1], m_vecPunchAngle[1])),
- RecvPropFloat (RECVINFO_NAME( m_vecPunchAngle.m_Value[2], m_vecPunchAngle[2] )),
- RecvPropFloat (RECVINFO_NAME( m_vecPunchAngleVel.m_Value[0], m_vecPunchAngleVel[0] )),
- RecvPropFloat (RECVINFO_NAME( m_vecPunchAngleVel.m_Value[1], m_vecPunchAngleVel[1] )),
- RecvPropFloat (RECVINFO_NAME( m_vecPunchAngleVel.m_Value[2], m_vecPunchAngleVel[2] )),
-#else
- RecvPropVector (RECVINFO(m_vecPunchAngle)),
- RecvPropVector (RECVINFO(m_vecPunchAngleVel)),
-#endif
-
- RecvPropInt (RECVINFO(m_bDrawViewmodel)),
- RecvPropInt (RECVINFO(m_bWearingSuit)),
- RecvPropBool (RECVINFO(m_bPoisoned)),
- RecvPropFloat (RECVINFO(m_flStepSize)),
- RecvPropInt (RECVINFO(m_bAllowAutoMovement)),
-
- // 3d skybox data
- RecvPropInt(RECVINFO(m_skybox3d.scale)),
- RecvPropVector(RECVINFO(m_skybox3d.origin)),
- RecvPropInt(RECVINFO(m_skybox3d.area)),
-
- // 3d skybox fog data
- RecvPropInt( RECVINFO( m_skybox3d.fog.enable ) ),
- RecvPropInt( RECVINFO( m_skybox3d.fog.blend ) ),
- RecvPropVector( RECVINFO( m_skybox3d.fog.dirPrimary ) ),
- RecvPropInt( RECVINFO( m_skybox3d.fog.colorPrimary ) ),
- RecvPropInt( RECVINFO( m_skybox3d.fog.colorSecondary ) ),
- RecvPropFloat( RECVINFO( m_skybox3d.fog.start ) ),
- RecvPropFloat( RECVINFO( m_skybox3d.fog.end ) ),
- RecvPropFloat( RECVINFO( m_skybox3d.fog.maxdensity ) ),
-
- // fog data
- RecvPropEHandle( RECVINFO( m_PlayerFog.m_hCtrl ) ),
-
- // audio data
- RecvPropVector( RECVINFO( m_audio.localSound[0] ) ),
- RecvPropVector( RECVINFO( m_audio.localSound[1] ) ),
- RecvPropVector( RECVINFO( m_audio.localSound[2] ) ),
- RecvPropVector( RECVINFO( m_audio.localSound[3] ) ),
- RecvPropVector( RECVINFO( m_audio.localSound[4] ) ),
- RecvPropVector( RECVINFO( m_audio.localSound[5] ) ),
- RecvPropVector( RECVINFO( m_audio.localSound[6] ) ),
- RecvPropVector( RECVINFO( m_audio.localSound[7] ) ),
- RecvPropInt( RECVINFO( m_audio.soundscapeIndex ) ),
- RecvPropInt( RECVINFO( m_audio.localBits ) ),
- RecvPropEHandle( RECVINFO( m_audio.ent ) ),
-END_RECV_TABLE()
-
-// -------------------------------------------------------------------------------- //
-// This data only gets sent to clients that ARE this player entity.
-// -------------------------------------------------------------------------------- //
-
- BEGIN_RECV_TABLE_NOBASE( C_BasePlayer, DT_LocalPlayerExclusive )
-
- RecvPropDataTable ( RECVINFO_DT(m_Local),0, &REFERENCE_RECV_TABLE(DT_Local) ),
-
- RecvPropFloat ( RECVINFO(m_vecViewOffset[0]) ),
- RecvPropFloat ( RECVINFO(m_vecViewOffset[1]) ),
- RecvPropFloat ( RECVINFO(m_vecViewOffset[2]) ),
- RecvPropFloat ( RECVINFO(m_flFriction) ),
-
- RecvPropArray3 ( RECVINFO_ARRAY(m_iAmmo), RecvPropInt( RECVINFO(m_iAmmo[0])) ),
-
- RecvPropInt ( RECVINFO(m_fOnTarget) ),
-
- RecvPropInt ( RECVINFO( m_nTickBase ) ),
- RecvPropInt ( RECVINFO( m_nNextThinkTick ) ),
-
- RecvPropEHandle ( RECVINFO( m_hLastWeapon ) ),
- RecvPropEHandle ( RECVINFO( m_hGroundEntity ) ),
-
- RecvPropFloat ( RECVINFO(m_vecVelocity[0]), 0, RecvProxy_LocalVelocityX ),
- RecvPropFloat ( RECVINFO(m_vecVelocity[1]), 0, RecvProxy_LocalVelocityY ),
- RecvPropFloat ( RECVINFO(m_vecVelocity[2]), 0, RecvProxy_LocalVelocityZ ),
-
- RecvPropVector ( RECVINFO( m_vecBaseVelocity ) ),
-
- RecvPropEHandle ( RECVINFO( m_hConstraintEntity)),
- RecvPropVector ( RECVINFO( m_vecConstraintCenter) ),
- RecvPropFloat ( RECVINFO( m_flConstraintRadius )),
- RecvPropFloat ( RECVINFO( m_flConstraintWidth )),
- RecvPropFloat ( RECVINFO( m_flConstraintSpeedFactor )),
-
- RecvPropFloat ( RECVINFO( m_flDeathTime )),
-
- RecvPropInt ( RECVINFO( m_nWaterLevel ) ),
- RecvPropFloat ( RECVINFO( m_flLaggedMovementValue )),
-
- END_RECV_TABLE()
-
-
-// -------------------------------------------------------------------------------- //
-// DT_BasePlayer datatable.
-// -------------------------------------------------------------------------------- //
-
-#if defined USES_ECON_ITEMS
- EXTERN_RECV_TABLE(DT_AttributeList);
-#endif
-
- IMPLEMENT_CLIENTCLASS_DT(C_BasePlayer, DT_BasePlayer, CBasePlayer)
- // We have both the local and nonlocal data in here, but the server proxies
- // only send one.
- RecvPropDataTable( "localdata", 0, 0, &REFERENCE_RECV_TABLE(DT_LocalPlayerExclusive) ),
-
-#if defined USES_ECON_ITEMS
- RecvPropDataTable(RECVINFO_DT(m_AttributeList),0, &REFERENCE_RECV_TABLE(DT_AttributeList) ),
-#endif
-
- RecvPropDataTable(RECVINFO_DT(pl), 0, &REFERENCE_RECV_TABLE(DT_PlayerState), DataTableRecvProxy_StaticDataTable),
-
- RecvPropInt (RECVINFO(m_iFOV)),
- RecvPropInt (RECVINFO(m_iFOVStart)),
- RecvPropFloat (RECVINFO(m_flFOVTime)),
- RecvPropInt (RECVINFO(m_iDefaultFOV)),
- RecvPropEHandle (RECVINFO(m_hZoomOwner)),
-
- RecvPropEHandle( RECVINFO(m_hVehicle) ),
- RecvPropEHandle( RECVINFO(m_hUseEntity) ),
-
- RecvPropInt (RECVINFO(m_iHealth)),
- RecvPropInt (RECVINFO(m_lifeState)),
-
- RecvPropInt (RECVINFO(m_iBonusProgress)),
- RecvPropInt (RECVINFO(m_iBonusChallenge)),
-
- RecvPropFloat (RECVINFO(m_flMaxspeed)),
- RecvPropInt (RECVINFO(m_fFlags)),
-
-
- RecvPropInt (RECVINFO(m_iObserverMode), 0, RecvProxy_ObserverMode ),
- RecvPropEHandle (RECVINFO(m_hObserverTarget), RecvProxy_ObserverTarget ),
- RecvPropArray ( RecvPropEHandle( RECVINFO( m_hViewModel[0] ) ), m_hViewModel ),
-
-
- RecvPropString( RECVINFO(m_szLastPlaceName) ),
-
-#if defined USES_ECON_ITEMS
- RecvPropUtlVector( RECVINFO_UTLVECTOR( m_hMyWearables ), MAX_WEARABLES_SENT_FROM_SERVER, RecvPropEHandle(NULL, 0, 0) ),
-#endif
-
- END_RECV_TABLE()
-
-BEGIN_PREDICTION_DATA_NO_BASE( CPlayerState )
-
- DEFINE_PRED_FIELD( deadflag, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
- // DEFINE_FIELD( netname, string_t ),
- // DEFINE_FIELD( fixangle, FIELD_INTEGER ),
- // DEFINE_FIELD( anglechange, FIELD_FLOAT ),
- // DEFINE_FIELD( v_angle, FIELD_VECTOR ),
-
-END_PREDICTION_DATA()
-
-BEGIN_PREDICTION_DATA_NO_BASE( CPlayerLocalData )
-
- // DEFINE_PRED_TYPEDESCRIPTION( m_skybox3d, sky3dparams_t ),
- // DEFINE_PRED_TYPEDESCRIPTION( m_fog, fogparams_t ),
- // DEFINE_PRED_TYPEDESCRIPTION( m_audio, audioparams_t ),
- DEFINE_FIELD( m_nStepside, FIELD_INTEGER ),
-
- DEFINE_PRED_FIELD( m_iHideHUD, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
-#if PREDICTION_ERROR_CHECK_LEVEL > 1
- DEFINE_PRED_FIELD( m_vecPunchAngle, FIELD_VECTOR, FTYPEDESC_INSENDTABLE ),
- DEFINE_PRED_FIELD( m_vecPunchAngleVel, FIELD_VECTOR, FTYPEDESC_INSENDTABLE ),
-#else
- DEFINE_PRED_FIELD_TOL( m_vecPunchAngle, FIELD_VECTOR, FTYPEDESC_INSENDTABLE, 0.125f ),
- DEFINE_PRED_FIELD_TOL( m_vecPunchAngleVel, FIELD_VECTOR, FTYPEDESC_INSENDTABLE, 0.125f ),
-#endif
- DEFINE_PRED_FIELD( m_bDrawViewmodel, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
- DEFINE_PRED_FIELD( m_bWearingSuit, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
- DEFINE_PRED_FIELD( m_bPoisoned, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
- DEFINE_PRED_FIELD( m_bAllowAutoMovement, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
-
- DEFINE_PRED_FIELD( m_bDucked, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
- DEFINE_PRED_FIELD( m_bDucking, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
- DEFINE_PRED_FIELD( m_bInDuckJump, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
- DEFINE_PRED_FIELD( m_flDucktime, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ),
- DEFINE_PRED_FIELD( m_flDuckJumpTime, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ),
- DEFINE_PRED_FIELD( m_flJumpTime, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ),
- DEFINE_PRED_FIELD_TOL( m_flFallVelocity, FIELD_FLOAT, FTYPEDESC_INSENDTABLE, 0.5f ),
-// DEFINE_PRED_FIELD( m_nOldButtons, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
- DEFINE_FIELD( m_nOldButtons, FIELD_INTEGER ),
- DEFINE_PRED_FIELD( m_flStepSize, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ),
- DEFINE_FIELD( m_flFOVRate, FIELD_FLOAT ),
-
-END_PREDICTION_DATA()
-
-BEGIN_PREDICTION_DATA( C_BasePlayer )
-
- DEFINE_PRED_TYPEDESCRIPTION( m_Local, CPlayerLocalData ),
- DEFINE_PRED_TYPEDESCRIPTION( pl, CPlayerState ),
-
- DEFINE_PRED_FIELD( m_iFOV, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
- DEFINE_PRED_FIELD( m_hZoomOwner, FIELD_EHANDLE, FTYPEDESC_INSENDTABLE ),
- DEFINE_PRED_FIELD( m_flFOVTime, FIELD_FLOAT, 0 ),
- DEFINE_PRED_FIELD( m_iFOVStart, FIELD_INTEGER, 0 ),
-
- DEFINE_PRED_FIELD( m_hVehicle, FIELD_EHANDLE, FTYPEDESC_INSENDTABLE ),
- DEFINE_PRED_FIELD_TOL( m_flMaxspeed, FIELD_FLOAT, FTYPEDESC_INSENDTABLE, 0.5f ),
- DEFINE_PRED_FIELD( m_iHealth, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
- DEFINE_PRED_FIELD( m_iBonusProgress, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
- DEFINE_PRED_FIELD( m_iBonusChallenge, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
- DEFINE_PRED_FIELD( m_fOnTarget, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
- DEFINE_PRED_FIELD( m_nNextThinkTick, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
- DEFINE_PRED_FIELD( m_lifeState, FIELD_CHARACTER, FTYPEDESC_INSENDTABLE ),
- DEFINE_PRED_FIELD( m_nWaterLevel, FIELD_CHARACTER, FTYPEDESC_INSENDTABLE ),
-
- DEFINE_PRED_FIELD_TOL( m_vecBaseVelocity, FIELD_VECTOR, FTYPEDESC_INSENDTABLE, 0.05 ),
-
- DEFINE_FIELD( m_nButtons, FIELD_INTEGER ),
- DEFINE_FIELD( m_flWaterJumpTime, FIELD_FLOAT ),
- DEFINE_FIELD( m_nImpulse, FIELD_INTEGER ),
- DEFINE_FIELD( m_flStepSoundTime, FIELD_FLOAT ),
- DEFINE_FIELD( m_flSwimSoundTime, FIELD_FLOAT ),
- DEFINE_FIELD( m_vecLadderNormal, FIELD_VECTOR ),
- DEFINE_FIELD( m_flPhysics, FIELD_INTEGER ),
- DEFINE_AUTO_ARRAY( m_szAnimExtension, FIELD_CHARACTER ),
- DEFINE_FIELD( m_afButtonLast, FIELD_INTEGER ),
- DEFINE_FIELD( m_afButtonPressed, FIELD_INTEGER ),
- DEFINE_FIELD( m_afButtonReleased, FIELD_INTEGER ),
- // DEFINE_FIELD( m_vecOldViewAngles, FIELD_VECTOR ),
-
- // DEFINE_ARRAY( m_iOldAmmo, FIELD_INTEGER, MAX_AMMO_TYPES ),
-
- //DEFINE_FIELD( m_hOldVehicle, FIELD_EHANDLE ),
- // DEFINE_FIELD( m_pModelLight, dlight_t* ),
- // DEFINE_FIELD( m_pEnvironmentLight, dlight_t* ),
- // DEFINE_FIELD( m_pBrightLight, dlight_t* ),
- DEFINE_PRED_FIELD( m_hLastWeapon, FIELD_EHANDLE, FTYPEDESC_INSENDTABLE ),
-
- DEFINE_PRED_FIELD( m_nTickBase, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
-
- DEFINE_PRED_FIELD( m_hGroundEntity, FIELD_EHANDLE, FTYPEDESC_INSENDTABLE ),
-
- DEFINE_PRED_ARRAY( m_hViewModel, FIELD_EHANDLE, MAX_VIEWMODELS, FTYPEDESC_INSENDTABLE ),
-
- DEFINE_FIELD( m_surfaceFriction, FIELD_FLOAT ),
-
-END_PREDICTION_DATA()
-
-LINK_ENTITY_TO_CLASS( player, C_BasePlayer );
-
-// -------------------------------------------------------------------------------- //
-// Functions.
-// -------------------------------------------------------------------------------- //
-C_BasePlayer::C_BasePlayer() : m_iv_vecViewOffset( "C_BasePlayer::m_iv_vecViewOffset" )
-{
- AddVar( &m_vecViewOffset, &m_iv_vecViewOffset, LATCH_SIMULATION_VAR );
-
-#ifdef _DEBUG
- m_vecLadderNormal.Init();
- m_vecOldViewAngles.Init();
-#endif
-
- m_pFlashlight = NULL;
-
- m_pCurrentVguiScreen = NULL;
- m_pCurrentCommand = NULL;
-
- m_flPredictionErrorTime = -100;
- m_StuckLast = 0;
- m_bWasFrozen = false;
-
- m_bResampleWaterSurface = true;
-
- ResetObserverMode();
-
- m_vecPredictionError.Init();
- m_flPredictionErrorTime = 0;
-
- m_surfaceProps = 0;
- m_pSurfaceData = NULL;
- m_surfaceFriction = 1.0f;
- m_chTextureType = 0;
-
- m_flNextAchievementAnnounceTime = 0;
-
- m_bFiredWeapon = false;
-
- m_nForceVisionFilterFlags = 0;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-C_BasePlayer::~C_BasePlayer()
-{
- DeactivateVguiScreen( m_pCurrentVguiScreen.Get() );
- if ( this == s_pLocalPlayer )
- {
- s_pLocalPlayer = NULL;
- }
-
- delete m_pFlashlight;
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void C_BasePlayer::Spawn( void )
-{
- // Clear all flags except for FL_FULLEDICT
- ClearFlags();
- AddFlag( FL_CLIENT );
-
- int effects = GetEffects() & EF_NOSHADOW;
- SetEffects( effects );
-
- m_iFOV = 0; // init field of view.
-
- SetModel( "models/player.mdl" );
-
- Precache();
-
- SetThink(NULL);
-
- SharedSpawn();
-
- m_bWasFreezeFraming = false;
-
- m_bFiredWeapon = false;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-bool C_BasePlayer::AudioStateIsUnderwater( Vector vecMainViewOrigin )
-{
- if ( IsObserver() )
- {
- // Just check the view position
- int cont = enginetrace->GetPointContents ( vecMainViewOrigin );
- return (cont & MASK_WATER);
- }
-
- return ( GetWaterLevel() >= WL_Eyes );
-}
-
-bool C_BasePlayer::IsHLTV() const
-{
- return ( IsLocalPlayer() && engine->IsHLTV() );
-}
-
-bool C_BasePlayer::IsReplay() const
-{
-#if defined( REPLAY_ENABLED )
- return ( IsLocalPlayer() && g_pEngineClientReplay->IsPlayingReplayDemo() );
-#else
- return false;
-#endif
-}
-
-CBaseEntity *C_BasePlayer::GetObserverTarget() const // returns players target or NULL
-{
-#ifndef _XBOX
- if ( IsHLTV() )
- {
- return HLTVCamera()->GetPrimaryTarget();
- }
-#if defined( REPLAY_ENABLED )
- if ( IsReplay() )
- {
- return ReplayCamera()->GetPrimaryTarget();
- }
-#endif
-#endif
-
- if ( GetObserverMode() == OBS_MODE_ROAMING )
- {
- return NULL; // no target in roaming mode
- }
- else
- {
- if ( IsLocalPlayer() && UseVR() )
- {
- // In VR mode, certain views cause disorientation and nausea. So let's not.
- switch ( m_iObserverMode )
- {
- case OBS_MODE_NONE: // not in spectator mode
- case OBS_MODE_FIXED: // view from a fixed camera position
- case OBS_MODE_IN_EYE: // follow a player in first person view
- case OBS_MODE_CHASE: // follow a player in third person view
- case OBS_MODE_ROAMING: // free roaming
- return m_hObserverTarget;
- break;
- case OBS_MODE_DEATHCAM: // special mode for death cam animation
- case OBS_MODE_FREEZECAM: // zooms to a target, and freeze-frames on them
- // These are both terrible - they get overriden to chase, but here we change it to "chase" your own body (which will be ragdolled).
- return (const_cast<C_BasePlayer*>(this))->GetBaseEntity();
- break;
- default:
- assert ( false );
- break;
- }
- }
-
- return m_hObserverTarget;
- }
-}
-
-// Called from Recv Proxy, mainly to reset tone map scale
-void C_BasePlayer::SetObserverTarget( EHANDLE hObserverTarget )
-{
- // If the observer target is changing to an entity that the client doesn't know about yet,
- // it can resolve to NULL. If the client didn't have an observer target before, then
- // comparing EHANDLEs directly will see them as equal, since it uses Get(), and compares
- // NULL to NULL. To combat this, we need to check against GetEntryIndex() and
- // GetSerialNumber().
- if ( hObserverTarget.GetEntryIndex() != m_hObserverTarget.GetEntryIndex() ||
- hObserverTarget.GetSerialNumber() != m_hObserverTarget.GetSerialNumber())
- {
- // Init based on the new handle's entry index and serial number, so that it's Get()
- // has a chance to become non-NULL even if it currently resolves to NULL.
- m_hObserverTarget.Init( hObserverTarget.GetEntryIndex(), hObserverTarget.GetSerialNumber() );
-
- IGameEvent *event = gameeventmanager->CreateEvent( "spec_target_updated" );
- if ( event )
- {
- gameeventmanager->FireEventClientSide( event );
- }
-
- if ( IsLocalPlayer() )
- {
- ResetToneMapping(1.0);
- }
- // NVNT notify haptics of changed player
- if ( haptics )
- haptics->OnPlayerChanged();
-
- if ( IsLocalPlayer() )
- {
- // On a change of viewing mode or target, we may want to reset both head and torso to point at the new target.
- g_ClientVirtualReality.AlignTorsoAndViewToWeapon();
- }
- }
-}
-
-
-void C_BasePlayer::SetObserverMode ( int iNewMode )
-{
- if ( m_iObserverMode != iNewMode )
- {
- m_iObserverMode = iNewMode;
- if ( IsLocalPlayer() )
- {
- // On a change of viewing mode or target, we may want to reset both head and torso to point at the new target.
- g_ClientVirtualReality.AlignTorsoAndViewToWeapon();
- }
- }
-}
-
-
-int C_BasePlayer::GetObserverMode() const
-{
-#ifndef _XBOX
- if ( IsHLTV() )
- {
- return HLTVCamera()->GetMode();
- }
-#if defined( REPLAY_ENABLED )
- if ( IsReplay() )
- {
- return ReplayCamera()->GetMode();
- }
-#endif
-#endif
-
- if ( IsLocalPlayer() && UseVR() )
- {
- // IN VR mode, certain views cause disorientation and nausea. So let's not.
- switch ( m_iObserverMode )
- {
- case OBS_MODE_NONE: // not in spectator mode
- case OBS_MODE_FIXED: // view from a fixed camera position
- case OBS_MODE_IN_EYE: // follow a player in first person view
- case OBS_MODE_CHASE: // follow a player in third person view
- case OBS_MODE_ROAMING: // free roaming
- return m_iObserverMode;
- break;
- case OBS_MODE_DEATHCAM: // special mode for death cam animation
- case OBS_MODE_FREEZECAM: // zooms to a target, and freeze-frames on them
- // These are both terrible - just do chase of your ragdoll.
- return OBS_MODE_CHASE;
- break;
- default:
- assert ( false );
- break;
- }
- }
-
- return m_iObserverMode;
-}
-
-bool C_BasePlayer::ViewModel_IsTransparent( void )
-{
- return IsTransparent();
-}
-
-bool C_BasePlayer::ViewModel_IsUsingFBTexture( void )
-{
- return UsesPowerOfTwoFrameBufferTexture();
-}
-
-//-----------------------------------------------------------------------------
-// Used by prediction, sets the view angles for the player
-//-----------------------------------------------------------------------------
-void C_BasePlayer::SetLocalViewAngles( const QAngle &viewAngles )
-{
- pl.v_angle = viewAngles;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : ang -
-//-----------------------------------------------------------------------------
-void C_BasePlayer::SetViewAngles( const QAngle& ang )
-{
- SetLocalAngles( ang );
- SetNetworkAngles( ang );
-}
-
-
-surfacedata_t* C_BasePlayer::GetGroundSurface()
-{
- //
- // Find the name of the material that lies beneath the player.
- //
- Vector start, end;
- VectorCopy( GetAbsOrigin(), start );
- VectorCopy( start, end );
-
- // Straight down
- end.z -= 64;
-
- // Fill in default values, just in case.
-
- Ray_t ray;
- ray.Init( start, end, GetPlayerMins(), GetPlayerMaxs() );
-
- trace_t trace;
- UTIL_TraceRay( ray, MASK_PLAYERSOLID_BRUSHONLY, this, COLLISION_GROUP_PLAYER_MOVEMENT, &trace );
-
- if ( trace.fraction == 1.0f )
- return NULL; // no ground
-
- return physprops->GetSurfaceData( trace.surface.surfaceProps );
-}
-
-
-//-----------------------------------------------------------------------------
-// returns the player name
-//-----------------------------------------------------------------------------
-const char * C_BasePlayer::GetPlayerName()
-{
- return g_PR ? g_PR->GetPlayerName( entindex() ) : "";
-}
-
-//-----------------------------------------------------------------------------
-// Is the player dead?
-//-----------------------------------------------------------------------------
-bool C_BasePlayer::IsPlayerDead()
-{
- return pl.deadflag == true;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void C_BasePlayer::SetVehicleRole( int nRole )
-{
- if ( !IsInAVehicle() )
- return;
-
- // HL2 has only a player in a vehicle.
- if ( nRole > VEHICLE_ROLE_DRIVER )
- return;
-
- char szCmd[64];
- Q_snprintf( szCmd, sizeof( szCmd ), "vehicleRole %i\n", nRole );
- engine->ServerCmd( szCmd );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Store original ammo data to see what has changed
-// Input : bnewentity -
-//-----------------------------------------------------------------------------
-void C_BasePlayer::OnPreDataChanged( DataUpdateType_t updateType )
-{
- for (int i = 0; i < MAX_AMMO_TYPES; ++i)
- {
- m_iOldAmmo[i] = GetAmmoCount(i);
- }
-
- m_bWasFreezeFraming = (GetObserverMode() == OBS_MODE_FREEZECAM);
- m_hOldFogController = m_Local.m_PlayerFog.m_hCtrl;
-
- BaseClass::OnPreDataChanged( updateType );
-}
-
-void C_BasePlayer::PreDataUpdate( DataUpdateType_t updateType )
-{
- BaseClass::PreDataUpdate( updateType );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : updateType -
-//-----------------------------------------------------------------------------
-void C_BasePlayer::PostDataUpdate( DataUpdateType_t updateType )
-{
- // This has to occur here as opposed to OnDataChanged so that EHandles to the player created
- // on this same frame are not stomped because prediction thinks there
- // isn't a local player yet!!!
-
- if ( updateType == DATA_UPDATE_CREATED )
- {
- // Make sure s_pLocalPlayer is correct
-
- int iLocalPlayerIndex = engine->GetLocalPlayer();
-
- if ( g_nKillCamMode )
- iLocalPlayerIndex = g_nKillCamTarget1;
-
- if ( iLocalPlayerIndex == index )
- {
- Assert( s_pLocalPlayer == NULL );
- s_pLocalPlayer = this;
-
- // Reset our sound mixed in case we were in a freeze cam when we
- // changed level, which would cause the snd_soundmixer to be left modified.
- ConVar *pVar = (ConVar *)cvar->FindVar( "snd_soundmixer" );
- pVar->Revert();
- }
- }
-
- bool bForceEFNoInterp = IsNoInterpolationFrame();
-
- if ( IsLocalPlayer() )
- {
- SetSimulatedEveryTick( true );
- }
- else
- {
- SetSimulatedEveryTick( false );
-
- // estimate velocity for non local players
- float flTimeDelta = m_flSimulationTime - m_flOldSimulationTime;
- if ( flTimeDelta > 0 && !( IsNoInterpolationFrame() || bForceEFNoInterp ) )
- {
- Vector newVelo = (GetNetworkOrigin() - GetOldOrigin() ) / flTimeDelta;
- SetAbsVelocity( newVelo);
- }
- }
-
- BaseClass::PostDataUpdate( updateType );
-
- // Only care about this for local player
- if ( IsLocalPlayer() )
- {
- QAngle angles;
- engine->GetViewAngles( angles );
- if ( updateType == DATA_UPDATE_CREATED )
- {
- SetLocalViewAngles( angles );
- m_flOldPlayerZ = GetLocalOrigin().z;
- // NVNT the local player has just been created.
- // set in the "on_foot" navigation.
- if ( haptics )
- {
- haptics->LocalPlayerReset();
- haptics->SetNavigationClass("on_foot");
- haptics->ProcessHapticEvent(2,"Movement","BasePlayer");
- }
-
- }
- SetLocalAngles( angles );
-
- if ( !m_bWasFreezeFraming && GetObserverMode() == OBS_MODE_FREEZECAM )
- {
- m_vecFreezeFrameStart = MainViewOrigin();
- m_flFreezeFrameStartTime = gpGlobals->curtime;
- m_flFreezeFrameDistance = RandomFloat( spec_freeze_distance_min.GetFloat(), spec_freeze_distance_max.GetFloat() );
- m_flFreezeZOffset = RandomFloat( -30, 20 );
- m_bSentFreezeFrame = false;
- m_nForceVisionFilterFlags = 0;
-
- C_BaseEntity *target = GetObserverTarget();
- if ( target && target->IsPlayer() )
- {
- C_BasePlayer *player = ToBasePlayer( target );
- if ( player )
- {
- m_nForceVisionFilterFlags = player->GetVisionFilterFlags();
- CalculateVisionUsingCurrentFlags();
- }
- }
-
- IGameEvent *pEvent = gameeventmanager->CreateEvent( "show_freezepanel" );
- if ( pEvent )
- {
- pEvent->SetInt( "killer", target ? target->entindex() : 0 );
- gameeventmanager->FireEventClientSide( pEvent );
- }
-
- // Force the sound mixer to the freezecam mixer
- ConVar *pVar = (ConVar *)cvar->FindVar( "snd_soundmixer" );
- pVar->SetValue( "FreezeCam_Only" );
- }
- else if ( m_bWasFreezeFraming && GetObserverMode() != OBS_MODE_FREEZECAM )
- {
- IGameEvent *pEvent = gameeventmanager->CreateEvent( "hide_freezepanel" );
- if ( pEvent )
- {
- gameeventmanager->FireEventClientSide( pEvent );
- }
-
- view->FreezeFrame(0);
-
- ConVar *pVar = (ConVar *)cvar->FindVar( "snd_soundmixer" );
- pVar->Revert();
-
- m_nForceVisionFilterFlags = 0;
- CalculateVisionUsingCurrentFlags();
- }
- }
-
- // If we are updated while paused, allow the player origin to be snapped by the
- // server if we receive a packet from the server
- if ( engine->IsPaused() || bForceEFNoInterp )
- {
- ResetLatched();
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-bool C_BasePlayer::CanSetSoundMixer( void )
-{
- // Can't set sound mixers when we're in freezecam mode, since it has a code-enforced mixer
- return (GetObserverMode() != OBS_MODE_FREEZECAM);
-}
-
-void C_BasePlayer::ReceiveMessage( int classID, bf_read &msg )
-{
- if ( classID != GetClientClass()->m_ClassID )
- {
- // message is for subclass
- BaseClass::ReceiveMessage( classID, msg );
- return;
- }
-
- int messageType = msg.ReadByte();
-
- switch( messageType )
- {
- case PLAY_PLAYER_JINGLE:
- PlayPlayerJingle();
- break;
- }
-}
-
-void C_BasePlayer::OnRestore()
-{
- BaseClass::OnRestore();
-
- if ( IsLocalPlayer() )
- {
- // debounce the attack key, for if it was used for restore
- input->ClearInputButton( IN_ATTACK | IN_ATTACK2 );
- // GetButtonBits() has to be called for the above to take effect
- input->GetButtonBits( 0 );
- }
-
- // For ammo history icons to current value so they don't flash on level transtions
- for ( int i = 0; i < MAX_AMMO_TYPES; i++ )
- {
- m_iOldAmmo[i] = GetAmmoCount(i);
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Process incoming data
-//-----------------------------------------------------------------------------
-void C_BasePlayer::OnDataChanged( DataUpdateType_t updateType )
-{
-#if !defined( NO_ENTITY_PREDICTION )
- if ( IsLocalPlayer() )
- {
- SetPredictionEligible( true );
- }
-#endif
-
- BaseClass::OnDataChanged( updateType );
-
- // Only care about this for local player
- if ( IsLocalPlayer() )
- {
- // Reset engine areabits pointer
- render->SetAreaState( m_Local.m_chAreaBits, m_Local.m_chAreaPortalBits );
-
- // Check for Ammo pickups.
- for ( int i = 0; i < MAX_AMMO_TYPES; i++ )
- {
- if ( GetAmmoCount(i) > m_iOldAmmo[i] )
- {
- // Don't add to ammo pickup if the ammo doesn't do it
- const FileWeaponInfo_t *pWeaponData = gWR.GetWeaponFromAmmo(i);
-
- if ( !pWeaponData || !( pWeaponData->iFlags & ITEM_FLAG_NOAMMOPICKUPS ) )
- {
- // We got more ammo for this ammo index. Add it to the ammo history
- CHudHistoryResource *pHudHR = GET_HUDELEMENT( CHudHistoryResource );
- if( pHudHR )
- {
- pHudHR->AddToHistory( HISTSLOT_AMMO, i, abs(GetAmmoCount(i) - m_iOldAmmo[i]) );
- }
- }
- }
- }
-
- Soundscape_Update( m_Local.m_audio );
-
- if ( m_hOldFogController != m_Local.m_PlayerFog.m_hCtrl )
- {
- FogControllerChanged( updateType == DATA_UPDATE_CREATED );
- }
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// Did we just enter a vehicle this frame?
-//-----------------------------------------------------------------------------
-bool C_BasePlayer::JustEnteredVehicle()
-{
- if ( !IsInAVehicle() )
- return false;
-
- return ( m_hOldVehicle == m_hVehicle );
-}
-
-//-----------------------------------------------------------------------------
-// Are we in VGUI input mode?.
-//-----------------------------------------------------------------------------
-bool C_BasePlayer::IsInVGuiInputMode() const
-{
- return (m_pCurrentVguiScreen.Get() != NULL);
-}
-
-//-----------------------------------------------------------------------------
-// Are we inputing to a view model vgui screen
-//-----------------------------------------------------------------------------
-bool C_BasePlayer::IsInViewModelVGuiInputMode() const
-{
- C_BaseEntity *pScreenEnt = m_pCurrentVguiScreen.Get();
-
- if ( !pScreenEnt )
- return false;
-
- Assert( dynamic_cast<C_VGuiScreen*>(pScreenEnt) );
- C_VGuiScreen *pVguiScreen = static_cast<C_VGuiScreen*>(pScreenEnt);
-
- return ( pVguiScreen->IsAttachedToViewModel() && pVguiScreen->AcceptsInput() );
-}
-
-//-----------------------------------------------------------------------------
-// Check to see if we're in vgui input mode...
-//-----------------------------------------------------------------------------
-void C_BasePlayer::DetermineVguiInputMode( CUserCmd *pCmd )
-{
- // If we're dead, close down and abort!
- if ( !IsAlive() )
- {
- DeactivateVguiScreen( m_pCurrentVguiScreen.Get() );
- m_pCurrentVguiScreen.Set( NULL );
- return;
- }
-
- // If we're in vgui mode *and* we're holding down mouse buttons,
- // stay in vgui mode even if we're outside the screen bounds
- if (m_pCurrentVguiScreen.Get() && (pCmd->buttons & (IN_ATTACK | IN_ATTACK2)) )
- {
- SetVGuiScreenButtonState( m_pCurrentVguiScreen.Get(), pCmd->buttons );
-
- // Kill all attack inputs if we're in vgui screen mode
- pCmd->buttons &= ~(IN_ATTACK | IN_ATTACK2);
- return;
- }
-
- // We're not in vgui input mode if we're moving, or have hit a key
- // that will make us move...
-
- // Not in vgui mode if we're moving too quickly
- // ROBIN: Disabled movement preventing VGUI screen usage
- //if (GetVelocity().LengthSqr() > MAX_VGUI_INPUT_MODE_SPEED_SQ)
- if ( 0 )
- {
- DeactivateVguiScreen( m_pCurrentVguiScreen.Get() );
- m_pCurrentVguiScreen.Set( NULL );
- return;
- }
-
- // Don't enter vgui mode if we've got combat buttons held down
- bool bAttacking = false;
- if ( ((pCmd->buttons & IN_ATTACK) || (pCmd->buttons & IN_ATTACK2)) && !m_pCurrentVguiScreen.Get() )
- {
- bAttacking = true;
- }
-
- // Not in vgui mode if we're pushing any movement key at all
- // Not in vgui mode if we're in a vehicle...
- // ROBIN: Disabled movement preventing VGUI screen usage
- //if ((pCmd->forwardmove > MAX_VGUI_INPUT_MODE_SPEED) ||
- // (pCmd->sidemove > MAX_VGUI_INPUT_MODE_SPEED) ||
- // (pCmd->upmove > MAX_VGUI_INPUT_MODE_SPEED) ||
- // (pCmd->buttons & IN_JUMP) ||
- // (bAttacking) )
- if ( bAttacking || IsInAVehicle() )
- {
- DeactivateVguiScreen( m_pCurrentVguiScreen.Get() );
- m_pCurrentVguiScreen.Set( NULL );
- return;
- }
-
- // Don't interact with world screens when we're in a menu
- if ( vgui::surface()->IsCursorVisible() )
- {
- DeactivateVguiScreen( m_pCurrentVguiScreen.Get() );
- m_pCurrentVguiScreen.Set( NULL );
- return;
- }
-
- // Not in vgui mode if there are no nearby screens
- C_BaseEntity *pOldScreen = m_pCurrentVguiScreen.Get();
-
- m_pCurrentVguiScreen = FindNearbyVguiScreen( EyePosition(), pCmd->viewangles, GetTeamNumber() );
-
- if (pOldScreen != m_pCurrentVguiScreen)
- {
- DeactivateVguiScreen( pOldScreen );
- ActivateVguiScreen( m_pCurrentVguiScreen.Get() );
- }
-
- if (m_pCurrentVguiScreen.Get())
- {
- SetVGuiScreenButtonState( m_pCurrentVguiScreen.Get(), pCmd->buttons );
-
- // Kill all attack inputs if we're in vgui screen mode
- pCmd->buttons &= ~(IN_ATTACK | IN_ATTACK2);
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Input handling
-//-----------------------------------------------------------------------------
-bool C_BasePlayer::CreateMove( float flInputSampleTime, CUserCmd *pCmd )
-{
- // Allow the vehicle to clamp the view angles
- if ( IsInAVehicle() )
- {
- IClientVehicle *pVehicle = m_hVehicle.Get()->GetClientVehicle();
- if ( pVehicle )
- {
- pVehicle->UpdateViewAngles( this, pCmd );
- engine->SetViewAngles( pCmd->viewangles );
- }
- }
- else
- {
-#ifndef _X360
- if ( joy_autosprint.GetBool() )
-#endif
- {
- if ( input->KeyState( &in_joyspeed ) != 0.0f )
- {
- pCmd->buttons |= IN_SPEED;
- }
- }
-
- CBaseCombatWeapon *pWeapon = GetActiveWeapon();
- if ( pWeapon )
- {
- pWeapon->CreateMove( flInputSampleTime, pCmd, m_vecOldViewAngles );
- }
- }
-
- // If the frozen flag is set, prevent view movement (server prevents the rest of the movement)
- if ( GetFlags() & FL_FROZEN )
- {
- // Don't stomp the first time we get frozen
- if ( m_bWasFrozen )
- {
- // Stomp the new viewangles with old ones
- pCmd->viewangles = m_vecOldViewAngles;
- engine->SetViewAngles( pCmd->viewangles );
- }
- else
- {
- m_bWasFrozen = true;
- }
- }
- else
- {
- m_bWasFrozen = false;
- }
-
- m_vecOldViewAngles = pCmd->viewangles;
-
- // Check to see if we're in vgui input mode...
- DetermineVguiInputMode( pCmd );
-
- return true;
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Player has changed to a new team
-//-----------------------------------------------------------------------------
-void C_BasePlayer::TeamChange( int iNewTeam )
-{
- // Base class does nothing
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Creates, destroys, and updates the flashlight effect as needed.
-//-----------------------------------------------------------------------------
-void C_BasePlayer::UpdateFlashlight()
-{
- // The dim light is the flashlight.
- if ( IsEffectActive( EF_DIMLIGHT ) )
- {
- if (!m_pFlashlight)
- {
- // Turned on the headlight; create it.
- m_pFlashlight = new CFlashlightEffect(index);
-
- if (!m_pFlashlight)
- return;
-
- m_pFlashlight->TurnOn();
- }
-
- Vector vecForward, vecRight, vecUp;
- EyeVectors( &vecForward, &vecRight, &vecUp );
-
- // Update the light with the new position and direction.
- m_pFlashlight->UpdateLight( EyePosition(), vecForward, vecRight, vecUp, FLASHLIGHT_DISTANCE );
- }
- else if (m_pFlashlight)
- {
- // Turned off the flashlight; delete it.
- delete m_pFlashlight;
- m_pFlashlight = NULL;
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Creates player flashlight if it's ative
-//-----------------------------------------------------------------------------
-void C_BasePlayer::Flashlight( void )
-{
- UpdateFlashlight();
-
- // Check for muzzle flash and apply to view model
- C_BaseAnimating *ve = this;
- if ( GetObserverMode() == OBS_MODE_IN_EYE )
- {
- ve = dynamic_cast< C_BaseAnimating* >( GetObserverTarget() );
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Engine is asking whether to add this player to the visible entities list
-//-----------------------------------------------------------------------------
-void C_BasePlayer::AddEntity( void )
-{
- // FIXME/UNDONE: Should the local player say yes to adding itself now
- // and then, when it ges time to render and it shouldn't still do the render with
- // STUDIO_EVENTS set so that its attachment points will get updated even if not
- // in third person?
-
- // Add in water effects
- if ( IsLocalPlayer() )
- {
- CreateWaterEffects();
- }
-
- // If set to invisible, skip. Do this before resetting the entity pointer so it has
- // valid data to decide whether it's visible.
- if ( !IsVisible() || !g_pClientMode->ShouldDrawLocalPlayer( this ) )
- {
- return;
- }
-
- // Server says don't interpolate this frame, so set previous info to new info.
- if ( IsNoInterpolationFrame() || Teleported() )
- {
- ResetLatched();
- }
-
- // Add in lighting effects
- CreateLightEffects();
-}
-
-extern float UTIL_WaterLevel( const Vector &position, float minz, float maxz );
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void C_BasePlayer::CreateWaterEffects( void )
-{
- // Must be completely submerged to bother
- if ( GetWaterLevel() < 3 )
- {
- m_bResampleWaterSurface = true;
- return;
- }
-
- // Do special setup if this is our first time back underwater
- if ( m_bResampleWaterSurface )
- {
- // Reset our particle timer
- m_tWaterParticleTimer.Init( 32 );
-
- // Find the surface of the water to clip against
- m_flWaterSurfaceZ = UTIL_WaterLevel( WorldSpaceCenter(), WorldSpaceCenter().z, WorldSpaceCenter().z + 256 );
- m_bResampleWaterSurface = false;
- }
-
- // Make sure the emitter is setup
- if ( m_pWaterEmitter == NULL )
- {
- if ( ( m_pWaterEmitter = WaterDebrisEffect::Create( "splish" ) ) == NULL )
- return;
- }
-
- Vector vecVelocity;
- GetVectors( &vecVelocity, NULL, NULL );
-
- Vector offset = WorldSpaceCenter();
-
- m_pWaterEmitter->SetSortOrigin( offset );
-
- SimpleParticle *pParticle;
-
- float curTime = gpGlobals->frametime;
-
- // Add as many particles as we need
- while ( m_tWaterParticleTimer.NextEvent( curTime ) )
- {
- offset = WorldSpaceCenter() + ( vecVelocity * 128.0f ) + RandomVector( -128, 128 );
-
- // Make sure we don't start out of the water!
- if ( offset.z > m_flWaterSurfaceZ )
- {
- offset.z = ( m_flWaterSurfaceZ - 8.0f );
- }
-
- pParticle = (SimpleParticle *) m_pWaterEmitter->AddParticle( sizeof(SimpleParticle), g_Mat_Fleck_Cement[random->RandomInt(0,1)], offset );
-
- if (pParticle == NULL)
- continue;
-
- pParticle->m_flLifetime = 0.0f;
- pParticle->m_flDieTime = random->RandomFloat( 2.0f, 4.0f );
-
- pParticle->m_vecVelocity = RandomVector( -2.0f, 2.0f );
-
- //FIXME: We should tint these based on the water's fog value!
- float color = random->RandomInt( 32, 128 );
- pParticle->m_uchColor[0] = color;
- pParticle->m_uchColor[1] = color;
- pParticle->m_uchColor[2] = color;
-
- pParticle->m_uchStartSize = 1;
- pParticle->m_uchEndSize = 1;
-
- pParticle->m_uchStartAlpha = 255;
- pParticle->m_uchEndAlpha = 0;
-
- pParticle->m_flRoll = random->RandomInt( 0, 360 );
- pParticle->m_flRollDelta = random->RandomFloat( -0.5f, 0.5f );
- }
-}
-
-//-----------------------------------------------------------------------------
-// Called when not in tactical mode. Allows view to be overriden for things like driving a tank.
-//-----------------------------------------------------------------------------
-void C_BasePlayer::OverrideView( CViewSetup *pSetup )
-{
-}
-
-bool C_BasePlayer::ShouldInterpolate()
-{
- // always interpolate myself
- if ( IsLocalPlayer() )
- return true;
-#ifndef _XBOX
- // always interpolate entity if followed by HLTV
- if ( HLTVCamera()->GetCameraMan() == this )
- return true;
-#endif
- return BaseClass::ShouldInterpolate();
-}
-
-
-bool C_BasePlayer::ShouldDraw()
-{
- return ShouldDrawThisPlayer() && BaseClass::ShouldDraw();
-}
-
-int C_BasePlayer::DrawModel( int flags )
-{
-#ifndef PORTAL
- // In Portal this check is already performed as part of
- // C_Portal_Player::DrawModel()
- if ( !ShouldDrawThisPlayer() )
- {
- return 0;
- }
-#endif
- return BaseClass::DrawModel( flags );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-Vector C_BasePlayer::GetChaseCamViewOffset( CBaseEntity *target )
-{
- C_BasePlayer *player = ToBasePlayer( target );
-
- if ( player )
- {
- if ( player->IsAlive() )
- {
- if ( player->GetFlags() & FL_DUCKING )
- {
- return VEC_DUCK_VIEW_SCALED( player );
- }
-
- return VEC_VIEW_SCALED( player );
- }
- else
- {
- // assume it's the players ragdoll
- return VEC_DEAD_VIEWHEIGHT_SCALED( player );
- }
- }
-
- // assume it's the players ragdoll
- return VEC_DEAD_VIEWHEIGHT;
-}
-
-void C_BasePlayer::CalcChaseCamView(Vector& eyeOrigin, QAngle& eyeAngles, float& fov)
-{
- C_BaseEntity *target = GetObserverTarget();
-
- if ( !target )
- {
- // just copy a save in-map position
- VectorCopy( EyePosition(), eyeOrigin );
- VectorCopy( EyeAngles(), eyeAngles );
- return;
- };
-
- // If our target isn't visible, we're at a camera point of some kind.
- // Instead of letting the player rotate around an invisible point, treat
- // the point as a fixed camera.
- if ( !target->GetBaseAnimating() && !target->GetModel() )
- {
- CalcRoamingView( eyeOrigin, eyeAngles, fov );
- return;
- }
-
- // QAngle tmpangles;
-
- Vector forward, viewpoint;
-
- // GetObserverCamOrigin() returns ragdoll pos if player is ragdolled
- Vector origin = target->GetObserverCamOrigin();
-
- VectorAdd( origin, GetChaseCamViewOffset( target ), origin );
-
- QAngle viewangles;
-
- if ( GetObserverMode() == OBS_MODE_IN_EYE )
- {
- viewangles = eyeAngles;
- }
- else if ( IsLocalPlayer() )
- {
- engine->GetViewAngles( viewangles );
- if ( UseVR() )
- {
- // Don't let people play with the pitch - they drive it into the ground or into the air and
- // it's distracting at best, nauseating at worst (e.g. when it clips through the ground plane).
- viewangles[PITCH] = 20.0f;
- }
- }
- else
- {
- viewangles = EyeAngles();
- }
-
- //=============================================================================
- // HPE_BEGIN:
- // [Forrest] Fix for (at least one potential case of) CSB-194. Spectating someone
- // who is headshotted by a teammate and then switching to chase cam leaves
- // you with a permanent roll to the camera that doesn't decay and is not reset
- // even when switching to different players or at the start of the next round
- // if you are still a spectator. (If you spawn as a player, the view is reset.
- // if you switch spectator modes, the view is reset.)
- //=============================================================================
-#ifdef CSTRIKE_DLL
- // The chase camera adopts the yaw and pitch of the previous camera, but the camera
- // should not roll.
- viewangles.z = 0;
-#endif
- //=============================================================================
- // HPE_END
- //=============================================================================
-
- m_flObserverChaseDistance += gpGlobals->frametime*48.0f;
-
- float flMinDistance = CHASE_CAM_DISTANCE_MIN;
- float flMaxDistance = CHASE_CAM_DISTANCE_MAX;
-
- if ( target && target->IsBaseTrain() )
- {
- // if this is a train, we want to be back a little further so we can see more of it
- flMaxDistance *= 2.5f;
- }
-
- if ( target )
- {
- C_BaseAnimating *pTargetAnimating = target->GetBaseAnimating();
- if ( pTargetAnimating )
- {
- float flScaleSquared = pTargetAnimating->GetModelScale() * pTargetAnimating->GetModelScale();
- flMinDistance *= flScaleSquared;
- flMaxDistance *= flScaleSquared;
- m_flObserverChaseDistance = flMaxDistance;
- }
- }
-
- if ( target && !target->IsPlayer() && target->IsNextBot() )
- {
- // if this is a boss, we want to be back a little further so we can see more of it
- flMaxDistance *= 2.5f;
- m_flObserverChaseDistance = flMaxDistance;
- }
-
- m_flObserverChaseDistance = clamp( m_flObserverChaseDistance, flMinDistance, flMaxDistance );
-
- AngleVectors( viewangles, &forward );
-
- VectorNormalize( forward );
-
- VectorMA(origin, -m_flObserverChaseDistance, forward, viewpoint );
-
- trace_t trace;
- CTraceFilterNoNPCsOrPlayer filter( target, COLLISION_GROUP_NONE );
- C_BaseEntity::PushEnableAbsRecomputations( false ); // HACK don't recompute positions while doing RayTrace
- UTIL_TraceHull( origin, viewpoint, WALL_MIN, WALL_MAX, MASK_SOLID, &filter, &trace );
- C_BaseEntity::PopEnableAbsRecomputations();
-
- if (trace.fraction < 1.0)
- {
- viewpoint = trace.endpos;
- m_flObserverChaseDistance = VectorLength(origin - eyeOrigin);
- }
-
- VectorCopy( viewangles, eyeAngles );
- VectorCopy( viewpoint, eyeOrigin );
-
- fov = GetFOV();
-}
-
-void C_BasePlayer::CalcRoamingView(Vector& eyeOrigin, QAngle& eyeAngles, float& fov)
-{
- C_BaseEntity *target = GetObserverTarget();
-
- if ( !target )
- {
- target = this;
- }
-
- m_flObserverChaseDistance = 0.0;
-
- eyeOrigin = target->EyePosition();
- eyeAngles = target->EyeAngles();
-
- if ( spec_track.GetInt() > 0 )
- {
- C_BaseEntity *target = ClientEntityList().GetBaseEntity( spec_track.GetInt() );
-
- if ( target )
- {
- Vector v = target->GetAbsOrigin(); v.z += 54;
- QAngle a; VectorAngles( v - eyeOrigin, a );
-
- NormalizeAngles( a );
- eyeAngles = a;
- engine->SetViewAngles( a );
- }
- }
-
- // Apply a smoothing offset to smooth out prediction errors.
- Vector vSmoothOffset;
- GetPredictionErrorSmoothingVector( vSmoothOffset );
- eyeOrigin += vSmoothOffset;
-
- fov = GetFOV();
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Calculate the view for the player while he's in freeze frame observer mode
-//-----------------------------------------------------------------------------
-void C_BasePlayer::CalcFreezeCamView( Vector& eyeOrigin, QAngle& eyeAngles, float& fov )
-{
- C_BaseEntity *pTarget = GetObserverTarget();
- if ( !pTarget )
- {
- CalcDeathCamView( eyeOrigin, eyeAngles, fov );
- return;
- }
-
- // Zoom towards our target
- float flCurTime = (gpGlobals->curtime - m_flFreezeFrameStartTime);
- float flBlendPerc = clamp( flCurTime / spec_freeze_traveltime.GetFloat(), 0.f, 1.f );
- flBlendPerc = SimpleSpline( flBlendPerc );
-
- Vector vecCamDesired = pTarget->GetObserverCamOrigin(); // Returns ragdoll origin if they're ragdolled
- VectorAdd( vecCamDesired, GetChaseCamViewOffset( pTarget ), vecCamDesired );
- Vector vecCamTarget = vecCamDesired;
- if ( pTarget->IsAlive() )
- {
- // Look at their chest, not their head
- Vector maxs = pTarget->GetBaseAnimating() ? VEC_HULL_MAX_SCALED( pTarget->GetBaseAnimating() ) : VEC_HULL_MAX;
- vecCamTarget.z -= (maxs.z * 0.5);
- }
- else
- {
- vecCamTarget.z += pTarget->GetBaseAnimating() ? VEC_DEAD_VIEWHEIGHT_SCALED( pTarget->GetBaseAnimating() ).z : VEC_DEAD_VIEWHEIGHT.z; // look over ragdoll, not through
- }
-
- // Figure out a view position in front of the target
- Vector vecEyeOnPlane = eyeOrigin;
- vecEyeOnPlane.z = vecCamTarget.z;
- Vector vecTargetPos = vecCamTarget;
- Vector vecToTarget = vecTargetPos - vecEyeOnPlane;
- VectorNormalize( vecToTarget );
-
- // Stop a few units away from the target, and shift up to be at the same height
- vecTargetPos = vecCamTarget - (vecToTarget * m_flFreezeFrameDistance);
- float flEyePosZ = pTarget->EyePosition().z;
- vecTargetPos.z = flEyePosZ + m_flFreezeZOffset;
-
- // Now trace out from the target, so that we're put in front of any walls
- trace_t trace;
- C_BaseEntity::PushEnableAbsRecomputations( false ); // HACK don't recompute positions while doing RayTrace
- UTIL_TraceHull( vecCamTarget, vecTargetPos, WALL_MIN, WALL_MAX, MASK_SOLID, pTarget, COLLISION_GROUP_NONE, &trace );
- C_BaseEntity::PopEnableAbsRecomputations();
- if (trace.fraction < 1.0)
- {
- // The camera's going to be really close to the target. So we don't end up
- // looking at someone's chest, aim close freezecams at the target's eyes.
- vecTargetPos = trace.endpos;
- vecCamTarget = vecCamDesired;
-
- // To stop all close in views looking up at character's chins, move the view up.
- vecTargetPos.z += fabs(vecCamTarget.z - vecTargetPos.z) * 0.85;
- C_BaseEntity::PushEnableAbsRecomputations( false ); // HACK don't recompute positions while doing RayTrace
- UTIL_TraceHull( vecCamTarget, vecTargetPos, WALL_MIN, WALL_MAX, MASK_SOLID, pTarget, COLLISION_GROUP_NONE, &trace );
- C_BaseEntity::PopEnableAbsRecomputations();
- vecTargetPos = trace.endpos;
- }
-
- // Look directly at the target
- vecToTarget = vecCamTarget - vecTargetPos;
- VectorNormalize( vecToTarget );
- VectorAngles( vecToTarget, eyeAngles );
-
- VectorLerp( m_vecFreezeFrameStart, vecTargetPos, flBlendPerc, eyeOrigin );
-
- if ( flCurTime >= spec_freeze_traveltime.GetFloat() && !m_bSentFreezeFrame )
- {
- IGameEvent *pEvent = gameeventmanager->CreateEvent( "freezecam_started" );
- if ( pEvent )
- {
- gameeventmanager->FireEventClientSide( pEvent );
- }
-
- m_bSentFreezeFrame = true;
- view->FreezeFrame( spec_freeze_time.GetFloat() );
- }
-}
-
-void C_BasePlayer::CalcInEyeCamView(Vector& eyeOrigin, QAngle& eyeAngles, float& fov)
-{
- C_BaseEntity *target = GetObserverTarget();
-
- if ( !target )
- {
- // just copy a save in-map position
- VectorCopy( EyePosition(), eyeOrigin );
- VectorCopy( EyeAngles(), eyeAngles );
- return;
- };
-
- if ( !target->IsAlive() )
- {
- // if dead, show from 3rd person
- CalcChaseCamView( eyeOrigin, eyeAngles, fov );
- return;
- }
-
- fov = GetFOV(); // TODO use tragets FOV
-
- m_flObserverChaseDistance = 0.0;
-
- eyeAngles = target->EyeAngles();
- eyeOrigin = target->GetAbsOrigin();
-
- // Apply punch angle
- VectorAdd( eyeAngles, GetPunchAngle(), eyeAngles );
-
-#if defined( REPLAY_ENABLED )
- if( engine->IsHLTV() || g_pEngineClientReplay->IsPlayingReplayDemo() )
-#else
- if( engine->IsHLTV() )
-#endif
- {
- C_BaseAnimating *pTargetAnimating = target->GetBaseAnimating();
- if ( target->GetFlags() & FL_DUCKING )
- {
- eyeOrigin += pTargetAnimating ? VEC_DUCK_VIEW_SCALED( pTargetAnimating ) : VEC_DUCK_VIEW;
- }
- else
- {
- eyeOrigin += pTargetAnimating ? VEC_VIEW_SCALED( pTargetAnimating ) : VEC_VIEW;
- }
- }
- else
- {
- Vector offset = GetViewOffset();
-#ifdef HL2MP
- offset = target->GetViewOffset();
-#endif
- eyeOrigin += offset; // hack hack
- }
-
- engine->SetViewAngles( eyeAngles );
-}
-
-float C_BasePlayer::GetDeathCamInterpolationTime()
-{
- return DEATH_ANIMATION_TIME;
-}
-
-
-void C_BasePlayer::CalcDeathCamView(Vector& eyeOrigin, QAngle& eyeAngles, float& fov)
-{
- CBaseEntity * pKiller = NULL;
-
- if ( mp_forcecamera.GetInt() == OBS_ALLOW_ALL )
- {
- // if mp_forcecamera is off let user see killer or look around
- pKiller = GetObserverTarget();
- eyeAngles = EyeAngles();
- }
-
- float interpolation = ( gpGlobals->curtime - m_flDeathTime ) / GetDeathCamInterpolationTime();
- interpolation = clamp( interpolation, 0.0f, 1.0f );
-
- m_flObserverChaseDistance += gpGlobals->frametime*48.0f;
- m_flObserverChaseDistance = clamp( m_flObserverChaseDistance, ( CHASE_CAM_DISTANCE_MIN * 2 ), CHASE_CAM_DISTANCE_MAX );
-
- QAngle aForward = eyeAngles;
- Vector origin = EyePosition();
-
- // NOTE: This will create the ragdoll in CSS if m_hRagdoll is set, but m_pRagdoll is not yet presetn
- IRagdoll *pRagdoll = GetRepresentativeRagdoll();
- if ( pRagdoll )
- {
- origin = pRagdoll->GetRagdollOrigin();
- origin.z += VEC_DEAD_VIEWHEIGHT_SCALED( this ).z;
- }
-
- if ( pKiller && pKiller->IsPlayer() && (pKiller != this) )
- {
- Vector vKiller = pKiller->EyePosition() - origin;
- QAngle aKiller; VectorAngles( vKiller, aKiller );
- InterpolateAngles( aForward, aKiller, eyeAngles, interpolation );
- };
-
- Vector vForward; AngleVectors( eyeAngles, &vForward );
-
- VectorNormalize( vForward );
-
- VectorMA( origin, -m_flObserverChaseDistance, vForward, eyeOrigin );
-
- trace_t trace; // clip against world
- C_BaseEntity::PushEnableAbsRecomputations( false ); // HACK don't recompute positions while doing RayTrace
- UTIL_TraceHull( origin, eyeOrigin, WALL_MIN, WALL_MAX, MASK_SOLID, this, COLLISION_GROUP_NONE, &trace );
- C_BaseEntity::PopEnableAbsRecomputations();
-
- if (trace.fraction < 1.0)
- {
- eyeOrigin = trace.endpos;
- m_flObserverChaseDistance = VectorLength(origin - eyeOrigin);
- }
-
- fov = GetFOV();
-}
-
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Return the weapon to have open the weapon selection on, based upon our currently active weapon
-// Base class just uses the weapon that's currently active.
-//-----------------------------------------------------------------------------
-C_BaseCombatWeapon *C_BasePlayer::GetActiveWeaponForSelection( void )
-{
- return GetActiveWeapon();
-}
-
-C_BaseAnimating* C_BasePlayer::GetRenderedWeaponModel()
-{
- // Attach to either their weapon model or their view model.
- if ( ShouldDrawLocalPlayer() || !IsLocalPlayer() )
- {
- return GetActiveWeapon();
- }
- else
- {
- return GetViewModel();
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Gets a pointer to the local player, if it exists yet.
-// Output : C_BasePlayer
-//-----------------------------------------------------------------------------
-C_BasePlayer *C_BasePlayer::GetLocalPlayer( void )
-{
- return s_pLocalPlayer;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : bThirdperson -
-//-----------------------------------------------------------------------------
-void C_BasePlayer::ThirdPersonSwitch( bool bThirdperson )
-{
- // We've switch from first to third, or vice versa.
- UpdateVisibility();
-
- // Update the visibility of anything bone attached to us.
- if ( IsLocalPlayer() )
- {
- bool bShouldDrawLocalPlayer = ShouldDrawLocalPlayer();
- for ( int i=0; i<GetNumBoneAttachments(); ++i )
- {
- C_BaseAnimating* pBoneAttachment = GetBoneAttachment( i );
- if ( pBoneAttachment )
- {
- if ( bShouldDrawLocalPlayer )
- {
- pBoneAttachment->RemoveEffects( EF_NODRAW );
- }
- else
- {
- pBoneAttachment->AddEffects( EF_NODRAW );
- }
- }
- }
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: single place to decide whether the camera is in the first-person position
-// NOTE - ShouldDrawLocalPlayer() can be true even if the camera is in the first-person position, e.g. in VR.
-//-----------------------------------------------------------------------------
-/*static*/ bool C_BasePlayer::LocalPlayerInFirstPersonView()
-{
- C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
- if ( pLocalPlayer == NULL )
- {
- return false;
- }
- int ObserverMode = pLocalPlayer->GetObserverMode();
- if ( ( ObserverMode == OBS_MODE_NONE ) || ( ObserverMode == OBS_MODE_IN_EYE ) )
- {
- return !input->CAM_IsThirdPerson() && ( !ToolsEnabled() || !ToolFramework_IsThirdPersonCamera() );
- }
- else
- {
- // Not looking at the local player, e.g. in a replay in third person mode or freelook.
- return false;
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: single place to decide whether the local player should draw
-//-----------------------------------------------------------------------------
-/*static*/ bool C_BasePlayer::ShouldDrawLocalPlayer()
-{
- if ( !UseVR() )
- {
- return !LocalPlayerInFirstPersonView() || cl_first_person_uses_world_model.GetBool();
- }
- else
- {
- static ConVarRef vr_first_person_uses_world_model( "vr_first_person_uses_world_model" );
- return !LocalPlayerInFirstPersonView() || vr_first_person_uses_world_model.GetBool();
- }
-}
-
-
-
-//-----------------------------------------------------------------------------
-// Purpose: single place to decide whether the camera is in the first-person position
-// NOTE - ShouldDrawLocalPlayer() can be true even if the camera is in the first-person position, e.g. in VR.
-//-----------------------------------------------------------------------------
-bool C_BasePlayer::InFirstPersonView()
-{
- if ( IsLocalPlayer() )
- {
- return LocalPlayerInFirstPersonView();
- }
- C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
- if ( pLocalPlayer == NULL )
- {
- return false;
- }
- // If this is who we're observing in first person, it's counted as the "local" player.
- if ( pLocalPlayer->GetObserverMode() == OBS_MODE_IN_EYE && pLocalPlayer->GetObserverTarget() == ToBasePlayer(this) )
- {
- return LocalPlayerInFirstPersonView();
- }
- return false;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: single place to decide whether the player is being drawn with the standard model (i.e. not the viewmodel)
-// NOTE - ShouldDrawLocalPlayer() can be true even if the camera is in the first-person position, e.g. in VR.
-//-----------------------------------------------------------------------------
-bool C_BasePlayer::ShouldDrawThisPlayer()
-{
- if ( !InFirstPersonView() )
- {
- return true;
- }
- if ( !UseVR() && cl_first_person_uses_world_model.GetBool() )
- {
- return true;
- }
- if ( UseVR() )
- {
- static ConVarRef vr_first_person_uses_world_model( "vr_first_person_uses_world_model" );
- if ( vr_first_person_uses_world_model.GetBool() )
- {
- return true;
- }
- }
- return false;
-}
-
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Output : Returns true on success, false on failure.
-//-----------------------------------------------------------------------------
-bool C_BasePlayer::IsLocalPlayer( void ) const
-{
- return ( GetLocalPlayer() == this );
-}
-
-int C_BasePlayer::GetUserID( void )
-{
- player_info_t pi;
-
- if ( !engine->GetPlayerInfo( entindex(), &pi ) )
- return -1;
-
- return pi.userID;
-}
-
-
-// For weapon prediction
-void C_BasePlayer::SetAnimation( PLAYER_ANIM playerAnim )
-{
- // FIXME
-}
-
-void C_BasePlayer::UpdateClientData( void )
-{
- // Update all the items
- for ( int i = 0; i < WeaponCount(); i++ )
- {
- if ( GetWeapon(i) ) // each item updates it's successors
- GetWeapon(i)->UpdateClientData( this );
- }
-}
-
-// Prediction stuff
-void C_BasePlayer::PreThink( void )
-{
-#if !defined( NO_ENTITY_PREDICTION )
- ItemPreFrame();
-
- UpdateClientData();
-
- UpdateUnderwaterState();
-
- // Update the player's fog data if necessary.
- UpdateFogController();
-
- if (m_lifeState >= LIFE_DYING)
- return;
-
- //
- // If we're not on the ground, we're falling. Update our falling velocity.
- //
- if ( !( GetFlags() & FL_ONGROUND ) )
- {
- m_Local.m_flFallVelocity = -GetAbsVelocity().z;
- }
-#endif
-}
-
-void C_BasePlayer::PostThink( void )
-{
-#if !defined( NO_ENTITY_PREDICTION )
- MDLCACHE_CRITICAL_SECTION();
-
- if ( IsAlive())
- {
- if ( !CommentaryModeShouldSwallowInput( this ) )
- {
- // do weapon stuff
- ItemPostFrame();
- }
-
- if ( GetFlags() & FL_ONGROUND )
- {
- m_Local.m_flFallVelocity = 0;
- }
-
- // Don't allow bogus sequence on player
- if ( GetSequence() == -1 )
- {
- SetSequence( 0 );
- }
-
- StudioFrameAdvance();
- }
-
- // Even if dead simulate entities
- SimulatePlayerSimulatedEntities();
-#endif
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: send various tool messages - viewoffset, and base class messages (flex and bones)
-//-----------------------------------------------------------------------------
-void C_BasePlayer::GetToolRecordingState( KeyValues *msg )
-{
- if ( !ToolsEnabled() )
- return;
-
- VPROF_BUDGET( "C_BasePlayer::GetToolRecordingState", VPROF_BUDGETGROUP_TOOLS );
-
- BaseClass::GetToolRecordingState( msg );
-
- msg->SetInt( "baseplayer", 1 );
- msg->SetInt( "localplayer", IsLocalPlayer() ? 1 : 0 );
- msg->SetString( "playername", GetPlayerName() );
-
- static CameraRecordingState_t state;
- state.m_flFOV = GetFOV();
-
- float flZNear = view->GetZNear();
- float flZFar = view->GetZFar();
- CalcView( state.m_vecEyePosition, state.m_vecEyeAngles, flZNear, flZFar, state.m_flFOV );
- state.m_bThirdPerson = !engine->IsPaused() && ::input->CAM_IsThirdPerson();
-
- // this is a straight copy from ClientModeShared::OverrideView,
- // When that method is removed in favor of rolling it into CalcView,
- // then this code can (should!) be removed
- if ( state.m_bThirdPerson )
- {
- Vector cam_ofs = g_ThirdPersonManager.GetCameraOffsetAngles();
-
- QAngle camAngles;
- camAngles[ PITCH ] = cam_ofs[ PITCH ];
- camAngles[ YAW ] = cam_ofs[ YAW ];
- camAngles[ ROLL ] = 0;
-
- Vector camForward, camRight, camUp;
- AngleVectors( camAngles, &camForward, &camRight, &camUp );
-
- VectorMA( state.m_vecEyePosition, -cam_ofs[ ROLL ], camForward, state.m_vecEyePosition );
-
- // Override angles from third person camera
- VectorCopy( camAngles, state.m_vecEyeAngles );
- }
-
- msg->SetPtr( "camera", &state );
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Simulate the player for this frame
-//-----------------------------------------------------------------------------
-void C_BasePlayer::Simulate()
-{
- //Frame updates
- if ( this == C_BasePlayer::GetLocalPlayer() )
- {
- //Update the flashlight
- Flashlight();
-
- // Update the player's fog data if necessary.
- UpdateFogController();
- }
- else
- {
- // update step sounds for all other players
- Vector vel;
- EstimateAbsVelocity( vel );
- UpdateStepSound( GetGroundSurface(), GetAbsOrigin(), vel );
- }
-
- BaseClass::Simulate();
- if ( IsNoInterpolationFrame() || Teleported() )
- {
- ResetLatched();
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Output : CBaseViewModel
-// Consider using GetRenderedWeaponModel() instead - it will get the
-// viewmodel or the active weapon as appropriate.
-//-----------------------------------------------------------------------------
-C_BaseViewModel *C_BasePlayer::GetViewModel( int index /*= 0*/, bool bObserverOK )
-{
- Assert( index >= 0 && index < MAX_VIEWMODELS );
-
- C_BaseViewModel *vm = m_hViewModel[ index ];
-
- if ( bObserverOK && GetObserverMode() == OBS_MODE_IN_EYE )
- {
- C_BasePlayer *target = ToBasePlayer( GetObserverTarget() );
-
- // get the targets viewmodel unless the target is an observer itself
- if ( target && target != this && !target->IsObserver() )
- {
- vm = target->GetViewModel( index );
- }
- }
-
- return vm;
-}
-
-C_BaseCombatWeapon *C_BasePlayer::GetActiveWeapon( void ) const
-{
- const C_BasePlayer *fromPlayer = this;
-
- // if localplayer is in InEye spectator mode, return weapon on chased player
- if ( (fromPlayer == GetLocalPlayer()) && ( GetObserverMode() == OBS_MODE_IN_EYE) )
- {
- C_BaseEntity *target = GetObserverTarget();
-
- if ( target && target->IsPlayer() )
- {
- fromPlayer = ToBasePlayer( target );
- }
- }
-
- return fromPlayer->C_BaseCombatCharacter::GetActiveWeapon();
-}
-
-//=========================================================
-// Autoaim
-// set crosshair position to point to enemey
-//=========================================================
-Vector C_BasePlayer::GetAutoaimVector( float flScale )
-{
- // Never autoaim a predicted weapon (for now)
- Vector forward;
- AngleVectors( GetAbsAngles() + m_Local.m_vecPunchAngle, &forward );
- return forward;
-}
-
-void C_BasePlayer::PlayPlayerJingle()
-{
-#ifndef _XBOX
- // Find player sound for shooter
- player_info_t info;
- engine->GetPlayerInfo( entindex(), &info );
-
- if ( !cl_customsounds.GetBool() )
- return;
-
- // Doesn't have a jingle sound
- if ( !info.customFiles[1] )
- return;
-
- char soundhex[ 16 ];
- Q_binarytohex( (byte *)&info.customFiles[1], sizeof( info.customFiles[1] ), soundhex, sizeof( soundhex ) );
-
- // See if logo has been downloaded.
- char fullsoundname[ 512 ];
- Q_snprintf( fullsoundname, sizeof( fullsoundname ), "sound/temp/%s.wav", soundhex );
-
- if ( !filesystem->FileExists( fullsoundname ) )
- {
- char custname[ 512 ];
- Q_snprintf( custname, sizeof( custname ), "download/user_custom/%c%c/%s.dat", soundhex[0], soundhex[1], soundhex );
- // it may have been downloaded but not copied under materials folder
- if ( !filesystem->FileExists( custname ) )
- return; // not downloaded yet
-
- // copy from download folder to materials/temp folder
- // this is done since material system can access only materials/*.vtf files
-
- if ( !engine->CopyLocalFile( custname, fullsoundname) )
- return;
- }
-
- Q_snprintf( fullsoundname, sizeof( fullsoundname ), "temp/%s.wav", soundhex );
-
- CLocalPlayerFilter filter;
-
- EmitSound_t ep;
- ep.m_nChannel = CHAN_VOICE;
- ep.m_pSoundName = fullsoundname;
- ep.m_flVolume = VOL_NORM;
- ep.m_SoundLevel = SNDLVL_NORM;
-
- C_BaseEntity::EmitSound( filter, GetSoundSourceIndex(), ep );
-#endif
-}
-
-// Stuff for prediction
-void C_BasePlayer::SetSuitUpdate(const char *name, int fgroup, int iNoRepeat)
-{
- // FIXME: Do something here?
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void C_BasePlayer::ResetAutoaim( void )
-{
-#if 0
- if (m_vecAutoAim.x != 0 || m_vecAutoAim.y != 0)
- {
- m_vecAutoAim = QAngle( 0, 0, 0 );
- engine->CrosshairAngle( edict(), 0, 0 );
- }
-#endif
- m_fOnTarget = false;
-}
-
-bool C_BasePlayer::ShouldPredict( void )
-{
-#if !defined( NO_ENTITY_PREDICTION )
- // Do this before calling into baseclass so prediction data block gets allocated
- if ( IsLocalPlayer() )
- {
- return true;
- }
-#endif
- return false;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Special processing for player simulation
-// NOTE: Don't chain to BaseClass!!!!
-//-----------------------------------------------------------------------------
-void C_BasePlayer::PhysicsSimulate( void )
-{
-#if !defined( NO_ENTITY_PREDICTION )
- VPROF( "C_BasePlayer::PhysicsSimulate" );
- // If we've got a moveparent, we must simulate that first.
- CBaseEntity *pMoveParent = GetMoveParent();
- if (pMoveParent)
- {
- pMoveParent->PhysicsSimulate();
- }
-
- // Make sure not to simulate this guy twice per frame
- if (m_nSimulationTick == gpGlobals->tickcount)
- return;
-
- m_nSimulationTick = gpGlobals->tickcount;
-
- if ( !IsLocalPlayer() )
- return;
-
- C_CommandContext *ctx = GetCommandContext();
- Assert( ctx );
- Assert( ctx->needsprocessing );
- if ( !ctx->needsprocessing )
- return;
-
- ctx->needsprocessing = false;
-
- // Handle FL_FROZEN.
- if(GetFlags() & FL_FROZEN)
- {
- ctx->cmd.forwardmove = 0;
- ctx->cmd.sidemove = 0;
- ctx->cmd.upmove = 0;
- ctx->cmd.buttons = 0;
- ctx->cmd.impulse = 0;
- //VectorCopy ( pl.v_angle, ctx->cmd.viewangles );
- }
-
- // Run the next command
- prediction->RunCommand(
- this,
- &ctx->cmd,
- MoveHelper() );
-#endif
-}
-
-const QAngle& C_BasePlayer::GetPunchAngle()
-{
- return m_Local.m_vecPunchAngle.Get();
-}
-
-
-void C_BasePlayer::SetPunchAngle( const QAngle &angle )
-{
- m_Local.m_vecPunchAngle = angle;
-}
-
-
-float C_BasePlayer::GetWaterJumpTime() const
-{
- return m_flWaterJumpTime;
-}
-
-void C_BasePlayer::SetWaterJumpTime( float flWaterJumpTime )
-{
- m_flWaterJumpTime = flWaterJumpTime;
-}
-
-float C_BasePlayer::GetSwimSoundTime() const
-{
- return m_flSwimSoundTime;
-}
-
-void C_BasePlayer::SetSwimSoundTime( float flSwimSoundTime )
-{
- m_flSwimSoundTime = flSwimSoundTime;
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Return true if this object can be +used by the player
-//-----------------------------------------------------------------------------
-bool C_BasePlayer::IsUseableEntity( CBaseEntity *pEntity, unsigned int requiredCaps )
-{
- return false;
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Output : float
-//-----------------------------------------------------------------------------
-float C_BasePlayer::GetFOV( void )
-{
- // Allow users to override the FOV during demo playback
- bool bUseDemoOverrideFov = engine->IsPlayingDemo() && demo_fov_override.GetFloat() > 0.0f;
-#if defined( REPLAY_ENABLED )
- bUseDemoOverrideFov = bUseDemoOverrideFov && !g_pEngineClientReplay->IsPlayingReplayDemo();
-#endif
- if ( bUseDemoOverrideFov )
- {
- return clamp( demo_fov_override.GetFloat(), 10.0f, 90.0f );
- }
-
- if ( GetObserverMode() == OBS_MODE_IN_EYE )
- {
- C_BasePlayer *pTargetPlayer = dynamic_cast<C_BasePlayer*>( GetObserverTarget() );
-
- // get fov from observer target. Not if target is observer itself
- if ( pTargetPlayer && !pTargetPlayer->IsObserver() )
- {
- return pTargetPlayer->GetFOV();
- }
- }
-
- // Allow our vehicle to override our FOV if it's currently at the default FOV.
- float flDefaultFOV;
- IClientVehicle *pVehicle = GetVehicle();
- if ( pVehicle )
- {
- CacheVehicleView();
- flDefaultFOV = ( m_flVehicleViewFOV == 0 ) ? GetDefaultFOV() : m_flVehicleViewFOV;
- }
- else
- {
- flDefaultFOV = GetDefaultFOV();
- }
-
- float fFOV = ( m_iFOV == 0 ) ? flDefaultFOV : m_iFOV;
-
- // Don't do lerping during prediction. It's only necessary when actually rendering,
- // and it'll cause problems due to prediction timing messiness.
- if ( !prediction->InPrediction() )
- {
- // See if we need to lerp the values for local player
- if ( IsLocalPlayer() && ( fFOV != m_iFOVStart ) && (m_Local.m_flFOVRate > 0.0f ) )
- {
- float deltaTime = (float)( gpGlobals->curtime - m_flFOVTime ) / m_Local.m_flFOVRate;
-
-#if !defined( NO_ENTITY_PREDICTION )
- if ( GetPredictable() )
- {
- // m_flFOVTime was set to a predicted time in the future, because the FOV change was predicted.
- deltaTime = (float)( GetFinalPredictedTime() - m_flFOVTime );
- deltaTime += ( gpGlobals->interpolation_amount * TICK_INTERVAL );
- deltaTime /= m_Local.m_flFOVRate;
- }
-#endif
-
- if ( deltaTime >= 1.0f )
- {
- //If we're past the zoom time, just take the new value and stop lerping
- m_iFOVStart = fFOV;
- }
- else
- {
- fFOV = SimpleSplineRemapValClamped( deltaTime, 0.0f, 1.0f, (float) m_iFOVStart, fFOV );
- }
- }
- }
-
- return fFOV;
-}
-
-void RecvProxy_LocalVelocityX( const CRecvProxyData *pData, void *pStruct, void *pOut )
-{
- C_BasePlayer *pPlayer = (C_BasePlayer *) pStruct;
-
- Assert( pPlayer );
-
- float flNewVel_x = pData->m_Value.m_Float;
-
- Vector vecVelocity = pPlayer->GetLocalVelocity();
-
- if( vecVelocity.x != flNewVel_x ) // Should this use an epsilon check?
- {
- vecVelocity.x = flNewVel_x;
- pPlayer->SetLocalVelocity( vecVelocity );
- }
-}
-
-void RecvProxy_LocalVelocityY( const CRecvProxyData *pData, void *pStruct, void *pOut )
-{
- C_BasePlayer *pPlayer = (C_BasePlayer *) pStruct;
-
- Assert( pPlayer );
-
- float flNewVel_y = pData->m_Value.m_Float;
-
- Vector vecVelocity = pPlayer->GetLocalVelocity();
-
- if( vecVelocity.y != flNewVel_y )
- {
- vecVelocity.y = flNewVel_y;
- pPlayer->SetLocalVelocity( vecVelocity );
- }
-}
-
-void RecvProxy_LocalVelocityZ( const CRecvProxyData *pData, void *pStruct, void *pOut )
-{
- C_BasePlayer *pPlayer = (C_BasePlayer *) pStruct;
-
- Assert( pPlayer );
-
- float flNewVel_z = pData->m_Value.m_Float;
-
- Vector vecVelocity = pPlayer->GetLocalVelocity();
-
- if( vecVelocity.z != flNewVel_z )
- {
- vecVelocity.z = flNewVel_z;
- pPlayer->SetLocalVelocity( vecVelocity );
- }
-}
-
-void RecvProxy_ObserverTarget( const CRecvProxyData *pData, void *pStruct, void *pOut )
-{
- C_BasePlayer *pPlayer = (C_BasePlayer *) pStruct;
-
- Assert( pPlayer );
-
- EHANDLE hTarget;
-
- RecvProxy_IntToEHandle( pData, pStruct, &hTarget );
-
- pPlayer->SetObserverTarget( hTarget );
-}
-
-void RecvProxy_ObserverMode( const CRecvProxyData *pData, void *pStruct, void *pOut )
-{
- C_BasePlayer *pPlayer = (C_BasePlayer *) pStruct;
-
- Assert( pPlayer );
-
- pPlayer->SetObserverMode ( pData->m_Value.m_Int );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Remove this player from a vehicle
-//-----------------------------------------------------------------------------
-void C_BasePlayer::LeaveVehicle( void )
-{
- if ( NULL == m_hVehicle.Get() )
- return;
-
-// Let server do this for now
-#if 0
- IClientVehicle *pVehicle = GetVehicle();
- Assert( pVehicle );
-
- int nRole = pVehicle->GetPassengerRole( this );
- Assert( nRole != VEHICLE_ROLE_NONE );
-
- SetParent( NULL );
-
- // Find the first non-blocked exit point:
- Vector vNewPos = GetAbsOrigin();
- QAngle qAngles = GetAbsAngles();
- pVehicle->GetPassengerExitPoint( nRole, &vNewPos, &qAngles );
- OnVehicleEnd( vNewPos );
- SetAbsOrigin( vNewPos );
- SetAbsAngles( qAngles );
-
- m_Local.m_iHideHUD &= ~HIDEHUD_WEAPONSELECTION;
- RemoveEffects( EF_NODRAW );
-
- SetMoveType( MOVETYPE_WALK );
- SetCollisionGroup( COLLISION_GROUP_PLAYER );
-
- qAngles[ROLL] = 0;
- SnapEyeAngles( qAngles );
-
- m_hVehicle = NULL;
- pVehicle->SetPassenger(nRole, NULL);
-
- Weapon_Switch( m_hLastWeapon );
-#endif
-}
-
-
-float C_BasePlayer::GetMinFOV() const
-{
- if ( gpGlobals->maxClients == 1 )
- {
- // Let them do whatever they want, more or less, in single player
- return 5;
- }
- else
- {
- return 75;
- }
-}
-
-float C_BasePlayer::GetFinalPredictedTime() const
-{
- return ( m_nFinalPredictedTick * TICK_INTERVAL );
-}
-
-void C_BasePlayer::NotePredictionError( const Vector &vDelta )
-{
- // don't worry about prediction errors when dead
- if ( !IsAlive() )
- return;
-
-#if !defined( NO_ENTITY_PREDICTION )
- Vector vOldDelta;
-
- GetPredictionErrorSmoothingVector( vOldDelta );
-
- // sum all errors within smoothing time
- m_vecPredictionError = vDelta + vOldDelta;
-
- // remember when last error happened
- m_flPredictionErrorTime = gpGlobals->curtime;
-
- ResetLatched();
-#endif
-}
-
-
-// offset curtime and setup bones at that time using fake interpolation
-// fake interpolation means we don't have reliable interpolation history (the local player doesn't animate locally)
-// so we just modify cycle and origin directly and use that as a fake guess
-void C_BasePlayer::ForceSetupBonesAtTimeFakeInterpolation( matrix3x4_t *pBonesOut, float curtimeOffset )
-{
- // we don't have any interpolation data, so fake it
- float cycle = m_flCycle;
- Vector origin = GetLocalOrigin();
-
- // blow the cached prev bones
- InvalidateBoneCache();
- // reset root position to flTime
- Interpolate( gpGlobals->curtime + curtimeOffset );
-
- // force cycle back by boneDt
- m_flCycle = fmod( 10 + cycle + m_flPlaybackRate * curtimeOffset, 1.0f );
- SetLocalOrigin( origin + curtimeOffset * GetLocalVelocity() );
- // Setup bone state to extrapolate physics velocity
- SetupBones( pBonesOut, MAXSTUDIOBONES, BONE_USED_BY_ANYTHING, gpGlobals->curtime + curtimeOffset );
-
- m_flCycle = cycle;
- SetLocalOrigin( origin );
-}
-
-void C_BasePlayer::GetRagdollInitBoneArrays( matrix3x4_t *pDeltaBones0, matrix3x4_t *pDeltaBones1, matrix3x4_t *pCurrentBones, float boneDt )
-{
- if ( !IsLocalPlayer() )
- {
- BaseClass::GetRagdollInitBoneArrays(pDeltaBones0, pDeltaBones1, pCurrentBones, boneDt);
- return;
- }
- ForceSetupBonesAtTimeFakeInterpolation( pDeltaBones0, -boneDt );
- ForceSetupBonesAtTimeFakeInterpolation( pDeltaBones1, 0 );
- float ragdollCreateTime = PhysGetSyncCreateTime();
- if ( ragdollCreateTime != gpGlobals->curtime )
- {
- ForceSetupBonesAtTimeFakeInterpolation( pCurrentBones, ragdollCreateTime - gpGlobals->curtime );
- }
- else
- {
- SetupBones( pCurrentBones, MAXSTUDIOBONES, BONE_USED_BY_ANYTHING, gpGlobals->curtime );
- }
-}
-
-
-void C_BasePlayer::GetPredictionErrorSmoothingVector( Vector &vOffset )
-{
-#if !defined( NO_ENTITY_PREDICTION )
- if ( engine->IsPlayingDemo() || !cl_smooth.GetInt() || !cl_predict->GetInt() || engine->IsPaused() )
- {
- vOffset.Init();
- return;
- }
-
- float errorAmount = ( gpGlobals->curtime - m_flPredictionErrorTime ) / cl_smoothtime.GetFloat();
-
- if ( errorAmount >= 1.0f )
- {
- vOffset.Init();
- return;
- }
-
- errorAmount = 1.0f - errorAmount;
-
- vOffset = m_vecPredictionError * errorAmount;
-#else
- vOffset.Init();
-#endif
-}
-
-
-IRagdoll* C_BasePlayer::GetRepresentativeRagdoll() const
-{
- return m_pRagdoll;
-}
-
-IMaterial *C_BasePlayer::GetHeadLabelMaterial( void )
-{
- if ( GetClientVoiceMgr() == NULL )
- return NULL;
-
- return GetClientVoiceMgr()->GetHeadLabelMaterial();
-}
-
-bool IsInFreezeCam( void )
-{
- C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
- if ( pPlayer && pPlayer->GetObserverMode() == OBS_MODE_FREEZECAM )
- return true;
-
- return false;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Set the fog controller data per player.
-// Input : &inputdata -
-//-----------------------------------------------------------------------------
-void C_BasePlayer::FogControllerChanged( bool bSnap )
-{
- if ( m_Local.m_PlayerFog.m_hCtrl )
- {
- fogparams_t *pFogParams = &(m_Local.m_PlayerFog.m_hCtrl->m_fog);
-
- /*
- Msg("Updating Fog Target: (%d,%d,%d) %.0f,%.0f -> (%d,%d,%d) %.0f,%.0f (%.2f seconds)\n",
- m_CurrentFog.colorPrimary.GetR(), m_CurrentFog.colorPrimary.GetB(), m_CurrentFog.colorPrimary.GetG(),
- m_CurrentFog.start.Get(), m_CurrentFog.end.Get(),
- pFogParams->colorPrimary.GetR(), pFogParams->colorPrimary.GetB(), pFogParams->colorPrimary.GetG(),
- pFogParams->start.Get(), pFogParams->end.Get(), pFogParams->duration.Get() );*/
-
-
- // Setup the fog color transition.
- m_Local.m_PlayerFog.m_OldColor = m_CurrentFog.colorPrimary;
- m_Local.m_PlayerFog.m_flOldStart = m_CurrentFog.start;
- m_Local.m_PlayerFog.m_flOldEnd = m_CurrentFog.end;
-
- m_Local.m_PlayerFog.m_NewColor = pFogParams->colorPrimary;
- m_Local.m_PlayerFog.m_flNewStart = pFogParams->start;
- m_Local.m_PlayerFog.m_flNewEnd = pFogParams->end;
-
- m_Local.m_PlayerFog.m_flTransitionTime = bSnap ? -1 : gpGlobals->curtime;
-
- m_CurrentFog = *pFogParams;
-
- // Update the fog player's local fog data with the fog controller's data if need be.
- UpdateFogController();
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Check to see that the controllers data is up to date.
-//-----------------------------------------------------------------------------
-void C_BasePlayer::UpdateFogController( void )
-{
- if ( m_Local.m_PlayerFog.m_hCtrl )
- {
- // Don't bother copying while we're transitioning, since it'll be stomped in UpdateFogBlend();
- if ( m_Local.m_PlayerFog.m_flTransitionTime == -1 && (m_hOldFogController == m_Local.m_PlayerFog.m_hCtrl) )
- {
- fogparams_t *pFogParams = &(m_Local.m_PlayerFog.m_hCtrl->m_fog);
- if ( m_CurrentFog != *pFogParams )
- {
- /*
- Msg("FORCING UPDATE: (%d,%d,%d) %.0f,%.0f -> (%d,%d,%d) %.0f,%.0f (%.2f seconds)\n",
- m_CurrentFog.colorPrimary.GetR(), m_CurrentFog.colorPrimary.GetB(), m_CurrentFog.colorPrimary.GetG(),
- m_CurrentFog.start.Get(), m_CurrentFog.end.Get(),
- pFogParams->colorPrimary.GetR(), pFogParams->colorPrimary.GetB(), pFogParams->colorPrimary.GetG(),
- pFogParams->start.Get(), pFogParams->end.Get(), pFogParams->duration.Get() );*/
-
-
- m_CurrentFog = *pFogParams;
- }
- }
- }
- else
- {
- if ( m_CurrentFog.farz != -1 || m_CurrentFog.enable != false )
- {
- // No fog controller in this level. Use default fog parameters.
- m_CurrentFog.farz = -1;
- m_CurrentFog.enable = false;
- }
- }
-
- // Update the fog blending state - of necessary.
- UpdateFogBlend();
-}
-
-//-----------------------------------------------------------------------------
-//
-//-----------------------------------------------------------------------------
-void C_BasePlayer::UpdateFogBlend( void )
-{
- // Transition.
- if ( m_Local.m_PlayerFog.m_flTransitionTime != -1 )
- {
- float flTimeDelta = gpGlobals->curtime - m_Local.m_PlayerFog.m_flTransitionTime;
- if ( flTimeDelta < m_CurrentFog.duration )
- {
- float flScale = flTimeDelta / m_CurrentFog.duration;
- m_CurrentFog.colorPrimary.SetR( ( m_Local.m_PlayerFog.m_NewColor.r * flScale ) + ( m_Local.m_PlayerFog.m_OldColor.r * ( 1.0f - flScale ) ) );
- m_CurrentFog.colorPrimary.SetG( ( m_Local.m_PlayerFog.m_NewColor.g * flScale ) + ( m_Local.m_PlayerFog.m_OldColor.g * ( 1.0f - flScale ) ) );
- m_CurrentFog.colorPrimary.SetB( ( m_Local.m_PlayerFog.m_NewColor.b * flScale ) + ( m_Local.m_PlayerFog.m_OldColor.b * ( 1.0f - flScale ) ) );
- m_CurrentFog.start.Set( ( m_Local.m_PlayerFog.m_flNewStart * flScale ) + ( ( m_Local.m_PlayerFog.m_flOldStart * ( 1.0f - flScale ) ) ) );
- m_CurrentFog.end.Set( ( m_Local.m_PlayerFog.m_flNewEnd * flScale ) + ( ( m_Local.m_PlayerFog.m_flOldEnd * ( 1.0f - flScale ) ) ) );
- }
- else
- {
- // Slam the final fog values.
- m_CurrentFog.colorPrimary.SetR( m_Local.m_PlayerFog.m_NewColor.r );
- m_CurrentFog.colorPrimary.SetG( m_Local.m_PlayerFog.m_NewColor.g );
- m_CurrentFog.colorPrimary.SetB( m_Local.m_PlayerFog.m_NewColor.b );
- m_CurrentFog.start.Set( m_Local.m_PlayerFog.m_flNewStart );
- m_CurrentFog.end.Set( m_Local.m_PlayerFog.m_flNewEnd );
- m_Local.m_PlayerFog.m_flTransitionTime = -1;
-
- /*
- Msg("Finished transition to (%d,%d,%d) %.0f,%.0f\n",
- m_CurrentFog.colorPrimary.GetR(), m_CurrentFog.colorPrimary.GetB(), m_CurrentFog.colorPrimary.GetG(),
- m_CurrentFog.start.Get(), m_CurrentFog.end.Get() );*/
-
- }
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-bool C_BasePlayer::GetSteamID( CSteamID *pID )
-{
- // try to make this a little more efficient
-
- player_info_t pi;
- if ( engine->GetPlayerInfo( entindex(), &pi ) )
- {
- if ( pi.friendsID && steamapicontext && steamapicontext->SteamUtils() )
- {
-#if 1 // new
- static EUniverse universe = k_EUniverseInvalid;
-
- if ( universe == k_EUniverseInvalid )
- universe = steamapicontext->SteamUtils()->GetConnectedUniverse();
-
- pID->InstancedSet( pi.friendsID, 1, universe, k_EAccountTypeIndividual );
-#else // old
- pID->InstancedSet( pi.friendsID, 1, steamapicontext->SteamUtils()->GetConnectedUniverse(), k_EAccountTypeIndividual );
-#endif
-
- return true;
- }
- }
- return false;
-}
-
-#if defined USES_ECON_ITEMS
-//-----------------------------------------------------------------------------
-// Purpose: Update the visibility of our worn items.
-//-----------------------------------------------------------------------------
-void C_BasePlayer::UpdateWearables( void )
-{
- for ( int i=0; i<m_hMyWearables.Count(); ++i )
- {
- CEconWearable* pItem = m_hMyWearables[i];
- if ( pItem )
- {
- pItem->ValidateModelIndex();
- pItem->UpdateVisibility();
- }
- }
-}
-#endif // USES_ECON_ITEMS
-
-
-//-----------------------------------------------------------------------------
-// Purpose: In meathook mode, fix the bone transforms to hang the user's own
-// avatar under the camera.
-//-----------------------------------------------------------------------------
-void C_BasePlayer::BuildFirstPersonMeathookTransformations( CStudioHdr *hdr, Vector *pos, Quaternion q[], const matrix3x4_t& cameraTransform, int boneMask, CBoneBitList &boneComputed, const char *pchHeadBoneName )
-{
- // Handle meathook mode. If we aren't rendering, just use last frame's transforms
- if ( !InFirstPersonView() )
- return;
-
- // If we're in third-person view, don't do anything special.
- // If we're in first-person view rendering the main view and using the viewmodel, we shouldn't have even got here!
- // If we're in first-person view rendering the main view(s), meathook and headless.
- // If we're in first-person view rendering shadowbuffers/reflections, don't do anything special either (we could do meathook but with a head?)
- if ( IsAboutToRagdoll() )
- {
- // We're re-animating specifically to set up the ragdoll.
- // Meathook can push the player through the floor, which makes the ragdoll fall through the world, which is no good.
- // So do nothing.
- return;
- }
-
- if ( !DrawingMainView() )
- {
- return;
- }
-
- // If we aren't drawing the player anyway, don't mess with the bones. This can happen in Portal.
- if( !ShouldDrawThisPlayer() )
- {
- return;
- }
-
- m_BoneAccessor.SetWritableBones( BONE_USED_BY_ANYTHING );
-
- matrix3x4_t &mHeadTransform = GetBoneForWrite( LookupBone( pchHeadBoneName ) );
-
- // "up" on the head bone is along the negative Y axis - not sure why.
- //Vector vHeadTransformUp ( -mHeadTransform[0][1], -mHeadTransform[1][1], -mHeadTransform[2][1] );
- //Vector vHeadTransformFwd ( mHeadTransform[0][1], mHeadTransform[1][1], mHeadTransform[2][1] );
- Vector vHeadTransformTranslation ( mHeadTransform[0][3], mHeadTransform[1][3], mHeadTransform[2][3] );
-
-
- // Find out where the player's head (driven by the HMD) is in the world.
- // We can't move this with animations or effects without causing nausea, so we need to move
- // the whole body so that the animated head is in the right place to match the player-controlled head.
- Vector vHeadUp;
- bool bMeathookEnable = true;
- Vector vRealPivotPoint;
- bool bEnableDecapitation = true;
- if( UseVR() )
- {
- static ConVarRef vr_neck_pivot_ingame_up( "vr_neck_pivot_ingame_up" );
- static ConVarRef vr_neck_pivot_ingame_fwd( "vr_neck_pivot_ingame_fwd" );
- static ConVarRef vr_meathook_enable ( "vr_meathook_enable" );
- static ConVarRef vr_decapitation_enable ( "vr_decapitation_enable" );
-
- VMatrix mWorldFromMideye = g_ClientVirtualReality.GetWorldFromMidEye();
-
- bMeathookEnable = vr_meathook_enable.GetBool();
- bEnableDecapitation = vr_decapitation_enable.GetBool();
-
- // What we do here is:
- // * Take the required eye pos+orn - the actual pose the player is controlling with the HMD.
- // * Go downwards in that space by headtrack_neck_pivot_ingame_* - this is now the neck-pivot in the game world of where the player is actually looking.
- // * Now place the body of the animated character so that the head bone is at that position.
- // The head bone is the neck pivot point of the in-game character.
-
- Vector vRealMidEyePos = mWorldFromMideye.GetTranslation();
- vRealPivotPoint = vRealMidEyePos - ( mWorldFromMideye.GetUp() * vr_neck_pivot_ingame_up.GetFloat() ) - ( mWorldFromMideye.GetForward() * vr_neck_pivot_ingame_fwd.GetFloat() );
- }
- else
- {
- // figure out where to put the body from the aim angles
- Vector vForward, vRight, vUp;
- AngleVectors( MainViewAngles(), &vForward, &vRight, &vUp );
-
- vRealPivotPoint = MainViewOrigin() - ( vUp * 7.3f ) - ( vForward * 3.f );
- }
-
- Vector vDeltaToAdd = vRealPivotPoint - vHeadTransformTranslation;
-
-
- if ( bMeathookEnable )
- {
- // Now add this offset to the entire skeleton.
- for (int i = 0; i < hdr->numbones(); i++)
- {
- // Only update bones reference by the bone mask.
- if ( !( hdr->boneFlags( i ) & boneMask ) )
- {
- continue;
- }
- matrix3x4_t& bone = GetBoneForWrite( i );
- Vector vBonePos;
- MatrixGetTranslation ( bone, vBonePos );
- vBonePos += vDeltaToAdd;
- MatrixSetTranslation ( vBonePos, bone );
- }
- }
-
- if ( bEnableDecapitation )
- {
- // Then scale the head to zero, but leave its position - forms a "neck stub".
- // This prevents us rendering junk all over the screen, e.g. inside of mouth, etc.
- MatrixScaleByZero ( mHeadTransform );
-
- // TODO: right now we nuke the hats by shrinking them to nothing,
- // but it feels like we should do something more sensible.
- // For example, for one sniper taunt he takes his hat off and waves it - would be nice to see it then.
- int iHelm = LookupBone( "prp_helmet" );
- if ( iHelm != -1 )
- {
- // Scale the helmet.
- matrix3x4_t &transformhelmet = GetBoneForWrite( iHelm );
- MatrixScaleByZero ( transformhelmet );
- }
-
- iHelm = LookupBone( "prp_hat" );
- if ( iHelm != -1 )
- {
- matrix3x4_t &transformhelmet = GetBoneForWrite( iHelm );
- MatrixScaleByZero ( transformhelmet );
- }
- }
-
-}
-
-
-
-void CC_DumpClientSoundscapeData( const CCommand& args )
-{
- C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
- if ( !pPlayer )
- return;
-
- Msg("Client Soundscape data dump:\n");
- Msg(" Position: %.2f %.2f %.2f\n", pPlayer->GetAbsOrigin().x, pPlayer->GetAbsOrigin().y, pPlayer->GetAbsOrigin().z );
- Msg(" soundscape index: %d\n", pPlayer->m_Local.m_audio.soundscapeIndex.Get() );
- Msg(" entity index: %d\n", pPlayer->m_Local.m_audio.ent.Get() ? pPlayer->m_Local.m_audio.ent->entindex() : -1 );
- if ( pPlayer->m_Local.m_audio.ent.Get() )
- {
- Msg(" entity pos: %.2f %.2f %.2f\n", pPlayer->m_Local.m_audio.ent.Get()->GetAbsOrigin().x, pPlayer->m_Local.m_audio.ent.Get()->GetAbsOrigin().y, pPlayer->m_Local.m_audio.ent.Get()->GetAbsOrigin().z );
- if ( pPlayer->m_Local.m_audio.ent.Get()->IsDormant() )
- {
- Msg(" ENTITY IS DORMANT\n");
- }
- }
- bool bFoundOne = false;
- for ( int i = 0; i < NUM_AUDIO_LOCAL_SOUNDS; i++ )
- {
- if ( pPlayer->m_Local.m_audio.localBits & (1<<i) )
- {
- if ( !bFoundOne )
- {
- Msg(" Sound Positions:\n");
- bFoundOne = true;
- }
-
- Vector vecPos = pPlayer->m_Local.m_audio.localSound[i];
- Msg(" %d: %.2f %.2f %.2f\n", i, vecPos.x,vecPos.y, vecPos.z );
- }
- }
-
- Msg("End dump.\n");
-}
-static ConCommand soundscape_dumpclient("soundscape_dumpclient", CC_DumpClientSoundscapeData, "Dumps the client's soundscape data.\n", FCVAR_CHEAT);
+//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Client-side CBasePlayer. +// +// - Manages the player's flashlight effect. +// +//===========================================================================// +#include "cbase.h" +#include "c_baseplayer.h" +#include "flashlighteffect.h" +#include "weapon_selection.h" +#include "history_resource.h" +#include "iinput.h" +#include "input.h" +#include "view.h" +#include "iviewrender.h" +#include "iclientmode.h" +#include "in_buttons.h" +#include "engine/IEngineSound.h" +#include "c_soundscape.h" +#include "usercmd.h" +#include "c_playerresource.h" +#include "iclientvehicle.h" +#include "view_shared.h" +#include "movevars_shared.h" +#include "prediction.h" +#include "tier0/vprof.h" +#include "filesystem.h" +#include "bitbuf.h" +#include "KeyValues.h" +#include "particles_simple.h" +#include "fx_water.h" +#include "hltvcamera.h" +#include "toolframework/itoolframework.h" +#include "toolframework_client.h" +#include "view_scene.h" +#include "c_vguiscreen.h" +#include "datacache/imdlcache.h" +#include "vgui/ISurface.h" +#include "voice_status.h" +#include "fx.h" +#include "dt_utlvector_recv.h" +#include "cam_thirdperson.h" +#if defined( REPLAY_ENABLED ) +#include "replay/replaycamera.h" +#include "replay/ireplaysystem.h" +#include "replay/ienginereplay.h" +#endif +#include "steam/steam_api.h" +#include "headtrack/isourcevirtualreality.h" +#include "client_virtualreality.h" + +#if defined USES_ECON_ITEMS +#include "econ_wearable.h" +#endif + +// NVNT haptics system interface +#include "haptics/ihaptics.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +// Don't alias here +#if defined( CBasePlayer ) +#undef CBasePlayer +#endif + +int g_nKillCamMode = OBS_MODE_NONE; +int g_nKillCamTarget1 = 0; +int g_nKillCamTarget2 = 0; + +extern ConVar mp_forcecamera; // in gamevars_shared.h + +#define FLASHLIGHT_DISTANCE 1000 +#define MAX_VGUI_INPUT_MODE_SPEED 30 +#define MAX_VGUI_INPUT_MODE_SPEED_SQ (MAX_VGUI_INPUT_MODE_SPEED*MAX_VGUI_INPUT_MODE_SPEED) + +static Vector WALL_MIN(-WALL_OFFSET,-WALL_OFFSET,-WALL_OFFSET); +static Vector WALL_MAX(WALL_OFFSET,WALL_OFFSET,WALL_OFFSET); + +bool CommentaryModeShouldSwallowInput( C_BasePlayer *pPlayer ); + +extern ConVar default_fov; +#ifndef _XBOX +extern ConVar sensitivity; +#endif + +static C_BasePlayer *s_pLocalPlayer = NULL; + +static ConVar cl_customsounds ( "cl_customsounds", "0", 0, "Enable customized player sound playback" ); +static ConVar spec_track ( "spec_track", "0", 0, "Tracks an entity in spec mode" ); +static ConVar cl_smooth ( "cl_smooth", "1", 0, "Smooth view/eye origin after prediction errors" ); +static ConVar cl_smoothtime ( + "cl_smoothtime", + "0.1", + 0, + "Smooth client's view after prediction error over this many seconds", + true, 0.01, // min/max is 0.01/2.0 + true, 2.0 + ); + +#ifdef CSTRIKE_DLL +ConVar spec_freeze_time( "spec_freeze_time", "5.0", FCVAR_CHEAT | FCVAR_REPLICATED, "Time spend frozen in observer freeze cam." ); +ConVar spec_freeze_traveltime( "spec_freeze_traveltime", "0.7", FCVAR_CHEAT | FCVAR_REPLICATED, "Time taken to zoom in to frame a target in observer freeze cam.", true, 0.01, false, 0 ); +ConVar spec_freeze_distance_min( "spec_freeze_distance_min", "80", FCVAR_CHEAT, "Minimum random distance from the target to stop when framing them in observer freeze cam." ); +ConVar spec_freeze_distance_max( "spec_freeze_distance_max", "90", FCVAR_CHEAT, "Maximum random distance from the target to stop when framing them in observer freeze cam." ); +#else +ConVar spec_freeze_time( "spec_freeze_time", "4.0", FCVAR_CHEAT | FCVAR_REPLICATED, "Time spend frozen in observer freeze cam." ); +ConVar spec_freeze_traveltime( "spec_freeze_traveltime", "0.4", FCVAR_CHEAT | FCVAR_REPLICATED, "Time taken to zoom in to frame a target in observer freeze cam.", true, 0.01, false, 0 ); +ConVar spec_freeze_distance_min( "spec_freeze_distance_min", "96", FCVAR_CHEAT, "Minimum random distance from the target to stop when framing them in observer freeze cam." ); +ConVar spec_freeze_distance_max( "spec_freeze_distance_max", "200", FCVAR_CHEAT, "Maximum random distance from the target to stop when framing them in observer freeze cam." ); +#endif + +static ConVar cl_first_person_uses_world_model ( "cl_first_person_uses_world_model", "0", FCVAR_ARCHIVE, "Causes the third person model to be drawn instead of the view model" ); + +ConVar demo_fov_override( "demo_fov_override", "0", FCVAR_CLIENTDLL | FCVAR_DONTRECORD, "If nonzero, this value will be used to override FOV during demo playback." ); + +void RecvProxy_LocalVelocityX( const CRecvProxyData *pData, void *pStruct, void *pOut ); +void RecvProxy_LocalVelocityY( const CRecvProxyData *pData, void *pStruct, void *pOut ); +void RecvProxy_LocalVelocityZ( const CRecvProxyData *pData, void *pStruct, void *pOut ); + +void RecvProxy_ObserverTarget( const CRecvProxyData *pData, void *pStruct, void *pOut ); +void RecvProxy_ObserverMode ( const CRecvProxyData *pData, void *pStruct, void *pOut ); + +// -------------------------------------------------------------------------------- // +// RecvTable for CPlayerState. +// -------------------------------------------------------------------------------- // + + BEGIN_RECV_TABLE_NOBASE(CPlayerState, DT_PlayerState) + RecvPropInt (RECVINFO(deadflag)), + END_RECV_TABLE() + + +BEGIN_RECV_TABLE_NOBASE( CPlayerLocalData, DT_Local ) + RecvPropArray3( RECVINFO_ARRAY(m_chAreaBits), RecvPropInt(RECVINFO(m_chAreaBits[0]))), + RecvPropArray3( RECVINFO_ARRAY(m_chAreaPortalBits), RecvPropInt(RECVINFO(m_chAreaPortalBits[0]))), + RecvPropInt(RECVINFO(m_iHideHUD)), + + // View + + RecvPropFloat(RECVINFO(m_flFOVRate)), + + RecvPropInt (RECVINFO(m_bDucked)), + RecvPropInt (RECVINFO(m_bDucking)), + RecvPropInt (RECVINFO(m_bInDuckJump)), + RecvPropFloat (RECVINFO(m_flDucktime)), + RecvPropFloat (RECVINFO(m_flDuckJumpTime)), + RecvPropFloat (RECVINFO(m_flJumpTime)), + RecvPropFloat (RECVINFO(m_flFallVelocity)), + +#if PREDICTION_ERROR_CHECK_LEVEL > 1 + RecvPropFloat (RECVINFO_NAME( m_vecPunchAngle.m_Value[0], m_vecPunchAngle[0])), + RecvPropFloat (RECVINFO_NAME( m_vecPunchAngle.m_Value[1], m_vecPunchAngle[1])), + RecvPropFloat (RECVINFO_NAME( m_vecPunchAngle.m_Value[2], m_vecPunchAngle[2] )), + RecvPropFloat (RECVINFO_NAME( m_vecPunchAngleVel.m_Value[0], m_vecPunchAngleVel[0] )), + RecvPropFloat (RECVINFO_NAME( m_vecPunchAngleVel.m_Value[1], m_vecPunchAngleVel[1] )), + RecvPropFloat (RECVINFO_NAME( m_vecPunchAngleVel.m_Value[2], m_vecPunchAngleVel[2] )), +#else + RecvPropVector (RECVINFO(m_vecPunchAngle)), + RecvPropVector (RECVINFO(m_vecPunchAngleVel)), +#endif + + RecvPropInt (RECVINFO(m_bDrawViewmodel)), + RecvPropInt (RECVINFO(m_bWearingSuit)), + RecvPropBool (RECVINFO(m_bPoisoned)), + RecvPropFloat (RECVINFO(m_flStepSize)), + RecvPropInt (RECVINFO(m_bAllowAutoMovement)), + + // 3d skybox data + RecvPropInt(RECVINFO(m_skybox3d.scale)), + RecvPropVector(RECVINFO(m_skybox3d.origin)), + RecvPropInt(RECVINFO(m_skybox3d.area)), + + // 3d skybox fog data + RecvPropInt( RECVINFO( m_skybox3d.fog.enable ) ), + RecvPropInt( RECVINFO( m_skybox3d.fog.blend ) ), + RecvPropVector( RECVINFO( m_skybox3d.fog.dirPrimary ) ), + RecvPropInt( RECVINFO( m_skybox3d.fog.colorPrimary ) ), + RecvPropInt( RECVINFO( m_skybox3d.fog.colorSecondary ) ), + RecvPropFloat( RECVINFO( m_skybox3d.fog.start ) ), + RecvPropFloat( RECVINFO( m_skybox3d.fog.end ) ), + RecvPropFloat( RECVINFO( m_skybox3d.fog.maxdensity ) ), + + // fog data + RecvPropEHandle( RECVINFO( m_PlayerFog.m_hCtrl ) ), + + // audio data + RecvPropVector( RECVINFO( m_audio.localSound[0] ) ), + RecvPropVector( RECVINFO( m_audio.localSound[1] ) ), + RecvPropVector( RECVINFO( m_audio.localSound[2] ) ), + RecvPropVector( RECVINFO( m_audio.localSound[3] ) ), + RecvPropVector( RECVINFO( m_audio.localSound[4] ) ), + RecvPropVector( RECVINFO( m_audio.localSound[5] ) ), + RecvPropVector( RECVINFO( m_audio.localSound[6] ) ), + RecvPropVector( RECVINFO( m_audio.localSound[7] ) ), + RecvPropInt( RECVINFO( m_audio.soundscapeIndex ) ), + RecvPropInt( RECVINFO( m_audio.localBits ) ), + RecvPropEHandle( RECVINFO( m_audio.ent ) ), +END_RECV_TABLE() + +// -------------------------------------------------------------------------------- // +// This data only gets sent to clients that ARE this player entity. +// -------------------------------------------------------------------------------- // + + BEGIN_RECV_TABLE_NOBASE( C_BasePlayer, DT_LocalPlayerExclusive ) + + RecvPropDataTable ( RECVINFO_DT(m_Local),0, &REFERENCE_RECV_TABLE(DT_Local) ), + + RecvPropFloat ( RECVINFO(m_vecViewOffset[0]) ), + RecvPropFloat ( RECVINFO(m_vecViewOffset[1]) ), + RecvPropFloat ( RECVINFO(m_vecViewOffset[2]) ), + RecvPropFloat ( RECVINFO(m_flFriction) ), + + RecvPropArray3 ( RECVINFO_ARRAY(m_iAmmo), RecvPropInt( RECVINFO(m_iAmmo[0])) ), + + RecvPropInt ( RECVINFO(m_fOnTarget) ), + + RecvPropInt ( RECVINFO( m_nTickBase ) ), + RecvPropInt ( RECVINFO( m_nNextThinkTick ) ), + + RecvPropEHandle ( RECVINFO( m_hLastWeapon ) ), + RecvPropEHandle ( RECVINFO( m_hGroundEntity ) ), + + RecvPropFloat ( RECVINFO(m_vecVelocity[0]), 0, RecvProxy_LocalVelocityX ), + RecvPropFloat ( RECVINFO(m_vecVelocity[1]), 0, RecvProxy_LocalVelocityY ), + RecvPropFloat ( RECVINFO(m_vecVelocity[2]), 0, RecvProxy_LocalVelocityZ ), + + RecvPropVector ( RECVINFO( m_vecBaseVelocity ) ), + + RecvPropEHandle ( RECVINFO( m_hConstraintEntity)), + RecvPropVector ( RECVINFO( m_vecConstraintCenter) ), + RecvPropFloat ( RECVINFO( m_flConstraintRadius )), + RecvPropFloat ( RECVINFO( m_flConstraintWidth )), + RecvPropFloat ( RECVINFO( m_flConstraintSpeedFactor )), + + RecvPropFloat ( RECVINFO( m_flDeathTime )), + + RecvPropInt ( RECVINFO( m_nWaterLevel ) ), + RecvPropFloat ( RECVINFO( m_flLaggedMovementValue )), + + END_RECV_TABLE() + + +// -------------------------------------------------------------------------------- // +// DT_BasePlayer datatable. +// -------------------------------------------------------------------------------- // + +#if defined USES_ECON_ITEMS + EXTERN_RECV_TABLE(DT_AttributeList); +#endif + + IMPLEMENT_CLIENTCLASS_DT(C_BasePlayer, DT_BasePlayer, CBasePlayer) + // We have both the local and nonlocal data in here, but the server proxies + // only send one. + RecvPropDataTable( "localdata", 0, 0, &REFERENCE_RECV_TABLE(DT_LocalPlayerExclusive) ), + +#if defined USES_ECON_ITEMS + RecvPropDataTable(RECVINFO_DT(m_AttributeList),0, &REFERENCE_RECV_TABLE(DT_AttributeList) ), +#endif + + RecvPropDataTable(RECVINFO_DT(pl), 0, &REFERENCE_RECV_TABLE(DT_PlayerState), DataTableRecvProxy_StaticDataTable), + + RecvPropInt (RECVINFO(m_iFOV)), + RecvPropInt (RECVINFO(m_iFOVStart)), + RecvPropFloat (RECVINFO(m_flFOVTime)), + RecvPropInt (RECVINFO(m_iDefaultFOV)), + RecvPropEHandle (RECVINFO(m_hZoomOwner)), + + RecvPropEHandle( RECVINFO(m_hVehicle) ), + RecvPropEHandle( RECVINFO(m_hUseEntity) ), + + RecvPropInt (RECVINFO(m_iHealth)), + RecvPropInt (RECVINFO(m_lifeState)), + + RecvPropInt (RECVINFO(m_iBonusProgress)), + RecvPropInt (RECVINFO(m_iBonusChallenge)), + + RecvPropFloat (RECVINFO(m_flMaxspeed)), + RecvPropInt (RECVINFO(m_fFlags)), + + + RecvPropInt (RECVINFO(m_iObserverMode), 0, RecvProxy_ObserverMode ), + RecvPropEHandle (RECVINFO(m_hObserverTarget), RecvProxy_ObserverTarget ), + RecvPropArray ( RecvPropEHandle( RECVINFO( m_hViewModel[0] ) ), m_hViewModel ), + + + RecvPropString( RECVINFO(m_szLastPlaceName) ), + +#if defined USES_ECON_ITEMS + RecvPropUtlVector( RECVINFO_UTLVECTOR( m_hMyWearables ), MAX_WEARABLES_SENT_FROM_SERVER, RecvPropEHandle(NULL, 0, 0) ), +#endif + + END_RECV_TABLE() + +BEGIN_PREDICTION_DATA_NO_BASE( CPlayerState ) + + DEFINE_PRED_FIELD( deadflag, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ), + // DEFINE_FIELD( netname, string_t ), + // DEFINE_FIELD( fixangle, FIELD_INTEGER ), + // DEFINE_FIELD( anglechange, FIELD_FLOAT ), + // DEFINE_FIELD( v_angle, FIELD_VECTOR ), + +END_PREDICTION_DATA() + +BEGIN_PREDICTION_DATA_NO_BASE( CPlayerLocalData ) + + // DEFINE_PRED_TYPEDESCRIPTION( m_skybox3d, sky3dparams_t ), + // DEFINE_PRED_TYPEDESCRIPTION( m_fog, fogparams_t ), + // DEFINE_PRED_TYPEDESCRIPTION( m_audio, audioparams_t ), + DEFINE_FIELD( m_nStepside, FIELD_INTEGER ), + + DEFINE_PRED_FIELD( m_iHideHUD, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ), +#if PREDICTION_ERROR_CHECK_LEVEL > 1 + DEFINE_PRED_FIELD( m_vecPunchAngle, FIELD_VECTOR, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_vecPunchAngleVel, FIELD_VECTOR, FTYPEDESC_INSENDTABLE ), +#else + DEFINE_PRED_FIELD_TOL( m_vecPunchAngle, FIELD_VECTOR, FTYPEDESC_INSENDTABLE, 0.125f ), + DEFINE_PRED_FIELD_TOL( m_vecPunchAngleVel, FIELD_VECTOR, FTYPEDESC_INSENDTABLE, 0.125f ), +#endif + DEFINE_PRED_FIELD( m_bDrawViewmodel, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_bWearingSuit, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_bPoisoned, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_bAllowAutoMovement, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ), + + DEFINE_PRED_FIELD( m_bDucked, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_bDucking, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_bInDuckJump, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_flDucktime, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_flDuckJumpTime, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_flJumpTime, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD_TOL( m_flFallVelocity, FIELD_FLOAT, FTYPEDESC_INSENDTABLE, 0.5f ), +// DEFINE_PRED_FIELD( m_nOldButtons, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ), + DEFINE_FIELD( m_nOldButtons, FIELD_INTEGER ), + DEFINE_PRED_FIELD( m_flStepSize, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ), + DEFINE_FIELD( m_flFOVRate, FIELD_FLOAT ), + +END_PREDICTION_DATA() + +BEGIN_PREDICTION_DATA( C_BasePlayer ) + + DEFINE_PRED_TYPEDESCRIPTION( m_Local, CPlayerLocalData ), + DEFINE_PRED_TYPEDESCRIPTION( pl, CPlayerState ), + + DEFINE_PRED_FIELD( m_iFOV, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_hZoomOwner, FIELD_EHANDLE, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_flFOVTime, FIELD_FLOAT, 0 ), + DEFINE_PRED_FIELD( m_iFOVStart, FIELD_INTEGER, 0 ), + + DEFINE_PRED_FIELD( m_hVehicle, FIELD_EHANDLE, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD_TOL( m_flMaxspeed, FIELD_FLOAT, FTYPEDESC_INSENDTABLE, 0.5f ), + DEFINE_PRED_FIELD( m_iHealth, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_iBonusProgress, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_iBonusChallenge, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_fOnTarget, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_nNextThinkTick, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_lifeState, FIELD_CHARACTER, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_nWaterLevel, FIELD_CHARACTER, FTYPEDESC_INSENDTABLE ), + + DEFINE_PRED_FIELD_TOL( m_vecBaseVelocity, FIELD_VECTOR, FTYPEDESC_INSENDTABLE, 0.05 ), + + DEFINE_FIELD( m_nButtons, FIELD_INTEGER ), + DEFINE_FIELD( m_flWaterJumpTime, FIELD_FLOAT ), + DEFINE_FIELD( m_nImpulse, FIELD_INTEGER ), + DEFINE_FIELD( m_flStepSoundTime, FIELD_FLOAT ), + DEFINE_FIELD( m_flSwimSoundTime, FIELD_FLOAT ), + DEFINE_FIELD( m_vecLadderNormal, FIELD_VECTOR ), + DEFINE_FIELD( m_flPhysics, FIELD_INTEGER ), + DEFINE_AUTO_ARRAY( m_szAnimExtension, FIELD_CHARACTER ), + DEFINE_FIELD( m_afButtonLast, FIELD_INTEGER ), + DEFINE_FIELD( m_afButtonPressed, FIELD_INTEGER ), + DEFINE_FIELD( m_afButtonReleased, FIELD_INTEGER ), + // DEFINE_FIELD( m_vecOldViewAngles, FIELD_VECTOR ), + + // DEFINE_ARRAY( m_iOldAmmo, FIELD_INTEGER, MAX_AMMO_TYPES ), + + //DEFINE_FIELD( m_hOldVehicle, FIELD_EHANDLE ), + // DEFINE_FIELD( m_pModelLight, dlight_t* ), + // DEFINE_FIELD( m_pEnvironmentLight, dlight_t* ), + // DEFINE_FIELD( m_pBrightLight, dlight_t* ), + DEFINE_PRED_FIELD( m_hLastWeapon, FIELD_EHANDLE, FTYPEDESC_INSENDTABLE ), + + DEFINE_PRED_FIELD( m_nTickBase, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ), + + DEFINE_PRED_FIELD( m_hGroundEntity, FIELD_EHANDLE, FTYPEDESC_INSENDTABLE ), + + DEFINE_PRED_ARRAY( m_hViewModel, FIELD_EHANDLE, MAX_VIEWMODELS, FTYPEDESC_INSENDTABLE ), + + DEFINE_FIELD( m_surfaceFriction, FIELD_FLOAT ), + +END_PREDICTION_DATA() + +LINK_ENTITY_TO_CLASS( player, C_BasePlayer ); + +// -------------------------------------------------------------------------------- // +// Functions. +// -------------------------------------------------------------------------------- // +C_BasePlayer::C_BasePlayer() : m_iv_vecViewOffset( "C_BasePlayer::m_iv_vecViewOffset" ) +{ + AddVar( &m_vecViewOffset, &m_iv_vecViewOffset, LATCH_SIMULATION_VAR ); + +#ifdef _DEBUG + m_vecLadderNormal.Init(); + m_vecOldViewAngles.Init(); +#endif + + m_pFlashlight = NULL; + + m_pCurrentVguiScreen = NULL; + m_pCurrentCommand = NULL; + + m_flPredictionErrorTime = -100; + m_StuckLast = 0; + m_bWasFrozen = false; + + m_bResampleWaterSurface = true; + + ResetObserverMode(); + + m_vecPredictionError.Init(); + m_flPredictionErrorTime = 0; + + m_surfaceProps = 0; + m_pSurfaceData = NULL; + m_surfaceFriction = 1.0f; + m_chTextureType = 0; + + m_flNextAchievementAnnounceTime = 0; + + m_bFiredWeapon = false; + + m_nForceVisionFilterFlags = 0; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_BasePlayer::~C_BasePlayer() +{ + DeactivateVguiScreen( m_pCurrentVguiScreen.Get() ); + if ( this == s_pLocalPlayer ) + { + s_pLocalPlayer = NULL; + } + + delete m_pFlashlight; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_BasePlayer::Spawn( void ) +{ + // Clear all flags except for FL_FULLEDICT + ClearFlags(); + AddFlag( FL_CLIENT ); + + int effects = GetEffects() & EF_NOSHADOW; + SetEffects( effects ); + + m_iFOV = 0; // init field of view. + + SetModel( "models/player.mdl" ); + + Precache(); + + SetThink(NULL); + + SharedSpawn(); + + m_bWasFreezeFraming = false; + + m_bFiredWeapon = false; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool C_BasePlayer::AudioStateIsUnderwater( Vector vecMainViewOrigin ) +{ + if ( IsObserver() ) + { + // Just check the view position + int cont = enginetrace->GetPointContents ( vecMainViewOrigin ); + return (cont & MASK_WATER); + } + + return ( GetWaterLevel() >= WL_Eyes ); +} + +bool C_BasePlayer::IsHLTV() const +{ + return ( IsLocalPlayer() && engine->IsHLTV() ); +} + +bool C_BasePlayer::IsReplay() const +{ +#if defined( REPLAY_ENABLED ) + return ( IsLocalPlayer() && g_pEngineClientReplay->IsPlayingReplayDemo() ); +#else + return false; +#endif +} + +CBaseEntity *C_BasePlayer::GetObserverTarget() const // returns players target or NULL +{ +#ifndef _XBOX + if ( IsHLTV() ) + { + return HLTVCamera()->GetPrimaryTarget(); + } +#if defined( REPLAY_ENABLED ) + if ( IsReplay() ) + { + return ReplayCamera()->GetPrimaryTarget(); + } +#endif +#endif + + if ( GetObserverMode() == OBS_MODE_ROAMING ) + { + return NULL; // no target in roaming mode + } + else + { + if ( IsLocalPlayer() && UseVR() ) + { + // In VR mode, certain views cause disorientation and nausea. So let's not. + switch ( m_iObserverMode ) + { + case OBS_MODE_NONE: // not in spectator mode + case OBS_MODE_FIXED: // view from a fixed camera position + case OBS_MODE_IN_EYE: // follow a player in first person view + case OBS_MODE_CHASE: // follow a player in third person view + case OBS_MODE_ROAMING: // free roaming + return m_hObserverTarget; + break; + case OBS_MODE_DEATHCAM: // special mode for death cam animation + case OBS_MODE_FREEZECAM: // zooms to a target, and freeze-frames on them + // These are both terrible - they get overriden to chase, but here we change it to "chase" your own body (which will be ragdolled). + return (const_cast<C_BasePlayer*>(this))->GetBaseEntity(); + break; + default: + assert ( false ); + break; + } + } + + return m_hObserverTarget; + } +} + +// Called from Recv Proxy, mainly to reset tone map scale +void C_BasePlayer::SetObserverTarget( EHANDLE hObserverTarget ) +{ + // If the observer target is changing to an entity that the client doesn't know about yet, + // it can resolve to NULL. If the client didn't have an observer target before, then + // comparing EHANDLEs directly will see them as equal, since it uses Get(), and compares + // NULL to NULL. To combat this, we need to check against GetEntryIndex() and + // GetSerialNumber(). + if ( hObserverTarget.GetEntryIndex() != m_hObserverTarget.GetEntryIndex() || + hObserverTarget.GetSerialNumber() != m_hObserverTarget.GetSerialNumber()) + { + // Init based on the new handle's entry index and serial number, so that it's Get() + // has a chance to become non-NULL even if it currently resolves to NULL. + m_hObserverTarget.Init( hObserverTarget.GetEntryIndex(), hObserverTarget.GetSerialNumber() ); + + IGameEvent *event = gameeventmanager->CreateEvent( "spec_target_updated" ); + if ( event ) + { + gameeventmanager->FireEventClientSide( event ); + } + + if ( IsLocalPlayer() ) + { + ResetToneMapping(1.0); + } + // NVNT notify haptics of changed player + if ( haptics ) + haptics->OnPlayerChanged(); + + if ( IsLocalPlayer() ) + { + // On a change of viewing mode or target, we may want to reset both head and torso to point at the new target. + g_ClientVirtualReality.AlignTorsoAndViewToWeapon(); + } + } +} + + +void C_BasePlayer::SetObserverMode ( int iNewMode ) +{ + if ( m_iObserverMode != iNewMode ) + { + m_iObserverMode = iNewMode; + if ( IsLocalPlayer() ) + { + // On a change of viewing mode or target, we may want to reset both head and torso to point at the new target. + g_ClientVirtualReality.AlignTorsoAndViewToWeapon(); + } + } +} + + +int C_BasePlayer::GetObserverMode() const +{ +#ifndef _XBOX + if ( IsHLTV() ) + { + return HLTVCamera()->GetMode(); + } +#if defined( REPLAY_ENABLED ) + if ( IsReplay() ) + { + return ReplayCamera()->GetMode(); + } +#endif +#endif + + if ( IsLocalPlayer() && UseVR() ) + { + // IN VR mode, certain views cause disorientation and nausea. So let's not. + switch ( m_iObserverMode ) + { + case OBS_MODE_NONE: // not in spectator mode + case OBS_MODE_FIXED: // view from a fixed camera position + case OBS_MODE_IN_EYE: // follow a player in first person view + case OBS_MODE_CHASE: // follow a player in third person view + case OBS_MODE_ROAMING: // free roaming + return m_iObserverMode; + break; + case OBS_MODE_DEATHCAM: // special mode for death cam animation + case OBS_MODE_FREEZECAM: // zooms to a target, and freeze-frames on them + // These are both terrible - just do chase of your ragdoll. + return OBS_MODE_CHASE; + break; + default: + assert ( false ); + break; + } + } + + return m_iObserverMode; +} + +bool C_BasePlayer::ViewModel_IsTransparent( void ) +{ + return IsTransparent(); +} + +bool C_BasePlayer::ViewModel_IsUsingFBTexture( void ) +{ + return UsesPowerOfTwoFrameBufferTexture(); +} + +//----------------------------------------------------------------------------- +// Used by prediction, sets the view angles for the player +//----------------------------------------------------------------------------- +void C_BasePlayer::SetLocalViewAngles( const QAngle &viewAngles ) +{ + pl.v_angle = viewAngles; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : ang - +//----------------------------------------------------------------------------- +void C_BasePlayer::SetViewAngles( const QAngle& ang ) +{ + SetLocalAngles( ang ); + SetNetworkAngles( ang ); +} + + +surfacedata_t* C_BasePlayer::GetGroundSurface() +{ + // + // Find the name of the material that lies beneath the player. + // + Vector start, end; + VectorCopy( GetAbsOrigin(), start ); + VectorCopy( start, end ); + + // Straight down + end.z -= 64; + + // Fill in default values, just in case. + + Ray_t ray; + ray.Init( start, end, GetPlayerMins(), GetPlayerMaxs() ); + + trace_t trace; + UTIL_TraceRay( ray, MASK_PLAYERSOLID_BRUSHONLY, this, COLLISION_GROUP_PLAYER_MOVEMENT, &trace ); + + if ( trace.fraction == 1.0f ) + return NULL; // no ground + + return physprops->GetSurfaceData( trace.surface.surfaceProps ); +} + + +//----------------------------------------------------------------------------- +// returns the player name +//----------------------------------------------------------------------------- +const char * C_BasePlayer::GetPlayerName() +{ + return g_PR ? g_PR->GetPlayerName( entindex() ) : ""; +} + +//----------------------------------------------------------------------------- +// Is the player dead? +//----------------------------------------------------------------------------- +bool C_BasePlayer::IsPlayerDead() +{ + return pl.deadflag == true; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_BasePlayer::SetVehicleRole( int nRole ) +{ + if ( !IsInAVehicle() ) + return; + + // HL2 has only a player in a vehicle. + if ( nRole > VEHICLE_ROLE_DRIVER ) + return; + + char szCmd[64]; + Q_snprintf( szCmd, sizeof( szCmd ), "vehicleRole %i\n", nRole ); + engine->ServerCmd( szCmd ); +} + +//----------------------------------------------------------------------------- +// Purpose: Store original ammo data to see what has changed +// Input : bnewentity - +//----------------------------------------------------------------------------- +void C_BasePlayer::OnPreDataChanged( DataUpdateType_t updateType ) +{ + for (int i = 0; i < MAX_AMMO_TYPES; ++i) + { + m_iOldAmmo[i] = GetAmmoCount(i); + } + + m_bWasFreezeFraming = (GetObserverMode() == OBS_MODE_FREEZECAM); + m_hOldFogController = m_Local.m_PlayerFog.m_hCtrl; + + BaseClass::OnPreDataChanged( updateType ); +} + +void C_BasePlayer::PreDataUpdate( DataUpdateType_t updateType ) +{ + BaseClass::PreDataUpdate( updateType ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : updateType - +//----------------------------------------------------------------------------- +void C_BasePlayer::PostDataUpdate( DataUpdateType_t updateType ) +{ + // This has to occur here as opposed to OnDataChanged so that EHandles to the player created + // on this same frame are not stomped because prediction thinks there + // isn't a local player yet!!! + + if ( updateType == DATA_UPDATE_CREATED ) + { + // Make sure s_pLocalPlayer is correct + + int iLocalPlayerIndex = engine->GetLocalPlayer(); + + if ( g_nKillCamMode ) + iLocalPlayerIndex = g_nKillCamTarget1; + + if ( iLocalPlayerIndex == index ) + { + Assert( s_pLocalPlayer == NULL ); + s_pLocalPlayer = this; + + // Reset our sound mixed in case we were in a freeze cam when we + // changed level, which would cause the snd_soundmixer to be left modified. + ConVar *pVar = (ConVar *)cvar->FindVar( "snd_soundmixer" ); + pVar->Revert(); + } + } + + bool bForceEFNoInterp = IsNoInterpolationFrame(); + + if ( IsLocalPlayer() ) + { + SetSimulatedEveryTick( true ); + } + else + { + SetSimulatedEveryTick( false ); + + // estimate velocity for non local players + float flTimeDelta = m_flSimulationTime - m_flOldSimulationTime; + if ( flTimeDelta > 0 && !( IsNoInterpolationFrame() || bForceEFNoInterp ) ) + { + Vector newVelo = (GetNetworkOrigin() - GetOldOrigin() ) / flTimeDelta; + SetAbsVelocity( newVelo); + } + } + + BaseClass::PostDataUpdate( updateType ); + + // Only care about this for local player + if ( IsLocalPlayer() ) + { + QAngle angles; + engine->GetViewAngles( angles ); + if ( updateType == DATA_UPDATE_CREATED ) + { + SetLocalViewAngles( angles ); + m_flOldPlayerZ = GetLocalOrigin().z; + // NVNT the local player has just been created. + // set in the "on_foot" navigation. + if ( haptics ) + { + haptics->LocalPlayerReset(); + haptics->SetNavigationClass("on_foot"); + haptics->ProcessHapticEvent(2,"Movement","BasePlayer"); + } + + } + SetLocalAngles( angles ); + + if ( !m_bWasFreezeFraming && GetObserverMode() == OBS_MODE_FREEZECAM ) + { + m_vecFreezeFrameStart = MainViewOrigin(); + m_flFreezeFrameStartTime = gpGlobals->curtime; + m_flFreezeFrameDistance = RandomFloat( spec_freeze_distance_min.GetFloat(), spec_freeze_distance_max.GetFloat() ); + m_flFreezeZOffset = RandomFloat( -30, 20 ); + m_bSentFreezeFrame = false; + m_nForceVisionFilterFlags = 0; + + C_BaseEntity *target = GetObserverTarget(); + if ( target && target->IsPlayer() ) + { + C_BasePlayer *player = ToBasePlayer( target ); + if ( player ) + { + m_nForceVisionFilterFlags = player->GetVisionFilterFlags(); + CalculateVisionUsingCurrentFlags(); + } + } + + IGameEvent *pEvent = gameeventmanager->CreateEvent( "show_freezepanel" ); + if ( pEvent ) + { + pEvent->SetInt( "killer", target ? target->entindex() : 0 ); + gameeventmanager->FireEventClientSide( pEvent ); + } + + // Force the sound mixer to the freezecam mixer + ConVar *pVar = (ConVar *)cvar->FindVar( "snd_soundmixer" ); + pVar->SetValue( "FreezeCam_Only" ); + } + else if ( m_bWasFreezeFraming && GetObserverMode() != OBS_MODE_FREEZECAM ) + { + IGameEvent *pEvent = gameeventmanager->CreateEvent( "hide_freezepanel" ); + if ( pEvent ) + { + gameeventmanager->FireEventClientSide( pEvent ); + } + + view->FreezeFrame(0); + + ConVar *pVar = (ConVar *)cvar->FindVar( "snd_soundmixer" ); + pVar->Revert(); + + m_nForceVisionFilterFlags = 0; + CalculateVisionUsingCurrentFlags(); + } + } + + // If we are updated while paused, allow the player origin to be snapped by the + // server if we receive a packet from the server + if ( engine->IsPaused() || bForceEFNoInterp ) + { + ResetLatched(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool C_BasePlayer::CanSetSoundMixer( void ) +{ + // Can't set sound mixers when we're in freezecam mode, since it has a code-enforced mixer + return (GetObserverMode() != OBS_MODE_FREEZECAM); +} + +void C_BasePlayer::ReceiveMessage( int classID, bf_read &msg ) +{ + if ( classID != GetClientClass()->m_ClassID ) + { + // message is for subclass + BaseClass::ReceiveMessage( classID, msg ); + return; + } + + int messageType = msg.ReadByte(); + + switch( messageType ) + { + case PLAY_PLAYER_JINGLE: + PlayPlayerJingle(); + break; + } +} + +void C_BasePlayer::OnRestore() +{ + BaseClass::OnRestore(); + + if ( IsLocalPlayer() ) + { + // debounce the attack key, for if it was used for restore + input->ClearInputButton( IN_ATTACK | IN_ATTACK2 ); + // GetButtonBits() has to be called for the above to take effect + input->GetButtonBits( 0 ); + } + + // For ammo history icons to current value so they don't flash on level transtions + for ( int i = 0; i < MAX_AMMO_TYPES; i++ ) + { + m_iOldAmmo[i] = GetAmmoCount(i); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Process incoming data +//----------------------------------------------------------------------------- +void C_BasePlayer::OnDataChanged( DataUpdateType_t updateType ) +{ +#if !defined( NO_ENTITY_PREDICTION ) + if ( IsLocalPlayer() ) + { + SetPredictionEligible( true ); + } +#endif + + BaseClass::OnDataChanged( updateType ); + + // Only care about this for local player + if ( IsLocalPlayer() ) + { + // Reset engine areabits pointer + render->SetAreaState( m_Local.m_chAreaBits, m_Local.m_chAreaPortalBits ); + + // Check for Ammo pickups. + for ( int i = 0; i < MAX_AMMO_TYPES; i++ ) + { + if ( GetAmmoCount(i) > m_iOldAmmo[i] ) + { + // Don't add to ammo pickup if the ammo doesn't do it + const FileWeaponInfo_t *pWeaponData = gWR.GetWeaponFromAmmo(i); + + if ( !pWeaponData || !( pWeaponData->iFlags & ITEM_FLAG_NOAMMOPICKUPS ) ) + { + // We got more ammo for this ammo index. Add it to the ammo history + CHudHistoryResource *pHudHR = GET_HUDELEMENT( CHudHistoryResource ); + if( pHudHR ) + { + pHudHR->AddToHistory( HISTSLOT_AMMO, i, abs(GetAmmoCount(i) - m_iOldAmmo[i]) ); + } + } + } + } + + Soundscape_Update( m_Local.m_audio ); + + if ( m_hOldFogController != m_Local.m_PlayerFog.m_hCtrl ) + { + FogControllerChanged( updateType == DATA_UPDATE_CREATED ); + } + } +} + + +//----------------------------------------------------------------------------- +// Did we just enter a vehicle this frame? +//----------------------------------------------------------------------------- +bool C_BasePlayer::JustEnteredVehicle() +{ + if ( !IsInAVehicle() ) + return false; + + return ( m_hOldVehicle == m_hVehicle ); +} + +//----------------------------------------------------------------------------- +// Are we in VGUI input mode?. +//----------------------------------------------------------------------------- +bool C_BasePlayer::IsInVGuiInputMode() const +{ + return (m_pCurrentVguiScreen.Get() != NULL); +} + +//----------------------------------------------------------------------------- +// Are we inputing to a view model vgui screen +//----------------------------------------------------------------------------- +bool C_BasePlayer::IsInViewModelVGuiInputMode() const +{ + C_BaseEntity *pScreenEnt = m_pCurrentVguiScreen.Get(); + + if ( !pScreenEnt ) + return false; + + Assert( dynamic_cast<C_VGuiScreen*>(pScreenEnt) ); + C_VGuiScreen *pVguiScreen = static_cast<C_VGuiScreen*>(pScreenEnt); + + return ( pVguiScreen->IsAttachedToViewModel() && pVguiScreen->AcceptsInput() ); +} + +//----------------------------------------------------------------------------- +// Check to see if we're in vgui input mode... +//----------------------------------------------------------------------------- +void C_BasePlayer::DetermineVguiInputMode( CUserCmd *pCmd ) +{ + // If we're dead, close down and abort! + if ( !IsAlive() ) + { + DeactivateVguiScreen( m_pCurrentVguiScreen.Get() ); + m_pCurrentVguiScreen.Set( NULL ); + return; + } + + // If we're in vgui mode *and* we're holding down mouse buttons, + // stay in vgui mode even if we're outside the screen bounds + if (m_pCurrentVguiScreen.Get() && (pCmd->buttons & (IN_ATTACK | IN_ATTACK2)) ) + { + SetVGuiScreenButtonState( m_pCurrentVguiScreen.Get(), pCmd->buttons ); + + // Kill all attack inputs if we're in vgui screen mode + pCmd->buttons &= ~(IN_ATTACK | IN_ATTACK2); + return; + } + + // We're not in vgui input mode if we're moving, or have hit a key + // that will make us move... + + // Not in vgui mode if we're moving too quickly + // ROBIN: Disabled movement preventing VGUI screen usage + //if (GetVelocity().LengthSqr() > MAX_VGUI_INPUT_MODE_SPEED_SQ) + if ( 0 ) + { + DeactivateVguiScreen( m_pCurrentVguiScreen.Get() ); + m_pCurrentVguiScreen.Set( NULL ); + return; + } + + // Don't enter vgui mode if we've got combat buttons held down + bool bAttacking = false; + if ( ((pCmd->buttons & IN_ATTACK) || (pCmd->buttons & IN_ATTACK2)) && !m_pCurrentVguiScreen.Get() ) + { + bAttacking = true; + } + + // Not in vgui mode if we're pushing any movement key at all + // Not in vgui mode if we're in a vehicle... + // ROBIN: Disabled movement preventing VGUI screen usage + //if ((pCmd->forwardmove > MAX_VGUI_INPUT_MODE_SPEED) || + // (pCmd->sidemove > MAX_VGUI_INPUT_MODE_SPEED) || + // (pCmd->upmove > MAX_VGUI_INPUT_MODE_SPEED) || + // (pCmd->buttons & IN_JUMP) || + // (bAttacking) ) + if ( bAttacking || IsInAVehicle() ) + { + DeactivateVguiScreen( m_pCurrentVguiScreen.Get() ); + m_pCurrentVguiScreen.Set( NULL ); + return; + } + + // Don't interact with world screens when we're in a menu + if ( vgui::surface()->IsCursorVisible() ) + { + DeactivateVguiScreen( m_pCurrentVguiScreen.Get() ); + m_pCurrentVguiScreen.Set( NULL ); + return; + } + + // Not in vgui mode if there are no nearby screens + C_BaseEntity *pOldScreen = m_pCurrentVguiScreen.Get(); + + m_pCurrentVguiScreen = FindNearbyVguiScreen( EyePosition(), pCmd->viewangles, GetTeamNumber() ); + + if (pOldScreen != m_pCurrentVguiScreen) + { + DeactivateVguiScreen( pOldScreen ); + ActivateVguiScreen( m_pCurrentVguiScreen.Get() ); + } + + if (m_pCurrentVguiScreen.Get()) + { + SetVGuiScreenButtonState( m_pCurrentVguiScreen.Get(), pCmd->buttons ); + + // Kill all attack inputs if we're in vgui screen mode + pCmd->buttons &= ~(IN_ATTACK | IN_ATTACK2); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Input handling +//----------------------------------------------------------------------------- +bool C_BasePlayer::CreateMove( float flInputSampleTime, CUserCmd *pCmd ) +{ + // Allow the vehicle to clamp the view angles + if ( IsInAVehicle() ) + { + IClientVehicle *pVehicle = m_hVehicle.Get()->GetClientVehicle(); + if ( pVehicle ) + { + pVehicle->UpdateViewAngles( this, pCmd ); + engine->SetViewAngles( pCmd->viewangles ); + } + } + else + { +#ifndef _X360 + if ( joy_autosprint.GetBool() ) +#endif + { + if ( input->KeyState( &in_joyspeed ) != 0.0f ) + { + pCmd->buttons |= IN_SPEED; + } + } + + CBaseCombatWeapon *pWeapon = GetActiveWeapon(); + if ( pWeapon ) + { + pWeapon->CreateMove( flInputSampleTime, pCmd, m_vecOldViewAngles ); + } + } + + // If the frozen flag is set, prevent view movement (server prevents the rest of the movement) + if ( GetFlags() & FL_FROZEN ) + { + // Don't stomp the first time we get frozen + if ( m_bWasFrozen ) + { + // Stomp the new viewangles with old ones + pCmd->viewangles = m_vecOldViewAngles; + engine->SetViewAngles( pCmd->viewangles ); + } + else + { + m_bWasFrozen = true; + } + } + else + { + m_bWasFrozen = false; + } + + m_vecOldViewAngles = pCmd->viewangles; + + // Check to see if we're in vgui input mode... + DetermineVguiInputMode( pCmd ); + + return true; +} + + +//----------------------------------------------------------------------------- +// Purpose: Player has changed to a new team +//----------------------------------------------------------------------------- +void C_BasePlayer::TeamChange( int iNewTeam ) +{ + // Base class does nothing +} + + +//----------------------------------------------------------------------------- +// Purpose: Creates, destroys, and updates the flashlight effect as needed. +//----------------------------------------------------------------------------- +void C_BasePlayer::UpdateFlashlight() +{ + // The dim light is the flashlight. + if ( IsEffectActive( EF_DIMLIGHT ) ) + { + if (!m_pFlashlight) + { + // Turned on the headlight; create it. + m_pFlashlight = new CFlashlightEffect(index); + + if (!m_pFlashlight) + return; + + m_pFlashlight->TurnOn(); + } + + Vector vecForward, vecRight, vecUp; + EyeVectors( &vecForward, &vecRight, &vecUp ); + + // Update the light with the new position and direction. + m_pFlashlight->UpdateLight( EyePosition(), vecForward, vecRight, vecUp, FLASHLIGHT_DISTANCE ); + } + else if (m_pFlashlight) + { + // Turned off the flashlight; delete it. + delete m_pFlashlight; + m_pFlashlight = NULL; + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Creates player flashlight if it's ative +//----------------------------------------------------------------------------- +void C_BasePlayer::Flashlight( void ) +{ + UpdateFlashlight(); + + // Check for muzzle flash and apply to view model + C_BaseAnimating *ve = this; + if ( GetObserverMode() == OBS_MODE_IN_EYE ) + { + ve = dynamic_cast< C_BaseAnimating* >( GetObserverTarget() ); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Engine is asking whether to add this player to the visible entities list +//----------------------------------------------------------------------------- +void C_BasePlayer::AddEntity( void ) +{ + // FIXME/UNDONE: Should the local player say yes to adding itself now + // and then, when it ges time to render and it shouldn't still do the render with + // STUDIO_EVENTS set so that its attachment points will get updated even if not + // in third person? + + // Add in water effects + if ( IsLocalPlayer() ) + { + CreateWaterEffects(); + } + + // If set to invisible, skip. Do this before resetting the entity pointer so it has + // valid data to decide whether it's visible. + if ( !IsVisible() || !g_pClientMode->ShouldDrawLocalPlayer( this ) ) + { + return; + } + + // Server says don't interpolate this frame, so set previous info to new info. + if ( IsNoInterpolationFrame() || Teleported() ) + { + ResetLatched(); + } + + // Add in lighting effects + CreateLightEffects(); +} + +extern float UTIL_WaterLevel( const Vector &position, float minz, float maxz ); + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_BasePlayer::CreateWaterEffects( void ) +{ + // Must be completely submerged to bother + if ( GetWaterLevel() < 3 ) + { + m_bResampleWaterSurface = true; + return; + } + + // Do special setup if this is our first time back underwater + if ( m_bResampleWaterSurface ) + { + // Reset our particle timer + m_tWaterParticleTimer.Init( 32 ); + + // Find the surface of the water to clip against + m_flWaterSurfaceZ = UTIL_WaterLevel( WorldSpaceCenter(), WorldSpaceCenter().z, WorldSpaceCenter().z + 256 ); + m_bResampleWaterSurface = false; + } + + // Make sure the emitter is setup + if ( m_pWaterEmitter == NULL ) + { + if ( ( m_pWaterEmitter = WaterDebrisEffect::Create( "splish" ) ) == NULL ) + return; + } + + Vector vecVelocity; + GetVectors( &vecVelocity, NULL, NULL ); + + Vector offset = WorldSpaceCenter(); + + m_pWaterEmitter->SetSortOrigin( offset ); + + SimpleParticle *pParticle; + + float curTime = gpGlobals->frametime; + + // Add as many particles as we need + while ( m_tWaterParticleTimer.NextEvent( curTime ) ) + { + offset = WorldSpaceCenter() + ( vecVelocity * 128.0f ) + RandomVector( -128, 128 ); + + // Make sure we don't start out of the water! + if ( offset.z > m_flWaterSurfaceZ ) + { + offset.z = ( m_flWaterSurfaceZ - 8.0f ); + } + + pParticle = (SimpleParticle *) m_pWaterEmitter->AddParticle( sizeof(SimpleParticle), g_Mat_Fleck_Cement[random->RandomInt(0,1)], offset ); + + if (pParticle == NULL) + continue; + + pParticle->m_flLifetime = 0.0f; + pParticle->m_flDieTime = random->RandomFloat( 2.0f, 4.0f ); + + pParticle->m_vecVelocity = RandomVector( -2.0f, 2.0f ); + + //FIXME: We should tint these based on the water's fog value! + float color = random->RandomInt( 32, 128 ); + pParticle->m_uchColor[0] = color; + pParticle->m_uchColor[1] = color; + pParticle->m_uchColor[2] = color; + + pParticle->m_uchStartSize = 1; + pParticle->m_uchEndSize = 1; + + pParticle->m_uchStartAlpha = 255; + pParticle->m_uchEndAlpha = 0; + + pParticle->m_flRoll = random->RandomInt( 0, 360 ); + pParticle->m_flRollDelta = random->RandomFloat( -0.5f, 0.5f ); + } +} + +//----------------------------------------------------------------------------- +// Called when not in tactical mode. Allows view to be overriden for things like driving a tank. +//----------------------------------------------------------------------------- +void C_BasePlayer::OverrideView( CViewSetup *pSetup ) +{ +} + +bool C_BasePlayer::ShouldInterpolate() +{ + // always interpolate myself + if ( IsLocalPlayer() ) + return true; +#ifndef _XBOX + // always interpolate entity if followed by HLTV + if ( HLTVCamera()->GetCameraMan() == this ) + return true; +#endif + return BaseClass::ShouldInterpolate(); +} + + +bool C_BasePlayer::ShouldDraw() +{ + return ShouldDrawThisPlayer() && BaseClass::ShouldDraw(); +} + +int C_BasePlayer::DrawModel( int flags ) +{ +#ifndef PORTAL + // In Portal this check is already performed as part of + // C_Portal_Player::DrawModel() + if ( !ShouldDrawThisPlayer() ) + { + return 0; + } +#endif + return BaseClass::DrawModel( flags ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +Vector C_BasePlayer::GetChaseCamViewOffset( CBaseEntity *target ) +{ + C_BasePlayer *player = ToBasePlayer( target ); + + if ( player ) + { + if ( player->IsAlive() ) + { + if ( player->GetFlags() & FL_DUCKING ) + { + return VEC_DUCK_VIEW_SCALED( player ); + } + + return VEC_VIEW_SCALED( player ); + } + else + { + // assume it's the players ragdoll + return VEC_DEAD_VIEWHEIGHT_SCALED( player ); + } + } + + // assume it's the players ragdoll + return VEC_DEAD_VIEWHEIGHT; +} + +void C_BasePlayer::CalcChaseCamView(Vector& eyeOrigin, QAngle& eyeAngles, float& fov) +{ + C_BaseEntity *target = GetObserverTarget(); + + if ( !target ) + { + // just copy a save in-map position + VectorCopy( EyePosition(), eyeOrigin ); + VectorCopy( EyeAngles(), eyeAngles ); + return; + }; + + // If our target isn't visible, we're at a camera point of some kind. + // Instead of letting the player rotate around an invisible point, treat + // the point as a fixed camera. + if ( !target->GetBaseAnimating() && !target->GetModel() ) + { + CalcRoamingView( eyeOrigin, eyeAngles, fov ); + return; + } + + // QAngle tmpangles; + + Vector forward, viewpoint; + + // GetObserverCamOrigin() returns ragdoll pos if player is ragdolled + Vector origin = target->GetObserverCamOrigin(); + + VectorAdd( origin, GetChaseCamViewOffset( target ), origin ); + + QAngle viewangles; + + if ( GetObserverMode() == OBS_MODE_IN_EYE ) + { + viewangles = eyeAngles; + } + else if ( IsLocalPlayer() ) + { + engine->GetViewAngles( viewangles ); + if ( UseVR() ) + { + // Don't let people play with the pitch - they drive it into the ground or into the air and + // it's distracting at best, nauseating at worst (e.g. when it clips through the ground plane). + viewangles[PITCH] = 20.0f; + } + } + else + { + viewangles = EyeAngles(); + } + + //============================================================================= + // HPE_BEGIN: + // [Forrest] Fix for (at least one potential case of) CSB-194. Spectating someone + // who is headshotted by a teammate and then switching to chase cam leaves + // you with a permanent roll to the camera that doesn't decay and is not reset + // even when switching to different players or at the start of the next round + // if you are still a spectator. (If you spawn as a player, the view is reset. + // if you switch spectator modes, the view is reset.) + //============================================================================= +#ifdef CSTRIKE_DLL + // The chase camera adopts the yaw and pitch of the previous camera, but the camera + // should not roll. + viewangles.z = 0; +#endif + //============================================================================= + // HPE_END + //============================================================================= + + m_flObserverChaseDistance += gpGlobals->frametime*48.0f; + + float flMinDistance = CHASE_CAM_DISTANCE_MIN; + float flMaxDistance = CHASE_CAM_DISTANCE_MAX; + + if ( target && target->IsBaseTrain() ) + { + // if this is a train, we want to be back a little further so we can see more of it + flMaxDistance *= 2.5f; + } + + if ( target ) + { + C_BaseAnimating *pTargetAnimating = target->GetBaseAnimating(); + if ( pTargetAnimating ) + { + float flScaleSquared = pTargetAnimating->GetModelScale() * pTargetAnimating->GetModelScale(); + flMinDistance *= flScaleSquared; + flMaxDistance *= flScaleSquared; + m_flObserverChaseDistance = flMaxDistance; + } + } + + if ( target && !target->IsPlayer() && target->IsNextBot() ) + { + // if this is a boss, we want to be back a little further so we can see more of it + flMaxDistance *= 2.5f; + m_flObserverChaseDistance = flMaxDistance; + } + + m_flObserverChaseDistance = clamp( m_flObserverChaseDistance, flMinDistance, flMaxDistance ); + + AngleVectors( viewangles, &forward ); + + VectorNormalize( forward ); + + VectorMA(origin, -m_flObserverChaseDistance, forward, viewpoint ); + + trace_t trace; + CTraceFilterNoNPCsOrPlayer filter( target, COLLISION_GROUP_NONE ); + C_BaseEntity::PushEnableAbsRecomputations( false ); // HACK don't recompute positions while doing RayTrace + UTIL_TraceHull( origin, viewpoint, WALL_MIN, WALL_MAX, MASK_SOLID, &filter, &trace ); + C_BaseEntity::PopEnableAbsRecomputations(); + + if (trace.fraction < 1.0) + { + viewpoint = trace.endpos; + m_flObserverChaseDistance = VectorLength(origin - eyeOrigin); + } + + VectorCopy( viewangles, eyeAngles ); + VectorCopy( viewpoint, eyeOrigin ); + + fov = GetFOV(); +} + +void C_BasePlayer::CalcRoamingView(Vector& eyeOrigin, QAngle& eyeAngles, float& fov) +{ + C_BaseEntity *target = GetObserverTarget(); + + if ( !target ) + { + target = this; + } + + m_flObserverChaseDistance = 0.0; + + eyeOrigin = target->EyePosition(); + eyeAngles = target->EyeAngles(); + + if ( spec_track.GetInt() > 0 ) + { + C_BaseEntity *target = ClientEntityList().GetBaseEntity( spec_track.GetInt() ); + + if ( target ) + { + Vector v = target->GetAbsOrigin(); v.z += 54; + QAngle a; VectorAngles( v - eyeOrigin, a ); + + NormalizeAngles( a ); + eyeAngles = a; + engine->SetViewAngles( a ); + } + } + + // Apply a smoothing offset to smooth out prediction errors. + Vector vSmoothOffset; + GetPredictionErrorSmoothingVector( vSmoothOffset ); + eyeOrigin += vSmoothOffset; + + fov = GetFOV(); +} + +//----------------------------------------------------------------------------- +// Purpose: Calculate the view for the player while he's in freeze frame observer mode +//----------------------------------------------------------------------------- +void C_BasePlayer::CalcFreezeCamView( Vector& eyeOrigin, QAngle& eyeAngles, float& fov ) +{ + C_BaseEntity *pTarget = GetObserverTarget(); + if ( !pTarget ) + { + CalcDeathCamView( eyeOrigin, eyeAngles, fov ); + return; + } + + // Zoom towards our target + float flCurTime = (gpGlobals->curtime - m_flFreezeFrameStartTime); + float flBlendPerc = clamp( flCurTime / spec_freeze_traveltime.GetFloat(), 0.f, 1.f ); + flBlendPerc = SimpleSpline( flBlendPerc ); + + Vector vecCamDesired = pTarget->GetObserverCamOrigin(); // Returns ragdoll origin if they're ragdolled + VectorAdd( vecCamDesired, GetChaseCamViewOffset( pTarget ), vecCamDesired ); + Vector vecCamTarget = vecCamDesired; + if ( pTarget->IsAlive() ) + { + // Look at their chest, not their head + Vector maxs = pTarget->GetBaseAnimating() ? VEC_HULL_MAX_SCALED( pTarget->GetBaseAnimating() ) : VEC_HULL_MAX; + vecCamTarget.z -= (maxs.z * 0.5); + } + else + { + vecCamTarget.z += pTarget->GetBaseAnimating() ? VEC_DEAD_VIEWHEIGHT_SCALED( pTarget->GetBaseAnimating() ).z : VEC_DEAD_VIEWHEIGHT.z; // look over ragdoll, not through + } + + // Figure out a view position in front of the target + Vector vecEyeOnPlane = eyeOrigin; + vecEyeOnPlane.z = vecCamTarget.z; + Vector vecTargetPos = vecCamTarget; + Vector vecToTarget = vecTargetPos - vecEyeOnPlane; + VectorNormalize( vecToTarget ); + + // Stop a few units away from the target, and shift up to be at the same height + vecTargetPos = vecCamTarget - (vecToTarget * m_flFreezeFrameDistance); + float flEyePosZ = pTarget->EyePosition().z; + vecTargetPos.z = flEyePosZ + m_flFreezeZOffset; + + // Now trace out from the target, so that we're put in front of any walls + trace_t trace; + C_BaseEntity::PushEnableAbsRecomputations( false ); // HACK don't recompute positions while doing RayTrace + UTIL_TraceHull( vecCamTarget, vecTargetPos, WALL_MIN, WALL_MAX, MASK_SOLID, pTarget, COLLISION_GROUP_NONE, &trace ); + C_BaseEntity::PopEnableAbsRecomputations(); + if (trace.fraction < 1.0) + { + // The camera's going to be really close to the target. So we don't end up + // looking at someone's chest, aim close freezecams at the target's eyes. + vecTargetPos = trace.endpos; + vecCamTarget = vecCamDesired; + + // To stop all close in views looking up at character's chins, move the view up. + vecTargetPos.z += fabs(vecCamTarget.z - vecTargetPos.z) * 0.85; + C_BaseEntity::PushEnableAbsRecomputations( false ); // HACK don't recompute positions while doing RayTrace + UTIL_TraceHull( vecCamTarget, vecTargetPos, WALL_MIN, WALL_MAX, MASK_SOLID, pTarget, COLLISION_GROUP_NONE, &trace ); + C_BaseEntity::PopEnableAbsRecomputations(); + vecTargetPos = trace.endpos; + } + + // Look directly at the target + vecToTarget = vecCamTarget - vecTargetPos; + VectorNormalize( vecToTarget ); + VectorAngles( vecToTarget, eyeAngles ); + + VectorLerp( m_vecFreezeFrameStart, vecTargetPos, flBlendPerc, eyeOrigin ); + + if ( flCurTime >= spec_freeze_traveltime.GetFloat() && !m_bSentFreezeFrame ) + { + IGameEvent *pEvent = gameeventmanager->CreateEvent( "freezecam_started" ); + if ( pEvent ) + { + gameeventmanager->FireEventClientSide( pEvent ); + } + + m_bSentFreezeFrame = true; + view->FreezeFrame( spec_freeze_time.GetFloat() ); + } +} + +void C_BasePlayer::CalcInEyeCamView(Vector& eyeOrigin, QAngle& eyeAngles, float& fov) +{ + C_BaseEntity *target = GetObserverTarget(); + + if ( !target ) + { + // just copy a save in-map position + VectorCopy( EyePosition(), eyeOrigin ); + VectorCopy( EyeAngles(), eyeAngles ); + return; + }; + + if ( !target->IsAlive() ) + { + // if dead, show from 3rd person + CalcChaseCamView( eyeOrigin, eyeAngles, fov ); + return; + } + + fov = GetFOV(); // TODO use tragets FOV + + m_flObserverChaseDistance = 0.0; + + eyeAngles = target->EyeAngles(); + eyeOrigin = target->GetAbsOrigin(); + + // Apply punch angle + VectorAdd( eyeAngles, GetPunchAngle(), eyeAngles ); + +#if defined( REPLAY_ENABLED ) + if( engine->IsHLTV() || g_pEngineClientReplay->IsPlayingReplayDemo() ) +#else + if( engine->IsHLTV() ) +#endif + { + C_BaseAnimating *pTargetAnimating = target->GetBaseAnimating(); + if ( target->GetFlags() & FL_DUCKING ) + { + eyeOrigin += pTargetAnimating ? VEC_DUCK_VIEW_SCALED( pTargetAnimating ) : VEC_DUCK_VIEW; + } + else + { + eyeOrigin += pTargetAnimating ? VEC_VIEW_SCALED( pTargetAnimating ) : VEC_VIEW; + } + } + else + { + Vector offset = GetViewOffset(); +#ifdef HL2MP + offset = target->GetViewOffset(); +#endif + eyeOrigin += offset; // hack hack + } + + engine->SetViewAngles( eyeAngles ); +} + +float C_BasePlayer::GetDeathCamInterpolationTime() +{ + return DEATH_ANIMATION_TIME; +} + + +void C_BasePlayer::CalcDeathCamView(Vector& eyeOrigin, QAngle& eyeAngles, float& fov) +{ + CBaseEntity * pKiller = NULL; + + if ( mp_forcecamera.GetInt() == OBS_ALLOW_ALL ) + { + // if mp_forcecamera is off let user see killer or look around + pKiller = GetObserverTarget(); + eyeAngles = EyeAngles(); + } + + float interpolation = ( gpGlobals->curtime - m_flDeathTime ) / GetDeathCamInterpolationTime(); + interpolation = clamp( interpolation, 0.0f, 1.0f ); + + m_flObserverChaseDistance += gpGlobals->frametime*48.0f; + m_flObserverChaseDistance = clamp( m_flObserverChaseDistance, ( CHASE_CAM_DISTANCE_MIN * 2 ), CHASE_CAM_DISTANCE_MAX ); + + QAngle aForward = eyeAngles; + Vector origin = EyePosition(); + + // NOTE: This will create the ragdoll in CSS if m_hRagdoll is set, but m_pRagdoll is not yet presetn + IRagdoll *pRagdoll = GetRepresentativeRagdoll(); + if ( pRagdoll ) + { + origin = pRagdoll->GetRagdollOrigin(); + origin.z += VEC_DEAD_VIEWHEIGHT_SCALED( this ).z; + } + + if ( pKiller && pKiller->IsPlayer() && (pKiller != this) ) + { + Vector vKiller = pKiller->EyePosition() - origin; + QAngle aKiller; VectorAngles( vKiller, aKiller ); + InterpolateAngles( aForward, aKiller, eyeAngles, interpolation ); + }; + + Vector vForward; AngleVectors( eyeAngles, &vForward ); + + VectorNormalize( vForward ); + + VectorMA( origin, -m_flObserverChaseDistance, vForward, eyeOrigin ); + + trace_t trace; // clip against world + C_BaseEntity::PushEnableAbsRecomputations( false ); // HACK don't recompute positions while doing RayTrace + UTIL_TraceHull( origin, eyeOrigin, WALL_MIN, WALL_MAX, MASK_SOLID, this, COLLISION_GROUP_NONE, &trace ); + C_BaseEntity::PopEnableAbsRecomputations(); + + if (trace.fraction < 1.0) + { + eyeOrigin = trace.endpos; + m_flObserverChaseDistance = VectorLength(origin - eyeOrigin); + } + + fov = GetFOV(); +} + + + +//----------------------------------------------------------------------------- +// Purpose: Return the weapon to have open the weapon selection on, based upon our currently active weapon +// Base class just uses the weapon that's currently active. +//----------------------------------------------------------------------------- +C_BaseCombatWeapon *C_BasePlayer::GetActiveWeaponForSelection( void ) +{ + return GetActiveWeapon(); +} + +C_BaseAnimating* C_BasePlayer::GetRenderedWeaponModel() +{ + // Attach to either their weapon model or their view model. + if ( ShouldDrawLocalPlayer() || !IsLocalPlayer() ) + { + return GetActiveWeapon(); + } + else + { + return GetViewModel(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Gets a pointer to the local player, if it exists yet. +// Output : C_BasePlayer +//----------------------------------------------------------------------------- +C_BasePlayer *C_BasePlayer::GetLocalPlayer( void ) +{ + return s_pLocalPlayer; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : bThirdperson - +//----------------------------------------------------------------------------- +void C_BasePlayer::ThirdPersonSwitch( bool bThirdperson ) +{ + // We've switch from first to third, or vice versa. + UpdateVisibility(); + + // Update the visibility of anything bone attached to us. + if ( IsLocalPlayer() ) + { + bool bShouldDrawLocalPlayer = ShouldDrawLocalPlayer(); + for ( int i=0; i<GetNumBoneAttachments(); ++i ) + { + C_BaseAnimating* pBoneAttachment = GetBoneAttachment( i ); + if ( pBoneAttachment ) + { + if ( bShouldDrawLocalPlayer ) + { + pBoneAttachment->RemoveEffects( EF_NODRAW ); + } + else + { + pBoneAttachment->AddEffects( EF_NODRAW ); + } + } + } + } +} + + +//----------------------------------------------------------------------------- +// Purpose: single place to decide whether the camera is in the first-person position +// NOTE - ShouldDrawLocalPlayer() can be true even if the camera is in the first-person position, e.g. in VR. +//----------------------------------------------------------------------------- +/*static*/ bool C_BasePlayer::LocalPlayerInFirstPersonView() +{ + C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer(); + if ( pLocalPlayer == NULL ) + { + return false; + } + int ObserverMode = pLocalPlayer->GetObserverMode(); + if ( ( ObserverMode == OBS_MODE_NONE ) || ( ObserverMode == OBS_MODE_IN_EYE ) ) + { + return !input->CAM_IsThirdPerson() && ( !ToolsEnabled() || !ToolFramework_IsThirdPersonCamera() ); + } + else + { + // Not looking at the local player, e.g. in a replay in third person mode or freelook. + return false; + } +} + +//----------------------------------------------------------------------------- +// Purpose: single place to decide whether the local player should draw +//----------------------------------------------------------------------------- +/*static*/ bool C_BasePlayer::ShouldDrawLocalPlayer() +{ + if ( !UseVR() ) + { + return !LocalPlayerInFirstPersonView() || cl_first_person_uses_world_model.GetBool(); + } + else + { + static ConVarRef vr_first_person_uses_world_model( "vr_first_person_uses_world_model" ); + return !LocalPlayerInFirstPersonView() || vr_first_person_uses_world_model.GetBool(); + } +} + + + +//----------------------------------------------------------------------------- +// Purpose: single place to decide whether the camera is in the first-person position +// NOTE - ShouldDrawLocalPlayer() can be true even if the camera is in the first-person position, e.g. in VR. +//----------------------------------------------------------------------------- +bool C_BasePlayer::InFirstPersonView() +{ + if ( IsLocalPlayer() ) + { + return LocalPlayerInFirstPersonView(); + } + C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer(); + if ( pLocalPlayer == NULL ) + { + return false; + } + // If this is who we're observing in first person, it's counted as the "local" player. + if ( pLocalPlayer->GetObserverMode() == OBS_MODE_IN_EYE && pLocalPlayer->GetObserverTarget() == ToBasePlayer(this) ) + { + return LocalPlayerInFirstPersonView(); + } + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: single place to decide whether the player is being drawn with the standard model (i.e. not the viewmodel) +// NOTE - ShouldDrawLocalPlayer() can be true even if the camera is in the first-person position, e.g. in VR. +//----------------------------------------------------------------------------- +bool C_BasePlayer::ShouldDrawThisPlayer() +{ + if ( !InFirstPersonView() ) + { + return true; + } + if ( !UseVR() && cl_first_person_uses_world_model.GetBool() ) + { + return true; + } + if ( UseVR() ) + { + static ConVarRef vr_first_person_uses_world_model( "vr_first_person_uses_world_model" ); + if ( vr_first_person_uses_world_model.GetBool() ) + { + return true; + } + } + return false; +} + + + +//----------------------------------------------------------------------------- +// Purpose: +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool C_BasePlayer::IsLocalPlayer( void ) const +{ + return ( GetLocalPlayer() == this ); +} + +int C_BasePlayer::GetUserID( void ) +{ + player_info_t pi; + + if ( !engine->GetPlayerInfo( entindex(), &pi ) ) + return -1; + + return pi.userID; +} + + +// For weapon prediction +void C_BasePlayer::SetAnimation( PLAYER_ANIM playerAnim ) +{ + // FIXME +} + +void C_BasePlayer::UpdateClientData( void ) +{ + // Update all the items + for ( int i = 0; i < WeaponCount(); i++ ) + { + if ( GetWeapon(i) ) // each item updates it's successors + GetWeapon(i)->UpdateClientData( this ); + } +} + +// Prediction stuff +void C_BasePlayer::PreThink( void ) +{ +#if !defined( NO_ENTITY_PREDICTION ) + ItemPreFrame(); + + UpdateClientData(); + + UpdateUnderwaterState(); + + // Update the player's fog data if necessary. + UpdateFogController(); + + if (m_lifeState >= LIFE_DYING) + return; + + // + // If we're not on the ground, we're falling. Update our falling velocity. + // + if ( !( GetFlags() & FL_ONGROUND ) ) + { + m_Local.m_flFallVelocity = -GetAbsVelocity().z; + } +#endif +} + +void C_BasePlayer::PostThink( void ) +{ +#if !defined( NO_ENTITY_PREDICTION ) + MDLCACHE_CRITICAL_SECTION(); + + if ( IsAlive()) + { + if ( !CommentaryModeShouldSwallowInput( this ) ) + { + // do weapon stuff + ItemPostFrame(); + } + + if ( GetFlags() & FL_ONGROUND ) + { + m_Local.m_flFallVelocity = 0; + } + + // Don't allow bogus sequence on player + if ( GetSequence() == -1 ) + { + SetSequence( 0 ); + } + + StudioFrameAdvance(); + } + + // Even if dead simulate entities + SimulatePlayerSimulatedEntities(); +#endif +} + +//----------------------------------------------------------------------------- +// Purpose: send various tool messages - viewoffset, and base class messages (flex and bones) +//----------------------------------------------------------------------------- +void C_BasePlayer::GetToolRecordingState( KeyValues *msg ) +{ + if ( !ToolsEnabled() ) + return; + + VPROF_BUDGET( "C_BasePlayer::GetToolRecordingState", VPROF_BUDGETGROUP_TOOLS ); + + BaseClass::GetToolRecordingState( msg ); + + msg->SetInt( "baseplayer", 1 ); + msg->SetInt( "localplayer", IsLocalPlayer() ? 1 : 0 ); + msg->SetString( "playername", GetPlayerName() ); + + static CameraRecordingState_t state; + state.m_flFOV = GetFOV(); + + float flZNear = view->GetZNear(); + float flZFar = view->GetZFar(); + CalcView( state.m_vecEyePosition, state.m_vecEyeAngles, flZNear, flZFar, state.m_flFOV ); + state.m_bThirdPerson = !engine->IsPaused() && ::input->CAM_IsThirdPerson(); + + // this is a straight copy from ClientModeShared::OverrideView, + // When that method is removed in favor of rolling it into CalcView, + // then this code can (should!) be removed + if ( state.m_bThirdPerson ) + { + Vector cam_ofs = g_ThirdPersonManager.GetCameraOffsetAngles(); + + QAngle camAngles; + camAngles[ PITCH ] = cam_ofs[ PITCH ]; + camAngles[ YAW ] = cam_ofs[ YAW ]; + camAngles[ ROLL ] = 0; + + Vector camForward, camRight, camUp; + AngleVectors( camAngles, &camForward, &camRight, &camUp ); + + VectorMA( state.m_vecEyePosition, -cam_ofs[ ROLL ], camForward, state.m_vecEyePosition ); + + // Override angles from third person camera + VectorCopy( camAngles, state.m_vecEyeAngles ); + } + + msg->SetPtr( "camera", &state ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Simulate the player for this frame +//----------------------------------------------------------------------------- +void C_BasePlayer::Simulate() +{ + //Frame updates + if ( this == C_BasePlayer::GetLocalPlayer() ) + { + //Update the flashlight + Flashlight(); + + // Update the player's fog data if necessary. + UpdateFogController(); + } + else + { + // update step sounds for all other players + Vector vel; + EstimateAbsVelocity( vel ); + UpdateStepSound( GetGroundSurface(), GetAbsOrigin(), vel ); + } + + BaseClass::Simulate(); + if ( IsNoInterpolationFrame() || Teleported() ) + { + ResetLatched(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : CBaseViewModel +// Consider using GetRenderedWeaponModel() instead - it will get the +// viewmodel or the active weapon as appropriate. +//----------------------------------------------------------------------------- +C_BaseViewModel *C_BasePlayer::GetViewModel( int index /*= 0*/, bool bObserverOK ) +{ + Assert( index >= 0 && index < MAX_VIEWMODELS ); + + C_BaseViewModel *vm = m_hViewModel[ index ]; + + if ( bObserverOK && GetObserverMode() == OBS_MODE_IN_EYE ) + { + C_BasePlayer *target = ToBasePlayer( GetObserverTarget() ); + + // get the targets viewmodel unless the target is an observer itself + if ( target && target != this && !target->IsObserver() ) + { + vm = target->GetViewModel( index ); + } + } + + return vm; +} + +C_BaseCombatWeapon *C_BasePlayer::GetActiveWeapon( void ) const +{ + const C_BasePlayer *fromPlayer = this; + + // if localplayer is in InEye spectator mode, return weapon on chased player + if ( (fromPlayer == GetLocalPlayer()) && ( GetObserverMode() == OBS_MODE_IN_EYE) ) + { + C_BaseEntity *target = GetObserverTarget(); + + if ( target && target->IsPlayer() ) + { + fromPlayer = ToBasePlayer( target ); + } + } + + return fromPlayer->C_BaseCombatCharacter::GetActiveWeapon(); +} + +//========================================================= +// Autoaim +// set crosshair position to point to enemey +//========================================================= +Vector C_BasePlayer::GetAutoaimVector( float flScale ) +{ + // Never autoaim a predicted weapon (for now) + Vector forward; + AngleVectors( GetAbsAngles() + m_Local.m_vecPunchAngle, &forward ); + return forward; +} + +void C_BasePlayer::PlayPlayerJingle() +{ +#ifndef _XBOX + // Find player sound for shooter + player_info_t info; + engine->GetPlayerInfo( entindex(), &info ); + + if ( !cl_customsounds.GetBool() ) + return; + + // Doesn't have a jingle sound + if ( !info.customFiles[1] ) + return; + + char soundhex[ 16 ]; + Q_binarytohex( (byte *)&info.customFiles[1], sizeof( info.customFiles[1] ), soundhex, sizeof( soundhex ) ); + + // See if logo has been downloaded. + char fullsoundname[ 512 ]; + Q_snprintf( fullsoundname, sizeof( fullsoundname ), "sound/temp/%s.wav", soundhex ); + + if ( !filesystem->FileExists( fullsoundname ) ) + { + char custname[ 512 ]; + Q_snprintf( custname, sizeof( custname ), "download/user_custom/%c%c/%s.dat", soundhex[0], soundhex[1], soundhex ); + // it may have been downloaded but not copied under materials folder + if ( !filesystem->FileExists( custname ) ) + return; // not downloaded yet + + // copy from download folder to materials/temp folder + // this is done since material system can access only materials/*.vtf files + + if ( !engine->CopyLocalFile( custname, fullsoundname) ) + return; + } + + Q_snprintf( fullsoundname, sizeof( fullsoundname ), "temp/%s.wav", soundhex ); + + CLocalPlayerFilter filter; + + EmitSound_t ep; + ep.m_nChannel = CHAN_VOICE; + ep.m_pSoundName = fullsoundname; + ep.m_flVolume = VOL_NORM; + ep.m_SoundLevel = SNDLVL_NORM; + + C_BaseEntity::EmitSound( filter, GetSoundSourceIndex(), ep ); +#endif +} + +// Stuff for prediction +void C_BasePlayer::SetSuitUpdate(const char *name, int fgroup, int iNoRepeat) +{ + // FIXME: Do something here? +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_BasePlayer::ResetAutoaim( void ) +{ +#if 0 + if (m_vecAutoAim.x != 0 || m_vecAutoAim.y != 0) + { + m_vecAutoAim = QAngle( 0, 0, 0 ); + engine->CrosshairAngle( edict(), 0, 0 ); + } +#endif + m_fOnTarget = false; +} + +bool C_BasePlayer::ShouldPredict( void ) +{ +#if !defined( NO_ENTITY_PREDICTION ) + // Do this before calling into baseclass so prediction data block gets allocated + if ( IsLocalPlayer() ) + { + return true; + } +#endif + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: Special processing for player simulation +// NOTE: Don't chain to BaseClass!!!! +//----------------------------------------------------------------------------- +void C_BasePlayer::PhysicsSimulate( void ) +{ +#if !defined( NO_ENTITY_PREDICTION ) + VPROF( "C_BasePlayer::PhysicsSimulate" ); + // If we've got a moveparent, we must simulate that first. + CBaseEntity *pMoveParent = GetMoveParent(); + if (pMoveParent) + { + pMoveParent->PhysicsSimulate(); + } + + // Make sure not to simulate this guy twice per frame + if (m_nSimulationTick == gpGlobals->tickcount) + return; + + m_nSimulationTick = gpGlobals->tickcount; + + if ( !IsLocalPlayer() ) + return; + + C_CommandContext *ctx = GetCommandContext(); + Assert( ctx ); + Assert( ctx->needsprocessing ); + if ( !ctx->needsprocessing ) + return; + + ctx->needsprocessing = false; + + // Handle FL_FROZEN. + if(GetFlags() & FL_FROZEN) + { + ctx->cmd.forwardmove = 0; + ctx->cmd.sidemove = 0; + ctx->cmd.upmove = 0; + ctx->cmd.buttons = 0; + ctx->cmd.impulse = 0; + //VectorCopy ( pl.v_angle, ctx->cmd.viewangles ); + } + + // Run the next command + prediction->RunCommand( + this, + &ctx->cmd, + MoveHelper() ); +#endif +} + +const QAngle& C_BasePlayer::GetPunchAngle() +{ + return m_Local.m_vecPunchAngle.Get(); +} + + +void C_BasePlayer::SetPunchAngle( const QAngle &angle ) +{ + m_Local.m_vecPunchAngle = angle; +} + + +float C_BasePlayer::GetWaterJumpTime() const +{ + return m_flWaterJumpTime; +} + +void C_BasePlayer::SetWaterJumpTime( float flWaterJumpTime ) +{ + m_flWaterJumpTime = flWaterJumpTime; +} + +float C_BasePlayer::GetSwimSoundTime() const +{ + return m_flSwimSoundTime; +} + +void C_BasePlayer::SetSwimSoundTime( float flSwimSoundTime ) +{ + m_flSwimSoundTime = flSwimSoundTime; +} + + +//----------------------------------------------------------------------------- +// Purpose: Return true if this object can be +used by the player +//----------------------------------------------------------------------------- +bool C_BasePlayer::IsUseableEntity( CBaseEntity *pEntity, unsigned int requiredCaps ) +{ + return false; +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Output : float +//----------------------------------------------------------------------------- +float C_BasePlayer::GetFOV( void ) +{ + // Allow users to override the FOV during demo playback + bool bUseDemoOverrideFov = engine->IsPlayingDemo() && demo_fov_override.GetFloat() > 0.0f; +#if defined( REPLAY_ENABLED ) + bUseDemoOverrideFov = bUseDemoOverrideFov && !g_pEngineClientReplay->IsPlayingReplayDemo(); +#endif + if ( bUseDemoOverrideFov ) + { + return clamp( demo_fov_override.GetFloat(), 10.0f, 90.0f ); + } + + if ( GetObserverMode() == OBS_MODE_IN_EYE ) + { + C_BasePlayer *pTargetPlayer = dynamic_cast<C_BasePlayer*>( GetObserverTarget() ); + + // get fov from observer target. Not if target is observer itself + if ( pTargetPlayer && !pTargetPlayer->IsObserver() ) + { + return pTargetPlayer->GetFOV(); + } + } + + // Allow our vehicle to override our FOV if it's currently at the default FOV. + float flDefaultFOV; + IClientVehicle *pVehicle = GetVehicle(); + if ( pVehicle ) + { + CacheVehicleView(); + flDefaultFOV = ( m_flVehicleViewFOV == 0 ) ? GetDefaultFOV() : m_flVehicleViewFOV; + } + else + { + flDefaultFOV = GetDefaultFOV(); + } + + float fFOV = ( m_iFOV == 0 ) ? flDefaultFOV : m_iFOV; + + // Don't do lerping during prediction. It's only necessary when actually rendering, + // and it'll cause problems due to prediction timing messiness. + if ( !prediction->InPrediction() ) + { + // See if we need to lerp the values for local player + if ( IsLocalPlayer() && ( fFOV != m_iFOVStart ) && (m_Local.m_flFOVRate > 0.0f ) ) + { + float deltaTime = (float)( gpGlobals->curtime - m_flFOVTime ) / m_Local.m_flFOVRate; + +#if !defined( NO_ENTITY_PREDICTION ) + if ( GetPredictable() ) + { + // m_flFOVTime was set to a predicted time in the future, because the FOV change was predicted. + deltaTime = (float)( GetFinalPredictedTime() - m_flFOVTime ); + deltaTime += ( gpGlobals->interpolation_amount * TICK_INTERVAL ); + deltaTime /= m_Local.m_flFOVRate; + } +#endif + + if ( deltaTime >= 1.0f ) + { + //If we're past the zoom time, just take the new value and stop lerping + m_iFOVStart = fFOV; + } + else + { + fFOV = SimpleSplineRemapValClamped( deltaTime, 0.0f, 1.0f, (float) m_iFOVStart, fFOV ); + } + } + } + + return fFOV; +} + +void RecvProxy_LocalVelocityX( const CRecvProxyData *pData, void *pStruct, void *pOut ) +{ + C_BasePlayer *pPlayer = (C_BasePlayer *) pStruct; + + Assert( pPlayer ); + + float flNewVel_x = pData->m_Value.m_Float; + + Vector vecVelocity = pPlayer->GetLocalVelocity(); + + if( vecVelocity.x != flNewVel_x ) // Should this use an epsilon check? + { + vecVelocity.x = flNewVel_x; + pPlayer->SetLocalVelocity( vecVelocity ); + } +} + +void RecvProxy_LocalVelocityY( const CRecvProxyData *pData, void *pStruct, void *pOut ) +{ + C_BasePlayer *pPlayer = (C_BasePlayer *) pStruct; + + Assert( pPlayer ); + + float flNewVel_y = pData->m_Value.m_Float; + + Vector vecVelocity = pPlayer->GetLocalVelocity(); + + if( vecVelocity.y != flNewVel_y ) + { + vecVelocity.y = flNewVel_y; + pPlayer->SetLocalVelocity( vecVelocity ); + } +} + +void RecvProxy_LocalVelocityZ( const CRecvProxyData *pData, void *pStruct, void *pOut ) +{ + C_BasePlayer *pPlayer = (C_BasePlayer *) pStruct; + + Assert( pPlayer ); + + float flNewVel_z = pData->m_Value.m_Float; + + Vector vecVelocity = pPlayer->GetLocalVelocity(); + + if( vecVelocity.z != flNewVel_z ) + { + vecVelocity.z = flNewVel_z; + pPlayer->SetLocalVelocity( vecVelocity ); + } +} + +void RecvProxy_ObserverTarget( const CRecvProxyData *pData, void *pStruct, void *pOut ) +{ + C_BasePlayer *pPlayer = (C_BasePlayer *) pStruct; + + Assert( pPlayer ); + + EHANDLE hTarget; + + RecvProxy_IntToEHandle( pData, pStruct, &hTarget ); + + pPlayer->SetObserverTarget( hTarget ); +} + +void RecvProxy_ObserverMode( const CRecvProxyData *pData, void *pStruct, void *pOut ) +{ + C_BasePlayer *pPlayer = (C_BasePlayer *) pStruct; + + Assert( pPlayer ); + + pPlayer->SetObserverMode ( pData->m_Value.m_Int ); +} + +//----------------------------------------------------------------------------- +// Purpose: Remove this player from a vehicle +//----------------------------------------------------------------------------- +void C_BasePlayer::LeaveVehicle( void ) +{ + if ( NULL == m_hVehicle.Get() ) + return; + +// Let server do this for now +#if 0 + IClientVehicle *pVehicle = GetVehicle(); + Assert( pVehicle ); + + int nRole = pVehicle->GetPassengerRole( this ); + Assert( nRole != VEHICLE_ROLE_NONE ); + + SetParent( NULL ); + + // Find the first non-blocked exit point: + Vector vNewPos = GetAbsOrigin(); + QAngle qAngles = GetAbsAngles(); + pVehicle->GetPassengerExitPoint( nRole, &vNewPos, &qAngles ); + OnVehicleEnd( vNewPos ); + SetAbsOrigin( vNewPos ); + SetAbsAngles( qAngles ); + + m_Local.m_iHideHUD &= ~HIDEHUD_WEAPONSELECTION; + RemoveEffects( EF_NODRAW ); + + SetMoveType( MOVETYPE_WALK ); + SetCollisionGroup( COLLISION_GROUP_PLAYER ); + + qAngles[ROLL] = 0; + SnapEyeAngles( qAngles ); + + m_hVehicle = NULL; + pVehicle->SetPassenger(nRole, NULL); + + Weapon_Switch( m_hLastWeapon ); +#endif +} + + +float C_BasePlayer::GetMinFOV() const +{ + if ( gpGlobals->maxClients == 1 ) + { + // Let them do whatever they want, more or less, in single player + return 5; + } + else + { + return 75; + } +} + +float C_BasePlayer::GetFinalPredictedTime() const +{ + return ( m_nFinalPredictedTick * TICK_INTERVAL ); +} + +void C_BasePlayer::NotePredictionError( const Vector &vDelta ) +{ + // don't worry about prediction errors when dead + if ( !IsAlive() ) + return; + +#if !defined( NO_ENTITY_PREDICTION ) + Vector vOldDelta; + + GetPredictionErrorSmoothingVector( vOldDelta ); + + // sum all errors within smoothing time + m_vecPredictionError = vDelta + vOldDelta; + + // remember when last error happened + m_flPredictionErrorTime = gpGlobals->curtime; + + ResetLatched(); +#endif +} + + +// offset curtime and setup bones at that time using fake interpolation +// fake interpolation means we don't have reliable interpolation history (the local player doesn't animate locally) +// so we just modify cycle and origin directly and use that as a fake guess +void C_BasePlayer::ForceSetupBonesAtTimeFakeInterpolation( matrix3x4_t *pBonesOut, float curtimeOffset ) +{ + // we don't have any interpolation data, so fake it + float cycle = m_flCycle; + Vector origin = GetLocalOrigin(); + + // blow the cached prev bones + InvalidateBoneCache(); + // reset root position to flTime + Interpolate( gpGlobals->curtime + curtimeOffset ); + + // force cycle back by boneDt + m_flCycle = fmod( 10 + cycle + m_flPlaybackRate * curtimeOffset, 1.0f ); + SetLocalOrigin( origin + curtimeOffset * GetLocalVelocity() ); + // Setup bone state to extrapolate physics velocity + SetupBones( pBonesOut, MAXSTUDIOBONES, BONE_USED_BY_ANYTHING, gpGlobals->curtime + curtimeOffset ); + + m_flCycle = cycle; + SetLocalOrigin( origin ); +} + +void C_BasePlayer::GetRagdollInitBoneArrays( matrix3x4_t *pDeltaBones0, matrix3x4_t *pDeltaBones1, matrix3x4_t *pCurrentBones, float boneDt ) +{ + if ( !IsLocalPlayer() ) + { + BaseClass::GetRagdollInitBoneArrays(pDeltaBones0, pDeltaBones1, pCurrentBones, boneDt); + return; + } + ForceSetupBonesAtTimeFakeInterpolation( pDeltaBones0, -boneDt ); + ForceSetupBonesAtTimeFakeInterpolation( pDeltaBones1, 0 ); + float ragdollCreateTime = PhysGetSyncCreateTime(); + if ( ragdollCreateTime != gpGlobals->curtime ) + { + ForceSetupBonesAtTimeFakeInterpolation( pCurrentBones, ragdollCreateTime - gpGlobals->curtime ); + } + else + { + SetupBones( pCurrentBones, MAXSTUDIOBONES, BONE_USED_BY_ANYTHING, gpGlobals->curtime ); + } +} + + +void C_BasePlayer::GetPredictionErrorSmoothingVector( Vector &vOffset ) +{ +#if !defined( NO_ENTITY_PREDICTION ) + if ( engine->IsPlayingDemo() || !cl_smooth.GetInt() || !cl_predict->GetInt() || engine->IsPaused() ) + { + vOffset.Init(); + return; + } + + float errorAmount = ( gpGlobals->curtime - m_flPredictionErrorTime ) / cl_smoothtime.GetFloat(); + + if ( errorAmount >= 1.0f ) + { + vOffset.Init(); + return; + } + + errorAmount = 1.0f - errorAmount; + + vOffset = m_vecPredictionError * errorAmount; +#else + vOffset.Init(); +#endif +} + + +IRagdoll* C_BasePlayer::GetRepresentativeRagdoll() const +{ + return m_pRagdoll; +} + +IMaterial *C_BasePlayer::GetHeadLabelMaterial( void ) +{ + if ( GetClientVoiceMgr() == NULL ) + return NULL; + + return GetClientVoiceMgr()->GetHeadLabelMaterial(); +} + +bool IsInFreezeCam( void ) +{ + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + if ( pPlayer && pPlayer->GetObserverMode() == OBS_MODE_FREEZECAM ) + return true; + + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: Set the fog controller data per player. +// Input : &inputdata - +//----------------------------------------------------------------------------- +void C_BasePlayer::FogControllerChanged( bool bSnap ) +{ + if ( m_Local.m_PlayerFog.m_hCtrl ) + { + fogparams_t *pFogParams = &(m_Local.m_PlayerFog.m_hCtrl->m_fog); + + /* + Msg("Updating Fog Target: (%d,%d,%d) %.0f,%.0f -> (%d,%d,%d) %.0f,%.0f (%.2f seconds)\n", + m_CurrentFog.colorPrimary.GetR(), m_CurrentFog.colorPrimary.GetB(), m_CurrentFog.colorPrimary.GetG(), + m_CurrentFog.start.Get(), m_CurrentFog.end.Get(), + pFogParams->colorPrimary.GetR(), pFogParams->colorPrimary.GetB(), pFogParams->colorPrimary.GetG(), + pFogParams->start.Get(), pFogParams->end.Get(), pFogParams->duration.Get() );*/ + + + // Setup the fog color transition. + m_Local.m_PlayerFog.m_OldColor = m_CurrentFog.colorPrimary; + m_Local.m_PlayerFog.m_flOldStart = m_CurrentFog.start; + m_Local.m_PlayerFog.m_flOldEnd = m_CurrentFog.end; + + m_Local.m_PlayerFog.m_NewColor = pFogParams->colorPrimary; + m_Local.m_PlayerFog.m_flNewStart = pFogParams->start; + m_Local.m_PlayerFog.m_flNewEnd = pFogParams->end; + + m_Local.m_PlayerFog.m_flTransitionTime = bSnap ? -1 : gpGlobals->curtime; + + m_CurrentFog = *pFogParams; + + // Update the fog player's local fog data with the fog controller's data if need be. + UpdateFogController(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Check to see that the controllers data is up to date. +//----------------------------------------------------------------------------- +void C_BasePlayer::UpdateFogController( void ) +{ + if ( m_Local.m_PlayerFog.m_hCtrl ) + { + // Don't bother copying while we're transitioning, since it'll be stomped in UpdateFogBlend(); + if ( m_Local.m_PlayerFog.m_flTransitionTime == -1 && (m_hOldFogController == m_Local.m_PlayerFog.m_hCtrl) ) + { + fogparams_t *pFogParams = &(m_Local.m_PlayerFog.m_hCtrl->m_fog); + if ( m_CurrentFog != *pFogParams ) + { + /* + Msg("FORCING UPDATE: (%d,%d,%d) %.0f,%.0f -> (%d,%d,%d) %.0f,%.0f (%.2f seconds)\n", + m_CurrentFog.colorPrimary.GetR(), m_CurrentFog.colorPrimary.GetB(), m_CurrentFog.colorPrimary.GetG(), + m_CurrentFog.start.Get(), m_CurrentFog.end.Get(), + pFogParams->colorPrimary.GetR(), pFogParams->colorPrimary.GetB(), pFogParams->colorPrimary.GetG(), + pFogParams->start.Get(), pFogParams->end.Get(), pFogParams->duration.Get() );*/ + + + m_CurrentFog = *pFogParams; + } + } + } + else + { + if ( m_CurrentFog.farz != -1 || m_CurrentFog.enable != false ) + { + // No fog controller in this level. Use default fog parameters. + m_CurrentFog.farz = -1; + m_CurrentFog.enable = false; + } + } + + // Update the fog blending state - of necessary. + UpdateFogBlend(); +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void C_BasePlayer::UpdateFogBlend( void ) +{ + // Transition. + if ( m_Local.m_PlayerFog.m_flTransitionTime != -1 ) + { + float flTimeDelta = gpGlobals->curtime - m_Local.m_PlayerFog.m_flTransitionTime; + if ( flTimeDelta < m_CurrentFog.duration ) + { + float flScale = flTimeDelta / m_CurrentFog.duration; + m_CurrentFog.colorPrimary.SetR( ( m_Local.m_PlayerFog.m_NewColor.r * flScale ) + ( m_Local.m_PlayerFog.m_OldColor.r * ( 1.0f - flScale ) ) ); + m_CurrentFog.colorPrimary.SetG( ( m_Local.m_PlayerFog.m_NewColor.g * flScale ) + ( m_Local.m_PlayerFog.m_OldColor.g * ( 1.0f - flScale ) ) ); + m_CurrentFog.colorPrimary.SetB( ( m_Local.m_PlayerFog.m_NewColor.b * flScale ) + ( m_Local.m_PlayerFog.m_OldColor.b * ( 1.0f - flScale ) ) ); + m_CurrentFog.start.Set( ( m_Local.m_PlayerFog.m_flNewStart * flScale ) + ( ( m_Local.m_PlayerFog.m_flOldStart * ( 1.0f - flScale ) ) ) ); + m_CurrentFog.end.Set( ( m_Local.m_PlayerFog.m_flNewEnd * flScale ) + ( ( m_Local.m_PlayerFog.m_flOldEnd * ( 1.0f - flScale ) ) ) ); + } + else + { + // Slam the final fog values. + m_CurrentFog.colorPrimary.SetR( m_Local.m_PlayerFog.m_NewColor.r ); + m_CurrentFog.colorPrimary.SetG( m_Local.m_PlayerFog.m_NewColor.g ); + m_CurrentFog.colorPrimary.SetB( m_Local.m_PlayerFog.m_NewColor.b ); + m_CurrentFog.start.Set( m_Local.m_PlayerFog.m_flNewStart ); + m_CurrentFog.end.Set( m_Local.m_PlayerFog.m_flNewEnd ); + m_Local.m_PlayerFog.m_flTransitionTime = -1; + + /* + Msg("Finished transition to (%d,%d,%d) %.0f,%.0f\n", + m_CurrentFog.colorPrimary.GetR(), m_CurrentFog.colorPrimary.GetB(), m_CurrentFog.colorPrimary.GetG(), + m_CurrentFog.start.Get(), m_CurrentFog.end.Get() );*/ + + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool C_BasePlayer::GetSteamID( CSteamID *pID ) +{ + // try to make this a little more efficient + + player_info_t pi; + if ( engine->GetPlayerInfo( entindex(), &pi ) ) + { + if ( pi.friendsID && steamapicontext && steamapicontext->SteamUtils() ) + { +#if 1 // new + static EUniverse universe = k_EUniverseInvalid; + + if ( universe == k_EUniverseInvalid ) + universe = steamapicontext->SteamUtils()->GetConnectedUniverse(); + + pID->InstancedSet( pi.friendsID, 1, universe, k_EAccountTypeIndividual ); +#else // old + pID->InstancedSet( pi.friendsID, 1, steamapicontext->SteamUtils()->GetConnectedUniverse(), k_EAccountTypeIndividual ); +#endif + + return true; + } + } + return false; +} + +#if defined USES_ECON_ITEMS +//----------------------------------------------------------------------------- +// Purpose: Update the visibility of our worn items. +//----------------------------------------------------------------------------- +void C_BasePlayer::UpdateWearables( void ) +{ + for ( int i=0; i<m_hMyWearables.Count(); ++i ) + { + CEconWearable* pItem = m_hMyWearables[i]; + if ( pItem ) + { + pItem->ValidateModelIndex(); + pItem->UpdateVisibility(); + } + } +} +#endif // USES_ECON_ITEMS + + +//----------------------------------------------------------------------------- +// Purpose: In meathook mode, fix the bone transforms to hang the user's own +// avatar under the camera. +//----------------------------------------------------------------------------- +void C_BasePlayer::BuildFirstPersonMeathookTransformations( CStudioHdr *hdr, Vector *pos, Quaternion q[], const matrix3x4_t& cameraTransform, int boneMask, CBoneBitList &boneComputed, const char *pchHeadBoneName ) +{ + // Handle meathook mode. If we aren't rendering, just use last frame's transforms + if ( !InFirstPersonView() ) + return; + + // If we're in third-person view, don't do anything special. + // If we're in first-person view rendering the main view and using the viewmodel, we shouldn't have even got here! + // If we're in first-person view rendering the main view(s), meathook and headless. + // If we're in first-person view rendering shadowbuffers/reflections, don't do anything special either (we could do meathook but with a head?) + if ( IsAboutToRagdoll() ) + { + // We're re-animating specifically to set up the ragdoll. + // Meathook can push the player through the floor, which makes the ragdoll fall through the world, which is no good. + // So do nothing. + return; + } + + if ( !DrawingMainView() ) + { + return; + } + + // If we aren't drawing the player anyway, don't mess with the bones. This can happen in Portal. + if( !ShouldDrawThisPlayer() ) + { + return; + } + + m_BoneAccessor.SetWritableBones( BONE_USED_BY_ANYTHING ); + + matrix3x4_t &mHeadTransform = GetBoneForWrite( LookupBone( pchHeadBoneName ) ); + + // "up" on the head bone is along the negative Y axis - not sure why. + //Vector vHeadTransformUp ( -mHeadTransform[0][1], -mHeadTransform[1][1], -mHeadTransform[2][1] ); + //Vector vHeadTransformFwd ( mHeadTransform[0][1], mHeadTransform[1][1], mHeadTransform[2][1] ); + Vector vHeadTransformTranslation ( mHeadTransform[0][3], mHeadTransform[1][3], mHeadTransform[2][3] ); + + + // Find out where the player's head (driven by the HMD) is in the world. + // We can't move this with animations or effects without causing nausea, so we need to move + // the whole body so that the animated head is in the right place to match the player-controlled head. + Vector vHeadUp; + bool bMeathookEnable = true; + Vector vRealPivotPoint; + bool bEnableDecapitation = true; + if( UseVR() ) + { + static ConVarRef vr_neck_pivot_ingame_up( "vr_neck_pivot_ingame_up" ); + static ConVarRef vr_neck_pivot_ingame_fwd( "vr_neck_pivot_ingame_fwd" ); + static ConVarRef vr_meathook_enable ( "vr_meathook_enable" ); + static ConVarRef vr_decapitation_enable ( "vr_decapitation_enable" ); + + VMatrix mWorldFromMideye = g_ClientVirtualReality.GetWorldFromMidEye(); + + bMeathookEnable = vr_meathook_enable.GetBool(); + bEnableDecapitation = vr_decapitation_enable.GetBool(); + + // What we do here is: + // * Take the required eye pos+orn - the actual pose the player is controlling with the HMD. + // * Go downwards in that space by headtrack_neck_pivot_ingame_* - this is now the neck-pivot in the game world of where the player is actually looking. + // * Now place the body of the animated character so that the head bone is at that position. + // The head bone is the neck pivot point of the in-game character. + + Vector vRealMidEyePos = mWorldFromMideye.GetTranslation(); + vRealPivotPoint = vRealMidEyePos - ( mWorldFromMideye.GetUp() * vr_neck_pivot_ingame_up.GetFloat() ) - ( mWorldFromMideye.GetForward() * vr_neck_pivot_ingame_fwd.GetFloat() ); + } + else + { + // figure out where to put the body from the aim angles + Vector vForward, vRight, vUp; + AngleVectors( MainViewAngles(), &vForward, &vRight, &vUp ); + + vRealPivotPoint = MainViewOrigin() - ( vUp * 7.3f ) - ( vForward * 3.f ); + } + + Vector vDeltaToAdd = vRealPivotPoint - vHeadTransformTranslation; + + + if ( bMeathookEnable ) + { + // Now add this offset to the entire skeleton. + for (int i = 0; i < hdr->numbones(); i++) + { + // Only update bones reference by the bone mask. + if ( !( hdr->boneFlags( i ) & boneMask ) ) + { + continue; + } + matrix3x4_t& bone = GetBoneForWrite( i ); + Vector vBonePos; + MatrixGetTranslation ( bone, vBonePos ); + vBonePos += vDeltaToAdd; + MatrixSetTranslation ( vBonePos, bone ); + } + } + + if ( bEnableDecapitation ) + { + // Then scale the head to zero, but leave its position - forms a "neck stub". + // This prevents us rendering junk all over the screen, e.g. inside of mouth, etc. + MatrixScaleByZero ( mHeadTransform ); + + // TODO: right now we nuke the hats by shrinking them to nothing, + // but it feels like we should do something more sensible. + // For example, for one sniper taunt he takes his hat off and waves it - would be nice to see it then. + int iHelm = LookupBone( "prp_helmet" ); + if ( iHelm != -1 ) + { + // Scale the helmet. + matrix3x4_t &transformhelmet = GetBoneForWrite( iHelm ); + MatrixScaleByZero ( transformhelmet ); + } + + iHelm = LookupBone( "prp_hat" ); + if ( iHelm != -1 ) + { + matrix3x4_t &transformhelmet = GetBoneForWrite( iHelm ); + MatrixScaleByZero ( transformhelmet ); + } + } + +} + + + +void CC_DumpClientSoundscapeData( const CCommand& args ) +{ + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + if ( !pPlayer ) + return; + + Msg("Client Soundscape data dump:\n"); + Msg(" Position: %.2f %.2f %.2f\n", pPlayer->GetAbsOrigin().x, pPlayer->GetAbsOrigin().y, pPlayer->GetAbsOrigin().z ); + Msg(" soundscape index: %d\n", pPlayer->m_Local.m_audio.soundscapeIndex.Get() ); + Msg(" entity index: %d\n", pPlayer->m_Local.m_audio.ent.Get() ? pPlayer->m_Local.m_audio.ent->entindex() : -1 ); + if ( pPlayer->m_Local.m_audio.ent.Get() ) + { + Msg(" entity pos: %.2f %.2f %.2f\n", pPlayer->m_Local.m_audio.ent.Get()->GetAbsOrigin().x, pPlayer->m_Local.m_audio.ent.Get()->GetAbsOrigin().y, pPlayer->m_Local.m_audio.ent.Get()->GetAbsOrigin().z ); + if ( pPlayer->m_Local.m_audio.ent.Get()->IsDormant() ) + { + Msg(" ENTITY IS DORMANT\n"); + } + } + bool bFoundOne = false; + for ( int i = 0; i < NUM_AUDIO_LOCAL_SOUNDS; i++ ) + { + if ( pPlayer->m_Local.m_audio.localBits & (1<<i) ) + { + if ( !bFoundOne ) + { + Msg(" Sound Positions:\n"); + bFoundOne = true; + } + + Vector vecPos = pPlayer->m_Local.m_audio.localSound[i]; + Msg(" %d: %.2f %.2f %.2f\n", i, vecPos.x,vecPos.y, vecPos.z ); + } + } + + Msg("End dump.\n"); +} +static ConCommand soundscape_dumpclient("soundscape_dumpclient", CC_DumpClientSoundscapeData, "Dumps the client's soundscape data.\n", FCVAR_CHEAT); |