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.

561 lines
15 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Used to create a path that can be followed by NPCs and trains.
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "pathtrack.h"
  8. #include "entitylist.h"
  9. #include "ndebugoverlay.h"
  10. // memdbgon must be the last include file in a .cpp file!!!
  11. #include "tier0/memdbgon.h"
  12. //-----------------------------------------------------------------------------
  13. // Save/load
  14. //-----------------------------------------------------------------------------
  15. BEGIN_DATADESC( CPathTrack )
  16. DEFINE_FIELD( m_pnext, FIELD_CLASSPTR ),
  17. DEFINE_FIELD( m_pprevious, FIELD_CLASSPTR ),
  18. DEFINE_FIELD( m_paltpath, FIELD_CLASSPTR ),
  19. DEFINE_KEYFIELD( m_flRadius, FIELD_FLOAT, "radius" ),
  20. DEFINE_FIELD( m_length, FIELD_FLOAT ),
  21. DEFINE_KEYFIELD( m_altName, FIELD_STRING, "altpath" ),
  22. DEFINE_KEYFIELD( m_eOrientationType, FIELD_INTEGER, "orientationtype" ),
  23. // DEFINE_FIELD( m_nIterVal, FIELD_INTEGER ),
  24. DEFINE_INPUTFUNC( FIELD_VOID, "InPass", InputPass ),
  25. DEFINE_INPUTFUNC( FIELD_VOID, "EnableAlternatePath", InputEnableAlternatePath ),
  26. DEFINE_INPUTFUNC( FIELD_VOID, "DisableAlternatePath", InputDisableAlternatePath ),
  27. DEFINE_INPUTFUNC( FIELD_VOID, "ToggleAlternatePath", InputToggleAlternatePath ),
  28. DEFINE_INPUTFUNC( FIELD_VOID, "EnablePath", InputEnablePath ),
  29. DEFINE_INPUTFUNC( FIELD_VOID, "DisablePath", InputDisablePath ),
  30. DEFINE_INPUTFUNC( FIELD_VOID, "TogglePath", InputTogglePath ),
  31. // Outputs
  32. DEFINE_OUTPUT(m_OnPass, "OnPass"),
  33. END_DATADESC()
  34. LINK_ENTITY_TO_CLASS( path_track, CPathTrack );
  35. //-----------------------------------------------------------------------------
  36. // Finds circular paths
  37. //-----------------------------------------------------------------------------
  38. int CPathTrack::s_nCurrIterVal = 0;
  39. bool CPathTrack::s_bIsIterating = false;
  40. //-----------------------------------------------------------------------------
  41. // Constructor
  42. //-----------------------------------------------------------------------------
  43. CPathTrack::CPathTrack()
  44. {
  45. m_nIterVal = -1;
  46. m_eOrientationType = TrackOrientation_FacePath;
  47. }
  48. //-----------------------------------------------------------------------------
  49. // Spawn!
  50. //-----------------------------------------------------------------------------
  51. void CPathTrack::Spawn( void )
  52. {
  53. SetSolid( SOLID_NONE );
  54. UTIL_SetSize(this, Vector(-8, -8, -8), Vector(8, 8, 8));
  55. m_pnext = NULL;
  56. m_pprevious = NULL;
  57. }
  58. //-----------------------------------------------------------------------------
  59. // Activate!
  60. //-----------------------------------------------------------------------------
  61. void CPathTrack::Activate( void )
  62. {
  63. BaseClass::Activate();
  64. if ( GetEntityName() != NULL_STRING ) // Link to next, and back-link
  65. {
  66. Link();
  67. }
  68. }
  69. //-----------------------------------------------------------------------------
  70. // Connects up the previons + next pointers
  71. //-----------------------------------------------------------------------------
  72. void CPathTrack::Link( void )
  73. {
  74. CBaseEntity *pTarget;
  75. if ( m_target != NULL_STRING )
  76. {
  77. pTarget = gEntList.FindEntityByName( NULL, m_target );
  78. if ( pTarget == this)
  79. {
  80. Warning("ERROR: path_track (%s) refers to itself as a target!\n", GetDebugName());
  81. //FIXME: Why were we removing this? If it was already connected to, we weren't updating the other linked
  82. // end, causing problems with walking through bogus memory links! -- jdw
  83. //UTIL_Remove(this);
  84. //return;
  85. }
  86. else if ( pTarget )
  87. {
  88. m_pnext = dynamic_cast<CPathTrack*>( pTarget );
  89. if ( m_pnext ) // If no next pointer, this is the end of a path
  90. {
  91. m_pnext->SetPrevious( this );
  92. }
  93. }
  94. else
  95. {
  96. Warning("Dead end link: %s\n", STRING( m_target ) );
  97. }
  98. }
  99. // Find "alternate" path
  100. if ( m_altName != NULL_STRING )
  101. {
  102. pTarget = gEntList.FindEntityByName( NULL, m_altName );
  103. if ( pTarget )
  104. {
  105. m_paltpath = dynamic_cast<CPathTrack*>( pTarget );
  106. m_paltpath->SetPrevious( this );
  107. }
  108. }
  109. }
  110. //-----------------------------------------------------------------------------
  111. // Circular path checking
  112. //-----------------------------------------------------------------------------
  113. void CPathTrack::BeginIteration()
  114. {
  115. Assert( !s_bIsIterating );
  116. ++s_nCurrIterVal;
  117. s_bIsIterating = true;
  118. }
  119. void CPathTrack::EndIteration()
  120. {
  121. Assert( s_bIsIterating );
  122. s_bIsIterating = false;
  123. }
  124. void CPathTrack::Visit()
  125. {
  126. m_nIterVal = s_nCurrIterVal;
  127. }
  128. bool CPathTrack::HasBeenVisited() const
  129. {
  130. return ( m_nIterVal == s_nCurrIterVal );
  131. }
  132. //-----------------------------------------------------------------------------
  133. // Do we have an alternate path?
  134. //-----------------------------------------------------------------------------
  135. bool CPathTrack::HasAlternathPath() const
  136. {
  137. return ( m_paltpath != NULL );
  138. }
  139. //-----------------------------------------------------------------------------
  140. // Purpose: Toggles the track to or from its alternate path
  141. //-----------------------------------------------------------------------------
  142. void CPathTrack::ToggleAlternatePath( void )
  143. {
  144. // Use toggles between two paths
  145. if ( m_paltpath != NULL )
  146. {
  147. if ( FBitSet( m_spawnflags, SF_PATH_ALTERNATE ) == false )
  148. {
  149. EnableAlternatePath();
  150. }
  151. else
  152. {
  153. DisableAlternatePath();
  154. }
  155. }
  156. }
  157. //-----------------------------------------------------------------------------
  158. // Purpose:
  159. //-----------------------------------------------------------------------------
  160. void CPathTrack::EnableAlternatePath( void )
  161. {
  162. if ( m_paltpath != NULL )
  163. {
  164. SETBITS( m_spawnflags, SF_PATH_ALTERNATE );
  165. }
  166. }
  167. //-----------------------------------------------------------------------------
  168. // Purpose:
  169. //-----------------------------------------------------------------------------
  170. void CPathTrack::DisableAlternatePath( void )
  171. {
  172. if ( m_paltpath != NULL )
  173. {
  174. CLEARBITS( m_spawnflags, SF_PATH_ALTERNATE );
  175. }
  176. }
  177. //-----------------------------------------------------------------------------
  178. // Purpose:
  179. // Input : &inputdata -
  180. //-----------------------------------------------------------------------------
  181. void CPathTrack::InputEnableAlternatePath( inputdata_t &inputdata )
  182. {
  183. EnableAlternatePath();
  184. }
  185. //-----------------------------------------------------------------------------
  186. // Purpose:
  187. // Input : &inputdata -
  188. //-----------------------------------------------------------------------------
  189. void CPathTrack::InputDisableAlternatePath( inputdata_t &inputdata )
  190. {
  191. DisableAlternatePath();
  192. }
  193. //-----------------------------------------------------------------------------
  194. // Purpose:
  195. // Input : &inputdata -
  196. //-----------------------------------------------------------------------------
  197. void CPathTrack::InputToggleAlternatePath( inputdata_t &inputdata )
  198. {
  199. ToggleAlternatePath();
  200. }
  201. //-----------------------------------------------------------------------------
  202. // Purpose: Toggles the track to or from its alternate path
  203. //-----------------------------------------------------------------------------
  204. void CPathTrack::TogglePath( void )
  205. {
  206. // Use toggles between two paths
  207. if ( FBitSet( m_spawnflags, SF_PATH_DISABLED ) )
  208. {
  209. EnablePath();
  210. }
  211. else
  212. {
  213. DisablePath();
  214. }
  215. }
  216. //-----------------------------------------------------------------------------
  217. // Purpose:
  218. //-----------------------------------------------------------------------------
  219. void CPathTrack::EnablePath( void )
  220. {
  221. CLEARBITS( m_spawnflags, SF_PATH_DISABLED );
  222. }
  223. //-----------------------------------------------------------------------------
  224. // Purpose:
  225. //-----------------------------------------------------------------------------
  226. void CPathTrack::DisablePath( void )
  227. {
  228. SETBITS( m_spawnflags, SF_PATH_DISABLED );
  229. }
  230. //-----------------------------------------------------------------------------
  231. // Purpose:
  232. // Input : &inputdata -
  233. //-----------------------------------------------------------------------------
  234. void CPathTrack::InputEnablePath( inputdata_t &inputdata )
  235. {
  236. EnablePath();
  237. }
  238. //-----------------------------------------------------------------------------
  239. // Purpose:
  240. // Input : &inputdata -
  241. //-----------------------------------------------------------------------------
  242. void CPathTrack::InputDisablePath( inputdata_t &inputdata )
  243. {
  244. DisablePath();
  245. }
  246. //-----------------------------------------------------------------------------
  247. // Purpose:
  248. // Input : &inputdata -
  249. //-----------------------------------------------------------------------------
  250. void CPathTrack::InputTogglePath( inputdata_t &inputdata )
  251. {
  252. TogglePath();
  253. }
  254. void CPathTrack::DrawDebugGeometryOverlays()
  255. {
  256. // ----------------------------------------------
  257. // Draw line to next target is bbox is selected
  258. // ----------------------------------------------
  259. if (m_debugOverlays & (OVERLAY_BBOX_BIT|OVERLAY_ABSBOX_BIT))
  260. {
  261. if (m_pnext)
  262. {
  263. NDebugOverlay::Line(GetAbsOrigin(),m_pnext->GetAbsOrigin(),255,100,100,true,0.0);
  264. }
  265. }
  266. BaseClass::DrawDebugGeometryOverlays();
  267. }
  268. CPathTrack *CPathTrack::ValidPath( CPathTrack *ppath, int testFlag )
  269. {
  270. if ( !ppath )
  271. return NULL;
  272. if ( testFlag && FBitSet( ppath->m_spawnflags, SF_PATH_DISABLED ) )
  273. return NULL;
  274. return ppath;
  275. }
  276. void CPathTrack::Project( CPathTrack *pstart, CPathTrack *pend, Vector &origin, float dist )
  277. {
  278. if ( pstart && pend )
  279. {
  280. Vector dir = (pend->GetLocalOrigin() - pstart->GetLocalOrigin());
  281. VectorNormalize( dir );
  282. origin = pend->GetLocalOrigin() + dir * dist;
  283. }
  284. }
  285. CPathTrack *CPathTrack::GetNext( void )
  286. {
  287. if ( m_paltpath && FBitSet( m_spawnflags, SF_PATH_ALTERNATE ) && !FBitSet( m_spawnflags, SF_PATH_ALTREVERSE ) )
  288. return m_paltpath;
  289. return m_pnext;
  290. }
  291. CPathTrack *CPathTrack::GetPrevious( void )
  292. {
  293. if ( m_paltpath && FBitSet( m_spawnflags, SF_PATH_ALTERNATE ) && FBitSet( m_spawnflags, SF_PATH_ALTREVERSE ) )
  294. return m_paltpath;
  295. return m_pprevious;
  296. }
  297. void CPathTrack::SetPrevious( CPathTrack *pprev )
  298. {
  299. // Only set previous if this isn't my alternate path
  300. if ( pprev && !FStrEq( STRING(pprev->GetEntityName()), STRING(m_altName) ) )
  301. m_pprevious = pprev;
  302. }
  303. CPathTrack *CPathTrack::GetNextInDir( bool bForward )
  304. {
  305. if ( bForward )
  306. return GetNext();
  307. return GetPrevious();
  308. }
  309. //-----------------------------------------------------------------------------
  310. // Purpose: Assumes this is ALWAYS enabled
  311. // Input : origin - position along path to look ahead from
  312. // dist - distance to look ahead, negative values look backward
  313. // move -
  314. // Output : Returns the track that we will be PAST in 'dist' units.
  315. //-----------------------------------------------------------------------------
  316. CPathTrack *CPathTrack::LookAhead( Vector &origin, float dist, int move, CPathTrack **pNextNext )
  317. {
  318. CPathTrack *pcurrent = this;
  319. float originalDist = dist;
  320. Vector currentPos = origin;
  321. bool bForward = true;
  322. if ( dist < 0 )
  323. {
  324. // Travelling backwards along the path.
  325. dist = -dist;
  326. bForward = false;
  327. }
  328. // Move along the path, until we've gone 'dist' units or run out of path.
  329. while ( dist > 0 )
  330. {
  331. // If there is no next path track, or it's disabled, we're done.
  332. if ( !ValidPath( pcurrent->GetNextInDir( bForward ), move ) )
  333. {
  334. if ( !move )
  335. {
  336. Project( pcurrent->GetNextInDir( !bForward ), pcurrent, origin, dist );
  337. }
  338. return NULL;
  339. }
  340. // The next path track is valid. How far are we from it?
  341. Vector dir = pcurrent->GetNextInDir( bForward )->GetLocalOrigin() - currentPos;
  342. float length = dir.Length();
  343. // If we are at the next node and there isn't one beyond it, return the next node.
  344. if ( !length && !ValidPath( pcurrent->GetNextInDir( bForward )->GetNextInDir( bForward ), move ) )
  345. {
  346. if ( pNextNext )
  347. {
  348. *pNextNext = NULL;
  349. }
  350. if ( dist == originalDist )
  351. {
  352. // Didn't move at all, must be in a dead end.
  353. return NULL;
  354. }
  355. return pcurrent->GetNextInDir( bForward );
  356. }
  357. // If we don't hit the next path track within the distance remaining, we're done.
  358. if ( length > dist )
  359. {
  360. origin = currentPos + ( dir * ( dist / length ) );
  361. if ( pNextNext )
  362. {
  363. *pNextNext = pcurrent->GetNextInDir( bForward );
  364. }
  365. return pcurrent;
  366. }
  367. // We hit the next path track, advance to it.
  368. dist -= length;
  369. currentPos = pcurrent->GetNextInDir( bForward )->GetLocalOrigin();
  370. pcurrent = pcurrent->GetNextInDir( bForward );
  371. origin = currentPos;
  372. }
  373. // We consumed all of the distance, and exactly landed on a path track.
  374. if ( pNextNext )
  375. {
  376. *pNextNext = pcurrent->GetNextInDir( bForward );
  377. }
  378. return pcurrent;
  379. }
  380. // Assumes this is ALWAYS enabled
  381. CPathTrack *CPathTrack::Nearest( const Vector &origin )
  382. {
  383. int deadCount;
  384. float minDist, dist;
  385. Vector delta;
  386. CPathTrack *ppath, *pnearest;
  387. delta = origin - GetLocalOrigin();
  388. delta.z = 0;
  389. minDist = delta.Length();
  390. pnearest = this;
  391. ppath = GetNext();
  392. // Hey, I could use the old 2 racing pointers solution to this, but I'm lazy :)
  393. deadCount = 0;
  394. while ( ppath && ppath != this )
  395. {
  396. deadCount++;
  397. if ( deadCount > 9999 )
  398. {
  399. Warning( "Bad sequence of path_tracks from %s\n", GetDebugName() );
  400. Assert(0);
  401. return NULL;
  402. }
  403. delta = origin - ppath->GetLocalOrigin();
  404. delta.z = 0;
  405. dist = delta.Length();
  406. if ( dist < minDist )
  407. {
  408. minDist = dist;
  409. pnearest = ppath;
  410. }
  411. ppath = ppath->GetNext();
  412. }
  413. return pnearest;
  414. }
  415. //-----------------------------------------------------------------------------
  416. // Purpose: Returns how the path follower should orient itself when moving
  417. // through this path track.
  418. //-----------------------------------------------------------------------------
  419. TrackOrientationType_t CPathTrack::GetOrientationType()
  420. {
  421. return m_eOrientationType;
  422. }
  423. //-----------------------------------------------------------------------------
  424. // Purpose:
  425. //-----------------------------------------------------------------------------
  426. QAngle CPathTrack::GetOrientation( bool bForwardDir )
  427. {
  428. TrackOrientationType_t eOrient = GetOrientationType();
  429. if ( eOrient == TrackOrientation_FacePathAngles )
  430. {
  431. return GetLocalAngles();
  432. }
  433. CPathTrack *pPrev = this;
  434. CPathTrack *pNext = GetNextInDir( bForwardDir );
  435. if ( !pNext )
  436. { pPrev = GetNextInDir( !bForwardDir );
  437. pNext = this;
  438. }
  439. Vector vecDir = pNext->GetLocalOrigin() - pPrev->GetLocalOrigin();
  440. QAngle angDir;
  441. VectorAngles( vecDir, angDir );
  442. return angDir;
  443. }
  444. //-----------------------------------------------------------------------------
  445. // Purpose:
  446. // Input : *pent -
  447. // Output : CPathTrack
  448. //-----------------------------------------------------------------------------
  449. CPathTrack *CPathTrack::Instance( edict_t *pent )
  450. {
  451. CBaseEntity *pEntity = CBaseEntity::Instance( pent );
  452. if ( FClassnameIs( pEntity, "path_track" ) )
  453. return (CPathTrack *)pEntity;
  454. return NULL;
  455. }
  456. //-----------------------------------------------------------------------------
  457. // Purpose:
  458. //-----------------------------------------------------------------------------
  459. void CPathTrack::InputPass( inputdata_t &inputdata )
  460. {
  461. m_OnPass.FireOutput( inputdata.pActivator, this );
  462. }