Counter Strike : Global Offensive Source Code
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.

3541 lines
94 KiB

  1. //========= Copyright © 1996-2005, 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. #include "collisionutils.h"
  12. #include "vphysics/player_controller.h"
  13. #include "SoundEmitterSystem/isoundemittersystembase.h"
  14. #if defined CLIENT_DLL
  15. #define CPhysicsProp C_PhysicsProp
  16. #define CPhysBox C_PhysBox
  17. #define CCSPlayer C_CSPlayer
  18. #endif
  19. #if defined( CLIENT_DLL )
  20. #include "iclientvehicle.h"
  21. #include "prediction.h"
  22. #include "c_basedoor.h"
  23. #include "c_world.h"
  24. #include "view.h"
  25. #include "c_physicsprop.h"
  26. #include "c_physbox.h"
  27. #if defined( CSTRIKE15 )
  28. #include "weapon_selection.h"
  29. #include "c_cs_player.h"
  30. #endif
  31. #define CRecipientFilter C_RecipientFilter
  32. #else
  33. #include "iservervehicle.h"
  34. #include "trains.h"
  35. #include "world.h"
  36. #include "doors.h"
  37. #include "ai_basenpc.h"
  38. #include "env_zoom.h"
  39. #include "ammodef.h"
  40. #include "props.h"
  41. #include "physobj.h"
  42. #if defined( CSTRIKE15 )
  43. #include "weapon_c4.h"
  44. #include "cs_shareddefs.h"
  45. #include "cs_gamerules.h"
  46. #include "cs_player.h"
  47. #endif
  48. #if defined( PORTAL )
  49. #include "portal_player.h"
  50. #include "physicsshadowclone.h"
  51. #endif
  52. extern int TrainSpeed(int iSpeed, int iMax);
  53. #endif
  54. #include "in_buttons.h"
  55. #include "engine/IEngineSound.h"
  56. #include "tier0/vprof.h"
  57. #include "SoundEmitterSystem/isoundemittersystembase.h"
  58. #include "decals.h"
  59. #include "obstacle_pushaway.h"
  60. #include "igamemovement.h"
  61. #ifdef SIXENSE
  62. #include "sixense/in_sixense.h"
  63. #endif
  64. // memdbgon must be the last include file in a .cpp file!!!
  65. #include "tier0/memdbgon.h"
  66. //----------------------------------------------------
  67. // Player Physics Shadow
  68. //----------------------------------------------------
  69. #define VPHYS_MAX_DISTANCE 2.0
  70. #define VPHYS_MAX_VEL 10
  71. #define VPHYS_MAX_DISTSQR (VPHYS_MAX_DISTANCE*VPHYS_MAX_DISTANCE)
  72. #define VPHYS_MAX_VELSQR (VPHYS_MAX_VEL*VPHYS_MAX_VEL)
  73. #if defined( DEBUG_MOTION_CONTROLLERS )
  74. #if defined( GAME_DLL )
  75. unsigned char g_uColorValue = 255;
  76. #else
  77. unsigned char g_uColorValue = 128;
  78. #endif
  79. Vector g_vLastPos = vec3_origin;
  80. Vector g_vShift = vec3_origin;
  81. ConVar dbg_motionlinetime( "dbg_motionlinetime", "30.0", FCVAR_REPLICATED );
  82. void DebugVelocity( const char *szString, const Vector &vStart, const Vector &vEnd, uint8 iRed, uint8 iGreen, uint8 iBlue )
  83. {
  84. if( dbg_motionlinetime.GetFloat() < 0.0f )
  85. return;
  86. Vector vShift = g_vShift;
  87. #if defined( CLIENT_DLL )
  88. # if defined( KEEP_COMMAND_REPREDICTION_COUNT )
  89. vShift *= (1.0f + (float)prediction->GetRepredictionCount());
  90. # else
  91. vShift *= prediction->IsFirstTimePredicted() ? 1.0f : 2.0f;
  92. # endif
  93. iRed >>= 1;
  94. iGreen >>= 1;
  95. iBlue >>= 1;
  96. #endif
  97. NDebugOverlay::Line( vStart + vShift, vEnd + vShift, iRed, iGreen, iBlue, true, dbg_motionlinetime.GetFloat() );
  98. }
  99. void DebugBox( const char *szString, const Vector &vPos, const Vector &vSize, uint8 iRed, uint8 iGreen, uint8 iBlue, uint8 iAlpha )
  100. {
  101. if( dbg_motionlinetime.GetFloat() < 0.0f )
  102. return;
  103. Vector vShift = g_vShift;
  104. #if defined( CLIENT_DLL )
  105. # if defined( KEEP_COMMAND_REPREDICTION_COUNT )
  106. vShift *= (1.0f + (float)prediction->GetRepredictionCount());
  107. # else
  108. vShift *= prediction->IsFirstTimePredicted() ? 1.0f : 2.0f;
  109. # endif
  110. iRed >>= 1;
  111. iGreen >>= 1;
  112. iBlue >>= 1;
  113. #endif
  114. NDebugOverlay::Box( vPos + vShift, -vSize, vSize, iRed, iGreen, iBlue, iAlpha, dbg_motionlinetime.GetFloat() );
  115. }
  116. #endif
  117. ConVar sv_infinite_ammo( "sv_infinite_ammo", "0", FCVAR_RELEASE | FCVAR_REPLICATED, "Player's active weapon will never run out of ammo. If set to 2 then player has infinite total ammo but still has to reload the magazine." );
  118. ConVar view_punch_decay( "view_punch_decay", "18", FCVAR_RELEASE | FCVAR_CHEAT | FCVAR_REPLICATED, "Decay factor exponent for view punch" );
  119. ConVar view_recoil_tracking( "view_recoil_tracking", "0.45", FCVAR_RELEASE | FCVAR_CHEAT | FCVAR_REPLICATED, "How closely the view tracks with the aim punch from weapon recoil" );
  120. ConVar sv_footstep_sound_frequency( "sv_footstep_sound_frequency", "0.97", FCVAR_CHEAT | FCVAR_REPLICATED, "How frequent to hear the player's step sound or how fast they appear to be running from first person." );
  121. #if defined(GAME_DLL)
  122. static ConVar physicsshadowupdate_render( "physicsshadowupdate_render", "0" );
  123. extern ConVar sv_pushaway_max_force;
  124. extern ConVar sv_pushaway_force;
  125. extern ConVar sv_turbophysics;
  126. class CUsePushFilter : public CTraceFilterEntitiesOnly
  127. {
  128. public:
  129. bool ShouldHitEntity( IHandleEntity *pHandleEntity, int contentsMask )
  130. {
  131. CBaseEntity *pEntity = EntityFromEntityHandle( pHandleEntity );
  132. // Static prop case...
  133. if ( !pEntity )
  134. return false;
  135. // Only impact on physics objects
  136. if ( !pEntity->VPhysicsGetObject() )
  137. return false;
  138. return g_pGameRules->CanEntityBeUsePushed( pEntity );
  139. }
  140. };
  141. #else
  142. static ConVar physicsshadowupdate_render( "cl_physicsshadowupdate_render", "0" );
  143. ConVar cl_shadowupdatespacing( "cl_shadowupdatespacing", "10.0" );
  144. ConVar cl_predict_motioncontrol( "cl_predict_motioncontrol", "0" );
  145. #endif
  146. #ifdef CLIENT_DLL
  147. 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
  148. #endif
  149. extern ConVar sv_turbophysics;
  150. extern CMoveData *g_pMoveData;
  151. extern ConVar sv_coaching_enabled;
  152. bool UseHWMorphModels()
  153. {
  154. #ifdef CLIENT_DLL
  155. if ( mp_usehwmmodels.GetInt() == 0 )
  156. return g_pMaterialSystemHardwareConfig->HasFastVertexTextures();
  157. return mp_usehwmmodels.GetInt() > 0;
  158. #else
  159. return false;
  160. #endif
  161. }
  162. //-----------------------------------------------------------------------------
  163. // Purpose:
  164. // Output : float
  165. //-----------------------------------------------------------------------------
  166. float CBasePlayer::GetTimeBase( void ) const
  167. {
  168. return m_nTickBase * TICK_INTERVAL;
  169. }
  170. float CBasePlayer::GetPlayerMaxSpeed()
  171. {
  172. // player max speed is the lower limit of m_flMaxSpeed and sv_maxspeed
  173. float fMaxSpeed = sv_maxspeed.GetFloat();
  174. if ( MaxSpeed() > 0.0f && MaxSpeed() < fMaxSpeed )
  175. fMaxSpeed = MaxSpeed();
  176. return fMaxSpeed;
  177. }
  178. //-----------------------------------------------------------------------------
  179. // Purpose: Called every usercmd by the player PreThink
  180. //-----------------------------------------------------------------------------
  181. void CBasePlayer::ItemPreFrame()
  182. {
  183. // Handle use events
  184. PlayerUse();
  185. CBaseCombatWeapon *pActive = GetActiveWeapon();
  186. // Allow all the holstered weapons to update
  187. for ( int i = 0; i < WeaponCount(); ++i )
  188. {
  189. CBaseCombatWeapon *pWeapon = GetWeapon( i );
  190. if ( pWeapon == NULL )
  191. continue;
  192. if ( pActive == pWeapon )
  193. continue;
  194. pWeapon->ItemHolsterFrame();
  195. }
  196. if ( gpGlobals->curtime < m_flNextAttack )
  197. return;
  198. if (!pActive)
  199. return;
  200. #if defined( CLIENT_DLL )
  201. // Not predicting this weapon
  202. if ( !pActive->IsPredicted() )
  203. return;
  204. #endif
  205. pActive->ItemPreFrame();
  206. }
  207. //-----------------------------------------------------------------------------
  208. // Purpose:
  209. // Output : Returns true on success, false on failure.
  210. //-----------------------------------------------------------------------------
  211. bool CBasePlayer::UsingStandardWeaponsInVehicle( void )
  212. {
  213. Assert( IsInAVehicle() );
  214. #if !defined( CLIENT_DLL )
  215. IServerVehicle *pVehicle = GetVehicle();
  216. #else
  217. IClientVehicle *pVehicle = GetVehicle();
  218. #endif
  219. Assert( pVehicle );
  220. if ( !pVehicle )
  221. return true;
  222. // NOTE: We *have* to do this before ItemPostFrame because ItemPostFrame
  223. // may dump us out of the vehicle
  224. int nRole = pVehicle->GetPassengerRole( this );
  225. bool bUsingStandardWeapons = pVehicle->IsPassengerUsingStandardWeapons( nRole );
  226. // Fall through and check weapons, etc. if we're using them
  227. if (!bUsingStandardWeapons )
  228. return false;
  229. return true;
  230. }
  231. //-----------------------------------------------------------------------------
  232. // Purpose: Called every usercmd by the player PostThink
  233. //-----------------------------------------------------------------------------
  234. void CBasePlayer::ItemPostFrame()
  235. {
  236. VPROF( "CBasePlayer::ItemPostFrame" );
  237. // Put viewmodels into basically correct place based on new player origin
  238. CalcViewModelView( EyePosition(), EyeAngles() );
  239. // Don't process items while in a vehicle.
  240. if ( GetVehicle() )
  241. {
  242. #if defined( CLIENT_DLL )
  243. IClientVehicle *pVehicle = GetVehicle();
  244. #else
  245. IServerVehicle *pVehicle = GetVehicle();
  246. #endif
  247. bool bUsingStandardWeapons = UsingStandardWeaponsInVehicle();
  248. #if defined( CLIENT_DLL )
  249. if ( pVehicle->IsPredicted() )
  250. #endif
  251. {
  252. pVehicle->ItemPostFrame( this );
  253. }
  254. if (!bUsingStandardWeapons || !GetVehicle())
  255. return;
  256. }
  257. // check if the player is using something
  258. if ( m_hUseEntity != NULL )
  259. {
  260. #if !defined( CLIENT_DLL )
  261. Assert( !IsInAVehicle() );
  262. ImpulseCommands();// this will call playerUse
  263. #endif
  264. return;
  265. }
  266. if ( gpGlobals->curtime < m_flNextAttack )
  267. {
  268. if ( GetActiveWeapon() )
  269. {
  270. GetActiveWeapon()->ItemBusyFrame();
  271. }
  272. }
  273. else
  274. {
  275. if ( GetActiveWeapon() && (!IsInAVehicle() || UsingStandardWeaponsInVehicle()) )
  276. {
  277. #if defined( CLIENT_DLL )
  278. // Not predicting this weapon
  279. if ( GetActiveWeapon()->IsPredicted() )
  280. #endif
  281. {
  282. GetActiveWeapon()->ItemPostFrame( );
  283. }
  284. }
  285. }
  286. #if defined( GAME_DLL )
  287. ImpulseCommands();
  288. #else
  289. // NOTE: If we ever support full impulse commands on the client,
  290. // remove this line and call ImpulseCommands instead.
  291. m_nImpulse = 0;
  292. #endif
  293. extern ConVar sv_infinite_ammo;
  294. if( ( sv_infinite_ammo.GetInt() == 1 ) && (GetActiveWeapon() != NULL) )
  295. {
  296. CBaseCombatWeapon *pWeapon = GetActiveWeapon();
  297. pWeapon->m_iClip1 = pWeapon->GetMaxClip1();
  298. pWeapon->m_iClip2 = pWeapon->GetMaxClip2();
  299. #if defined( GAME_DLL )
  300. if ( pWeapon->GetWpnData().iFlags & ITEM_FLAG_EXHAUSTIBLE )
  301. {
  302. int iPrimaryAmmoType = pWeapon->GetPrimaryAmmoType();
  303. if ( iPrimaryAmmoType >= 0 )
  304. SetAmmoCount( GetAmmoDef()->MaxCarry( iPrimaryAmmoType, this ), iPrimaryAmmoType );
  305. int iSecondaryAmmoType = pWeapon->GetSecondaryAmmoType();
  306. if ( iSecondaryAmmoType >= 0 )
  307. SetAmmoCount( GetAmmoDef()->MaxCarry( iSecondaryAmmoType, this ), iSecondaryAmmoType );
  308. }
  309. else
  310. {
  311. pWeapon->SetReserveAmmoCount( AMMO_POSITION_PRIMARY, pWeapon->GetReserveAmmoMax( AMMO_POSITION_PRIMARY ), true );
  312. pWeapon->SetReserveAmmoCount( AMMO_POSITION_SECONDARY, pWeapon->GetReserveAmmoMax( AMMO_POSITION_SECONDARY ), true );
  313. }
  314. #endif
  315. }
  316. }
  317. //-----------------------------------------------------------------------------
  318. // Eye angles
  319. //-----------------------------------------------------------------------------
  320. const QAngle &CBasePlayer::EyeAngles( )
  321. {
  322. // NOTE: Viewangles are measured *relative* to the parent's coordinate system
  323. CBaseEntity *pMoveParent = const_cast<CBasePlayer*>(this)->GetMoveParent();
  324. if ( !pMoveParent )
  325. {
  326. // if in camera mode, use that
  327. if ( GetViewEntity() != NULL )
  328. {
  329. return GetViewEntity()->EyeAngles();
  330. }
  331. return pl.v_angle;
  332. }
  333. // FIXME: Cache off the angles?
  334. matrix3x4_t eyesToParent, eyesToWorld;
  335. AngleMatrix( pl.v_angle, eyesToParent );
  336. ConcatTransforms( pMoveParent->EntityToWorldTransform(), eyesToParent, eyesToWorld );
  337. static QAngle angEyeWorld;
  338. MatrixAngles( eyesToWorld, angEyeWorld );
  339. return angEyeWorld;
  340. }
  341. const QAngle &CBasePlayer::LocalEyeAngles()
  342. {
  343. return pl.v_angle;
  344. }
  345. //-----------------------------------------------------------------------------
  346. // Actual Eye position + angles
  347. //-----------------------------------------------------------------------------
  348. Vector CBasePlayer::EyePosition( )
  349. {
  350. if ( GetVehicle() != NULL )
  351. {
  352. // Return the cached result
  353. CacheVehicleView();
  354. return m_vecVehicleViewOrigin;
  355. }
  356. else
  357. {
  358. #ifdef CLIENT_DLL
  359. if ( IsObserver() )
  360. {
  361. if ( m_iObserverMode == OBS_MODE_CHASE )
  362. {
  363. if ( IsLocalPlayer( this ) )
  364. {
  365. return MainViewOrigin(GetSplitScreenPlayerSlot());
  366. }
  367. }
  368. }
  369. #endif
  370. // if in camera mode, use that
  371. if ( GetViewEntity() != NULL )
  372. {
  373. return GetViewEntity()->EyePosition();
  374. }
  375. #ifdef CLIENT_DLL
  376. if ( !IsLocalPlayer( this ) && IsAlive() )
  377. {
  378. if( ( GetFlags() & FL_DUCKING ) || m_Local.m_bDucked )
  379. {
  380. return GetAbsOrigin() + VEC_DUCK_VIEW;
  381. }
  382. else
  383. {
  384. return GetAbsOrigin() + VEC_VIEW;
  385. }
  386. }
  387. else
  388. {
  389. return BaseClass::EyePosition();
  390. }
  391. #else
  392. return BaseClass::EyePosition();
  393. #endif
  394. }
  395. }
  396. //-----------------------------------------------------------------------------
  397. // Purpose:
  398. // Input :
  399. // Output : const Vector
  400. //-----------------------------------------------------------------------------
  401. const Vector CBasePlayer::GetPlayerMins( void ) const
  402. {
  403. if ( IsObserver() )
  404. {
  405. return VEC_OBS_HULL_MIN;
  406. }
  407. else
  408. {
  409. if ( GetFlags() & FL_DUCKING )
  410. {
  411. return VEC_DUCK_HULL_MIN;
  412. }
  413. else
  414. {
  415. return VEC_HULL_MIN;
  416. }
  417. }
  418. }
  419. //-----------------------------------------------------------------------------
  420. // Purpose:
  421. // Input :
  422. // Output : const Vector
  423. //-----------------------------------------------------------------------------
  424. const Vector CBasePlayer::GetPlayerMaxs( void ) const
  425. {
  426. if ( IsObserver() )
  427. {
  428. return VEC_OBS_HULL_MAX;
  429. }
  430. else
  431. {
  432. if ( GetFlags() & FL_DUCKING )
  433. {
  434. return VEC_DUCK_HULL_MAX;
  435. }
  436. else
  437. {
  438. return VEC_HULL_MAX;
  439. }
  440. }
  441. }
  442. //-----------------------------------------------------------------------------
  443. // Purpose:
  444. //-----------------------------------------------------------------------------
  445. void CBasePlayer::UpdateCollisionBounds( void )
  446. {
  447. if ( GetFlags() & FL_DUCKING )
  448. {
  449. SetCollisionBounds( VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX );
  450. }
  451. else
  452. {
  453. SetCollisionBounds( VEC_HULL_MIN, VEC_HULL_MAX );
  454. }
  455. }
  456. //-----------------------------------------------------------------------------
  457. // Purpose: Update the vehicle view, or simply return the cached position and angles
  458. //-----------------------------------------------------------------------------
  459. void CBasePlayer::CacheVehicleView( void )
  460. {
  461. // If we've calculated the view this frame, then there's no need to recalculate it
  462. if ( m_nVehicleViewSavedFrame == gpGlobals->framecount )
  463. return;
  464. #ifdef CLIENT_DLL
  465. IClientVehicle *pVehicle = GetVehicle();
  466. #else
  467. IServerVehicle *pVehicle = GetVehicle();
  468. #endif
  469. if ( pVehicle != NULL )
  470. {
  471. int nRole = pVehicle->GetPassengerRole( this );
  472. // Get our view for this frame
  473. pVehicle->GetVehicleViewPosition( nRole, &m_vecVehicleViewOrigin, &m_vecVehicleViewAngles, &m_flVehicleViewFOV );
  474. m_nVehicleViewSavedFrame = gpGlobals->framecount;
  475. }
  476. }
  477. //-----------------------------------------------------------------------------
  478. // Returns eye vectors
  479. //-----------------------------------------------------------------------------
  480. void CBasePlayer::EyeVectors( Vector *pForward, Vector *pRight, Vector *pUp )
  481. {
  482. if ( GetVehicle() != NULL )
  483. {
  484. // Cache or retrieve our calculated position in the vehicle
  485. CacheVehicleView();
  486. AngleVectors( m_vecVehicleViewAngles, pForward, pRight, pUp );
  487. }
  488. else
  489. {
  490. AngleVectors( EyeAngles(), pForward, pRight, pUp );
  491. }
  492. }
  493. //-----------------------------------------------------------------------------
  494. // Purpose: Returns the eye position and angle vectors.
  495. //-----------------------------------------------------------------------------
  496. void CBasePlayer::EyePositionAndVectors( Vector *pPosition, Vector *pForward,
  497. Vector *pRight, Vector *pUp )
  498. {
  499. // Handle the view in the vehicle
  500. if ( GetVehicle() != NULL )
  501. {
  502. CacheVehicleView();
  503. AngleVectors( m_vecVehicleViewAngles, pForward, pRight, pUp );
  504. if ( pPosition != NULL )
  505. {
  506. *pPosition = m_vecVehicleViewOrigin;
  507. }
  508. }
  509. else
  510. {
  511. VectorCopy( EyePosition(), *pPosition );
  512. AngleVectors( EyeAngles(), pForward, pRight, pUp );
  513. }
  514. }
  515. #ifdef CLIENT_DLL
  516. surfacedata_t * CBasePlayer::GetFootstepSurface( const Vector &origin, const char *surfaceName )
  517. {
  518. return physprops->GetSurfaceData( physprops->GetSurfaceIndex( surfaceName ) );
  519. }
  520. #endif
  521. surfacedata_t *CBasePlayer::GetLadderSurface( const Vector &origin )
  522. {
  523. #ifdef CLIENT_DLL
  524. return GetFootstepSurface( origin, "ladder" );
  525. #else
  526. return physprops->GetSurfaceData( physprops->GetSurfaceIndex( "ladder" ) );
  527. #endif
  528. }
  529. void CBasePlayer::UpdateStepSound( surfacedata_t *psurface, const Vector &vecOrigin, const Vector &vecVelocity )
  530. {
  531. bool bWalking;
  532. float fvol;
  533. Vector knee;
  534. Vector feet;
  535. float height;
  536. float speed;
  537. float velrun;
  538. float velwalk;
  539. bool fLadder;
  540. if ( m_flStepSoundTime > 0 )
  541. {
  542. m_flStepSoundTime -= 1000.0f * gpGlobals->frametime;
  543. if ( m_flStepSoundTime < 0 )
  544. {
  545. m_flStepSoundTime = 0;
  546. }
  547. }
  548. if ( m_flStepSoundTime > 0 )
  549. return;
  550. if ( GetFlags() & (FL_FROZEN|FL_ATCONTROLS))
  551. return;
  552. if ( GetMoveType() == MOVETYPE_NOCLIP || GetMoveType() == MOVETYPE_OBSERVER )
  553. return;
  554. if ( !sv_footsteps.GetFloat() )
  555. return;
  556. speed = VectorLength( vecVelocity );
  557. float groundspeed = Vector2DLength( vecVelocity.AsVector2D() );
  558. // determine if we are on a ladder
  559. fLadder = ( GetMoveType() == MOVETYPE_LADDER );
  560. GetStepSoundVelocities( &velwalk, &velrun );
  561. bool onground = ( GetFlags() & FL_ONGROUND );
  562. bool movingalongground = ( groundspeed > 0.0001f );
  563. bool moving_fast_enough = ( speed >= velwalk );
  564. // To hear step sounds you must be either on a ladder or moving along the ground AND
  565. // You must be moving fast enough
  566. if ( !moving_fast_enough || !(fLadder || ( onground && movingalongground )) )
  567. return;
  568. // MoveHelper()->PlayerSetAnimation( PLAYER_WALK );
  569. bWalking = speed < velrun;
  570. VectorCopy( vecOrigin, knee );
  571. VectorCopy( vecOrigin, feet );
  572. height = GetPlayerMaxs()[ 2 ] - GetPlayerMins()[ 2 ];
  573. knee[2] = vecOrigin[2] + 0.2 * height;
  574. // find out what we're stepping in or on...
  575. if ( fLadder )
  576. {
  577. psurface = GetLadderSurface(vecOrigin);
  578. fvol = 0.5;
  579. SetStepSoundTime( STEPSOUNDTIME_ON_LADDER, bWalking );
  580. }
  581. #ifdef CSTRIKE_DLL
  582. else if ( enginetrace->GetPointContents( knee ) & MASK_WATER ) // we want to use the knee for Cstrike, not the waist
  583. #else
  584. else if ( GetWaterLevel() == WL_Waist )
  585. #endif // CSTRIKE_DLL
  586. {
  587. static int iSkipStep = 0;
  588. if ( iSkipStep == 0 )
  589. {
  590. iSkipStep++;
  591. return;
  592. }
  593. if ( iSkipStep++ == 3 )
  594. {
  595. iSkipStep = 0;
  596. }
  597. psurface = physprops->GetSurfaceData( physprops->GetSurfaceIndex( "wade" ) );
  598. fvol = 0.65;
  599. SetStepSoundTime( STEPSOUNDTIME_WATER_KNEE, bWalking );
  600. }
  601. else if ( GetWaterLevel() == WL_Feet )
  602. {
  603. psurface = physprops->GetSurfaceData( physprops->GetSurfaceIndex( "water" ) );
  604. fvol = bWalking ? 0.2 : 0.5;
  605. SetStepSoundTime( STEPSOUNDTIME_WATER_FOOT, bWalking );
  606. }
  607. else
  608. {
  609. if ( !psurface )
  610. return;
  611. SetStepSoundTime( STEPSOUNDTIME_NORMAL, bWalking );
  612. switch ( psurface->game.material )
  613. {
  614. default:
  615. case CHAR_TEX_CONCRETE:
  616. fvol = bWalking ? 0.2 : 0.5;
  617. break;
  618. case CHAR_TEX_METAL:
  619. fvol = bWalking ? 0.2 : 0.5;
  620. break;
  621. case CHAR_TEX_DIRT:
  622. fvol = bWalking ? 0.25 : 0.55;
  623. break;
  624. case CHAR_TEX_VENT:
  625. fvol = bWalking ? 0.4 : 0.7;
  626. break;
  627. case CHAR_TEX_GRATE:
  628. fvol = bWalking ? 0.2 : 0.5;
  629. break;
  630. case CHAR_TEX_TILE:
  631. fvol = bWalking ? 0.2 : 0.5;
  632. break;
  633. case CHAR_TEX_SLOSH:
  634. fvol = bWalking ? 0.2 : 0.5;
  635. break;
  636. }
  637. }
  638. // play the sound
  639. // 65% volume if ducking
  640. if ( GetFlags() & FL_DUCKING )
  641. {
  642. fvol *= 0.65;
  643. }
  644. PlayStepSound( feet, psurface, fvol, false );
  645. }
  646. ConVar sv_max_distance_transmit_footsteps( "sv_max_distance_transmit_footsteps", "1250.0", FCVAR_REPLICATED, "Maximum distance to transmit footstep sound effects." );
  647. //-----------------------------------------------------------------------------
  648. // Purpose:
  649. // Input : step -
  650. // fvol -
  651. // force - force sound to play
  652. //-----------------------------------------------------------------------------
  653. void CBasePlayer::PlayStepSound( Vector &vecOrigin, surfacedata_t *psurface, float fvol, bool bForce )
  654. {
  655. if ( gpGlobals->maxClients > 1 && !sv_footsteps.GetFloat() )
  656. return;
  657. #if defined( CLIENT_DLL )
  658. // during prediction play footstep sounds only once
  659. if ( prediction->InPrediction() && !prediction->IsFirstTimePredicted() )
  660. return;
  661. #endif
  662. if ( !psurface )
  663. return;
  664. int nSide = m_Local.m_nStepside;
  665. unsigned short stepSoundName = nSide ? psurface->sounds.runStepLeft : psurface->sounds.runStepRight;
  666. if ( !stepSoundName )
  667. return;
  668. m_Local.m_nStepside = !nSide;
  669. CSoundParameters params;
  670. Assert( nSide == 0 || nSide == 1 );
  671. if ( m_StepSoundCache[ nSide ].m_usSoundNameIndex == stepSoundName )
  672. {
  673. params = m_StepSoundCache[ nSide ].m_SoundParameters;
  674. }
  675. else
  676. {
  677. IPhysicsSurfaceProps *physprops = MoveHelper()->GetSurfaceProps();
  678. // footstep sounds
  679. #if defined( CSTRIKE15 )
  680. const char *pRawSoundName = physprops->GetString( stepSoundName );
  681. const char *pSoundName = NULL;
  682. int const nStepCopyLen = V_strlen(pRawSoundName) + 4;
  683. char *szStep = ( char * ) stackalloc( nStepCopyLen );
  684. if ( GetTeamNumber() == TEAM_CT )
  685. {
  686. Q_snprintf(szStep, nStepCopyLen, "ct_%s", pRawSoundName);
  687. }
  688. else
  689. {
  690. Q_snprintf(szStep, nStepCopyLen, "t_%s", pRawSoundName);
  691. }
  692. pSoundName = szStep;
  693. if ( !CBaseEntity::GetParametersForSound( pSoundName, params, NULL ) )
  694. {
  695. DevMsg( "Can't find specific footstep sound! (%s) - Using the default instead. (%s)\n", pSoundName, pRawSoundName );
  696. pSoundName = pRawSoundName;
  697. }
  698. #else
  699. const char *pSoundName = physprops->GetString( stepSoundName );
  700. #endif
  701. if ( !CBaseEntity::GetParametersForSound( pSoundName, params, NULL ) )
  702. return;
  703. // Only cache if there's one option. Otherwise we'd never here any other sounds
  704. if ( params.count == 1 )
  705. {
  706. m_StepSoundCache[ nSide ].m_usSoundNameIndex = stepSoundName;
  707. m_StepSoundCache[ nSide ].m_SoundParameters = params;
  708. }
  709. }
  710. CRecipientFilter filter;
  711. #if defined( CLIENT_DLL )
  712. // make sure we hear our own jump
  713. filter.AddRecipient( this );
  714. if ( prediction->InPrediction() && !bForce )
  715. {
  716. // Only use these rules when in prediction.
  717. filter.UsePredictionRules();
  718. }
  719. #endif
  720. if( !bForce )
  721. {
  722. filter.AddRecipientsByPAS( vecOrigin );
  723. }
  724. #ifndef CLIENT_DLL
  725. // in MP, server removes all players in the vecOrigin's PVS, these players generate the footsteps client side
  726. if ( gpGlobals->maxClients > 1 && !bForce )
  727. {
  728. filter.RemoveRecipientsByPVS( vecOrigin );
  729. }
  730. if( bForce )
  731. {
  732. filter.AddAllPlayers();
  733. }
  734. // the client plays it's own sound
  735. filter.RemoveRecipient( this );
  736. // Don't transmit footsteps if they are outside maximum footstep transmission range.
  737. for ( int i = 0; i < filter.GetRecipientCount(); ++i )
  738. {
  739. int entIndex = filter.GetRecipientIndex( i );
  740. IHandleEntity* entity = gEntList.LookupEntityByNetworkIndex( entIndex );
  741. if ( entity )
  742. {
  743. CBasePlayer* player = dynamic_cast<CBasePlayer*>( gEntList.GetBaseEntity( entity->GetRefEHandle() ) );
  744. if ( player != NULL )
  745. {
  746. float dist = vecOrigin.DistTo( player->EyePosition() );
  747. if ( dist > sv_max_distance_transmit_footsteps.GetFloat() )
  748. {
  749. filter.RemoveRecipient( player );
  750. }
  751. }
  752. }
  753. }
  754. #endif
  755. // #if defined( CLIENT_DLL )
  756. // Msg( "CLIENT_DLL: (PlayStepSound) filter recipients = %d\n", filter.GetRecipientCount() );
  757. // #else
  758. // Msg( "GAME_DLL: (PlayStepSound) filter recipients = %d\n", filter.GetRecipientCount() );
  759. // #endif
  760. EmitSound_t ep;
  761. ep.m_nChannel = CHAN_BODY;
  762. ep.m_pSoundName = params.soundname;
  763. ep.m_flVolume = fvol;
  764. ep.m_SoundLevel = params.soundlevel;
  765. ep.m_nFlags = 0;
  766. ep.m_nPitch = params.pitch;
  767. ep.m_pOrigin = &vecOrigin;
  768. ep.m_hSoundScriptHash = params.m_hSoundScriptHash;
  769. ep.m_nSoundEntryVersion = params.m_nSoundEntryVersion;
  770. EmitSound( filter, entindex(), ep );
  771. // Step Suit
  772. if (CCSPlayer *pThisCsPlayer = dynamic_cast<CCSPlayer *>(this))
  773. {
  774. if (pThisCsPlayer->IsBot() && pThisCsPlayer->HasHeavyArmor())
  775. {
  776. extern ISoundEmitterSystemBase *soundemitterbase;
  777. static const char * const k_HeavyStepSoundName = "Heavy.Step";
  778. static HSOUNDSCRIPTHASH const k_HeavyStepSoundHash = soundemitterbase->HashSoundName( k_HeavyStepSoundName );
  779. ep.m_pSoundName = k_HeavyStepSoundName;
  780. ep.m_hSoundScriptHash = k_HeavyStepSoundHash;
  781. EmitSound(filter, entindex(), ep);
  782. }
  783. }
  784. CSoundParameters paramsSuitSound;
  785. if (!CBaseEntity::GetParametersForSound((GetTeamNumber() == TEAM_CT) ? "CT_Default.Suit" : "T_Default.Suit", paramsSuitSound, NULL))
  786. return;
  787. EmitSound_t epSuitSound;
  788. epSuitSound.m_nChannel = CHAN_AUTO;
  789. epSuitSound.m_pSoundName = paramsSuitSound.soundname;
  790. epSuitSound.m_flVolume = fvol;
  791. epSuitSound.m_SoundLevel = paramsSuitSound.soundlevel;
  792. epSuitSound.m_nFlags = 0;
  793. epSuitSound.m_nPitch = paramsSuitSound.pitch;
  794. epSuitSound.m_pOrigin = &vecOrigin;
  795. epSuitSound.m_hSoundScriptHash = paramsSuitSound.m_hSoundScriptHash;
  796. epSuitSound.m_nSoundEntryVersion = paramsSuitSound.m_nSoundEntryVersion;
  797. EmitSound(filter, entindex(), epSuitSound);
  798. }
  799. void CBasePlayer::UpdateButtonState( int nUserCmdButtonMask )
  800. {
  801. // Track button info so we can detect 'pressed' and 'released' buttons next frame
  802. m_afButtonLast = m_nButtons;
  803. // Get button states
  804. m_nButtons = nUserCmdButtonMask;
  805. int buttonsChanged = m_afButtonLast ^ m_nButtons;
  806. // Debounced button codes for pressed/released
  807. // UNDONE: Do we need auto-repeat?
  808. m_afButtonPressed = buttonsChanged & m_nButtons; // The changed ones still down are "pressed"
  809. m_afButtonReleased = buttonsChanged & (~m_nButtons); // The ones not down are "released"
  810. }
  811. //-----------------------------------------------------------------------------
  812. // Purpose:
  813. //-----------------------------------------------------------------------------
  814. void CBasePlayer::GetStepSoundVelocities( float *velwalk, float *velrun )
  815. {
  816. // UNDONE: need defined numbers for run, walk, crouch, crouch run velocities!!!!
  817. if ( ( GetFlags() & FL_DUCKING) || ( GetMoveType() == MOVETYPE_LADDER ) )
  818. {
  819. *velwalk = 60; // These constants should be based on cl_movespeedkey * cl_forwardspeed somehow
  820. *velrun = 80;
  821. }
  822. else
  823. {
  824. *velwalk = 90;
  825. *velrun = 220;
  826. }
  827. }
  828. //-----------------------------------------------------------------------------
  829. // Purpose:
  830. //-----------------------------------------------------------------------------
  831. void CBasePlayer::SetStepSoundTime( stepsoundtimes_t iStepSoundTime, bool bWalking )
  832. {
  833. switch ( iStepSoundTime )
  834. {
  835. case STEPSOUNDTIME_NORMAL:
  836. case STEPSOUNDTIME_WATER_FOOT:
  837. m_flStepSoundTime = bWalking ? 400 : 300;
  838. break;
  839. case STEPSOUNDTIME_ON_LADDER:
  840. m_flStepSoundTime = 200;
  841. break;
  842. case STEPSOUNDTIME_WATER_KNEE:
  843. m_flStepSoundTime = 600;
  844. break;
  845. default:
  846. Assert(0);
  847. break;
  848. }
  849. m_flStepSoundTime *= sv_footstep_sound_frequency.GetFloat();
  850. // UNDONE: need defined numbers for run, walk, crouch, crouch run velocities!!!!
  851. if ( ( GetFlags() & FL_DUCKING) || ( GetMoveType() == MOVETYPE_LADDER ) )
  852. {
  853. m_flStepSoundTime += 100;
  854. }
  855. }
  856. Vector CBasePlayer::Weapon_ShootPosition( )
  857. {
  858. return EyePosition();
  859. }
  860. bool CBasePlayer::Weapon_CanUse( CBaseCombatWeapon *pWeapon )
  861. {
  862. return true;
  863. }
  864. void CBasePlayer::SetAnimationExtension( const char *pExtension )
  865. {
  866. Q_strncpy( m_szAnimExtension, pExtension, sizeof(m_szAnimExtension) );
  867. }
  868. //-----------------------------------------------------------------------------
  869. // Purpose: Set the weapon to switch to when the player uses the 'lastinv' command
  870. //-----------------------------------------------------------------------------
  871. void CBasePlayer::Weapon_SetLast( CBaseCombatWeapon *pWeapon )
  872. {
  873. m_hLastWeapon = pWeapon;
  874. }
  875. //-----------------------------------------------------------------------------
  876. // Purpose: Override to clear dropped weapon from the hud
  877. //-----------------------------------------------------------------------------
  878. void CBasePlayer::Weapon_Drop( CBaseCombatWeapon *pWeapon, const Vector *pvecTarget /* = NULL */, const Vector *pVelocity /* = NULL */ )
  879. {
  880. bool bWasActiveWeapon = false;
  881. if ( pWeapon == GetActiveWeapon() )
  882. {
  883. bWasActiveWeapon = true;
  884. }
  885. if ( pWeapon )
  886. {
  887. if ( bWasActiveWeapon )
  888. {
  889. pWeapon->SendWeaponAnim( ACT_VM_IDLE );
  890. }
  891. }
  892. #if defined( GAME_DLL )
  893. BaseClass::Weapon_Drop( pWeapon, pvecTarget, pVelocity );
  894. #endif
  895. if ( bWasActiveWeapon )
  896. {
  897. if (!SwitchToNextBestWeapon( NULL ))
  898. {
  899. CBaseViewModel *vm = GetViewModel();
  900. if ( vm )
  901. {
  902. vm->AddEffects( EF_NODRAW );
  903. }
  904. }
  905. }
  906. }
  907. //-----------------------------------------------------------------------------
  908. // Purpose: Override base class so player can reset autoaim
  909. // Input :
  910. // Output :
  911. //-----------------------------------------------------------------------------
  912. bool CBasePlayer::Weapon_Switch( CBaseCombatWeapon *pWeapon, int viewmodelindex /*=0*/ )
  913. {
  914. CBaseCombatWeapon *pLastWeapon = GetActiveWeapon();
  915. if ( BaseClass::Weapon_Switch( pWeapon, viewmodelindex ))
  916. {
  917. if ( pLastWeapon && Weapon_ShouldSetLast( pLastWeapon, GetActiveWeapon() ) )
  918. {
  919. Weapon_SetLast( pLastWeapon->GetLastWeapon() );
  920. }
  921. CBaseViewModel *pViewModel = GetViewModel( viewmodelindex );
  922. Assert( pViewModel );
  923. if ( pViewModel )
  924. pViewModel->RemoveEffects( EF_NODRAW );
  925. ResetAutoaim( );
  926. OnSwitchWeapons( pWeapon );
  927. #if defined ( CLIENT_DLL ) && defined ( CSTRIKE15 )
  928. CBaseHudWeaponSelection *pHudSelection = GetHudWeaponSelection();
  929. if ( pHudSelection )
  930. {
  931. pHudSelection->OnWeaponSwitch( pWeapon );
  932. }
  933. #endif
  934. return true;
  935. }
  936. return false;
  937. }
  938. void CBasePlayer::SelectLastItem(void)
  939. {
  940. if ( m_hLastWeapon.Get() == NULL )
  941. return;
  942. if ( GetActiveWeapon() && !GetActiveWeapon()->CanHolster() )
  943. return;
  944. SelectItem( m_hLastWeapon.Get()->GetClassname(), m_hLastWeapon.Get()->GetSubType() );
  945. }
  946. //-----------------------------------------------------------------------------
  947. // Purpose: Abort any reloads we're in
  948. //-----------------------------------------------------------------------------
  949. void CBasePlayer::AbortReload( void )
  950. {
  951. if ( GetActiveWeapon() )
  952. {
  953. GetActiveWeapon()->AbortReload();
  954. }
  955. }
  956. #if !defined( NO_ENTITY_PREDICTION )
  957. void CBasePlayer::AddToPlayerSimulationList( CBaseEntity *other )
  958. {
  959. CHandle< CBaseEntity > h;
  960. h = other;
  961. // Already in list
  962. if ( m_SimulatedByThisPlayer.Find( h ) != m_SimulatedByThisPlayer.InvalidIndex() )
  963. return;
  964. Assert( other->IsPlayerSimulated() );
  965. m_SimulatedByThisPlayer.AddToTail( h );
  966. }
  967. //-----------------------------------------------------------------------------
  968. // Purpose: Fixme, this should occur if the player fails to drive simulation
  969. // often enough!!!
  970. // Input : *other -
  971. //-----------------------------------------------------------------------------
  972. void CBasePlayer::RemoveFromPlayerSimulationList( CBaseEntity *other )
  973. {
  974. if ( !other )
  975. return;
  976. Assert( other->IsPlayerSimulated() );
  977. Assert( other->GetSimulatingPlayer() == this );
  978. CHandle< CBaseEntity > h;
  979. h = other;
  980. m_SimulatedByThisPlayer.FindAndRemove( h );
  981. }
  982. void CBasePlayer::SimulatePlayerSimulatedEntities( void )
  983. {
  984. int c = m_SimulatedByThisPlayer.Count();
  985. int i;
  986. for ( i = c - 1; i >= 0; i-- )
  987. {
  988. CHandle< CBaseEntity > h;
  989. h = m_SimulatedByThisPlayer[ i ];
  990. CBaseEntity *e = h;
  991. if ( !e || !e->IsPlayerSimulated() )
  992. {
  993. m_SimulatedByThisPlayer.Remove( i );
  994. continue;
  995. }
  996. Assert( e->IsPlayerSimulated() );
  997. Assert( e->GetSimulatingPlayer() == this );
  998. e->PhysicsSimulate();
  999. }
  1000. // Loop through all entities again, checking their untouch if flagged to do so
  1001. c = m_SimulatedByThisPlayer.Count();
  1002. for ( i = c - 1; i >= 0; i-- )
  1003. {
  1004. CHandle< CBaseEntity > h;
  1005. h = m_SimulatedByThisPlayer[ i ];
  1006. CBaseEntity *e = h;
  1007. if ( !e || !e->IsPlayerSimulated() )
  1008. {
  1009. m_SimulatedByThisPlayer.Remove( i );
  1010. continue;
  1011. }
  1012. Assert( e->IsPlayerSimulated() );
  1013. Assert( e->GetSimulatingPlayer() == this );
  1014. if ( !e->GetCheckUntouch() )
  1015. continue;
  1016. e->PhysicsCheckForEntityUntouch();
  1017. }
  1018. }
  1019. //-----------------------------------------------------------------------------
  1020. // Purpose:
  1021. //-----------------------------------------------------------------------------
  1022. void CBasePlayer::ClearPlayerSimulationList( void )
  1023. {
  1024. int c = m_SimulatedByThisPlayer.Count();
  1025. int i;
  1026. for ( i = c - 1; i >= 0; i-- )
  1027. {
  1028. CHandle< CBaseEntity > h;
  1029. h = m_SimulatedByThisPlayer[ i ];
  1030. CBaseEntity *e = h;
  1031. if ( e )
  1032. {
  1033. e->UnsetPlayerSimulated();
  1034. }
  1035. }
  1036. m_SimulatedByThisPlayer.RemoveAll();
  1037. }
  1038. #endif
  1039. //-----------------------------------------------------------------------------
  1040. // Purpose: Return true if we should allow selection of the specified item
  1041. //-----------------------------------------------------------------------------
  1042. bool CBasePlayer::Weapon_ShouldSelectItem( CBaseCombatWeapon *pWeapon )
  1043. {
  1044. return ( pWeapon != GetActiveWeapon() );
  1045. }
  1046. //-----------------------------------------------------------------------------
  1047. // Purpose:
  1048. //-----------------------------------------------------------------------------
  1049. void CBasePlayer::SelectItem( const char *pstr, int iSubType )
  1050. {
  1051. if (!pstr)
  1052. return;
  1053. CBaseCombatWeapon *pItem = Weapon_OwnsThisType( pstr, iSubType );
  1054. if (!pItem)
  1055. return;
  1056. if( GetObserverMode() != OBS_MODE_NONE )
  1057. return;// Observers can't select things.
  1058. if ( !Weapon_ShouldSelectItem( pItem ) )
  1059. return;
  1060. // FIX, this needs to queue them up and delay
  1061. // Make sure the current weapon can be holstered
  1062. if ( GetActiveWeapon() )
  1063. {
  1064. if ( !GetActiveWeapon()->CanHolster() )
  1065. return;
  1066. ResetAutoaim( );
  1067. }
  1068. Weapon_Switch( pItem );
  1069. }
  1070. //-----------------------------------------------------------------------------
  1071. // Purpose:
  1072. //-----------------------------------------------------------------------------
  1073. 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" );
  1074. float IntervalDistance( float x, float x0, float x1 )
  1075. {
  1076. // swap so x0 < x1
  1077. if ( x0 > x1 )
  1078. {
  1079. float tmp = x0;
  1080. x0 = x1;
  1081. x1 = tmp;
  1082. }
  1083. if ( x < x0 )
  1084. return x0-x;
  1085. else if ( x > x1 )
  1086. return x - x1;
  1087. return 0;
  1088. }
  1089. CBaseEntity *CBasePlayer::FindUseEntity()
  1090. {
  1091. Vector forward, up;
  1092. // NOTE: This doesn't handle the case when the player is in a vehicle.
  1093. AngleVectors( GetFinalAimAngle(), &forward, NULL, &up );
  1094. trace_t tr;
  1095. // Search for objects in a sphere (tests for entities that are not solid, yet still useable)
  1096. Vector searchCenter = EyePosition();
  1097. // NOTE: Some debris objects are useable too, so hit those as well
  1098. // A button, etc. can be made out of clip brushes, make sure it's +useable via a traceline, too.
  1099. int useableContents = MASK_SOLID | CONTENTS_DEBRIS | CONTENTS_PLAYERCLIP;
  1100. #ifdef CSTRIKE_DLL
  1101. useableContents = (MASK_NPCSOLID_BRUSHONLY | MASK_OPAQUE_AND_NPCS) & ~CONTENTS_OPAQUE;
  1102. #endif
  1103. #ifndef CLIENT_DLL
  1104. CBaseEntity *pFoundByTrace = NULL;
  1105. #endif
  1106. // UNDONE: Might be faster to just fold this range into the sphere query
  1107. CBaseEntity *pObject = NULL;
  1108. float nearestDist = FLT_MAX;
  1109. // try the hit entity if there is one, or the ground entity if there isn't.
  1110. CBaseEntity *pNearest = NULL;
  1111. const int NUM_TANGENTS = 8;
  1112. #if defined( CSTRIKE15 ) && defined( GAME_DLL )
  1113. const int NUM_TRACES = 1;
  1114. #else
  1115. const int NUM_TRACES = NUM_TANGENTS;
  1116. #endif
  1117. // trace a box at successive angles down
  1118. // forward, 45 deg, 30 deg, 20 deg, 15 deg, 10 deg, -10, -15
  1119. const float tangents[NUM_TANGENTS] = { 0, 1, 0.57735026919f, 0.3639702342f, 0.267949192431f, 0.1763269807f, -0.1763269807f, -0.267949192431f };
  1120. for ( int i = 0; i < NUM_TRACES; i++ )
  1121. {
  1122. if ( i == 0 )
  1123. {
  1124. UTIL_TraceLine( searchCenter, searchCenter + forward * 1024, useableContents, this, COLLISION_GROUP_NONE, &tr );
  1125. }
  1126. else
  1127. {
  1128. Vector down = forward - tangents[i]*up;
  1129. VectorNormalize(down);
  1130. UTIL_TraceHull( searchCenter, searchCenter + down * 72, -Vector(16,16,16), Vector(16,16,16), useableContents, this, COLLISION_GROUP_NONE, &tr );
  1131. }
  1132. pObject = tr.m_pEnt;
  1133. #ifndef CLIENT_DLL
  1134. pFoundByTrace = pObject;
  1135. #endif
  1136. bool bUsable = IsUseableEntity(pObject, 0);
  1137. while ( pObject && !bUsable && pObject->GetMoveParent() )
  1138. {
  1139. pObject = pObject->GetMoveParent();
  1140. bUsable = IsUseableEntity(pObject, 0);
  1141. }
  1142. if ( bUsable )
  1143. {
  1144. Vector delta = tr.endpos - tr.startpos;
  1145. float centerZ = CollisionProp()->WorldSpaceCenter().z;
  1146. delta.z = IntervalDistance( tr.endpos.z, centerZ + CollisionProp()->OBBMins().z, centerZ + CollisionProp()->OBBMaxs().z );
  1147. float dist = delta.Length();
  1148. #if defined( CSTRIKE15 )
  1149. CCSPlayer *pPlayer = dynamic_cast<CCSPlayer*>( pObject );
  1150. if ( (pPlayer && pPlayer->IsBot() && dist < PLAYER_USE_BOT_RADIUS) || dist < PLAYER_USE_RADIUS )
  1151. {
  1152. #else
  1153. if ( dist < PLAYER_USE_RADIUS )
  1154. {
  1155. #endif
  1156. #ifndef CLIENT_DLL
  1157. if ( sv_debug_player_use.GetBool() )
  1158. {
  1159. NDebugOverlay::Line( searchCenter, tr.endpos, 0, 255, 0, true, 30 );
  1160. NDebugOverlay::Cross3D( tr.endpos, 16, 0, 255, 0, true, 30 );
  1161. }
  1162. if ( pObject->MyNPCPointer() && pObject->MyNPCPointer()->IsPlayerAlly( this ) )
  1163. {
  1164. // If about to select an NPC, do a more thorough check to ensure
  1165. // that we're selecting the right one from a group.
  1166. pObject = DoubleCheckUseNPC( pObject, searchCenter, forward );
  1167. }
  1168. #endif
  1169. if ( sv_debug_player_use.GetBool() )
  1170. {
  1171. Msg( "Trace using: %s\n", pObject ? pObject->GetDebugName() : "no usable entity found" );
  1172. }
  1173. pNearest = pObject;
  1174. // if this is directly under the cursor just return it now
  1175. if ( i == 0 )
  1176. return pObject;
  1177. }
  1178. }
  1179. }
  1180. // check ground entity first
  1181. // if you've got a useable ground entity, then shrink the cone of this search to 45 degrees
  1182. // otherwise, search out in a 90 degree cone (hemisphere)
  1183. if ( GetGroundEntity() && IsUseableEntity(GetGroundEntity(), FCAP_USE_ONGROUND) )
  1184. {
  1185. pNearest = GetGroundEntity();
  1186. }
  1187. if ( pNearest )
  1188. {
  1189. // estimate nearest object by distance from the view vector
  1190. Vector point;
  1191. pNearest->CollisionProp()->CalcNearestPoint( searchCenter, &point );
  1192. nearestDist = CalcDistanceToLine( point, searchCenter, forward );
  1193. if ( sv_debug_player_use.GetBool() )
  1194. {
  1195. Msg("Trace found %s, dist %.2f\n", pNearest->GetClassname(), nearestDist );
  1196. }
  1197. }
  1198. #if defined( CSTRIKE15 ) && defined( GAME_DLL )
  1199. CCSPlayer* pPlayer = ToCSPlayer( this );
  1200. const float MIN_DOT_FOR_WEAPONS = 0.99f;
  1201. #endif
  1202. for ( CEntitySphereQuery sphere( searchCenter, PLAYER_USE_RADIUS ); ( pObject = sphere.GetCurrentEntity() ) != NULL; sphere.NextEntity() )
  1203. {
  1204. if ( !pObject )
  1205. continue;
  1206. if ( !IsUseableEntity( pObject, FCAP_USE_IN_RADIUS ) )
  1207. continue;
  1208. // see if it's more roughly in front of the player than previous guess
  1209. Vector point;
  1210. pObject->CollisionProp()->CalcNearestPoint( searchCenter, &point );
  1211. float fMinimumDot = pObject->GetUseLookAtAngle();
  1212. #if defined( CSTRIKE15 ) && defined( GAME_DLL )
  1213. CWeaponCSBase *pWeapon = dynamic_cast<CWeaponCSBase*>( pObject );
  1214. CSWeaponType nWepType = WEAPONTYPE_UNKNOWN;
  1215. if ( pWeapon )
  1216. {
  1217. nWepType = pWeapon->GetWeaponType();
  1218. if ( pPlayer->IsPrimaryOrSecondaryWeapon( nWepType ) )
  1219. fMinimumDot = MIN_DOT_FOR_WEAPONS;
  1220. }
  1221. #endif
  1222. Vector dir = point - searchCenter;
  1223. VectorNormalize(dir);
  1224. float dot = DotProduct( dir, forward );
  1225. // Need to be looking at the object more or less
  1226. if ( dot < fMinimumDot )
  1227. continue;
  1228. float dist = CalcDistanceToLine( point, searchCenter, forward );
  1229. if ( sv_debug_player_use.GetBool() )
  1230. {
  1231. Msg("Radius found %s, dist %.2f\n", pObject->GetClassname(), dist );
  1232. }
  1233. if ( dist < nearestDist )
  1234. {
  1235. // Since this has purely been a radius search to this point, we now
  1236. // make sure the object isn't behind glass or a grate.
  1237. trace_t trCheckOccluded;
  1238. UTIL_TraceLine( searchCenter, point, useableContents, this, COLLISION_GROUP_NONE, &trCheckOccluded );
  1239. if ( trCheckOccluded.fraction == 1.0 || trCheckOccluded.m_pEnt == pObject )
  1240. {
  1241. pNearest = pObject;
  1242. nearestDist = dist;
  1243. }
  1244. }
  1245. }
  1246. #ifndef CLIENT_DLL
  1247. if ( !pNearest )
  1248. {
  1249. // Haven't found anything near the player to use, nor any NPC's at distance.
  1250. // Check to see if the player is trying to select an NPC through a rail, fence, or other 'see-though' volume.
  1251. trace_t trAllies;
  1252. UTIL_TraceLine( searchCenter, searchCenter + forward * PLAYER_USE_RADIUS, MASK_OPAQUE_AND_NPCS, this, COLLISION_GROUP_NONE, &trAllies );
  1253. if ( trAllies.m_pEnt && IsUseableEntity( trAllies.m_pEnt, 0 ) && trAllies.m_pEnt->MyNPCPointer() && trAllies.m_pEnt->MyNPCPointer()->IsPlayerAlly( this ) )
  1254. {
  1255. // This is an NPC, take it!
  1256. pNearest = trAllies.m_pEnt;
  1257. }
  1258. }
  1259. if ( pNearest && pNearest->MyNPCPointer() && pNearest->MyNPCPointer()->IsPlayerAlly( this ) )
  1260. {
  1261. pNearest = DoubleCheckUseNPC( pNearest, searchCenter, forward );
  1262. }
  1263. if ( sv_debug_player_use.GetBool() )
  1264. {
  1265. if ( !pNearest )
  1266. {
  1267. NDebugOverlay::Line( searchCenter, tr.endpos, 255, 0, 0, true, 30 );
  1268. NDebugOverlay::Cross3D( tr.endpos, 16, 255, 0, 0, true, 30 );
  1269. }
  1270. else if ( pNearest == pFoundByTrace )
  1271. {
  1272. NDebugOverlay::Line( searchCenter, tr.endpos, 0, 255, 0, true, 30 );
  1273. NDebugOverlay::Cross3D( tr.endpos, 16, 0, 255, 0, true, 30 );
  1274. }
  1275. else
  1276. {
  1277. NDebugOverlay::Box( pNearest->WorldSpaceCenter(), Vector(-8, -8, -8), Vector(8, 8, 8), 0, 255, 0, true, 30 );
  1278. }
  1279. }
  1280. #endif
  1281. if ( sv_debug_player_use.GetBool() )
  1282. {
  1283. Msg( "Radial using: %s\n", pNearest ? pNearest->GetDebugName() : "no usable entity found" );
  1284. }
  1285. return pNearest;
  1286. }
  1287. //-----------------------------------------------------------------------------
  1288. // Purpose: Handles USE keypress
  1289. //-----------------------------------------------------------------------------
  1290. void CBasePlayer::PlayerUse ( void )
  1291. {
  1292. #ifdef GAME_DLL
  1293. // Was use pressed or released?
  1294. if ( ! ((m_nButtons | m_afButtonPressed | m_afButtonReleased) & IN_USE) )
  1295. return;
  1296. if ( IsObserver() )
  1297. {
  1298. // do special use operation in oberserver mode
  1299. if ( m_afButtonPressed & IN_USE )
  1300. ObserverUse( true );
  1301. else if ( m_afButtonReleased & IN_USE )
  1302. ObserverUse( false );
  1303. return;
  1304. }
  1305. // push objects in turbo physics mode
  1306. if ( (m_nButtons & IN_USE) && sv_turbophysics.GetBool() )
  1307. {
  1308. Vector forward, up;
  1309. EyeVectors( &forward, NULL, &up );
  1310. trace_t tr;
  1311. // Search for objects in a sphere (tests for entities that are not solid, yet still useable)
  1312. Vector searchCenter = EyePosition();
  1313. CUsePushFilter filter;
  1314. UTIL_TraceLine( searchCenter, searchCenter + forward * 96.0f, MASK_SOLID, &filter, &tr );
  1315. // try the hit entity if there is one, or the ground entity if there isn't.
  1316. CBaseEntity *entity = tr.m_pEnt;
  1317. if ( entity )
  1318. {
  1319. IPhysicsObject *pObj = entity->VPhysicsGetObject();
  1320. if ( pObj )
  1321. {
  1322. Vector vPushAway = (entity->WorldSpaceCenter() - WorldSpaceCenter());
  1323. vPushAway.z = 0;
  1324. float flDist = VectorNormalize( vPushAway );
  1325. flDist = MAX( flDist, 1 );
  1326. float flForce = sv_pushaway_force.GetFloat() / flDist;
  1327. flForce = MIN( flForce, sv_pushaway_max_force.GetFloat() );
  1328. pObj->ApplyForceOffset( vPushAway * flForce, WorldSpaceCenter() );
  1329. }
  1330. }
  1331. }
  1332. if ( m_afButtonPressed & IN_USE )
  1333. {
  1334. // Controlling some latched entity?
  1335. if ( ClearUseEntity() )
  1336. {
  1337. return;
  1338. }
  1339. else
  1340. {
  1341. if ( m_afPhysicsFlags & PFLAG_DIROVERRIDE )
  1342. {
  1343. m_afPhysicsFlags &= ~PFLAG_DIROVERRIDE;
  1344. m_iTrain = TRAIN_NEW|TRAIN_OFF;
  1345. return;
  1346. }
  1347. else
  1348. { // Start controlling the train!
  1349. CBaseEntity *pTrain = GetGroundEntity();
  1350. if ( pTrain && !(m_nButtons & IN_JUMP) && (GetFlags() & FL_ONGROUND) && (pTrain->ObjectCaps() & FCAP_DIRECTIONAL_USE) && pTrain->OnControls(this) )
  1351. {
  1352. m_afPhysicsFlags |= PFLAG_DIROVERRIDE;
  1353. m_iTrain = TrainSpeed(pTrain->m_flSpeed, ((CFuncTrackTrain*)pTrain)->GetMaxSpeed());
  1354. m_iTrain |= TRAIN_NEW;
  1355. EmitSound( "Player.UseTrain" );
  1356. return;
  1357. }
  1358. }
  1359. }
  1360. }
  1361. CBaseEntity *pUseEntity = FindUseEntity();
  1362. #if defined( CSTRIKE15 )
  1363. // in counterstrike 15, we need to allow the buy menu to open more easily
  1364. // The old code defaulted to using whatever you were pointing at.
  1365. // This code first checks to see if you're in a buy zone. If that's true,
  1366. // then it ignores any weapon you may be pointing at. (the planted c4 is
  1367. // not a weapon).
  1368. if ( m_afButtonPressed & IN_USE )
  1369. {
  1370. CCSPlayer* pPlayer = ToCSPlayer( this );
  1371. CWeaponCSBase *pWeapon = dynamic_cast<CWeaponCSBase*>( pUseEntity );
  1372. CSWeaponType nWepType = WEAPONTYPE_UNKNOWN;
  1373. if ( pWeapon )
  1374. nWepType = pWeapon->GetWeaponType();
  1375. bool bOpenBuyWithUse = true;
  1376. if ( pPlayer )
  1377. {
  1378. const char *cl_useopensbuymenu = engine->GetClientConVarValue( ENTINDEX( pPlayer->edict() ), "cl_use_opens_buy_menu" );
  1379. if ( cl_useopensbuymenu && atoi( cl_useopensbuymenu ) <= 0 )
  1380. bOpenBuyWithUse = false;
  1381. }
  1382. if ( pWeapon && pWeapon->CanBePickedUp() && pPlayer->IsPrimaryOrSecondaryWeapon( nWepType ) )
  1383. {
  1384. bool bPickupIsPrimary = IsPrimaryWeapon( pWeapon->GetCSWeaponID() );
  1385. CBaseCombatWeapon *pPlayerWeapon = NULL;
  1386. if ( bPickupIsPrimary )
  1387. {
  1388. pPlayerWeapon = pPlayer->Weapon_GetSlot( WEAPON_SLOT_RIFLE );
  1389. }
  1390. else
  1391. {
  1392. pPlayerWeapon = pPlayer->Weapon_GetSlot( WEAPON_SLOT_PISTOL );
  1393. }
  1394. // if the player has a weapon in the slot that occupies the weapon that they'd like to pick up
  1395. // AND they are able to drop it, pick up the new weapon
  1396. // OR if they don't have a weapon in that slot, go ahead and pick up the new weapon
  1397. if ( (pPlayerWeapon && pPlayer->HandleDropWeapon( pPlayerWeapon, true )) || !pPlayerWeapon )
  1398. {
  1399. pWeapon->Touch( this );
  1400. }
  1401. }
  1402. else if ( pPlayer && bOpenBuyWithUse && pPlayer->IsInBuyZone() && pPlayer->CanPlayerBuy( false ) && !CSGameRules()->IsPlayingGunGame() )
  1403. {
  1404. bool bItemIsNullOrWeapon = true;
  1405. if ( pUseEntity )
  1406. {
  1407. bItemIsNullOrWeapon = ( pWeapon != 0 );
  1408. }
  1409. if ( bItemIsNullOrWeapon )
  1410. {
  1411. engine->ClientCommand( edict(), "buymenu\n" );
  1412. return;
  1413. }
  1414. }
  1415. else if( !pUseEntity && pPlayer && pPlayer->HasC4() && pPlayer->GetActiveCSWeapon() )
  1416. {
  1417. if( pPlayer->m_bInBombZone && !( pPlayer->GetActiveCSWeapon()->IsA( WEAPON_C4 ) ) )
  1418. {
  1419. // we're in a bomb zone with C4, but it's not equipped. Equip it.
  1420. CWeaponCSBase *pC4Weapon = NULL;
  1421. //Search for the c4 weapon to use
  1422. for ( int i = 0; i < pPlayer->WeaponCount(); i++ )
  1423. {
  1424. CBaseCombatWeapon* pWeaponBase = pPlayer->GetWeapon(i);
  1425. CWeaponCSBase* pWeapon = dynamic_cast< CWeaponCSBase* > ( pWeaponBase );
  1426. if ( pWeapon == NULL )
  1427. {
  1428. continue;
  1429. }
  1430. if ( !pWeapon->IsA( WEAPON_C4 ) )
  1431. {
  1432. continue;
  1433. }
  1434. // Must be eligible for switching to.
  1435. if ( !pPlayer->Weapon_CanSwitchTo( pWeapon ) )
  1436. {
  1437. continue;
  1438. }
  1439. pC4Weapon = pWeapon;
  1440. }
  1441. if ( pC4Weapon != NULL )
  1442. {
  1443. //pPlayer->SetLastWeaponBeforeAutoSwitchToC4( pPlayer->GetActiveCSWeapon() );
  1444. pPlayer->Weapon_Switch(pC4Weapon);
  1445. static_cast<CC4*>(pC4Weapon)->m_bIsPlantingViaUse = true;
  1446. }
  1447. }
  1448. else if( pPlayer->GetActiveCSWeapon()->IsA( WEAPON_C4 ) )
  1449. {
  1450. static_cast<CC4*>(pPlayer->GetActiveWeapon())->m_bIsPlantingViaUse = true;
  1451. }
  1452. }
  1453. else if ( pUseEntity && pUseEntity->IsPlayer() )
  1454. {
  1455. // Bots can give their C4 to the requesting human.
  1456. CCSPlayer* pPlayer = ToCSPlayer( this );
  1457. CCSPlayer* pBot = ToCSPlayer( pUseEntity );
  1458. if ( pPlayer && pPlayer->IsAlive() && pBot && pBot->IsBot() && pBot->IsOtherSameTeam(pPlayer->GetTeamNumber()) && pBot->HasC4() )
  1459. {
  1460. //distance check is implicit in +use, but check it anyway
  1461. if ( (pBot->WorldSpaceCenter() - pPlayer->WorldSpaceCenter()).Length() < 200 )
  1462. {
  1463. CBaseCombatWeapon *pC4 = pBot->Weapon_OwnsThisType( "weapon_c4" );
  1464. if ( pC4 )
  1465. {
  1466. pBot->SetBombDroppedTime( gpGlobals->curtime );
  1467. pBot->CSWeaponDrop( pC4, WorldSpaceCenter(), false );
  1468. pBot->Radio( "Radio.YouTakeThePoint", "#Cstrike_TitlesTXT_Game_afk_bomb_drop" );
  1469. }
  1470. }
  1471. }
  1472. }
  1473. }
  1474. #endif
  1475. if ( pUseEntity )
  1476. {
  1477. //!!!UNDONE: traceline here to prevent +USEing buttons through walls
  1478. int caps = pUseEntity->ObjectCaps();
  1479. variant_t emptyVariant;
  1480. if ( ( (m_nButtons & IN_USE) && (caps & FCAP_CONTINUOUS_USE) ) || ( (m_afButtonPressed & IN_USE) && (caps & (FCAP_IMPULSE_USE|FCAP_ONOFF_USE)) ) )
  1481. {
  1482. if ( caps & FCAP_CONTINUOUS_USE )
  1483. {
  1484. m_afPhysicsFlags |= PFLAG_USING;
  1485. }
  1486. if ( pUseEntity->ObjectCaps() & FCAP_ONOFF_USE )
  1487. {
  1488. pUseEntity->AcceptInput( "Use", this, this, emptyVariant, USE_ON );
  1489. }
  1490. else
  1491. {
  1492. pUseEntity->AcceptInput( "Use", this, this, emptyVariant, USE_TOGGLE );
  1493. }
  1494. }
  1495. // UNDONE: Send different USE codes for ON/OFF. Cache last ONOFF_USE object to send 'off' if you turn away
  1496. else if ( (m_afButtonReleased & IN_USE) && (pUseEntity->ObjectCaps() & FCAP_ONOFF_USE) ) // BUGBUG This is an "off" use
  1497. {
  1498. pUseEntity->AcceptInput( "Use", this, this, emptyVariant, USE_OFF );
  1499. }
  1500. }
  1501. #if !defined( CSTRIKE15 )
  1502. else if ( m_afButtonPressed & IN_USE )
  1503. {
  1504. // [sbodenbender] buymenu is mapped to use; bring up buy if nothing to use
  1505. engine->ClientCommand(edict(),"buymenu\n");
  1506. //PlayUseDenySound();
  1507. }
  1508. #endif
  1509. #endif
  1510. }
  1511. ConVar sv_suppress_viewpunch( "sv_suppress_viewpunch", "0", FCVAR_REPLICATED | FCVAR_CHEAT | FCVAR_DEVELOPMENTONLY );
  1512. //-----------------------------------------------------------------------------
  1513. // Purpose:
  1514. //-----------------------------------------------------------------------------
  1515. void CBasePlayer::ViewPunch( const QAngle &angleOffset )
  1516. {
  1517. //See if we're suppressing the view punching
  1518. if ( sv_suppress_viewpunch.GetBool() )
  1519. return;
  1520. // We don't allow view kicks in the vehicle
  1521. if ( IsInAVehicle() )
  1522. return;
  1523. m_Local.m_viewPunchAngle += angleOffset;
  1524. }
  1525. //-----------------------------------------------------------------------------
  1526. // Purpose:
  1527. //-----------------------------------------------------------------------------
  1528. void CBasePlayer::ViewPunchReset( float tolerance )
  1529. {
  1530. if ( tolerance != 0 )
  1531. {
  1532. tolerance *= tolerance; // square
  1533. float check = m_Local.m_viewPunchAngle->LengthSqr();
  1534. if ( check > tolerance )
  1535. return;
  1536. }
  1537. m_Local.m_viewPunchAngle = vec3_angle;
  1538. }
  1539. #if defined( CLIENT_DLL )
  1540. #include "iviewrender.h"
  1541. #include "ivieweffects.h"
  1542. #endif
  1543. static ConVar smoothstairs( "smoothstairs", "1", FCVAR_REPLICATED, "Smooth player eye z coordinate when traversing stairs." );
  1544. //-----------------------------------------------------------------------------
  1545. // Handle view smoothing when going up or down stairs
  1546. //-----------------------------------------------------------------------------
  1547. void CBasePlayer::SmoothViewOnStairs( Vector& eyeOrigin )
  1548. {
  1549. CBaseEntity *pGroundEntity = GetGroundEntity();
  1550. float flCurrentPlayerZ = GetLocalOrigin().z;
  1551. float flCurrentPlayerViewOffsetZ = GetViewOffset().z;
  1552. #if defined( CLIENT_DLL )
  1553. {
  1554. matrix3x4_t matOriginDisontinuity;
  1555. if( GetOriginInterpolator().GetDiscontinuityTransform( GetEffectiveInterpolationCurTime( gpGlobals->curtime ), matOriginDisontinuity ) )
  1556. {
  1557. //if the origin has a discontinuity, assume that m_flOldPlayerZ is in the new space. Therefore, we need to transform the local origin into the new space for comparisons
  1558. Vector vCurrentSpaceLocalOrigin;
  1559. VectorITransform( GetLocalOrigin(), matOriginDisontinuity, vCurrentSpaceLocalOrigin ); //inverse transform because the matrix goes from new space to old space
  1560. flCurrentPlayerZ = vCurrentSpaceLocalOrigin.z;
  1561. }
  1562. }
  1563. #endif
  1564. // Smooth out stair step ups
  1565. // NOTE: Don't want to do this when the ground entity is moving the player
  1566. if ( ( pGroundEntity != NULL && pGroundEntity->GetMoveType() == MOVETYPE_NONE ) && ( flCurrentPlayerZ != m_flOldPlayerZ ) && smoothstairs.GetBool() &&
  1567. m_flOldPlayerViewOffsetZ == flCurrentPlayerViewOffsetZ )
  1568. {
  1569. int dir = ( flCurrentPlayerZ > m_flOldPlayerZ ) ? 1 : -1;
  1570. float steptime = gpGlobals->frametime;
  1571. if (steptime < 0)
  1572. {
  1573. steptime = 0;
  1574. }
  1575. m_flOldPlayerZ += steptime * 150 * dir;
  1576. const float stepSize = 18.0f;
  1577. if ( dir > 0 )
  1578. {
  1579. if (m_flOldPlayerZ > flCurrentPlayerZ)
  1580. {
  1581. m_flOldPlayerZ = flCurrentPlayerZ;
  1582. }
  1583. if (flCurrentPlayerZ - m_flOldPlayerZ > stepSize)
  1584. {
  1585. m_flOldPlayerZ = flCurrentPlayerZ - stepSize;
  1586. }
  1587. }
  1588. else
  1589. {
  1590. if (m_flOldPlayerZ < flCurrentPlayerZ)
  1591. {
  1592. m_flOldPlayerZ = flCurrentPlayerZ;
  1593. }
  1594. if (flCurrentPlayerZ - m_flOldPlayerZ < -stepSize)
  1595. {
  1596. m_flOldPlayerZ = flCurrentPlayerZ + stepSize;
  1597. }
  1598. }
  1599. eyeOrigin[2] += m_flOldPlayerZ - flCurrentPlayerZ;
  1600. }
  1601. else
  1602. {
  1603. m_flOldPlayerZ = flCurrentPlayerZ;
  1604. m_flOldPlayerViewOffsetZ = flCurrentPlayerViewOffsetZ;
  1605. }
  1606. }
  1607. static bool IsWaterContents( int contents )
  1608. {
  1609. if ( contents & MASK_WATER )
  1610. return true;
  1611. // if ( contents & CONTENTS_TESTFOGVOLUME )
  1612. // return true;
  1613. return false;
  1614. }
  1615. void CBasePlayer::ResetObserverMode()
  1616. {
  1617. m_hObserverTarget.Set( 0 );
  1618. m_iObserverMode = (int)OBS_MODE_NONE;
  1619. #ifndef CLIENT_DLL
  1620. m_iObserverLastMode = OBS_MODE_ROAMING;
  1621. m_bForcedObserverMode = false;
  1622. m_afPhysicsFlags &= ~PFLAG_OBSERVER;
  1623. m_bIsSpecLerping = false;
  1624. m_vecSpecLerpIdealPos = Vector( 0, 0, 0 );
  1625. m_angSpecLerpIdealAng = QAngle( 0, 0, 0 );
  1626. m_vecSpecLerpOldPos = Vector( 0, 0, 0 );
  1627. m_angSpecLerpOldAng = QAngle( 0, 0, 0 );
  1628. m_flSpecLerpEndTime = 0.0f;
  1629. m_flSpecLerpTime = 1.0f;
  1630. #else
  1631. UpdateVisibility();
  1632. #endif
  1633. }
  1634. //-----------------------------------------------------------------------------
  1635. // Purpose:
  1636. // Input : eyeOrigin -
  1637. // eyeAngles -
  1638. // zNear -
  1639. // zFar -
  1640. // fov -
  1641. //-----------------------------------------------------------------------------
  1642. void CBasePlayer::CalcView( Vector &eyeOrigin, QAngle &eyeAngles, float &zNear, float &zFar, float &fov )
  1643. {
  1644. #if defined( CLIENT_DLL )
  1645. IClientVehicle *pVehicle;
  1646. #else
  1647. IServerVehicle *pVehicle;
  1648. #endif
  1649. pVehicle = GetVehicle();
  1650. if ( !pVehicle )
  1651. {
  1652. if ( IsObserver() )
  1653. {
  1654. CalcObserverView( eyeOrigin, eyeAngles, fov );
  1655. }
  1656. else
  1657. {
  1658. CalcPlayerView( eyeOrigin, eyeAngles, fov );
  1659. }
  1660. }
  1661. else
  1662. {
  1663. CalcVehicleView( pVehicle, eyeOrigin, eyeAngles, zNear, zFar, fov );
  1664. }
  1665. #if defined( CLIENT_DLL )
  1666. // Set the follow bone if necessary
  1667. FOR_EACH_VALID_SPLITSCREEN_PLAYER( hh )
  1668. {
  1669. ACTIVE_SPLITSCREEN_PLAYER_GUARD( hh );
  1670. static ConVarRef cvFollowBoneIndexVar( "cl_camera_follow_bone_index" );
  1671. CStudioHdr const* pHdr = GetModelPtr();
  1672. if ( pHdr &&
  1673. cvFollowBoneIndexVar.IsValid() &&
  1674. C_BasePlayer::GetLocalPlayer() == this )
  1675. {
  1676. int boneIdx = cvFollowBoneIndexVar.GetInt();
  1677. if ( boneIdx >= -1 && boneIdx < pHdr->numbones() )
  1678. {
  1679. extern Vector g_cameraFollowPos;
  1680. if ( boneIdx == -1 )
  1681. {
  1682. VectorCopy( GetRenderOrigin(), g_cameraFollowPos );
  1683. }
  1684. else if ( pHdr->pBone( boneIdx )->flags & BONE_USED_BY_ANYTHING )
  1685. {
  1686. MatrixPosition( m_BoneAccessor.GetBone( boneIdx ), g_cameraFollowPos );
  1687. }
  1688. }
  1689. }
  1690. }
  1691. #endif
  1692. }
  1693. void CBasePlayer::CalcViewModelView( const Vector& eyeOrigin, const QAngle& eyeAngles)
  1694. {
  1695. for ( int i = 0; i < MAX_VIEWMODELS; i++ )
  1696. {
  1697. CBaseViewModel *vm = GetViewModel( i );
  1698. if ( !vm )
  1699. continue;
  1700. vm->CalcViewModelView( this, eyeOrigin, eyeAngles );
  1701. }
  1702. }
  1703. void CBasePlayer::CalcPlayerView( Vector& eyeOrigin, QAngle& eyeAngles, float& fov )
  1704. {
  1705. #if defined( CLIENT_DLL )
  1706. if ( !prediction->InPrediction() )
  1707. {
  1708. // FIXME: Move into prediction
  1709. view->DriftPitch();
  1710. }
  1711. #endif
  1712. // TrackIR
  1713. if ( IsHeadTrackingEnabled() )
  1714. {
  1715. VectorCopy( EyePosition() + GetEyeOffset(), eyeOrigin );
  1716. }
  1717. else
  1718. {
  1719. VectorCopy( EyePosition(), eyeOrigin );
  1720. }
  1721. VectorCopy( EyeAngles(), eyeAngles );
  1722. #if defined( CLIENT_DLL )
  1723. if ( !prediction->InPrediction() )
  1724. #endif
  1725. {
  1726. SmoothViewOnStairs( eyeOrigin );
  1727. }
  1728. // Snack off the origin before bob + water offset are applied
  1729. Vector vecBaseEyePosition = eyeOrigin;
  1730. QAngle baseEyeAngles = eyeAngles;
  1731. CalcViewBob( eyeOrigin );
  1732. CalcViewRoll( eyeAngles );
  1733. CalcAddViewmodelCameraAnimation( eyeOrigin, eyeAngles );
  1734. // Apply punch angles
  1735. VectorAdd( eyeAngles, m_Local.m_viewPunchAngle, eyeAngles );
  1736. // TODO[pmf]: apply a scaling factor to this
  1737. VectorAdd( eyeAngles, GetAimPunchAngle() * view_recoil_tracking.GetFloat(), eyeAngles );
  1738. #if defined( CLIENT_DLL )
  1739. if ( !prediction->InPrediction() )
  1740. {
  1741. // Shake it up baby!
  1742. GetViewEffects()->CalcShake();
  1743. GetViewEffects()->ApplyShake( eyeOrigin, eyeAngles, 1.0 );
  1744. // Tilting handled in CInput::AdjustAngles
  1745. }
  1746. #endif
  1747. #if defined( CLIENT_DLL )
  1748. // Apply a smoothing offset to smooth out prediction errors.
  1749. Vector vSmoothOffset;
  1750. GetPredictionErrorSmoothingVector( vSmoothOffset );
  1751. eyeOrigin += vSmoothOffset;
  1752. m_flObserverChaseDistance = 0.0;
  1753. #endif
  1754. // calc current FOV
  1755. fov = GetFOV();
  1756. }
  1757. //-----------------------------------------------------------------------------
  1758. // Purpose: The main view setup function for vehicles
  1759. //-----------------------------------------------------------------------------
  1760. void CBasePlayer::CalcVehicleView(
  1761. #if defined( CLIENT_DLL )
  1762. IClientVehicle *pVehicle,
  1763. #else
  1764. IServerVehicle *pVehicle,
  1765. #endif
  1766. Vector& eyeOrigin, QAngle& eyeAngles,
  1767. float& zNear, float& zFar, float& fov )
  1768. {
  1769. Assert( pVehicle );
  1770. // Start with our base origin and angles
  1771. CacheVehicleView();
  1772. eyeOrigin = m_vecVehicleViewOrigin;
  1773. eyeAngles = m_vecVehicleViewAngles;
  1774. // TrackIR
  1775. if ( IsHeadTrackingEnabled() )
  1776. {
  1777. eyeOrigin += GetEyeOffset();
  1778. }
  1779. // TrackIR
  1780. #if defined( CLIENT_DLL )
  1781. fov = GetFOV();
  1782. // Allows the vehicle to change the clip planes
  1783. pVehicle->GetVehicleClipPlanes( zNear, zFar );
  1784. #endif
  1785. // Snack off the origin before bob + water offset are applied
  1786. Vector vecBaseEyePosition = eyeOrigin;
  1787. CalcViewRoll( eyeAngles );
  1788. CalcAddViewmodelCameraAnimation( eyeOrigin, eyeAngles );
  1789. // Apply punch angle
  1790. VectorAdd( eyeAngles, m_Local.m_viewPunchAngle, eyeAngles );
  1791. #if defined( CLIENT_DLL )
  1792. if ( !prediction->InPrediction() )
  1793. {
  1794. // Shake it up baby!
  1795. GetViewEffects()->CalcShake();
  1796. GetViewEffects()->ApplyShake( eyeOrigin, eyeAngles, 1.0 );
  1797. }
  1798. #endif
  1799. #if defined( CLIENT_DLL )
  1800. // Apply a smoothing offset to smooth out prediction errors.
  1801. Vector vSmoothOffset;
  1802. GetPredictionErrorSmoothingVector( vSmoothOffset );
  1803. eyeOrigin += vSmoothOffset;
  1804. #endif
  1805. }
  1806. void CBasePlayer::CalcObserverView( Vector& eyeOrigin, QAngle& eyeAngles, float& fov )
  1807. {
  1808. #if defined( CLIENT_DLL )
  1809. switch ( GetObserverMode() )
  1810. {
  1811. case OBS_MODE_DEATHCAM : CalcDeathCamView( eyeOrigin, eyeAngles, fov );
  1812. break;
  1813. case OBS_MODE_ROAMING : // just copy current position without view offset
  1814. case OBS_MODE_FIXED : CalcRoamingView( eyeOrigin, eyeAngles, fov );
  1815. break;
  1816. case OBS_MODE_IN_EYE : CalcInEyeCamView( eyeOrigin, eyeAngles, fov );
  1817. break;
  1818. case OBS_MODE_CHASE : CalcChaseCamView( eyeOrigin, eyeAngles, fov );
  1819. break;
  1820. case OBS_MODE_FREEZECAM : CalcFreezeCamView( eyeOrigin, eyeAngles, fov );
  1821. break;
  1822. }
  1823. #else
  1824. // on server just copy target postions, final view positions will be calculated on client
  1825. VectorCopy( EyePosition(), eyeOrigin );
  1826. VectorCopy( EyeAngles(), eyeAngles );
  1827. #endif
  1828. }
  1829. //-----------------------------------------------------------------------------
  1830. // Purpose: Compute roll angle for a particular lateral velocity
  1831. // Input : angles -
  1832. // velocity -
  1833. // rollangle -
  1834. // rollspeed -
  1835. // Output : float CViewRender::CalcRoll
  1836. //-----------------------------------------------------------------------------
  1837. float CBasePlayer::CalcRoll (const QAngle& angles, const Vector& velocity, float rollangle, float rollspeed)
  1838. {
  1839. float sign;
  1840. float side;
  1841. float value;
  1842. Vector forward, right, up;
  1843. AngleVectors (angles, &forward, &right, &up);
  1844. // Get amount of lateral movement
  1845. side = DotProduct( velocity, right );
  1846. // Right or left side?
  1847. sign = side < 0 ? -1 : 1;
  1848. side = fabs(side);
  1849. value = rollangle;
  1850. // Hit 100% of rollangle at rollspeed. Below that get linear approx.
  1851. if ( side < rollspeed )
  1852. {
  1853. side = side * value / rollspeed;
  1854. }
  1855. else
  1856. {
  1857. side = value;
  1858. }
  1859. // Scale by right/left sign
  1860. return side*sign;
  1861. }
  1862. //-----------------------------------------------------------------------------
  1863. // Purpose: Allow the viewmodel to layer in artist-authored additive camera animation (to make some first-person anims 'punchier')
  1864. //-----------------------------------------------------------------------------
  1865. #define CAM_DRIVER_RETURN_TO_NORMAL 0.25f
  1866. #define CAM_DRIVER_RETURN_TO_NORMAL_GAIN 0.8f
  1867. void CBasePlayer::CalcAddViewmodelCameraAnimation( Vector& eyeOrigin, QAngle& eyeAngles )
  1868. {
  1869. #ifdef CLIENT_DLL
  1870. CBaseViewModel *vm = GetViewModel();
  1871. if ( vm && vm->GetModelPtr() )
  1872. {
  1873. float flTimeDelta = clamp( (gpGlobals->curtime - vm->m_flCamDriverAppliedTime), 0, CAM_DRIVER_RETURN_TO_NORMAL);
  1874. if ( flTimeDelta < CAM_DRIVER_RETURN_TO_NORMAL )
  1875. {
  1876. vm->m_flCamDriverWeight = clamp( Gain( RemapValClamped( flTimeDelta, 0.0f, CAM_DRIVER_RETURN_TO_NORMAL, 1.0f, 0.0f ), CAM_DRIVER_RETURN_TO_NORMAL_GAIN ), 0, 1 );
  1877. //eyeOrigin += (vm->m_vecCamDriverLastPos * vm->m_flCamDriverWeight);
  1878. eyeAngles += (vm->m_angCamDriverLastAng * vm->m_flCamDriverWeight);
  1879. }
  1880. else
  1881. {
  1882. vm->m_flCamDriverWeight = 0;
  1883. }
  1884. }
  1885. #endif
  1886. }
  1887. //-----------------------------------------------------------------------------
  1888. // Purpose: Determine view roll, including data kick
  1889. //-----------------------------------------------------------------------------
  1890. void CBasePlayer::CalcViewRoll( QAngle& eyeAngles )
  1891. {
  1892. if ( GetMoveType() == MOVETYPE_NOCLIP )
  1893. return;
  1894. float side = CalcRoll( GetAbsAngles(), GetAbsVelocity(), sv_rollangle.GetFloat(), sv_rollspeed.GetFloat() );
  1895. eyeAngles[ROLL] += side;
  1896. }
  1897. #if defined( CSTRIKE15 )
  1898. #if defined( CLIENT_DLL )
  1899. extern ConVar cl_use_new_headbob;
  1900. //ConVar cl_headbob_freq( "cl_headbob_freq", "12", FCVAR_CLIENTDLL );
  1901. //ConVar cl_headbob_amp("cl_headbob_amp", "1.5", FCVAR_CLIENTDLL );
  1902. ConVar cl_headbob_land_dip_amt("cl_headbob_land_dip_amt", "4", FCVAR_CLIENTDLL );
  1903. #endif
  1904. #endif
  1905. void CBasePlayer::CalcViewBob( Vector& eyeOrigin )
  1906. {
  1907. #if defined( CSTRIKE15 )
  1908. #if defined( CLIENT_DLL )
  1909. if ( cl_use_new_headbob.GetBool() == false )
  1910. return;
  1911. Vector vecBaseEyePosition = eyeOrigin;
  1912. // if we just landed, dip the player's view
  1913. float flOldFallVel = m_Local.m_flOldFallVelocity;
  1914. float flFallVel = m_Local.m_flFallVelocity;
  1915. //Msg("Fall Velocity: %f\n", flFallVel );
  1916. if ( flFallVel <= 0.1f && flOldFallVel > 10.0f && flOldFallVel <= PLAYER_FATAL_FALL_SPEED && m_Local.m_bInLanding == false )
  1917. {
  1918. m_Local.m_bInLanding = true;
  1919. m_Local.m_flLandingTime = gpGlobals->curtime;
  1920. }
  1921. // don't bob the view right now
  1922. /*
  1923. const float flMaxSpeed = sv_maxspeed.GetFloat();
  1924. float flSpeedFactor;
  1925. */
  1926. if ( m_Local.m_bInLanding == true )
  1927. {
  1928. float landseconds = MAX(gpGlobals->curtime - m_Local.m_flLandingTime, 0.0f);
  1929. float landFraction = SimpleSpline( landseconds / 0.25f );
  1930. clamp( landFraction, 0.0f, 1.0f );
  1931. float flDipAmount = (1 / flOldFallVel) * 0.1f;
  1932. int dipHighOffset = 64;
  1933. int dipLowOffset = dipHighOffset - cl_headbob_land_dip_amt.GetInt();
  1934. Vector temp = GetViewOffset();
  1935. temp.z = ( ( dipLowOffset - flDipAmount ) * landFraction ) +
  1936. ( dipHighOffset * ( 1 - landFraction ) );
  1937. if ( temp.z > dipHighOffset )
  1938. {
  1939. temp.z = dipHighOffset;
  1940. m_Local.m_bInLanding = false;
  1941. }
  1942. eyeOrigin.z -= ( dipHighOffset - temp.z );
  1943. //SetViewOffset( temp );
  1944. }
  1945. else
  1946. {
  1947. // don't bob the view right now
  1948. /*
  1949. flSpeedFactor = GetAbsVelocity().Length() / flMaxSpeed;
  1950. clamp( flSpeedFactor, 0.0f, 1.0f );
  1951. eyeOrigin.z += flSpeedFactor * (sin(gpGlobals->curtime * cl_headbob_freq.GetFloat() ) * cl_headbob_amp.GetFloat());
  1952. */
  1953. }
  1954. // stop when our eyes get back to default
  1955. if ( m_Local.m_bInLanding == true && ( (eyeOrigin.z - 0.001f) >= vecBaseEyePosition.z ) )
  1956. {
  1957. m_Local.m_bInLanding = false;
  1958. }
  1959. if ( m_Local.m_bInLanding == false )
  1960. {
  1961. // Set the old velocity to the new velocity, we check next frame to see if we hit the ground
  1962. m_Local.m_flOldFallVelocity = m_Local.m_flFallVelocity;
  1963. }
  1964. #endif
  1965. #endif
  1966. }
  1967. void CBasePlayer::DoMuzzleFlash()
  1968. {
  1969. for ( int i = 0; i < MAX_VIEWMODELS; i++ )
  1970. {
  1971. CBaseViewModel *vm = GetViewModel( i );
  1972. if ( !vm )
  1973. continue;
  1974. vm->DoMuzzleFlash();
  1975. }
  1976. BaseClass::DoMuzzleFlash();
  1977. }
  1978. float CBasePlayer::GetFOVDistanceAdjustFactor()
  1979. {
  1980. float defaultFOV = (float)GetDefaultFOV();
  1981. float localFOV = (float)GetFOV();
  1982. if ( localFOV == defaultFOV || defaultFOV < 0.001f )
  1983. {
  1984. return 1.0f;
  1985. }
  1986. // If FOV is lower, then we're "zoomed" in and this will give a factor < 1 so apparent LOD distances can be
  1987. // shorted accordingly
  1988. return localFOV / defaultFOV;
  1989. }
  1990. //-----------------------------------------------------------------------------
  1991. // Purpose:
  1992. // Input : &vecTracerSrc -
  1993. // &tr -
  1994. // iTracerType -
  1995. //-----------------------------------------------------------------------------
  1996. void CBasePlayer::MakeTracer( const Vector &vecTracerSrc, const trace_t &tr, int iTracerType )
  1997. {
  1998. if ( GetActiveWeapon() )
  1999. {
  2000. GetActiveWeapon()->MakeTracer( vecTracerSrc, tr, iTracerType );
  2001. return;
  2002. }
  2003. BaseClass::MakeTracer( vecTracerSrc, tr, iTracerType );
  2004. }
  2005. void CBasePlayer::SharedSpawn()
  2006. {
  2007. SetMoveType( MOVETYPE_WALK );
  2008. SetSolid( SOLID_BBOX );
  2009. AddSolidFlags( FSOLID_NOT_STANDABLE );
  2010. SetFriction( 1.0f );
  2011. pl.deadflag = false;
  2012. m_lifeState = LIFE_ALIVE;
  2013. m_iHealth = 100;
  2014. m_takedamage = DAMAGE_YES;
  2015. m_Local.m_bDrawViewmodel = true;
  2016. m_Local.m_flStepSize = sv_stepsize.GetFloat();
  2017. m_Local.m_bAllowAutoMovement = true;
  2018. SetRenderFX( kRenderFxNone );
  2019. m_flNextAttack = gpGlobals->curtime;
  2020. m_flMaxspeed = 0.0f;
  2021. MDLCACHE_CRITICAL_SECTION();
  2022. int iIdleSequence = SelectWeightedSequence( ACT_IDLE );
  2023. if( iIdleSequence < 0 )
  2024. {
  2025. iIdleSequence = 0;
  2026. }
  2027. SetSequence( iIdleSequence );
  2028. if ( GetFlags() & FL_DUCKING )
  2029. SetCollisionBounds( VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX );
  2030. else
  2031. SetCollisionBounds( VEC_HULL_MIN, VEC_HULL_MAX );
  2032. // dont let uninitialized value here hurt the player
  2033. m_Local.m_flFallVelocity = 0;
  2034. SetBloodColor( BLOOD_COLOR_RED );
  2035. m_hUseEntity = NULL;
  2036. m_flDuckAmount = 0;
  2037. m_flDuckSpeed = CS_PLAYER_DUCK_SPEED_IDEAL;
  2038. }
  2039. //-----------------------------------------------------------------------------
  2040. // Purpose:
  2041. // Output : int
  2042. //-----------------------------------------------------------------------------
  2043. int CBasePlayer::GetDefaultFOV( void ) const
  2044. {
  2045. #if defined( CLIENT_DLL )
  2046. if ( GetObserverMode() == OBS_MODE_IN_EYE )
  2047. {
  2048. C_BasePlayer *pTargetPlayer = ToBasePlayer( GetObserverTarget() );
  2049. if ( pTargetPlayer && !pTargetPlayer->IsObserver() )
  2050. {
  2051. return pTargetPlayer->GetDefaultFOV();
  2052. }
  2053. }
  2054. #endif
  2055. int iFOV = ( m_iDefaultFOV == 0 ) ? g_pGameRules->DefaultFOV() : m_iDefaultFOV;
  2056. return iFOV;
  2057. }
  2058. void CBasePlayer::AvoidPhysicsProps( CUserCmd *pCmd )
  2059. {
  2060. // Don't avoid if noclipping or in movetype none
  2061. switch ( GetMoveType() )
  2062. {
  2063. case MOVETYPE_NOCLIP:
  2064. case MOVETYPE_NONE:
  2065. case MOVETYPE_OBSERVER:
  2066. return;
  2067. default:
  2068. break;
  2069. }
  2070. if ( GetObserverMode() != OBS_MODE_NONE || !IsAlive() )
  2071. return;
  2072. AvoidPushawayProps( this, pCmd );
  2073. }
  2074. //-----------------------------------------------------------------------------
  2075. // Purpose:
  2076. // Output : const char
  2077. //-----------------------------------------------------------------------------
  2078. const char *CBasePlayer::GetTracerType( void )
  2079. {
  2080. if ( GetActiveWeapon() )
  2081. {
  2082. return GetActiveWeapon()->GetTracerType();
  2083. }
  2084. return BaseClass::GetTracerType();
  2085. }
  2086. //-----------------------------------------------------------------------------
  2087. // Purpose:
  2088. //-----------------------------------------------------------------------------
  2089. void CBasePlayer::ClearZoomOwner( void )
  2090. {
  2091. m_hZoomOwner = NULL;
  2092. }
  2093. //-----------------------------------------------------------------------------
  2094. // Purpose: Sets the FOV of the client, doing interpolation between old and new if requested
  2095. // Input : FOV - New FOV
  2096. // zoomRate - Amount of time (in seconds) to move between old and new FOV
  2097. //-----------------------------------------------------------------------------
  2098. bool CBasePlayer::SetFOV( CBaseEntity *pRequester, int FOV, float zoomRate, int iZoomStart /* = 0 */ )
  2099. {
  2100. //NOTENOTE: You MUST specify who is requesting the zoom change
  2101. assert( pRequester != NULL );
  2102. if ( pRequester == NULL )
  2103. return false;
  2104. // If we already have an owner, we only allow requests from that owner
  2105. if ( ( m_hZoomOwner.Get() != NULL ) && ( m_hZoomOwner.Get() != pRequester ) )
  2106. {
  2107. #ifdef GAME_DLL
  2108. if ( CanOverrideEnvZoomOwner( m_hZoomOwner.Get() ) == false )
  2109. #endif
  2110. return false;
  2111. }
  2112. else
  2113. {
  2114. //FIXME: Maybe do this is as an accessor instead
  2115. if ( FOV == 0 )
  2116. {
  2117. m_hZoomOwner = NULL;
  2118. }
  2119. else
  2120. {
  2121. m_hZoomOwner = pRequester;
  2122. }
  2123. }
  2124. // Setup our FOV and our scaling time
  2125. if ( iZoomStart > 0 )
  2126. {
  2127. m_iFOVStart = iZoomStart;
  2128. }
  2129. else
  2130. {
  2131. m_iFOVStart = GetFOV();
  2132. }
  2133. m_flFOVTime = gpGlobals->curtime;
  2134. m_iFOV = FOV;
  2135. m_Local.m_flFOVRate = zoomRate;
  2136. return true;
  2137. }
  2138. //-----------------------------------------------------------------------------
  2139. // Purpose:
  2140. //-----------------------------------------------------------------------------
  2141. void CBasePlayer::UpdateUnderwaterState( void )
  2142. {
  2143. if ( GetWaterLevel() == WL_Eyes )
  2144. {
  2145. if ( IsPlayerUnderwater() == false )
  2146. {
  2147. SetPlayerUnderwater( true );
  2148. }
  2149. return;
  2150. }
  2151. if ( IsPlayerUnderwater() )
  2152. {
  2153. SetPlayerUnderwater( false );
  2154. }
  2155. if ( GetWaterLevel() == WL_NotInWater )
  2156. {
  2157. if ( GetFlags() & FL_INWATER )
  2158. {
  2159. #ifndef CLIENT_DLL
  2160. if ( m_iHealth > 0 && IsAlive() )
  2161. {
  2162. if ( GetAbsVelocity().Length() >= 135 )
  2163. {
  2164. EmitSound( "Player.Wade" );
  2165. }
  2166. }
  2167. #endif
  2168. RemoveFlag( FL_INWATER );
  2169. }
  2170. }
  2171. else if ( !(GetFlags() & FL_INWATER) )
  2172. {
  2173. #ifndef CLIENT_DLL
  2174. // player enter water sound
  2175. if (GetWaterType() == CONTENTS_WATER)
  2176. {
  2177. if ( GetAbsVelocity().Length() >= 135 )
  2178. {
  2179. EmitSound( "Player.Wade" );
  2180. }
  2181. }
  2182. #endif
  2183. AddFlag( FL_INWATER );
  2184. }
  2185. }
  2186. //-----------------------------------------------------------------------------
  2187. // Purpose: data accessor
  2188. // ensure that for every emitsound there is a matching stopsound
  2189. //-----------------------------------------------------------------------------
  2190. void CBasePlayer::SetPlayerUnderwater( bool state )
  2191. {
  2192. if ( m_bPlayerUnderwater != state )
  2193. {
  2194. m_bPlayerUnderwater = state;
  2195. #ifdef CLIENT_DLL
  2196. if ( state )
  2197. EmitSound( "Player.AmbientUnderWater" );
  2198. else
  2199. StopSound( "Player.AmbientUnderWater" );
  2200. #endif
  2201. }
  2202. }
  2203. void CBasePlayer::SetPreviouslyPredictedOrigin( const Vector &vecAbsOrigin )
  2204. {
  2205. m_vecPreviouslyPredictedOrigin = vecAbsOrigin;
  2206. }
  2207. const Vector &CBasePlayer::GetPreviouslyPredictedOrigin() const
  2208. {
  2209. return m_vecPreviouslyPredictedOrigin;
  2210. }
  2211. bool fogparams_t::operator !=( const fogparams_t& other ) const
  2212. {
  2213. if ( this->enable != other.enable ||
  2214. this->blend != other.blend ||
  2215. !VectorsAreEqual(this->dirPrimary, other.dirPrimary, 0.01f ) ||
  2216. this->colorPrimary.Get() != other.colorPrimary.Get() ||
  2217. this->colorSecondary.Get() != other.colorSecondary.Get() ||
  2218. this->start != other.start ||
  2219. this->end != other.end ||
  2220. this->farz != other.farz ||
  2221. this->maxdensity != other.maxdensity ||
  2222. this->colorPrimaryLerpTo.Get() != other.colorPrimaryLerpTo.Get() ||
  2223. this->colorSecondaryLerpTo.Get() != other.colorSecondaryLerpTo.Get() ||
  2224. this->startLerpTo != other.startLerpTo ||
  2225. this->endLerpTo != other.endLerpTo ||
  2226. this->maxdensityLerpTo != other.maxdensityLerpTo ||
  2227. this->lerptime != other.lerptime ||
  2228. this->duration != other.duration ||
  2229. this->HDRColorScale != other.HDRColorScale ||
  2230. this->ZoomFogScale != other.ZoomFogScale)
  2231. return true;
  2232. return false;
  2233. }
  2234. void CBasePlayer::IncrementEFNoInterpParity()
  2235. {
  2236. // Only matters in multiplayer
  2237. if ( gpGlobals->maxClients == 1 )
  2238. return;
  2239. m_ubEFNoInterpParity = (m_ubEFNoInterpParity + 1) % NOINTERP_PARITY_MAX;
  2240. }
  2241. int CBasePlayer::GetEFNoInterpParity() const
  2242. {
  2243. return (int)m_ubEFNoInterpParity;
  2244. }
  2245. void CBasePlayer::AddSplitScreenPlayer( CBasePlayer *pOther )
  2246. {
  2247. CHandle< CBasePlayer > h;
  2248. h = pOther;
  2249. if ( m_hSplitScreenPlayers.Find( h ) == m_hSplitScreenPlayers.InvalidIndex() )
  2250. {
  2251. m_hSplitScreenPlayers.AddToTail( h );
  2252. }
  2253. UpdateSplitScreenAndPictureInPicturePlayerList();
  2254. }
  2255. void CBasePlayer::RemoveSplitScreenPlayer( CBasePlayer *pOther )
  2256. {
  2257. CHandle< CBasePlayer > h;
  2258. h = pOther;
  2259. m_hSplitScreenPlayers.FindAndRemove( h );
  2260. UpdateSplitScreenAndPictureInPicturePlayerList();
  2261. }
  2262. CUtlVector< CHandle< CBasePlayer > > &CBasePlayer::GetSplitScreenPlayers()
  2263. {
  2264. return m_hSplitScreenPlayers;
  2265. }
  2266. bool CBasePlayer::HasAttachedSplitScreenPlayers() const
  2267. {
  2268. return ( m_hSplitScreenPlayers.Count() > 0 );
  2269. }
  2270. void CBasePlayer::AddPictureInPicturePlayer( CBasePlayer *pOther )
  2271. {
  2272. CHandle< CBasePlayer > h;
  2273. h = pOther;
  2274. if ( m_hPipPlayers.Find( h ) == m_hPipPlayers.InvalidIndex() )
  2275. {
  2276. m_hPipPlayers.AddToTail( h );
  2277. }
  2278. UpdateSplitScreenAndPictureInPicturePlayerList();
  2279. }
  2280. void CBasePlayer::RemovePictureInPicturePlayer( CBasePlayer *pOther )
  2281. {
  2282. CHandle< CBasePlayer > h;
  2283. h = pOther;
  2284. m_hPipPlayers.FindAndRemove( h );
  2285. UpdateSplitScreenAndPictureInPicturePlayerList();
  2286. }
  2287. CUtlVector< CHandle< CBasePlayer > > &CBasePlayer::GetSplitScreenAndPictureInPicturePlayers()
  2288. {
  2289. return m_hSplitScreenAndPipPlayers;
  2290. }
  2291. CUtlVector< CHandle< CBasePlayer > >& CBasePlayer::GetPictureInPicturePlayers( void )
  2292. {
  2293. return m_hPipPlayers;
  2294. }
  2295. void CBasePlayer::UpdateSplitScreenAndPictureInPicturePlayerList()
  2296. {
  2297. // Make m_hSplitScreenAndPipPlayers the union of m_hSplitScreenPlayers and m_hPipPlayers
  2298. m_hSplitScreenAndPipPlayers.RemoveAll();
  2299. m_hSplitScreenAndPipPlayers.AddVectorToTail( m_hSplitScreenPlayers );
  2300. for ( int i = 0; i < m_hPipPlayers.Count(); i++ )
  2301. {
  2302. CHandle< CBasePlayer > h = m_hPipPlayers[i];
  2303. if ( m_hSplitScreenAndPipPlayers.Find( h ) == m_hSplitScreenAndPipPlayers.InvalidIndex() )
  2304. {
  2305. m_hSplitScreenAndPipPlayers.AddToTail( h );
  2306. }
  2307. }
  2308. }
  2309. //-----------------------------------------------------------------------------
  2310. // Purpose: Strips off IN_xxx flags from the player's input
  2311. //-----------------------------------------------------------------------------
  2312. void CBasePlayer::ForceButtons( int nButtons )
  2313. {
  2314. m_afButtonForced |= nButtons;
  2315. }
  2316. //-----------------------------------------------------------------------------
  2317. // Purpose: Re-enables stripped IN_xxx flags to the player's input
  2318. //-----------------------------------------------------------------------------
  2319. void CBasePlayer::UnforceButtons( int nButtons )
  2320. {
  2321. m_afButtonForced &= ~nButtons;
  2322. }
  2323. CBaseEntity* CBasePlayer::GetSoundscapeListener()
  2324. {
  2325. return this;
  2326. }
  2327. void CBasePlayer::SetUseEntity( CBaseEntity *pUseEntity )
  2328. {
  2329. m_hUseEntity = pUseEntity;
  2330. }
  2331. #if defined( PORTAL2 ) || !defined( CLIENT_DLL )
  2332. bool CBasePlayer::ClearUseEntity()
  2333. {
  2334. if ( m_hUseEntity != NULL )
  2335. {
  2336. #if !defined( CLIENT_DLL )
  2337. if( !m_bDropEnabled )
  2338. {
  2339. return false;
  2340. }
  2341. #endif
  2342. // Stop controlling the train/object
  2343. // TODO: Send HUD Update
  2344. #if defined ( PORTAL2 )
  2345. CPlayerPickupController *pPickup = (CPlayerPickupController*)GetUseEntity();
  2346. Assert( pPickup );
  2347. if ( pPickup )
  2348. {
  2349. if ( pPickup->UsePickupController( this, this, USE_OFF, 0 ) )
  2350. {
  2351. m_hUseEntity = NULL;
  2352. return true;
  2353. }
  2354. }
  2355. #else
  2356. GetUseEntity()->Use( this, this, USE_OFF, 0 );
  2357. #endif // PORTAL2
  2358. }
  2359. return false;
  2360. }
  2361. //-----------------------------------------------------------------------------
  2362. // Purpose:
  2363. //-----------------------------------------------------------------------------
  2364. bool CBasePlayer::CanPickupObject( CBaseEntity *pObject, float massLimit, float sizeLimit )
  2365. {
  2366. // UNDONE: Make this virtual and move to HL2 player
  2367. #if defined( HL2_DLL ) || defined( PORTAL2 )
  2368. //Must be valid
  2369. if ( pObject == NULL )
  2370. return false;
  2371. //Must move with physics
  2372. if ( pObject->GetMoveType() != MOVETYPE_VPHYSICS )
  2373. return false;
  2374. IPhysicsObject *pList[VPHYSICS_MAX_OBJECT_LIST_COUNT];
  2375. int count = pObject->VPhysicsGetObjectList( pList, ARRAYSIZE(pList) );
  2376. //Must have a physics object
  2377. if (!count)
  2378. return false;
  2379. float objectMass = 0;
  2380. bool checkEnable = false;
  2381. for ( int i = 0; i < count; i++ )
  2382. {
  2383. objectMass += pList[i]->GetMass();
  2384. if ( !pList[i]->IsMoveable() )
  2385. {
  2386. checkEnable = true;
  2387. }
  2388. if ( pList[i]->GetGameFlags() & FVPHYSICS_NO_PLAYER_PICKUP )
  2389. return false;
  2390. if ( pList[i]->IsHinged() )
  2391. return false;
  2392. }
  2393. //Msg( "Target mass: %f\n", pPhys->GetMass() );
  2394. //Must be under our threshold weight
  2395. if ( massLimit > 0 && objectMass > massLimit )
  2396. return false;
  2397. if ( checkEnable )
  2398. {
  2399. // Allow pickup of phys props that are motion enabled on player pickup
  2400. CPhysicsProp *pProp = dynamic_cast<CPhysicsProp*>(pObject);
  2401. CPhysBox *pBox = dynamic_cast<CPhysBox*>(pObject);
  2402. if ( !pProp && !pBox )
  2403. return false;
  2404. #if !defined ( CLIENT_DLL )
  2405. if ( pProp && !(pProp->HasSpawnFlags( SF_PHYSPROP_ENABLE_ON_PHYSCANNON )) )
  2406. return false;
  2407. if ( pBox && !(pBox->HasSpawnFlags( SF_PHYSBOX_ENABLE_ON_PHYSCANNON )) )
  2408. return false;
  2409. #endif
  2410. }
  2411. if ( sizeLimit > 0 )
  2412. {
  2413. const Vector &size = pObject->CollisionProp()->OBBSize();
  2414. if ( size.x > sizeLimit || size.y > sizeLimit || size.z > sizeLimit )
  2415. return false;
  2416. }
  2417. return true;
  2418. #else
  2419. return false;
  2420. #endif
  2421. }
  2422. float CBasePlayer::GetHeldObjectMass( IPhysicsObject *pHeldObject )
  2423. {
  2424. return 0;
  2425. }
  2426. #endif
  2427. //-----------------------------------------------------------------------------
  2428. // Purpose:
  2429. //-----------------------------------------------------------------------------
  2430. void CBasePlayer::VPhysicsShadowUpdate( IPhysicsObject *pPhysics )
  2431. {
  2432. if ( sv_turbophysics.GetBool() )
  2433. return;
  2434. #if defined( DEBUG_MOTION_CONTROLLERS ) && defined( CLIENT_DLL )
  2435. GetVectors( NULL, &g_vShift, NULL );
  2436. g_vShift *= cl_shadowupdatespacing.GetFloat();
  2437. #endif
  2438. Vector newPosition;
  2439. bool physicsUpdated = m_pPhysicsController->GetShadowPosition( &newPosition, NULL ) > 0 ? true : false;
  2440. #if defined( GAME_DLL )
  2441. // UNDONE: If the player is penetrating, but the player's game collisions are not stuck, teleport the physics shadow to the game position
  2442. if ( pPhysics->GetGameFlags() & FVPHYSICS_PENETRATING )
  2443. {
  2444. CUtlVector<CBaseEntity *> list;
  2445. PhysGetListOfPenetratingEntities( this, list );
  2446. for ( int i = list.Count()-1; i >= 0; --i )
  2447. {
  2448. // filter out anything that isn't simulated by vphysics
  2449. // UNDONE: Filter out motion disabled objects?
  2450. if ( list[i]->GetMoveType() == MOVETYPE_VPHYSICS )
  2451. {
  2452. // I'm currently stuck inside a moving object, so allow vphysics to
  2453. // apply velocity to the player in order to separate these objects
  2454. m_bTouchedPhysObject = true;
  2455. }
  2456. // if it's an NPC, tell them that the player is intersecting them
  2457. CAI_BaseNPC *pNPC = list[i]->MyNPCPointer();
  2458. if ( pNPC )
  2459. {
  2460. pNPC->PlayerPenetratingVPhysics();
  2461. }
  2462. }
  2463. }
  2464. #endif
  2465. bool bCheckStuck = false;
  2466. if ( m_afPhysicsFlags & PFLAG_GAMEPHYSICS_ROTPUSH )
  2467. {
  2468. bCheckStuck = true;
  2469. m_afPhysicsFlags &= ~PFLAG_GAMEPHYSICS_ROTPUSH;
  2470. }
  2471. uint32 nContactState = m_pPhysicsController->GetContactState( FVPHYSICS_PUSH_PLAYER );
  2472. if ( (nContactState & PLAYER_CONTACT_PHYSICS) || (m_afPhysicsFlags & PFLAG_VPHYSICS_MOTIONCONTROLLER) )
  2473. {
  2474. m_bTouchedPhysObject = true;
  2475. }
  2476. if ( IsFollowingPhysics() )
  2477. {
  2478. m_bTouchedPhysObject = true;
  2479. }
  2480. #if defined( CLIENT_DLL )
  2481. if( !cl_predict_motioncontrol.GetBool() )
  2482. {
  2483. m_bTouchedPhysObject = false;
  2484. }
  2485. #endif
  2486. if ( GetMoveType() == MOVETYPE_NOCLIP || pl.deadflag )
  2487. {
  2488. m_oldOrigin = GetAbsOrigin();
  2489. return;
  2490. }
  2491. #if defined( GAME_DLL )
  2492. if ( phys_timescale.GetFloat() == 0.0f )
  2493. {
  2494. physicsUpdated = false;
  2495. }
  2496. #endif
  2497. if ( !physicsUpdated )
  2498. return;
  2499. IPhysicsObject *pPhysGround = GetGroundVPhysics();
  2500. Vector newVelocity;
  2501. pPhysics->GetPosition( &newPosition, 0 );
  2502. m_pPhysicsController->GetShadowVelocity( &newVelocity );
  2503. // assume vphysics gave us back a position without penetration
  2504. Vector lastValidPosition = newPosition;
  2505. if ( physicsshadowupdate_render.GetBool() )
  2506. {
  2507. #if defined( GAME_DLL )
  2508. NDebugOverlay::Box( GetAbsOrigin(), WorldAlignMins(), WorldAlignMaxs(), 255, 0, 0, 24, 15.0f );
  2509. NDebugOverlay::Box( newPosition, WorldAlignMins(), WorldAlignMaxs(), 0,0,255, 24, 15.0f);
  2510. // NDebugOverlay::Box( newPosition, WorldAlignMins(), WorldAlignMaxs(), 0,0,255, 24, .01f);
  2511. #else
  2512. NDebugOverlay::Box( GetAbsOrigin(), WorldAlignMins(), WorldAlignMaxs(), 255, 255, 0, 24, 15.0f );
  2513. NDebugOverlay::Box( newPosition, WorldAlignMins(), WorldAlignMaxs(), 0,255,255, 24, 15.0f);
  2514. // NDebugOverlay::Box( newPosition, WorldAlignMins(), WorldAlignMaxs(), 0,255,255, 24, .01f);
  2515. #endif
  2516. }
  2517. Vector tmp = GetAbsOrigin() - newPosition;
  2518. if ( !m_bTouchedPhysObject && !(GetFlags() & FL_ONGROUND) )
  2519. {
  2520. tmp.z *= 0.5f; // don't care about z delta as much
  2521. }
  2522. float dist = tmp.LengthSqr();
  2523. float deltaV = (newVelocity - GetAbsVelocity()).LengthSqr();
  2524. float maxDistErrorSqr = VPHYS_MAX_DISTSQR;
  2525. float maxVelErrorSqr = VPHYS_MAX_VELSQR;
  2526. if ( IsRideablePhysics(pPhysGround) )
  2527. {
  2528. maxDistErrorSqr *= 0.25;
  2529. maxVelErrorSqr *= 0.25;
  2530. }
  2531. // player's physics was frozen, try moving to the game's simulated position if possible
  2532. if ( m_pPhysicsController->WasFrozen() )
  2533. {
  2534. m_bPhysicsWasFrozen = true;
  2535. // check my position (physics object could have simulated into my position
  2536. // physics is not very far away, check my position
  2537. trace_t trace;
  2538. UTIL_TraceEntity( this, GetAbsOrigin(), GetAbsOrigin(), PhysicsSolidMaskForEntity(), this, COLLISION_GROUP_PLAYER_MOVEMENT, &trace );
  2539. if ( !trace.startsolid )
  2540. return;
  2541. // The physics shadow position is probably not in solid, try to move from there to the desired position
  2542. UTIL_TraceEntity( this, newPosition, GetAbsOrigin(), PhysicsSolidMaskForEntity(), this, COLLISION_GROUP_PLAYER_MOVEMENT, &trace );
  2543. if ( !trace.startsolid )
  2544. {
  2545. // found a valid position between the two? take it.
  2546. SetAbsOrigin( trace.endpos );
  2547. UpdateVPhysicsPosition(trace.endpos, vec3_origin, 0);
  2548. return;
  2549. }
  2550. }
  2551. if ( dist >= maxDistErrorSqr || deltaV >= maxVelErrorSqr || (pPhysGround && !m_bTouchedPhysObject) )
  2552. {
  2553. if ( m_bTouchedPhysObject || pPhysGround )
  2554. {
  2555. // BUGBUG: Rewrite this code using fixed timestep
  2556. if ( deltaV >= maxVelErrorSqr && !m_bPhysicsWasFrozen )
  2557. {
  2558. if ( !IsRideablePhysics(pPhysGround) )
  2559. {
  2560. Vector dir = GetAbsVelocity();
  2561. float len = VectorNormalize(dir);
  2562. float dot = DotProduct( newVelocity, dir );
  2563. if ( dot > len )
  2564. {
  2565. dot = len;
  2566. }
  2567. else if ( dot < -len )
  2568. {
  2569. dot = -len;
  2570. }
  2571. VectorMA( newVelocity, -dot, dir, newVelocity );
  2572. if ( m_afPhysicsFlags & PFLAG_VPHYSICS_MOTIONCONTROLLER )
  2573. {
  2574. float val = Lerp( 0.1f, len, dot );
  2575. VectorMA( newVelocity, val - len, dir, newVelocity );
  2576. }
  2577. if ( !(m_afPhysicsFlags & PFLAG_VPHYSICS_MOTIONCONTROLLER ) && IsSimulatingOnAlternateTicks() )
  2578. {
  2579. newVelocity *= 0.5f;
  2580. }
  2581. ApplyAbsVelocityImpulse( newVelocity );
  2582. }
  2583. else
  2584. {
  2585. Vector forward, right, up;
  2586. AngleVectors (g_pMoveData->m_vecViewAngles, &forward, &right, &up); // Determine movement angles
  2587. // Copy movement amounts
  2588. float fmove = g_pMoveData->m_flForwardMove;
  2589. float smove = g_pMoveData->m_flSideMove;
  2590. // Keep movement vectors in our plane of movement
  2591. forward -= Vector(0,0,-1) * DotProduct( forward, Vector(0,0,-1) );
  2592. VectorNormalize( forward );
  2593. right -= Vector(0,0,-1) * DotProduct( right, Vector(0,0,-1) );
  2594. VectorNormalize( right );
  2595. // Determine velocity
  2596. Vector wishvel = fmove * forward + smove * right;
  2597. // HACK!: This code let's the player walk around with a little more control when on a func_physbox.
  2598. // They still slide around more than physical objects, but at least you can actually
  2599. // control yourself.
  2600. // Trying to walk around
  2601. if( wishvel.Length2DSqr() )
  2602. {
  2603. Vector vVel = -newVelocity;
  2604. vVel += GetAbsVelocity() + wishvel;
  2605. // Clamp or else this can get wildy huge and I don't know why
  2606. for( int i=0; i<3; ++i )
  2607. {
  2608. vVel[i] = clamp( vVel[i], newVelocity[i] - 180, newVelocity[i] + 180 );
  2609. }
  2610. SetAbsVelocity( vVel );
  2611. }
  2612. }
  2613. }
  2614. trace_t trace;
  2615. UTIL_TraceEntity( this, newPosition, newPosition, PhysicsSolidMaskForEntity(), this, COLLISION_GROUP_PLAYER_MOVEMENT, &trace );
  2616. if ( !trace.allsolid && !trace.startsolid )
  2617. {
  2618. SetAbsOrigin( newPosition );
  2619. }
  2620. }
  2621. else
  2622. {
  2623. #if defined( PORTAL ) && defined( GAME_DLL )
  2624. CPortal_Player *pPortalPlayer = (CPortal_Player *)this;
  2625. CPortal_Base2D *pPortalEnvironment = pPortalPlayer->m_hPortalEnvironment.Get();
  2626. if( pPortalEnvironment != NULL )
  2627. {
  2628. trace_t trace;
  2629. Ray_t ray;
  2630. ray.Init( GetAbsOrigin(), GetAbsOrigin(), WorldAlignMins(), WorldAlignMaxs() );
  2631. CTraceFilterSimple OriginalTraceFilter( this, COLLISION_GROUP_PLAYER_MOVEMENT );
  2632. CTraceFilterTranslateClones traceFilter( &OriginalTraceFilter );
  2633. enginetrace->TraceRay( ray, MASK_PLAYERSOLID, &traceFilter, &trace );
  2634. if( trace.startsolid )
  2635. {
  2636. UTIL_Portal_TraceRay_With( pPortalEnvironment, ray, MASK_PLAYERSOLID, &traceFilter, &trace );
  2637. // current position is not ok, fixup
  2638. if ( trace.allsolid || trace.startsolid )
  2639. {
  2640. //try again with new position
  2641. ray.Init( newPosition, newPosition, WorldAlignMins(), WorldAlignMaxs() );
  2642. UTIL_Portal_TraceRay_With( pPortalEnvironment, ray, MASK_PLAYERSOLID, &traceFilter, &trace );
  2643. if( trace.startsolid == false )
  2644. {
  2645. SetAbsOrigin( newPosition );
  2646. }
  2647. else
  2648. {
  2649. Vector vNewCenter = vec3_origin;
  2650. Vector vExtents = (pPortalPlayer->GetHullMaxs() - pPortalPlayer->GetHullMins()) * 0.5f;
  2651. Vector vOriginToCenter = (pPortalPlayer->GetHullMaxs() + pPortalPlayer->GetHullMins()) * 0.5f;
  2652. if( UTIL_FindClosestPassableSpace_InPortal_CenterMustStayInFront( pPortalEnvironment, GetAbsOrigin() + vOriginToCenter, vExtents, pPortalEnvironment->m_plane_Origin.normal, &traceFilter, MASK_PLAYERSOLID, 100, vNewCenter ) &&
  2653. (pPortalEnvironment->m_plane_Origin.normal.Dot( vNewCenter ) - pPortalEnvironment->m_plane_Origin.dist) >= 0.0f )
  2654. {
  2655. SetAbsOrigin( vNewCenter - vOriginToCenter );
  2656. }
  2657. else
  2658. {
  2659. VPlane stayInFrontOfPlane;
  2660. stayInFrontOfPlane.m_Normal = pPortalEnvironment->m_plane_Origin.normal;
  2661. stayInFrontOfPlane.m_Dist = pPortalEnvironment->m_plane_Origin.dist;
  2662. if( !(UTIL_FindClosestPassableSpace_CenterMustStayInFrontOfPlane( GetAbsOrigin() + vOriginToCenter, vExtents, newPosition - GetAbsOrigin(), &traceFilter, MASK_PLAYERSOLID, 100, vNewCenter, stayInFrontOfPlane ) &&
  2663. (pPortalEnvironment->m_plane_Origin.normal.Dot( vNewCenter ) - pPortalEnvironment->m_plane_Origin.dist) >= 0.0f) )
  2664. {
  2665. // Try moving the player closer to the center of the portal
  2666. newPosition += ( pPortalEnvironment->GetAbsOrigin() - WorldSpaceCenter() ) * 0.1f;
  2667. SetAbsOrigin( newPosition );
  2668. DevMsg( "Hurting the player for FindClosestPassableSpaceFailure!\n" );
  2669. // Deal 1 damage per frame... this will kill a player very fast, but allow for the above correction to fix some cases
  2670. CTakeDamageInfo info( this, this, vec3_origin, vec3_origin, 1, DMG_CRUSH );
  2671. OnTakeDamage( info );
  2672. }
  2673. else
  2674. {
  2675. SetAbsOrigin( vNewCenter - vOriginToCenter );
  2676. }
  2677. }
  2678. }
  2679. }
  2680. }
  2681. }
  2682. }
  2683. else
  2684. #endif
  2685. {
  2686. bCheckStuck = true;
  2687. }
  2688. }
  2689. }
  2690. else
  2691. {
  2692. if ( m_bTouchedPhysObject || (nContactState & PLAYER_CONTACT_GAMEOBJECT) )
  2693. {
  2694. // check my position (physics object could have simulated into my position
  2695. // physics is not very far away, check my position
  2696. trace_t trace;
  2697. UTIL_TraceEntity( this, GetAbsOrigin(), GetAbsOrigin(),
  2698. PhysicsSolidMaskForEntity(), this, COLLISION_GROUP_PLAYER_MOVEMENT, &trace );
  2699. // is current position ok?
  2700. if ( trace.allsolid || trace.startsolid )
  2701. {
  2702. // no use the final stuck check to move back to old if this stuck fix didn't work
  2703. bCheckStuck = true;
  2704. lastValidPosition = m_oldOrigin;
  2705. SetAbsOrigin( newPosition );
  2706. }
  2707. }
  2708. }
  2709. if ( bCheckStuck )
  2710. {
  2711. trace_t trace;
  2712. UTIL_TraceEntity( this, GetAbsOrigin(), GetAbsOrigin(), PhysicsSolidMaskForEntity(), this, COLLISION_GROUP_PLAYER_MOVEMENT, &trace );
  2713. // current position is not ok, fixup
  2714. if ( trace.allsolid || trace.startsolid )
  2715. {
  2716. // STUCK!?!?!
  2717. //Warning( "Checkstuck failed. Stuck on %s!!\n", trace.m_pEnt->GetClassname() );
  2718. SetAbsOrigin( lastValidPosition );
  2719. }
  2720. }
  2721. m_oldOrigin = GetAbsOrigin();
  2722. m_bPhysicsWasFrozen = false;
  2723. #if defined( DEBUG_MOTION_CONTROLLERS )
  2724. g_vLastPos = newPosition;
  2725. #endif
  2726. }
  2727. //-----------------------------------------------------------------------------
  2728. // Purpose:
  2729. //-----------------------------------------------------------------------------
  2730. void CBasePlayer::PostThinkVPhysics( void )
  2731. {
  2732. // Check to see if things are initialized!
  2733. if ( !m_pPhysicsController )
  2734. {
  2735. #if defined( CLIENT_DLL )
  2736. if( !physenv->IsPredicted() )
  2737. {
  2738. if ( GetMoveType() == MOVETYPE_NOCLIP || GetMoveType() == MOVETYPE_OBSERVER )
  2739. {
  2740. m_vphysicsCollisionState = VPHYS_NOCLIP;
  2741. }
  2742. else if ( GetFlags() & FL_DUCKING )
  2743. {
  2744. m_vphysicsCollisionState = VPHYS_CROUCH;
  2745. }
  2746. else
  2747. {
  2748. m_vphysicsCollisionState = VPHYS_WALK;
  2749. }
  2750. }
  2751. #endif
  2752. return;
  2753. }
  2754. Vector newPosition = GetAbsOrigin();
  2755. float frametime = gpGlobals->frametime;
  2756. if ( frametime <= 0 || frametime > 0.1f )
  2757. frametime = 0.1f;
  2758. IPhysicsObject *pPhysGround = GetGroundVPhysics();
  2759. if ( !pPhysGround && m_bTouchedPhysObject && g_pMoveData->m_outStepHeight <= 0.f && (GetFlags() & FL_ONGROUND) )
  2760. {
  2761. newPosition = m_oldOrigin + frametime * g_pMoveData->m_outWishVel;
  2762. newPosition = (GetAbsOrigin() * 0.5f) + (newPosition * 0.5f);
  2763. }
  2764. int collisionState = VPHYS_WALK;
  2765. if ( GetMoveType() == MOVETYPE_NOCLIP || GetMoveType() == MOVETYPE_OBSERVER )
  2766. {
  2767. collisionState = VPHYS_NOCLIP;
  2768. }
  2769. else if ( GetFlags() & FL_DUCKING )
  2770. {
  2771. collisionState = VPHYS_CROUCH;
  2772. }
  2773. if ( collisionState != m_vphysicsCollisionState )
  2774. {
  2775. SetVCollisionState( GetAbsOrigin(), GetAbsVelocity(), collisionState );
  2776. }
  2777. if ( !(TouchedPhysics() || pPhysGround) )
  2778. {
  2779. float maxSpeed = m_flMaxspeed > 0.0f ? m_flMaxspeed : sv_maxspeed.GetFloat();
  2780. g_pMoveData->m_outWishVel.Init( maxSpeed, maxSpeed, maxSpeed );
  2781. }
  2782. // teleport the physics object up by stepheight (game code does this - reflect in the physics)
  2783. if ( g_pMoveData->m_outStepHeight > 0.1f )
  2784. {
  2785. if ( g_pMoveData->m_outStepHeight > 4.0f )
  2786. {
  2787. VPhysicsGetObject()->SetPosition( GetAbsOrigin(), vec3_angle, true );
  2788. }
  2789. else
  2790. {
  2791. // don't ever teleport into solid
  2792. Vector position, end;
  2793. VPhysicsGetObject()->GetPosition( &position, NULL );
  2794. end = position;
  2795. end.z += g_pMoveData->m_outStepHeight;
  2796. trace_t trace;
  2797. UTIL_TraceEntity( this, position, end, PhysicsSolidMaskForEntity(), this, COLLISION_GROUP_PLAYER_MOVEMENT, &trace );
  2798. if ( trace.DidHit() )
  2799. {
  2800. g_pMoveData->m_outStepHeight = trace.endpos.z - position.z;
  2801. }
  2802. m_pPhysicsController->StepUp( g_pMoveData->m_outStepHeight );
  2803. }
  2804. m_pPhysicsController->Jump();
  2805. }
  2806. g_pMoveData->m_outStepHeight = 0.0f;
  2807. // Store these off because after running the usercmds, it'll pass them
  2808. // to UpdateVPhysicsPosition.
  2809. m_vNewVPhysicsPosition = newPosition;
  2810. m_vNewVPhysicsVelocity = g_pMoveData->m_outWishVel;
  2811. m_oldOrigin = GetAbsOrigin();
  2812. }
  2813. IPhysicsObject *CBasePlayer::GetGroundVPhysics()
  2814. {
  2815. CBaseEntity *pGroundEntity = GetGroundEntity();
  2816. if ( pGroundEntity && pGroundEntity->GetMoveType() == MOVETYPE_VPHYSICS )
  2817. {
  2818. IPhysicsObject *pPhysGround = pGroundEntity->VPhysicsGetObject();
  2819. if ( pPhysGround && pPhysGround->IsMoveable() )
  2820. return pPhysGround;
  2821. }
  2822. return NULL;
  2823. }
  2824. // UNDONE: Look and see if the ground entity is in hierarchy with a MOVETYPE_VPHYSICS?
  2825. // Behavior in that case is not as good currently when the parent is rideable
  2826. bool CBasePlayer::IsRideablePhysics( IPhysicsObject *pPhysics )
  2827. {
  2828. if ( pPhysics )
  2829. {
  2830. if ( pPhysics->GetMass() > (VPhysicsGetObject()->GetMass()*2) )
  2831. return true;
  2832. }
  2833. return false;
  2834. }
  2835. void CBasePlayer::UpdateVPhysicsPosition( const Vector &position, const Vector &velocity, float secondsToArrival )
  2836. {
  2837. if( !m_pPhysicsController )
  2838. return;
  2839. bool onground = (GetFlags() & FL_ONGROUND) ? true : false;
  2840. IPhysicsObject *pPhysGround = GetGroundVPhysics();
  2841. // if the object is much heavier than the player, treat it as a local coordinate system
  2842. // the player controller will solve movement differently in this case.
  2843. if ( !IsRideablePhysics(pPhysGround) )
  2844. {
  2845. pPhysGround = NULL;
  2846. }
  2847. #if defined( DEBUG_MOTION_CONTROLLERS )
  2848. if( (GetFlags() & FL_ONGROUND) == 0 )
  2849. {
  2850. Vector vCurPos;
  2851. m_pPhysicsController->GetShadowPosition( &vCurPos, NULL );
  2852. # if defined( CLIENT_DLL )
  2853. DebugVelocity( "CBasePlayer::UpdateVPhysicsPosition", vCurPos, position, 255, prediction->IsFirstTimePredicted() ? 0 : 128, 0 );
  2854. DebugBox( "CBasePlayer::UpdateVPhysicsPosition", vCurPos, Vector( 0.1f, 0.1f, 0.1f ), 0, prediction->IsFirstTimePredicted() ? 0 : 128, 255, 100 );
  2855. DebugBox( "CBasePlayer::UpdateVPhysicsPosition", position, Vector( 0.1f, 0.1f, 0.1f ), 255, prediction->IsFirstTimePredicted() ? 0 : 128, 0, 100 );
  2856. # else
  2857. DebugVelocity( "CBasePlayer::UpdateVPhysicsPosition", vCurPos, position, 255, 0, 0 );
  2858. DebugBox( "CBasePlayer::UpdateVPhysicsPosition", vCurPos, Vector( 0.1f, 0.1f, 0.1f ), 0, 0, 255, 100 );
  2859. DebugBox( "CBasePlayer::UpdateVPhysicsPosition", position, Vector( 0.1f, 0.1f, 0.1f ), 255, 0, 0, 100 );
  2860. # endif
  2861. }
  2862. #endif
  2863. m_pPhysicsController->Update( position, velocity, secondsToArrival, onground, pPhysGround );
  2864. }
  2865. // used by the physics gun and game physics... is there a better interface?
  2866. void CBasePlayer::SetPhysicsFlag( int nFlag, bool bSet )
  2867. {
  2868. if (bSet)
  2869. m_afPhysicsFlags |= nFlag;
  2870. else
  2871. m_afPhysicsFlags &= ~nFlag;
  2872. }
  2873. //-----------------------------------------------------------------------------
  2874. // Purpose:
  2875. //-----------------------------------------------------------------------------
  2876. void CBasePlayer::SetVCollisionState( const Vector &vecAbsOrigin, const Vector &vecAbsVelocity, int collisionState )
  2877. {
  2878. m_vphysicsCollisionState = collisionState;
  2879. if( m_pShadowStand == NULL )
  2880. return;
  2881. switch( collisionState )
  2882. {
  2883. case VPHYS_WALK:
  2884. m_pShadowStand->SetPosition( vecAbsOrigin, vec3_angle, true );
  2885. m_pShadowStand->SetVelocity( &vecAbsVelocity, NULL );
  2886. m_pShadowCrouch->EnableCollisions( false );
  2887. m_pPhysicsController->SetObject( m_pShadowStand );
  2888. VPhysicsSwapObject( m_pShadowStand );
  2889. m_pShadowStand->EnableCollisions( true );
  2890. break;
  2891. case VPHYS_CROUCH:
  2892. m_pShadowCrouch->SetPosition( vecAbsOrigin, vec3_angle, true );
  2893. m_pShadowCrouch->SetVelocity( &vecAbsVelocity, NULL );
  2894. m_pShadowStand->EnableCollisions( false );
  2895. m_pPhysicsController->SetObject( m_pShadowCrouch );
  2896. VPhysicsSwapObject( m_pShadowCrouch );
  2897. m_pShadowCrouch->EnableCollisions( true );
  2898. break;
  2899. case VPHYS_NOCLIP:
  2900. m_pShadowCrouch->EnableCollisions( false );
  2901. m_pShadowStand->EnableCollisions( false );
  2902. break;
  2903. }
  2904. }
  2905. void CBasePlayer::UpdatePhysicsShadowToCurrentPosition()
  2906. {
  2907. UpdateVPhysicsPosition( GetAbsOrigin(), vec3_origin, gpGlobals->frametime );
  2908. }
  2909. void CBasePlayer::UpdatePhysicsShadowToPosition( const Vector &vecAbsOrigin )
  2910. {
  2911. UpdateVPhysicsPosition( vecAbsOrigin, vec3_origin, gpGlobals->frametime );
  2912. }
  2913. const char *CBasePlayer::GetPlayerModelName( void )
  2914. {
  2915. return "models/player.mdl";
  2916. }
  2917. float CBasePlayer::GetAirTime( void )
  2918. {
  2919. return m_flTimeLastTouchedGround == 0.0f ? 0.0f : gpGlobals->curtime - m_flTimeLastTouchedGround;
  2920. }
  2921. const Vector& CBasePlayer::GetEyeOffset() const
  2922. {
  2923. return m_vecEyeOffset;
  2924. }
  2925. void CBasePlayer::SetEyeOffset( const Vector& v )
  2926. {
  2927. m_vecEyeOffset = v;
  2928. }
  2929. const QAngle & CBasePlayer::GetEyeAngleOffset() const
  2930. {
  2931. return m_EyeAngleOffset;
  2932. }
  2933. void CBasePlayer::SetEyeAngleOffset( const QAngle& qa )
  2934. {
  2935. m_EyeAngleOffset = qa;
  2936. }
  2937. const Vector & CBasePlayer::GetAimDirection() const
  2938. {
  2939. return m_AimDirection;
  2940. }
  2941. void CBasePlayer::SetAimDirection( const Vector& v )
  2942. {
  2943. m_AimDirection = v;
  2944. }
  2945. bool CBasePlayer::IsCoach( void ) const
  2946. {
  2947. return ( GetCoachingTeam() != 0 );
  2948. }
  2949. int CBasePlayer::GetCoachingTeam( void ) const
  2950. {
  2951. if ( sv_coaching_enabled.GetBool() && ( GetTeamNumber() == TEAM_SPECTATOR ) )
  2952. {
  2953. return m_iCoachingTeam;
  2954. }
  2955. else
  2956. {
  2957. return 0;
  2958. }
  2959. }
  2960. // returns the player's team or, if coach, coaching team.
  2961. int CBasePlayer::GetAssociatedTeamNumber( void ) const
  2962. {
  2963. return ( IsCoach() ? GetCoachingTeam() : GetTeamNumber() );
  2964. }
  2965. // is a true spectator, i.e. NOT a team coach
  2966. bool CBasePlayer::IsSpectator( void ) const
  2967. {
  2968. return ( GetTeamNumber() == TEAM_SPECTATOR && !IsCoach() );
  2969. }