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.

805 lines
20 KiB

  1. // NextBotPlayerBody.cpp
  2. // Implementation of Body interface for CBasePlayer-derived classes
  3. // Author: Michael Booth, October 2006
  4. // Copyright (c) 2006 Turtle Rock Studios, Inc. - All Rights Reserved
  5. #include "cbase.h"
  6. #include "NextBot.h"
  7. #include "NextBotPlayerBody.h"
  8. #include "NextBotPlayer.h"
  9. // memdbgon must be the last include file in a .cpp file!!!
  10. #include "tier0/memdbgon.h"
  11. ConVar NextBotSaccadeTime( "nb_saccade_time", "0.1", FCVAR_CHEAT );
  12. ConVar NextBotSaccadeSpeed( "nb_saccade_speed", "1000", FCVAR_CHEAT );
  13. ConVar NextBotHeadAimSteadyMaxRate( "nb_head_aim_steady_max_rate", "100", FCVAR_CHEAT );
  14. ConVar NextBotHeadAimSettleDuration( "nb_head_aim_settle_duration", "0.3", FCVAR_CHEAT );
  15. //-----------------------------------------------------------------------------------------------
  16. /**
  17. * A useful reply for IBody::AimHeadTowards. When the
  18. * head is aiming on target, press the fire button.
  19. */
  20. void PressFireButtonReply::OnSuccess( INextBot *bot )
  21. {
  22. INextBotPlayerInput *playerInput = dynamic_cast< INextBotPlayerInput * >( bot->GetEntity() );
  23. if ( playerInput )
  24. {
  25. playerInput->PressFireButton();
  26. }
  27. }
  28. //-----------------------------------------------------------------------------------------------
  29. /**
  30. * A useful reply for IBody::AimHeadTowards. When the
  31. * head is aiming on target, press the alternate fire button.
  32. */
  33. void PressAltFireButtonReply::OnSuccess( INextBot *bot )
  34. {
  35. INextBotPlayerInput *playerInput = dynamic_cast< INextBotPlayerInput * >( bot->GetEntity() );
  36. if ( playerInput )
  37. {
  38. playerInput->PressMeleeButton();
  39. }
  40. }
  41. //-----------------------------------------------------------------------------------------------
  42. /**
  43. * A useful reply for IBody::AimHeadTowards. When the
  44. * head is aiming on target, press the jump button.
  45. */
  46. void PressJumpButtonReply::OnSuccess( INextBot *bot )
  47. {
  48. INextBotPlayerInput *playerInput = dynamic_cast< INextBotPlayerInput * >( bot->GetEntity() );
  49. if ( playerInput )
  50. {
  51. playerInput->PressJumpButton();
  52. }
  53. }
  54. //-----------------------------------------------------------------------------------------------
  55. //-----------------------------------------------------------------------------------------------
  56. PlayerBody::PlayerBody( INextBot *bot ) : IBody( bot )
  57. {
  58. m_player = static_cast< CBasePlayer * >( bot->GetEntity() );
  59. }
  60. //-----------------------------------------------------------------------------------------------
  61. PlayerBody::~PlayerBody()
  62. {
  63. }
  64. //-----------------------------------------------------------------------------------------------
  65. /**
  66. * reset to initial state
  67. */
  68. void PlayerBody::Reset( void )
  69. {
  70. m_posture = STAND;
  71. m_lookAtPos = vec3_origin;
  72. m_lookAtSubject = NULL;
  73. m_lookAtReplyWhenAimed = NULL;
  74. m_lookAtPriority = BORING;
  75. m_lookAtExpireTimer.Invalidate();
  76. m_lookAtDurationTimer.Invalidate();
  77. m_isSightedIn = false;
  78. m_hasBeenSightedIn = false;
  79. m_headSteadyTimer.Invalidate();
  80. m_yawRate = 0.0f;
  81. m_pitchRate = 0.0f;
  82. m_priorAngles = vec3_angle;
  83. }
  84. static ConVar bot_mimic( "bot_mimic", "0", 0, "Bot uses usercmd of player by index." );
  85. //-----------------------------------------------------------------------------------------------
  86. /**
  87. * Update internal state.
  88. * Do this every tick to keep head aims smooth and accurate
  89. */
  90. void PlayerBody::Upkeep( void )
  91. {
  92. // If mimicking the player, don't modify the view angles.
  93. static ConVarRef bot_mimic( "bot_mimic" );
  94. if ( bot_mimic.IsValid() && bot_mimic.GetBool() )
  95. return;
  96. const float deltaT = gpGlobals->frametime;
  97. if ( deltaT < 0.00001f )
  98. {
  99. return;
  100. }
  101. CBasePlayer *player = ( CBasePlayer * )GetBot()->GetEntity();
  102. // get current view angles
  103. QAngle currentAngles = player->EyeAngles() + player->GetPunchAngle();
  104. // track when our head is "steady"
  105. bool isSteady = true;
  106. float actualPitchRate = AngleDiff( currentAngles.x, m_priorAngles.x );
  107. if ( abs( actualPitchRate ) > NextBotHeadAimSteadyMaxRate.GetFloat() * deltaT )
  108. {
  109. isSteady = false;
  110. }
  111. else
  112. {
  113. float actualYawRate = AngleDiff( currentAngles.y, m_priorAngles.y );
  114. if ( abs( actualYawRate ) > NextBotHeadAimSteadyMaxRate.GetFloat() * deltaT )
  115. {
  116. isSteady = false;
  117. }
  118. }
  119. if ( isSteady )
  120. {
  121. if ( !m_headSteadyTimer.HasStarted() )
  122. {
  123. m_headSteadyTimer.Start();
  124. }
  125. }
  126. else
  127. {
  128. m_headSteadyTimer.Invalidate();
  129. }
  130. if ( GetBot()->IsDebugging( NEXTBOT_LOOK_AT ) )
  131. {
  132. if ( IsHeadSteady() )
  133. {
  134. const float maxTime = 3.0f;
  135. float t = GetHeadSteadyDuration() / maxTime;
  136. t = clamp( t, 0, 1.0f );
  137. NDebugOverlay::Circle( player->EyePosition(), t * 10.0f, 0, 255, 0, 255, true, 2.0f * deltaT );
  138. }
  139. }
  140. m_priorAngles = currentAngles;
  141. // if our current look-at has expired, don't change our aim further
  142. if ( m_hasBeenSightedIn && m_lookAtExpireTimer.IsElapsed() )
  143. {
  144. return;
  145. }
  146. // if we have a subject, update lookat point
  147. CBaseEntity *subject = m_lookAtSubject;
  148. if ( subject )
  149. {
  150. if ( subject->MyCombatCharacterPointer() )
  151. {
  152. m_lookAtPos = GetBot()->GetIntentionInterface()->SelectTargetPoint( GetBot(), subject->MyCombatCharacterPointer() );
  153. }
  154. else
  155. {
  156. m_lookAtPos = subject->WorldSpaceCenter();
  157. }
  158. m_lookAtPos += GetHeadAimSubjectLeadTime() * subject->GetAbsVelocity();
  159. }
  160. // aim view towards last look at point
  161. Vector to = m_lookAtPos - GetEyePosition();
  162. to.NormalizeInPlace();
  163. QAngle desiredAngles;
  164. VectorAngles( to, desiredAngles );
  165. QAngle angles;
  166. const Vector &forward = GetViewVector();
  167. if ( GetBot()->IsDebugging( NEXTBOT_LOOK_AT ) )
  168. {
  169. NDebugOverlay::Line( GetEyePosition(), GetEyePosition() + 100.0f * forward, 255, 255, 0, false, 2.0f * deltaT );
  170. float thickness = isSteady ? 2.0f : 3.0f;
  171. int g = subject ? 255 : 0;
  172. NDebugOverlay::HorzArrow( GetEyePosition(), m_lookAtPos, thickness, 0, g, 255, 255, false, 2.0f * deltaT );
  173. }
  174. const float onTargetTolerance = 0.98f;
  175. float dot = DotProduct( forward, to );
  176. if ( dot > onTargetTolerance )
  177. {
  178. // on target
  179. m_isSightedIn = true;
  180. m_hasBeenSightedIn = true;
  181. if ( m_lookAtReplyWhenAimed )
  182. {
  183. m_lookAtReplyWhenAimed->OnSuccess( GetBot() );
  184. m_lookAtReplyWhenAimed = NULL;
  185. }
  186. }
  187. else
  188. {
  189. // off target
  190. m_isSightedIn = false;
  191. }
  192. // rotate view at a rate proportional to how far we have to turn
  193. // max rate if we need to turn around
  194. // want first derivative continuity of rate as our aim hits to avoid pop
  195. float approachRate = GetMaxHeadAngularVelocity();
  196. const float easeOut = 0.7f;
  197. if ( dot > easeOut )
  198. {
  199. float t = RemapVal( dot, easeOut, 1.0f, 1.0f, 0.02f );
  200. const float halfPI = 1.57f;
  201. approachRate *= sin( halfPI * t );
  202. }
  203. const float easeInTime = 0.25f;
  204. if ( m_lookAtDurationTimer.GetElapsedTime() < easeInTime )
  205. {
  206. approachRate *= m_lookAtDurationTimer.GetElapsedTime() / easeInTime;
  207. }
  208. angles.y = ApproachAngle( desiredAngles.y, currentAngles.y, approachRate * deltaT );
  209. angles.x = ApproachAngle( desiredAngles.x, currentAngles.x, approachRate * deltaT );
  210. angles.z = 0.0f;
  211. // back out "punch angle"
  212. angles -= player->GetPunchAngle();
  213. angles.x = AngleNormalize( angles.x );
  214. angles.y = AngleNormalize( angles.y );
  215. player->SnapEyeAngles( angles );
  216. }
  217. //-----------------------------------------------------------------------------------------------
  218. bool PlayerBody::SetPosition( const Vector &pos )
  219. {
  220. m_player->SetAbsOrigin( pos );
  221. return true;
  222. }
  223. //-----------------------------------------------------------------------------------------------
  224. /**
  225. * Return the eye position of the bot in world coordinates
  226. */
  227. const Vector &PlayerBody::GetEyePosition( void ) const
  228. {
  229. m_eyePos = m_player->EyePosition();
  230. return m_eyePos;
  231. }
  232. CBaseEntity *PlayerBody::GetEntity( void )
  233. {
  234. return m_player;
  235. }
  236. //-----------------------------------------------------------------------------------------------
  237. /**
  238. * Return the view unit direction vector in world coordinates
  239. */
  240. const Vector &PlayerBody::GetViewVector( void ) const
  241. {
  242. m_player->EyeVectors( &m_viewVector );
  243. return m_viewVector;
  244. }
  245. //-----------------------------------------------------------------------------------------------
  246. /**
  247. * Aim the bot's head towards the given goal
  248. */
  249. void PlayerBody::AimHeadTowards( const Vector &lookAtPos, LookAtPriorityType priority, float duration, INextBotReply *replyWhenAimed, const char *reason )
  250. {
  251. if ( duration <= 0.0f )
  252. {
  253. duration = 0.1f;
  254. }
  255. // don't spaz our aim around
  256. if ( m_lookAtPriority == priority )
  257. {
  258. if ( !IsHeadSteady() || GetHeadSteadyDuration() < NextBotHeadAimSettleDuration.GetFloat() )
  259. {
  260. // we're still finishing a look-at at the same priority
  261. if ( replyWhenAimed )
  262. {
  263. replyWhenAimed->OnFail( GetBot(), INextBotReply::DENIED );
  264. }
  265. if ( GetBot()->IsDebugging( NEXTBOT_LOOK_AT ) )
  266. {
  267. ConColorMsg( Color( 255, 0, 0, 255 ), "%3.2f: %s Look At rejected - previous aim not settled\n",
  268. gpGlobals->curtime,
  269. m_player->GetPlayerName() );
  270. }
  271. return;
  272. }
  273. }
  274. // don't short-circuit if "sighted in" to avoid rapid view jitter
  275. if ( m_lookAtPriority > priority && !m_lookAtExpireTimer.IsElapsed() )
  276. {
  277. // higher priority lookat still ongoing
  278. if ( replyWhenAimed )
  279. {
  280. replyWhenAimed->OnFail( GetBot(), INextBotReply::DENIED );
  281. }
  282. if ( GetBot()->IsDebugging( NEXTBOT_LOOK_AT ) )
  283. {
  284. ConColorMsg( Color( 255, 0, 0, 255 ), "%3.2f: %s Look At rejected - higher priority aim in progress\n",
  285. gpGlobals->curtime,
  286. m_player->GetPlayerName() );
  287. }
  288. return;
  289. }
  290. if ( m_lookAtReplyWhenAimed )
  291. {
  292. // in-process aim was interrupted
  293. m_lookAtReplyWhenAimed->OnFail( GetBot(), INextBotReply::INTERRUPTED );
  294. }
  295. m_lookAtReplyWhenAimed = replyWhenAimed;
  296. m_lookAtExpireTimer.Start( duration );
  297. // if given the same point, just update priority
  298. const float epsilon = 1.0f;
  299. if ( ( m_lookAtPos - lookAtPos ).IsLengthLessThan( epsilon ) )
  300. {
  301. m_lookAtPriority = priority;
  302. return;
  303. }
  304. // new look-at point
  305. m_lookAtPos = lookAtPos;
  306. m_lookAtSubject = NULL;
  307. m_lookAtPriority = priority;
  308. m_lookAtDurationTimer.Start();
  309. m_isSightedIn = false;
  310. m_hasBeenSightedIn = false;
  311. if ( GetBot()->IsDebugging( NEXTBOT_LOOK_AT ) )
  312. {
  313. NDebugOverlay::Cross3D( lookAtPos, 2.0f, 255, 255, 100, true, 2.0f * duration );
  314. char *priName = "";
  315. switch( priority )
  316. {
  317. case BORING: priName = "BORING"; break;
  318. case INTERESTING: priName = "INTERESTING"; break;
  319. case IMPORTANT: priName = "IMPORTANT"; break;
  320. case CRITICAL: priName = "CRITICAL"; break;
  321. }
  322. ConColorMsg( Color( 255, 100, 0, 255 ), "%3.2f: %s Look At ( %g, %g, %g ) for %3.2f s, Pri = %s, Reason = %s\n",
  323. gpGlobals->curtime,
  324. m_player->GetPlayerName(),
  325. lookAtPos.x, lookAtPos.y, lookAtPos.z,
  326. duration,
  327. priName,
  328. ( reason ) ? reason : "" );
  329. }
  330. }
  331. //-----------------------------------------------------------------------------------------------
  332. /**
  333. * Aim the bot's head towards the given goal
  334. */
  335. void PlayerBody::AimHeadTowards( CBaseEntity *subject, LookAtPriorityType priority, float duration, INextBotReply *replyWhenAimed, const char *reason )
  336. {
  337. if ( duration <= 0.0f )
  338. {
  339. duration = 0.1f;
  340. }
  341. if ( subject == NULL )
  342. {
  343. return;
  344. }
  345. // don't spaz our aim around
  346. if ( m_lookAtPriority == priority )
  347. {
  348. if ( !IsHeadSteady() || GetHeadSteadyDuration() < NextBotHeadAimSettleDuration.GetFloat() )
  349. {
  350. // we're still finishing a look-at at the same priority
  351. if ( replyWhenAimed )
  352. {
  353. replyWhenAimed->OnFail( GetBot(), INextBotReply::DENIED );
  354. }
  355. if ( GetBot()->IsDebugging( NEXTBOT_LOOK_AT ) )
  356. {
  357. ConColorMsg( Color( 255, 0, 0, 255 ), "%3.2f: %s Look At rejected - previous aim not settled\n",
  358. gpGlobals->curtime,
  359. m_player->GetPlayerName() );
  360. }
  361. return;
  362. }
  363. }
  364. // don't short-circuit if "sighted in" to avoid rapid view jitter
  365. if ( m_lookAtPriority > priority && !m_lookAtExpireTimer.IsElapsed() )
  366. {
  367. // higher priority lookat still ongoing
  368. if ( replyWhenAimed )
  369. {
  370. replyWhenAimed->OnFail( GetBot(), INextBotReply::DENIED );
  371. }
  372. if ( GetBot()->IsDebugging( NEXTBOT_LOOK_AT ) )
  373. {
  374. ConColorMsg( Color( 255, 0, 0, 255 ), "%3.2f: %s Look At rejected - higher priority aim in progress\n",
  375. gpGlobals->curtime,
  376. m_player->GetPlayerName() );
  377. }
  378. return;
  379. }
  380. if ( m_lookAtReplyWhenAimed )
  381. {
  382. // in-process aim was interrupted
  383. m_lookAtReplyWhenAimed->OnFail( GetBot(), INextBotReply::INTERRUPTED );
  384. }
  385. m_lookAtReplyWhenAimed = replyWhenAimed;
  386. m_lookAtExpireTimer.Start( duration );
  387. // if given the same subject, just update priority
  388. if ( subject == m_lookAtSubject )
  389. {
  390. m_lookAtPriority = priority;
  391. return;
  392. }
  393. // new subject
  394. m_lookAtSubject = subject;
  395. #ifdef REFACTOR_FOR_CLIENT_SIDE_EYE_TRACKING
  396. CBasePlayer *pMyPlayer = static_cast< CBasePlayer * >( GetEntity() );
  397. if ( subject->IsPlayer() )
  398. {
  399. // looking at a player, look at their eye position
  400. TerrorPlayer *pMyTarget = ToTerrorPlayer( subject );
  401. m_lookAtPos = subject->EyePosition();
  402. if(pMyPlayer)
  403. {
  404. pMyPlayer->SetLookatPlayer( pMyTarget );
  405. }
  406. }
  407. else
  408. {
  409. // not looking at a player
  410. m_lookAtPos = subject->WorldSpaceCenter();
  411. if(pMyPlayer)
  412. {
  413. pMyPlayer->SetLookatPlayer( NULL );
  414. }
  415. }
  416. #endif
  417. m_lookAtPriority = priority;
  418. m_lookAtDurationTimer.Start();
  419. m_isSightedIn = false;
  420. m_hasBeenSightedIn = false;
  421. if ( GetBot()->IsDebugging( NEXTBOT_LOOK_AT ) )
  422. {
  423. NDebugOverlay::Cross3D( m_lookAtPos, 2.0f, 100, 100, 100, true, duration );
  424. char *priName = "";
  425. switch( priority )
  426. {
  427. case BORING: priName = "BORING"; break;
  428. case INTERESTING: priName = "INTERESTING"; break;
  429. case IMPORTANT: priName = "IMPORTANT"; break;
  430. case CRITICAL: priName = "CRITICAL"; break;
  431. }
  432. ConColorMsg( Color( 255, 100, 0, 255 ), "%3.2f: %s Look At subject %s for %3.2f s, Pri = %s, Reason = %s\n",
  433. gpGlobals->curtime,
  434. m_player->GetPlayerName(),
  435. subject->GetClassname(),
  436. duration,
  437. priName,
  438. ( reason ) ? reason : "" );
  439. }
  440. }
  441. //-----------------------------------------------------------------------------------------------
  442. /**
  443. * Return true if head is not rapidly turning to look somewhere else
  444. */
  445. bool PlayerBody::IsHeadSteady( void ) const
  446. {
  447. return m_headSteadyTimer.HasStarted();
  448. }
  449. //-----------------------------------------------------------------------------------------------
  450. /**
  451. * Return the duration that the bot's head has been on-target
  452. */
  453. float PlayerBody::GetHeadSteadyDuration( void ) const
  454. {
  455. // return ( IsHeadAimingOnTarget() ) ? m_headSteadyTimer.GetElapsedTime() : 0.0f;
  456. return m_headSteadyTimer.HasStarted() ? m_headSteadyTimer.GetElapsedTime() : 0.0f;
  457. }
  458. //-----------------------------------------------------------------------------------------------
  459. float PlayerBody::GetMaxHeadAngularVelocity( void ) const
  460. {
  461. return NextBotSaccadeSpeed.GetFloat();
  462. }
  463. //-----------------------------------------------------------------------------------------------
  464. bool PlayerBody::StartActivity( Activity act, unsigned int flags )
  465. {
  466. // player animation state is controlled on the client
  467. return false;
  468. }
  469. //-----------------------------------------------------------------------------------------------
  470. /**
  471. * Return currently animating activity
  472. */
  473. Activity PlayerBody::GetActivity( void ) const
  474. {
  475. return ACT_INVALID;
  476. }
  477. //-----------------------------------------------------------------------------------------------
  478. /**
  479. * Return true if currently animating activity matches the given one
  480. */
  481. bool PlayerBody::IsActivity( Activity act ) const
  482. {
  483. return false;
  484. }
  485. //-----------------------------------------------------------------------------------------------
  486. /**
  487. * Return true if currently animating activity has any of the given flags
  488. */
  489. bool PlayerBody::HasActivityType( unsigned int flags ) const
  490. {
  491. return false;
  492. }
  493. //-----------------------------------------------------------------------------------------------
  494. /**
  495. * Request a posture change
  496. */
  497. void PlayerBody::SetDesiredPosture( PostureType posture )
  498. {
  499. m_posture = posture;
  500. }
  501. //-----------------------------------------------------------------------------------------------
  502. /**
  503. * Get posture body is trying to assume
  504. */
  505. IBody::PostureType PlayerBody::GetDesiredPosture( void ) const
  506. {
  507. return m_posture;
  508. }
  509. //-----------------------------------------------------------------------------------------------
  510. /**
  511. * Return true if body is trying to assume this posture
  512. */
  513. bool PlayerBody::IsDesiredPosture( PostureType posture ) const
  514. {
  515. return ( posture == m_posture );
  516. }
  517. //-----------------------------------------------------------------------------------------------
  518. /**
  519. * Return true if body's actual posture matches its desired posture
  520. */
  521. bool PlayerBody::IsInDesiredPosture( void ) const
  522. {
  523. return true;
  524. }
  525. //-----------------------------------------------------------------------------------------------
  526. /**
  527. * Return body's current actual posture
  528. */
  529. IBody::PostureType PlayerBody::GetActualPosture( void ) const
  530. {
  531. return m_posture;
  532. }
  533. //-----------------------------------------------------------------------------------------------
  534. /**
  535. * Return true if body is actually in the given posture
  536. */
  537. bool PlayerBody::IsActualPosture( PostureType posture ) const
  538. {
  539. return ( posture == m_posture );
  540. }
  541. //-----------------------------------------------------------------------------------------------
  542. /**
  543. * Return true if body's current posture allows it to move around the world
  544. */
  545. bool PlayerBody::IsPostureMobile( void ) const
  546. {
  547. return true;
  548. }
  549. //-----------------------------------------------------------------------------------------------
  550. /**
  551. * Return true if body's posture is in the process of changing to new posture
  552. */
  553. bool PlayerBody::IsPostureChanging( void ) const
  554. {
  555. return false;
  556. }
  557. //-----------------------------------------------------------------------------------------------
  558. /**
  559. * Arousal level change
  560. */
  561. void PlayerBody::SetArousal( ArousalType arousal )
  562. {
  563. m_arousal = arousal;
  564. }
  565. //-----------------------------------------------------------------------------------------------
  566. /**
  567. * Get arousal level
  568. */
  569. IBody::ArousalType PlayerBody::GetArousal( void ) const
  570. {
  571. return m_arousal;
  572. }
  573. //-----------------------------------------------------------------------------------------------
  574. /**
  575. * Return true if body is at this arousal level
  576. */
  577. bool PlayerBody::IsArousal( ArousalType arousal ) const
  578. {
  579. return ( arousal == m_arousal );
  580. }
  581. //-----------------------------------------------------------------------------------------------
  582. /**
  583. * Width of bot's collision hull in XY plane
  584. */
  585. float PlayerBody::GetHullWidth( void ) const
  586. {
  587. return VEC_HULL_MAX.x - VEC_HULL_MIN.x;
  588. }
  589. //-----------------------------------------------------------------------------------------------
  590. /**
  591. * Height of bot's current collision hull based on posture
  592. */
  593. float PlayerBody::GetHullHeight( void ) const
  594. {
  595. if ( m_posture == CROUCH )
  596. {
  597. return GetCrouchHullHeight();
  598. }
  599. return GetStandHullHeight();
  600. }
  601. //-----------------------------------------------------------------------------------------------
  602. /**
  603. * Height of bot's collision hull when standing
  604. */
  605. float PlayerBody::GetStandHullHeight( void ) const
  606. {
  607. return VEC_HULL_MAX.z - VEC_HULL_MIN.z;
  608. }
  609. //-----------------------------------------------------------------------------------------------
  610. /**
  611. * Height of bot's collision hull when crouched
  612. */
  613. float PlayerBody::GetCrouchHullHeight( void ) const
  614. {
  615. return VEC_DUCK_HULL_MAX.z - VEC_DUCK_HULL_MIN.z;
  616. }
  617. //-----------------------------------------------------------------------------------------------
  618. /**
  619. * Return current collision hull minimums based on actual body posture
  620. */
  621. const Vector &PlayerBody::GetHullMins( void ) const
  622. {
  623. if ( m_posture == CROUCH )
  624. {
  625. m_hullMins = VEC_DUCK_HULL_MIN;
  626. }
  627. else
  628. {
  629. m_hullMins = VEC_HULL_MIN;
  630. }
  631. return m_hullMins;
  632. }
  633. //-----------------------------------------------------------------------------------------------
  634. /**
  635. * Return current collision hull maximums based on actual body posture
  636. */
  637. const Vector &PlayerBody::GetHullMaxs( void ) const
  638. {
  639. if ( m_posture == CROUCH )
  640. {
  641. m_hullMaxs = VEC_DUCK_HULL_MAX;
  642. }
  643. else
  644. {
  645. m_hullMaxs = VEC_HULL_MAX;
  646. }
  647. return m_hullMaxs;
  648. }
  649. //-----------------------------------------------------------------------------------------------
  650. /**
  651. * Return the bot's collision mask (hack until we get a general hull trace abstraction here or in the locomotion interface)
  652. */
  653. unsigned int PlayerBody::GetSolidMask( void ) const
  654. {
  655. return ( m_player ) ? m_player->PlayerSolidMask() : MASK_PLAYERSOLID;
  656. }