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

1696 lines
53 KiB

  1. //========= Copyright 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. // NOTE: This version is bugged, but I didn't want to make the fix
  784. // here for fear of breaking a lot of maps late in the day.
  785. // So, only the chopper does the "right" thing.
  786. #ifdef HL2_EPISODIC
  787. // Episodic uses the fixed logic for all trackpathers
  788. if ( 1 )
  789. #else
  790. if ( ShouldUseFixedPatrolLogic() )
  791. #endif
  792. {
  793. CPathTrack *pOldDest = m_pDestPathTarget;
  794. // Only switch polarity of movement if we're at the *end* of the path
  795. // This is really useful for initial conditions of patrolling
  796. // NOTE: We've got to do some extra work for circular paths
  797. bool bIsCircular = false;
  798. {
  799. BEGIN_PATH_TRACK_ITERATION();
  800. CPathTrack *pTravPath = m_pDestPathTarget;
  801. while( CPathTrack::ValidPath( pTravPath ) )
  802. {
  803. // Circular loop checking
  804. if ( pTravPath->HasBeenVisited() )
  805. {
  806. bIsCircular = true;
  807. break;
  808. }
  809. pTravPath->Visit();
  810. pTravPath = NextAlongCurrentPath( pTravPath );
  811. }
  812. }
  813. if ( bIsCircular || (NextAlongCurrentPath( m_pDestPathTarget ) == NULL) )
  814. {
  815. m_bMovingForward = !m_bMovingForward;
  816. }
  817. BEGIN_PATH_TRACK_ITERATION();
  818. while ( true )
  819. {
  820. CPathTrack *pNextTrack = NextAlongCurrentPath( m_pDestPathTarget );
  821. if ( !pNextTrack || (pNextTrack == pOldDest) || pNextTrack->HasBeenVisited() )
  822. break;
  823. pNextTrack->Visit();
  824. m_pDestPathTarget = pNextTrack;
  825. }
  826. }
  827. else
  828. {
  829. CPathTrack *pOldDest = m_pDestPathTarget;
  830. // For patrolling, switch the polarity of movement
  831. m_bMovingForward = !m_bMovingForward;
  832. int loopCount = 0;
  833. while ( true )
  834. {
  835. CPathTrack *pNextTrack = NextAlongCurrentPath( m_pDestPathTarget );
  836. if ( !pNextTrack )
  837. break;
  838. if ( ++loopCount > 1024 )
  839. {
  840. DevMsg(1,"WARNING: Looping path for %s\n", GetDebugName() );
  841. break;
  842. }
  843. m_pDestPathTarget = pNextTrack;
  844. }
  845. if ( m_pDestPathTarget == pOldDest )
  846. {
  847. // This can occur if we move to the first point on the path
  848. SelectNewDestTarget();
  849. }
  850. }
  851. }
  852. //------------------------------------------------------------------------------
  853. // Moves to the track
  854. //------------------------------------------------------------------------------
  855. void CAI_TrackPather::UpdateCurrentTargetLeading()
  856. {
  857. bool bRestingAtDest = false;
  858. CPathTrack *pAdjustedDest;
  859. // Find the point along the line that we're closest to.
  860. const Vector &vecTarget = m_pCurrentPathTarget->GetAbsOrigin();
  861. Vector vecPoint;
  862. float t = ClosestPointToCurrentPath( &vecPoint );
  863. if ( (t < 1.0f) && ( vecPoint.DistToSqr( vecTarget ) > m_flTargetTolerance * m_flTargetTolerance ) )
  864. goto visualizeDebugInfo;
  865. // Trip our "path_track reached" output
  866. if ( m_pCurrentPathTarget != m_pLastPathTarget )
  867. {
  868. // Get the path's specified max speed
  869. m_flPathMaxSpeed = m_pCurrentPathTarget->m_flSpeed;
  870. variant_t emptyVariant;
  871. m_pCurrentPathTarget->AcceptInput( "InPass", this, this, emptyVariant, 0 );
  872. m_pLastPathTarget = m_pCurrentPathTarget;
  873. }
  874. // NOTE: CurrentPathTarget doesn't mean the same thing as dest path target!
  875. // It's the "next"most when moving forward + "prev"most when moving backward
  876. // Must do the tests in the same space
  877. pAdjustedDest = AdjustForMovementDirection( m_pDestPathTarget );
  878. // Update our dest path target, if appropriate...
  879. if ( m_pCurrentPathTarget == pAdjustedDest )
  880. {
  881. m_bForcedMove = false;
  882. SelectNewDestTarget();
  883. // NOTE: Must do this again since SelectNewDestTarget may change m_pDestPathTarget
  884. pAdjustedDest = AdjustForMovementDirection( m_pDestPathTarget );
  885. }
  886. if ( m_pCurrentPathTarget != pAdjustedDest )
  887. {
  888. // Update to the next path, if there is one...
  889. m_pCurrentPathTarget = NextAlongCurrentPath( m_pCurrentPathTarget );
  890. if ( !m_pCurrentPathTarget )
  891. {
  892. m_pCurrentPathTarget = m_pLastPathTarget;
  893. }
  894. }
  895. else
  896. {
  897. // NOTE: Have to do this here because the NextAlongCurrentPath call above
  898. // could make m_pCurrentPathTarget == m_pDestPathTarget.
  899. // In this case, we're at rest (no patrolling behavior)
  900. bRestingAtDest = true;
  901. }
  902. if ( bRestingAtDest )
  903. {
  904. // NOTE: Must use current path target, instead of dest
  905. // to get the PreviousAlongCurrentPath working correctly
  906. CPathTrack *pSegmentStart = PreviousAlongCurrentPath( m_pCurrentPathTarget );
  907. if ( !pSegmentStart )
  908. {
  909. pSegmentStart = m_pCurrentPathTarget;
  910. }
  911. m_vecSegmentStartPoint = pSegmentStart->GetAbsOrigin();
  912. }
  913. else
  914. {
  915. m_vecSegmentStartPoint = m_pLastPathTarget->GetAbsOrigin();
  916. }
  917. visualizeDebugInfo:
  918. VisualizeDebugInfo( vecPoint, vecTarget );
  919. }
  920. //-----------------------------------------------------------------------------
  921. // Purpose:
  922. //-----------------------------------------------------------------------------
  923. void CAI_TrackPather::UpdateTargetPositionLeading( void )
  924. {
  925. Vector targetPos;
  926. if ( !GetTrackPatherTarget( &targetPos ) )
  927. return;
  928. // NOTE: FindClosestPointOnPath *always* returns the point on the "far",
  929. // end of the line segment containing the closest point (namely the 'next'
  930. // track, as opposed to the 'prev' track)
  931. Vector vecClosestPoint, vecPathDir;
  932. float flTargetDistanceFromPath;
  933. CPathTrack *pNextPath = FindClosestPointOnPath( m_pCurrentPathTarget,
  934. targetPos, &vecClosestPoint, &vecPathDir, &flTargetDistanceFromPath );
  935. // This means that a valid path could not be found to our target!
  936. if ( CPathTrack::ValidPath( pNextPath ) == NULL )
  937. return;
  938. // NDebugOverlay::Cross3D( vecClosestPoint, -Vector(24,24,24), Vector(24,24,24), 0, 255, 255, true, 0.1f );
  939. // NDebugOverlay::Cross3D( pNextPath->GetAbsOrigin(), -Vector(24,24,24), Vector(24,24,24), 255, 255, 0, true, 0.1f );
  940. // Here's how far we are from the path
  941. m_flTargetDistFromPath = flTargetDistanceFromPath;
  942. m_vecTargetPathDir = vecPathDir;
  943. // Here's info about where the target is along the path
  944. m_vecTargetPathPoint = vecClosestPoint;
  945. m_pTargetNearestPath = pNextPath;
  946. // Find the best position to be on our path
  947. // NOTE: This will *also* return a path track on the "far" end of the line segment
  948. // containing the leading position, namely the "next" end of the segment as opposed
  949. // to the "prev" end of the segment.
  950. CPathTrack *pDest = ComputeLeadingPointAlongPath( vecClosestPoint, pNextPath, m_flLeadDistance, &targetPos );
  951. SetDesiredPosition( targetPos );
  952. // We only want to switch movement directions when absolutely necessary
  953. // so convert dest into a more appropriate value based on the current movement direction
  954. if ( pDest != m_pDestPathTarget )
  955. {
  956. // NOTE: This is really tricky + subtle
  957. // For leading, we don't want to ever change direction when the current target == the
  958. // adjusted destination target. Namely, if we're going forward, both dest + curr
  959. // mean the "next"most node so we can compare them directly against eath other.
  960. // If we're moving backward, dest means "next"most, but curr means "prev"most.
  961. // We first have to adjust the dest to mean "prev"most, and then do the comparison.
  962. // If the adjusted dest == curr, then maintain direction. Otherwise, use the forward along path test.
  963. bool bMovingForward = m_bMovingForward;
  964. CPathTrack *pAdjustedDest = AdjustForMovementDirection( pDest );
  965. if ( m_pCurrentPathTarget != pAdjustedDest )
  966. {
  967. bMovingForward = IsForwardAlongPath( m_pCurrentPathTarget, pAdjustedDest );
  968. }
  969. if ( bMovingForward != m_bMovingForward )
  970. {
  971. // As a result of the tricky note above, this should never occur
  972. Assert( pAdjustedDest != m_pCurrentPathTarget );
  973. // Oops! Need to reverse direction
  974. m_bMovingForward = bMovingForward;
  975. m_vecSegmentStartPoint = m_pCurrentPathTarget->GetAbsOrigin();
  976. m_pCurrentPathTarget = NextAlongCurrentPath( m_pCurrentPathTarget );
  977. }
  978. m_pDestPathTarget = pDest;
  979. }
  980. // NDebugOverlay::Cross3D( m_pCurrentPathTarget->GetAbsOrigin(), -Vector(36,36,36), Vector(36,36,36), 255, 0, 0, true, 0.1f );
  981. // NDebugOverlay::Cross3D( m_pDestPathTarget->GetAbsOrigin(), -Vector(48,48,48), Vector(48,48,48), 0, 255, 0, true, 0.1f );
  982. // NDebugOverlay::Cross3D( targetPos, -Vector(36,36,36), Vector(36,36,36), 0, 0, 255, true, 0.1f );
  983. }
  984. //-----------------------------------------------------------------------------
  985. // Purpose:
  986. //-----------------------------------------------------------------------------
  987. void CAI_TrackPather::UpdateTargetPosition( void )
  988. {
  989. // Don't update our target if we're being told to go somewhere
  990. if ( m_bForcedMove && !m_bPatrolBreakable )
  991. return;
  992. // Don't update our target if we're patrolling
  993. if ( m_bPatrolling )
  994. {
  995. // If we have an enemy, and our patrol is breakable, stop patrolling
  996. if ( !m_bPatrolBreakable || !GetEnemy() )
  997. return;
  998. m_bPatrolling = false;
  999. }
  1000. Vector targetPos;
  1001. if ( !GetTrackPatherTarget( &targetPos ) )
  1002. return;
  1003. // Not time to update again
  1004. if ( m_flEnemyPathUpdateTime > gpGlobals->curtime )
  1005. return;
  1006. // See if the target has moved enough to make us recheck
  1007. float flDistSqr = ( targetPos - m_vecLastGoalCheckPosition ).LengthSqr();
  1008. if ( flDistSqr < m_flTargetDistanceThreshold * m_flTargetDistanceThreshold )
  1009. return;
  1010. // Find the best position to be on our path
  1011. CPathTrack *pDest = BestPointOnPath( m_pCurrentPathTarget, targetPos, m_flAvoidDistance, true, m_bChooseFarthestPoint );
  1012. if ( CPathTrack::ValidPath( pDest ) == NULL )
  1013. {
  1014. // This means that a valid path could not be found to our target!
  1015. // Assert(0);
  1016. return;
  1017. }
  1018. if ( pDest != m_pDestPathTarget )
  1019. {
  1020. // This is our new destination
  1021. bool bMovingForward = IsForwardAlongPath( m_pCurrentPathTarget, pDest );
  1022. if ( bMovingForward != m_bMovingForward )
  1023. {
  1024. // Oops! Need to reverse direction
  1025. m_bMovingForward = bMovingForward;
  1026. if ( pDest != m_pCurrentPathTarget )
  1027. {
  1028. SetupNewCurrentTarget( NextAlongCurrentPath( m_pCurrentPathTarget ) );
  1029. }
  1030. }
  1031. m_pDestPathTarget = pDest;
  1032. }
  1033. // Keep this goal point for comparisons later
  1034. m_vecLastGoalCheckPosition = targetPos;
  1035. // Only do this on set intervals
  1036. m_flEnemyPathUpdateTime = gpGlobals->curtime + 1.0f;
  1037. }
  1038. //------------------------------------------------------------------------------
  1039. // Returns the direction of the path at the closest point to the target
  1040. //------------------------------------------------------------------------------
  1041. const Vector &CAI_TrackPather::TargetPathDirection() const
  1042. {
  1043. return m_vecTargetPathDir;
  1044. }
  1045. const Vector &CAI_TrackPather::TargetPathAcrossDirection() const
  1046. {
  1047. static Vector s_Result;
  1048. CrossProduct( m_vecTargetPathDir, Vector( 0, 0, 1 ), s_Result );
  1049. return s_Result;
  1050. }
  1051. //------------------------------------------------------------------------------
  1052. // Returns the speed of the target relative to the path
  1053. //------------------------------------------------------------------------------
  1054. float CAI_TrackPather::TargetSpeedAlongPath() const
  1055. {
  1056. if ( !GetEnemy() || !IsLeading() )
  1057. return 0.0f;
  1058. Vector vecSmoothedVelocity = GetEnemy()->GetSmoothedVelocity();
  1059. return DotProduct( vecSmoothedVelocity, TargetPathDirection() );
  1060. }
  1061. //------------------------------------------------------------------------------
  1062. // Returns the speed of the target *across* the path
  1063. //------------------------------------------------------------------------------
  1064. float CAI_TrackPather::TargetSpeedAcrossPath() const
  1065. {
  1066. if ( !GetEnemy() || !IsLeading() )
  1067. return 0.0f;
  1068. Vector vecSmoothedVelocity = GetEnemy()->GetSmoothedVelocity();
  1069. return DotProduct( vecSmoothedVelocity, TargetPathAcrossDirection() );
  1070. }
  1071. //------------------------------------------------------------------------------
  1072. // Returns the max distance we can be from the path
  1073. //------------------------------------------------------------------------------
  1074. float CAI_TrackPather::MaxDistanceFromCurrentPath() const
  1075. {
  1076. if ( !IsLeading() || !m_pCurrentPathTarget )
  1077. return 0.0f;
  1078. CPathTrack *pPrevPath = PreviousAlongCurrentPath( m_pCurrentPathTarget );
  1079. if ( !pPrevPath )
  1080. {
  1081. pPrevPath = m_pCurrentPathTarget;
  1082. }
  1083. // NOTE: Can't use m_vecSegmentStartPoint because we don't have a radius defined for it
  1084. float t;
  1085. Vector vecTemp;
  1086. CalcClosestPointOnLine( GetAbsOrigin(), pPrevPath->GetAbsOrigin(),
  1087. m_pCurrentPathTarget->GetAbsOrigin(), vecTemp, &t );
  1088. t = clamp( t, 0.0f, 1.0f );
  1089. float flRadius = (1.0f - t) * pPrevPath->GetRadius() + t * m_pCurrentPathTarget->GetRadius();
  1090. return flRadius;
  1091. }
  1092. //------------------------------------------------------------------------------
  1093. // Purpose : A different version of the track pather which is more explicit about
  1094. // the meaning of dest, current, and prev path points
  1095. //------------------------------------------------------------------------------
  1096. void CAI_TrackPather::UpdateTrackNavigation( void )
  1097. {
  1098. // No target? Use the string specified. We have no spawn method (sucky!!) so this is how that works
  1099. if ( ( CPathTrack::ValidPath( m_pDestPathTarget ) == NULL ) && ( m_target != NULL_STRING ) )
  1100. {
  1101. FlyToPathTrack( m_target );
  1102. m_target = NULL_STRING;
  1103. }
  1104. if ( !IsLeading() )
  1105. {
  1106. if ( !m_pCurrentPathTarget )
  1107. return;
  1108. // Updates our destination node if we're tracking something
  1109. UpdateTargetPosition();
  1110. // Move along our path towards our current destination
  1111. UpdateCurrentTarget();
  1112. }
  1113. else
  1114. {
  1115. // Updates our destination position if we're leading something
  1116. UpdateTargetPositionLeading();
  1117. // Move along our path towards our current destination
  1118. UpdateCurrentTargetLeading();
  1119. }
  1120. }
  1121. //------------------------------------------------------------------------------
  1122. // Sets the farthest path distance
  1123. //------------------------------------------------------------------------------
  1124. void CAI_TrackPather::SetFarthestPathDist( float flMaxPathDist )
  1125. {
  1126. m_flFarthestPathDist = flMaxPathDist;
  1127. }
  1128. //------------------------------------------------------------------------------
  1129. // Sets up a new current path target
  1130. //------------------------------------------------------------------------------
  1131. void CAI_TrackPather::SetupNewCurrentTarget( CPathTrack *pTrack )
  1132. {
  1133. Assert( pTrack );
  1134. m_vecSegmentStartPoint = GetAbsOrigin();
  1135. VectorMA( m_vecSegmentStartPoint, -2.0f, GetAbsVelocity(), m_vecSegmentStartSplinePoint );
  1136. m_pCurrentPathTarget = pTrack;
  1137. SetDesiredPosition( m_pCurrentPathTarget->GetAbsOrigin() );
  1138. }
  1139. //------------------------------------------------------------------------------
  1140. // Moves to an explicit track point
  1141. //------------------------------------------------------------------------------
  1142. void CAI_TrackPather::MoveToTrackPoint( CPathTrack *pTrack )
  1143. {
  1144. if ( IsOnSameTrack( pTrack, m_pDestPathTarget ) )
  1145. {
  1146. // The track must be valid
  1147. if ( CPathTrack::ValidPath( pTrack ) == NULL )
  1148. return;
  1149. m_pDestPathTarget = pTrack;
  1150. m_bMovingForward = IsForwardAlongPath( m_pCurrentPathTarget, pTrack );
  1151. m_bForcedMove = true;
  1152. }
  1153. else
  1154. {
  1155. CPathTrack *pClosestTrack = BestPointOnPath( pTrack, WorldSpaceCenter(), 0.0f, false, false );
  1156. // The track must be valid
  1157. if ( CPathTrack::ValidPath( pClosestTrack ) == NULL )
  1158. return;
  1159. SetupNewCurrentTarget( pClosestTrack );
  1160. m_pDestPathTarget = pTrack;
  1161. m_bMovingForward = IsForwardAlongPath( pClosestTrack, pTrack );
  1162. m_bForcedMove = true;
  1163. }
  1164. }
  1165. //------------------------------------------------------------------------------
  1166. // Moves to the closest track point
  1167. //------------------------------------------------------------------------------
  1168. void CAI_TrackPather::MoveToClosestTrackPoint( CPathTrack *pTrack )
  1169. {
  1170. if ( IsOnSameTrack( pTrack, m_pDestPathTarget ) )
  1171. return;
  1172. CPathTrack *pClosestTrack = BestPointOnPath( pTrack, WorldSpaceCenter(), 0.0f, false, false );
  1173. // The track must be valid
  1174. if ( CPathTrack::ValidPath( pClosestTrack ) == NULL )
  1175. return;
  1176. SetupNewCurrentTarget( pClosestTrack );
  1177. m_pDestPathTarget = pClosestTrack;
  1178. m_bMovingForward = true;
  1179. // Force us to switch tracks if we're leading
  1180. if ( IsLeading() )
  1181. {
  1182. m_bForcedMove = true;
  1183. }
  1184. }
  1185. //-----------------------------------------------------------------------------
  1186. // Are the two path tracks connected?
  1187. //-----------------------------------------------------------------------------
  1188. bool CAI_TrackPather::IsOnSameTrack( CPathTrack *pPath1, CPathTrack *pPath2 ) const
  1189. {
  1190. if ( pPath1 == pPath2 )
  1191. return true;
  1192. {
  1193. BEGIN_PATH_TRACK_ITERATION();
  1194. CPathTrack *pTravPath = pPath1->GetPrevious();
  1195. while( CPathTrack::ValidPath( pTravPath ) && (pTravPath != pPath1) )
  1196. {
  1197. // Circular loop checking
  1198. if ( pTravPath->HasBeenVisited() )
  1199. break;
  1200. pTravPath->Visit();
  1201. if ( pTravPath == pPath2 )
  1202. return true;
  1203. pTravPath = pTravPath->GetPrevious();
  1204. }
  1205. }
  1206. {
  1207. BEGIN_PATH_TRACK_ITERATION();
  1208. CPathTrack *pTravPath = pPath1->GetNext();
  1209. while( CPathTrack::ValidPath( pTravPath ) && (pTravPath != pPath1) )
  1210. {
  1211. // Circular loop checking
  1212. if ( pTravPath->HasBeenVisited() )
  1213. break;
  1214. pTravPath->Visit();
  1215. if ( pTravPath == pPath2 )
  1216. return true;
  1217. pTravPath = pTravPath->GetNext();
  1218. }
  1219. }
  1220. return false;
  1221. }
  1222. //-----------------------------------------------------------------------------
  1223. // Deal with teleportation
  1224. //-----------------------------------------------------------------------------
  1225. void CAI_TrackPather::Teleported()
  1226. {
  1227. // This updates the paths so they are reasonable
  1228. CPathTrack *pClosestTrack = BestPointOnPath( GetDestPathTarget(), WorldSpaceCenter(), 0.0f, false, false );
  1229. m_pDestPathTarget = NULL;
  1230. MoveToClosestTrackPoint( pClosestTrack );
  1231. }
  1232. //-----------------------------------------------------------------------------
  1233. // Returns distance along path to target, returns FLT_MAX if there's no path
  1234. //-----------------------------------------------------------------------------
  1235. float CAI_TrackPather::ComputePathDistance( CPathTrack *pPath, CPathTrack *pDest, bool bForward ) const
  1236. {
  1237. float flDist = 0.0f;
  1238. CPathTrack *pLast = pPath;
  1239. BEGIN_PATH_TRACK_ITERATION();
  1240. while ( CPathTrack::ValidPath( pPath ) )
  1241. {
  1242. // Ciruclar loop checking
  1243. if ( pPath->HasBeenVisited() )
  1244. return FLT_MAX;
  1245. pPath->Visit();
  1246. flDist += pLast->GetAbsOrigin().DistTo( pPath->GetAbsOrigin() );
  1247. if ( pDest == pPath )
  1248. return flDist;
  1249. pLast = pPath;
  1250. pPath = bForward ? pPath->GetNext() : pPath->GetPrevious();
  1251. }
  1252. return FLT_MAX;
  1253. }
  1254. //-----------------------------------------------------------------------------
  1255. // Is pPathTest in "front" of pPath on the same path? (Namely, does GetNext() get us there?)
  1256. //-----------------------------------------------------------------------------
  1257. bool CAI_TrackPather::IsForwardAlongPath( CPathTrack *pPath, CPathTrack *pPathTest ) const
  1258. {
  1259. // Also, in the case of looping paths, we want to return the shortest path
  1260. float flForwardDist = ComputePathDistance( pPath, pPathTest, true );
  1261. float flReverseDist = ComputePathDistance( pPath, pPathTest, false );
  1262. Assert( ( flForwardDist != FLT_MAX ) || ( flReverseDist != FLT_MAX ) );
  1263. return ( flForwardDist <= flReverseDist );
  1264. }
  1265. //-----------------------------------------------------------------------------
  1266. // Computes distance + nearest point from the current path..
  1267. //-----------------------------------------------------------------------------
  1268. float CAI_TrackPather::ClosestPointToCurrentPath( Vector *pVecPoint ) const
  1269. {
  1270. if (!m_pCurrentPathTarget)
  1271. {
  1272. *pVecPoint = GetAbsOrigin();
  1273. return 0;
  1274. }
  1275. float t;
  1276. CalcClosestPointOnLine( GetAbsOrigin(), m_vecSegmentStartPoint,
  1277. m_pCurrentPathTarget->GetAbsOrigin(), *pVecPoint, &t );
  1278. return t;
  1279. }
  1280. //-----------------------------------------------------------------------------
  1281. // Computes a "path" velocity at a particular point along the current path
  1282. //-----------------------------------------------------------------------------
  1283. void CAI_TrackPather::ComputePathTangent( float t, Vector *pVecTangent ) const
  1284. {
  1285. CPathTrack *pNextTrack = NextAlongCurrentPath(m_pCurrentPathTarget);
  1286. if ( !pNextTrack )
  1287. {
  1288. pNextTrack = m_pCurrentPathTarget;
  1289. }
  1290. t = clamp( t, 0.0f, 1.0f );
  1291. pVecTangent->Init(0,0,0);
  1292. Catmull_Rom_Spline_Tangent( m_vecSegmentStartSplinePoint, m_vecSegmentStartPoint,
  1293. m_pCurrentPathTarget->GetAbsOrigin(), pNextTrack->GetAbsOrigin(), t, *pVecTangent );
  1294. VectorNormalize( *pVecTangent );
  1295. }
  1296. //-----------------------------------------------------------------------------
  1297. // Computes the *normalized* velocity at which the helicopter should approach the final point
  1298. //-----------------------------------------------------------------------------
  1299. void CAI_TrackPather::ComputeNormalizedDestVelocity( Vector *pVecVelocity ) const
  1300. {
  1301. if ( m_nPauseState != PAUSE_NO_PAUSE )
  1302. {
  1303. pVecVelocity->Init(0,0,0);
  1304. return;
  1305. }
  1306. CPathTrack *pNextTrack = NextAlongCurrentPath(m_pCurrentPathTarget);
  1307. if ( !pNextTrack )
  1308. {
  1309. pNextTrack = m_pCurrentPathTarget;
  1310. }
  1311. if ( ( pNextTrack == m_pCurrentPathTarget ) || ( m_pCurrentPathTarget == m_pDestPathTarget ) )
  1312. {
  1313. pVecVelocity->Init(0,0,0);
  1314. return;
  1315. }
  1316. VectorSubtract( pNextTrack->GetAbsOrigin(), m_pCurrentPathTarget->GetAbsOrigin(), *pVecVelocity );
  1317. VectorNormalize( *pVecVelocity );
  1318. // Slow it down if we're approaching a sharp corner
  1319. Vector vecDelta;
  1320. VectorSubtract( m_pCurrentPathTarget->GetAbsOrigin(), m_vecSegmentStartPoint, vecDelta );
  1321. VectorNormalize( vecDelta );
  1322. float flDot = DotProduct( *pVecVelocity, vecDelta );
  1323. *pVecVelocity *= clamp( flDot, 0.0f, 1.0f );
  1324. }
  1325. //-----------------------------------------------------------------------------
  1326. // Purpose:
  1327. // Input : &inputdata -
  1328. //-----------------------------------------------------------------------------
  1329. void CAI_TrackPather::SetTrack( CBaseEntity *pGoalEnt )
  1330. {
  1331. // Ignore this input if we're *already* on that path.
  1332. CPathTrack *pTrack = dynamic_cast<CPathTrack *>(pGoalEnt);
  1333. if ( !pTrack )
  1334. {
  1335. DevWarning( "%s: Specified entity '%s' must be a path_track!\n", pGoalEnt->GetClassname(), pGoalEnt->GetEntityName().ToCStr() );
  1336. return;
  1337. }
  1338. MoveToClosestTrackPoint( pTrack );
  1339. }
  1340. void CAI_TrackPather::SetTrack( string_t strTrackName )
  1341. {
  1342. // Find our specified target
  1343. CBaseEntity *pGoalEnt = gEntList.FindEntityByName( NULL, strTrackName );
  1344. if ( pGoalEnt == NULL )
  1345. {
  1346. DevWarning( "%s: Could not find path_track '%s'!\n", GetClassname(), STRING( strTrackName ) );
  1347. return;
  1348. }
  1349. SetTrack( pGoalEnt );
  1350. }
  1351. //-----------------------------------------------------------------------------
  1352. // Purpose:
  1353. // Input : &inputdata -
  1354. //-----------------------------------------------------------------------------
  1355. void CAI_TrackPather::InputSetTrack( inputdata_t &inputdata )
  1356. {
  1357. string_t strTrackName = MAKE_STRING( inputdata.value.String() );
  1358. SetTrack( MAKE_STRING( inputdata.value.String() ) );
  1359. }
  1360. //-----------------------------------------------------------------------------
  1361. // Purpose:
  1362. // Input : strTrackName -
  1363. //-----------------------------------------------------------------------------
  1364. void CAI_TrackPather::FlyToPathTrack( string_t strTrackName )
  1365. {
  1366. CBaseEntity *pGoalEnt = gEntList.FindEntityByName( NULL, strTrackName );
  1367. if ( pGoalEnt == NULL )
  1368. {
  1369. DevWarning( "%s: Could not find path_track '%s'!\n", GetClassname(), STRING( strTrackName ) );
  1370. return;
  1371. }
  1372. // Ignore this input if we're *already* on that path.
  1373. CPathTrack *pTrack = dynamic_cast<CPathTrack *>(pGoalEnt);
  1374. if ( !pTrack )
  1375. {
  1376. DevWarning( "%s: Specified entity '%s' must be a path_track!\n", GetClassname(), STRING( strTrackName ) );
  1377. return;
  1378. }
  1379. // Find our specified target
  1380. MoveToTrackPoint( pTrack );
  1381. }
  1382. //-----------------------------------------------------------------------------
  1383. // Purpose:
  1384. // Input : &inputdata -
  1385. //-----------------------------------------------------------------------------
  1386. void CAI_TrackPather::InputFlyToPathTrack( inputdata_t &inputdata )
  1387. {
  1388. // Find our specified target
  1389. string_t strTrackName = MAKE_STRING( inputdata.value.String() );
  1390. m_nPauseState = PAUSE_NO_PAUSE;
  1391. FlyToPathTrack( strTrackName );
  1392. }
  1393. //-----------------------------------------------------------------------------
  1394. // Changes the mode used to determine which path point to move to
  1395. //-----------------------------------------------------------------------------
  1396. void CAI_TrackPather::InputChooseFarthestPathPoint( inputdata_t &inputdata )
  1397. {
  1398. UseFarthestPathPoint( true );
  1399. }
  1400. void CAI_TrackPather::InputChooseNearestPathPoint( inputdata_t &inputdata )
  1401. {
  1402. UseFarthestPathPoint( false );
  1403. }
  1404. void CAI_TrackPather::UseFarthestPathPoint( bool useFarthest )
  1405. {
  1406. m_bChooseFarthestPoint = useFarthest;
  1407. }