aboutsummaryrefslogtreecommitdiff
path: root/mp/src/game/shared/baseplayer_shared.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'mp/src/game/shared/baseplayer_shared.cpp')
-rw-r--r--mp/src/game/shared/baseplayer_shared.cpp4168
1 files changed, 2084 insertions, 2084 deletions
diff --git a/mp/src/game/shared/baseplayer_shared.cpp b/mp/src/game/shared/baseplayer_shared.cpp
index 06d8a82d..f56e72e4 100644
--- a/mp/src/game/shared/baseplayer_shared.cpp
+++ b/mp/src/game/shared/baseplayer_shared.cpp
@@ -1,2084 +1,2084 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose: Implements shared baseplayer class functionality
-//
-// $NoKeywords: $
-//=============================================================================//
-
-#include "cbase.h"
-#include "movevars_shared.h"
-#include "util_shared.h"
-#include "datacache/imdlcache.h"
-#if defined ( TF_DLL ) || defined ( TF_CLIENT_DLL )
-#include "tf_gamerules.h"
-#endif
-
-#if defined( CLIENT_DLL )
-
- #include "iclientvehicle.h"
- #include "prediction.h"
- #include "c_basedoor.h"
- #include "c_world.h"
- #include "view.h"
- #include "client_virtualreality.h"
- #define CRecipientFilter C_RecipientFilter
- #include "headtrack/isourcevirtualreality.h"
-
-#else
-
- #include "iservervehicle.h"
- #include "trains.h"
- #include "world.h"
- #include "doors.h"
- #include "ai_basenpc.h"
- #include "env_zoom.h"
-
- extern int TrainSpeed(int iSpeed, int iMax);
-
-#endif
-
-#if defined( CSTRIKE_DLL )
-#include "weapon_c4.h"
-#endif // CSTRIKE_DLL
-
-#include "in_buttons.h"
-#include "engine/IEngineSound.h"
-#include "tier0/vprof.h"
-#include "SoundEmitterSystem/isoundemittersystembase.h"
-#include "decals.h"
-#include "obstacle_pushaway.h"
-#ifdef SIXENSE
-#include "sixense/in_sixense.h"
-#endif
-
-// NVNT haptic utils
-#include "haptics/haptic_utils.h"
-// memdbgon must be the last include file in a .cpp file!!!
-#include "tier0/memdbgon.h"
-
-#if defined(GAME_DLL) && !defined(_XBOX)
- extern ConVar sv_pushaway_max_force;
- extern ConVar sv_pushaway_force;
- extern ConVar sv_turbophysics;
-
- class CUsePushFilter : public CTraceFilterEntitiesOnly
- {
- public:
- bool ShouldHitEntity( IHandleEntity *pHandleEntity, int contentsMask )
- {
- CBaseEntity *pEntity = EntityFromEntityHandle( pHandleEntity );
-
- // Static prop case...
- if ( !pEntity )
- return false;
-
- // Only impact on physics objects
- if ( !pEntity->VPhysicsGetObject() )
- return false;
-
-#if defined( CSTRIKE_DLL )
- // don't push the bomb!
- if ( dynamic_cast<CC4*>( pEntity ) )
- return false;
-#endif // CSTRIKE_DLL
-
- return g_pGameRules->CanEntityBeUsePushed( pEntity );
- }
- };
-#endif
-
-#ifdef CLIENT_DLL
-ConVar mp_usehwmmodels( "mp_usehwmmodels", "0", NULL, "Enable the use of the hw morph models. (-1 = never, 1 = always, 0 = based upon GPU)" ); // -1 = never, 0 = if hasfastvertextextures, 1 = always
-#endif
-
-bool UseHWMorphModels()
-{
-// #ifdef CLIENT_DLL
-// if ( mp_usehwmmodels.GetInt() == 0 )
-// return g_pMaterialSystemHardwareConfig->HasFastVertexTextures();
-//
-// return mp_usehwmmodels.GetInt() > 0;
-// #else
-// return false;
-// #endif
- return false;
-}
-
-void CopySoundNameWithModifierToken( char *pchDest, const char *pchSource, int nMaxLenInChars, const char *pchToken )
-{
- // Copy the sound name
- int nSource = 0;
- int nDest = 0;
- bool bFoundPeriod = false;
-
- while ( pchSource[ nSource ] != '\0' && nDest < nMaxLenInChars - 2 )
- {
- pchDest[ nDest ] = pchSource[ nSource ];
- nDest++;
- nSource++;
-
- if ( !bFoundPeriod && pchSource[ nSource - 1 ] == '.' )
- {
- // Insert special token after the period
- bFoundPeriod = true;
-
- int nToken = 0;
-
- while ( pchToken[ nToken ] != '\0' && nDest < nMaxLenInChars - 2 )
- {
- pchDest[ nDest ] = pchToken[ nToken ];
- nDest++;
- nToken++;
- }
- }
- }
-
- pchDest[ nDest ] = '\0';
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Output : float
-//-----------------------------------------------------------------------------
-float CBasePlayer::GetTimeBase( void ) const
-{
- return m_nTickBase * TICK_INTERVAL;
-}
-
-float CBasePlayer::GetPlayerMaxSpeed()
-{
- // player max speed is the lower limit of m_flMaxSpeed and sv_maxspeed
- float fMaxSpeed = sv_maxspeed.GetFloat();
- if ( MaxSpeed() > 0.0f && MaxSpeed() < fMaxSpeed )
- fMaxSpeed = MaxSpeed();
-
- return fMaxSpeed;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Called every usercmd by the player PreThink
-//-----------------------------------------------------------------------------
-void CBasePlayer::ItemPreFrame()
-{
- // Handle use events
- PlayerUse();
-
- CBaseCombatWeapon *pActive = GetActiveWeapon();
-
- // Allow all the holstered weapons to update
- for ( int i = 0; i < WeaponCount(); ++i )
- {
- CBaseCombatWeapon *pWeapon = GetWeapon( i );
-
- if ( pWeapon == NULL )
- continue;
-
- if ( pActive == pWeapon )
- continue;
-
- pWeapon->ItemHolsterFrame();
- }
-
- if ( gpGlobals->curtime < m_flNextAttack )
- return;
-
- if (!pActive)
- return;
-
-#if defined( CLIENT_DLL )
- // Not predicting this weapon
- if ( !pActive->IsPredicted() )
- return;
-#endif
-
- pActive->ItemPreFrame();
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Output : Returns true on success, false on failure.
-//-----------------------------------------------------------------------------
-bool CBasePlayer::UsingStandardWeaponsInVehicle( void )
-{
- Assert( IsInAVehicle() );
-#if !defined( CLIENT_DLL )
- IServerVehicle *pVehicle = GetVehicle();
-#else
- IClientVehicle *pVehicle = GetVehicle();
-#endif
- Assert( pVehicle );
- if ( !pVehicle )
- return true;
-
- // NOTE: We *have* to do this before ItemPostFrame because ItemPostFrame
- // may dump us out of the vehicle
- int nRole = pVehicle->GetPassengerRole( this );
- bool bUsingStandardWeapons = pVehicle->IsPassengerUsingStandardWeapons( nRole );
-
- // Fall through and check weapons, etc. if we're using them
- if (!bUsingStandardWeapons )
- return false;
-
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Called every usercmd by the player PostThink
-//-----------------------------------------------------------------------------
-void CBasePlayer::ItemPostFrame()
-{
- VPROF( "CBasePlayer::ItemPostFrame" );
-
- // Put viewmodels into basically correct place based on new player origin
- CalcViewModelView( EyePosition(), EyeAngles() );
-
- // Don't process items while in a vehicle.
- if ( GetVehicle() )
- {
-#if defined( CLIENT_DLL )
- IClientVehicle *pVehicle = GetVehicle();
-#else
- IServerVehicle *pVehicle = GetVehicle();
-#endif
-
- bool bUsingStandardWeapons = UsingStandardWeaponsInVehicle();
-
-#if defined( CLIENT_DLL )
- if ( pVehicle->IsPredicted() )
-#endif
- {
- pVehicle->ItemPostFrame( this );
- }
-
- if (!bUsingStandardWeapons || !GetVehicle())
- return;
- }
-
-
- // check if the player is using something
- if ( m_hUseEntity != NULL )
- {
-#if !defined( CLIENT_DLL )
- Assert( !IsInAVehicle() );
- ImpulseCommands();// this will call playerUse
-#endif
- return;
- }
-
- if ( gpGlobals->curtime < m_flNextAttack )
- {
- if ( GetActiveWeapon() )
- {
- GetActiveWeapon()->ItemBusyFrame();
- }
- }
- else
- {
- if ( GetActiveWeapon() && (!IsInAVehicle() || UsingStandardWeaponsInVehicle()) )
- {
-#if defined( CLIENT_DLL )
- // Not predicting this weapon
- if ( GetActiveWeapon()->IsPredicted() )
-#endif
-
- {
- GetActiveWeapon()->ItemPostFrame( );
- }
- }
- }
-
-#if !defined( CLIENT_DLL )
- ImpulseCommands();
-#else
- // NOTE: If we ever support full impulse commands on the client,
- // remove this line and call ImpulseCommands instead.
- m_nImpulse = 0;
-#endif
-}
-
-
-//-----------------------------------------------------------------------------
-// Eye angles
-//-----------------------------------------------------------------------------
-const QAngle &CBasePlayer::EyeAngles( )
-{
- // NOTE: Viewangles are measured *relative* to the parent's coordinate system
- CBaseEntity *pMoveParent = const_cast<CBasePlayer*>(this)->GetMoveParent();
-
- if ( !pMoveParent )
- {
- return pl.v_angle;
- }
-
- // FIXME: Cache off the angles?
- matrix3x4_t eyesToParent, eyesToWorld;
- AngleMatrix( pl.v_angle, eyesToParent );
- ConcatTransforms( pMoveParent->EntityToWorldTransform(), eyesToParent, eyesToWorld );
-
- static QAngle angEyeWorld;
- MatrixAngles( eyesToWorld, angEyeWorld );
- return angEyeWorld;
-}
-
-
-const QAngle &CBasePlayer::LocalEyeAngles()
-{
- return pl.v_angle;
-}
-
-//-----------------------------------------------------------------------------
-// Actual Eye position + angles
-//-----------------------------------------------------------------------------
-Vector CBasePlayer::EyePosition( )
-{
- if ( GetVehicle() != NULL )
- {
- // Return the cached result
- CacheVehicleView();
- return m_vecVehicleViewOrigin;
- }
- else
- {
-#ifdef CLIENT_DLL
- if ( IsObserver() )
- {
- if ( GetObserverMode() == OBS_MODE_CHASE )
- {
- if ( IsLocalPlayer() )
- {
- return MainViewOrigin();
- }
- }
- }
-#endif
- return BaseClass::EyePosition();
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input :
-// Output : const Vector
-//-----------------------------------------------------------------------------
-const Vector CBasePlayer::GetPlayerMins( void ) const
-{
- if ( IsObserver() )
- {
- return VEC_OBS_HULL_MIN_SCALED( this );
- }
- else
- {
- if ( GetFlags() & FL_DUCKING )
- {
- return VEC_DUCK_HULL_MIN_SCALED( this );
- }
- else
- {
- return VEC_HULL_MIN_SCALED( this );
- }
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input :
-// Output : const Vector
-//-----------------------------------------------------------------------------
-const Vector CBasePlayer::GetPlayerMaxs( void ) const
-{
- if ( IsObserver() )
- {
- return VEC_OBS_HULL_MAX_SCALED( this );
- }
- else
- {
- if ( GetFlags() & FL_DUCKING )
- {
- return VEC_DUCK_HULL_MAX_SCALED( this );
- }
- else
- {
- return VEC_HULL_MAX_SCALED( this );
- }
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Update the vehicle view, or simply return the cached position and angles
-//-----------------------------------------------------------------------------
-void CBasePlayer::CacheVehicleView( void )
-{
- // If we've calculated the view this frame, then there's no need to recalculate it
- if ( m_nVehicleViewSavedFrame == gpGlobals->framecount )
- return;
-
-#ifdef CLIENT_DLL
- IClientVehicle *pVehicle = GetVehicle();
-#else
- IServerVehicle *pVehicle = GetVehicle();
-#endif
-
- if ( pVehicle != NULL )
- {
- int nRole = pVehicle->GetPassengerRole( this );
-
- // Get our view for this frame
- pVehicle->GetVehicleViewPosition( nRole, &m_vecVehicleViewOrigin, &m_vecVehicleViewAngles, &m_flVehicleViewFOV );
- m_nVehicleViewSavedFrame = gpGlobals->framecount;
-
-#ifdef CLIENT_DLL
- if( UseVR() )
- {
- C_BaseAnimating *pVehicleAnimating = dynamic_cast<C_BaseAnimating *>( pVehicle );
- if( pVehicleAnimating )
- {
- int eyeAttachmentIndex = pVehicleAnimating->LookupAttachment( "vehicle_driver_eyes" );
-
- Vector vehicleEyeOrigin;
- QAngle vehicleEyeAngles;
- pVehicleAnimating->GetAttachment( eyeAttachmentIndex, vehicleEyeOrigin, vehicleEyeAngles );
-
- g_ClientVirtualReality.OverrideTorsoTransform( vehicleEyeOrigin, vehicleEyeAngles );
- }
- }
-#endif
- }
-}
-
-//-----------------------------------------------------------------------------
-// Returns eye vectors
-//-----------------------------------------------------------------------------
-void CBasePlayer::EyeVectors( Vector *pForward, Vector *pRight, Vector *pUp )
-{
- if ( GetVehicle() != NULL )
- {
- // Cache or retrieve our calculated position in the vehicle
- CacheVehicleView();
- AngleVectors( m_vecVehicleViewAngles, pForward, pRight, pUp );
- }
- else
- {
- AngleVectors( EyeAngles(), pForward, pRight, pUp );
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Returns the eye position and angle vectors.
-//-----------------------------------------------------------------------------
-void CBasePlayer::EyePositionAndVectors( Vector *pPosition, Vector *pForward,
- Vector *pRight, Vector *pUp )
-{
- // Handle the view in the vehicle
- if ( GetVehicle() != NULL )
- {
- CacheVehicleView();
- AngleVectors( m_vecVehicleViewAngles, pForward, pRight, pUp );
-
- if ( pPosition != NULL )
- {
- *pPosition = m_vecVehicleViewOrigin;
- }
- }
- else
- {
- VectorCopy( BaseClass::EyePosition(), *pPosition );
- AngleVectors( EyeAngles(), pForward, pRight, pUp );
- }
-}
-
-#ifdef CLIENT_DLL
-surfacedata_t * CBasePlayer::GetFootstepSurface( const Vector &origin, const char *surfaceName )
-{
- return physprops->GetSurfaceData( physprops->GetSurfaceIndex( surfaceName ) );
-}
-#endif
-
-surfacedata_t *CBasePlayer::GetLadderSurface( const Vector &origin )
-{
-#ifdef CLIENT_DLL
- return GetFootstepSurface( origin, "ladder" );
-#else
- return physprops->GetSurfaceData( physprops->GetSurfaceIndex( "ladder" ) );
-#endif
-}
-
-void CBasePlayer::UpdateStepSound( surfacedata_t *psurface, const Vector &vecOrigin, const Vector &vecVelocity )
-{
- bool bWalking;
- float fvol;
- Vector knee;
- Vector feet;
- float height;
- float speed;
- float velrun;
- float velwalk;
- int fLadder;
-
- if ( m_flStepSoundTime > 0 )
- {
- m_flStepSoundTime -= 1000.0f * gpGlobals->frametime;
- if ( m_flStepSoundTime < 0 )
- {
- m_flStepSoundTime = 0;
- }
- }
-
- if ( m_flStepSoundTime > 0 )
- return;
-
- if ( GetFlags() & (FL_FROZEN|FL_ATCONTROLS))
- return;
-
- if ( GetMoveType() == MOVETYPE_NOCLIP || GetMoveType() == MOVETYPE_OBSERVER )
- return;
-
- if ( !sv_footsteps.GetFloat() )
- return;
-
- speed = VectorLength( vecVelocity );
- float groundspeed = Vector2DLength( vecVelocity.AsVector2D() );
-
- // determine if we are on a ladder
- fLadder = ( GetMoveType() == MOVETYPE_LADDER );
-
- GetStepSoundVelocities( &velwalk, &velrun );
-
- bool onground = ( GetFlags() & FL_ONGROUND );
- bool movingalongground = ( groundspeed > 0.0001f );
- bool moving_fast_enough = ( speed >= velwalk );
-
-#ifdef PORTAL
- // In Portal we MUST play footstep sounds even when the player is moving very slowly
- // This is used to count the number of footsteps they take in the challenge mode
- // -Jeep
- moving_fast_enough = true;
-#endif
-
- // To hear step sounds you must be either on a ladder or moving along the ground AND
- // You must be moving fast enough
-
- if ( !moving_fast_enough || !(fLadder || ( onground && movingalongground )) )
- return;
-
-// MoveHelper()->PlayerSetAnimation( PLAYER_WALK );
-
- bWalking = speed < velrun;
-
- VectorCopy( vecOrigin, knee );
- VectorCopy( vecOrigin, feet );
-
- height = GetPlayerMaxs()[ 2 ] - GetPlayerMins()[ 2 ];
-
- knee[2] = vecOrigin[2] + 0.2 * height;
-
- // find out what we're stepping in or on...
- if ( fLadder )
- {
- psurface = GetLadderSurface(vecOrigin);
- fvol = 0.5;
-
- SetStepSoundTime( STEPSOUNDTIME_ON_LADDER, bWalking );
- }
-#ifdef CSTRIKE_DLL
- else if ( enginetrace->GetPointContents( knee ) & MASK_WATER ) // we want to use the knee for Cstrike, not the waist
-#else
- else if ( GetWaterLevel() == WL_Waist )
-#endif // CSTRIKE_DLL
- {
- static int iSkipStep = 0;
-
- if ( iSkipStep == 0 )
- {
- iSkipStep++;
- return;
- }
-
- if ( iSkipStep++ == 3 )
- {
- iSkipStep = 0;
- }
- psurface = physprops->GetSurfaceData( physprops->GetSurfaceIndex( "wade" ) );
- fvol = 0.65;
- SetStepSoundTime( STEPSOUNDTIME_WATER_KNEE, bWalking );
- }
- else if ( GetWaterLevel() == WL_Feet )
- {
- psurface = physprops->GetSurfaceData( physprops->GetSurfaceIndex( "water" ) );
- fvol = bWalking ? 0.2 : 0.5;
-
- SetStepSoundTime( STEPSOUNDTIME_WATER_FOOT, bWalking );
- }
- else
- {
- if ( !psurface )
- return;
-
- SetStepSoundTime( STEPSOUNDTIME_NORMAL, bWalking );
-
- switch ( psurface->game.material )
- {
- default:
- case CHAR_TEX_CONCRETE:
- fvol = bWalking ? 0.2 : 0.5;
- break;
-
- case CHAR_TEX_METAL:
- fvol = bWalking ? 0.2 : 0.5;
- break;
-
- case CHAR_TEX_DIRT:
- fvol = bWalking ? 0.25 : 0.55;
- break;
-
- case CHAR_TEX_VENT:
- fvol = bWalking ? 0.4 : 0.7;
- break;
-
- case CHAR_TEX_GRATE:
- fvol = bWalking ? 0.2 : 0.5;
- break;
-
- case CHAR_TEX_TILE:
- fvol = bWalking ? 0.2 : 0.5;
- break;
-
- case CHAR_TEX_SLOSH:
- fvol = bWalking ? 0.2 : 0.5;
- break;
- }
- }
-
- // play the sound
- // 65% volume if ducking
- if ( GetFlags() & FL_DUCKING )
- {
- fvol *= 0.65;
- }
-
- PlayStepSound( feet, psurface, fvol, false );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : step -
-// fvol -
-// force - force sound to play
-//-----------------------------------------------------------------------------
-void CBasePlayer::PlayStepSound( Vector &vecOrigin, surfacedata_t *psurface, float fvol, bool force )
-{
- if ( gpGlobals->maxClients > 1 && !sv_footsteps.GetFloat() )
- return;
-
-#if defined( CLIENT_DLL )
- // during prediction play footstep sounds only once
- if ( prediction->InPrediction() && !prediction->IsFirstTimePredicted() )
- return;
-#endif
-
- if ( !psurface )
- return;
-
- int nSide = m_Local.m_nStepside;
- unsigned short stepSoundName = nSide ? psurface->sounds.stepleft : psurface->sounds.stepright;
- if ( !stepSoundName )
- return;
-
- m_Local.m_nStepside = !nSide;
-
- CSoundParameters params;
-
- Assert( nSide == 0 || nSide == 1 );
-
- if ( m_StepSoundCache[ nSide ].m_usSoundNameIndex == stepSoundName )
- {
- params = m_StepSoundCache[ nSide ].m_SoundParameters;
- }
- else
- {
- IPhysicsSurfaceProps *physprops = MoveHelper()->GetSurfaceProps();
- const char *pSoundName = physprops->GetString( stepSoundName );
-
- // Give child classes an opportunity to override.
- pSoundName = GetOverrideStepSound( pSoundName );
-
- if ( !CBaseEntity::GetParametersForSound( pSoundName, params, NULL ) )
- return;
-
- // Only cache if there's one option. Otherwise we'd never here any other sounds
- if ( params.count == 1 )
- {
- m_StepSoundCache[ nSide ].m_usSoundNameIndex = stepSoundName;
- m_StepSoundCache[ nSide ].m_SoundParameters = params;
- }
- }
-
- CRecipientFilter filter;
- filter.AddRecipientsByPAS( vecOrigin );
-
-#ifndef CLIENT_DLL
- // in MP, server removes all players in the vecOrigin's PVS, these players generate the footsteps client side
- if ( gpGlobals->maxClients > 1 )
- {
- filter.RemoveRecipientsByPVS( vecOrigin );
- }
-#endif
-
- EmitSound_t ep;
- ep.m_nChannel = CHAN_BODY;
- ep.m_pSoundName = params.soundname;
-#if defined ( TF_DLL ) || defined ( TF_CLIENT_DLL )
- if( TFGameRules()->IsMannVsMachineMode() )
- {
- ep.m_flVolume = params.volume;
- }
- else
- {
- ep.m_flVolume = fvol;
- }
-#else
- ep.m_flVolume = fvol;
-#endif
- ep.m_SoundLevel = params.soundlevel;
- ep.m_nFlags = 0;
- ep.m_nPitch = params.pitch;
- ep.m_pOrigin = &vecOrigin;
-
- EmitSound( filter, entindex(), ep );
-
- // Kyle says: ugggh. This function may as well be called "PerformPileOfDesperateGameSpecificFootstepHacks".
- OnEmitFootstepSound( params, vecOrigin, fvol );
-}
-
-void CBasePlayer::UpdateButtonState( int nUserCmdButtonMask )
-{
- // Track button info so we can detect 'pressed' and 'released' buttons next frame
- m_afButtonLast = m_nButtons;
-
- // Get button states
- m_nButtons = nUserCmdButtonMask;
- int buttonsChanged = m_afButtonLast ^ m_nButtons;
-
- // Debounced button codes for pressed/released
- // UNDONE: Do we need auto-repeat?
- m_afButtonPressed = buttonsChanged & m_nButtons; // The changed ones still down are "pressed"
- m_afButtonReleased = buttonsChanged & (~m_nButtons); // The ones not down are "released"
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void CBasePlayer::GetStepSoundVelocities( float *velwalk, float *velrun )
-{
- // UNDONE: need defined numbers for run, walk, crouch, crouch run velocities!!!!
- if ( ( GetFlags() & FL_DUCKING) || ( GetMoveType() == MOVETYPE_LADDER ) )
- {
- *velwalk = 60; // These constants should be based on cl_movespeedkey * cl_forwardspeed somehow
- *velrun = 80;
- }
- else
- {
- *velwalk = 90;
- *velrun = 220;
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void CBasePlayer::SetStepSoundTime( stepsoundtimes_t iStepSoundTime, bool bWalking )
-{
- switch ( iStepSoundTime )
- {
- case STEPSOUNDTIME_NORMAL:
- case STEPSOUNDTIME_WATER_FOOT:
- m_flStepSoundTime = bWalking ? 400 : 300;
- break;
-
- case STEPSOUNDTIME_ON_LADDER:
- m_flStepSoundTime = 350;
- break;
-
- case STEPSOUNDTIME_WATER_KNEE:
- m_flStepSoundTime = 600;
- break;
-
- default:
- Assert(0);
- break;
- }
-
- // UNDONE: need defined numbers for run, walk, crouch, crouch run velocities!!!!
- if ( ( GetFlags() & FL_DUCKING) || ( GetMoveType() == MOVETYPE_LADDER ) )
- {
- m_flStepSoundTime += 100;
- }
-}
-
-Vector CBasePlayer::Weapon_ShootPosition( )
-{
- return EyePosition();
-}
-
-void CBasePlayer::SetAnimationExtension( const char *pExtension )
-{
- Q_strncpy( m_szAnimExtension, pExtension, sizeof(m_szAnimExtension) );
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Set the weapon to switch to when the player uses the 'lastinv' command
-//-----------------------------------------------------------------------------
-void CBasePlayer::Weapon_SetLast( CBaseCombatWeapon *pWeapon )
-{
- m_hLastWeapon = pWeapon;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Override base class so player can reset autoaim
-// Input :
-// Output :
-//-----------------------------------------------------------------------------
-bool CBasePlayer::Weapon_Switch( CBaseCombatWeapon *pWeapon, int viewmodelindex /*=0*/ )
-{
- CBaseCombatWeapon *pLastWeapon = GetActiveWeapon();
-
- if ( BaseClass::Weapon_Switch( pWeapon, viewmodelindex ))
- {
- if ( pLastWeapon && Weapon_ShouldSetLast( pLastWeapon, GetActiveWeapon() ) )
- {
- Weapon_SetLast( pLastWeapon->GetLastWeapon() );
- }
-
- CBaseViewModel *pViewModel = GetViewModel( viewmodelindex );
- Assert( pViewModel );
- if ( pViewModel )
- pViewModel->RemoveEffects( EF_NODRAW );
- ResetAutoaim( );
- return true;
- }
- return false;
-}
-
-void CBasePlayer::SelectLastItem(void)
-{
- if ( m_hLastWeapon.Get() == NULL )
- return;
-
- if ( GetActiveWeapon() && !GetActiveWeapon()->CanHolster() )
- return;
-
- SelectItem( m_hLastWeapon.Get()->GetClassname(), m_hLastWeapon.Get()->GetSubType() );
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Abort any reloads we're in
-//-----------------------------------------------------------------------------
-void CBasePlayer::AbortReload( void )
-{
- if ( GetActiveWeapon() )
- {
- GetActiveWeapon()->AbortReload();
- }
-}
-
-#if !defined( NO_ENTITY_PREDICTION )
-void CBasePlayer::AddToPlayerSimulationList( CBaseEntity *other )
-{
- CHandle< CBaseEntity > h;
- h = other;
- // Already in list
- if ( m_SimulatedByThisPlayer.Find( h ) != m_SimulatedByThisPlayer.InvalidIndex() )
- return;
-
- Assert( other->IsPlayerSimulated() );
-
- m_SimulatedByThisPlayer.AddToTail( h );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Fixme, this should occur if the player fails to drive simulation
-// often enough!!!
-// Input : *other -
-//-----------------------------------------------------------------------------
-void CBasePlayer::RemoveFromPlayerSimulationList( CBaseEntity *other )
-{
- if ( !other )
- return;
-
- Assert( other->IsPlayerSimulated() );
- Assert( other->GetSimulatingPlayer() == this );
-
-
- CHandle< CBaseEntity > h;
- h = other;
-
- m_SimulatedByThisPlayer.FindAndRemove( h );
-}
-
-void CBasePlayer::SimulatePlayerSimulatedEntities( void )
-{
- int c = m_SimulatedByThisPlayer.Count();
- int i;
-
- for ( i = c - 1; i >= 0; i-- )
- {
- CHandle< CBaseEntity > h;
-
- h = m_SimulatedByThisPlayer[ i ];
- CBaseEntity *e = h;
-
- if ( !e || !e->IsPlayerSimulated() )
- {
- m_SimulatedByThisPlayer.Remove( i );
- continue;
- }
-
-#if defined( CLIENT_DLL )
- if ( e->IsClientCreated() && prediction->InPrediction() && !prediction->IsFirstTimePredicted() )
- {
- continue;
- }
-#endif
- Assert( e->IsPlayerSimulated() );
- Assert( e->GetSimulatingPlayer() == this );
-
- e->PhysicsSimulate();
- }
-
- // Loop through all entities again, checking their untouch if flagged to do so
- c = m_SimulatedByThisPlayer.Count();
-
- for ( i = c - 1; i >= 0; i-- )
- {
- CHandle< CBaseEntity > h;
-
- h = m_SimulatedByThisPlayer[ i ];
-
- CBaseEntity *e = h;
- if ( !e || !e->IsPlayerSimulated() )
- {
- m_SimulatedByThisPlayer.Remove( i );
- continue;
- }
-
-#if defined( CLIENT_DLL )
- if ( e->IsClientCreated() && prediction->InPrediction() && !prediction->IsFirstTimePredicted() )
- {
- continue;
- }
-#endif
-
- Assert( e->IsPlayerSimulated() );
- Assert( e->GetSimulatingPlayer() == this );
-
- if ( !e->GetCheckUntouch() )
- continue;
-
- e->PhysicsCheckForEntityUntouch();
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void CBasePlayer::ClearPlayerSimulationList( void )
-{
- int c = m_SimulatedByThisPlayer.Size();
- int i;
-
- for ( i = c - 1; i >= 0; i-- )
- {
- CHandle< CBaseEntity > h;
-
- h = m_SimulatedByThisPlayer[ i ];
- CBaseEntity *e = h;
- if ( e )
- {
- e->UnsetPlayerSimulated();
- }
- }
-
- m_SimulatedByThisPlayer.RemoveAll();
-}
-#endif
-
-//-----------------------------------------------------------------------------
-// Purpose: Return true if we should allow selection of the specified item
-//-----------------------------------------------------------------------------
-bool CBasePlayer::Weapon_ShouldSelectItem( CBaseCombatWeapon *pWeapon )
-{
- return ( pWeapon != GetActiveWeapon() );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void CBasePlayer::SelectItem( const char *pstr, int iSubType )
-{
- if (!pstr)
- return;
-
- CBaseCombatWeapon *pItem = Weapon_OwnsThisType( pstr, iSubType );
-
- if (!pItem)
- return;
-
- if( GetObserverMode() != OBS_MODE_NONE )
- return;// Observers can't select things.
-
- if ( !Weapon_ShouldSelectItem( pItem ) )
- return;
-
- // FIX, this needs to queue them up and delay
- // Make sure the current weapon can be holstered
- if ( GetActiveWeapon() )
- {
- if ( !GetActiveWeapon()->CanHolster() )
- return;
-
- ResetAutoaim( );
- }
-
- Weapon_Switch( pItem );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-ConVar sv_debug_player_use( "sv_debug_player_use", "0", FCVAR_REPLICATED, "Visualizes +use logic. Green cross=trace success, Red cross=trace too far, Green box=radius success" );
-float IntervalDistance( float x, float x0, float x1 )
-{
- // swap so x0 < x1
- if ( x0 > x1 )
- {
- float tmp = x0;
- x0 = x1;
- x1 = tmp;
- }
-
- if ( x < x0 )
- return x0-x;
- else if ( x > x1 )
- return x - x1;
- return 0;
-}
-
-CBaseEntity *CBasePlayer::FindUseEntity()
-{
- Vector forward, up;
- EyeVectors( &forward, NULL, &up );
-
- trace_t tr;
- // Search for objects in a sphere (tests for entities that are not solid, yet still useable)
- Vector searchCenter = EyePosition();
-
- // NOTE: Some debris objects are useable too, so hit those as well
- // A button, etc. can be made out of clip brushes, make sure it's +useable via a traceline, too.
- int useableContents = MASK_SOLID | CONTENTS_DEBRIS | CONTENTS_PLAYERCLIP;
-
-#ifdef CSTRIKE_DLL
- useableContents = MASK_NPCSOLID_BRUSHONLY | MASK_OPAQUE_AND_NPCS;
-#endif
-
-#ifdef HL1_DLL
- useableContents = MASK_SOLID;
-#endif
-#ifndef CLIENT_DLL
- CBaseEntity *pFoundByTrace = NULL;
-#endif
-
- // UNDONE: Might be faster to just fold this range into the sphere query
- CBaseEntity *pObject = NULL;
-
- float nearestDist = FLT_MAX;
- // try the hit entity if there is one, or the ground entity if there isn't.
- CBaseEntity *pNearest = NULL;
-
- const int NUM_TANGENTS = 8;
- // trace a box at successive angles down
- // forward, 45 deg, 30 deg, 20 deg, 15 deg, 10 deg, -10, -15
- const float tangents[NUM_TANGENTS] = { 0, 1, 0.57735026919f, 0.3639702342f, 0.267949192431f, 0.1763269807f, -0.1763269807f, -0.267949192431f };
- for ( int i = 0; i < NUM_TANGENTS; i++ )
- {
- if ( i == 0 )
- {
- UTIL_TraceLine( searchCenter, searchCenter + forward * 1024, useableContents, this, COLLISION_GROUP_NONE, &tr );
- }
- else
- {
- Vector down = forward - tangents[i]*up;
- VectorNormalize(down);
- UTIL_TraceHull( searchCenter, searchCenter + down * 72, -Vector(16,16,16), Vector(16,16,16), useableContents, this, COLLISION_GROUP_NONE, &tr );
- }
- pObject = tr.m_pEnt;
-
-#ifndef CLIENT_DLL
- pFoundByTrace = pObject;
-#endif
- bool bUsable = IsUseableEntity(pObject, 0);
- while ( pObject && !bUsable && pObject->GetMoveParent() )
- {
- pObject = pObject->GetMoveParent();
- bUsable = IsUseableEntity(pObject, 0);
- }
-
- if ( bUsable )
- {
- Vector delta = tr.endpos - tr.startpos;
- float centerZ = CollisionProp()->WorldSpaceCenter().z;
- delta.z = IntervalDistance( tr.endpos.z, centerZ + CollisionProp()->OBBMins().z, centerZ + CollisionProp()->OBBMaxs().z );
- float dist = delta.Length();
- if ( dist < PLAYER_USE_RADIUS )
- {
-#ifndef CLIENT_DLL
-
- if ( sv_debug_player_use.GetBool() )
- {
- NDebugOverlay::Line( searchCenter, tr.endpos, 0, 255, 0, true, 30 );
- NDebugOverlay::Cross3D( tr.endpos, 16, 0, 255, 0, true, 30 );
- }
-
- if ( pObject->MyNPCPointer() && pObject->MyNPCPointer()->IsPlayerAlly( this ) )
- {
- // If about to select an NPC, do a more thorough check to ensure
- // that we're selecting the right one from a group.
- pObject = DoubleCheckUseNPC( pObject, searchCenter, forward );
- }
-#endif
- if ( sv_debug_player_use.GetBool() )
- {
- Msg( "Trace using: %s\n", pObject ? pObject->GetDebugName() : "no usable entity found" );
- }
-
- pNearest = pObject;
-
- // if this is directly under the cursor just return it now
- if ( i == 0 )
- return pObject;
- }
- }
- }
-
- // check ground entity first
- // if you've got a useable ground entity, then shrink the cone of this search to 45 degrees
- // otherwise, search out in a 90 degree cone (hemisphere)
- if ( GetGroundEntity() && IsUseableEntity(GetGroundEntity(), FCAP_USE_ONGROUND) )
- {
- pNearest = GetGroundEntity();
- }
- if ( pNearest )
- {
- // estimate nearest object by distance from the view vector
- Vector point;
- pNearest->CollisionProp()->CalcNearestPoint( searchCenter, &point );
- nearestDist = CalcDistanceToLine( point, searchCenter, forward );
- if ( sv_debug_player_use.GetBool() )
- {
- Msg("Trace found %s, dist %.2f\n", pNearest->GetClassname(), nearestDist );
- }
- }
-
- for ( CEntitySphereQuery sphere( searchCenter, PLAYER_USE_RADIUS ); ( pObject = sphere.GetCurrentEntity() ) != NULL; sphere.NextEntity() )
- {
- if ( !pObject )
- continue;
-
- if ( !IsUseableEntity( pObject, FCAP_USE_IN_RADIUS ) )
- continue;
-
- // see if it's more roughly in front of the player than previous guess
- Vector point;
- pObject->CollisionProp()->CalcNearestPoint( searchCenter, &point );
-
- Vector dir = point - searchCenter;
- VectorNormalize(dir);
- float dot = DotProduct( dir, forward );
-
- // Need to be looking at the object more or less
- if ( dot < 0.8 )
- continue;
-
- float dist = CalcDistanceToLine( point, searchCenter, forward );
-
- if ( sv_debug_player_use.GetBool() )
- {
- Msg("Radius found %s, dist %.2f\n", pObject->GetClassname(), dist );
- }
-
- if ( dist < nearestDist )
- {
- // Since this has purely been a radius search to this point, we now
- // make sure the object isn't behind glass or a grate.
- trace_t trCheckOccluded;
- UTIL_TraceLine( searchCenter, point, useableContents, this, COLLISION_GROUP_NONE, &trCheckOccluded );
-
- if ( trCheckOccluded.fraction == 1.0 || trCheckOccluded.m_pEnt == pObject )
- {
- pNearest = pObject;
- nearestDist = dist;
- }
- }
- }
-
-#ifndef CLIENT_DLL
- if ( !pNearest )
- {
- // Haven't found anything near the player to use, nor any NPC's at distance.
- // Check to see if the player is trying to select an NPC through a rail, fence, or other 'see-though' volume.
- trace_t trAllies;
- UTIL_TraceLine( searchCenter, searchCenter + forward * PLAYER_USE_RADIUS, MASK_OPAQUE_AND_NPCS, this, COLLISION_GROUP_NONE, &trAllies );
-
- if ( trAllies.m_pEnt && IsUseableEntity( trAllies.m_pEnt, 0 ) && trAllies.m_pEnt->MyNPCPointer() && trAllies.m_pEnt->MyNPCPointer()->IsPlayerAlly( this ) )
- {
- // This is an NPC, take it!
- pNearest = trAllies.m_pEnt;
- }
- }
-
- if ( pNearest && pNearest->MyNPCPointer() && pNearest->MyNPCPointer()->IsPlayerAlly( this ) )
- {
- pNearest = DoubleCheckUseNPC( pNearest, searchCenter, forward );
- }
-
- if ( sv_debug_player_use.GetBool() )
- {
- if ( !pNearest )
- {
- NDebugOverlay::Line( searchCenter, tr.endpos, 255, 0, 0, true, 30 );
- NDebugOverlay::Cross3D( tr.endpos, 16, 255, 0, 0, true, 30 );
- }
- else if ( pNearest == pFoundByTrace )
- {
- NDebugOverlay::Line( searchCenter, tr.endpos, 0, 255, 0, true, 30 );
- NDebugOverlay::Cross3D( tr.endpos, 16, 0, 255, 0, true, 30 );
- }
- else
- {
- NDebugOverlay::Box( pNearest->WorldSpaceCenter(), Vector(-8, -8, -8), Vector(8, 8, 8), 0, 255, 0, true, 30 );
- }
- }
-#endif
-
- if ( sv_debug_player_use.GetBool() )
- {
- Msg( "Radial using: %s\n", pNearest ? pNearest->GetDebugName() : "no usable entity found" );
- }
-
- return pNearest;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Handles USE keypress
-//-----------------------------------------------------------------------------
-void CBasePlayer::PlayerUse ( void )
-{
-#ifdef GAME_DLL
- // Was use pressed or released?
- if ( ! ((m_nButtons | m_afButtonPressed | m_afButtonReleased) & IN_USE) )
- return;
-
- if ( IsObserver() )
- {
- // do special use operation in oberserver mode
- if ( m_afButtonPressed & IN_USE )
- ObserverUse( true );
- else if ( m_afButtonReleased & IN_USE )
- ObserverUse( false );
-
- return;
- }
-
-#if !defined(_XBOX)
- // push objects in turbo physics mode
- if ( (m_nButtons & IN_USE) && sv_turbophysics.GetBool() )
- {
- Vector forward, up;
- EyeVectors( &forward, NULL, &up );
-
- trace_t tr;
- // Search for objects in a sphere (tests for entities that are not solid, yet still useable)
- Vector searchCenter = EyePosition();
-
- CUsePushFilter filter;
-
- UTIL_TraceLine( searchCenter, searchCenter + forward * 96.0f, MASK_SOLID, &filter, &tr );
-
- // try the hit entity if there is one, or the ground entity if there isn't.
- CBaseEntity *entity = tr.m_pEnt;
-
- if ( entity )
- {
- IPhysicsObject *pObj = entity->VPhysicsGetObject();
-
- if ( pObj )
- {
- Vector vPushAway = (entity->WorldSpaceCenter() - WorldSpaceCenter());
- vPushAway.z = 0;
-
- float flDist = VectorNormalize( vPushAway );
- flDist = MAX( flDist, 1 );
-
- float flForce = sv_pushaway_force.GetFloat() / flDist;
- flForce = MIN( flForce, sv_pushaway_max_force.GetFloat() );
-
- pObj->ApplyForceOffset( vPushAway * flForce, WorldSpaceCenter() );
- }
- }
- }
-#endif
-
- if ( m_afButtonPressed & IN_USE )
- {
- // Controlling some latched entity?
- if ( ClearUseEntity() )
- {
- return;
- }
- else
- {
- if ( m_afPhysicsFlags & PFLAG_DIROVERRIDE )
- {
- m_afPhysicsFlags &= ~PFLAG_DIROVERRIDE;
- m_iTrain = TRAIN_NEW|TRAIN_OFF;
- return;
- }
- else
- { // Start controlling the train!
- CBaseEntity *pTrain = GetGroundEntity();
- if ( pTrain && !(m_nButtons & IN_JUMP) && (GetFlags() & FL_ONGROUND) && (pTrain->ObjectCaps() & FCAP_DIRECTIONAL_USE) && pTrain->OnControls(this) )
- {
- m_afPhysicsFlags |= PFLAG_DIROVERRIDE;
- m_iTrain = TrainSpeed(pTrain->m_flSpeed, ((CFuncTrackTrain*)pTrain)->GetMaxSpeed());
- m_iTrain |= TRAIN_NEW;
- EmitSound( "Player.UseTrain" );
- return;
- }
- }
- }
- }
-
- CBaseEntity *pUseEntity = FindUseEntity();
-
- // Found an object
- if ( pUseEntity )
- {
-
- //!!!UNDONE: traceline here to prevent +USEing buttons through walls
-
- int caps = pUseEntity->ObjectCaps();
- variant_t emptyVariant;
- if ( ( (m_nButtons & IN_USE) && (caps & FCAP_CONTINUOUS_USE) ) || ( (m_afButtonPressed & IN_USE) && (caps & (FCAP_IMPULSE_USE|FCAP_ONOFF_USE)) ) )
- {
- if ( caps & FCAP_CONTINUOUS_USE )
- {
- m_afPhysicsFlags |= PFLAG_USING;
- }
-
- if ( pUseEntity->ObjectCaps() & FCAP_ONOFF_USE )
- {
- pUseEntity->AcceptInput( "Use", this, this, emptyVariant, USE_ON );
- }
- else
- {
- pUseEntity->AcceptInput( "Use", this, this, emptyVariant, USE_TOGGLE );
- }
- }
- // UNDONE: Send different USE codes for ON/OFF. Cache last ONOFF_USE object to send 'off' if you turn away
- else if ( (m_afButtonReleased & IN_USE) && (pUseEntity->ObjectCaps() & FCAP_ONOFF_USE) ) // BUGBUG This is an "off" use
- {
- pUseEntity->AcceptInput( "Use", this, this, emptyVariant, USE_OFF );
- }
- }
- else if ( m_afButtonPressed & IN_USE )
- {
- PlayUseDenySound();
- }
-#endif
-}
-
-ConVar sv_suppress_viewpunch( "sv_suppress_viewpunch", "0", FCVAR_REPLICATED | FCVAR_CHEAT | FCVAR_DEVELOPMENTONLY );
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void CBasePlayer::ViewPunch( const QAngle &angleOffset )
-{
- //See if we're suppressing the view punching
- if ( sv_suppress_viewpunch.GetBool() )
- return;
-
- // We don't allow view kicks in the vehicle
- if ( IsInAVehicle() )
- return;
-
- m_Local.m_vecPunchAngleVel += angleOffset * 20;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void CBasePlayer::ViewPunchReset( float tolerance )
-{
- if ( tolerance != 0 )
- {
- tolerance *= tolerance; // square
- float check = m_Local.m_vecPunchAngleVel->LengthSqr() + m_Local.m_vecPunchAngle->LengthSqr();
- if ( check > tolerance )
- return;
- }
- m_Local.m_vecPunchAngle = vec3_angle;
- m_Local.m_vecPunchAngleVel = vec3_angle;
-}
-
-#if defined( CLIENT_DLL )
-
-#include "iviewrender.h"
-#include "ivieweffects.h"
-
-#endif
-
-static ConVar smoothstairs( "smoothstairs", "1", FCVAR_REPLICATED, "Smooth player eye z coordinate when traversing stairs." );
-
-//-----------------------------------------------------------------------------
-// Handle view smoothing when going up or down stairs
-//-----------------------------------------------------------------------------
-void CBasePlayer::SmoothViewOnStairs( Vector& eyeOrigin )
-{
- CBaseEntity *pGroundEntity = GetGroundEntity();
- float flCurrentPlayerZ = GetLocalOrigin().z;
- float flCurrentPlayerViewOffsetZ = GetViewOffset().z;
-
- // Smooth out stair step ups
- // NOTE: Don't want to do this when the ground entity is moving the player
- if ( ( pGroundEntity != NULL && pGroundEntity->GetMoveType() == MOVETYPE_NONE ) && ( flCurrentPlayerZ != m_flOldPlayerZ ) && smoothstairs.GetBool() &&
- m_flOldPlayerViewOffsetZ == flCurrentPlayerViewOffsetZ )
- {
- int dir = ( flCurrentPlayerZ > m_flOldPlayerZ ) ? 1 : -1;
-
- float steptime = gpGlobals->frametime;
- if (steptime < 0)
- {
- steptime = 0;
- }
-
- m_flOldPlayerZ += steptime * 150 * dir;
-
- const float stepSize = 18.0f;
-
- if ( dir > 0 )
- {
- if (m_flOldPlayerZ > flCurrentPlayerZ)
- {
- m_flOldPlayerZ = flCurrentPlayerZ;
- }
- if (flCurrentPlayerZ - m_flOldPlayerZ > stepSize)
- {
- m_flOldPlayerZ = flCurrentPlayerZ - stepSize;
- }
- }
- else
- {
- if (m_flOldPlayerZ < flCurrentPlayerZ)
- {
- m_flOldPlayerZ = flCurrentPlayerZ;
- }
- if (flCurrentPlayerZ - m_flOldPlayerZ < -stepSize)
- {
- m_flOldPlayerZ = flCurrentPlayerZ + stepSize;
- }
- }
-
- eyeOrigin[2] += m_flOldPlayerZ - flCurrentPlayerZ;
- }
- else
- {
- m_flOldPlayerZ = flCurrentPlayerZ;
- m_flOldPlayerViewOffsetZ = flCurrentPlayerViewOffsetZ;
- }
-}
-
-static bool IsWaterContents( int contents )
-{
- if ( contents & MASK_WATER )
- return true;
-
-// if ( contents & CONTENTS_TESTFOGVOLUME )
-// return true;
-
- return false;
-}
-
-void CBasePlayer::ResetObserverMode()
-{
-
- m_hObserverTarget.Set( 0 );
- m_iObserverMode = (int)OBS_MODE_NONE;
-
-#ifndef CLIENT_DLL
- m_iObserverLastMode = OBS_MODE_ROAMING;
- m_bForcedObserverMode = false;
- m_afPhysicsFlags &= ~PFLAG_OBSERVER;
-#endif
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : eyeOrigin -
-// eyeAngles -
-// zNear -
-// zFar -
-// fov -
-//-----------------------------------------------------------------------------
-void CBasePlayer::CalcView( Vector &eyeOrigin, QAngle &eyeAngles, float &zNear, float &zFar, float &fov )
-{
-#if defined( CLIENT_DLL )
- IClientVehicle *pVehicle;
-#else
- IServerVehicle *pVehicle;
-#endif
- pVehicle = GetVehicle();
-
- if ( !pVehicle )
- {
-#if defined( CLIENT_DLL )
- if( UseVR() )
- g_ClientVirtualReality.CancelTorsoTransformOverride();
-#endif
-
- if ( IsObserver() )
- {
- CalcObserverView( eyeOrigin, eyeAngles, fov );
- }
- else
- {
- CalcPlayerView( eyeOrigin, eyeAngles, fov );
- }
- }
- else
- {
- CalcVehicleView( pVehicle, eyeOrigin, eyeAngles, zNear, zFar, fov );
- }
- // NVNT update fov on the haptics dll for input scaling.
-#if defined( CLIENT_DLL )
- if(IsLocalPlayer() && haptics)
- haptics->UpdatePlayerFOV(fov);
-#endif
-}
-
-
-void CBasePlayer::CalcViewModelView( const Vector& eyeOrigin, const QAngle& eyeAngles)
-{
- for ( int i = 0; i < MAX_VIEWMODELS; i++ )
- {
- CBaseViewModel *vm = GetViewModel( i );
- if ( !vm )
- continue;
-
- vm->CalcViewModelView( this, eyeOrigin, eyeAngles );
- }
-}
-
-void CBasePlayer::CalcPlayerView( Vector& eyeOrigin, QAngle& eyeAngles, float& fov )
-{
-#if defined( CLIENT_DLL )
- if ( !prediction->InPrediction() )
- {
- // FIXME: Move into prediction
- view->DriftPitch();
- }
-#endif
-
- VectorCopy( EyePosition(), eyeOrigin );
-#ifdef SIXENSE
- if ( g_pSixenseInput->IsEnabled() )
- {
- VectorCopy( EyeAngles() + GetEyeAngleOffset(), eyeAngles );
- }
- else
- {
- VectorCopy( EyeAngles(), eyeAngles );
- }
-#else
- VectorCopy( EyeAngles(), eyeAngles );
-#endif
-
-#if defined( CLIENT_DLL )
- if ( !prediction->InPrediction() )
-#endif
- {
- SmoothViewOnStairs( eyeOrigin );
- }
-
- // Snack off the origin before bob + water offset are applied
- Vector vecBaseEyePosition = eyeOrigin;
-
- CalcViewRoll( eyeAngles );
-
- // Apply punch angle
- VectorAdd( eyeAngles, m_Local.m_vecPunchAngle, eyeAngles );
-
-#if defined( CLIENT_DLL )
- if ( !prediction->InPrediction() )
- {
- // Shake it up baby!
- vieweffects->CalcShake();
- vieweffects->ApplyShake( eyeOrigin, eyeAngles, 1.0 );
- }
-#endif
-
-#if defined( CLIENT_DLL )
- // Apply a smoothing offset to smooth out prediction errors.
- Vector vSmoothOffset;
- GetPredictionErrorSmoothingVector( vSmoothOffset );
- eyeOrigin += vSmoothOffset;
- m_flObserverChaseDistance = 0.0;
-#endif
-
- // calc current FOV
- fov = GetFOV();
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: The main view setup function for vehicles
-//-----------------------------------------------------------------------------
-void CBasePlayer::CalcVehicleView(
-#if defined( CLIENT_DLL )
- IClientVehicle *pVehicle,
-#else
- IServerVehicle *pVehicle,
-#endif
- Vector& eyeOrigin, QAngle& eyeAngles,
- float& zNear, float& zFar, float& fov )
-{
- Assert( pVehicle );
-
- // Start with our base origin and angles
- CacheVehicleView();
- eyeOrigin = m_vecVehicleViewOrigin;
- eyeAngles = m_vecVehicleViewAngles;
-
-#if defined( CLIENT_DLL )
-
- fov = GetFOV();
-
- // Allows the vehicle to change the clip planes
- pVehicle->GetVehicleClipPlanes( zNear, zFar );
-#endif
-
- // Snack off the origin before bob + water offset are applied
- Vector vecBaseEyePosition = eyeOrigin;
-
- CalcViewRoll( eyeAngles );
-
- // Apply punch angle
- VectorAdd( eyeAngles, m_Local.m_vecPunchAngle, eyeAngles );
-
-#if defined( CLIENT_DLL )
- if ( !prediction->InPrediction() )
- {
- // Shake it up baby!
- vieweffects->CalcShake();
- vieweffects->ApplyShake( eyeOrigin, eyeAngles, 1.0 );
- }
-#endif
-
-}
-
-
-void CBasePlayer::CalcObserverView( Vector& eyeOrigin, QAngle& eyeAngles, float& fov )
-{
-#if defined( CLIENT_DLL )
- switch ( GetObserverMode() )
- {
-
- case OBS_MODE_DEATHCAM : CalcDeathCamView( eyeOrigin, eyeAngles, fov );
- break;
-
- case OBS_MODE_ROAMING : // just copy current position without view offset
- case OBS_MODE_FIXED : CalcRoamingView( eyeOrigin, eyeAngles, fov );
- break;
-
- case OBS_MODE_IN_EYE : CalcInEyeCamView( eyeOrigin, eyeAngles, fov );
- break;
-
- case OBS_MODE_CHASE : CalcChaseCamView( eyeOrigin, eyeAngles, fov );
- break;
-
- case OBS_MODE_FREEZECAM : CalcFreezeCamView( eyeOrigin, eyeAngles, fov );
- break;
- }
-#else
- // on server just copy target postions, final view positions will be calculated on client
- VectorCopy( EyePosition(), eyeOrigin );
- VectorCopy( EyeAngles(), eyeAngles );
-#endif
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Compute roll angle for a particular lateral velocity
-// Input : angles -
-// velocity -
-// rollangle -
-// rollspeed -
-// Output : float CViewRender::CalcRoll
-//-----------------------------------------------------------------------------
-float CBasePlayer::CalcRoll (const QAngle& angles, const Vector& velocity, float rollangle, float rollspeed)
-{
- float sign;
- float side;
- float value;
-
- Vector forward, right, up;
-
- AngleVectors (angles, &forward, &right, &up);
-
- // Get amount of lateral movement
- side = DotProduct( velocity, right );
- // Right or left side?
- sign = side < 0 ? -1 : 1;
- side = fabs(side);
-
- value = rollangle;
- // Hit 100% of rollangle at rollspeed. Below that get linear approx.
- if ( side < rollspeed )
- {
- side = side * value / rollspeed;
- }
- else
- {
- side = value;
- }
-
- // Scale by right/left sign
- return side*sign;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Determine view roll, including data kick
-//-----------------------------------------------------------------------------
-void CBasePlayer::CalcViewRoll( QAngle& eyeAngles )
-{
- if ( GetMoveType() == MOVETYPE_NOCLIP )
- return;
-
- float side = CalcRoll( GetAbsAngles(), GetAbsVelocity(), sv_rollangle.GetFloat(), sv_rollspeed.GetFloat() );
- eyeAngles[ROLL] += side;
-}
-
-
-void CBasePlayer::DoMuzzleFlash()
-{
- for ( int i = 0; i < MAX_VIEWMODELS; i++ )
- {
- CBaseViewModel *vm = GetViewModel( i );
- if ( !vm )
- continue;
-
- vm->DoMuzzleFlash();
- }
-
- BaseClass::DoMuzzleFlash();
-}
-
-
-float CBasePlayer::GetFOVDistanceAdjustFactor()
-{
- float defaultFOV = (float)GetDefaultFOV();
- float localFOV = (float)GetFOV();
-
- if ( localFOV == defaultFOV || defaultFOV < 0.001f )
- {
- return 1.0f;
- }
-
- // If FOV is lower, then we're "zoomed" in and this will give a factor < 1 so apparent LOD distances can be
- // shorted accordingly
- return localFOV / defaultFOV;
-
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : &vecTracerSrc -
-// &tr -
-// iTracerType -
-//-----------------------------------------------------------------------------
-void CBasePlayer::MakeTracer( const Vector &vecTracerSrc, const trace_t &tr, int iTracerType )
-{
- if ( GetActiveWeapon() )
- {
- GetActiveWeapon()->MakeTracer( vecTracerSrc, tr, iTracerType );
- return;
- }
-
- BaseClass::MakeTracer( vecTracerSrc, tr, iTracerType );
-}
-
-
-void CBasePlayer::SharedSpawn()
-{
- SetMoveType( MOVETYPE_WALK );
- SetSolid( SOLID_BBOX );
- AddSolidFlags( FSOLID_NOT_STANDABLE );
- SetFriction( 1.0f );
-
- pl.deadflag = false;
- m_lifeState = LIFE_ALIVE;
- m_iHealth = 100;
- m_takedamage = DAMAGE_YES;
-
- m_Local.m_bDrawViewmodel = true;
- m_Local.m_flStepSize = sv_stepsize.GetFloat();
- m_Local.m_bAllowAutoMovement = true;
-
- m_nRenderFX = kRenderFxNone;
- m_flNextAttack = gpGlobals->curtime;
- m_flMaxspeed = 0.0f;
-
- MDLCACHE_CRITICAL_SECTION();
- SetSequence( SelectWeightedSequence( ACT_IDLE ) );
-
- if ( GetFlags() & FL_DUCKING )
- SetCollisionBounds( VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX );
- else
- SetCollisionBounds( VEC_HULL_MIN, VEC_HULL_MAX );
-
- // dont let uninitialized value here hurt the player
- m_Local.m_flFallVelocity = 0;
-
- SetBloodColor( BLOOD_COLOR_RED );
- // NVNT inform haptic dll we have just spawned local player
-#ifdef CLIENT_DLL
- if(IsLocalPlayer() &&haptics)
- haptics->LocalPlayerReset();
-#endif
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Output : int
-//-----------------------------------------------------------------------------
-int CBasePlayer::GetDefaultFOV( void ) const
-{
-#if defined( CLIENT_DLL )
- if ( GetObserverMode() == OBS_MODE_IN_EYE )
- {
- C_BasePlayer *pTargetPlayer = dynamic_cast<C_BasePlayer*>( GetObserverTarget() );
-
- if ( pTargetPlayer && !pTargetPlayer->IsObserver() )
- {
- return pTargetPlayer->GetDefaultFOV();
- }
- }
-#endif
-
- int iFOV = ( m_iDefaultFOV == 0 ) ? g_pGameRules->DefaultFOV() : m_iDefaultFOV;
- if ( iFOV > MAX_FOV )
- iFOV = MAX_FOV;
-
- return iFOV;
-}
-
-void CBasePlayer::AvoidPhysicsProps( CUserCmd *pCmd )
-{
-#ifndef _XBOX
- // Don't avoid if noclipping or in movetype none
- switch ( GetMoveType() )
- {
- case MOVETYPE_NOCLIP:
- case MOVETYPE_NONE:
- case MOVETYPE_OBSERVER:
- return;
- default:
- break;
- }
-
- if ( GetObserverMode() != OBS_MODE_NONE || !IsAlive() )
- return;
-
- AvoidPushawayProps( this, pCmd );
-#endif
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Output : const char
-//-----------------------------------------------------------------------------
-const char *CBasePlayer::GetTracerType( void )
-{
- if ( GetActiveWeapon() )
- {
- return GetActiveWeapon()->GetTracerType();
- }
-
- return BaseClass::GetTracerType();
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void CBasePlayer::ClearZoomOwner( void )
-{
- m_hZoomOwner = NULL;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Sets the FOV of the client, doing interpolation between old and new if requested
-// Input : FOV - New FOV
-// zoomRate - Amount of time (in seconds) to move between old and new FOV
-//-----------------------------------------------------------------------------
-bool CBasePlayer::SetFOV( CBaseEntity *pRequester, int FOV, float zoomRate, int iZoomStart /* = 0 */ )
-{
- //NOTENOTE: You MUST specify who is requesting the zoom change
- assert( pRequester != NULL );
- if ( pRequester == NULL )
- return false;
-
- // If we already have an owner, we only allow requests from that owner
- if ( ( m_hZoomOwner.Get() != NULL ) && ( m_hZoomOwner.Get() != pRequester ) )
- {
-#ifdef GAME_DLL
- if ( CanOverrideEnvZoomOwner( m_hZoomOwner.Get() ) == false )
-#endif
- return false;
- }
- else
- {
- //FIXME: Maybe do this is as an accessor instead
- if ( FOV == 0 )
- {
- m_hZoomOwner = NULL;
- }
- else
- {
- m_hZoomOwner = pRequester;
- }
- }
-
- // Setup our FOV and our scaling time
-
- if ( iZoomStart > 0 )
- {
- m_iFOVStart = iZoomStart;
- }
- else
- {
- m_iFOVStart = GetFOV();
- }
-
- m_flFOVTime = gpGlobals->curtime;
- m_iFOV = FOV;
-
- m_Local.m_flFOVRate = zoomRate;
-
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void CBasePlayer::UpdateUnderwaterState( void )
-{
- if ( GetWaterLevel() == WL_Eyes )
- {
- if ( IsPlayerUnderwater() == false )
- {
- SetPlayerUnderwater( true );
- }
- return;
- }
-
- if ( IsPlayerUnderwater() )
- {
- SetPlayerUnderwater( false );
- }
-
- if ( GetWaterLevel() == 0 )
- {
- if ( GetFlags() & FL_INWATER )
- {
-#ifndef CLIENT_DLL
- if ( m_iHealth > 0 && IsAlive() )
- {
- EmitSound( "Player.Wade" );
- }
-#endif
- RemoveFlag( FL_INWATER );
- }
- }
- else if ( !(GetFlags() & FL_INWATER) )
- {
-#ifndef CLIENT_DLL
- // player enter water sound
- if (GetWaterType() == CONTENTS_WATER)
- {
- EmitSound( "Player.Wade" );
- }
-#endif
-
- AddFlag( FL_INWATER );
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: data accessor
-// ensure that for every emitsound there is a matching stopsound
-//-----------------------------------------------------------------------------
-void CBasePlayer::SetPlayerUnderwater( bool state )
-{
- if ( m_bPlayerUnderwater != state )
- {
-#if defined( WIN32 ) && !defined( _X360 )
- // NVNT turn on haptic drag when underwater
- if(state)
- HapticSetDrag(this,1);
- else
- HapticSetDrag(this,0);
-#endif
- m_bPlayerUnderwater = state;
-
-#ifdef CLIENT_DLL
- if ( state )
- EmitSound( "Player.AmbientUnderWater" );
- else
- StopSound( "Player.AmbientUnderWater" );
-#endif
- }
-}
-
-
-void CBasePlayer::SetPreviouslyPredictedOrigin( const Vector &vecAbsOrigin )
-{
- m_vecPreviouslyPredictedOrigin = vecAbsOrigin;
-}
-
-const Vector &CBasePlayer::GetPreviouslyPredictedOrigin() const
-{
- return m_vecPreviouslyPredictedOrigin;
-}
-
-bool fogparams_t::operator !=( const fogparams_t& other ) const
-{
- if ( this->enable != other.enable ||
- this->blend != other.blend ||
- !VectorsAreEqual(this->dirPrimary, other.dirPrimary, 0.01f ) ||
- this->colorPrimary.Get() != other.colorPrimary.Get() ||
- this->colorSecondary.Get() != other.colorSecondary.Get() ||
- this->start != other.start ||
- this->end != other.end ||
- this->farz != other.farz ||
- this->maxdensity != other.maxdensity ||
- this->colorPrimaryLerpTo.Get() != other.colorPrimaryLerpTo.Get() ||
- this->colorSecondaryLerpTo.Get() != other.colorSecondaryLerpTo.Get() ||
- this->startLerpTo != other.startLerpTo ||
- this->endLerpTo != other.endLerpTo ||
- this->lerptime != other.lerptime ||
- this->duration != other.duration )
- return true;
-
- return false;
-}
-
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Implements shared baseplayer class functionality
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "cbase.h"
+#include "movevars_shared.h"
+#include "util_shared.h"
+#include "datacache/imdlcache.h"
+#if defined ( TF_DLL ) || defined ( TF_CLIENT_DLL )
+#include "tf_gamerules.h"
+#endif
+
+#if defined( CLIENT_DLL )
+
+ #include "iclientvehicle.h"
+ #include "prediction.h"
+ #include "c_basedoor.h"
+ #include "c_world.h"
+ #include "view.h"
+ #include "client_virtualreality.h"
+ #define CRecipientFilter C_RecipientFilter
+ #include "headtrack/isourcevirtualreality.h"
+
+#else
+
+ #include "iservervehicle.h"
+ #include "trains.h"
+ #include "world.h"
+ #include "doors.h"
+ #include "ai_basenpc.h"
+ #include "env_zoom.h"
+
+ extern int TrainSpeed(int iSpeed, int iMax);
+
+#endif
+
+#if defined( CSTRIKE_DLL )
+#include "weapon_c4.h"
+#endif // CSTRIKE_DLL
+
+#include "in_buttons.h"
+#include "engine/IEngineSound.h"
+#include "tier0/vprof.h"
+#include "SoundEmitterSystem/isoundemittersystembase.h"
+#include "decals.h"
+#include "obstacle_pushaway.h"
+#ifdef SIXENSE
+#include "sixense/in_sixense.h"
+#endif
+
+// NVNT haptic utils
+#include "haptics/haptic_utils.h"
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+#if defined(GAME_DLL) && !defined(_XBOX)
+ extern ConVar sv_pushaway_max_force;
+ extern ConVar sv_pushaway_force;
+ extern ConVar sv_turbophysics;
+
+ class CUsePushFilter : public CTraceFilterEntitiesOnly
+ {
+ public:
+ bool ShouldHitEntity( IHandleEntity *pHandleEntity, int contentsMask )
+ {
+ CBaseEntity *pEntity = EntityFromEntityHandle( pHandleEntity );
+
+ // Static prop case...
+ if ( !pEntity )
+ return false;
+
+ // Only impact on physics objects
+ if ( !pEntity->VPhysicsGetObject() )
+ return false;
+
+#if defined( CSTRIKE_DLL )
+ // don't push the bomb!
+ if ( dynamic_cast<CC4*>( pEntity ) )
+ return false;
+#endif // CSTRIKE_DLL
+
+ return g_pGameRules->CanEntityBeUsePushed( pEntity );
+ }
+ };
+#endif
+
+#ifdef CLIENT_DLL
+ConVar mp_usehwmmodels( "mp_usehwmmodels", "0", NULL, "Enable the use of the hw morph models. (-1 = never, 1 = always, 0 = based upon GPU)" ); // -1 = never, 0 = if hasfastvertextextures, 1 = always
+#endif
+
+bool UseHWMorphModels()
+{
+// #ifdef CLIENT_DLL
+// if ( mp_usehwmmodels.GetInt() == 0 )
+// return g_pMaterialSystemHardwareConfig->HasFastVertexTextures();
+//
+// return mp_usehwmmodels.GetInt() > 0;
+// #else
+// return false;
+// #endif
+ return false;
+}
+
+void CopySoundNameWithModifierToken( char *pchDest, const char *pchSource, int nMaxLenInChars, const char *pchToken )
+{
+ // Copy the sound name
+ int nSource = 0;
+ int nDest = 0;
+ bool bFoundPeriod = false;
+
+ while ( pchSource[ nSource ] != '\0' && nDest < nMaxLenInChars - 2 )
+ {
+ pchDest[ nDest ] = pchSource[ nSource ];
+ nDest++;
+ nSource++;
+
+ if ( !bFoundPeriod && pchSource[ nSource - 1 ] == '.' )
+ {
+ // Insert special token after the period
+ bFoundPeriod = true;
+
+ int nToken = 0;
+
+ while ( pchToken[ nToken ] != '\0' && nDest < nMaxLenInChars - 2 )
+ {
+ pchDest[ nDest ] = pchToken[ nToken ];
+ nDest++;
+ nToken++;
+ }
+ }
+ }
+
+ pchDest[ nDest ] = '\0';
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : float
+//-----------------------------------------------------------------------------
+float CBasePlayer::GetTimeBase( void ) const
+{
+ return m_nTickBase * TICK_INTERVAL;
+}
+
+float CBasePlayer::GetPlayerMaxSpeed()
+{
+ // player max speed is the lower limit of m_flMaxSpeed and sv_maxspeed
+ float fMaxSpeed = sv_maxspeed.GetFloat();
+ if ( MaxSpeed() > 0.0f && MaxSpeed() < fMaxSpeed )
+ fMaxSpeed = MaxSpeed();
+
+ return fMaxSpeed;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Called every usercmd by the player PreThink
+//-----------------------------------------------------------------------------
+void CBasePlayer::ItemPreFrame()
+{
+ // Handle use events
+ PlayerUse();
+
+ CBaseCombatWeapon *pActive = GetActiveWeapon();
+
+ // Allow all the holstered weapons to update
+ for ( int i = 0; i < WeaponCount(); ++i )
+ {
+ CBaseCombatWeapon *pWeapon = GetWeapon( i );
+
+ if ( pWeapon == NULL )
+ continue;
+
+ if ( pActive == pWeapon )
+ continue;
+
+ pWeapon->ItemHolsterFrame();
+ }
+
+ if ( gpGlobals->curtime < m_flNextAttack )
+ return;
+
+ if (!pActive)
+ return;
+
+#if defined( CLIENT_DLL )
+ // Not predicting this weapon
+ if ( !pActive->IsPredicted() )
+ return;
+#endif
+
+ pActive->ItemPreFrame();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CBasePlayer::UsingStandardWeaponsInVehicle( void )
+{
+ Assert( IsInAVehicle() );
+#if !defined( CLIENT_DLL )
+ IServerVehicle *pVehicle = GetVehicle();
+#else
+ IClientVehicle *pVehicle = GetVehicle();
+#endif
+ Assert( pVehicle );
+ if ( !pVehicle )
+ return true;
+
+ // NOTE: We *have* to do this before ItemPostFrame because ItemPostFrame
+ // may dump us out of the vehicle
+ int nRole = pVehicle->GetPassengerRole( this );
+ bool bUsingStandardWeapons = pVehicle->IsPassengerUsingStandardWeapons( nRole );
+
+ // Fall through and check weapons, etc. if we're using them
+ if (!bUsingStandardWeapons )
+ return false;
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Called every usercmd by the player PostThink
+//-----------------------------------------------------------------------------
+void CBasePlayer::ItemPostFrame()
+{
+ VPROF( "CBasePlayer::ItemPostFrame" );
+
+ // Put viewmodels into basically correct place based on new player origin
+ CalcViewModelView( EyePosition(), EyeAngles() );
+
+ // Don't process items while in a vehicle.
+ if ( GetVehicle() )
+ {
+#if defined( CLIENT_DLL )
+ IClientVehicle *pVehicle = GetVehicle();
+#else
+ IServerVehicle *pVehicle = GetVehicle();
+#endif
+
+ bool bUsingStandardWeapons = UsingStandardWeaponsInVehicle();
+
+#if defined( CLIENT_DLL )
+ if ( pVehicle->IsPredicted() )
+#endif
+ {
+ pVehicle->ItemPostFrame( this );
+ }
+
+ if (!bUsingStandardWeapons || !GetVehicle())
+ return;
+ }
+
+
+ // check if the player is using something
+ if ( m_hUseEntity != NULL )
+ {
+#if !defined( CLIENT_DLL )
+ Assert( !IsInAVehicle() );
+ ImpulseCommands();// this will call playerUse
+#endif
+ return;
+ }
+
+ if ( gpGlobals->curtime < m_flNextAttack )
+ {
+ if ( GetActiveWeapon() )
+ {
+ GetActiveWeapon()->ItemBusyFrame();
+ }
+ }
+ else
+ {
+ if ( GetActiveWeapon() && (!IsInAVehicle() || UsingStandardWeaponsInVehicle()) )
+ {
+#if defined( CLIENT_DLL )
+ // Not predicting this weapon
+ if ( GetActiveWeapon()->IsPredicted() )
+#endif
+
+ {
+ GetActiveWeapon()->ItemPostFrame( );
+ }
+ }
+ }
+
+#if !defined( CLIENT_DLL )
+ ImpulseCommands();
+#else
+ // NOTE: If we ever support full impulse commands on the client,
+ // remove this line and call ImpulseCommands instead.
+ m_nImpulse = 0;
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Eye angles
+//-----------------------------------------------------------------------------
+const QAngle &CBasePlayer::EyeAngles( )
+{
+ // NOTE: Viewangles are measured *relative* to the parent's coordinate system
+ CBaseEntity *pMoveParent = const_cast<CBasePlayer*>(this)->GetMoveParent();
+
+ if ( !pMoveParent )
+ {
+ return pl.v_angle;
+ }
+
+ // FIXME: Cache off the angles?
+ matrix3x4_t eyesToParent, eyesToWorld;
+ AngleMatrix( pl.v_angle, eyesToParent );
+ ConcatTransforms( pMoveParent->EntityToWorldTransform(), eyesToParent, eyesToWorld );
+
+ static QAngle angEyeWorld;
+ MatrixAngles( eyesToWorld, angEyeWorld );
+ return angEyeWorld;
+}
+
+
+const QAngle &CBasePlayer::LocalEyeAngles()
+{
+ return pl.v_angle;
+}
+
+//-----------------------------------------------------------------------------
+// Actual Eye position + angles
+//-----------------------------------------------------------------------------
+Vector CBasePlayer::EyePosition( )
+{
+ if ( GetVehicle() != NULL )
+ {
+ // Return the cached result
+ CacheVehicleView();
+ return m_vecVehicleViewOrigin;
+ }
+ else
+ {
+#ifdef CLIENT_DLL
+ if ( IsObserver() )
+ {
+ if ( GetObserverMode() == OBS_MODE_CHASE )
+ {
+ if ( IsLocalPlayer() )
+ {
+ return MainViewOrigin();
+ }
+ }
+ }
+#endif
+ return BaseClass::EyePosition();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input :
+// Output : const Vector
+//-----------------------------------------------------------------------------
+const Vector CBasePlayer::GetPlayerMins( void ) const
+{
+ if ( IsObserver() )
+ {
+ return VEC_OBS_HULL_MIN_SCALED( this );
+ }
+ else
+ {
+ if ( GetFlags() & FL_DUCKING )
+ {
+ return VEC_DUCK_HULL_MIN_SCALED( this );
+ }
+ else
+ {
+ return VEC_HULL_MIN_SCALED( this );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input :
+// Output : const Vector
+//-----------------------------------------------------------------------------
+const Vector CBasePlayer::GetPlayerMaxs( void ) const
+{
+ if ( IsObserver() )
+ {
+ return VEC_OBS_HULL_MAX_SCALED( this );
+ }
+ else
+ {
+ if ( GetFlags() & FL_DUCKING )
+ {
+ return VEC_DUCK_HULL_MAX_SCALED( this );
+ }
+ else
+ {
+ return VEC_HULL_MAX_SCALED( this );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Update the vehicle view, or simply return the cached position and angles
+//-----------------------------------------------------------------------------
+void CBasePlayer::CacheVehicleView( void )
+{
+ // If we've calculated the view this frame, then there's no need to recalculate it
+ if ( m_nVehicleViewSavedFrame == gpGlobals->framecount )
+ return;
+
+#ifdef CLIENT_DLL
+ IClientVehicle *pVehicle = GetVehicle();
+#else
+ IServerVehicle *pVehicle = GetVehicle();
+#endif
+
+ if ( pVehicle != NULL )
+ {
+ int nRole = pVehicle->GetPassengerRole( this );
+
+ // Get our view for this frame
+ pVehicle->GetVehicleViewPosition( nRole, &m_vecVehicleViewOrigin, &m_vecVehicleViewAngles, &m_flVehicleViewFOV );
+ m_nVehicleViewSavedFrame = gpGlobals->framecount;
+
+#ifdef CLIENT_DLL
+ if( UseVR() )
+ {
+ C_BaseAnimating *pVehicleAnimating = dynamic_cast<C_BaseAnimating *>( pVehicle );
+ if( pVehicleAnimating )
+ {
+ int eyeAttachmentIndex = pVehicleAnimating->LookupAttachment( "vehicle_driver_eyes" );
+
+ Vector vehicleEyeOrigin;
+ QAngle vehicleEyeAngles;
+ pVehicleAnimating->GetAttachment( eyeAttachmentIndex, vehicleEyeOrigin, vehicleEyeAngles );
+
+ g_ClientVirtualReality.OverrideTorsoTransform( vehicleEyeOrigin, vehicleEyeAngles );
+ }
+ }
+#endif
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Returns eye vectors
+//-----------------------------------------------------------------------------
+void CBasePlayer::EyeVectors( Vector *pForward, Vector *pRight, Vector *pUp )
+{
+ if ( GetVehicle() != NULL )
+ {
+ // Cache or retrieve our calculated position in the vehicle
+ CacheVehicleView();
+ AngleVectors( m_vecVehicleViewAngles, pForward, pRight, pUp );
+ }
+ else
+ {
+ AngleVectors( EyeAngles(), pForward, pRight, pUp );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Returns the eye position and angle vectors.
+//-----------------------------------------------------------------------------
+void CBasePlayer::EyePositionAndVectors( Vector *pPosition, Vector *pForward,
+ Vector *pRight, Vector *pUp )
+{
+ // Handle the view in the vehicle
+ if ( GetVehicle() != NULL )
+ {
+ CacheVehicleView();
+ AngleVectors( m_vecVehicleViewAngles, pForward, pRight, pUp );
+
+ if ( pPosition != NULL )
+ {
+ *pPosition = m_vecVehicleViewOrigin;
+ }
+ }
+ else
+ {
+ VectorCopy( BaseClass::EyePosition(), *pPosition );
+ AngleVectors( EyeAngles(), pForward, pRight, pUp );
+ }
+}
+
+#ifdef CLIENT_DLL
+surfacedata_t * CBasePlayer::GetFootstepSurface( const Vector &origin, const char *surfaceName )
+{
+ return physprops->GetSurfaceData( physprops->GetSurfaceIndex( surfaceName ) );
+}
+#endif
+
+surfacedata_t *CBasePlayer::GetLadderSurface( const Vector &origin )
+{
+#ifdef CLIENT_DLL
+ return GetFootstepSurface( origin, "ladder" );
+#else
+ return physprops->GetSurfaceData( physprops->GetSurfaceIndex( "ladder" ) );
+#endif
+}
+
+void CBasePlayer::UpdateStepSound( surfacedata_t *psurface, const Vector &vecOrigin, const Vector &vecVelocity )
+{
+ bool bWalking;
+ float fvol;
+ Vector knee;
+ Vector feet;
+ float height;
+ float speed;
+ float velrun;
+ float velwalk;
+ int fLadder;
+
+ if ( m_flStepSoundTime > 0 )
+ {
+ m_flStepSoundTime -= 1000.0f * gpGlobals->frametime;
+ if ( m_flStepSoundTime < 0 )
+ {
+ m_flStepSoundTime = 0;
+ }
+ }
+
+ if ( m_flStepSoundTime > 0 )
+ return;
+
+ if ( GetFlags() & (FL_FROZEN|FL_ATCONTROLS))
+ return;
+
+ if ( GetMoveType() == MOVETYPE_NOCLIP || GetMoveType() == MOVETYPE_OBSERVER )
+ return;
+
+ if ( !sv_footsteps.GetFloat() )
+ return;
+
+ speed = VectorLength( vecVelocity );
+ float groundspeed = Vector2DLength( vecVelocity.AsVector2D() );
+
+ // determine if we are on a ladder
+ fLadder = ( GetMoveType() == MOVETYPE_LADDER );
+
+ GetStepSoundVelocities( &velwalk, &velrun );
+
+ bool onground = ( GetFlags() & FL_ONGROUND );
+ bool movingalongground = ( groundspeed > 0.0001f );
+ bool moving_fast_enough = ( speed >= velwalk );
+
+#ifdef PORTAL
+ // In Portal we MUST play footstep sounds even when the player is moving very slowly
+ // This is used to count the number of footsteps they take in the challenge mode
+ // -Jeep
+ moving_fast_enough = true;
+#endif
+
+ // To hear step sounds you must be either on a ladder or moving along the ground AND
+ // You must be moving fast enough
+
+ if ( !moving_fast_enough || !(fLadder || ( onground && movingalongground )) )
+ return;
+
+// MoveHelper()->PlayerSetAnimation( PLAYER_WALK );
+
+ bWalking = speed < velrun;
+
+ VectorCopy( vecOrigin, knee );
+ VectorCopy( vecOrigin, feet );
+
+ height = GetPlayerMaxs()[ 2 ] - GetPlayerMins()[ 2 ];
+
+ knee[2] = vecOrigin[2] + 0.2 * height;
+
+ // find out what we're stepping in or on...
+ if ( fLadder )
+ {
+ psurface = GetLadderSurface(vecOrigin);
+ fvol = 0.5;
+
+ SetStepSoundTime( STEPSOUNDTIME_ON_LADDER, bWalking );
+ }
+#ifdef CSTRIKE_DLL
+ else if ( enginetrace->GetPointContents( knee ) & MASK_WATER ) // we want to use the knee for Cstrike, not the waist
+#else
+ else if ( GetWaterLevel() == WL_Waist )
+#endif // CSTRIKE_DLL
+ {
+ static int iSkipStep = 0;
+
+ if ( iSkipStep == 0 )
+ {
+ iSkipStep++;
+ return;
+ }
+
+ if ( iSkipStep++ == 3 )
+ {
+ iSkipStep = 0;
+ }
+ psurface = physprops->GetSurfaceData( physprops->GetSurfaceIndex( "wade" ) );
+ fvol = 0.65;
+ SetStepSoundTime( STEPSOUNDTIME_WATER_KNEE, bWalking );
+ }
+ else if ( GetWaterLevel() == WL_Feet )
+ {
+ psurface = physprops->GetSurfaceData( physprops->GetSurfaceIndex( "water" ) );
+ fvol = bWalking ? 0.2 : 0.5;
+
+ SetStepSoundTime( STEPSOUNDTIME_WATER_FOOT, bWalking );
+ }
+ else
+ {
+ if ( !psurface )
+ return;
+
+ SetStepSoundTime( STEPSOUNDTIME_NORMAL, bWalking );
+
+ switch ( psurface->game.material )
+ {
+ default:
+ case CHAR_TEX_CONCRETE:
+ fvol = bWalking ? 0.2 : 0.5;
+ break;
+
+ case CHAR_TEX_METAL:
+ fvol = bWalking ? 0.2 : 0.5;
+ break;
+
+ case CHAR_TEX_DIRT:
+ fvol = bWalking ? 0.25 : 0.55;
+ break;
+
+ case CHAR_TEX_VENT:
+ fvol = bWalking ? 0.4 : 0.7;
+ break;
+
+ case CHAR_TEX_GRATE:
+ fvol = bWalking ? 0.2 : 0.5;
+ break;
+
+ case CHAR_TEX_TILE:
+ fvol = bWalking ? 0.2 : 0.5;
+ break;
+
+ case CHAR_TEX_SLOSH:
+ fvol = bWalking ? 0.2 : 0.5;
+ break;
+ }
+ }
+
+ // play the sound
+ // 65% volume if ducking
+ if ( GetFlags() & FL_DUCKING )
+ {
+ fvol *= 0.65;
+ }
+
+ PlayStepSound( feet, psurface, fvol, false );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : step -
+// fvol -
+// force - force sound to play
+//-----------------------------------------------------------------------------
+void CBasePlayer::PlayStepSound( Vector &vecOrigin, surfacedata_t *psurface, float fvol, bool force )
+{
+ if ( gpGlobals->maxClients > 1 && !sv_footsteps.GetFloat() )
+ return;
+
+#if defined( CLIENT_DLL )
+ // during prediction play footstep sounds only once
+ if ( prediction->InPrediction() && !prediction->IsFirstTimePredicted() )
+ return;
+#endif
+
+ if ( !psurface )
+ return;
+
+ int nSide = m_Local.m_nStepside;
+ unsigned short stepSoundName = nSide ? psurface->sounds.stepleft : psurface->sounds.stepright;
+ if ( !stepSoundName )
+ return;
+
+ m_Local.m_nStepside = !nSide;
+
+ CSoundParameters params;
+
+ Assert( nSide == 0 || nSide == 1 );
+
+ if ( m_StepSoundCache[ nSide ].m_usSoundNameIndex == stepSoundName )
+ {
+ params = m_StepSoundCache[ nSide ].m_SoundParameters;
+ }
+ else
+ {
+ IPhysicsSurfaceProps *physprops = MoveHelper()->GetSurfaceProps();
+ const char *pSoundName = physprops->GetString( stepSoundName );
+
+ // Give child classes an opportunity to override.
+ pSoundName = GetOverrideStepSound( pSoundName );
+
+ if ( !CBaseEntity::GetParametersForSound( pSoundName, params, NULL ) )
+ return;
+
+ // Only cache if there's one option. Otherwise we'd never here any other sounds
+ if ( params.count == 1 )
+ {
+ m_StepSoundCache[ nSide ].m_usSoundNameIndex = stepSoundName;
+ m_StepSoundCache[ nSide ].m_SoundParameters = params;
+ }
+ }
+
+ CRecipientFilter filter;
+ filter.AddRecipientsByPAS( vecOrigin );
+
+#ifndef CLIENT_DLL
+ // in MP, server removes all players in the vecOrigin's PVS, these players generate the footsteps client side
+ if ( gpGlobals->maxClients > 1 )
+ {
+ filter.RemoveRecipientsByPVS( vecOrigin );
+ }
+#endif
+
+ EmitSound_t ep;
+ ep.m_nChannel = CHAN_BODY;
+ ep.m_pSoundName = params.soundname;
+#if defined ( TF_DLL ) || defined ( TF_CLIENT_DLL )
+ if( TFGameRules()->IsMannVsMachineMode() )
+ {
+ ep.m_flVolume = params.volume;
+ }
+ else
+ {
+ ep.m_flVolume = fvol;
+ }
+#else
+ ep.m_flVolume = fvol;
+#endif
+ ep.m_SoundLevel = params.soundlevel;
+ ep.m_nFlags = 0;
+ ep.m_nPitch = params.pitch;
+ ep.m_pOrigin = &vecOrigin;
+
+ EmitSound( filter, entindex(), ep );
+
+ // Kyle says: ugggh. This function may as well be called "PerformPileOfDesperateGameSpecificFootstepHacks".
+ OnEmitFootstepSound( params, vecOrigin, fvol );
+}
+
+void CBasePlayer::UpdateButtonState( int nUserCmdButtonMask )
+{
+ // Track button info so we can detect 'pressed' and 'released' buttons next frame
+ m_afButtonLast = m_nButtons;
+
+ // Get button states
+ m_nButtons = nUserCmdButtonMask;
+ int buttonsChanged = m_afButtonLast ^ m_nButtons;
+
+ // Debounced button codes for pressed/released
+ // UNDONE: Do we need auto-repeat?
+ m_afButtonPressed = buttonsChanged & m_nButtons; // The changed ones still down are "pressed"
+ m_afButtonReleased = buttonsChanged & (~m_nButtons); // The ones not down are "released"
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBasePlayer::GetStepSoundVelocities( float *velwalk, float *velrun )
+{
+ // UNDONE: need defined numbers for run, walk, crouch, crouch run velocities!!!!
+ if ( ( GetFlags() & FL_DUCKING) || ( GetMoveType() == MOVETYPE_LADDER ) )
+ {
+ *velwalk = 60; // These constants should be based on cl_movespeedkey * cl_forwardspeed somehow
+ *velrun = 80;
+ }
+ else
+ {
+ *velwalk = 90;
+ *velrun = 220;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBasePlayer::SetStepSoundTime( stepsoundtimes_t iStepSoundTime, bool bWalking )
+{
+ switch ( iStepSoundTime )
+ {
+ case STEPSOUNDTIME_NORMAL:
+ case STEPSOUNDTIME_WATER_FOOT:
+ m_flStepSoundTime = bWalking ? 400 : 300;
+ break;
+
+ case STEPSOUNDTIME_ON_LADDER:
+ m_flStepSoundTime = 350;
+ break;
+
+ case STEPSOUNDTIME_WATER_KNEE:
+ m_flStepSoundTime = 600;
+ break;
+
+ default:
+ Assert(0);
+ break;
+ }
+
+ // UNDONE: need defined numbers for run, walk, crouch, crouch run velocities!!!!
+ if ( ( GetFlags() & FL_DUCKING) || ( GetMoveType() == MOVETYPE_LADDER ) )
+ {
+ m_flStepSoundTime += 100;
+ }
+}
+
+Vector CBasePlayer::Weapon_ShootPosition( )
+{
+ return EyePosition();
+}
+
+void CBasePlayer::SetAnimationExtension( const char *pExtension )
+{
+ Q_strncpy( m_szAnimExtension, pExtension, sizeof(m_szAnimExtension) );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Set the weapon to switch to when the player uses the 'lastinv' command
+//-----------------------------------------------------------------------------
+void CBasePlayer::Weapon_SetLast( CBaseCombatWeapon *pWeapon )
+{
+ m_hLastWeapon = pWeapon;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Override base class so player can reset autoaim
+// Input :
+// Output :
+//-----------------------------------------------------------------------------
+bool CBasePlayer::Weapon_Switch( CBaseCombatWeapon *pWeapon, int viewmodelindex /*=0*/ )
+{
+ CBaseCombatWeapon *pLastWeapon = GetActiveWeapon();
+
+ if ( BaseClass::Weapon_Switch( pWeapon, viewmodelindex ))
+ {
+ if ( pLastWeapon && Weapon_ShouldSetLast( pLastWeapon, GetActiveWeapon() ) )
+ {
+ Weapon_SetLast( pLastWeapon->GetLastWeapon() );
+ }
+
+ CBaseViewModel *pViewModel = GetViewModel( viewmodelindex );
+ Assert( pViewModel );
+ if ( pViewModel )
+ pViewModel->RemoveEffects( EF_NODRAW );
+ ResetAutoaim( );
+ return true;
+ }
+ return false;
+}
+
+void CBasePlayer::SelectLastItem(void)
+{
+ if ( m_hLastWeapon.Get() == NULL )
+ return;
+
+ if ( GetActiveWeapon() && !GetActiveWeapon()->CanHolster() )
+ return;
+
+ SelectItem( m_hLastWeapon.Get()->GetClassname(), m_hLastWeapon.Get()->GetSubType() );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Abort any reloads we're in
+//-----------------------------------------------------------------------------
+void CBasePlayer::AbortReload( void )
+{
+ if ( GetActiveWeapon() )
+ {
+ GetActiveWeapon()->AbortReload();
+ }
+}
+
+#if !defined( NO_ENTITY_PREDICTION )
+void CBasePlayer::AddToPlayerSimulationList( CBaseEntity *other )
+{
+ CHandle< CBaseEntity > h;
+ h = other;
+ // Already in list
+ if ( m_SimulatedByThisPlayer.Find( h ) != m_SimulatedByThisPlayer.InvalidIndex() )
+ return;
+
+ Assert( other->IsPlayerSimulated() );
+
+ m_SimulatedByThisPlayer.AddToTail( h );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Fixme, this should occur if the player fails to drive simulation
+// often enough!!!
+// Input : *other -
+//-----------------------------------------------------------------------------
+void CBasePlayer::RemoveFromPlayerSimulationList( CBaseEntity *other )
+{
+ if ( !other )
+ return;
+
+ Assert( other->IsPlayerSimulated() );
+ Assert( other->GetSimulatingPlayer() == this );
+
+
+ CHandle< CBaseEntity > h;
+ h = other;
+
+ m_SimulatedByThisPlayer.FindAndRemove( h );
+}
+
+void CBasePlayer::SimulatePlayerSimulatedEntities( void )
+{
+ int c = m_SimulatedByThisPlayer.Count();
+ int i;
+
+ for ( i = c - 1; i >= 0; i-- )
+ {
+ CHandle< CBaseEntity > h;
+
+ h = m_SimulatedByThisPlayer[ i ];
+ CBaseEntity *e = h;
+
+ if ( !e || !e->IsPlayerSimulated() )
+ {
+ m_SimulatedByThisPlayer.Remove( i );
+ continue;
+ }
+
+#if defined( CLIENT_DLL )
+ if ( e->IsClientCreated() && prediction->InPrediction() && !prediction->IsFirstTimePredicted() )
+ {
+ continue;
+ }
+#endif
+ Assert( e->IsPlayerSimulated() );
+ Assert( e->GetSimulatingPlayer() == this );
+
+ e->PhysicsSimulate();
+ }
+
+ // Loop through all entities again, checking their untouch if flagged to do so
+ c = m_SimulatedByThisPlayer.Count();
+
+ for ( i = c - 1; i >= 0; i-- )
+ {
+ CHandle< CBaseEntity > h;
+
+ h = m_SimulatedByThisPlayer[ i ];
+
+ CBaseEntity *e = h;
+ if ( !e || !e->IsPlayerSimulated() )
+ {
+ m_SimulatedByThisPlayer.Remove( i );
+ continue;
+ }
+
+#if defined( CLIENT_DLL )
+ if ( e->IsClientCreated() && prediction->InPrediction() && !prediction->IsFirstTimePredicted() )
+ {
+ continue;
+ }
+#endif
+
+ Assert( e->IsPlayerSimulated() );
+ Assert( e->GetSimulatingPlayer() == this );
+
+ if ( !e->GetCheckUntouch() )
+ continue;
+
+ e->PhysicsCheckForEntityUntouch();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBasePlayer::ClearPlayerSimulationList( void )
+{
+ int c = m_SimulatedByThisPlayer.Size();
+ int i;
+
+ for ( i = c - 1; i >= 0; i-- )
+ {
+ CHandle< CBaseEntity > h;
+
+ h = m_SimulatedByThisPlayer[ i ];
+ CBaseEntity *e = h;
+ if ( e )
+ {
+ e->UnsetPlayerSimulated();
+ }
+ }
+
+ m_SimulatedByThisPlayer.RemoveAll();
+}
+#endif
+
+//-----------------------------------------------------------------------------
+// Purpose: Return true if we should allow selection of the specified item
+//-----------------------------------------------------------------------------
+bool CBasePlayer::Weapon_ShouldSelectItem( CBaseCombatWeapon *pWeapon )
+{
+ return ( pWeapon != GetActiveWeapon() );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBasePlayer::SelectItem( const char *pstr, int iSubType )
+{
+ if (!pstr)
+ return;
+
+ CBaseCombatWeapon *pItem = Weapon_OwnsThisType( pstr, iSubType );
+
+ if (!pItem)
+ return;
+
+ if( GetObserverMode() != OBS_MODE_NONE )
+ return;// Observers can't select things.
+
+ if ( !Weapon_ShouldSelectItem( pItem ) )
+ return;
+
+ // FIX, this needs to queue them up and delay
+ // Make sure the current weapon can be holstered
+ if ( GetActiveWeapon() )
+ {
+ if ( !GetActiveWeapon()->CanHolster() )
+ return;
+
+ ResetAutoaim( );
+ }
+
+ Weapon_Switch( pItem );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+ConVar sv_debug_player_use( "sv_debug_player_use", "0", FCVAR_REPLICATED, "Visualizes +use logic. Green cross=trace success, Red cross=trace too far, Green box=radius success" );
+float IntervalDistance( float x, float x0, float x1 )
+{
+ // swap so x0 < x1
+ if ( x0 > x1 )
+ {
+ float tmp = x0;
+ x0 = x1;
+ x1 = tmp;
+ }
+
+ if ( x < x0 )
+ return x0-x;
+ else if ( x > x1 )
+ return x - x1;
+ return 0;
+}
+
+CBaseEntity *CBasePlayer::FindUseEntity()
+{
+ Vector forward, up;
+ EyeVectors( &forward, NULL, &up );
+
+ trace_t tr;
+ // Search for objects in a sphere (tests for entities that are not solid, yet still useable)
+ Vector searchCenter = EyePosition();
+
+ // NOTE: Some debris objects are useable too, so hit those as well
+ // A button, etc. can be made out of clip brushes, make sure it's +useable via a traceline, too.
+ int useableContents = MASK_SOLID | CONTENTS_DEBRIS | CONTENTS_PLAYERCLIP;
+
+#ifdef CSTRIKE_DLL
+ useableContents = MASK_NPCSOLID_BRUSHONLY | MASK_OPAQUE_AND_NPCS;
+#endif
+
+#ifdef HL1_DLL
+ useableContents = MASK_SOLID;
+#endif
+#ifndef CLIENT_DLL
+ CBaseEntity *pFoundByTrace = NULL;
+#endif
+
+ // UNDONE: Might be faster to just fold this range into the sphere query
+ CBaseEntity *pObject = NULL;
+
+ float nearestDist = FLT_MAX;
+ // try the hit entity if there is one, or the ground entity if there isn't.
+ CBaseEntity *pNearest = NULL;
+
+ const int NUM_TANGENTS = 8;
+ // trace a box at successive angles down
+ // forward, 45 deg, 30 deg, 20 deg, 15 deg, 10 deg, -10, -15
+ const float tangents[NUM_TANGENTS] = { 0, 1, 0.57735026919f, 0.3639702342f, 0.267949192431f, 0.1763269807f, -0.1763269807f, -0.267949192431f };
+ for ( int i = 0; i < NUM_TANGENTS; i++ )
+ {
+ if ( i == 0 )
+ {
+ UTIL_TraceLine( searchCenter, searchCenter + forward * 1024, useableContents, this, COLLISION_GROUP_NONE, &tr );
+ }
+ else
+ {
+ Vector down = forward - tangents[i]*up;
+ VectorNormalize(down);
+ UTIL_TraceHull( searchCenter, searchCenter + down * 72, -Vector(16,16,16), Vector(16,16,16), useableContents, this, COLLISION_GROUP_NONE, &tr );
+ }
+ pObject = tr.m_pEnt;
+
+#ifndef CLIENT_DLL
+ pFoundByTrace = pObject;
+#endif
+ bool bUsable = IsUseableEntity(pObject, 0);
+ while ( pObject && !bUsable && pObject->GetMoveParent() )
+ {
+ pObject = pObject->GetMoveParent();
+ bUsable = IsUseableEntity(pObject, 0);
+ }
+
+ if ( bUsable )
+ {
+ Vector delta = tr.endpos - tr.startpos;
+ float centerZ = CollisionProp()->WorldSpaceCenter().z;
+ delta.z = IntervalDistance( tr.endpos.z, centerZ + CollisionProp()->OBBMins().z, centerZ + CollisionProp()->OBBMaxs().z );
+ float dist = delta.Length();
+ if ( dist < PLAYER_USE_RADIUS )
+ {
+#ifndef CLIENT_DLL
+
+ if ( sv_debug_player_use.GetBool() )
+ {
+ NDebugOverlay::Line( searchCenter, tr.endpos, 0, 255, 0, true, 30 );
+ NDebugOverlay::Cross3D( tr.endpos, 16, 0, 255, 0, true, 30 );
+ }
+
+ if ( pObject->MyNPCPointer() && pObject->MyNPCPointer()->IsPlayerAlly( this ) )
+ {
+ // If about to select an NPC, do a more thorough check to ensure
+ // that we're selecting the right one from a group.
+ pObject = DoubleCheckUseNPC( pObject, searchCenter, forward );
+ }
+#endif
+ if ( sv_debug_player_use.GetBool() )
+ {
+ Msg( "Trace using: %s\n", pObject ? pObject->GetDebugName() : "no usable entity found" );
+ }
+
+ pNearest = pObject;
+
+ // if this is directly under the cursor just return it now
+ if ( i == 0 )
+ return pObject;
+ }
+ }
+ }
+
+ // check ground entity first
+ // if you've got a useable ground entity, then shrink the cone of this search to 45 degrees
+ // otherwise, search out in a 90 degree cone (hemisphere)
+ if ( GetGroundEntity() && IsUseableEntity(GetGroundEntity(), FCAP_USE_ONGROUND) )
+ {
+ pNearest = GetGroundEntity();
+ }
+ if ( pNearest )
+ {
+ // estimate nearest object by distance from the view vector
+ Vector point;
+ pNearest->CollisionProp()->CalcNearestPoint( searchCenter, &point );
+ nearestDist = CalcDistanceToLine( point, searchCenter, forward );
+ if ( sv_debug_player_use.GetBool() )
+ {
+ Msg("Trace found %s, dist %.2f\n", pNearest->GetClassname(), nearestDist );
+ }
+ }
+
+ for ( CEntitySphereQuery sphere( searchCenter, PLAYER_USE_RADIUS ); ( pObject = sphere.GetCurrentEntity() ) != NULL; sphere.NextEntity() )
+ {
+ if ( !pObject )
+ continue;
+
+ if ( !IsUseableEntity( pObject, FCAP_USE_IN_RADIUS ) )
+ continue;
+
+ // see if it's more roughly in front of the player than previous guess
+ Vector point;
+ pObject->CollisionProp()->CalcNearestPoint( searchCenter, &point );
+
+ Vector dir = point - searchCenter;
+ VectorNormalize(dir);
+ float dot = DotProduct( dir, forward );
+
+ // Need to be looking at the object more or less
+ if ( dot < 0.8 )
+ continue;
+
+ float dist = CalcDistanceToLine( point, searchCenter, forward );
+
+ if ( sv_debug_player_use.GetBool() )
+ {
+ Msg("Radius found %s, dist %.2f\n", pObject->GetClassname(), dist );
+ }
+
+ if ( dist < nearestDist )
+ {
+ // Since this has purely been a radius search to this point, we now
+ // make sure the object isn't behind glass or a grate.
+ trace_t trCheckOccluded;
+ UTIL_TraceLine( searchCenter, point, useableContents, this, COLLISION_GROUP_NONE, &trCheckOccluded );
+
+ if ( trCheckOccluded.fraction == 1.0 || trCheckOccluded.m_pEnt == pObject )
+ {
+ pNearest = pObject;
+ nearestDist = dist;
+ }
+ }
+ }
+
+#ifndef CLIENT_DLL
+ if ( !pNearest )
+ {
+ // Haven't found anything near the player to use, nor any NPC's at distance.
+ // Check to see if the player is trying to select an NPC through a rail, fence, or other 'see-though' volume.
+ trace_t trAllies;
+ UTIL_TraceLine( searchCenter, searchCenter + forward * PLAYER_USE_RADIUS, MASK_OPAQUE_AND_NPCS, this, COLLISION_GROUP_NONE, &trAllies );
+
+ if ( trAllies.m_pEnt && IsUseableEntity( trAllies.m_pEnt, 0 ) && trAllies.m_pEnt->MyNPCPointer() && trAllies.m_pEnt->MyNPCPointer()->IsPlayerAlly( this ) )
+ {
+ // This is an NPC, take it!
+ pNearest = trAllies.m_pEnt;
+ }
+ }
+
+ if ( pNearest && pNearest->MyNPCPointer() && pNearest->MyNPCPointer()->IsPlayerAlly( this ) )
+ {
+ pNearest = DoubleCheckUseNPC( pNearest, searchCenter, forward );
+ }
+
+ if ( sv_debug_player_use.GetBool() )
+ {
+ if ( !pNearest )
+ {
+ NDebugOverlay::Line( searchCenter, tr.endpos, 255, 0, 0, true, 30 );
+ NDebugOverlay::Cross3D( tr.endpos, 16, 255, 0, 0, true, 30 );
+ }
+ else if ( pNearest == pFoundByTrace )
+ {
+ NDebugOverlay::Line( searchCenter, tr.endpos, 0, 255, 0, true, 30 );
+ NDebugOverlay::Cross3D( tr.endpos, 16, 0, 255, 0, true, 30 );
+ }
+ else
+ {
+ NDebugOverlay::Box( pNearest->WorldSpaceCenter(), Vector(-8, -8, -8), Vector(8, 8, 8), 0, 255, 0, true, 30 );
+ }
+ }
+#endif
+
+ if ( sv_debug_player_use.GetBool() )
+ {
+ Msg( "Radial using: %s\n", pNearest ? pNearest->GetDebugName() : "no usable entity found" );
+ }
+
+ return pNearest;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Handles USE keypress
+//-----------------------------------------------------------------------------
+void CBasePlayer::PlayerUse ( void )
+{
+#ifdef GAME_DLL
+ // Was use pressed or released?
+ if ( ! ((m_nButtons | m_afButtonPressed | m_afButtonReleased) & IN_USE) )
+ return;
+
+ if ( IsObserver() )
+ {
+ // do special use operation in oberserver mode
+ if ( m_afButtonPressed & IN_USE )
+ ObserverUse( true );
+ else if ( m_afButtonReleased & IN_USE )
+ ObserverUse( false );
+
+ return;
+ }
+
+#if !defined(_XBOX)
+ // push objects in turbo physics mode
+ if ( (m_nButtons & IN_USE) && sv_turbophysics.GetBool() )
+ {
+ Vector forward, up;
+ EyeVectors( &forward, NULL, &up );
+
+ trace_t tr;
+ // Search for objects in a sphere (tests for entities that are not solid, yet still useable)
+ Vector searchCenter = EyePosition();
+
+ CUsePushFilter filter;
+
+ UTIL_TraceLine( searchCenter, searchCenter + forward * 96.0f, MASK_SOLID, &filter, &tr );
+
+ // try the hit entity if there is one, or the ground entity if there isn't.
+ CBaseEntity *entity = tr.m_pEnt;
+
+ if ( entity )
+ {
+ IPhysicsObject *pObj = entity->VPhysicsGetObject();
+
+ if ( pObj )
+ {
+ Vector vPushAway = (entity->WorldSpaceCenter() - WorldSpaceCenter());
+ vPushAway.z = 0;
+
+ float flDist = VectorNormalize( vPushAway );
+ flDist = MAX( flDist, 1 );
+
+ float flForce = sv_pushaway_force.GetFloat() / flDist;
+ flForce = MIN( flForce, sv_pushaway_max_force.GetFloat() );
+
+ pObj->ApplyForceOffset( vPushAway * flForce, WorldSpaceCenter() );
+ }
+ }
+ }
+#endif
+
+ if ( m_afButtonPressed & IN_USE )
+ {
+ // Controlling some latched entity?
+ if ( ClearUseEntity() )
+ {
+ return;
+ }
+ else
+ {
+ if ( m_afPhysicsFlags & PFLAG_DIROVERRIDE )
+ {
+ m_afPhysicsFlags &= ~PFLAG_DIROVERRIDE;
+ m_iTrain = TRAIN_NEW|TRAIN_OFF;
+ return;
+ }
+ else
+ { // Start controlling the train!
+ CBaseEntity *pTrain = GetGroundEntity();
+ if ( pTrain && !(m_nButtons & IN_JUMP) && (GetFlags() & FL_ONGROUND) && (pTrain->ObjectCaps() & FCAP_DIRECTIONAL_USE) && pTrain->OnControls(this) )
+ {
+ m_afPhysicsFlags |= PFLAG_DIROVERRIDE;
+ m_iTrain = TrainSpeed(pTrain->m_flSpeed, ((CFuncTrackTrain*)pTrain)->GetMaxSpeed());
+ m_iTrain |= TRAIN_NEW;
+ EmitSound( "Player.UseTrain" );
+ return;
+ }
+ }
+ }
+ }
+
+ CBaseEntity *pUseEntity = FindUseEntity();
+
+ // Found an object
+ if ( pUseEntity )
+ {
+
+ //!!!UNDONE: traceline here to prevent +USEing buttons through walls
+
+ int caps = pUseEntity->ObjectCaps();
+ variant_t emptyVariant;
+ if ( ( (m_nButtons & IN_USE) && (caps & FCAP_CONTINUOUS_USE) ) || ( (m_afButtonPressed & IN_USE) && (caps & (FCAP_IMPULSE_USE|FCAP_ONOFF_USE)) ) )
+ {
+ if ( caps & FCAP_CONTINUOUS_USE )
+ {
+ m_afPhysicsFlags |= PFLAG_USING;
+ }
+
+ if ( pUseEntity->ObjectCaps() & FCAP_ONOFF_USE )
+ {
+ pUseEntity->AcceptInput( "Use", this, this, emptyVariant, USE_ON );
+ }
+ else
+ {
+ pUseEntity->AcceptInput( "Use", this, this, emptyVariant, USE_TOGGLE );
+ }
+ }
+ // UNDONE: Send different USE codes for ON/OFF. Cache last ONOFF_USE object to send 'off' if you turn away
+ else if ( (m_afButtonReleased & IN_USE) && (pUseEntity->ObjectCaps() & FCAP_ONOFF_USE) ) // BUGBUG This is an "off" use
+ {
+ pUseEntity->AcceptInput( "Use", this, this, emptyVariant, USE_OFF );
+ }
+ }
+ else if ( m_afButtonPressed & IN_USE )
+ {
+ PlayUseDenySound();
+ }
+#endif
+}
+
+ConVar sv_suppress_viewpunch( "sv_suppress_viewpunch", "0", FCVAR_REPLICATED | FCVAR_CHEAT | FCVAR_DEVELOPMENTONLY );
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBasePlayer::ViewPunch( const QAngle &angleOffset )
+{
+ //See if we're suppressing the view punching
+ if ( sv_suppress_viewpunch.GetBool() )
+ return;
+
+ // We don't allow view kicks in the vehicle
+ if ( IsInAVehicle() )
+ return;
+
+ m_Local.m_vecPunchAngleVel += angleOffset * 20;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBasePlayer::ViewPunchReset( float tolerance )
+{
+ if ( tolerance != 0 )
+ {
+ tolerance *= tolerance; // square
+ float check = m_Local.m_vecPunchAngleVel->LengthSqr() + m_Local.m_vecPunchAngle->LengthSqr();
+ if ( check > tolerance )
+ return;
+ }
+ m_Local.m_vecPunchAngle = vec3_angle;
+ m_Local.m_vecPunchAngleVel = vec3_angle;
+}
+
+#if defined( CLIENT_DLL )
+
+#include "iviewrender.h"
+#include "ivieweffects.h"
+
+#endif
+
+static ConVar smoothstairs( "smoothstairs", "1", FCVAR_REPLICATED, "Smooth player eye z coordinate when traversing stairs." );
+
+//-----------------------------------------------------------------------------
+// Handle view smoothing when going up or down stairs
+//-----------------------------------------------------------------------------
+void CBasePlayer::SmoothViewOnStairs( Vector& eyeOrigin )
+{
+ CBaseEntity *pGroundEntity = GetGroundEntity();
+ float flCurrentPlayerZ = GetLocalOrigin().z;
+ float flCurrentPlayerViewOffsetZ = GetViewOffset().z;
+
+ // Smooth out stair step ups
+ // NOTE: Don't want to do this when the ground entity is moving the player
+ if ( ( pGroundEntity != NULL && pGroundEntity->GetMoveType() == MOVETYPE_NONE ) && ( flCurrentPlayerZ != m_flOldPlayerZ ) && smoothstairs.GetBool() &&
+ m_flOldPlayerViewOffsetZ == flCurrentPlayerViewOffsetZ )
+ {
+ int dir = ( flCurrentPlayerZ > m_flOldPlayerZ ) ? 1 : -1;
+
+ float steptime = gpGlobals->frametime;
+ if (steptime < 0)
+ {
+ steptime = 0;
+ }
+
+ m_flOldPlayerZ += steptime * 150 * dir;
+
+ const float stepSize = 18.0f;
+
+ if ( dir > 0 )
+ {
+ if (m_flOldPlayerZ > flCurrentPlayerZ)
+ {
+ m_flOldPlayerZ = flCurrentPlayerZ;
+ }
+ if (flCurrentPlayerZ - m_flOldPlayerZ > stepSize)
+ {
+ m_flOldPlayerZ = flCurrentPlayerZ - stepSize;
+ }
+ }
+ else
+ {
+ if (m_flOldPlayerZ < flCurrentPlayerZ)
+ {
+ m_flOldPlayerZ = flCurrentPlayerZ;
+ }
+ if (flCurrentPlayerZ - m_flOldPlayerZ < -stepSize)
+ {
+ m_flOldPlayerZ = flCurrentPlayerZ + stepSize;
+ }
+ }
+
+ eyeOrigin[2] += m_flOldPlayerZ - flCurrentPlayerZ;
+ }
+ else
+ {
+ m_flOldPlayerZ = flCurrentPlayerZ;
+ m_flOldPlayerViewOffsetZ = flCurrentPlayerViewOffsetZ;
+ }
+}
+
+static bool IsWaterContents( int contents )
+{
+ if ( contents & MASK_WATER )
+ return true;
+
+// if ( contents & CONTENTS_TESTFOGVOLUME )
+// return true;
+
+ return false;
+}
+
+void CBasePlayer::ResetObserverMode()
+{
+
+ m_hObserverTarget.Set( 0 );
+ m_iObserverMode = (int)OBS_MODE_NONE;
+
+#ifndef CLIENT_DLL
+ m_iObserverLastMode = OBS_MODE_ROAMING;
+ m_bForcedObserverMode = false;
+ m_afPhysicsFlags &= ~PFLAG_OBSERVER;
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : eyeOrigin -
+// eyeAngles -
+// zNear -
+// zFar -
+// fov -
+//-----------------------------------------------------------------------------
+void CBasePlayer::CalcView( Vector &eyeOrigin, QAngle &eyeAngles, float &zNear, float &zFar, float &fov )
+{
+#if defined( CLIENT_DLL )
+ IClientVehicle *pVehicle;
+#else
+ IServerVehicle *pVehicle;
+#endif
+ pVehicle = GetVehicle();
+
+ if ( !pVehicle )
+ {
+#if defined( CLIENT_DLL )
+ if( UseVR() )
+ g_ClientVirtualReality.CancelTorsoTransformOverride();
+#endif
+
+ if ( IsObserver() )
+ {
+ CalcObserverView( eyeOrigin, eyeAngles, fov );
+ }
+ else
+ {
+ CalcPlayerView( eyeOrigin, eyeAngles, fov );
+ }
+ }
+ else
+ {
+ CalcVehicleView( pVehicle, eyeOrigin, eyeAngles, zNear, zFar, fov );
+ }
+ // NVNT update fov on the haptics dll for input scaling.
+#if defined( CLIENT_DLL )
+ if(IsLocalPlayer() && haptics)
+ haptics->UpdatePlayerFOV(fov);
+#endif
+}
+
+
+void CBasePlayer::CalcViewModelView( const Vector& eyeOrigin, const QAngle& eyeAngles)
+{
+ for ( int i = 0; i < MAX_VIEWMODELS; i++ )
+ {
+ CBaseViewModel *vm = GetViewModel( i );
+ if ( !vm )
+ continue;
+
+ vm->CalcViewModelView( this, eyeOrigin, eyeAngles );
+ }
+}
+
+void CBasePlayer::CalcPlayerView( Vector& eyeOrigin, QAngle& eyeAngles, float& fov )
+{
+#if defined( CLIENT_DLL )
+ if ( !prediction->InPrediction() )
+ {
+ // FIXME: Move into prediction
+ view->DriftPitch();
+ }
+#endif
+
+ VectorCopy( EyePosition(), eyeOrigin );
+#ifdef SIXENSE
+ if ( g_pSixenseInput->IsEnabled() )
+ {
+ VectorCopy( EyeAngles() + GetEyeAngleOffset(), eyeAngles );
+ }
+ else
+ {
+ VectorCopy( EyeAngles(), eyeAngles );
+ }
+#else
+ VectorCopy( EyeAngles(), eyeAngles );
+#endif
+
+#if defined( CLIENT_DLL )
+ if ( !prediction->InPrediction() )
+#endif
+ {
+ SmoothViewOnStairs( eyeOrigin );
+ }
+
+ // Snack off the origin before bob + water offset are applied
+ Vector vecBaseEyePosition = eyeOrigin;
+
+ CalcViewRoll( eyeAngles );
+
+ // Apply punch angle
+ VectorAdd( eyeAngles, m_Local.m_vecPunchAngle, eyeAngles );
+
+#if defined( CLIENT_DLL )
+ if ( !prediction->InPrediction() )
+ {
+ // Shake it up baby!
+ vieweffects->CalcShake();
+ vieweffects->ApplyShake( eyeOrigin, eyeAngles, 1.0 );
+ }
+#endif
+
+#if defined( CLIENT_DLL )
+ // Apply a smoothing offset to smooth out prediction errors.
+ Vector vSmoothOffset;
+ GetPredictionErrorSmoothingVector( vSmoothOffset );
+ eyeOrigin += vSmoothOffset;
+ m_flObserverChaseDistance = 0.0;
+#endif
+
+ // calc current FOV
+ fov = GetFOV();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: The main view setup function for vehicles
+//-----------------------------------------------------------------------------
+void CBasePlayer::CalcVehicleView(
+#if defined( CLIENT_DLL )
+ IClientVehicle *pVehicle,
+#else
+ IServerVehicle *pVehicle,
+#endif
+ Vector& eyeOrigin, QAngle& eyeAngles,
+ float& zNear, float& zFar, float& fov )
+{
+ Assert( pVehicle );
+
+ // Start with our base origin and angles
+ CacheVehicleView();
+ eyeOrigin = m_vecVehicleViewOrigin;
+ eyeAngles = m_vecVehicleViewAngles;
+
+#if defined( CLIENT_DLL )
+
+ fov = GetFOV();
+
+ // Allows the vehicle to change the clip planes
+ pVehicle->GetVehicleClipPlanes( zNear, zFar );
+#endif
+
+ // Snack off the origin before bob + water offset are applied
+ Vector vecBaseEyePosition = eyeOrigin;
+
+ CalcViewRoll( eyeAngles );
+
+ // Apply punch angle
+ VectorAdd( eyeAngles, m_Local.m_vecPunchAngle, eyeAngles );
+
+#if defined( CLIENT_DLL )
+ if ( !prediction->InPrediction() )
+ {
+ // Shake it up baby!
+ vieweffects->CalcShake();
+ vieweffects->ApplyShake( eyeOrigin, eyeAngles, 1.0 );
+ }
+#endif
+
+}
+
+
+void CBasePlayer::CalcObserverView( Vector& eyeOrigin, QAngle& eyeAngles, float& fov )
+{
+#if defined( CLIENT_DLL )
+ switch ( GetObserverMode() )
+ {
+
+ case OBS_MODE_DEATHCAM : CalcDeathCamView( eyeOrigin, eyeAngles, fov );
+ break;
+
+ case OBS_MODE_ROAMING : // just copy current position without view offset
+ case OBS_MODE_FIXED : CalcRoamingView( eyeOrigin, eyeAngles, fov );
+ break;
+
+ case OBS_MODE_IN_EYE : CalcInEyeCamView( eyeOrigin, eyeAngles, fov );
+ break;
+
+ case OBS_MODE_CHASE : CalcChaseCamView( eyeOrigin, eyeAngles, fov );
+ break;
+
+ case OBS_MODE_FREEZECAM : CalcFreezeCamView( eyeOrigin, eyeAngles, fov );
+ break;
+ }
+#else
+ // on server just copy target postions, final view positions will be calculated on client
+ VectorCopy( EyePosition(), eyeOrigin );
+ VectorCopy( EyeAngles(), eyeAngles );
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Compute roll angle for a particular lateral velocity
+// Input : angles -
+// velocity -
+// rollangle -
+// rollspeed -
+// Output : float CViewRender::CalcRoll
+//-----------------------------------------------------------------------------
+float CBasePlayer::CalcRoll (const QAngle& angles, const Vector& velocity, float rollangle, float rollspeed)
+{
+ float sign;
+ float side;
+ float value;
+
+ Vector forward, right, up;
+
+ AngleVectors (angles, &forward, &right, &up);
+
+ // Get amount of lateral movement
+ side = DotProduct( velocity, right );
+ // Right or left side?
+ sign = side < 0 ? -1 : 1;
+ side = fabs(side);
+
+ value = rollangle;
+ // Hit 100% of rollangle at rollspeed. Below that get linear approx.
+ if ( side < rollspeed )
+ {
+ side = side * value / rollspeed;
+ }
+ else
+ {
+ side = value;
+ }
+
+ // Scale by right/left sign
+ return side*sign;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Determine view roll, including data kick
+//-----------------------------------------------------------------------------
+void CBasePlayer::CalcViewRoll( QAngle& eyeAngles )
+{
+ if ( GetMoveType() == MOVETYPE_NOCLIP )
+ return;
+
+ float side = CalcRoll( GetAbsAngles(), GetAbsVelocity(), sv_rollangle.GetFloat(), sv_rollspeed.GetFloat() );
+ eyeAngles[ROLL] += side;
+}
+
+
+void CBasePlayer::DoMuzzleFlash()
+{
+ for ( int i = 0; i < MAX_VIEWMODELS; i++ )
+ {
+ CBaseViewModel *vm = GetViewModel( i );
+ if ( !vm )
+ continue;
+
+ vm->DoMuzzleFlash();
+ }
+
+ BaseClass::DoMuzzleFlash();
+}
+
+
+float CBasePlayer::GetFOVDistanceAdjustFactor()
+{
+ float defaultFOV = (float)GetDefaultFOV();
+ float localFOV = (float)GetFOV();
+
+ if ( localFOV == defaultFOV || defaultFOV < 0.001f )
+ {
+ return 1.0f;
+ }
+
+ // If FOV is lower, then we're "zoomed" in and this will give a factor < 1 so apparent LOD distances can be
+ // shorted accordingly
+ return localFOV / defaultFOV;
+
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : &vecTracerSrc -
+// &tr -
+// iTracerType -
+//-----------------------------------------------------------------------------
+void CBasePlayer::MakeTracer( const Vector &vecTracerSrc, const trace_t &tr, int iTracerType )
+{
+ if ( GetActiveWeapon() )
+ {
+ GetActiveWeapon()->MakeTracer( vecTracerSrc, tr, iTracerType );
+ return;
+ }
+
+ BaseClass::MakeTracer( vecTracerSrc, tr, iTracerType );
+}
+
+
+void CBasePlayer::SharedSpawn()
+{
+ SetMoveType( MOVETYPE_WALK );
+ SetSolid( SOLID_BBOX );
+ AddSolidFlags( FSOLID_NOT_STANDABLE );
+ SetFriction( 1.0f );
+
+ pl.deadflag = false;
+ m_lifeState = LIFE_ALIVE;
+ m_iHealth = 100;
+ m_takedamage = DAMAGE_YES;
+
+ m_Local.m_bDrawViewmodel = true;
+ m_Local.m_flStepSize = sv_stepsize.GetFloat();
+ m_Local.m_bAllowAutoMovement = true;
+
+ m_nRenderFX = kRenderFxNone;
+ m_flNextAttack = gpGlobals->curtime;
+ m_flMaxspeed = 0.0f;
+
+ MDLCACHE_CRITICAL_SECTION();
+ SetSequence( SelectWeightedSequence( ACT_IDLE ) );
+
+ if ( GetFlags() & FL_DUCKING )
+ SetCollisionBounds( VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX );
+ else
+ SetCollisionBounds( VEC_HULL_MIN, VEC_HULL_MAX );
+
+ // dont let uninitialized value here hurt the player
+ m_Local.m_flFallVelocity = 0;
+
+ SetBloodColor( BLOOD_COLOR_RED );
+ // NVNT inform haptic dll we have just spawned local player
+#ifdef CLIENT_DLL
+ if(IsLocalPlayer() &&haptics)
+ haptics->LocalPlayerReset();
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : int
+//-----------------------------------------------------------------------------
+int CBasePlayer::GetDefaultFOV( void ) const
+{
+#if defined( CLIENT_DLL )
+ if ( GetObserverMode() == OBS_MODE_IN_EYE )
+ {
+ C_BasePlayer *pTargetPlayer = dynamic_cast<C_BasePlayer*>( GetObserverTarget() );
+
+ if ( pTargetPlayer && !pTargetPlayer->IsObserver() )
+ {
+ return pTargetPlayer->GetDefaultFOV();
+ }
+ }
+#endif
+
+ int iFOV = ( m_iDefaultFOV == 0 ) ? g_pGameRules->DefaultFOV() : m_iDefaultFOV;
+ if ( iFOV > MAX_FOV )
+ iFOV = MAX_FOV;
+
+ return iFOV;
+}
+
+void CBasePlayer::AvoidPhysicsProps( CUserCmd *pCmd )
+{
+#ifndef _XBOX
+ // Don't avoid if noclipping or in movetype none
+ switch ( GetMoveType() )
+ {
+ case MOVETYPE_NOCLIP:
+ case MOVETYPE_NONE:
+ case MOVETYPE_OBSERVER:
+ return;
+ default:
+ break;
+ }
+
+ if ( GetObserverMode() != OBS_MODE_NONE || !IsAlive() )
+ return;
+
+ AvoidPushawayProps( this, pCmd );
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : const char
+//-----------------------------------------------------------------------------
+const char *CBasePlayer::GetTracerType( void )
+{
+ if ( GetActiveWeapon() )
+ {
+ return GetActiveWeapon()->GetTracerType();
+ }
+
+ return BaseClass::GetTracerType();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBasePlayer::ClearZoomOwner( void )
+{
+ m_hZoomOwner = NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Sets the FOV of the client, doing interpolation between old and new if requested
+// Input : FOV - New FOV
+// zoomRate - Amount of time (in seconds) to move between old and new FOV
+//-----------------------------------------------------------------------------
+bool CBasePlayer::SetFOV( CBaseEntity *pRequester, int FOV, float zoomRate, int iZoomStart /* = 0 */ )
+{
+ //NOTENOTE: You MUST specify who is requesting the zoom change
+ assert( pRequester != NULL );
+ if ( pRequester == NULL )
+ return false;
+
+ // If we already have an owner, we only allow requests from that owner
+ if ( ( m_hZoomOwner.Get() != NULL ) && ( m_hZoomOwner.Get() != pRequester ) )
+ {
+#ifdef GAME_DLL
+ if ( CanOverrideEnvZoomOwner( m_hZoomOwner.Get() ) == false )
+#endif
+ return false;
+ }
+ else
+ {
+ //FIXME: Maybe do this is as an accessor instead
+ if ( FOV == 0 )
+ {
+ m_hZoomOwner = NULL;
+ }
+ else
+ {
+ m_hZoomOwner = pRequester;
+ }
+ }
+
+ // Setup our FOV and our scaling time
+
+ if ( iZoomStart > 0 )
+ {
+ m_iFOVStart = iZoomStart;
+ }
+ else
+ {
+ m_iFOVStart = GetFOV();
+ }
+
+ m_flFOVTime = gpGlobals->curtime;
+ m_iFOV = FOV;
+
+ m_Local.m_flFOVRate = zoomRate;
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBasePlayer::UpdateUnderwaterState( void )
+{
+ if ( GetWaterLevel() == WL_Eyes )
+ {
+ if ( IsPlayerUnderwater() == false )
+ {
+ SetPlayerUnderwater( true );
+ }
+ return;
+ }
+
+ if ( IsPlayerUnderwater() )
+ {
+ SetPlayerUnderwater( false );
+ }
+
+ if ( GetWaterLevel() == 0 )
+ {
+ if ( GetFlags() & FL_INWATER )
+ {
+#ifndef CLIENT_DLL
+ if ( m_iHealth > 0 && IsAlive() )
+ {
+ EmitSound( "Player.Wade" );
+ }
+#endif
+ RemoveFlag( FL_INWATER );
+ }
+ }
+ else if ( !(GetFlags() & FL_INWATER) )
+ {
+#ifndef CLIENT_DLL
+ // player enter water sound
+ if (GetWaterType() == CONTENTS_WATER)
+ {
+ EmitSound( "Player.Wade" );
+ }
+#endif
+
+ AddFlag( FL_INWATER );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: data accessor
+// ensure that for every emitsound there is a matching stopsound
+//-----------------------------------------------------------------------------
+void CBasePlayer::SetPlayerUnderwater( bool state )
+{
+ if ( m_bPlayerUnderwater != state )
+ {
+#if defined( WIN32 ) && !defined( _X360 )
+ // NVNT turn on haptic drag when underwater
+ if(state)
+ HapticSetDrag(this,1);
+ else
+ HapticSetDrag(this,0);
+#endif
+ m_bPlayerUnderwater = state;
+
+#ifdef CLIENT_DLL
+ if ( state )
+ EmitSound( "Player.AmbientUnderWater" );
+ else
+ StopSound( "Player.AmbientUnderWater" );
+#endif
+ }
+}
+
+
+void CBasePlayer::SetPreviouslyPredictedOrigin( const Vector &vecAbsOrigin )
+{
+ m_vecPreviouslyPredictedOrigin = vecAbsOrigin;
+}
+
+const Vector &CBasePlayer::GetPreviouslyPredictedOrigin() const
+{
+ return m_vecPreviouslyPredictedOrigin;
+}
+
+bool fogparams_t::operator !=( const fogparams_t& other ) const
+{
+ if ( this->enable != other.enable ||
+ this->blend != other.blend ||
+ !VectorsAreEqual(this->dirPrimary, other.dirPrimary, 0.01f ) ||
+ this->colorPrimary.Get() != other.colorPrimary.Get() ||
+ this->colorSecondary.Get() != other.colorSecondary.Get() ||
+ this->start != other.start ||
+ this->end != other.end ||
+ this->farz != other.farz ||
+ this->maxdensity != other.maxdensity ||
+ this->colorPrimaryLerpTo.Get() != other.colorPrimaryLerpTo.Get() ||
+ this->colorSecondaryLerpTo.Get() != other.colorSecondaryLerpTo.Get() ||
+ this->startLerpTo != other.startLerpTo ||
+ this->endLerpTo != other.endLerpTo ||
+ this->lerptime != other.lerptime ||
+ this->duration != other.duration )
+ return true;
+
+ return false;
+}
+