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.

826 lines
22 KiB

  1. // NextBotPlayerLocomotion.cpp
  2. // Implementation of Locomotion interface for CBasePlayer-derived classes
  3. // Author: Michael Booth, November 2005
  4. // Copyright (c) 2005 Turtle Rock Studios, Inc. - All Rights Reserved
  5. #include "cbase.h"
  6. #include "nav_mesh.h"
  7. #include "in_buttons.h"
  8. #include "NextBot.h"
  9. #include "NextBotUtil.h"
  10. #include "NextBotPlayer.h"
  11. #include "NextBotPlayerLocomotion.h"
  12. // memdbgon must be the last include file in a .cpp file!!!
  13. #include "tier0/memdbgon.h"
  14. ConVar NextBotPlayerMoveDirect( "nb_player_move_direct", "0" );
  15. //-----------------------------------------------------------------------------------------------------
  16. PlayerLocomotion::PlayerLocomotion( INextBot *bot ) : ILocomotion( bot )
  17. {
  18. m_player = NULL;
  19. Reset();
  20. }
  21. //-----------------------------------------------------------------------------------------------------
  22. /**
  23. * Reset locomotor to initial state
  24. */
  25. void PlayerLocomotion::Reset( void )
  26. {
  27. m_player = static_cast< CBasePlayer * >( GetBot()->GetEntity() );
  28. m_isJumping = false;
  29. m_isClimbingUpToLedge = false;
  30. m_isJumpingAcrossGap = false;
  31. m_hasLeftTheGround = false;
  32. m_desiredSpeed = 0.0f;
  33. m_ladderState = NO_LADDER;
  34. m_ladderInfo = NULL;
  35. m_ladderDismountGoal = NULL;
  36. m_ladderTimer.Invalidate();
  37. m_minSpeedLimit = 0.0f;
  38. m_maxSpeedLimit = 9999999.9f;
  39. BaseClass::Reset();
  40. }
  41. //-----------------------------------------------------------------------------------------------------
  42. bool PlayerLocomotion::TraverseLadder( void )
  43. {
  44. switch( m_ladderState )
  45. {
  46. case APPROACHING_ASCENDING_LADDER:
  47. m_ladderState = ApproachAscendingLadder();
  48. return true;
  49. case APPROACHING_DESCENDING_LADDER:
  50. m_ladderState = ApproachDescendingLadder();
  51. return true;
  52. case ASCENDING_LADDER:
  53. m_ladderState = AscendLadder();
  54. return true;
  55. case DESCENDING_LADDER:
  56. m_ladderState = DescendLadder();
  57. return true;
  58. case DISMOUNTING_LADDER_TOP:
  59. m_ladderState = DismountLadderTop();
  60. return true;
  61. case DISMOUNTING_LADDER_BOTTOM:
  62. m_ladderState = DismountLadderBottom();
  63. return true;
  64. case NO_LADDER:
  65. default:
  66. m_ladderInfo = NULL;
  67. if ( GetBot()->GetEntity()->GetMoveType() == MOVETYPE_LADDER )
  68. {
  69. // on ladder and don't want to be
  70. GetBot()->GetEntity()->SetMoveType( MOVETYPE_WALK );
  71. }
  72. return false;
  73. }
  74. return true;
  75. }
  76. //-----------------------------------------------------------------------------------------------------
  77. /**
  78. * We're close, but not yet on, this ladder - approach it
  79. */
  80. PlayerLocomotion::LadderState PlayerLocomotion::ApproachAscendingLadder( void )
  81. {
  82. if ( m_ladderInfo == NULL )
  83. {
  84. return NO_LADDER;
  85. }
  86. // sanity check - are we already at the end of this ladder?
  87. if ( GetFeet().z >= m_ladderInfo->m_top.z - GetStepHeight() )
  88. {
  89. m_ladderTimer.Start( 2.0f );
  90. return DISMOUNTING_LADDER_TOP;
  91. }
  92. // sanity check - are we too far below this ladder to reach it?
  93. if ( GetFeet().z <= m_ladderInfo->m_bottom.z - GetMaxJumpHeight() )
  94. {
  95. return NO_LADDER;
  96. }
  97. FaceTowards( m_ladderInfo->m_bottom );
  98. // it is important to approach precisely, so use a very large weight to wash out all other Approaches
  99. Approach( m_ladderInfo->m_bottom, 9999999.9f );
  100. if ( GetBot()->GetEntity()->GetMoveType() == MOVETYPE_LADDER )
  101. {
  102. // we're on the ladder
  103. return ASCENDING_LADDER;
  104. }
  105. if ( GetBot()->IsDebugging( NEXTBOT_LOCOMOTION ) )
  106. {
  107. NDebugOverlay::EntityText( GetBot()->GetEntity()->entindex(), 0, "Approach ascending ladder", 0.1f, 255, 255, 255, 255 );
  108. }
  109. return APPROACHING_ASCENDING_LADDER;
  110. }
  111. //-----------------------------------------------------------------------------------------------------
  112. PlayerLocomotion::LadderState PlayerLocomotion::ApproachDescendingLadder( void )
  113. {
  114. if ( m_ladderInfo == NULL )
  115. {
  116. return NO_LADDER;
  117. }
  118. // sanity check - are we already at the end of this ladder?
  119. if ( GetFeet().z <= m_ladderInfo->m_bottom.z + GetMaxJumpHeight() )
  120. {
  121. m_ladderTimer.Start( 2.0f );
  122. return DISMOUNTING_LADDER_BOTTOM;
  123. }
  124. Vector mountPoint = m_ladderInfo->m_top + 0.25f * GetBot()->GetBodyInterface()->GetHullWidth() * m_ladderInfo->GetNormal();
  125. Vector to = mountPoint - GetFeet();
  126. to.z = 0.0f;
  127. float mountRange = to.NormalizeInPlace();
  128. Vector moveGoal;
  129. const float veryClose = 10.0f;
  130. if ( mountRange < veryClose )
  131. {
  132. // we're right at the ladder - just keep moving forward until we grab it
  133. const Vector &forward = GetMotionVector();
  134. moveGoal = GetFeet() + 100.0f * forward;
  135. }
  136. else
  137. {
  138. if ( DotProduct( to, m_ladderInfo->GetNormal() ) < 0.0f )
  139. {
  140. // approaching front of downward ladder
  141. // ##
  142. // ->+ ##
  143. // | ##
  144. // | ##
  145. // | ##
  146. // <-+ ##
  147. // ######
  148. //
  149. moveGoal = m_ladderInfo->m_top - 100.0f * m_ladderInfo->GetNormal();
  150. }
  151. else
  152. {
  153. // approaching back of downward ladder
  154. //
  155. // ->+
  156. // ##|
  157. // ##|
  158. // ##+-->
  159. // ######
  160. //
  161. moveGoal = m_ladderInfo->m_top + 100.0f * m_ladderInfo->GetNormal();
  162. }
  163. }
  164. FaceTowards( moveGoal );
  165. // it is important to approach precisely, so use a very large weight to wash out all other Approaches
  166. Approach( moveGoal, 9999999.9f );
  167. if ( GetBot()->GetEntity()->GetMoveType() == MOVETYPE_LADDER )
  168. {
  169. // we're on the ladder
  170. return DESCENDING_LADDER;
  171. }
  172. if ( GetBot()->IsDebugging( NEXTBOT_LOCOMOTION ) )
  173. {
  174. NDebugOverlay::EntityText( GetBot()->GetEntity()->entindex(), 0, "Approach descending ladder", 0.1f, 255, 255, 255, 255 );
  175. }
  176. return APPROACHING_DESCENDING_LADDER;
  177. }
  178. //-----------------------------------------------------------------------------------------------------
  179. PlayerLocomotion::LadderState PlayerLocomotion::AscendLadder( void )
  180. {
  181. if ( m_ladderInfo == NULL )
  182. {
  183. return NO_LADDER;
  184. }
  185. if ( GetBot()->GetEntity()->GetMoveType() != MOVETYPE_LADDER )
  186. {
  187. // slipped off ladder
  188. m_ladderInfo = NULL;
  189. return NO_LADDER;
  190. }
  191. if ( GetFeet().z >= m_ladderInfo->m_top.z )
  192. {
  193. // reached top of ladder
  194. m_ladderTimer.Start( 2.0f );
  195. return DISMOUNTING_LADDER_TOP;
  196. }
  197. // climb up this ladder - look up
  198. Vector goal = GetFeet() + 100.0f * ( -m_ladderInfo->GetNormal() + Vector( 0, 0, 2 ) );
  199. GetBot()->GetBodyInterface()->AimHeadTowards( goal, IBody::MANDATORY, 0.1f, NULL, "Ladder" );
  200. // it is important to approach precisely, so use a very large weight to wash out all other Approaches
  201. Approach( goal, 9999999.9f );
  202. if ( GetBot()->IsDebugging( NEXTBOT_LOCOMOTION ) )
  203. {
  204. NDebugOverlay::EntityText( GetBot()->GetEntity()->entindex(), 0, "Ascend", 0.1f, 255, 255, 255, 255 );
  205. }
  206. return ASCENDING_LADDER;
  207. }
  208. //-----------------------------------------------------------------------------------------------------
  209. PlayerLocomotion::LadderState PlayerLocomotion::DescendLadder( void )
  210. {
  211. if ( m_ladderInfo == NULL )
  212. {
  213. return NO_LADDER;
  214. }
  215. if ( GetBot()->GetEntity()->GetMoveType() != MOVETYPE_LADDER )
  216. {
  217. // slipped off ladder
  218. m_ladderInfo = NULL;
  219. return NO_LADDER;
  220. }
  221. if ( GetFeet().z <= m_ladderInfo->m_bottom.z + GetBot()->GetLocomotionInterface()->GetStepHeight() )
  222. {
  223. // reached bottom of ladder
  224. m_ladderTimer.Start( 2.0f );
  225. return DISMOUNTING_LADDER_BOTTOM;
  226. }
  227. // climb down this ladder - look down
  228. Vector goal = GetFeet() + 100.0f * ( m_ladderInfo->GetNormal() + Vector( 0, 0, -2 ) );
  229. GetBot()->GetBodyInterface()->AimHeadTowards( goal, IBody::MANDATORY, 0.1f, NULL, "Ladder" );
  230. // it is important to approach precisely, so use a very large weight to wash out all other Approaches
  231. Approach( goal, 9999999.9f );
  232. if ( GetBot()->IsDebugging( NEXTBOT_LOCOMOTION ) )
  233. {
  234. NDebugOverlay::EntityText( GetBot()->GetEntity()->entindex(), 0, "Descend", 0.1f, 255, 255, 255, 255 );
  235. }
  236. return DESCENDING_LADDER;
  237. }
  238. //-----------------------------------------------------------------------------------------------------
  239. PlayerLocomotion::LadderState PlayerLocomotion::DismountLadderTop( void )
  240. {
  241. if ( m_ladderInfo == NULL || m_ladderTimer.IsElapsed() )
  242. {
  243. m_ladderInfo = NULL;
  244. return NO_LADDER;
  245. }
  246. IBody *body = GetBot()->GetBodyInterface();
  247. Vector toGoal = m_ladderDismountGoal->GetCenter() - GetFeet();
  248. toGoal.z = 0.0f;
  249. float range = toGoal.NormalizeInPlace();
  250. toGoal.z = 1.0f;
  251. body->AimHeadTowards( body->GetEyePosition() + 100.0f * toGoal, IBody::MANDATORY, 0.1f, NULL, "Ladder dismount" );
  252. // it is important to approach precisely, so use a very large weight to wash out all other Approaches
  253. Approach( GetFeet() + 100.0f * toGoal, 9999999.9f );
  254. if ( GetBot()->IsDebugging( NEXTBOT_LOCOMOTION ) )
  255. {
  256. NDebugOverlay::EntityText( GetBot()->GetEntity()->entindex(), 0, "Dismount top", 0.1f, 255, 255, 255, 255 );
  257. NDebugOverlay::HorzArrow( GetFeet(), m_ladderDismountGoal->GetCenter(), 5.0f, 255, 255, 0, 255, true, 0.1f );
  258. }
  259. // test 2D vector here in case nav area is under the geometry a bit
  260. const float tolerance = 10.0f;
  261. if ( GetBot()->GetEntity()->GetLastKnownArea() == m_ladderDismountGoal && range < tolerance )
  262. {
  263. // reached dismount goal
  264. m_ladderInfo = NULL;
  265. return NO_LADDER;
  266. }
  267. return DISMOUNTING_LADDER_TOP;
  268. }
  269. //-----------------------------------------------------------------------------------------------------
  270. PlayerLocomotion::LadderState PlayerLocomotion::DismountLadderBottom( void )
  271. {
  272. if ( m_ladderInfo == NULL || m_ladderTimer.IsElapsed() )
  273. {
  274. m_ladderInfo = NULL;
  275. return NO_LADDER;
  276. }
  277. if ( GetBot()->GetEntity()->GetMoveType() == MOVETYPE_LADDER )
  278. {
  279. // near the bottom - just let go
  280. GetBot()->GetEntity()->SetMoveType( MOVETYPE_WALK );
  281. m_ladderInfo = NULL;
  282. }
  283. return NO_LADDER;
  284. }
  285. //-----------------------------------------------------------------------------------------------------
  286. /**
  287. * Update internal state
  288. */
  289. void PlayerLocomotion::Update( void )
  290. {
  291. if ( TraverseLadder() )
  292. {
  293. return BaseClass::Update();
  294. }
  295. if ( m_isJumpingAcrossGap || m_isClimbingUpToLedge )
  296. {
  297. // force a run
  298. SetMinimumSpeedLimit( GetRunSpeed() );
  299. Vector toLanding = m_landingGoal - GetFeet();
  300. toLanding.z = 0.0f;
  301. toLanding.NormalizeInPlace();
  302. if ( m_hasLeftTheGround )
  303. {
  304. // face into the jump/climb
  305. GetBot()->GetBodyInterface()->AimHeadTowards( GetBot()->GetEntity()->EyePosition() + 100.0 * toLanding, IBody::MANDATORY, 0.25f, NULL, "Facing impending jump/climb" );
  306. if ( IsOnGround() )
  307. {
  308. // back on the ground - jump is complete
  309. m_isClimbingUpToLedge = false;
  310. m_isJumpingAcrossGap = false;
  311. SetMinimumSpeedLimit( 0.0f );
  312. }
  313. }
  314. else
  315. {
  316. // haven't left the ground yet - just starting the jump
  317. if ( !IsClimbingOrJumping() )
  318. {
  319. Jump();
  320. }
  321. Vector vel = GetBot()->GetEntity()->GetAbsVelocity();
  322. if ( m_isJumpingAcrossGap )
  323. {
  324. // cheat and max our velocity in case we were stopped at the edge of this gap
  325. vel.x = GetRunSpeed() * toLanding.x;
  326. vel.y = GetRunSpeed() * toLanding.y;
  327. // leave vel.z unchanged
  328. }
  329. GetBot()->GetEntity()->SetAbsVelocity( vel );
  330. if ( !IsOnGround() )
  331. {
  332. // jump has begun
  333. m_hasLeftTheGround = true;
  334. }
  335. }
  336. Approach( m_landingGoal );
  337. }
  338. BaseClass::Update();
  339. }
  340. //-----------------------------------------------------------------------------------------------------
  341. void PlayerLocomotion::AdjustPosture( const Vector &moveGoal )
  342. {
  343. // This function has no effect if we're not standing or crouching
  344. IBody *body = GetBot()->GetBodyInterface();
  345. if ( !body->IsActualPosture( IBody::STAND ) && !body->IsActualPosture( IBody::CROUCH ) )
  346. return;
  347. // not all games have auto-crouch, so don't assume it here
  348. BaseClass::AdjustPosture( moveGoal );
  349. }
  350. //-----------------------------------------------------------------------------------------------------
  351. /**
  352. * Build a user command to move this player towards the goal position
  353. */
  354. void PlayerLocomotion::Approach( const Vector &pos, float goalWeight )
  355. {
  356. VPROF_BUDGET( "PlayerLocomotion::Approach", "NextBot" );
  357. BaseClass::Approach( pos );
  358. AdjustPosture( pos );
  359. if ( GetBot()->IsDebugging( NEXTBOT_LOCOMOTION ) )
  360. {
  361. NDebugOverlay::Line( GetFeet(), pos, 255, 255, 0, true, 0.1f );
  362. }
  363. INextBotPlayerInput *playerButtons = dynamic_cast< INextBotPlayerInput * >( GetBot() );
  364. if ( !playerButtons )
  365. {
  366. DevMsg( "PlayerLocomotion::Approach: No INextBotPlayerInput\n " );
  367. return;
  368. }
  369. Vector forward3D;
  370. m_player->EyeVectors( &forward3D );
  371. Vector2D forward( forward3D.x, forward3D.y );
  372. forward.NormalizeInPlace();
  373. Vector2D right( forward.y, -forward.x );
  374. // compute unit vector to goal position
  375. Vector2D to = ( pos - GetFeet() ).AsVector2D();
  376. float goalDistance = to.NormalizeInPlace();
  377. float ahead = to.Dot( forward );
  378. float side = to.Dot( right );
  379. #ifdef NEED_TO_INTEGRATE_MOTION_CONTROLLED_CODE_FROM_L4D_PLAYERS
  380. // If we're climbing ledges, we need to stay crouched to prevent player movement code from messing
  381. // with our origin.
  382. CTerrorPlayer *player = ToTerrorPlayer(m_player);
  383. if ( player && player->IsMotionControlledZ( player->GetMainActivity() ) )
  384. {
  385. playerButtons->PressCrouchButton();
  386. return;
  387. }
  388. #endif
  389. if ( m_player->IsOnLadder() && IsUsingLadder() && ( m_ladderState == ASCENDING_LADDER || m_ladderState == DESCENDING_LADDER ) )
  390. {
  391. // we are on a ladder and WANT to be on a ladder.
  392. playerButtons->PressForwardButton();
  393. // Stay in center of ladder. The gamemovement will autocenter us in most cases, but this is needed in case it doesn't.
  394. if ( m_ladderInfo )
  395. {
  396. Vector posOnLadder;
  397. CalcClosestPointOnLine( GetFeet(), m_ladderInfo->m_bottom, m_ladderInfo->m_top, posOnLadder );
  398. Vector alongLadder = m_ladderInfo->m_top - m_ladderInfo->m_bottom;
  399. alongLadder.NormalizeInPlace();
  400. Vector rightLadder = CrossProduct( alongLadder, m_ladderInfo->GetNormal() );
  401. Vector away = GetFeet() - posOnLadder;
  402. // we only want error in plane of ladder
  403. float error = DotProduct( away, rightLadder );
  404. away.NormalizeInPlace();
  405. const float tolerance = 5.0f + 0.25f * GetBot()->GetBodyInterface()->GetHullWidth();
  406. if ( error > tolerance )
  407. {
  408. if ( DotProduct( away, rightLadder ) > 0.0f )
  409. {
  410. playerButtons->PressLeftButton();
  411. }
  412. else
  413. {
  414. playerButtons->PressRightButton();
  415. }
  416. }
  417. }
  418. }
  419. else
  420. {
  421. const float epsilon = 0.25f;
  422. if ( NextBotPlayerMoveDirect.GetBool() )
  423. {
  424. if ( goalDistance > epsilon )
  425. {
  426. playerButtons->SetButtonScale( ahead, side );
  427. }
  428. }
  429. if ( ahead > epsilon )
  430. {
  431. playerButtons->PressForwardButton();
  432. if ( GetBot()->IsDebugging( NEXTBOT_LOCOMOTION ) )
  433. {
  434. NDebugOverlay::HorzArrow( m_player->GetAbsOrigin(), m_player->GetAbsOrigin() + 50.0f * Vector( forward.x, forward.y, 0.0f ), 15.0f, 0, 255, 0, 255, true, 0.1f );
  435. }
  436. }
  437. else if ( ahead < -epsilon )
  438. {
  439. playerButtons->PressBackwardButton();
  440. if ( GetBot()->IsDebugging( NEXTBOT_LOCOMOTION ) )
  441. {
  442. NDebugOverlay::HorzArrow( m_player->GetAbsOrigin(), m_player->GetAbsOrigin() - 50.0f * Vector( forward.x, forward.y, 0.0f ), 15.0f, 255, 0, 0, 255, true, 0.1f );
  443. }
  444. }
  445. if ( side <= -epsilon )
  446. {
  447. playerButtons->PressLeftButton();
  448. if ( GetBot()->IsDebugging( NEXTBOT_LOCOMOTION ) )
  449. {
  450. NDebugOverlay::HorzArrow( m_player->GetAbsOrigin(), m_player->GetAbsOrigin() - 50.0f * Vector( right.x, right.y, 0.0f ), 15.0f, 255, 0, 255, 255, true, 0.1f );
  451. }
  452. }
  453. else if ( side >= epsilon )
  454. {
  455. playerButtons->PressRightButton();
  456. if ( GetBot()->IsDebugging( NEXTBOT_LOCOMOTION ) )
  457. {
  458. NDebugOverlay::HorzArrow( m_player->GetAbsOrigin(), m_player->GetAbsOrigin() + 50.0f * Vector( right.x, right.y, 0.0f ), 15.0f, 0, 255, 255, 255, true, 0.1f );
  459. }
  460. }
  461. }
  462. if ( !IsRunning() )
  463. {
  464. playerButtons->PressWalkButton();
  465. }
  466. }
  467. //----------------------------------------------------------------------------------------------------
  468. /**
  469. * Move the bot to the precise given position immediately,
  470. */
  471. void PlayerLocomotion::DriveTo( const Vector &pos )
  472. {
  473. BaseClass::DriveTo( pos );
  474. Approach( pos );
  475. }
  476. //----------------------------------------------------------------------------------------------------
  477. bool PlayerLocomotion::IsClimbPossible( INextBot *me, const CBaseEntity *obstacle ) const
  478. {
  479. // don't jump unless we have to
  480. const PathFollower *path = GetBot()->GetCurrentPath();
  481. if ( path )
  482. {
  483. const float watchForClimbRange = 75.0f;
  484. if ( !path->IsDiscontinuityAhead( GetBot(), Path::CLIMB_UP, watchForClimbRange ) )
  485. {
  486. // we are not planning on climbing
  487. // always allow climbing over movable obstacles
  488. if ( obstacle && !const_cast< CBaseEntity * >( obstacle )->IsWorld() )
  489. {
  490. IPhysicsObject *physics = obstacle->VPhysicsGetObject();
  491. if ( physics && physics->IsMoveable() )
  492. {
  493. // movable physics object - climb over it
  494. return true;
  495. }
  496. }
  497. if ( !GetBot()->GetLocomotionInterface()->IsStuck() )
  498. {
  499. // we're not stuck - don't try to jump up yet
  500. return false;
  501. }
  502. }
  503. }
  504. return true;
  505. }
  506. //----------------------------------------------------------------------------------------------------
  507. bool PlayerLocomotion::ClimbUpToLedge( const Vector &landingGoal, const Vector &landingForward, const CBaseEntity *obstacle )
  508. {
  509. if ( !IsClimbPossible( GetBot(), obstacle ) )
  510. {
  511. return false;
  512. }
  513. Jump();
  514. m_isClimbingUpToLedge = true;
  515. m_landingGoal = landingGoal;
  516. m_hasLeftTheGround = false;
  517. return true;
  518. }
  519. //----------------------------------------------------------------------------------------------------
  520. void PlayerLocomotion::JumpAcrossGap( const Vector &landingGoal, const Vector &landingForward )
  521. {
  522. Jump();
  523. // face forward
  524. GetBot()->GetBodyInterface()->AimHeadTowards( landingGoal, IBody::MANDATORY, 1.0f, NULL, "Looking forward while jumping a gap" );
  525. m_isJumpingAcrossGap = true;
  526. m_landingGoal = landingGoal;
  527. m_hasLeftTheGround = false;
  528. }
  529. //----------------------------------------------------------------------------------------------------
  530. void PlayerLocomotion::Jump( void )
  531. {
  532. m_isJumping = true;
  533. m_jumpTimer.Start( 0.5f );
  534. INextBotPlayerInput *playerButtons = dynamic_cast< INextBotPlayerInput * >( GetBot() );
  535. if ( playerButtons )
  536. {
  537. playerButtons->PressJumpButton();
  538. }
  539. }
  540. //----------------------------------------------------------------------------------------------------
  541. bool PlayerLocomotion::IsClimbingOrJumping( void ) const
  542. {
  543. if ( !m_isJumping )
  544. return false;
  545. if ( m_jumpTimer.IsElapsed() && IsOnGround() )
  546. {
  547. m_isJumping = false;
  548. return false;
  549. }
  550. return true;
  551. }
  552. //----------------------------------------------------------------------------------------------------
  553. bool PlayerLocomotion::IsClimbingUpToLedge( void ) const
  554. {
  555. return m_isClimbingUpToLedge;
  556. }
  557. //----------------------------------------------------------------------------------------------------
  558. bool PlayerLocomotion::IsJumpingAcrossGap( void ) const
  559. {
  560. return m_isJumpingAcrossGap;
  561. }
  562. //----------------------------------------------------------------------------------------------------
  563. /**
  564. * Return true if standing on something
  565. */
  566. bool PlayerLocomotion::IsOnGround( void ) const
  567. {
  568. return (m_player->GetGroundEntity() != NULL);
  569. }
  570. //----------------------------------------------------------------------------------------------------
  571. /**
  572. * Return the current ground entity or NULL if not on the ground
  573. */
  574. CBaseEntity *PlayerLocomotion::GetGround( void ) const
  575. {
  576. return m_player->GetGroundEntity();
  577. }
  578. //----------------------------------------------------------------------------------------------------
  579. /**
  580. * Surface normal of the ground we are in contact with
  581. */
  582. const Vector &PlayerLocomotion::GetGroundNormal( void ) const
  583. {
  584. static Vector up( 0, 0, 1.0f );
  585. return up;
  586. // TODO: Integrate movehelper_server for this: return m_player->GetGroundNormal();
  587. }
  588. //----------------------------------------------------------------------------------------------------
  589. /**
  590. * Climb the given ladder to the top and dismount
  591. */
  592. void PlayerLocomotion::ClimbLadder( const CNavLadder *ladder, const CNavArea *dismountGoal )
  593. {
  594. // look up and push forward
  595. // Vector goal = GetBot()->GetPosition() + 100.0f * ( Vector( 0, 0, 1.0f ) - ladder->GetNormal() );
  596. // Approach( goal );
  597. // FaceTowards( goal );
  598. m_ladderState = APPROACHING_ASCENDING_LADDER;
  599. m_ladderInfo = ladder;
  600. m_ladderDismountGoal = dismountGoal;
  601. }
  602. //----------------------------------------------------------------------------------------------------
  603. /**
  604. * Descend the given ladder to the bottom and dismount
  605. */
  606. void PlayerLocomotion::DescendLadder( const CNavLadder *ladder, const CNavArea *dismountGoal )
  607. {
  608. // look down and push forward
  609. // Vector goal = GetBot()->GetPosition() + 100.0f * ( Vector( 0, 0, -1.0f ) - ladder->GetNormal() );
  610. // Approach( goal );
  611. // FaceTowards( goal );
  612. m_ladderState = APPROACHING_DESCENDING_LADDER;
  613. m_ladderInfo = ladder;
  614. m_ladderDismountGoal = dismountGoal;
  615. }
  616. //----------------------------------------------------------------------------------------------------
  617. bool PlayerLocomotion::IsUsingLadder( void ) const
  618. {
  619. return ( m_ladderState != NO_LADDER );
  620. }
  621. //----------------------------------------------------------------------------------------------------
  622. /**
  623. * Rotate body to face towards "target"
  624. */
  625. void PlayerLocomotion::FaceTowards( const Vector &target )
  626. {
  627. // player body follows view direction
  628. Vector look( target.x, target.y, GetBot()->GetEntity()->EyePosition().z );
  629. GetBot()->GetBodyInterface()->AimHeadTowards( look, IBody::BORING, 0.1f, NULL, "Body facing" );
  630. }
  631. //-----------------------------------------------------------------------------------------------------
  632. /**
  633. * Return position of "feet" - point below centroid of bot at feet level
  634. */
  635. const Vector &PlayerLocomotion::GetFeet( void ) const
  636. {
  637. return m_player->GetAbsOrigin();
  638. }
  639. //-----------------------------------------------------------------------------------------------------
  640. /**
  641. * Return current world space velocity
  642. */
  643. const Vector &PlayerLocomotion::GetVelocity( void ) const
  644. {
  645. return m_player->GetAbsVelocity();
  646. }
  647. //-----------------------------------------------------------------------------------------------------
  648. float PlayerLocomotion::GetRunSpeed( void ) const
  649. {
  650. return m_player->MaxSpeed();
  651. }
  652. //-----------------------------------------------------------------------------------------------------
  653. float PlayerLocomotion::GetWalkSpeed( void ) const
  654. {
  655. return 0.5f * m_player->MaxSpeed();
  656. }