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.

1718 lines
54 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "trains.h"
  8. #include "ai_trackpather.h"
  9. // memdbgon must be the last include file in a .cpp file!!!
  10. #include "tier0/memdbgon.h"
  11. #define TRACKPATHER_DEBUG_LEADING 1
  12. #define TRACKPATHER_DEBUG_PATH 2
  13. #define TRACKPATHER_DEBUG_TRACKS 3
  14. ConVar g_debug_trackpather( "g_debug_trackpather", "0", FCVAR_CHEAT );
  15. //------------------------------------------------------------------------------
  16. BEGIN_DATADESC( CAI_TrackPather )
  17. DEFINE_FIELD( m_vecDesiredPosition, FIELD_POSITION_VECTOR ),
  18. DEFINE_FIELD( m_vecGoalOrientation, FIELD_VECTOR ),
  19. DEFINE_FIELD( m_pCurrentPathTarget, FIELD_CLASSPTR ),
  20. DEFINE_FIELD( m_pDestPathTarget, FIELD_CLASSPTR ),
  21. DEFINE_FIELD( m_pLastPathTarget, FIELD_CLASSPTR ),
  22. DEFINE_FIELD( m_pTargetNearestPath, FIELD_CLASSPTR ),
  23. DEFINE_FIELD( m_strCurrentPathName, FIELD_STRING ),
  24. DEFINE_FIELD( m_strDestPathName, FIELD_STRING ),
  25. DEFINE_FIELD( m_strLastPathName, FIELD_STRING ),
  26. DEFINE_FIELD( m_strTargetNearestPathName, FIELD_STRING ),
  27. DEFINE_FIELD( m_vecLastGoalCheckPosition, FIELD_POSITION_VECTOR ),
  28. DEFINE_FIELD( m_flEnemyPathUpdateTime, FIELD_TIME ),
  29. DEFINE_FIELD( m_bForcedMove, FIELD_BOOLEAN ),
  30. DEFINE_FIELD( m_bPatrolling, FIELD_BOOLEAN ),
  31. DEFINE_FIELD( m_bPatrolBreakable, FIELD_BOOLEAN ),
  32. DEFINE_FIELD( m_bLeading, FIELD_BOOLEAN ),
  33. // Derived class pathing data
  34. DEFINE_FIELD( m_flTargetDistanceThreshold, FIELD_FLOAT ),
  35. DEFINE_FIELD( m_flAvoidDistance, FIELD_FLOAT ),
  36. DEFINE_FIELD( m_flTargetTolerance, FIELD_FLOAT ),
  37. DEFINE_FIELD( m_vecSegmentStartPoint, FIELD_POSITION_VECTOR ),
  38. DEFINE_FIELD( m_vecSegmentStartSplinePoint, FIELD_POSITION_VECTOR ),
  39. DEFINE_FIELD( m_bMovingForward, FIELD_BOOLEAN ),
  40. DEFINE_FIELD( m_bChooseFarthestPoint, FIELD_BOOLEAN ),
  41. DEFINE_FIELD( m_flFarthestPathDist, FIELD_FLOAT ),
  42. DEFINE_FIELD( m_flPathMaxSpeed, FIELD_FLOAT ),
  43. DEFINE_FIELD( m_flTargetDistFromPath, FIELD_FLOAT ),
  44. DEFINE_FIELD( m_flLeadDistance, FIELD_FLOAT ),
  45. DEFINE_FIELD( m_vecTargetPathDir, FIELD_VECTOR ),
  46. DEFINE_FIELD( m_vecTargetPathPoint, FIELD_POSITION_VECTOR ),
  47. DEFINE_FIELD( m_nPauseState, FIELD_INTEGER ),
  48. // Inputs
  49. DEFINE_INPUTFUNC( FIELD_STRING, "SetTrack", InputSetTrack ),
  50. DEFINE_INPUTFUNC( FIELD_STRING, "FlyToSpecificTrackViaPath", InputFlyToPathTrack ),
  51. DEFINE_INPUTFUNC( FIELD_VOID, "StartPatrol", InputStartPatrol ),
  52. DEFINE_INPUTFUNC( FIELD_VOID, "StopPatrol", InputStopPatrol ),
  53. DEFINE_INPUTFUNC( FIELD_VOID, "StartBreakableMovement", InputStartBreakableMovement ),
  54. DEFINE_INPUTFUNC( FIELD_VOID, "StopBreakableMovement", InputStopBreakableMovement ),
  55. DEFINE_INPUTFUNC( FIELD_VOID, "ChooseFarthestPathPoint", InputChooseFarthestPathPoint ),
  56. DEFINE_INPUTFUNC( FIELD_VOID, "ChooseNearestPathPoint", InputChooseNearestPathPoint ),
  57. DEFINE_INPUTFUNC( FIELD_INTEGER,"InputStartLeading", InputStartLeading ),
  58. DEFINE_INPUTFUNC( FIELD_VOID, "InputStopLeading", InputStopLeading ),
  59. // Obsolete, for backwards compatibility
  60. DEFINE_INPUTFUNC( FIELD_VOID, "StartPatrolBreakable", InputStartPatrolBreakable ),
  61. DEFINE_INPUTFUNC( FIELD_STRING, "FlyToPathTrack", InputFlyToPathTrack ),
  62. END_DATADESC()
  63. //-----------------------------------------------------------------------------
  64. // Purpose: Initialize pathing data
  65. //-----------------------------------------------------------------------------
  66. void CAI_TrackPather::InitPathingData( float flTrackArrivalTolerance, float flTargetDistance, float flAvoidDistance )
  67. {
  68. m_flTargetTolerance = flTrackArrivalTolerance;
  69. m_flTargetDistanceThreshold = flTargetDistance;
  70. m_flAvoidDistance = flAvoidDistance;
  71. m_pCurrentPathTarget = NULL;
  72. m_pDestPathTarget = NULL;
  73. m_pLastPathTarget = NULL;
  74. m_pTargetNearestPath = NULL;
  75. m_bLeading = false;
  76. m_flEnemyPathUpdateTime = gpGlobals->curtime;
  77. m_bForcedMove = false;
  78. m_bPatrolling = false;
  79. m_bPatrolBreakable = false;
  80. m_flLeadDistance = 0.0f;
  81. m_bMovingForward = true;
  82. m_vecSegmentStartPoint = m_vecSegmentStartSplinePoint = m_vecDesiredPosition = GetAbsOrigin();
  83. m_bChooseFarthestPoint = true;
  84. m_flFarthestPathDist = 1e10;
  85. m_flPathMaxSpeed = 0;
  86. m_nPauseState = PAUSE_NO_PAUSE;
  87. }
  88. //-----------------------------------------------------------------------------
  89. // Purpose:
  90. //-----------------------------------------------------------------------------
  91. void CAI_TrackPather::OnRestore( void )
  92. {
  93. BaseClass::OnRestore();
  94. // Restore current path
  95. if ( m_strCurrentPathName != NULL_STRING )
  96. {
  97. m_pCurrentPathTarget = (CPathTrack *) gEntList.FindEntityByName( NULL, m_strCurrentPathName );
  98. }
  99. else
  100. {
  101. m_pCurrentPathTarget = NULL;
  102. }
  103. // Restore destination path
  104. if ( m_strDestPathName != NULL_STRING )
  105. {
  106. m_pDestPathTarget = (CPathTrack *) gEntList.FindEntityByName( NULL, m_strDestPathName );
  107. }
  108. else
  109. {
  110. m_pDestPathTarget = NULL;
  111. }
  112. // Restore last path
  113. if ( m_strLastPathName != NULL_STRING )
  114. {
  115. m_pLastPathTarget = (CPathTrack *) gEntList.FindEntityByName( NULL, m_strLastPathName );
  116. }
  117. else
  118. {
  119. m_pLastPathTarget = NULL;
  120. }
  121. // Restore target nearest path
  122. if ( m_strTargetNearestPathName != NULL_STRING )
  123. {
  124. m_pTargetNearestPath = (CPathTrack *) gEntList.FindEntityByName( NULL, m_strTargetNearestPathName );
  125. }
  126. else
  127. {
  128. m_pTargetNearestPath = NULL;
  129. }
  130. }
  131. //-----------------------------------------------------------------------------
  132. // Purpose:
  133. //-----------------------------------------------------------------------------
  134. void CAI_TrackPather::OnSave( IEntitySaveUtils *pUtils )
  135. {
  136. BaseClass::OnSave( pUtils );
  137. // Stash all the paths into strings for restoration later
  138. m_strCurrentPathName = ( m_pCurrentPathTarget != NULL ) ? m_pCurrentPathTarget->GetEntityName() : NULL_STRING;
  139. m_strDestPathName = ( m_pDestPathTarget != NULL ) ? m_pDestPathTarget->GetEntityName() : NULL_STRING;
  140. m_strLastPathName = ( m_pLastPathTarget != NULL ) ? m_pLastPathTarget->GetEntityName() : NULL_STRING;
  141. m_strTargetNearestPathName = ( m_pTargetNearestPath != NULL ) ? m_pTargetNearestPath->GetEntityName() : NULL_STRING;
  142. }
  143. //-----------------------------------------------------------------------------
  144. // Leading distance
  145. //-----------------------------------------------------------------------------
  146. void CAI_TrackPather::EnableLeading( bool bEnable )
  147. {
  148. bool bWasLeading = m_bLeading;
  149. m_bLeading = bEnable;
  150. if ( m_bLeading )
  151. {
  152. m_bPatrolling = false;
  153. }
  154. else if ( bWasLeading )
  155. {
  156. // Going from leading to not leading. Refresh the desired position
  157. // to prevent us from hovering around our old, no longer valid lead position.
  158. if ( m_pCurrentPathTarget )
  159. {
  160. SetDesiredPosition( m_pCurrentPathTarget->GetAbsOrigin() );
  161. }
  162. }
  163. }
  164. void CAI_TrackPather::SetLeadingDistance( float flLeadDistance )
  165. {
  166. m_flLeadDistance = flLeadDistance;
  167. }
  168. float CAI_TrackPather::GetLeadingDistance( ) const
  169. {
  170. return m_flLeadDistance;
  171. }
  172. //-----------------------------------------------------------------------------
  173. // Returns the next path along our current path
  174. //-----------------------------------------------------------------------------
  175. inline CPathTrack *CAI_TrackPather::NextAlongCurrentPath( CPathTrack *pPath ) const
  176. {
  177. return CPathTrack::ValidPath( m_bMovingForward ? pPath->GetNext() : pPath->GetPrevious() );
  178. }
  179. inline CPathTrack *CAI_TrackPather::PreviousAlongCurrentPath( CPathTrack *pPath ) const
  180. {
  181. return CPathTrack::ValidPath( m_bMovingForward ? pPath->GetPrevious() : pPath->GetNext() );
  182. }
  183. inline CPathTrack *CAI_TrackPather::AdjustForMovementDirection( CPathTrack *pPath ) const
  184. {
  185. if ( !m_bMovingForward && CPathTrack::ValidPath( pPath->GetPrevious( ) ) )
  186. {
  187. pPath = CPathTrack::ValidPath( pPath->GetPrevious() );
  188. }
  189. return pPath;
  190. }
  191. //-----------------------------------------------------------------------------
  192. // Enemy visibility check
  193. //-----------------------------------------------------------------------------
  194. CBaseEntity *CAI_TrackPather::FindTrackBlocker( const Vector &vecViewPoint, const Vector &vecTargetPos )
  195. {
  196. trace_t tr;
  197. AI_TraceHull( vecViewPoint, vecTargetPos, -Vector(4,4,4), Vector(4,4,4), MASK_SHOT, this, COLLISION_GROUP_NONE, &tr );
  198. return (tr.fraction != 1.0f) ? tr.m_pEnt : NULL;
  199. }
  200. //-----------------------------------------------------------------------------
  201. // Purpose:
  202. // Input : &targetPos -
  203. // Output : CBaseEntity
  204. //-----------------------------------------------------------------------------
  205. CPathTrack *CAI_TrackPather::BestPointOnPath( CPathTrack *pPath, const Vector &targetPos, float flAvoidRadius, bool visible, bool bFarthestPoint )
  206. {
  207. // Find the node nearest to the destination path target if a path is not specified
  208. if ( pPath == NULL )
  209. {
  210. pPath = m_pDestPathTarget;
  211. }
  212. // If the path node we're trying to use is not valid, then we're done.
  213. if ( CPathTrack::ValidPath( pPath ) == NULL )
  214. {
  215. //FIXME: Implement
  216. Assert(0);
  217. return NULL;
  218. }
  219. // Our target may be in a vehicle
  220. CBaseEntity *pVehicle = NULL;
  221. CBaseEntity *pTargetEnt = GetTrackPatherTargetEnt();
  222. if ( pTargetEnt != NULL )
  223. {
  224. CBaseCombatCharacter *pCCTarget = pTargetEnt->MyCombatCharacterPointer();
  225. if ( pCCTarget != NULL && pCCTarget->IsInAVehicle() )
  226. {
  227. pVehicle = pCCTarget->GetVehicleEntity();
  228. }
  229. }
  230. // Faster math...
  231. flAvoidRadius *= flAvoidRadius;
  232. // Find the nearest node to the target (going forward)
  233. CPathTrack *pNearestPath = NULL;
  234. float flNearestDist = bFarthestPoint ? 0 : 999999999;
  235. float flPathDist;
  236. float flFarthestDistSqr = ( m_flFarthestPathDist - 2.0f * m_flTargetDistanceThreshold );
  237. flFarthestDistSqr *= flFarthestDistSqr;
  238. // NOTE: Gotta do it this crazy way because paths can be one-way.
  239. for ( int i = 0; i < 2; ++i )
  240. {
  241. int loopCheck = 0;
  242. CPathTrack *pTravPath = pPath;
  243. CPathTrack *pNextPath;
  244. BEGIN_PATH_TRACK_ITERATION();
  245. for ( ; CPathTrack::ValidPath( pTravPath ); pTravPath = pNextPath, loopCheck++ )
  246. {
  247. // Circular loop checking
  248. if ( pTravPath->HasBeenVisited() )
  249. break;
  250. pTravPath->Visit();
  251. pNextPath = (i == 0) ? pTravPath->GetPrevious() : pTravPath->GetNext();
  252. // Find the distance between this test point and our goal point
  253. flPathDist = ( pTravPath->GetAbsOrigin() - targetPos ).LengthSqr();
  254. // See if it's closer and it's also not within our avoidance radius
  255. if ( bFarthestPoint )
  256. {
  257. if ( ( flPathDist <= flNearestDist ) && ( flNearestDist <= flFarthestDistSqr ) )
  258. continue;
  259. }
  260. else
  261. {
  262. if ( flPathDist >= flNearestDist )
  263. continue;
  264. }
  265. // Don't choose points that are within the avoid radius
  266. if ( flAvoidRadius && ( pTravPath->GetAbsOrigin() - targetPos ).Length2DSqr() <= flAvoidRadius )
  267. continue;
  268. if ( visible )
  269. {
  270. // If it has to be visible, run those checks
  271. CBaseEntity *pBlocker = FindTrackBlocker( pTravPath->GetAbsOrigin(), targetPos );
  272. // Check to see if we've hit the target, or the player's vehicle if it's a player in a vehicle
  273. bool bHitTarget = ( pTargetEnt && ( pTargetEnt == pBlocker ) ) ||
  274. ( pVehicle && ( pVehicle == pBlocker ) );
  275. // If we hit something, and it wasn't the target or his vehicle, then no dice
  276. // If we hit the target and forced move was set, *still* no dice
  277. if ( (pBlocker != NULL) && ( !bHitTarget || m_bForcedMove ) )
  278. continue;
  279. }
  280. pNearestPath = pTravPath;
  281. flNearestDist = flPathDist;
  282. }
  283. }
  284. return pNearestPath;
  285. }
  286. //-----------------------------------------------------------------------------
  287. // Compute a point n units along a path
  288. //-----------------------------------------------------------------------------
  289. CPathTrack *CAI_TrackPather::ComputeLeadingPointAlongPath( const Vector &vecStartPoint,
  290. CPathTrack *pFirstTrack, float flDistance, Vector *pTarget )
  291. {
  292. bool bMovingForward = (flDistance > 0.0f);
  293. flDistance = fabs(flDistance);
  294. CPathTrack *pTravPath = pFirstTrack;
  295. if ( (!bMovingForward) && pFirstTrack->GetPrevious() )
  296. {
  297. pTravPath = pFirstTrack->GetPrevious();
  298. }
  299. *pTarget = vecStartPoint;
  300. CPathTrack *pNextPath;
  301. // No circular loop checking needed; eventually, it'll run out of distance
  302. for ( ; CPathTrack::ValidPath( pTravPath ); pTravPath = pNextPath )
  303. {
  304. pNextPath = bMovingForward ? pTravPath->GetNext() : pTravPath->GetPrevious();
  305. // Find the distance between this test point and our goal point
  306. float flPathDist = pTarget->DistTo( pTravPath->GetAbsOrigin() );
  307. // Find the distance between this test point and our goal point
  308. if ( flPathDist <= flDistance )
  309. {
  310. flDistance -= flPathDist;
  311. *pTarget = pTravPath->GetAbsOrigin();
  312. if ( !CPathTrack::ValidPath(pNextPath) )
  313. return bMovingForward ? pTravPath : pTravPath->GetNext();
  314. continue;
  315. }
  316. ComputeClosestPoint( *pTarget, flDistance, pTravPath->GetAbsOrigin(), pTarget );
  317. return bMovingForward ? pTravPath : pTravPath->GetNext();
  318. }
  319. return NULL;
  320. }
  321. //-----------------------------------------------------------------------------
  322. // Compute the distance to a particular point on the path
  323. //-----------------------------------------------------------------------------
  324. float CAI_TrackPather::ComputeDistanceAlongPathToPoint( CPathTrack *pStartTrack,
  325. CPathTrack *pDestTrack, const Vector &vecDestPosition, bool bMovingForward )
  326. {
  327. float flTotalDist = 0.0f;
  328. Vector vecPoint;
  329. ClosestPointToCurrentPath( &vecPoint );
  330. CPathTrack *pTravPath = pStartTrack;
  331. CPathTrack *pNextPath, *pTestPath;
  332. BEGIN_PATH_TRACK_ITERATION();
  333. for ( ; CPathTrack::ValidPath( pTravPath ); pTravPath = pNextPath )
  334. {
  335. // Circular loop checking
  336. if ( pTravPath->HasBeenVisited() )
  337. break;
  338. // Mark it as being visited.
  339. pTravPath->Visit();
  340. pNextPath = bMovingForward ? pTravPath->GetNext() : pTravPath->GetPrevious();
  341. pTestPath = pTravPath;
  342. Assert( pTestPath );
  343. if ( pTravPath == pDestTrack )
  344. {
  345. Vector vecDelta;
  346. Vector vecPathDelta;
  347. VectorSubtract( vecDestPosition, vecPoint, vecDelta );
  348. ComputePathDirection( pTravPath, &vecPathDelta );
  349. float flDot = DotProduct( vecDelta, vecPathDelta );
  350. flTotalDist += (flDot > 0.0f ? 1.0f : -1.0f) * vecDelta.Length2D();
  351. break;
  352. }
  353. // NOTE: This would be made more accurate if we did the path direction check here too.
  354. // The starting vecPoint is sometimes *not* within the bounds of the line segment.
  355. // Find the distance between this test point and our goal point
  356. flTotalDist += (bMovingForward ? 1.0f : -1.0f) * vecPoint.AsVector2D().DistTo( pTestPath->GetAbsOrigin().AsVector2D() );
  357. vecPoint = pTestPath->GetAbsOrigin();
  358. }
  359. return flTotalDist;
  360. }
  361. //------------------------------------------------------------------------------
  362. // Track debugging info
  363. //------------------------------------------------------------------------------
  364. void CAI_TrackPather::VisualizeDebugInfo( const Vector &vecNearestPoint, const Vector &vecTarget )
  365. {
  366. if ( g_debug_trackpather.GetInt() == TRACKPATHER_DEBUG_PATH )
  367. {
  368. NDebugOverlay::Line( m_vecSegmentStartPoint, vecTarget, 0, 0, 255, true, 0.1f );
  369. NDebugOverlay::Cross3D( vecNearestPoint, -Vector(16,16,16), Vector(16,16,16), 255, 0, 0, true, 0.1f );
  370. NDebugOverlay::Cross3D( m_pCurrentPathTarget->GetAbsOrigin(), -Vector(16,16,16), Vector(16,16,16), 0, 255, 0, true, 0.1f );
  371. NDebugOverlay::Cross3D( m_vecDesiredPosition, -Vector(16,16,16), Vector(16,16,16), 0, 0, 255, true, 0.1f );
  372. NDebugOverlay::Cross3D( m_pDestPathTarget->GetAbsOrigin(), -Vector(16,16,16), Vector(16,16,16), 255, 255, 255, true, 0.1f );
  373. if ( m_pTargetNearestPath )
  374. {
  375. NDebugOverlay::Cross3D( m_pTargetNearestPath->GetAbsOrigin(), -Vector(24,24,24), Vector(24,24,24), 255, 0, 255, true, 0.1f );
  376. }
  377. }
  378. if ( g_debug_trackpather.GetInt() == TRACKPATHER_DEBUG_TRACKS )
  379. {
  380. if ( m_pCurrentPathTarget )
  381. {
  382. CPathTrack *pPathTrack = m_pCurrentPathTarget;
  383. for ( ; CPathTrack::ValidPath( pPathTrack ); pPathTrack = pPathTrack->GetNext() )
  384. {
  385. NDebugOverlay::Box( pPathTrack->GetAbsOrigin(), -Vector(2,2,2), Vector(2,2,2), 0,255, 0, 8, 0.1 );
  386. if ( CPathTrack::ValidPath( pPathTrack->GetNext() ) )
  387. {
  388. NDebugOverlay::Line( pPathTrack->GetAbsOrigin(), pPathTrack->GetNext()->GetAbsOrigin(), 0,255,0, true, 0.1 );
  389. }
  390. if ( pPathTrack->GetNext() == m_pCurrentPathTarget )
  391. break;
  392. }
  393. }
  394. }
  395. }
  396. //------------------------------------------------------------------------------
  397. // Does this path track have LOS to the target?
  398. //------------------------------------------------------------------------------
  399. bool CAI_TrackPather::HasLOSToTarget( CPathTrack *pTrack )
  400. {
  401. CBaseEntity *pTargetEnt = GetTrackPatherTargetEnt();
  402. if ( !pTargetEnt )
  403. return true;
  404. Vector targetPos;
  405. if ( !GetTrackPatherTarget( &targetPos ) )
  406. return true;
  407. // Translate driver into vehicle for testing
  408. CBaseEntity *pVehicle = NULL;
  409. CBaseCombatCharacter *pCCTarget = pTargetEnt->MyCombatCharacterPointer();
  410. if ( pCCTarget != NULL && pCCTarget->IsInAVehicle() )
  411. {
  412. pVehicle = pCCTarget->GetVehicleEntity();
  413. }
  414. // If it has to be visible, run those checks
  415. CBaseEntity *pBlocker = FindTrackBlocker( pTrack->GetAbsOrigin(), targetPos );
  416. // Check to see if we've hit the target, or the player's vehicle if it's a player in a vehicle
  417. bool bHitTarget = ( pTargetEnt && ( pTargetEnt == pBlocker ) ) ||
  418. ( pVehicle && ( pVehicle == pBlocker ) );
  419. return (pBlocker == NULL) || bHitTarget;
  420. }
  421. //------------------------------------------------------------------------------
  422. // Moves to the track
  423. //------------------------------------------------------------------------------
  424. void CAI_TrackPather::UpdateCurrentTarget()
  425. {
  426. // Find the point along the line that we're closest to.
  427. const Vector &vecTarget = m_pCurrentPathTarget->GetAbsOrigin();
  428. Vector vecPoint;
  429. float t = ClosestPointToCurrentPath( &vecPoint );
  430. if ( (t < 1.0f) && ( vecPoint.DistToSqr( vecTarget ) > m_flTargetTolerance * m_flTargetTolerance ) )
  431. goto visualizeDebugInfo;
  432. // Forced move is gone as soon as we've reached the first point on our path
  433. if ( m_bLeading )
  434. {
  435. m_bForcedMove = false;
  436. }
  437. // Trip our "path_track reached" output
  438. if ( m_pCurrentPathTarget != m_pLastPathTarget )
  439. {
  440. // Get the path's specified max speed
  441. m_flPathMaxSpeed = m_pCurrentPathTarget->m_flSpeed;
  442. variant_t emptyVariant;
  443. m_pCurrentPathTarget->AcceptInput( "InPass", this, this, emptyVariant, 0 );
  444. m_pLastPathTarget = m_pCurrentPathTarget;
  445. }
  446. if ( m_nPauseState == PAUSED_AT_POSITION )
  447. return;
  448. if ( m_nPauseState == PAUSE_AT_NEXT_LOS_POSITION )
  449. {
  450. if ( HasLOSToTarget(m_pCurrentPathTarget) )
  451. {
  452. m_nPauseState = PAUSED_AT_POSITION;
  453. return;
  454. }
  455. }
  456. // Update our dest path target, if appropriate...
  457. if ( m_pCurrentPathTarget == m_pDestPathTarget )
  458. {
  459. m_bForcedMove = false;
  460. SelectNewDestTarget();
  461. }
  462. // Did SelectNewDestTarget give us a new point to move to?
  463. if ( m_pCurrentPathTarget != m_pDestPathTarget )
  464. {
  465. // Update to the next path, if there is one...
  466. m_pCurrentPathTarget = NextAlongCurrentPath( m_pCurrentPathTarget );
  467. if ( !m_pCurrentPathTarget )
  468. {
  469. m_pCurrentPathTarget = m_pLastPathTarget;
  470. }
  471. }
  472. else
  473. {
  474. // We're at rest (no patrolling behavior), which means we're moving forward now.
  475. m_bMovingForward = true;
  476. }
  477. SetDesiredPosition( m_pCurrentPathTarget->GetAbsOrigin() );
  478. m_vecSegmentStartSplinePoint = m_vecSegmentStartPoint;
  479. m_vecSegmentStartPoint = m_pLastPathTarget->GetAbsOrigin();
  480. visualizeDebugInfo:
  481. VisualizeDebugInfo( vecPoint, vecTarget );
  482. }
  483. //-----------------------------------------------------------------------------
  484. //
  485. // NOTE: All code below is used exclusively for leading/trailing behavior
  486. //
  487. //-----------------------------------------------------------------------------
  488. //-----------------------------------------------------------------------------
  489. // Compute the distance to the leading position
  490. //-----------------------------------------------------------------------------
  491. float CAI_TrackPather::ComputeDistanceToLeadingPosition()
  492. {
  493. return ComputeDistanceAlongPathToPoint( m_pCurrentPathTarget, m_pDestPathTarget, GetDesiredPosition(), m_bMovingForward );
  494. }
  495. //-----------------------------------------------------------------------------
  496. // Compute the distance to the *target* position
  497. //-----------------------------------------------------------------------------
  498. float CAI_TrackPather::ComputeDistanceToTargetPosition()
  499. {
  500. Assert( m_pTargetNearestPath );
  501. CPathTrack *pDest = m_bMovingForward ? m_pTargetNearestPath.Get() : m_pTargetNearestPath->GetPrevious();
  502. if ( !pDest )
  503. {
  504. pDest = m_pTargetNearestPath;
  505. }
  506. bool bMovingForward = IsForwardAlongPath( m_pCurrentPathTarget, pDest );
  507. CPathTrack *pStart = m_pCurrentPathTarget;
  508. if ( bMovingForward != m_bMovingForward )
  509. {
  510. if (bMovingForward)
  511. {
  512. if ( pStart->GetNext() )
  513. {
  514. pStart = pStart->GetNext();
  515. }
  516. if ( pDest->GetNext() )
  517. {
  518. pDest = pDest->GetNext();
  519. }
  520. }
  521. else
  522. {
  523. if ( pStart->GetPrevious() )
  524. {
  525. pStart = pStart->GetPrevious();
  526. }
  527. if ( pDest->GetPrevious() )
  528. {
  529. pDest = pDest->GetPrevious();
  530. }
  531. }
  532. }
  533. return ComputeDistanceAlongPathToPoint( pStart, pDest, m_vecTargetPathPoint, bMovingForward );
  534. }
  535. //-----------------------------------------------------------------------------
  536. // Compute a path direction
  537. //-----------------------------------------------------------------------------
  538. void CAI_TrackPather::ComputePathDirection( CPathTrack *pPath, Vector *pVecPathDir )
  539. {
  540. if ( pPath->GetPrevious() )
  541. {
  542. VectorSubtract( pPath->GetAbsOrigin(), pPath->GetPrevious()->GetAbsOrigin(), *pVecPathDir );
  543. }
  544. else
  545. {
  546. if ( pPath->GetNext() )
  547. {
  548. VectorSubtract( pPath->GetNext()->GetAbsOrigin(), pPath->GetAbsOrigin(), *pVecPathDir );
  549. }
  550. else
  551. {
  552. pVecPathDir->Init( 1, 0, 0 );
  553. }
  554. }
  555. VectorNormalize( *pVecPathDir );
  556. }
  557. //-----------------------------------------------------------------------------
  558. // What's the current path direction?
  559. //-----------------------------------------------------------------------------
  560. void CAI_TrackPather::CurrentPathDirection( Vector *pVecPathDir )
  561. {
  562. if ( m_pCurrentPathTarget )
  563. {
  564. ComputePathDirection( m_pCurrentPathTarget, pVecPathDir );
  565. }
  566. else
  567. {
  568. pVecPathDir->Init( 0, 0, 1 );
  569. }
  570. }
  571. //-----------------------------------------------------------------------------
  572. // Compute a point n units along the current path from our current position
  573. // (but don't pass the desired target point)
  574. //-----------------------------------------------------------------------------
  575. void CAI_TrackPather::ComputePointAlongCurrentPath( float flDistance, float flPerpDist, Vector *pTarget )
  576. {
  577. Vector vecPathDir;
  578. Vector vecStartPoint;
  579. ClosestPointToCurrentPath( &vecStartPoint );
  580. *pTarget = vecStartPoint;
  581. if ( flDistance != 0.0f )
  582. {
  583. Vector vecPrevPoint = vecStartPoint;
  584. CPathTrack *pTravPath = m_pCurrentPathTarget;
  585. CPathTrack *pAdjustedDest = AdjustForMovementDirection( m_pDestPathTarget );
  586. for ( ; CPathTrack::ValidPath( pTravPath ); pTravPath = NextAlongCurrentPath( pTravPath ) )
  587. {
  588. if ( pTravPath == pAdjustedDest )
  589. {
  590. ComputePathDirection( pTravPath, &vecPathDir );
  591. float flPathDist = pTarget->DistTo( GetDesiredPosition() );
  592. if ( flDistance > flPathDist )
  593. {
  594. *pTarget = GetDesiredPosition();
  595. }
  596. else
  597. {
  598. ComputeClosestPoint( *pTarget, flDistance, GetDesiredPosition(), pTarget );
  599. }
  600. break;
  601. }
  602. // Find the distance between this test point and our goal point
  603. float flPathDist = pTarget->DistTo( pTravPath->GetAbsOrigin() );
  604. // Find the distance between this test point and our goal point
  605. if ( flPathDist <= flDistance )
  606. {
  607. flDistance -= flPathDist;
  608. *pTarget = pTravPath->GetAbsOrigin();
  609. // FIXME: Reduce the distance further based on the angle between this segment + the next
  610. continue;
  611. }
  612. ComputePathDirection( pTravPath, &vecPathDir );
  613. ComputeClosestPoint( *pTarget, flDistance, pTravPath->GetAbsOrigin(), pTarget );
  614. break;
  615. }
  616. }
  617. else
  618. {
  619. VectorSubtract( m_pCurrentPathTarget->GetAbsOrigin(), m_vecSegmentStartPoint, vecPathDir );
  620. VectorNormalize( vecPathDir );
  621. }
  622. // Add in the horizontal component
  623. ComputePointFromPerpDistance( *pTarget, vecPathDir, flPerpDist, pTarget );
  624. }
  625. //-----------------------------------------------------------------------------
  626. // Methods to find a signed perp distance from the track
  627. // and to compute a point off the path based on the signed perp distance
  628. //-----------------------------------------------------------------------------
  629. float CAI_TrackPather::ComputePerpDistanceFromPath( const Vector &vecPointOnPath, const Vector &vecPathDir, const Vector &vecPointOffPath )
  630. {
  631. // Make it be a signed distance of the target from the path
  632. // Positive means on the right side, negative means on the left side
  633. Vector vecAcross, vecDelta;
  634. CrossProduct( vecPathDir, Vector( 0, 0, 1 ), vecAcross );
  635. VectorSubtract( vecPointOffPath, vecPointOnPath, vecDelta );
  636. VectorMA( vecDelta, -DotProduct( vecPathDir, vecDelta ), vecPathDir, vecDelta );
  637. float flDistanceFromPath = vecDelta.Length2D();
  638. if ( DotProduct2D( vecAcross.AsVector2D(), vecDelta.AsVector2D() ) < 0.0f )
  639. {
  640. flDistanceFromPath *= -1.0f;
  641. }
  642. return flDistanceFromPath;
  643. }
  644. void CAI_TrackPather::ComputePointFromPerpDistance( const Vector &vecPointOnPath, const Vector &vecPathDir, float flPerpDist, Vector *pResult )
  645. {
  646. Vector vecAcross;
  647. CrossProduct( vecPathDir, Vector( 0, 0, 1 ), vecAcross );
  648. VectorMA( vecPointOnPath, flPerpDist, vecAcross, *pResult );
  649. }
  650. //-----------------------------------------------------------------------------
  651. // Finds the closest point on the path, returns a signed perpendicular distance
  652. // where negative means on the left side of the path (when travelled from prev to next)
  653. // and positive means on the right side
  654. //-----------------------------------------------------------------------------
  655. CPathTrack *CAI_TrackPather::FindClosestPointOnPath( CPathTrack *pPath,
  656. const Vector &targetPos, Vector *pVecClosestPoint, Vector *pVecPathDir, float *pDistanceFromPath )
  657. {
  658. // Find the node nearest to the destination path target if a path is not specified
  659. if ( pPath == NULL )
  660. {
  661. pPath = m_pDestPathTarget;
  662. }
  663. // If the path node we're trying to use is not valid, then we're done.
  664. if ( CPathTrack::ValidPath( pPath ) == NULL )
  665. {
  666. //FIXME: Implement
  667. Assert(0);
  668. return NULL;
  669. }
  670. // Find the nearest node to the target (going forward)
  671. CPathTrack *pNearestPath = NULL;
  672. float flNearestDist2D = 999999999;
  673. float flNearestDist = 999999999;
  674. float flPathDist, flPathDist2D;
  675. // NOTE: Gotta do it this crazy way because paths can be one-way.
  676. Vector vecNearestPoint;
  677. Vector vecNearestPathSegment;
  678. for ( int i = 0; i < 2; ++i )
  679. {
  680. int loopCheck = 0;
  681. CPathTrack *pTravPath = pPath;
  682. CPathTrack *pNextPath;
  683. BEGIN_PATH_TRACK_ITERATION();
  684. for ( ; CPathTrack::ValidPath( pTravPath ); pTravPath = pNextPath, loopCheck++ )
  685. {
  686. // Circular loop checking
  687. if ( pTravPath->HasBeenVisited() )
  688. break;
  689. // Mark it as being visited.
  690. pTravPath->Visit();
  691. pNextPath = (i == 0) ? pTravPath->GetPrevious() : pTravPath->GetNext();
  692. // No alt paths allowed in leading mode.
  693. if ( pTravPath->m_paltpath )
  694. {
  695. Warning( "%s: Alternative paths in path_track not allowed when using the leading behavior!\n", GetEntityName().ToCStr() );
  696. }
  697. // Need line segments
  698. if ( !CPathTrack::ValidPath(pNextPath) )
  699. break;
  700. // Find the closest point on the line segment on the path
  701. Vector vecClosest;
  702. CalcClosestPointOnLineSegment( targetPos, pTravPath->GetAbsOrigin(), pNextPath->GetAbsOrigin(), vecClosest );
  703. // Find the distance between this test point and our goal point
  704. flPathDist2D = vecClosest.AsVector2D().DistToSqr( targetPos.AsVector2D() );
  705. if ( flPathDist2D > flNearestDist2D )
  706. continue;
  707. flPathDist = vecClosest.z - targetPos.z;
  708. flPathDist *= flPathDist;
  709. flPathDist += flPathDist2D;
  710. if (( flPathDist2D == flNearestDist2D ) && ( flPathDist >= flNearestDist ))
  711. continue;
  712. pNearestPath = (i == 0) ? pTravPath : pNextPath;
  713. flNearestDist2D = flPathDist2D;
  714. flNearestDist = flPathDist;
  715. vecNearestPoint = vecClosest;
  716. VectorSubtract( pNextPath->GetAbsOrigin(), pTravPath->GetAbsOrigin(), vecNearestPathSegment );
  717. if ( i == 0 )
  718. {
  719. vecNearestPathSegment *= -1.0f;
  720. }
  721. }
  722. }
  723. VectorNormalize( vecNearestPathSegment );
  724. *pDistanceFromPath = ComputePerpDistanceFromPath( vecNearestPoint, vecNearestPathSegment, targetPos );
  725. *pVecClosestPoint = vecNearestPoint;
  726. *pVecPathDir = vecNearestPathSegment;
  727. return pNearestPath;
  728. }
  729. //-----------------------------------------------------------------------------
  730. // Breakable paths?
  731. //-----------------------------------------------------------------------------
  732. void CAI_TrackPather::InputStartBreakableMovement( inputdata_t &inputdata )
  733. {
  734. m_bPatrolBreakable = true;
  735. }
  736. void CAI_TrackPather::InputStopBreakableMovement( inputdata_t &inputdata )
  737. {
  738. m_bPatrolBreakable = false;
  739. }
  740. //-----------------------------------------------------------------------------
  741. // Purpose:
  742. // Input : &inputdata -
  743. //-----------------------------------------------------------------------------
  744. void CAI_TrackPather::InputStartPatrol( inputdata_t &inputdata )
  745. {
  746. m_bPatrolling = true;
  747. }
  748. //-----------------------------------------------------------------------------
  749. //
  750. //-----------------------------------------------------------------------------
  751. void CAI_TrackPather::InputStopPatrol( inputdata_t &inputdata )
  752. {
  753. m_bPatrolling = false;
  754. }
  755. //-----------------------------------------------------------------------------
  756. // Purpose:
  757. // Input : &inputdata -
  758. //-----------------------------------------------------------------------------
  759. void CAI_TrackPather::InputStartPatrolBreakable( inputdata_t &inputdata )
  760. {
  761. m_bPatrolBreakable = true;
  762. m_bPatrolling = true;
  763. }
  764. //------------------------------------------------------------------------------
  765. // Leading behaviors
  766. //------------------------------------------------------------------------------
  767. void CAI_TrackPather::InputStartLeading( inputdata_t &inputdata )
  768. {
  769. EnableLeading( true );
  770. SetLeadingDistance( inputdata.value.Int() );
  771. }
  772. void CAI_TrackPather::InputStopLeading( inputdata_t &inputdata )
  773. {
  774. EnableLeading( false );
  775. }
  776. //------------------------------------------------------------------------------
  777. // Selects a new destination target
  778. //------------------------------------------------------------------------------
  779. void CAI_TrackPather::SelectNewDestTarget()
  780. {
  781. if ( !m_bPatrolling )
  782. return;
  783. #ifdef HL2_EP3
  784. Vector targetPos;
  785. bool bTargetPosValid = GetTrackPatherTarget( &targetPos );
  786. float flAvoidSq = m_flAvoidDistance * m_flAvoidDistance;
  787. #endif
  788. // NOTE: This version is bugged, but I didn't want to make the fix
  789. // here for fear of breaking a lot of maps late in the day.
  790. // So, only the chopper does the "right" thing.
  791. #ifdef HL2_EPISODIC
  792. // Episodic uses the fixed logic for all trackpathers
  793. if ( 1 )
  794. #else
  795. if ( ShouldUseFixedPatrolLogic() )
  796. #endif
  797. {
  798. CPathTrack *pOldDest = m_pDestPathTarget;
  799. // Only switch polarity of movement if we're at the *end* of the path
  800. // This is really useful for initial conditions of patrolling
  801. // NOTE: We've got to do some extra work for circular paths
  802. bool bIsCircular = false;
  803. {
  804. BEGIN_PATH_TRACK_ITERATION();
  805. CPathTrack *pTravPath = m_pDestPathTarget;
  806. while( CPathTrack::ValidPath( pTravPath ) )
  807. {
  808. // Circular loop checking
  809. if ( pTravPath->HasBeenVisited() )
  810. {
  811. bIsCircular = true;
  812. break;
  813. }
  814. pTravPath->Visit();
  815. pTravPath = NextAlongCurrentPath( pTravPath );
  816. }
  817. }
  818. if ( bIsCircular || (NextAlongCurrentPath( m_pDestPathTarget ) == NULL) )
  819. {
  820. m_bMovingForward = !m_bMovingForward;
  821. }
  822. BEGIN_PATH_TRACK_ITERATION();
  823. while ( true )
  824. {
  825. CPathTrack *pNextTrack = NextAlongCurrentPath( m_pDestPathTarget );
  826. if ( !pNextTrack || (pNextTrack == pOldDest) || pNextTrack->HasBeenVisited() )
  827. break;
  828. pNextTrack->Visit();
  829. #ifdef HL2_EP3
  830. if ( bTargetPosValid && ShouldUseAvoidanceWhenTracking() )
  831. {
  832. Vector posTrackPt = pNextTrack->GetAbsOrigin();
  833. if ( ( posTrackPt - targetPos ).Length2DSqr() < flAvoidSq )
  834. {
  835. // can't go there
  836. break;
  837. }
  838. }
  839. m_pDestPathTarget = pNextTrack;
  840. #else
  841. m_pDestPathTarget = pNextTrack;
  842. #endif
  843. }
  844. }
  845. else
  846. {
  847. CPathTrack *pOldDest = m_pDestPathTarget;
  848. // For patrolling, switch the polarity of movement
  849. m_bMovingForward = !m_bMovingForward;
  850. int loopCount = 0;
  851. while ( true )
  852. {
  853. CPathTrack *pNextTrack = NextAlongCurrentPath( m_pDestPathTarget );
  854. if ( !pNextTrack )
  855. break;
  856. if ( ++loopCount > 1024 )
  857. {
  858. DevMsg(1,"WARNING: Looping path for %s\n", GetDebugName() );
  859. break;
  860. }
  861. m_pDestPathTarget = pNextTrack;
  862. }
  863. if ( m_pDestPathTarget == pOldDest )
  864. {
  865. // This can occur if we move to the first point on the path
  866. SelectNewDestTarget();
  867. }
  868. }
  869. }
  870. //------------------------------------------------------------------------------
  871. // Moves to the track
  872. //------------------------------------------------------------------------------
  873. void CAI_TrackPather::UpdateCurrentTargetLeading()
  874. {
  875. bool bRestingAtDest = false;
  876. CPathTrack *pAdjustedDest;
  877. // Find the point along the line that we're closest to.
  878. const Vector &vecTarget = m_pCurrentPathTarget->GetAbsOrigin();
  879. Vector vecPoint;
  880. float t = ClosestPointToCurrentPath( &vecPoint );
  881. if ( (t < 1.0f) && ( vecPoint.DistToSqr( vecTarget ) > m_flTargetTolerance * m_flTargetTolerance ) )
  882. goto visualizeDebugInfo;
  883. // Trip our "path_track reached" output
  884. if ( m_pCurrentPathTarget != m_pLastPathTarget )
  885. {
  886. // Get the path's specified max speed
  887. m_flPathMaxSpeed = m_pCurrentPathTarget->m_flSpeed;
  888. variant_t emptyVariant;
  889. m_pCurrentPathTarget->AcceptInput( "InPass", this, this, emptyVariant, 0 );
  890. m_pLastPathTarget = m_pCurrentPathTarget;
  891. }
  892. // NOTE: CurrentPathTarget doesn't mean the same thing as dest path target!
  893. // It's the "next"most when moving forward + "prev"most when moving backward
  894. // Must do the tests in the same space
  895. pAdjustedDest = AdjustForMovementDirection( m_pDestPathTarget );
  896. // Update our dest path target, if appropriate...
  897. if ( m_pCurrentPathTarget == pAdjustedDest )
  898. {
  899. m_bForcedMove = false;
  900. SelectNewDestTarget();
  901. // NOTE: Must do this again since SelectNewDestTarget may change m_pDestPathTarget
  902. pAdjustedDest = AdjustForMovementDirection( m_pDestPathTarget );
  903. }
  904. if ( m_pCurrentPathTarget != pAdjustedDest )
  905. {
  906. // Update to the next path, if there is one...
  907. m_pCurrentPathTarget = NextAlongCurrentPath( m_pCurrentPathTarget );
  908. if ( !m_pCurrentPathTarget )
  909. {
  910. m_pCurrentPathTarget = m_pLastPathTarget;
  911. }
  912. }
  913. else
  914. {
  915. // NOTE: Have to do this here because the NextAlongCurrentPath call above
  916. // could make m_pCurrentPathTarget == m_pDestPathTarget.
  917. // In this case, we're at rest (no patrolling behavior)
  918. bRestingAtDest = true;
  919. }
  920. if ( bRestingAtDest )
  921. {
  922. // NOTE: Must use current path target, instead of dest
  923. // to get the PreviousAlongCurrentPath working correctly
  924. CPathTrack *pSegmentStart = PreviousAlongCurrentPath( m_pCurrentPathTarget );
  925. if ( !pSegmentStart )
  926. {
  927. pSegmentStart = m_pCurrentPathTarget;
  928. }
  929. m_vecSegmentStartPoint = pSegmentStart->GetAbsOrigin();
  930. }
  931. else
  932. {
  933. m_vecSegmentStartPoint = m_pLastPathTarget->GetAbsOrigin();
  934. }
  935. visualizeDebugInfo:
  936. VisualizeDebugInfo( vecPoint, vecTarget );
  937. }
  938. //-----------------------------------------------------------------------------
  939. // Purpose:
  940. //-----------------------------------------------------------------------------
  941. void CAI_TrackPather::UpdateTargetPositionLeading( void )
  942. {
  943. Vector targetPos;
  944. if ( !GetTrackPatherTarget( &targetPos ) )
  945. return;
  946. // NOTE: FindClosestPointOnPath *always* returns the point on the "far",
  947. // end of the line segment containing the closest point (namely the 'next'
  948. // track, as opposed to the 'prev' track)
  949. Vector vecClosestPoint, vecPathDir;
  950. float flTargetDistanceFromPath;
  951. CPathTrack *pNextPath = FindClosestPointOnPath( m_pCurrentPathTarget,
  952. targetPos, &vecClosestPoint, &vecPathDir, &flTargetDistanceFromPath );
  953. // This means that a valid path could not be found to our target!
  954. if ( CPathTrack::ValidPath( pNextPath ) == NULL )
  955. return;
  956. // NDebugOverlay::Cross3D( vecClosestPoint, -Vector(24,24,24), Vector(24,24,24), 0, 255, 255, true, 0.1f );
  957. // NDebugOverlay::Cross3D( pNextPath->GetAbsOrigin(), -Vector(24,24,24), Vector(24,24,24), 255, 255, 0, true, 0.1f );
  958. // Here's how far we are from the path
  959. m_flTargetDistFromPath = flTargetDistanceFromPath;
  960. m_vecTargetPathDir = vecPathDir;
  961. // Here's info about where the target is along the path
  962. m_vecTargetPathPoint = vecClosestPoint;
  963. m_pTargetNearestPath = pNextPath;
  964. // Find the best position to be on our path
  965. // NOTE: This will *also* return a path track on the "far" end of the line segment
  966. // containing the leading position, namely the "next" end of the segment as opposed
  967. // to the "prev" end of the segment.
  968. CPathTrack *pDest = ComputeLeadingPointAlongPath( vecClosestPoint, pNextPath, m_flLeadDistance, &targetPos );
  969. SetDesiredPosition( targetPos );
  970. // We only want to switch movement directions when absolutely necessary
  971. // so convert dest into a more appropriate value based on the current movement direction
  972. if ( pDest != m_pDestPathTarget )
  973. {
  974. // NOTE: This is really tricky + subtle
  975. // For leading, we don't want to ever change direction when the current target == the
  976. // adjusted destination target. Namely, if we're going forward, both dest + curr
  977. // mean the "next"most node so we can compare them directly against eath other.
  978. // If we're moving backward, dest means "next"most, but curr means "prev"most.
  979. // We first have to adjust the dest to mean "prev"most, and then do the comparison.
  980. // If the adjusted dest == curr, then maintain direction. Otherwise, use the forward along path test.
  981. bool bMovingForward = m_bMovingForward;
  982. CPathTrack *pAdjustedDest = AdjustForMovementDirection( pDest );
  983. if ( m_pCurrentPathTarget != pAdjustedDest )
  984. {
  985. bMovingForward = IsForwardAlongPath( m_pCurrentPathTarget, pAdjustedDest );
  986. }
  987. if ( bMovingForward != m_bMovingForward )
  988. {
  989. // As a result of the tricky note above, this should never occur
  990. Assert( pAdjustedDest != m_pCurrentPathTarget );
  991. // Oops! Need to reverse direction
  992. m_bMovingForward = bMovingForward;
  993. m_vecSegmentStartPoint = m_pCurrentPathTarget->GetAbsOrigin();
  994. m_pCurrentPathTarget = NextAlongCurrentPath( m_pCurrentPathTarget );
  995. }
  996. m_pDestPathTarget = pDest;
  997. }
  998. // NDebugOverlay::Cross3D( m_pCurrentPathTarget->GetAbsOrigin(), -Vector(36,36,36), Vector(36,36,36), 255, 0, 0, true, 0.1f );
  999. // NDebugOverlay::Cross3D( m_pDestPathTarget->GetAbsOrigin(), -Vector(48,48,48), Vector(48,48,48), 0, 255, 0, true, 0.1f );
  1000. // NDebugOverlay::Cross3D( targetPos, -Vector(36,36,36), Vector(36,36,36), 0, 0, 255, true, 0.1f );
  1001. }
  1002. //-----------------------------------------------------------------------------
  1003. // Purpose:
  1004. //-----------------------------------------------------------------------------
  1005. void CAI_TrackPather::UpdateTargetPosition( void )
  1006. {
  1007. // Don't update our target if we're being told to go somewhere
  1008. if ( m_bForcedMove && !m_bPatrolBreakable )
  1009. return;
  1010. // Don't update our target if we're patrolling
  1011. if ( m_bPatrolling )
  1012. {
  1013. // If we have an enemy, and our patrol is breakable, stop patrolling
  1014. if ( !m_bPatrolBreakable || !GetEnemy() )
  1015. return;
  1016. m_bPatrolling = false;
  1017. }
  1018. Vector targetPos;
  1019. if ( !GetTrackPatherTarget( &targetPos ) )
  1020. return;
  1021. // Not time to update again
  1022. if ( m_flEnemyPathUpdateTime > gpGlobals->curtime )
  1023. return;
  1024. // See if the target has moved enough to make us recheck
  1025. float flDistSqr = ( targetPos - m_vecLastGoalCheckPosition ).LengthSqr();
  1026. if ( flDistSqr < m_flTargetDistanceThreshold * m_flTargetDistanceThreshold )
  1027. return;
  1028. // Find the best position to be on our path
  1029. CPathTrack *pDest = BestPointOnPath( m_pCurrentPathTarget, targetPos, m_flAvoidDistance, true, m_bChooseFarthestPoint );
  1030. if ( CPathTrack::ValidPath( pDest ) == NULL )
  1031. {
  1032. // This means that a valid path could not be found to our target!
  1033. // Assert(0);
  1034. return;
  1035. }
  1036. if ( pDest != m_pDestPathTarget )
  1037. {
  1038. // This is our new destination
  1039. bool bMovingForward = IsForwardAlongPath( m_pCurrentPathTarget, pDest );
  1040. if ( bMovingForward != m_bMovingForward )
  1041. {
  1042. // Oops! Need to reverse direction
  1043. m_bMovingForward = bMovingForward;
  1044. if ( pDest != m_pCurrentPathTarget )
  1045. {
  1046. SetupNewCurrentTarget( NextAlongCurrentPath( m_pCurrentPathTarget ) );
  1047. }
  1048. }
  1049. m_pDestPathTarget = pDest;
  1050. }
  1051. // Keep this goal point for comparisons later
  1052. m_vecLastGoalCheckPosition = targetPos;
  1053. // Only do this on set intervals
  1054. m_flEnemyPathUpdateTime = gpGlobals->curtime + 1.0f;
  1055. }
  1056. //------------------------------------------------------------------------------
  1057. // Returns the direction of the path at the closest point to the target
  1058. //------------------------------------------------------------------------------
  1059. const Vector &CAI_TrackPather::TargetPathDirection() const
  1060. {
  1061. return m_vecTargetPathDir;
  1062. }
  1063. const Vector &CAI_TrackPather::TargetPathAcrossDirection() const
  1064. {
  1065. static Vector s_Result;
  1066. CrossProduct( m_vecTargetPathDir, Vector( 0, 0, 1 ), s_Result );
  1067. return s_Result;
  1068. }
  1069. //------------------------------------------------------------------------------
  1070. // Returns the speed of the target relative to the path
  1071. //------------------------------------------------------------------------------
  1072. float CAI_TrackPather::TargetSpeedAlongPath() const
  1073. {
  1074. if ( !GetEnemy() || !IsLeading() )
  1075. return 0.0f;
  1076. Vector vecSmoothedVelocity = GetEnemy()->GetSmoothedVelocity();
  1077. return DotProduct( vecSmoothedVelocity, TargetPathDirection() );
  1078. }
  1079. //------------------------------------------------------------------------------
  1080. // Returns the speed of the target *across* the path
  1081. //------------------------------------------------------------------------------
  1082. float CAI_TrackPather::TargetSpeedAcrossPath() const
  1083. {
  1084. if ( !GetEnemy() || !IsLeading() )
  1085. return 0.0f;
  1086. Vector vecSmoothedVelocity = GetEnemy()->GetSmoothedVelocity();
  1087. return DotProduct( vecSmoothedVelocity, TargetPathAcrossDirection() );
  1088. }
  1089. //------------------------------------------------------------------------------
  1090. // Returns the max distance we can be from the path
  1091. //------------------------------------------------------------------------------
  1092. float CAI_TrackPather::MaxDistanceFromCurrentPath() const
  1093. {
  1094. if ( !IsLeading() || !m_pCurrentPathTarget )
  1095. return 0.0f;
  1096. CPathTrack *pPrevPath = PreviousAlongCurrentPath( m_pCurrentPathTarget );
  1097. if ( !pPrevPath )
  1098. {
  1099. pPrevPath = m_pCurrentPathTarget;
  1100. }
  1101. // NOTE: Can't use m_vecSegmentStartPoint because we don't have a radius defined for it
  1102. float t;
  1103. Vector vecTemp;
  1104. CalcClosestPointOnLine( GetAbsOrigin(), pPrevPath->GetAbsOrigin(),
  1105. m_pCurrentPathTarget->GetAbsOrigin(), vecTemp, &t );
  1106. t = clamp( t, 0.0f, 1.0f );
  1107. float flRadius = (1.0f - t) * pPrevPath->GetRadius() + t * m_pCurrentPathTarget->GetRadius();
  1108. return flRadius;
  1109. }
  1110. //------------------------------------------------------------------------------
  1111. // Purpose : A different version of the track pather which is more explicit about
  1112. // the meaning of dest, current, and prev path points
  1113. //------------------------------------------------------------------------------
  1114. void CAI_TrackPather::UpdateTrackNavigation( void )
  1115. {
  1116. // No target? Use the string specified. We have no spawn method (sucky!!) so this is how that works
  1117. if ( ( CPathTrack::ValidPath( m_pDestPathTarget ) == NULL ) && ( m_target != NULL_STRING ) )
  1118. {
  1119. FlyToPathTrack( m_target );
  1120. m_target = NULL_STRING;
  1121. }
  1122. if ( !IsLeading() )
  1123. {
  1124. if ( !m_pCurrentPathTarget )
  1125. return;
  1126. // Updates our destination node if we're tracking something
  1127. UpdateTargetPosition();
  1128. // Move along our path towards our current destination
  1129. UpdateCurrentTarget();
  1130. }
  1131. else
  1132. {
  1133. // Updates our destination position if we're leading something
  1134. UpdateTargetPositionLeading();
  1135. // Move along our path towards our current destination
  1136. UpdateCurrentTargetLeading();
  1137. }
  1138. }
  1139. //------------------------------------------------------------------------------
  1140. // Sets the farthest path distance
  1141. //------------------------------------------------------------------------------
  1142. void CAI_TrackPather::SetFarthestPathDist( float flMaxPathDist )
  1143. {
  1144. m_flFarthestPathDist = flMaxPathDist;
  1145. }
  1146. //------------------------------------------------------------------------------
  1147. // Sets up a new current path target
  1148. //------------------------------------------------------------------------------
  1149. void CAI_TrackPather::SetupNewCurrentTarget( CPathTrack *pTrack )
  1150. {
  1151. Assert( pTrack );
  1152. m_vecSegmentStartPoint = GetAbsOrigin();
  1153. VectorMA( m_vecSegmentStartPoint, -2.0f, GetAbsVelocity(), m_vecSegmentStartSplinePoint );
  1154. OnNewCurrentTarget( pTrack, m_pCurrentPathTarget );
  1155. m_pCurrentPathTarget = pTrack;
  1156. SetDesiredPosition( m_pCurrentPathTarget->GetAbsOrigin() );
  1157. }
  1158. //------------------------------------------------------------------------------
  1159. // Moves to an explicit track point
  1160. //------------------------------------------------------------------------------
  1161. void CAI_TrackPather::MoveToTrackPoint( CPathTrack *pTrack )
  1162. {
  1163. if ( IsOnSameTrack( pTrack, m_pDestPathTarget ) )
  1164. {
  1165. // The track must be valid
  1166. if ( CPathTrack::ValidPath( pTrack ) == NULL )
  1167. return;
  1168. m_pDestPathTarget = pTrack;
  1169. m_bMovingForward = IsForwardAlongPath( m_pCurrentPathTarget, pTrack );
  1170. m_bForcedMove = true;
  1171. }
  1172. else
  1173. {
  1174. CPathTrack *pClosestTrack = BestPointOnPath( pTrack, WorldSpaceCenter(), 0.0f, false, false );
  1175. // The track must be valid
  1176. if ( CPathTrack::ValidPath( pClosestTrack ) == NULL )
  1177. return;
  1178. SetupNewCurrentTarget( pClosestTrack );
  1179. m_pDestPathTarget = pTrack;
  1180. m_bMovingForward = IsForwardAlongPath( pClosestTrack, pTrack );
  1181. m_bForcedMove = true;
  1182. }
  1183. }
  1184. //------------------------------------------------------------------------------
  1185. // Moves to the closest track point
  1186. //------------------------------------------------------------------------------
  1187. void CAI_TrackPather::MoveToClosestTrackPoint( CPathTrack *pTrack )
  1188. {
  1189. if ( IsOnSameTrack( pTrack, m_pDestPathTarget ) )
  1190. return;
  1191. CPathTrack *pClosestTrack = BestPointOnPath( pTrack, WorldSpaceCenter(), 0.0f, false, false );
  1192. // The track must be valid
  1193. if ( CPathTrack::ValidPath( pClosestTrack ) == NULL )
  1194. return;
  1195. SetupNewCurrentTarget( pClosestTrack );
  1196. m_pDestPathTarget = pClosestTrack;
  1197. m_bMovingForward = true;
  1198. // Force us to switch tracks if we're leading
  1199. if ( IsLeading() )
  1200. {
  1201. m_bForcedMove = true;
  1202. }
  1203. }
  1204. //-----------------------------------------------------------------------------
  1205. // Are the two path tracks connected?
  1206. //-----------------------------------------------------------------------------
  1207. bool CAI_TrackPather::IsOnSameTrack( CPathTrack *pPath1, CPathTrack *pPath2 ) const
  1208. {
  1209. if ( pPath1 == pPath2 )
  1210. return true;
  1211. {
  1212. BEGIN_PATH_TRACK_ITERATION();
  1213. CPathTrack *pTravPath = pPath1->GetPrevious();
  1214. while( CPathTrack::ValidPath( pTravPath ) && (pTravPath != pPath1) )
  1215. {
  1216. // Circular loop checking
  1217. if ( pTravPath->HasBeenVisited() )
  1218. break;
  1219. pTravPath->Visit();
  1220. if ( pTravPath == pPath2 )
  1221. return true;
  1222. pTravPath = pTravPath->GetPrevious();
  1223. }
  1224. }
  1225. {
  1226. BEGIN_PATH_TRACK_ITERATION();
  1227. CPathTrack *pTravPath = pPath1->GetNext();
  1228. while( CPathTrack::ValidPath( pTravPath ) && (pTravPath != pPath1) )
  1229. {
  1230. // Circular loop checking
  1231. if ( pTravPath->HasBeenVisited() )
  1232. break;
  1233. pTravPath->Visit();
  1234. if ( pTravPath == pPath2 )
  1235. return true;
  1236. pTravPath = pTravPath->GetNext();
  1237. }
  1238. }
  1239. return false;
  1240. }
  1241. //-----------------------------------------------------------------------------
  1242. // Deal with teleportation
  1243. //-----------------------------------------------------------------------------
  1244. void CAI_TrackPather::Teleported()
  1245. {
  1246. // This updates the paths so they are reasonable
  1247. CPathTrack *pClosestTrack = BestPointOnPath( GetDestPathTarget(), WorldSpaceCenter(), 0.0f, false, false );
  1248. m_pDestPathTarget = NULL;
  1249. MoveToClosestTrackPoint( pClosestTrack );
  1250. }
  1251. //-----------------------------------------------------------------------------
  1252. // Returns distance along path to target, returns FLT_MAX if there's no path
  1253. //-----------------------------------------------------------------------------
  1254. float CAI_TrackPather::ComputePathDistance( CPathTrack *pPath, CPathTrack *pDest, bool bForward ) const
  1255. {
  1256. float flDist = 0.0f;
  1257. CPathTrack *pLast = pPath;
  1258. BEGIN_PATH_TRACK_ITERATION();
  1259. while ( CPathTrack::ValidPath( pPath ) )
  1260. {
  1261. // Ciruclar loop checking
  1262. if ( pPath->HasBeenVisited() )
  1263. return FLT_MAX;
  1264. pPath->Visit();
  1265. flDist += pLast->GetAbsOrigin().DistTo( pPath->GetAbsOrigin() );
  1266. if ( pDest == pPath )
  1267. return flDist;
  1268. pLast = pPath;
  1269. pPath = bForward ? pPath->GetNext() : pPath->GetPrevious();
  1270. }
  1271. return FLT_MAX;
  1272. }
  1273. //-----------------------------------------------------------------------------
  1274. // Is pPathTest in "front" of pPath on the same path? (Namely, does GetNext() get us there?)
  1275. //-----------------------------------------------------------------------------
  1276. bool CAI_TrackPather::IsForwardAlongPath( CPathTrack *pPath, CPathTrack *pPathTest ) const
  1277. {
  1278. // Also, in the case of looping paths, we want to return the shortest path
  1279. float flForwardDist = ComputePathDistance( pPath, pPathTest, true );
  1280. float flReverseDist = ComputePathDistance( pPath, pPathTest, false );
  1281. Assert( ( flForwardDist != FLT_MAX ) || ( flReverseDist != FLT_MAX ) );
  1282. return ( flForwardDist <= flReverseDist );
  1283. }
  1284. //-----------------------------------------------------------------------------
  1285. // Computes distance + nearest point from the current path..
  1286. //-----------------------------------------------------------------------------
  1287. float CAI_TrackPather::ClosestPointToCurrentPath( Vector *pVecPoint ) const
  1288. {
  1289. if (!m_pCurrentPathTarget)
  1290. {
  1291. *pVecPoint = GetAbsOrigin();
  1292. return 0;
  1293. }
  1294. float t;
  1295. CalcClosestPointOnLine( GetAbsOrigin(), m_vecSegmentStartPoint,
  1296. m_pCurrentPathTarget->GetAbsOrigin(), *pVecPoint, &t );
  1297. return t;
  1298. }
  1299. //-----------------------------------------------------------------------------
  1300. // Computes a "path" velocity at a particular point along the current path
  1301. //-----------------------------------------------------------------------------
  1302. void CAI_TrackPather::ComputePathTangent( float t, Vector *pVecTangent ) const
  1303. {
  1304. CPathTrack *pNextTrack = NextAlongCurrentPath(m_pCurrentPathTarget);
  1305. if ( !pNextTrack )
  1306. {
  1307. pNextTrack = m_pCurrentPathTarget;
  1308. }
  1309. t = clamp( t, 0.0f, 1.0f );
  1310. pVecTangent->Init(0,0,0);
  1311. Catmull_Rom_Spline_Tangent( m_vecSegmentStartSplinePoint, m_vecSegmentStartPoint,
  1312. m_pCurrentPathTarget->GetAbsOrigin(), pNextTrack->GetAbsOrigin(), t, *pVecTangent );
  1313. VectorNormalize( *pVecTangent );
  1314. }
  1315. //-----------------------------------------------------------------------------
  1316. // Computes the *normalized* velocity at which the helicopter should approach the final point
  1317. //-----------------------------------------------------------------------------
  1318. void CAI_TrackPather::ComputeNormalizedDestVelocity( Vector *pVecVelocity ) const
  1319. {
  1320. if ( m_nPauseState != PAUSE_NO_PAUSE )
  1321. {
  1322. pVecVelocity->Init(0,0,0);
  1323. return;
  1324. }
  1325. CPathTrack *pNextTrack = NextAlongCurrentPath(m_pCurrentPathTarget);
  1326. if ( !pNextTrack )
  1327. {
  1328. pNextTrack = m_pCurrentPathTarget;
  1329. }
  1330. if ( ( pNextTrack == m_pCurrentPathTarget ) || ( m_pCurrentPathTarget == m_pDestPathTarget ) )
  1331. {
  1332. pVecVelocity->Init(0,0,0);
  1333. return;
  1334. }
  1335. VectorSubtract( pNextTrack->GetAbsOrigin(), m_pCurrentPathTarget->GetAbsOrigin(), *pVecVelocity );
  1336. VectorNormalize( *pVecVelocity );
  1337. // Slow it down if we're approaching a sharp corner
  1338. Vector vecDelta;
  1339. VectorSubtract( m_pCurrentPathTarget->GetAbsOrigin(), m_vecSegmentStartPoint, vecDelta );
  1340. VectorNormalize( vecDelta );
  1341. float flDot = DotProduct( *pVecVelocity, vecDelta );
  1342. *pVecVelocity *= clamp( flDot, 0.0f, 1.0f );
  1343. }
  1344. //-----------------------------------------------------------------------------
  1345. // Purpose:
  1346. // Input : &inputdata -
  1347. //-----------------------------------------------------------------------------
  1348. void CAI_TrackPather::SetTrack( CBaseEntity *pGoalEnt )
  1349. {
  1350. // Ignore this input if we're *already* on that path.
  1351. CPathTrack *pTrack = dynamic_cast<CPathTrack *>(pGoalEnt);
  1352. if ( !pTrack )
  1353. {
  1354. DevWarning( "%s: Specified entity '%s' must be a path_track!\n", pGoalEnt->GetClassname(), pGoalEnt->GetEntityName().ToCStr() );
  1355. return;
  1356. }
  1357. MoveToClosestTrackPoint( pTrack );
  1358. }
  1359. void CAI_TrackPather::SetTrack( string_t strTrackName )
  1360. {
  1361. // Find our specified target
  1362. CBaseEntity *pGoalEnt = gEntList.FindEntityByName( NULL, strTrackName );
  1363. if ( pGoalEnt == NULL )
  1364. {
  1365. DevWarning( "%s: Could not find path_track '%s'!\n", GetClassname(), STRING( strTrackName ) );
  1366. return;
  1367. }
  1368. SetTrack( pGoalEnt );
  1369. }
  1370. //-----------------------------------------------------------------------------
  1371. // Purpose:
  1372. // Input : &inputdata -
  1373. //-----------------------------------------------------------------------------
  1374. void CAI_TrackPather::InputSetTrack( inputdata_t &inputdata )
  1375. {
  1376. string_t strTrackName = MAKE_STRING( inputdata.value.String() );
  1377. SetTrack( MAKE_STRING( inputdata.value.String() ) );
  1378. }
  1379. //-----------------------------------------------------------------------------
  1380. // Purpose:
  1381. // Input : strTrackName -
  1382. //-----------------------------------------------------------------------------
  1383. void CAI_TrackPather::FlyToPathTrack( string_t strTrackName )
  1384. {
  1385. CBaseEntity *pGoalEnt = gEntList.FindEntityByName( NULL, strTrackName );
  1386. if ( pGoalEnt == NULL )
  1387. {
  1388. DevWarning( "%s: Could not find path_track '%s'!\n", GetClassname(), STRING( strTrackName ) );
  1389. return;
  1390. }
  1391. // Ignore this input if we're *already* on that path.
  1392. CPathTrack *pTrack = dynamic_cast<CPathTrack *>(pGoalEnt);
  1393. if ( !pTrack )
  1394. {
  1395. DevWarning( "%s: Specified entity '%s' must be a path_track!\n", GetClassname(), STRING( strTrackName ) );
  1396. return;
  1397. }
  1398. // Find our specified target
  1399. MoveToTrackPoint( pTrack );
  1400. }
  1401. //-----------------------------------------------------------------------------
  1402. // Purpose:
  1403. // Input : &inputdata -
  1404. //-----------------------------------------------------------------------------
  1405. void CAI_TrackPather::InputFlyToPathTrack( inputdata_t &inputdata )
  1406. {
  1407. // Find our specified target
  1408. string_t strTrackName = MAKE_STRING( inputdata.value.String() );
  1409. m_nPauseState = PAUSE_NO_PAUSE;
  1410. FlyToPathTrack( strTrackName );
  1411. }
  1412. //-----------------------------------------------------------------------------
  1413. // Changes the mode used to determine which path point to move to
  1414. //-----------------------------------------------------------------------------
  1415. void CAI_TrackPather::InputChooseFarthestPathPoint( inputdata_t &inputdata )
  1416. {
  1417. UseFarthestPathPoint( true );
  1418. }
  1419. void CAI_TrackPather::InputChooseNearestPathPoint( inputdata_t &inputdata )
  1420. {
  1421. UseFarthestPathPoint( false );
  1422. }
  1423. void CAI_TrackPather::UseFarthestPathPoint( bool useFarthest )
  1424. {
  1425. m_bChooseFarthestPoint = useFarthest;
  1426. }