From f56bb35301836e56582a575a75864392a0177875 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rgen=20P=2E=20Tjern=C3=B8?= Date: Mon, 2 Dec 2013 19:31:46 -0800 Subject: Fix line endings. WHAMMY. --- mp/src/game/shared/baseplayer_shared.cpp | 4168 +++++++++++++++--------------- 1 file changed, 2084 insertions(+), 2084 deletions(-) (limited to 'mp/src/game/shared/baseplayer_shared.cpp') 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( 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(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( 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( 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( 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(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( 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( 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; +} + -- cgit v1.2.3