Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2097 lines
52 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Implements shared baseplayer class functionality
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "movevars_shared.h"
  9. #include "util_shared.h"
  10. #include "datacache/imdlcache.h"
  11. #if defined ( TF_DLL ) || defined ( TF_CLIENT_DLL )
  12. #include "tf_gamerules.h"
  13. #endif
  14. #if defined( CLIENT_DLL )
  15. #include "iclientvehicle.h"
  16. #include "prediction.h"
  17. #include "c_basedoor.h"
  18. #include "c_world.h"
  19. #include "view.h"
  20. #include "client_virtualreality.h"
  21. #define CRecipientFilter C_RecipientFilter
  22. #include "sourcevr/isourcevirtualreality.h"
  23. #else
  24. #include "iservervehicle.h"
  25. #include "trains.h"
  26. #include "world.h"
  27. #include "doors.h"
  28. #include "ai_basenpc.h"
  29. #include "env_zoom.h"
  30. extern int TrainSpeed(int iSpeed, int iMax);
  31. #endif
  32. #if defined( CSTRIKE_DLL )
  33. #include "weapon_c4.h"
  34. #endif // CSTRIKE_DLL
  35. #include "in_buttons.h"
  36. #include "engine/IEngineSound.h"
  37. #include "tier0/vprof.h"
  38. #include "SoundEmitterSystem/isoundemittersystembase.h"
  39. #include "decals.h"
  40. #include "obstacle_pushaway.h"
  41. #ifdef SIXENSE
  42. #include "sixense/in_sixense.h"
  43. #endif
  44. // NVNT haptic utils
  45. #include "haptics/haptic_utils.h"
  46. // memdbgon must be the last include file in a .cpp file!!!
  47. #include "tier0/memdbgon.h"
  48. #if defined(GAME_DLL) && !defined(_XBOX)
  49. extern ConVar sv_pushaway_max_force;
  50. extern ConVar sv_pushaway_force;
  51. extern ConVar sv_turbophysics;
  52. class CUsePushFilter : public CTraceFilterEntitiesOnly
  53. {
  54. public:
  55. bool ShouldHitEntity( IHandleEntity *pHandleEntity, int contentsMask )
  56. {
  57. CBaseEntity *pEntity = EntityFromEntityHandle( pHandleEntity );
  58. // Static prop case...
  59. if ( !pEntity )
  60. return false;
  61. // Only impact on physics objects
  62. if ( !pEntity->VPhysicsGetObject() )
  63. return false;
  64. #if defined( CSTRIKE_DLL )
  65. // don't push the bomb!
  66. if ( dynamic_cast<CC4*>( pEntity ) )
  67. return false;
  68. #endif // CSTRIKE_DLL
  69. return g_pGameRules->CanEntityBeUsePushed( pEntity );
  70. }
  71. };
  72. #endif
  73. #ifdef CLIENT_DLL
  74. 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
  75. #endif
  76. bool UseHWMorphModels()
  77. {
  78. // #ifdef CLIENT_DLL
  79. // if ( mp_usehwmmodels.GetInt() == 0 )
  80. // return g_pMaterialSystemHardwareConfig->HasFastVertexTextures();
  81. //
  82. // return mp_usehwmmodels.GetInt() > 0;
  83. // #else
  84. // return false;
  85. // #endif
  86. return false;
  87. }
  88. void CopySoundNameWithModifierToken( char *pchDest, const char *pchSource, int nMaxLenInChars, const char *pchToken )
  89. {
  90. // Copy the sound name
  91. int nSource = 0;
  92. int nDest = 0;
  93. bool bFoundPeriod = false;
  94. while ( pchSource[ nSource ] != '\0' && nDest < nMaxLenInChars - 2 )
  95. {
  96. pchDest[ nDest ] = pchSource[ nSource ];
  97. nDest++;
  98. nSource++;
  99. if ( !bFoundPeriod && pchSource[ nSource - 1 ] == '.' )
  100. {
  101. // Insert special token after the period
  102. bFoundPeriod = true;
  103. int nToken = 0;
  104. while ( pchToken[ nToken ] != '\0' && nDest < nMaxLenInChars - 2 )
  105. {
  106. pchDest[ nDest ] = pchToken[ nToken ];
  107. nDest++;
  108. nToken++;
  109. }
  110. }
  111. }
  112. pchDest[ nDest ] = '\0';
  113. }
  114. //-----------------------------------------------------------------------------
  115. // Purpose:
  116. // Output : float
  117. //-----------------------------------------------------------------------------
  118. float CBasePlayer::GetTimeBase( void ) const
  119. {
  120. return m_nTickBase * TICK_INTERVAL;
  121. }
  122. float CBasePlayer::GetPlayerMaxSpeed()
  123. {
  124. // player max speed is the lower limit of m_flMaxSpeed and sv_maxspeed
  125. float fMaxSpeed = sv_maxspeed.GetFloat();
  126. if ( MaxSpeed() > 0.0f && MaxSpeed() < fMaxSpeed )
  127. fMaxSpeed = MaxSpeed();
  128. return fMaxSpeed;
  129. }
  130. //-----------------------------------------------------------------------------
  131. // Purpose: Called every usercmd by the player PreThink
  132. //-----------------------------------------------------------------------------
  133. void CBasePlayer::ItemPreFrame()
  134. {
  135. // Handle use events
  136. PlayerUse();
  137. CBaseCombatWeapon *pActive = GetActiveWeapon();
  138. // Allow all the holstered weapons to update
  139. for ( int i = 0; i < WeaponCount(); ++i )
  140. {
  141. CBaseCombatWeapon *pWeapon = GetWeapon( i );
  142. if ( pWeapon == NULL )
  143. continue;
  144. if ( pActive == pWeapon )
  145. continue;
  146. pWeapon->ItemHolsterFrame();
  147. }
  148. if ( gpGlobals->curtime < m_flNextAttack )
  149. return;
  150. if (!pActive)
  151. return;
  152. #if defined( CLIENT_DLL )
  153. // Not predicting this weapon
  154. if ( !pActive->IsPredicted() )
  155. return;
  156. #endif
  157. pActive->ItemPreFrame();
  158. }
  159. //-----------------------------------------------------------------------------
  160. // Purpose:
  161. // Output : Returns true on success, false on failure.
  162. //-----------------------------------------------------------------------------
  163. bool CBasePlayer::UsingStandardWeaponsInVehicle( void )
  164. {
  165. Assert( IsInAVehicle() );
  166. #if !defined( CLIENT_DLL )
  167. IServerVehicle *pVehicle = GetVehicle();
  168. #else
  169. IClientVehicle *pVehicle = GetVehicle();
  170. #endif
  171. Assert( pVehicle );
  172. if ( !pVehicle )
  173. return true;
  174. // NOTE: We *have* to do this before ItemPostFrame because ItemPostFrame
  175. // may dump us out of the vehicle
  176. int nRole = pVehicle->GetPassengerRole( this );
  177. bool bUsingStandardWeapons = pVehicle->IsPassengerUsingStandardWeapons( nRole );
  178. // Fall through and check weapons, etc. if we're using them
  179. if (!bUsingStandardWeapons )
  180. return false;
  181. return true;
  182. }
  183. //-----------------------------------------------------------------------------
  184. // Purpose: Called every usercmd by the player PostThink
  185. //-----------------------------------------------------------------------------
  186. void CBasePlayer::ItemPostFrame()
  187. {
  188. VPROF( "CBasePlayer::ItemPostFrame" );
  189. // Put viewmodels into basically correct place based on new player origin
  190. CalcViewModelView( EyePosition(), EyeAngles() );
  191. // Don't process items while in a vehicle.
  192. if ( GetVehicle() )
  193. {
  194. #if defined( CLIENT_DLL )
  195. IClientVehicle *pVehicle = GetVehicle();
  196. #else
  197. IServerVehicle *pVehicle = GetVehicle();
  198. #endif
  199. bool bUsingStandardWeapons = UsingStandardWeaponsInVehicle();
  200. #if defined( CLIENT_DLL )
  201. if ( pVehicle->IsPredicted() )
  202. #endif
  203. {
  204. pVehicle->ItemPostFrame( this );
  205. }
  206. if (!bUsingStandardWeapons || !GetVehicle())
  207. return;
  208. }
  209. // check if the player is using something
  210. if ( m_hUseEntity != NULL )
  211. {
  212. #if !defined( CLIENT_DLL )
  213. Assert( !IsInAVehicle() );
  214. ImpulseCommands();// this will call playerUse
  215. #endif
  216. return;
  217. }
  218. if ( gpGlobals->curtime < m_flNextAttack )
  219. {
  220. if ( GetActiveWeapon() )
  221. {
  222. GetActiveWeapon()->ItemBusyFrame();
  223. }
  224. }
  225. else
  226. {
  227. if ( GetActiveWeapon() && (!IsInAVehicle() || UsingStandardWeaponsInVehicle()) )
  228. {
  229. #if defined( CLIENT_DLL )
  230. // Not predicting this weapon
  231. if ( GetActiveWeapon()->IsPredicted() )
  232. #endif
  233. {
  234. GetActiveWeapon()->ItemPostFrame( );
  235. }
  236. }
  237. }
  238. #if !defined( CLIENT_DLL )
  239. ImpulseCommands();
  240. #else
  241. // NOTE: If we ever support full impulse commands on the client,
  242. // remove this line and call ImpulseCommands instead.
  243. m_nImpulse = 0;
  244. #endif
  245. }
  246. //-----------------------------------------------------------------------------
  247. // Eye angles
  248. //-----------------------------------------------------------------------------
  249. const QAngle &CBasePlayer::EyeAngles( )
  250. {
  251. // NOTE: Viewangles are measured *relative* to the parent's coordinate system
  252. CBaseEntity *pMoveParent = const_cast<CBasePlayer*>(this)->GetMoveParent();
  253. if ( !pMoveParent )
  254. {
  255. return pl.v_angle;
  256. }
  257. // FIXME: Cache off the angles?
  258. matrix3x4_t eyesToParent, eyesToWorld;
  259. AngleMatrix( pl.v_angle, eyesToParent );
  260. ConcatTransforms( pMoveParent->EntityToWorldTransform(), eyesToParent, eyesToWorld );
  261. static QAngle angEyeWorld;
  262. MatrixAngles( eyesToWorld, angEyeWorld );
  263. return angEyeWorld;
  264. }
  265. const QAngle &CBasePlayer::LocalEyeAngles()
  266. {
  267. return pl.v_angle;
  268. }
  269. //-----------------------------------------------------------------------------
  270. // Actual Eye position + angles
  271. //-----------------------------------------------------------------------------
  272. Vector CBasePlayer::EyePosition( )
  273. {
  274. if ( GetVehicle() != NULL )
  275. {
  276. // Return the cached result
  277. CacheVehicleView();
  278. return m_vecVehicleViewOrigin;
  279. }
  280. else
  281. {
  282. #ifdef CLIENT_DLL
  283. if ( IsObserver() )
  284. {
  285. if ( GetObserverMode() == OBS_MODE_CHASE || GetObserverMode() == OBS_MODE_POI )
  286. {
  287. if ( IsLocalPlayer() )
  288. {
  289. return MainViewOrigin();
  290. }
  291. }
  292. }
  293. #endif
  294. return BaseClass::EyePosition();
  295. }
  296. }
  297. //-----------------------------------------------------------------------------
  298. // Purpose:
  299. // Input :
  300. // Output : const Vector
  301. //-----------------------------------------------------------------------------
  302. const Vector CBasePlayer::GetPlayerMins( void ) const
  303. {
  304. if ( IsObserver() )
  305. {
  306. return VEC_OBS_HULL_MIN_SCALED( this );
  307. }
  308. else
  309. {
  310. if ( GetFlags() & FL_DUCKING )
  311. {
  312. return VEC_DUCK_HULL_MIN_SCALED( this );
  313. }
  314. else
  315. {
  316. return VEC_HULL_MIN_SCALED( this );
  317. }
  318. }
  319. }
  320. //-----------------------------------------------------------------------------
  321. // Purpose:
  322. // Input :
  323. // Output : const Vector
  324. //-----------------------------------------------------------------------------
  325. const Vector CBasePlayer::GetPlayerMaxs( void ) const
  326. {
  327. if ( IsObserver() )
  328. {
  329. return VEC_OBS_HULL_MAX_SCALED( this );
  330. }
  331. else
  332. {
  333. if ( GetFlags() & FL_DUCKING )
  334. {
  335. return VEC_DUCK_HULL_MAX_SCALED( this );
  336. }
  337. else
  338. {
  339. return VEC_HULL_MAX_SCALED( this );
  340. }
  341. }
  342. }
  343. //-----------------------------------------------------------------------------
  344. // Purpose: Update the vehicle view, or simply return the cached position and angles
  345. //-----------------------------------------------------------------------------
  346. void CBasePlayer::CacheVehicleView( void )
  347. {
  348. // If we've calculated the view this frame, then there's no need to recalculate it
  349. if ( m_nVehicleViewSavedFrame == gpGlobals->framecount )
  350. return;
  351. #ifdef CLIENT_DLL
  352. IClientVehicle *pVehicle = GetVehicle();
  353. #else
  354. IServerVehicle *pVehicle = GetVehicle();
  355. #endif
  356. if ( pVehicle != NULL )
  357. {
  358. int nRole = pVehicle->GetPassengerRole( this );
  359. // Get our view for this frame
  360. pVehicle->GetVehicleViewPosition( nRole, &m_vecVehicleViewOrigin, &m_vecVehicleViewAngles, &m_flVehicleViewFOV );
  361. m_nVehicleViewSavedFrame = gpGlobals->framecount;
  362. #ifdef CLIENT_DLL
  363. if( UseVR() )
  364. {
  365. C_BaseAnimating *pVehicleAnimating = dynamic_cast<C_BaseAnimating *>( pVehicle );
  366. if( pVehicleAnimating )
  367. {
  368. int eyeAttachmentIndex = pVehicleAnimating->LookupAttachment( "vehicle_driver_eyes" );
  369. Vector vehicleEyeOrigin;
  370. QAngle vehicleEyeAngles;
  371. pVehicleAnimating->GetAttachment( eyeAttachmentIndex, vehicleEyeOrigin, vehicleEyeAngles );
  372. g_ClientVirtualReality.OverrideTorsoTransform( vehicleEyeOrigin, vehicleEyeAngles );
  373. }
  374. }
  375. #endif
  376. }
  377. }
  378. //-----------------------------------------------------------------------------
  379. // Returns eye vectors
  380. //-----------------------------------------------------------------------------
  381. void CBasePlayer::EyeVectors( Vector *pForward, Vector *pRight, Vector *pUp )
  382. {
  383. if ( GetVehicle() != NULL )
  384. {
  385. // Cache or retrieve our calculated position in the vehicle
  386. CacheVehicleView();
  387. AngleVectors( m_vecVehicleViewAngles, pForward, pRight, pUp );
  388. }
  389. else
  390. {
  391. AngleVectors( EyeAngles(), pForward, pRight, pUp );
  392. }
  393. }
  394. //-----------------------------------------------------------------------------
  395. // Purpose: Returns the eye position and angle vectors.
  396. //-----------------------------------------------------------------------------
  397. void CBasePlayer::EyePositionAndVectors( Vector *pPosition, Vector *pForward,
  398. Vector *pRight, Vector *pUp )
  399. {
  400. // Handle the view in the vehicle
  401. if ( GetVehicle() != NULL )
  402. {
  403. CacheVehicleView();
  404. AngleVectors( m_vecVehicleViewAngles, pForward, pRight, pUp );
  405. if ( pPosition != NULL )
  406. {
  407. *pPosition = m_vecVehicleViewOrigin;
  408. }
  409. }
  410. else
  411. {
  412. VectorCopy( BaseClass::EyePosition(), *pPosition );
  413. AngleVectors( EyeAngles(), pForward, pRight, pUp );
  414. }
  415. }
  416. #ifdef CLIENT_DLL
  417. surfacedata_t * CBasePlayer::GetFootstepSurface( const Vector &origin, const char *surfaceName )
  418. {
  419. return physprops->GetSurfaceData( physprops->GetSurfaceIndex( surfaceName ) );
  420. }
  421. #endif
  422. surfacedata_t *CBasePlayer::GetLadderSurface( const Vector &origin )
  423. {
  424. #ifdef CLIENT_DLL
  425. return GetFootstepSurface( origin, "ladder" );
  426. #else
  427. return physprops->GetSurfaceData( physprops->GetSurfaceIndex( "ladder" ) );
  428. #endif
  429. }
  430. void CBasePlayer::UpdateStepSound( surfacedata_t *psurface, const Vector &vecOrigin, const Vector &vecVelocity )
  431. {
  432. bool bWalking;
  433. float fvol;
  434. Vector knee;
  435. Vector feet;
  436. float height;
  437. float speed;
  438. float velrun;
  439. float velwalk;
  440. int fLadder;
  441. if ( m_flStepSoundTime > 0 )
  442. {
  443. m_flStepSoundTime -= 1000.0f * gpGlobals->frametime;
  444. if ( m_flStepSoundTime < 0 )
  445. {
  446. m_flStepSoundTime = 0;
  447. }
  448. }
  449. if ( m_flStepSoundTime > 0 )
  450. return;
  451. if ( GetFlags() & (FL_FROZEN|FL_ATCONTROLS))
  452. return;
  453. if ( GetMoveType() == MOVETYPE_NOCLIP || GetMoveType() == MOVETYPE_OBSERVER )
  454. return;
  455. if ( !sv_footsteps.GetFloat() )
  456. return;
  457. speed = VectorLength( vecVelocity );
  458. float groundspeed = Vector2DLength( vecVelocity.AsVector2D() );
  459. // determine if we are on a ladder
  460. fLadder = ( GetMoveType() == MOVETYPE_LADDER );
  461. GetStepSoundVelocities( &velwalk, &velrun );
  462. bool onground = ( GetFlags() & FL_ONGROUND );
  463. bool movingalongground = ( groundspeed > 0.0001f );
  464. bool moving_fast_enough = ( speed >= velwalk );
  465. #ifdef PORTAL
  466. // In Portal we MUST play footstep sounds even when the player is moving very slowly
  467. // This is used to count the number of footsteps they take in the challenge mode
  468. // -Jeep
  469. moving_fast_enough = true;
  470. #endif
  471. // To hear step sounds you must be either on a ladder or moving along the ground AND
  472. // You must be moving fast enough
  473. if ( !moving_fast_enough || !(fLadder || ( onground && movingalongground )) )
  474. return;
  475. // MoveHelper()->PlayerSetAnimation( PLAYER_WALK );
  476. bWalking = speed < velrun;
  477. VectorCopy( vecOrigin, knee );
  478. VectorCopy( vecOrigin, feet );
  479. height = GetPlayerMaxs()[ 2 ] - GetPlayerMins()[ 2 ];
  480. knee[2] = vecOrigin[2] + 0.2 * height;
  481. // find out what we're stepping in or on...
  482. if ( fLadder )
  483. {
  484. psurface = GetLadderSurface(vecOrigin);
  485. fvol = 0.5;
  486. SetStepSoundTime( STEPSOUNDTIME_ON_LADDER, bWalking );
  487. }
  488. #ifdef CSTRIKE_DLL
  489. else if ( enginetrace->GetPointContents( knee ) & MASK_WATER ) // we want to use the knee for Cstrike, not the waist
  490. #else
  491. else if ( GetWaterLevel() == WL_Waist )
  492. #endif // CSTRIKE_DLL
  493. {
  494. static int iSkipStep = 0;
  495. if ( iSkipStep == 0 )
  496. {
  497. iSkipStep++;
  498. return;
  499. }
  500. if ( iSkipStep++ == 3 )
  501. {
  502. iSkipStep = 0;
  503. }
  504. psurface = physprops->GetSurfaceData( physprops->GetSurfaceIndex( "wade" ) );
  505. fvol = 0.65;
  506. SetStepSoundTime( STEPSOUNDTIME_WATER_KNEE, bWalking );
  507. }
  508. else if ( GetWaterLevel() == WL_Feet )
  509. {
  510. psurface = physprops->GetSurfaceData( physprops->GetSurfaceIndex( "water" ) );
  511. fvol = bWalking ? 0.2 : 0.5;
  512. SetStepSoundTime( STEPSOUNDTIME_WATER_FOOT, bWalking );
  513. }
  514. else
  515. {
  516. if ( !psurface )
  517. return;
  518. SetStepSoundTime( STEPSOUNDTIME_NORMAL, bWalking );
  519. switch ( psurface->game.material )
  520. {
  521. default:
  522. case CHAR_TEX_CONCRETE:
  523. fvol = bWalking ? 0.2 : 0.5;
  524. break;
  525. case CHAR_TEX_METAL:
  526. fvol = bWalking ? 0.2 : 0.5;
  527. break;
  528. case CHAR_TEX_DIRT:
  529. fvol = bWalking ? 0.25 : 0.55;
  530. break;
  531. case CHAR_TEX_VENT:
  532. fvol = bWalking ? 0.4 : 0.7;
  533. break;
  534. case CHAR_TEX_GRATE:
  535. fvol = bWalking ? 0.2 : 0.5;
  536. break;
  537. case CHAR_TEX_TILE:
  538. fvol = bWalking ? 0.2 : 0.5;
  539. break;
  540. case CHAR_TEX_SLOSH:
  541. fvol = bWalking ? 0.2 : 0.5;
  542. break;
  543. }
  544. }
  545. // play the sound
  546. // 65% volume if ducking
  547. if ( GetFlags() & FL_DUCKING )
  548. {
  549. fvol *= 0.65;
  550. }
  551. PlayStepSound( feet, psurface, fvol, false );
  552. }
  553. //-----------------------------------------------------------------------------
  554. // Purpose:
  555. // Input : step -
  556. // fvol -
  557. // force - force sound to play
  558. //-----------------------------------------------------------------------------
  559. void CBasePlayer::PlayStepSound( Vector &vecOrigin, surfacedata_t *psurface, float fvol, bool force )
  560. {
  561. if ( gpGlobals->maxClients > 1 && !sv_footsteps.GetFloat() )
  562. return;
  563. #if defined( CLIENT_DLL )
  564. // during prediction play footstep sounds only once
  565. if ( prediction->InPrediction() && !prediction->IsFirstTimePredicted() )
  566. return;
  567. #endif
  568. if ( !psurface )
  569. return;
  570. int nSide = m_Local.m_nStepside;
  571. unsigned short stepSoundName = nSide ? psurface->sounds.stepleft : psurface->sounds.stepright;
  572. if ( !stepSoundName )
  573. return;
  574. m_Local.m_nStepside = !nSide;
  575. CSoundParameters params;
  576. Assert( nSide == 0 || nSide == 1 );
  577. if ( m_StepSoundCache[ nSide ].m_usSoundNameIndex == stepSoundName )
  578. {
  579. params = m_StepSoundCache[ nSide ].m_SoundParameters;
  580. }
  581. else
  582. {
  583. const char *pSoundName = MoveHelper()->GetSurfaceProps()->GetString( stepSoundName );
  584. // Give child classes an opportunity to override.
  585. pSoundName = GetOverrideStepSound( pSoundName );
  586. if ( !CBaseEntity::GetParametersForSound( pSoundName, params, NULL ) )
  587. return;
  588. // Only cache if there's one option. Otherwise we'd never here any other sounds
  589. if ( params.count == 1 )
  590. {
  591. m_StepSoundCache[ nSide ].m_usSoundNameIndex = stepSoundName;
  592. m_StepSoundCache[ nSide ].m_SoundParameters = params;
  593. }
  594. }
  595. CRecipientFilter filter;
  596. filter.AddRecipientsByPAS( vecOrigin );
  597. #ifndef CLIENT_DLL
  598. // in MP, server removes all players in the vecOrigin's PVS, these players generate the footsteps client side
  599. if ( gpGlobals->maxClients > 1 )
  600. {
  601. filter.RemoveRecipientsByPVS( vecOrigin );
  602. }
  603. #endif
  604. EmitSound_t ep;
  605. ep.m_nChannel = CHAN_BODY;
  606. ep.m_pSoundName = params.soundname;
  607. #if defined ( TF_DLL ) || defined ( TF_CLIENT_DLL )
  608. if( TFGameRules()->IsMannVsMachineMode() )
  609. {
  610. ep.m_flVolume = params.volume;
  611. }
  612. else
  613. {
  614. ep.m_flVolume = fvol;
  615. }
  616. #else
  617. ep.m_flVolume = fvol;
  618. #endif
  619. ep.m_SoundLevel = params.soundlevel;
  620. ep.m_nFlags = 0;
  621. ep.m_nPitch = params.pitch;
  622. ep.m_pOrigin = &vecOrigin;
  623. EmitSound( filter, entindex(), ep );
  624. // Kyle says: ugggh. This function may as well be called "PerformPileOfDesperateGameSpecificFootstepHacks".
  625. OnEmitFootstepSound( params, vecOrigin, fvol );
  626. }
  627. void CBasePlayer::UpdateButtonState( int nUserCmdButtonMask )
  628. {
  629. // Track button info so we can detect 'pressed' and 'released' buttons next frame
  630. m_afButtonLast = m_nButtons;
  631. // Get button states
  632. m_nButtons = nUserCmdButtonMask;
  633. int buttonsChanged = m_afButtonLast ^ m_nButtons;
  634. // Debounced button codes for pressed/released
  635. // UNDONE: Do we need auto-repeat?
  636. m_afButtonPressed = buttonsChanged & m_nButtons; // The changed ones still down are "pressed"
  637. m_afButtonReleased = buttonsChanged & (~m_nButtons); // The ones not down are "released"
  638. }
  639. //-----------------------------------------------------------------------------
  640. // Purpose:
  641. //-----------------------------------------------------------------------------
  642. void CBasePlayer::GetStepSoundVelocities( float *velwalk, float *velrun )
  643. {
  644. // UNDONE: need defined numbers for run, walk, crouch, crouch run velocities!!!!
  645. if ( ( GetFlags() & FL_DUCKING) || ( GetMoveType() == MOVETYPE_LADDER ) )
  646. {
  647. *velwalk = 60; // These constants should be based on cl_movespeedkey * cl_forwardspeed somehow
  648. *velrun = 80;
  649. }
  650. else
  651. {
  652. *velwalk = 90;
  653. *velrun = 220;
  654. }
  655. }
  656. //-----------------------------------------------------------------------------
  657. // Purpose:
  658. //-----------------------------------------------------------------------------
  659. void CBasePlayer::SetStepSoundTime( stepsoundtimes_t iStepSoundTime, bool bWalking )
  660. {
  661. switch ( iStepSoundTime )
  662. {
  663. case STEPSOUNDTIME_NORMAL:
  664. case STEPSOUNDTIME_WATER_FOOT:
  665. m_flStepSoundTime = bWalking ? 400 : 300;
  666. break;
  667. case STEPSOUNDTIME_ON_LADDER:
  668. m_flStepSoundTime = 350;
  669. break;
  670. case STEPSOUNDTIME_WATER_KNEE:
  671. m_flStepSoundTime = 600;
  672. break;
  673. default:
  674. Assert(0);
  675. break;
  676. }
  677. // UNDONE: need defined numbers for run, walk, crouch, crouch run velocities!!!!
  678. if ( ( GetFlags() & FL_DUCKING) || ( GetMoveType() == MOVETYPE_LADDER ) )
  679. {
  680. m_flStepSoundTime += 100;
  681. }
  682. }
  683. Vector CBasePlayer::Weapon_ShootPosition( )
  684. {
  685. return EyePosition();
  686. }
  687. void CBasePlayer::SetAnimationExtension( const char *pExtension )
  688. {
  689. Q_strncpy( m_szAnimExtension, pExtension, sizeof(m_szAnimExtension) );
  690. }
  691. //-----------------------------------------------------------------------------
  692. // Purpose: Set the weapon to switch to when the player uses the 'lastinv' command
  693. //-----------------------------------------------------------------------------
  694. void CBasePlayer::Weapon_SetLast( CBaseCombatWeapon *pWeapon )
  695. {
  696. m_hLastWeapon = pWeapon;
  697. }
  698. //-----------------------------------------------------------------------------
  699. // Purpose: Override base class so player can reset autoaim
  700. // Input :
  701. // Output :
  702. //-----------------------------------------------------------------------------
  703. bool CBasePlayer::Weapon_Switch( CBaseCombatWeapon *pWeapon, int viewmodelindex /*=0*/ )
  704. {
  705. CBaseCombatWeapon *pLastWeapon = GetActiveWeapon();
  706. if ( BaseClass::Weapon_Switch( pWeapon, viewmodelindex ))
  707. {
  708. if ( pLastWeapon && Weapon_ShouldSetLast( pLastWeapon, GetActiveWeapon() ) )
  709. {
  710. Weapon_SetLast( pLastWeapon->GetLastWeapon() );
  711. }
  712. CBaseViewModel *pViewModel = GetViewModel( viewmodelindex );
  713. Assert( pViewModel );
  714. if ( pViewModel )
  715. pViewModel->RemoveEffects( EF_NODRAW );
  716. ResetAutoaim( );
  717. return true;
  718. }
  719. return false;
  720. }
  721. void CBasePlayer::SelectLastItem(void)
  722. {
  723. if ( m_hLastWeapon.Get() == NULL )
  724. return;
  725. if ( GetActiveWeapon() && !GetActiveWeapon()->CanHolster() )
  726. return;
  727. SelectItem( m_hLastWeapon.Get()->GetClassname(), m_hLastWeapon.Get()->GetSubType() );
  728. }
  729. //-----------------------------------------------------------------------------
  730. // Purpose: Abort any reloads we're in
  731. //-----------------------------------------------------------------------------
  732. void CBasePlayer::AbortReload( void )
  733. {
  734. if ( GetActiveWeapon() )
  735. {
  736. GetActiveWeapon()->AbortReload();
  737. }
  738. }
  739. #if !defined( NO_ENTITY_PREDICTION )
  740. void CBasePlayer::AddToPlayerSimulationList( CBaseEntity *other )
  741. {
  742. CHandle< CBaseEntity > h;
  743. h = other;
  744. // Already in list
  745. if ( m_SimulatedByThisPlayer.Find( h ) != m_SimulatedByThisPlayer.InvalidIndex() )
  746. return;
  747. Assert( other->IsPlayerSimulated() );
  748. m_SimulatedByThisPlayer.AddToTail( h );
  749. }
  750. //-----------------------------------------------------------------------------
  751. // Purpose: Fixme, this should occur if the player fails to drive simulation
  752. // often enough!!!
  753. // Input : *other -
  754. //-----------------------------------------------------------------------------
  755. void CBasePlayer::RemoveFromPlayerSimulationList( CBaseEntity *other )
  756. {
  757. if ( !other )
  758. return;
  759. Assert( other->IsPlayerSimulated() );
  760. Assert( other->GetSimulatingPlayer() == this );
  761. CHandle< CBaseEntity > h;
  762. h = other;
  763. m_SimulatedByThisPlayer.FindAndRemove( h );
  764. }
  765. void CBasePlayer::SimulatePlayerSimulatedEntities( void )
  766. {
  767. int c = m_SimulatedByThisPlayer.Count();
  768. int i;
  769. for ( i = c - 1; i >= 0; i-- )
  770. {
  771. CHandle< CBaseEntity > h;
  772. h = m_SimulatedByThisPlayer[ i ];
  773. CBaseEntity *e = h;
  774. if ( !e || !e->IsPlayerSimulated() )
  775. {
  776. m_SimulatedByThisPlayer.Remove( i );
  777. continue;
  778. }
  779. #if defined( CLIENT_DLL )
  780. if ( e->IsClientCreated() && prediction->InPrediction() && !prediction->IsFirstTimePredicted() )
  781. {
  782. continue;
  783. }
  784. #endif
  785. Assert( e->IsPlayerSimulated() );
  786. Assert( e->GetSimulatingPlayer() == this );
  787. e->PhysicsSimulate();
  788. }
  789. // Loop through all entities again, checking their untouch if flagged to do so
  790. c = m_SimulatedByThisPlayer.Count();
  791. for ( i = c - 1; i >= 0; i-- )
  792. {
  793. CHandle< CBaseEntity > h;
  794. h = m_SimulatedByThisPlayer[ i ];
  795. CBaseEntity *e = h;
  796. if ( !e || !e->IsPlayerSimulated() )
  797. {
  798. m_SimulatedByThisPlayer.Remove( i );
  799. continue;
  800. }
  801. #if defined( CLIENT_DLL )
  802. if ( e->IsClientCreated() && prediction->InPrediction() && !prediction->IsFirstTimePredicted() )
  803. {
  804. continue;
  805. }
  806. #endif
  807. Assert( e->IsPlayerSimulated() );
  808. Assert( e->GetSimulatingPlayer() == this );
  809. if ( !e->GetCheckUntouch() )
  810. continue;
  811. e->PhysicsCheckForEntityUntouch();
  812. }
  813. }
  814. //-----------------------------------------------------------------------------
  815. // Purpose:
  816. //-----------------------------------------------------------------------------
  817. void CBasePlayer::ClearPlayerSimulationList( void )
  818. {
  819. int c = m_SimulatedByThisPlayer.Size();
  820. int i;
  821. for ( i = c - 1; i >= 0; i-- )
  822. {
  823. CHandle< CBaseEntity > h;
  824. h = m_SimulatedByThisPlayer[ i ];
  825. CBaseEntity *e = h;
  826. if ( e )
  827. {
  828. e->UnsetPlayerSimulated();
  829. }
  830. }
  831. m_SimulatedByThisPlayer.RemoveAll();
  832. }
  833. #endif
  834. //-----------------------------------------------------------------------------
  835. // Purpose: Return true if we should allow selection of the specified item
  836. //-----------------------------------------------------------------------------
  837. bool CBasePlayer::Weapon_ShouldSelectItem( CBaseCombatWeapon *pWeapon )
  838. {
  839. return ( pWeapon != GetActiveWeapon() );
  840. }
  841. //-----------------------------------------------------------------------------
  842. // Purpose:
  843. //-----------------------------------------------------------------------------
  844. void CBasePlayer::SelectItem( const char *pstr, int iSubType )
  845. {
  846. if (!pstr)
  847. return;
  848. CBaseCombatWeapon *pItem = Weapon_OwnsThisType( pstr, iSubType );
  849. if (!pItem)
  850. return;
  851. if( GetObserverMode() != OBS_MODE_NONE )
  852. return;// Observers can't select things.
  853. if ( !Weapon_ShouldSelectItem( pItem ) )
  854. return;
  855. // FIX, this needs to queue them up and delay
  856. // Make sure the current weapon can be holstered
  857. if ( GetActiveWeapon() )
  858. {
  859. if ( !GetActiveWeapon()->CanHolster() && !pItem->ForceWeaponSwitch() )
  860. return;
  861. ResetAutoaim( );
  862. }
  863. Weapon_Switch( pItem );
  864. }
  865. //-----------------------------------------------------------------------------
  866. // Purpose:
  867. //-----------------------------------------------------------------------------
  868. 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" );
  869. float IntervalDistance( float x, float x0, float x1 )
  870. {
  871. // swap so x0 < x1
  872. if ( x0 > x1 )
  873. {
  874. float tmp = x0;
  875. x0 = x1;
  876. x1 = tmp;
  877. }
  878. if ( x < x0 )
  879. return x0-x;
  880. else if ( x > x1 )
  881. return x - x1;
  882. return 0;
  883. }
  884. CBaseEntity *CBasePlayer::FindUseEntity()
  885. {
  886. Vector forward, up;
  887. EyeVectors( &forward, NULL, &up );
  888. trace_t tr;
  889. // Search for objects in a sphere (tests for entities that are not solid, yet still useable)
  890. Vector searchCenter = EyePosition();
  891. // NOTE: Some debris objects are useable too, so hit those as well
  892. // A button, etc. can be made out of clip brushes, make sure it's +useable via a traceline, too.
  893. int useableContents = MASK_SOLID | CONTENTS_DEBRIS | CONTENTS_PLAYERCLIP;
  894. #ifdef CSTRIKE_DLL
  895. useableContents = MASK_NPCSOLID_BRUSHONLY | MASK_OPAQUE_AND_NPCS;
  896. #endif
  897. #ifdef HL1_DLL
  898. useableContents = MASK_SOLID;
  899. #endif
  900. #ifndef CLIENT_DLL
  901. CBaseEntity *pFoundByTrace = NULL;
  902. #endif
  903. // UNDONE: Might be faster to just fold this range into the sphere query
  904. CBaseEntity *pObject = NULL;
  905. float nearestDist = FLT_MAX;
  906. // try the hit entity if there is one, or the ground entity if there isn't.
  907. CBaseEntity *pNearest = NULL;
  908. const int NUM_TANGENTS = 8;
  909. // trace a box at successive angles down
  910. // forward, 45 deg, 30 deg, 20 deg, 15 deg, 10 deg, -10, -15
  911. const float tangents[NUM_TANGENTS] = { 0, 1, 0.57735026919f, 0.3639702342f, 0.267949192431f, 0.1763269807f, -0.1763269807f, -0.267949192431f };
  912. for ( int i = 0; i < NUM_TANGENTS; i++ )
  913. {
  914. if ( i == 0 )
  915. {
  916. UTIL_TraceLine( searchCenter, searchCenter + forward * 1024, useableContents, this, COLLISION_GROUP_NONE, &tr );
  917. }
  918. else
  919. {
  920. Vector down = forward - tangents[i]*up;
  921. VectorNormalize(down);
  922. UTIL_TraceHull( searchCenter, searchCenter + down * 72, -Vector(16,16,16), Vector(16,16,16), useableContents, this, COLLISION_GROUP_NONE, &tr );
  923. }
  924. pObject = tr.m_pEnt;
  925. #ifndef CLIENT_DLL
  926. pFoundByTrace = pObject;
  927. #endif
  928. bool bUsable = IsUseableEntity(pObject, 0);
  929. while ( pObject && !bUsable && pObject->GetMoveParent() )
  930. {
  931. pObject = pObject->GetMoveParent();
  932. bUsable = IsUseableEntity(pObject, 0);
  933. }
  934. if ( bUsable )
  935. {
  936. Vector delta = tr.endpos - tr.startpos;
  937. float centerZ = CollisionProp()->WorldSpaceCenter().z;
  938. delta.z = IntervalDistance( tr.endpos.z, centerZ + CollisionProp()->OBBMins().z, centerZ + CollisionProp()->OBBMaxs().z );
  939. float dist = delta.Length();
  940. if ( dist < PLAYER_USE_RADIUS )
  941. {
  942. #ifndef CLIENT_DLL
  943. if ( sv_debug_player_use.GetBool() )
  944. {
  945. NDebugOverlay::Line( searchCenter, tr.endpos, 0, 255, 0, true, 30 );
  946. NDebugOverlay::Cross3D( tr.endpos, 16, 0, 255, 0, true, 30 );
  947. }
  948. if ( pObject->MyNPCPointer() && pObject->MyNPCPointer()->IsPlayerAlly( this ) )
  949. {
  950. // If about to select an NPC, do a more thorough check to ensure
  951. // that we're selecting the right one from a group.
  952. pObject = DoubleCheckUseNPC( pObject, searchCenter, forward );
  953. }
  954. #endif
  955. if ( sv_debug_player_use.GetBool() )
  956. {
  957. Msg( "Trace using: %s\n", pObject ? pObject->GetDebugName() : "no usable entity found" );
  958. }
  959. pNearest = pObject;
  960. // if this is directly under the cursor just return it now
  961. if ( i == 0 )
  962. return pObject;
  963. }
  964. }
  965. }
  966. // check ground entity first
  967. // if you've got a useable ground entity, then shrink the cone of this search to 45 degrees
  968. // otherwise, search out in a 90 degree cone (hemisphere)
  969. if ( GetGroundEntity() && IsUseableEntity(GetGroundEntity(), FCAP_USE_ONGROUND) )
  970. {
  971. pNearest = GetGroundEntity();
  972. }
  973. if ( pNearest )
  974. {
  975. // estimate nearest object by distance from the view vector
  976. Vector point;
  977. pNearest->CollisionProp()->CalcNearestPoint( searchCenter, &point );
  978. nearestDist = CalcDistanceToLine( point, searchCenter, forward );
  979. if ( sv_debug_player_use.GetBool() )
  980. {
  981. Msg("Trace found %s, dist %.2f\n", pNearest->GetClassname(), nearestDist );
  982. }
  983. }
  984. for ( CEntitySphereQuery sphere( searchCenter, PLAYER_USE_RADIUS ); ( pObject = sphere.GetCurrentEntity() ) != NULL; sphere.NextEntity() )
  985. {
  986. if ( !pObject )
  987. continue;
  988. if ( !IsUseableEntity( pObject, FCAP_USE_IN_RADIUS ) )
  989. continue;
  990. // see if it's more roughly in front of the player than previous guess
  991. Vector point;
  992. pObject->CollisionProp()->CalcNearestPoint( searchCenter, &point );
  993. Vector dir = point - searchCenter;
  994. VectorNormalize(dir);
  995. float dot = DotProduct( dir, forward );
  996. // Need to be looking at the object more or less
  997. if ( dot < 0.8 )
  998. continue;
  999. float dist = CalcDistanceToLine( point, searchCenter, forward );
  1000. if ( sv_debug_player_use.GetBool() )
  1001. {
  1002. Msg("Radius found %s, dist %.2f\n", pObject->GetClassname(), dist );
  1003. }
  1004. if ( dist < nearestDist )
  1005. {
  1006. // Since this has purely been a radius search to this point, we now
  1007. // make sure the object isn't behind glass or a grate.
  1008. trace_t trCheckOccluded;
  1009. UTIL_TraceLine( searchCenter, point, useableContents, this, COLLISION_GROUP_NONE, &trCheckOccluded );
  1010. if ( trCheckOccluded.fraction == 1.0 || trCheckOccluded.m_pEnt == pObject )
  1011. {
  1012. pNearest = pObject;
  1013. nearestDist = dist;
  1014. }
  1015. }
  1016. }
  1017. #ifndef CLIENT_DLL
  1018. if ( !pNearest )
  1019. {
  1020. // Haven't found anything near the player to use, nor any NPC's at distance.
  1021. // Check to see if the player is trying to select an NPC through a rail, fence, or other 'see-though' volume.
  1022. trace_t trAllies;
  1023. UTIL_TraceLine( searchCenter, searchCenter + forward * PLAYER_USE_RADIUS, MASK_OPAQUE_AND_NPCS, this, COLLISION_GROUP_NONE, &trAllies );
  1024. if ( trAllies.m_pEnt && IsUseableEntity( trAllies.m_pEnt, 0 ) && trAllies.m_pEnt->MyNPCPointer() && trAllies.m_pEnt->MyNPCPointer()->IsPlayerAlly( this ) )
  1025. {
  1026. // This is an NPC, take it!
  1027. pNearest = trAllies.m_pEnt;
  1028. }
  1029. }
  1030. if ( pNearest && pNearest->MyNPCPointer() && pNearest->MyNPCPointer()->IsPlayerAlly( this ) )
  1031. {
  1032. pNearest = DoubleCheckUseNPC( pNearest, searchCenter, forward );
  1033. }
  1034. if ( sv_debug_player_use.GetBool() )
  1035. {
  1036. if ( !pNearest )
  1037. {
  1038. NDebugOverlay::Line( searchCenter, tr.endpos, 255, 0, 0, true, 30 );
  1039. NDebugOverlay::Cross3D( tr.endpos, 16, 255, 0, 0, true, 30 );
  1040. }
  1041. else if ( pNearest == pFoundByTrace )
  1042. {
  1043. NDebugOverlay::Line( searchCenter, tr.endpos, 0, 255, 0, true, 30 );
  1044. NDebugOverlay::Cross3D( tr.endpos, 16, 0, 255, 0, true, 30 );
  1045. }
  1046. else
  1047. {
  1048. NDebugOverlay::Box( pNearest->WorldSpaceCenter(), Vector(-8, -8, -8), Vector(8, 8, 8), 0, 255, 0, true, 30 );
  1049. }
  1050. }
  1051. #endif
  1052. if ( sv_debug_player_use.GetBool() )
  1053. {
  1054. Msg( "Radial using: %s\n", pNearest ? pNearest->GetDebugName() : "no usable entity found" );
  1055. }
  1056. return pNearest;
  1057. }
  1058. //-----------------------------------------------------------------------------
  1059. // Purpose: Handles USE keypress
  1060. //-----------------------------------------------------------------------------
  1061. void CBasePlayer::PlayerUse ( void )
  1062. {
  1063. #ifdef GAME_DLL
  1064. // Was use pressed or released?
  1065. if ( ! ((m_nButtons | m_afButtonPressed | m_afButtonReleased) & IN_USE) )
  1066. return;
  1067. if ( IsObserver() )
  1068. {
  1069. // do special use operation in oberserver mode
  1070. if ( m_afButtonPressed & IN_USE )
  1071. ObserverUse( true );
  1072. else if ( m_afButtonReleased & IN_USE )
  1073. ObserverUse( false );
  1074. return;
  1075. }
  1076. #if !defined(_XBOX)
  1077. // push objects in turbo physics mode
  1078. if ( (m_nButtons & IN_USE) && sv_turbophysics.GetBool() )
  1079. {
  1080. Vector forward, up;
  1081. EyeVectors( &forward, NULL, &up );
  1082. trace_t tr;
  1083. // Search for objects in a sphere (tests for entities that are not solid, yet still useable)
  1084. Vector searchCenter = EyePosition();
  1085. CUsePushFilter filter;
  1086. UTIL_TraceLine( searchCenter, searchCenter + forward * 96.0f, MASK_SOLID, &filter, &tr );
  1087. // try the hit entity if there is one, or the ground entity if there isn't.
  1088. CBaseEntity *entity = tr.m_pEnt;
  1089. if ( entity )
  1090. {
  1091. IPhysicsObject *pObj = entity->VPhysicsGetObject();
  1092. if ( pObj )
  1093. {
  1094. Vector vPushAway = (entity->WorldSpaceCenter() - WorldSpaceCenter());
  1095. vPushAway.z = 0;
  1096. float flDist = VectorNormalize( vPushAway );
  1097. flDist = MAX( flDist, 1 );
  1098. float flForce = sv_pushaway_force.GetFloat() / flDist;
  1099. flForce = MIN( flForce, sv_pushaway_max_force.GetFloat() );
  1100. pObj->ApplyForceOffset( vPushAway * flForce, WorldSpaceCenter() );
  1101. }
  1102. }
  1103. }
  1104. #endif
  1105. if ( m_afButtonPressed & IN_USE )
  1106. {
  1107. // Controlling some latched entity?
  1108. if ( ClearUseEntity() )
  1109. {
  1110. return;
  1111. }
  1112. else
  1113. {
  1114. if ( m_afPhysicsFlags & PFLAG_DIROVERRIDE )
  1115. {
  1116. m_afPhysicsFlags &= ~PFLAG_DIROVERRIDE;
  1117. m_iTrain = TRAIN_NEW|TRAIN_OFF;
  1118. return;
  1119. }
  1120. else
  1121. { // Start controlling the train!
  1122. CBaseEntity *pTrain = GetGroundEntity();
  1123. if ( pTrain && !(m_nButtons & IN_JUMP) && (GetFlags() & FL_ONGROUND) && (pTrain->ObjectCaps() & FCAP_DIRECTIONAL_USE) && pTrain->OnControls(this) )
  1124. {
  1125. m_afPhysicsFlags |= PFLAG_DIROVERRIDE;
  1126. m_iTrain = TrainSpeed(pTrain->m_flSpeed, ((CFuncTrackTrain*)pTrain)->GetMaxSpeed());
  1127. m_iTrain |= TRAIN_NEW;
  1128. EmitSound( "Player.UseTrain" );
  1129. return;
  1130. }
  1131. }
  1132. }
  1133. }
  1134. CBaseEntity *pUseEntity = FindUseEntity();
  1135. // Found an object
  1136. if ( pUseEntity )
  1137. {
  1138. //!!!UNDONE: traceline here to prevent +USEing buttons through walls
  1139. int caps = pUseEntity->ObjectCaps();
  1140. variant_t emptyVariant;
  1141. if ( ( (m_nButtons & IN_USE) && (caps & FCAP_CONTINUOUS_USE) ) || ( (m_afButtonPressed & IN_USE) && (caps & (FCAP_IMPULSE_USE|FCAP_ONOFF_USE)) ) )
  1142. {
  1143. if ( caps & FCAP_CONTINUOUS_USE )
  1144. {
  1145. m_afPhysicsFlags |= PFLAG_USING;
  1146. }
  1147. if ( pUseEntity->ObjectCaps() & FCAP_ONOFF_USE )
  1148. {
  1149. pUseEntity->AcceptInput( "Use", this, this, emptyVariant, USE_ON );
  1150. }
  1151. else
  1152. {
  1153. pUseEntity->AcceptInput( "Use", this, this, emptyVariant, USE_TOGGLE );
  1154. }
  1155. }
  1156. // UNDONE: Send different USE codes for ON/OFF. Cache last ONOFF_USE object to send 'off' if you turn away
  1157. else if ( (m_afButtonReleased & IN_USE) && (pUseEntity->ObjectCaps() & FCAP_ONOFF_USE) ) // BUGBUG This is an "off" use
  1158. {
  1159. pUseEntity->AcceptInput( "Use", this, this, emptyVariant, USE_OFF );
  1160. }
  1161. }
  1162. else if ( m_afButtonPressed & IN_USE )
  1163. {
  1164. PlayUseDenySound();
  1165. }
  1166. #endif
  1167. }
  1168. ConVar sv_suppress_viewpunch( "sv_suppress_viewpunch", "0", FCVAR_REPLICATED | FCVAR_CHEAT | FCVAR_DEVELOPMENTONLY );
  1169. //-----------------------------------------------------------------------------
  1170. // Purpose:
  1171. //-----------------------------------------------------------------------------
  1172. void CBasePlayer::ViewPunch( const QAngle &angleOffset )
  1173. {
  1174. //See if we're suppressing the view punching
  1175. if ( sv_suppress_viewpunch.GetBool() )
  1176. return;
  1177. // We don't allow view kicks in the vehicle
  1178. if ( IsInAVehicle() )
  1179. return;
  1180. m_Local.m_vecPunchAngleVel += angleOffset * 20;
  1181. }
  1182. //-----------------------------------------------------------------------------
  1183. // Purpose:
  1184. //-----------------------------------------------------------------------------
  1185. void CBasePlayer::ViewPunchReset( float tolerance )
  1186. {
  1187. if ( tolerance != 0 )
  1188. {
  1189. tolerance *= tolerance; // square
  1190. float check = m_Local.m_vecPunchAngleVel->LengthSqr() + m_Local.m_vecPunchAngle->LengthSqr();
  1191. if ( check > tolerance )
  1192. return;
  1193. }
  1194. m_Local.m_vecPunchAngle = vec3_angle;
  1195. m_Local.m_vecPunchAngleVel = vec3_angle;
  1196. }
  1197. #if defined( CLIENT_DLL )
  1198. #include "iviewrender.h"
  1199. #include "ivieweffects.h"
  1200. #endif
  1201. static ConVar smoothstairs( "smoothstairs", "1", FCVAR_REPLICATED, "Smooth player eye z coordinate when traversing stairs." );
  1202. //-----------------------------------------------------------------------------
  1203. // Handle view smoothing when going up or down stairs
  1204. //-----------------------------------------------------------------------------
  1205. void CBasePlayer::SmoothViewOnStairs( Vector& eyeOrigin )
  1206. {
  1207. CBaseEntity *pGroundEntity = GetGroundEntity();
  1208. float flCurrentPlayerZ = GetLocalOrigin().z;
  1209. float flCurrentPlayerViewOffsetZ = GetViewOffset().z;
  1210. // Smooth out stair step ups
  1211. // NOTE: Don't want to do this when the ground entity is moving the player
  1212. if ( ( pGroundEntity != NULL && pGroundEntity->GetMoveType() == MOVETYPE_NONE ) && ( flCurrentPlayerZ != m_flOldPlayerZ ) && smoothstairs.GetBool() &&
  1213. m_flOldPlayerViewOffsetZ == flCurrentPlayerViewOffsetZ )
  1214. {
  1215. int dir = ( flCurrentPlayerZ > m_flOldPlayerZ ) ? 1 : -1;
  1216. float steptime = gpGlobals->frametime;
  1217. if (steptime < 0)
  1218. {
  1219. steptime = 0;
  1220. }
  1221. m_flOldPlayerZ += steptime * 150 * dir;
  1222. const float stepSize = 18.0f;
  1223. if ( dir > 0 )
  1224. {
  1225. if (m_flOldPlayerZ > flCurrentPlayerZ)
  1226. {
  1227. m_flOldPlayerZ = flCurrentPlayerZ;
  1228. }
  1229. if (flCurrentPlayerZ - m_flOldPlayerZ > stepSize)
  1230. {
  1231. m_flOldPlayerZ = flCurrentPlayerZ - stepSize;
  1232. }
  1233. }
  1234. else
  1235. {
  1236. if (m_flOldPlayerZ < flCurrentPlayerZ)
  1237. {
  1238. m_flOldPlayerZ = flCurrentPlayerZ;
  1239. }
  1240. if (flCurrentPlayerZ - m_flOldPlayerZ < -stepSize)
  1241. {
  1242. m_flOldPlayerZ = flCurrentPlayerZ + stepSize;
  1243. }
  1244. }
  1245. eyeOrigin[2] += m_flOldPlayerZ - flCurrentPlayerZ;
  1246. }
  1247. else
  1248. {
  1249. m_flOldPlayerZ = flCurrentPlayerZ;
  1250. m_flOldPlayerViewOffsetZ = flCurrentPlayerViewOffsetZ;
  1251. }
  1252. }
  1253. static bool IsWaterContents( int contents )
  1254. {
  1255. if ( contents & MASK_WATER )
  1256. return true;
  1257. // if ( contents & CONTENTS_TESTFOGVOLUME )
  1258. // return true;
  1259. return false;
  1260. }
  1261. void CBasePlayer::ResetObserverMode()
  1262. {
  1263. m_hObserverTarget.Set( 0 );
  1264. m_iObserverMode = (int)OBS_MODE_NONE;
  1265. #ifndef CLIENT_DLL
  1266. m_iObserverLastMode = OBS_MODE_ROAMING;
  1267. m_bForcedObserverMode = false;
  1268. m_afPhysicsFlags &= ~PFLAG_OBSERVER;
  1269. #endif
  1270. }
  1271. //-----------------------------------------------------------------------------
  1272. // Purpose:
  1273. // Input : eyeOrigin -
  1274. // eyeAngles -
  1275. // zNear -
  1276. // zFar -
  1277. // fov -
  1278. //-----------------------------------------------------------------------------
  1279. void CBasePlayer::CalcView( Vector &eyeOrigin, QAngle &eyeAngles, float &zNear, float &zFar, float &fov )
  1280. {
  1281. #if defined( CLIENT_DLL )
  1282. IClientVehicle *pVehicle;
  1283. #else
  1284. IServerVehicle *pVehicle;
  1285. #endif
  1286. pVehicle = GetVehicle();
  1287. if ( !pVehicle )
  1288. {
  1289. #if defined( CLIENT_DLL )
  1290. if( UseVR() )
  1291. g_ClientVirtualReality.CancelTorsoTransformOverride();
  1292. #endif
  1293. if ( IsObserver() )
  1294. {
  1295. CalcObserverView( eyeOrigin, eyeAngles, fov );
  1296. }
  1297. else
  1298. {
  1299. CalcPlayerView( eyeOrigin, eyeAngles, fov );
  1300. }
  1301. }
  1302. else
  1303. {
  1304. CalcVehicleView( pVehicle, eyeOrigin, eyeAngles, zNear, zFar, fov );
  1305. }
  1306. // NVNT update fov on the haptics dll for input scaling.
  1307. #if defined( CLIENT_DLL )
  1308. if(IsLocalPlayer() && haptics)
  1309. haptics->UpdatePlayerFOV(fov);
  1310. #endif
  1311. }
  1312. void CBasePlayer::CalcViewModelView( const Vector& eyeOrigin, const QAngle& eyeAngles)
  1313. {
  1314. for ( int i = 0; i < MAX_VIEWMODELS; i++ )
  1315. {
  1316. CBaseViewModel *vm = GetViewModel( i );
  1317. if ( !vm )
  1318. continue;
  1319. vm->CalcViewModelView( this, eyeOrigin, eyeAngles );
  1320. }
  1321. }
  1322. void CBasePlayer::CalcPlayerView( Vector& eyeOrigin, QAngle& eyeAngles, float& fov )
  1323. {
  1324. #if defined( CLIENT_DLL )
  1325. if ( !prediction->InPrediction() )
  1326. {
  1327. // FIXME: Move into prediction
  1328. view->DriftPitch();
  1329. }
  1330. #endif
  1331. VectorCopy( EyePosition(), eyeOrigin );
  1332. #ifdef SIXENSE
  1333. if ( g_pSixenseInput->IsEnabled() )
  1334. {
  1335. VectorCopy( EyeAngles() + GetEyeAngleOffset(), eyeAngles );
  1336. }
  1337. else
  1338. {
  1339. VectorCopy( EyeAngles(), eyeAngles );
  1340. }
  1341. #else
  1342. VectorCopy( EyeAngles(), eyeAngles );
  1343. #endif
  1344. #if defined( CLIENT_DLL )
  1345. if ( !prediction->InPrediction() )
  1346. #endif
  1347. {
  1348. SmoothViewOnStairs( eyeOrigin );
  1349. }
  1350. // Snack off the origin before bob + water offset are applied
  1351. Vector vecBaseEyePosition = eyeOrigin;
  1352. CalcViewRoll( eyeAngles );
  1353. // Apply punch angle
  1354. VectorAdd( eyeAngles, m_Local.m_vecPunchAngle, eyeAngles );
  1355. #if defined( CLIENT_DLL )
  1356. if ( !prediction->InPrediction() )
  1357. {
  1358. // Shake it up baby!
  1359. vieweffects->CalcShake();
  1360. vieweffects->ApplyShake( eyeOrigin, eyeAngles, 1.0 );
  1361. }
  1362. #endif
  1363. #if defined( CLIENT_DLL )
  1364. // Apply a smoothing offset to smooth out prediction errors.
  1365. Vector vSmoothOffset;
  1366. GetPredictionErrorSmoothingVector( vSmoothOffset );
  1367. eyeOrigin += vSmoothOffset;
  1368. m_flObserverChaseDistance = 0.0;
  1369. #endif
  1370. // calc current FOV
  1371. fov = GetFOV();
  1372. }
  1373. //-----------------------------------------------------------------------------
  1374. // Purpose: The main view setup function for vehicles
  1375. //-----------------------------------------------------------------------------
  1376. void CBasePlayer::CalcVehicleView(
  1377. #if defined( CLIENT_DLL )
  1378. IClientVehicle *pVehicle,
  1379. #else
  1380. IServerVehicle *pVehicle,
  1381. #endif
  1382. Vector& eyeOrigin, QAngle& eyeAngles,
  1383. float& zNear, float& zFar, float& fov )
  1384. {
  1385. Assert( pVehicle );
  1386. // Start with our base origin and angles
  1387. CacheVehicleView();
  1388. eyeOrigin = m_vecVehicleViewOrigin;
  1389. eyeAngles = m_vecVehicleViewAngles;
  1390. #if defined( CLIENT_DLL )
  1391. fov = GetFOV();
  1392. // Allows the vehicle to change the clip planes
  1393. pVehicle->GetVehicleClipPlanes( zNear, zFar );
  1394. #endif
  1395. // Snack off the origin before bob + water offset are applied
  1396. Vector vecBaseEyePosition = eyeOrigin;
  1397. CalcViewRoll( eyeAngles );
  1398. // Apply punch angle
  1399. VectorAdd( eyeAngles, m_Local.m_vecPunchAngle, eyeAngles );
  1400. #if defined( CLIENT_DLL )
  1401. if ( !prediction->InPrediction() )
  1402. {
  1403. // Shake it up baby!
  1404. vieweffects->CalcShake();
  1405. vieweffects->ApplyShake( eyeOrigin, eyeAngles, 1.0 );
  1406. }
  1407. #endif
  1408. }
  1409. void CBasePlayer::CalcObserverView( Vector& eyeOrigin, QAngle& eyeAngles, float& fov )
  1410. {
  1411. #if defined( CLIENT_DLL )
  1412. switch ( GetObserverMode() )
  1413. {
  1414. case OBS_MODE_DEATHCAM : CalcDeathCamView( eyeOrigin, eyeAngles, fov );
  1415. break;
  1416. case OBS_MODE_ROAMING : // just copy current position without view offset
  1417. case OBS_MODE_FIXED : CalcRoamingView( eyeOrigin, eyeAngles, fov );
  1418. break;
  1419. case OBS_MODE_IN_EYE : CalcInEyeCamView( eyeOrigin, eyeAngles, fov );
  1420. break;
  1421. case OBS_MODE_POI : // PASSTIME
  1422. case OBS_MODE_CHASE : CalcChaseCamView( eyeOrigin, eyeAngles, fov );
  1423. break;
  1424. case OBS_MODE_FREEZECAM : CalcFreezeCamView( eyeOrigin, eyeAngles, fov );
  1425. break;
  1426. }
  1427. #else
  1428. // on server just copy target postions, final view positions will be calculated on client
  1429. VectorCopy( EyePosition(), eyeOrigin );
  1430. VectorCopy( EyeAngles(), eyeAngles );
  1431. #endif
  1432. }
  1433. //-----------------------------------------------------------------------------
  1434. // Purpose: Compute roll angle for a particular lateral velocity
  1435. // Input : angles -
  1436. // velocity -
  1437. // rollangle -
  1438. // rollspeed -
  1439. // Output : float CViewRender::CalcRoll
  1440. //-----------------------------------------------------------------------------
  1441. float CBasePlayer::CalcRoll (const QAngle& angles, const Vector& velocity, float rollangle, float rollspeed)
  1442. {
  1443. float sign;
  1444. float side;
  1445. float value;
  1446. Vector forward, right, up;
  1447. AngleVectors (angles, &forward, &right, &up);
  1448. // Get amount of lateral movement
  1449. side = DotProduct( velocity, right );
  1450. // Right or left side?
  1451. sign = side < 0 ? -1 : 1;
  1452. side = fabs(side);
  1453. value = rollangle;
  1454. // Hit 100% of rollangle at rollspeed. Below that get linear approx.
  1455. if ( side < rollspeed )
  1456. {
  1457. side = side * value / rollspeed;
  1458. }
  1459. else
  1460. {
  1461. side = value;
  1462. }
  1463. // Scale by right/left sign
  1464. return side*sign;
  1465. }
  1466. //-----------------------------------------------------------------------------
  1467. // Purpose: Determine view roll, including data kick
  1468. //-----------------------------------------------------------------------------
  1469. void CBasePlayer::CalcViewRoll( QAngle& eyeAngles )
  1470. {
  1471. if ( GetMoveType() == MOVETYPE_NOCLIP )
  1472. return;
  1473. float side = CalcRoll( GetAbsAngles(), GetAbsVelocity(), sv_rollangle.GetFloat(), sv_rollspeed.GetFloat() );
  1474. eyeAngles[ROLL] += side;
  1475. }
  1476. void CBasePlayer::DoMuzzleFlash()
  1477. {
  1478. for ( int i = 0; i < MAX_VIEWMODELS; i++ )
  1479. {
  1480. CBaseViewModel *vm = GetViewModel( i );
  1481. if ( !vm )
  1482. continue;
  1483. vm->DoMuzzleFlash();
  1484. }
  1485. BaseClass::DoMuzzleFlash();
  1486. }
  1487. float CBasePlayer::GetFOVDistanceAdjustFactor()
  1488. {
  1489. float defaultFOV = (float)GetDefaultFOV();
  1490. float localFOV = (float)GetFOV();
  1491. if ( localFOV == defaultFOV || defaultFOV < 0.001f )
  1492. {
  1493. return 1.0f;
  1494. }
  1495. // If FOV is lower, then we're "zoomed" in and this will give a factor < 1 so apparent LOD distances can be
  1496. // shorted accordingly
  1497. return localFOV / defaultFOV;
  1498. }
  1499. //-----------------------------------------------------------------------------
  1500. // Purpose:
  1501. // Input : &vecTracerSrc -
  1502. // &tr -
  1503. // iTracerType -
  1504. //-----------------------------------------------------------------------------
  1505. void CBasePlayer::MakeTracer( const Vector &vecTracerSrc, const trace_t &tr, int iTracerType )
  1506. {
  1507. if ( GetActiveWeapon() )
  1508. {
  1509. GetActiveWeapon()->MakeTracer( vecTracerSrc, tr, iTracerType );
  1510. return;
  1511. }
  1512. BaseClass::MakeTracer( vecTracerSrc, tr, iTracerType );
  1513. }
  1514. void CBasePlayer::SharedSpawn()
  1515. {
  1516. SetMoveType( MOVETYPE_WALK );
  1517. SetSolid( SOLID_BBOX );
  1518. AddSolidFlags( FSOLID_NOT_STANDABLE );
  1519. SetFriction( 1.0f );
  1520. pl.deadflag = false;
  1521. m_lifeState = LIFE_ALIVE;
  1522. m_iHealth = 100;
  1523. m_takedamage = DAMAGE_YES;
  1524. m_Local.m_bDrawViewmodel = true;
  1525. m_Local.m_flStepSize = sv_stepsize.GetFloat();
  1526. m_Local.m_bAllowAutoMovement = true;
  1527. m_nRenderFX = kRenderFxNone;
  1528. m_flNextAttack = gpGlobals->curtime;
  1529. m_flMaxspeed = 0.0f;
  1530. MDLCACHE_CRITICAL_SECTION();
  1531. SetSequence( SelectWeightedSequence( ACT_IDLE ) );
  1532. if ( GetFlags() & FL_DUCKING )
  1533. SetCollisionBounds( VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX );
  1534. else
  1535. SetCollisionBounds( VEC_HULL_MIN, VEC_HULL_MAX );
  1536. // dont let uninitialized value here hurt the player
  1537. m_Local.m_flFallVelocity = 0;
  1538. SetBloodColor( BLOOD_COLOR_RED );
  1539. // NVNT inform haptic dll we have just spawned local player
  1540. #ifdef CLIENT_DLL
  1541. if(IsLocalPlayer() &&haptics)
  1542. haptics->LocalPlayerReset();
  1543. #endif
  1544. }
  1545. //-----------------------------------------------------------------------------
  1546. // Purpose:
  1547. //-----------------------------------------------------------------------------
  1548. bool CBasePlayer::IsLerpingFOV( void ) const
  1549. {
  1550. // If it's immediate, just do it
  1551. if (m_Local.m_flFOVRate == 0.0f)
  1552. return false;
  1553. float deltaTime = (float)(gpGlobals->curtime - m_flFOVTime) / m_Local.m_flFOVRate;
  1554. return deltaTime < 1.f;
  1555. }
  1556. //-----------------------------------------------------------------------------
  1557. // Purpose:
  1558. // Output : int
  1559. //-----------------------------------------------------------------------------
  1560. int CBasePlayer::GetDefaultFOV( void ) const
  1561. {
  1562. #if defined( CLIENT_DLL )
  1563. if ( GetObserverMode() == OBS_MODE_IN_EYE )
  1564. {
  1565. C_BasePlayer *pTargetPlayer = dynamic_cast<C_BasePlayer*>( GetObserverTarget() );
  1566. if ( pTargetPlayer && !pTargetPlayer->IsObserver() )
  1567. {
  1568. return pTargetPlayer->GetDefaultFOV();
  1569. }
  1570. }
  1571. #endif
  1572. int iFOV = ( m_iDefaultFOV == 0 ) ? g_pGameRules->DefaultFOV() : m_iDefaultFOV;
  1573. if ( iFOV > MAX_FOV )
  1574. iFOV = MAX_FOV;
  1575. return iFOV;
  1576. }
  1577. void CBasePlayer::AvoidPhysicsProps( CUserCmd *pCmd )
  1578. {
  1579. #ifndef _XBOX
  1580. // Don't avoid if noclipping or in movetype none
  1581. switch ( GetMoveType() )
  1582. {
  1583. case MOVETYPE_NOCLIP:
  1584. case MOVETYPE_NONE:
  1585. case MOVETYPE_OBSERVER:
  1586. return;
  1587. default:
  1588. break;
  1589. }
  1590. if ( GetObserverMode() != OBS_MODE_NONE || !IsAlive() )
  1591. return;
  1592. AvoidPushawayProps( this, pCmd );
  1593. #endif
  1594. }
  1595. //-----------------------------------------------------------------------------
  1596. // Purpose:
  1597. // Output : const char
  1598. //-----------------------------------------------------------------------------
  1599. const char *CBasePlayer::GetTracerType( void )
  1600. {
  1601. if ( GetActiveWeapon() )
  1602. {
  1603. return GetActiveWeapon()->GetTracerType();
  1604. }
  1605. return BaseClass::GetTracerType();
  1606. }
  1607. //-----------------------------------------------------------------------------
  1608. // Purpose:
  1609. //-----------------------------------------------------------------------------
  1610. void CBasePlayer::ClearZoomOwner( void )
  1611. {
  1612. m_hZoomOwner = NULL;
  1613. }
  1614. //-----------------------------------------------------------------------------
  1615. // Purpose: Sets the FOV of the client, doing interpolation between old and new if requested
  1616. // Input : FOV - New FOV
  1617. // zoomRate - Amount of time (in seconds) to move between old and new FOV
  1618. //-----------------------------------------------------------------------------
  1619. bool CBasePlayer::SetFOV( CBaseEntity *pRequester, int FOV, float zoomRate, int iZoomStart /* = 0 */ )
  1620. {
  1621. //NOTENOTE: You MUST specify who is requesting the zoom change
  1622. assert( pRequester != NULL );
  1623. if ( pRequester == NULL )
  1624. return false;
  1625. // If we already have an owner, we only allow requests from that owner
  1626. if ( ( m_hZoomOwner.Get() != NULL ) && ( m_hZoomOwner.Get() != pRequester ) )
  1627. {
  1628. #ifdef GAME_DLL
  1629. if ( CanOverrideEnvZoomOwner( m_hZoomOwner.Get() ) == false )
  1630. #endif
  1631. return false;
  1632. }
  1633. else
  1634. {
  1635. //FIXME: Maybe do this is as an accessor instead
  1636. if ( FOV == 0 )
  1637. {
  1638. m_hZoomOwner = NULL;
  1639. }
  1640. else
  1641. {
  1642. m_hZoomOwner = pRequester;
  1643. }
  1644. }
  1645. // Setup our FOV and our scaling time
  1646. if ( iZoomStart > 0 )
  1647. {
  1648. m_iFOVStart = iZoomStart;
  1649. }
  1650. else
  1651. {
  1652. m_iFOVStart = GetFOV();
  1653. }
  1654. m_flFOVTime = gpGlobals->curtime;
  1655. m_iFOV = FOV;
  1656. m_Local.m_flFOVRate = zoomRate;
  1657. return true;
  1658. }
  1659. //-----------------------------------------------------------------------------
  1660. // Purpose:
  1661. //-----------------------------------------------------------------------------
  1662. void CBasePlayer::UpdateUnderwaterState( void )
  1663. {
  1664. if ( GetWaterLevel() == WL_Eyes )
  1665. {
  1666. if ( IsPlayerUnderwater() == false )
  1667. {
  1668. SetPlayerUnderwater( true );
  1669. }
  1670. return;
  1671. }
  1672. if ( IsPlayerUnderwater() )
  1673. {
  1674. SetPlayerUnderwater( false );
  1675. }
  1676. if ( GetWaterLevel() == 0 )
  1677. {
  1678. if ( GetFlags() & FL_INWATER )
  1679. {
  1680. #ifndef CLIENT_DLL
  1681. if ( m_iHealth > 0 && IsAlive() )
  1682. {
  1683. EmitSound( "Player.Wade" );
  1684. }
  1685. #endif
  1686. RemoveFlag( FL_INWATER );
  1687. }
  1688. }
  1689. else if ( !(GetFlags() & FL_INWATER) )
  1690. {
  1691. #ifndef CLIENT_DLL
  1692. // player enter water sound
  1693. if (GetWaterType() == CONTENTS_WATER)
  1694. {
  1695. EmitSound( "Player.Wade" );
  1696. }
  1697. #endif
  1698. AddFlag( FL_INWATER );
  1699. }
  1700. }
  1701. //-----------------------------------------------------------------------------
  1702. // Purpose: data accessor
  1703. // ensure that for every emitsound there is a matching stopsound
  1704. //-----------------------------------------------------------------------------
  1705. void CBasePlayer::SetPlayerUnderwater( bool state )
  1706. {
  1707. if ( m_bPlayerUnderwater != state )
  1708. {
  1709. #if defined( WIN32 ) && !defined( _X360 )
  1710. // NVNT turn on haptic drag when underwater
  1711. if(state)
  1712. HapticSetDrag(this,1);
  1713. else
  1714. HapticSetDrag(this,0);
  1715. #endif
  1716. m_bPlayerUnderwater = state;
  1717. #ifdef CLIENT_DLL
  1718. if ( state )
  1719. EmitSound( "Player.AmbientUnderWater" );
  1720. else
  1721. StopSound( "Player.AmbientUnderWater" );
  1722. #endif
  1723. }
  1724. }
  1725. void CBasePlayer::SetPreviouslyPredictedOrigin( const Vector &vecAbsOrigin )
  1726. {
  1727. m_vecPreviouslyPredictedOrigin = vecAbsOrigin;
  1728. }
  1729. const Vector &CBasePlayer::GetPreviouslyPredictedOrigin() const
  1730. {
  1731. return m_vecPreviouslyPredictedOrigin;
  1732. }
  1733. bool fogparams_t::operator !=( const fogparams_t& other ) const
  1734. {
  1735. if ( this->enable != other.enable ||
  1736. this->blend != other.blend ||
  1737. !VectorsAreEqual(this->dirPrimary, other.dirPrimary, 0.01f ) ||
  1738. this->colorPrimary.Get() != other.colorPrimary.Get() ||
  1739. this->colorSecondary.Get() != other.colorSecondary.Get() ||
  1740. this->start != other.start ||
  1741. this->end != other.end ||
  1742. this->farz != other.farz ||
  1743. this->maxdensity != other.maxdensity ||
  1744. this->colorPrimaryLerpTo.Get() != other.colorPrimaryLerpTo.Get() ||
  1745. this->colorSecondaryLerpTo.Get() != other.colorSecondaryLerpTo.Get() ||
  1746. this->startLerpTo != other.startLerpTo ||
  1747. this->endLerpTo != other.endLerpTo ||
  1748. this->lerptime != other.lerptime ||
  1749. this->duration != other.duration )
  1750. return true;
  1751. return false;
  1752. }