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.

753 lines
21 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: A link that can be turned on and off. Unlike normal links
  4. // dyanimc links must be entities so they can receive messages.
  5. // They update the state of the actual links. Allows us to save
  6. // a lot of memory by not making all links into entities
  7. //
  8. // $NoKeywords: $
  9. //=============================================================================//
  10. #include "cbase.h"
  11. #include "collisionutils.h"
  12. #include "ai_dynamiclink.h"
  13. #include "ai_node.h"
  14. #include "ai_link.h"
  15. #include "ai_network.h"
  16. #include "ai_networkmanager.h"
  17. #include "saverestore_utlvector.h"
  18. #include "editor_sendcommand.h"
  19. #include "bitstring.h"
  20. #include "tier0/vprof.h"
  21. // memdbgon must be the last include file in a .cpp file!!!
  22. #include "tier0/memdbgon.h"
  23. //-----------------------------------------------------------------------------
  24. LINK_ENTITY_TO_CLASS(info_node_link_controller, CAI_DynamicLinkController);
  25. BEGIN_DATADESC( CAI_DynamicLinkController )
  26. DEFINE_KEYFIELD( m_nLinkState, FIELD_INTEGER, "initialstate" ),
  27. DEFINE_KEYFIELD( m_strAllowUse, FIELD_STRING, "AllowUse" ),
  28. DEFINE_KEYFIELD( m_bInvertAllow, FIELD_BOOLEAN, "InvertAllow" ),
  29. DEFINE_KEYFIELD( m_nPriority, FIELD_INTEGER, "Priority" ),
  30. DEFINE_KEYFIELD( m_bUseAirLinkRadius, FIELD_BOOLEAN, "useairlinkradius" ),
  31. // m_ControlledLinks (rebuilt)
  32. DEFINE_INPUTFUNC( FIELD_VOID, "TurnOn", InputTurnOn ),
  33. DEFINE_INPUTFUNC( FIELD_VOID, "TurnOff", InputTurnOff ),
  34. DEFINE_INPUTFUNC( FIELD_STRING, "SetAllowed", InputSetAllowed ),
  35. DEFINE_INPUTFUNC( FIELD_BOOLEAN, "SetInvert", InputSetInvert ),
  36. END_DATADESC()
  37. void CAI_DynamicLinkController::GenerateLinksFromVolume()
  38. {
  39. Assert( m_ControlledLinks.Count() == 0 );
  40. int nNodes = g_pBigAINet->NumNodes();
  41. CAI_Node **ppNodes = g_pBigAINet->AccessNodes();
  42. float MinDistCareSq = 0;
  43. if (m_bUseAirLinkRadius)
  44. {
  45. MinDistCareSq = Square(MAX_AIR_NODE_LINK_DIST + 0.1);
  46. }
  47. else
  48. {
  49. MinDistCareSq = Square(MAX_NODE_LINK_DIST + 0.1);
  50. }
  51. const Vector &origin = WorldSpaceCenter();
  52. Vector vAbsMins, vAbsMaxs;
  53. CollisionProp()->WorldSpaceAABB( &vAbsMins, &vAbsMaxs );
  54. vAbsMins -= Vector( 1, 1, 1 );
  55. vAbsMaxs += Vector( 1, 1, 1 );
  56. for ( int i = 0; i < nNodes; i++ )
  57. {
  58. CAI_Node *pNode = ppNodes[i];
  59. const Vector &nodeOrigin = pNode->GetOrigin();
  60. if ( origin.DistToSqr(nodeOrigin) >= MinDistCareSq )
  61. continue;
  62. int nLinks = pNode->NumLinks();
  63. for ( int j = 0; j < nLinks; j++ )
  64. {
  65. CAI_Link *pLink = pNode->GetLinkByIndex( j );
  66. int iLinkDest = pLink->DestNodeID( i );
  67. if ( iLinkDest <= i )
  68. continue;
  69. const Vector &originOther = ppNodes[iLinkDest]->GetOrigin();
  70. if ( origin.DistToSqr(originOther) >= MinDistCareSq )
  71. continue;
  72. if ( !IsBoxIntersectingRay( vAbsMins, vAbsMaxs, nodeOrigin, originOther - nodeOrigin ) )
  73. continue;
  74. Assert( IsBoxIntersectingRay( vAbsMins, vAbsMaxs, originOther, nodeOrigin - originOther ) );
  75. CAI_DynamicLink *pDynamicLink = (CAI_DynamicLink *)CreateEntityByName( "info_node_link" );
  76. pDynamicLink->m_nSrcID = i;
  77. pDynamicLink->m_nDestID = iLinkDest;
  78. pDynamicLink->m_nSrcEditID = g_pAINetworkManager->GetEditOps()->GetWCIdFromNodeId( pDynamicLink->m_nSrcID );
  79. pDynamicLink->m_nDestEditID = g_pAINetworkManager->GetEditOps()->GetWCIdFromNodeId( pDynamicLink->m_nDestID );
  80. pDynamicLink->m_nLinkState = m_nLinkState;
  81. pDynamicLink->m_strAllowUse = m_strAllowUse;
  82. pDynamicLink->m_bInvertAllow = m_bInvertAllow;
  83. pDynamicLink->m_bFixedUpIds = true;
  84. pDynamicLink->m_bNotSaved = true;
  85. pDynamicLink->m_nPriority = m_nPriority;
  86. pDynamicLink->Spawn();
  87. m_ControlledLinks.AddToTail( pDynamicLink );
  88. }
  89. }
  90. }
  91. void CAI_DynamicLinkController::InputTurnOn( inputdata_t &inputdata )
  92. {
  93. for ( int i = 0; i < m_ControlledLinks.Count(); i++ )
  94. {
  95. if ( m_ControlledLinks[i] == NULL )
  96. {
  97. m_ControlledLinks.FastRemove(i);
  98. if ( i >= m_ControlledLinks.Count() )
  99. break;
  100. }
  101. m_ControlledLinks[i]->InputTurnOn( inputdata );
  102. }
  103. m_nLinkState = LINK_ON;
  104. }
  105. void CAI_DynamicLinkController::InputTurnOff( inputdata_t &inputdata )
  106. {
  107. for ( int i = 0; i < m_ControlledLinks.Count(); i++ )
  108. {
  109. if ( m_ControlledLinks[i] == NULL )
  110. {
  111. m_ControlledLinks.FastRemove(i);
  112. if ( i >= m_ControlledLinks.Count() )
  113. break;
  114. }
  115. m_ControlledLinks[i]->InputTurnOff( inputdata );
  116. }
  117. m_nLinkState = LINK_OFF;
  118. }
  119. void CAI_DynamicLinkController::InputSetAllowed( inputdata_t &inputdata )
  120. {
  121. m_strAllowUse = inputdata.value.StringID();
  122. for ( int i = 0; i < m_ControlledLinks.Count(); i++ )
  123. {
  124. if ( m_ControlledLinks[i] == NULL )
  125. {
  126. m_ControlledLinks.FastRemove(i);
  127. if ( i >= m_ControlledLinks.Count() )
  128. break;
  129. }
  130. m_ControlledLinks[i]->m_strAllowUse = m_strAllowUse;
  131. }
  132. }
  133. void CAI_DynamicLinkController::InputSetInvert( inputdata_t &inputdata )
  134. {
  135. m_bInvertAllow = inputdata.value.Bool();
  136. for ( int i = 0; i < m_ControlledLinks.Count(); i++ )
  137. {
  138. if ( m_ControlledLinks[i] == NULL )
  139. {
  140. m_ControlledLinks.FastRemove(i);
  141. if ( i >= m_ControlledLinks.Count() )
  142. break;
  143. }
  144. m_ControlledLinks[i]->m_bInvertAllow = m_bInvertAllow;
  145. }
  146. }
  147. //-----------------------------------------------------------------------------
  148. LINK_ENTITY_TO_CLASS(info_node_link, CAI_DynamicLink);
  149. BEGIN_DATADESC( CAI_DynamicLink )
  150. // m_pNextDynamicLink
  151. DEFINE_KEYFIELD( m_nLinkState, FIELD_INTEGER, "initialstate" ),
  152. DEFINE_KEYFIELD( m_nSrcEditID, FIELD_INTEGER, "startnode" ),
  153. DEFINE_KEYFIELD( m_nDestEditID, FIELD_INTEGER, "endnode" ),
  154. DEFINE_KEYFIELD( m_nLinkType, FIELD_INTEGER, "linktype" ),
  155. DEFINE_FIELD( m_bInvertAllow, FIELD_BOOLEAN ),
  156. DEFINE_KEYFIELD( m_nPriority, FIELD_INTEGER, "Priority" ),
  157. DEFINE_KEYFIELD( m_bPreciseMovement, FIELD_BOOLEAN, "preciseMovement" ),
  158. // m_nSrcID (rebuilt)
  159. // m_nDestID (rebuilt)
  160. DEFINE_KEYFIELD( m_strAllowUse, FIELD_STRING, "AllowUse" ),
  161. // m_bFixedUpIds (part of rebuild)
  162. // m_bNotSaved (rebuilt)
  163. DEFINE_INPUTFUNC( FIELD_VOID, "TurnOn", InputTurnOn ),
  164. DEFINE_INPUTFUNC( FIELD_VOID, "TurnOff", InputTurnOff ),
  165. END_DATADESC()
  166. //-----------------------------------------------------------------------------
  167. // Init static variables
  168. //-----------------------------------------------------------------------------
  169. CAI_DynamicLink *CAI_DynamicLink::m_pAllDynamicLinks = NULL;
  170. bool CAI_DynamicLink::gm_bInitialized;
  171. //------------------------------------------------------------------------------
  172. void CAI_DynamicLink::GenerateControllerLinks()
  173. {
  174. CAI_DynamicLinkController *pController = NULL;
  175. while ( ( pController = gEntList.NextEntByClass( pController ) ) != NULL )
  176. {
  177. pController->GenerateLinksFromVolume();
  178. }
  179. }
  180. //------------------------------------------------------------------------------
  181. // Purpose : Initializes src and dest IDs for all dynamic links
  182. //
  183. // Input :
  184. // Output :
  185. //------------------------------------------------------------------------------
  186. void CAI_DynamicLink::InitDynamicLinks(void)
  187. {
  188. if (!g_pAINetworkManager->GetEditOps()->m_pNodeIndexTable)
  189. {
  190. Warning("ERROR: Trying initialize links with no WC ID table!\n");
  191. return;
  192. }
  193. if ( gm_bInitialized )
  194. return;
  195. gm_bInitialized = true;
  196. bool bUpdateZones = false;
  197. GenerateControllerLinks();
  198. CAI_DynamicLink* pDynamicLink = CAI_DynamicLink::m_pAllDynamicLinks;
  199. while (pDynamicLink)
  200. {
  201. // -------------------------------------------------------------
  202. // First convert this links WC IDs to engine IDs
  203. // -------------------------------------------------------------
  204. if ( !pDynamicLink->m_bFixedUpIds )
  205. {
  206. int nSrcID = g_pAINetworkManager->GetEditOps()->GetNodeIdFromWCId( pDynamicLink->m_nSrcEditID );
  207. if (nSrcID == -1)
  208. {
  209. DevMsg( "ERROR: Dynamic link source WC node %d not found\n", pDynamicLink->m_nSrcEditID );
  210. nSrcID = NO_NODE;
  211. }
  212. int nDestID = g_pAINetworkManager->GetEditOps()->GetNodeIdFromWCId( pDynamicLink->m_nDestEditID );
  213. if (nDestID == -1)
  214. {
  215. DevMsg( "ERROR: Dynamic link dest WC node %d not found\n", pDynamicLink->m_nDestEditID );
  216. nDestID = NO_NODE;
  217. }
  218. pDynamicLink->m_nSrcID = nSrcID;
  219. pDynamicLink->m_nDestID = nDestID;
  220. pDynamicLink->m_bFixedUpIds = true;
  221. }
  222. if ( pDynamicLink->m_nSrcID != NO_NODE && pDynamicLink->m_nDestID != NO_NODE )
  223. {
  224. if ( ( pDynamicLink->GetSpawnFlags() & bits_HULL_BITS_MASK ) != 0 )
  225. {
  226. CAI_Link *pLink = pDynamicLink->FindLink();
  227. if ( !pLink )
  228. {
  229. CAI_Node *pNode1, *pNode2;
  230. pNode1 = g_pBigAINet->GetNode( pDynamicLink->m_nSrcID );
  231. pNode2 = g_pBigAINet->GetNode( pDynamicLink->m_nDestID );
  232. if ( pNode1 && pNode2 )
  233. {
  234. pLink = g_pBigAINet->CreateLink( pDynamicLink->m_nSrcID, pDynamicLink->m_nDestID );
  235. if ( !pLink )
  236. {
  237. DevMsg( "Failed to create dynamic link (%d <--> %d)\n", pDynamicLink->m_nSrcEditID, pDynamicLink->m_nDestEditID );
  238. }
  239. }
  240. }
  241. if ( pLink )
  242. {
  243. bUpdateZones = true;
  244. int hullBits = ( pDynamicLink->GetSpawnFlags() & bits_HULL_BITS_MASK );
  245. for ( int i = 0; i < NUM_HULLS; i++ )
  246. {
  247. if ( hullBits & HullToBit( Hull_t(i) ) )
  248. {
  249. pLink->m_iAcceptedMoveTypes[i] = pDynamicLink->m_nLinkType;
  250. }
  251. }
  252. }
  253. }
  254. // Now set the link's state
  255. pDynamicLink->SetLinkState();
  256. // Go on to the next dynamic link
  257. pDynamicLink = pDynamicLink->m_pNextDynamicLink;
  258. }
  259. else
  260. {
  261. CAI_DynamicLink *pBadDynamicLink = pDynamicLink;
  262. // Go on to the next dynamic link
  263. pDynamicLink = pDynamicLink->m_pNextDynamicLink;
  264. UTIL_RemoveImmediate( pBadDynamicLink );
  265. }
  266. }
  267. if ( bUpdateZones )
  268. {
  269. g_AINetworkBuilder.InitZones( g_pBigAINet );
  270. }
  271. }
  272. //------------------------------------------------------------------------------
  273. // Purpose : Goes through each dynamic link and updates the state of all
  274. // AINetwork links
  275. // Input :
  276. // Output :
  277. //------------------------------------------------------------------------------
  278. void CAI_DynamicLink::ResetDynamicLinks(void)
  279. {
  280. CAI_DynamicLink* pDynamicLink = CAI_DynamicLink::m_pAllDynamicLinks;
  281. while (pDynamicLink)
  282. {
  283. // Now set the link's state
  284. pDynamicLink->SetLinkState();
  285. // Go on to the next dynamic link
  286. pDynamicLink = pDynamicLink->m_pNextDynamicLink;
  287. }
  288. }
  289. //------------------------------------------------------------------------------
  290. // Purpose : Goes through each dynamic link and checks to make sure that
  291. // there is still a corresponding node link, if not removes it
  292. // Input :
  293. // Output :
  294. //------------------------------------------------------------------------------
  295. void CAI_DynamicLink::PurgeDynamicLinks(void)
  296. {
  297. CAI_DynamicLink* pDynamicLink = CAI_DynamicLink::m_pAllDynamicLinks;
  298. while (pDynamicLink)
  299. {
  300. if (!pDynamicLink->IsLinkValid())
  301. {
  302. // Didn't find the link, so remove it
  303. #ifdef _WIN32
  304. int nWCSrcID = g_pAINetworkManager->GetEditOps()->m_pNodeIndexTable[pDynamicLink->m_nSrcID];
  305. int nWCDstID = g_pAINetworkManager->GetEditOps()->m_pNodeIndexTable[pDynamicLink->m_nDestID];
  306. int status = Editor_DeleteNodeLink(nWCSrcID, nWCDstID, false);
  307. if (status == Editor_BadCommand)
  308. {
  309. DevMsg( "Worldcraft failed in PurgeDynamicLinks...\n" );
  310. }
  311. #endif
  312. // Safe to remove it here as this happens only after I leave this function
  313. UTIL_Remove(pDynamicLink);
  314. }
  315. // Go on to the next dynamic link
  316. pDynamicLink = pDynamicLink->m_pNextDynamicLink;
  317. }
  318. }
  319. //------------------------------------------------------------------------------
  320. // Purpose : Returns false if the dynamic link doesn't have a corresponding
  321. // node link
  322. // Input :
  323. // Output :
  324. //------------------------------------------------------------------------------
  325. bool CAI_DynamicLink::IsLinkValid( void )
  326. {
  327. CAI_Node *pNode = g_pBigAINet->GetNode(m_nSrcID);
  328. return ( pNode->GetLink( m_nDestID ) != NULL );
  329. }
  330. //------------------------------------------------------------------------------
  331. // Purpose :
  332. //------------------------------------------------------------------------------
  333. void CAI_DynamicLink::InputTurnOn( inputdata_t &inputdata )
  334. {
  335. if (m_nLinkState == LINK_OFF)
  336. {
  337. m_nLinkState = LINK_ON;
  338. CAI_DynamicLink::SetLinkState();
  339. }
  340. }
  341. //------------------------------------------------------------------------------
  342. // Purpose :
  343. //------------------------------------------------------------------------------
  344. void CAI_DynamicLink::InputTurnOff( inputdata_t &inputdata )
  345. {
  346. if (m_nLinkState == LINK_ON)
  347. {
  348. m_nLinkState = LINK_OFF;
  349. CAI_DynamicLink::SetLinkState();
  350. }
  351. }
  352. //------------------------------------------------------------------------------
  353. //------------------------------------------------------------------------------
  354. CAI_Link *CAI_DynamicLink::FindLink()
  355. {
  356. CAI_Node * pSrcNode = g_pBigAINet->GetNode(m_nSrcID, false);
  357. if ( pSrcNode )
  358. {
  359. int numLinks = pSrcNode->NumLinks();
  360. for (int i=0;i<numLinks;i++)
  361. {
  362. CAI_Link* pLink = pSrcNode->GetLinkByIndex(i);
  363. if (((pLink->m_iSrcID == m_nSrcID )&&
  364. (pLink->m_iDestID == m_nDestID)) ||
  365. ((pLink->m_iSrcID == m_nDestID)&&
  366. (pLink->m_iDestID == m_nSrcID )) )
  367. {
  368. return pLink;
  369. }
  370. }
  371. }
  372. return NULL;
  373. }
  374. //------------------------------------------------------------------------------
  375. //------------------------------------------------------------------------------
  376. int CAI_DynamicLink::ObjectCaps()
  377. {
  378. int caps = BaseClass::ObjectCaps();
  379. if ( m_bNotSaved )
  380. caps |= FCAP_DONT_SAVE;
  381. return caps;
  382. }
  383. //------------------------------------------------------------------------------
  384. // Purpose : Updates network link state if dynamic link state has changed
  385. // Input :
  386. // Output :
  387. //------------------------------------------------------------------------------
  388. void CAI_DynamicLink::SetLinkState(void)
  389. {
  390. if ( !gm_bInitialized )
  391. {
  392. // Safe to quietly return. Consistency will be enforced when InitDynamicLinks() is called
  393. return;
  394. }
  395. if (m_nSrcID == NO_NODE || m_nDestID == NO_NODE)
  396. {
  397. Vector pos = GetAbsOrigin();
  398. DevWarning("ERROR: Dynamic link at %f %f %f pointing to invalid node ID!!\n", pos.x, pos.y, pos.z);
  399. return;
  400. }
  401. // ------------------------------------------------------------------
  402. // Now update the node links...
  403. // Nodes share links so we only have to find the node from the src
  404. // For now just using one big AINetwork so find src node on that network
  405. // ------------------------------------------------------------------
  406. CAI_Node *pSrcNode = g_pBigAINet->GetNode( m_nSrcID, false );
  407. if ( !pSrcNode )
  408. return;
  409. CAI_Link* pLink = FindLink();
  410. if ( !pLink )
  411. {
  412. DevMsg("Dynamic Link Error: (%s) unable to form between nodes %d and %d\n", GetDebugName(), m_nSrcID, m_nDestID );
  413. return;
  414. }
  415. pLink->m_pDynamicLink = this;
  416. if (m_nLinkState == LINK_OFF)
  417. {
  418. pLink->m_LinkInfo |= bits_LINK_OFF;
  419. }
  420. else
  421. {
  422. pLink->m_LinkInfo &= ~bits_LINK_OFF;
  423. }
  424. if ( m_bPreciseMovement )
  425. {
  426. pLink->m_LinkInfo |= bits_LINK_PRECISE_MOVEMENT;
  427. }
  428. else
  429. {
  430. pLink->m_LinkInfo &= ~bits_LINK_PRECISE_MOVEMENT;
  431. }
  432. if ( m_nPriority == 0 )
  433. {
  434. pLink->m_LinkInfo &= ~bits_PREFER_AVOID;
  435. }
  436. else
  437. {
  438. pLink->m_LinkInfo |= bits_PREFER_AVOID;
  439. }
  440. }
  441. //------------------------------------------------------------------------------
  442. // Purpose : Given two node ID's return the related dynamic link if any or NULL
  443. //
  444. // Input :
  445. // Output :
  446. //------------------------------------------------------------------------------
  447. CAI_DynamicLink* CAI_DynamicLink::GetDynamicLink(int nSrcID, int nDstID)
  448. {
  449. CAI_DynamicLink* pDynamicLink = CAI_DynamicLink::m_pAllDynamicLinks;
  450. while (pDynamicLink)
  451. {
  452. if ((nSrcID == pDynamicLink->m_nSrcID && nDstID == pDynamicLink->m_nDestID) ||
  453. (nSrcID == pDynamicLink->m_nDestID && nDstID == pDynamicLink->m_nSrcID ) )
  454. {
  455. return pDynamicLink;
  456. }
  457. // Go on to the next dynamic link
  458. pDynamicLink = pDynamicLink->m_pNextDynamicLink;
  459. }
  460. return NULL;
  461. }
  462. //-----------------------------------------------------------------------------
  463. // Purpose: Constructor
  464. // Input :
  465. // Output :
  466. //-----------------------------------------------------------------------------
  467. CAI_DynamicLink::CAI_DynamicLink(void)
  468. {
  469. m_bFixedUpIds = false;
  470. m_bNotSaved = false;
  471. m_nSrcID = NO_NODE;
  472. m_nDestID = NO_NODE;
  473. m_nLinkState = LINK_OFF;
  474. m_nLinkType = bits_CAP_MOVE_GROUND;
  475. m_bInvertAllow = false;
  476. // -------------------------------------
  477. // Add to linked list of dynamic links
  478. // -------------------------------------
  479. m_pNextDynamicLink = CAI_DynamicLink::m_pAllDynamicLinks;
  480. CAI_DynamicLink::m_pAllDynamicLinks = this;
  481. };
  482. //-----------------------------------------------------------------------------
  483. // Purpose:
  484. // Input :
  485. // Output :
  486. //-----------------------------------------------------------------------------
  487. CAI_DynamicLink::~CAI_DynamicLink(void) {
  488. // ----------------------------------------------
  489. // Remove from linked list of all dynamic links
  490. // ----------------------------------------------
  491. CAI_DynamicLink* pDynamicLink = CAI_DynamicLink::m_pAllDynamicLinks;
  492. if (pDynamicLink == this)
  493. {
  494. m_pAllDynamicLinks = pDynamicLink->m_pNextDynamicLink;
  495. }
  496. else
  497. {
  498. while (pDynamicLink)
  499. {
  500. if (pDynamicLink->m_pNextDynamicLink == this)
  501. {
  502. pDynamicLink->m_pNextDynamicLink = pDynamicLink->m_pNextDynamicLink->m_pNextDynamicLink;
  503. break;
  504. }
  505. pDynamicLink = pDynamicLink->m_pNextDynamicLink;
  506. }
  507. }
  508. }
  509. LINK_ENTITY_TO_CLASS(info_radial_link_controller, CAI_RadialLinkController);
  510. BEGIN_DATADESC( CAI_RadialLinkController )
  511. DEFINE_KEYFIELD( m_flRadius, FIELD_FLOAT, "radius" ),
  512. DEFINE_FIELD( m_vecAtRestOrigin, FIELD_POSITION_VECTOR ),
  513. DEFINE_FIELD( m_bAtRest, FIELD_BOOLEAN ),
  514. DEFINE_THINKFUNC( PollMotionThink ),
  515. END_DATADESC()
  516. //---------------------------------------------------------
  517. //---------------------------------------------------------
  518. void CAI_RadialLinkController::Spawn()
  519. {
  520. SetSolid( SOLID_NONE );
  521. AddEffects( EF_NODRAW );
  522. }
  523. //---------------------------------------------------------
  524. //---------------------------------------------------------
  525. void CAI_RadialLinkController::Activate()
  526. {
  527. BaseClass::Activate();
  528. m_bAtRest = false;
  529. m_vecAtRestOrigin = vec3_invalid;
  530. // Force re-evaluation
  531. SetThink( &CAI_RadialLinkController::PollMotionThink );
  532. // Spread think times out.
  533. SetNextThink( gpGlobals->curtime + random->RandomFloat( 0.0f, 1.0f) );
  534. if( GetParent() != NULL )
  535. {
  536. float flDist = GetAbsOrigin().DistTo( GetParent()->GetAbsOrigin() );
  537. if( flDist > 200.0f )
  538. {
  539. // Warn at the console if a link controller is far away from its parent. This
  540. // most likely means that a level designer has copied an entity without researching its hierarchy.
  541. DevMsg("RadialLinkController (%s) is far from its parent!\n", GetDebugName() );
  542. }
  543. }
  544. }
  545. //---------------------------------------------------------
  546. //---------------------------------------------------------
  547. void CAI_RadialLinkController::PollMotionThink()
  548. {
  549. SetNextThink( gpGlobals->curtime + 0.5f );
  550. CBaseEntity *pParent = GetParent();
  551. if( pParent )
  552. {
  553. if( pParent->VPhysicsGetObject()->IsAsleep() )
  554. {
  555. if( !m_bAtRest )
  556. {
  557. m_vecAtRestOrigin = GetAbsOrigin();
  558. ModifyNodeLinks( true );
  559. m_bAtRest = true;
  560. //Msg("At Rest!\n");
  561. }
  562. }
  563. else
  564. {
  565. if( m_bAtRest )
  566. {
  567. float flDist;
  568. flDist = GetAbsOrigin().DistTo(m_vecAtRestOrigin);
  569. if( flDist < 18.0f )
  570. {
  571. // Ignore movement If moved less than 18 inches from the place where we came to rest.
  572. //Msg("Reject.\n");
  573. return;
  574. }
  575. }
  576. //Msg("Polling!\n");
  577. if( m_vecAtRestOrigin != vec3_invalid )
  578. {
  579. ModifyNodeLinks( false );
  580. m_bAtRest = false;
  581. m_vecAtRestOrigin = vec3_invalid;
  582. }
  583. }
  584. }
  585. }
  586. //---------------------------------------------------------
  587. //---------------------------------------------------------
  588. ConVar ai_radial_max_link_dist( "ai_radial_max_link_dist", "512" );
  589. void CAI_RadialLinkController::ModifyNodeLinks( bool bMakeStale )
  590. {
  591. int nNodes = g_pBigAINet->NumNodes();
  592. CAI_Node **ppNodes = g_pBigAINet->AccessNodes();
  593. VPROF_BUDGET("ModifyLinks", "ModifyLinks");
  594. const float MinDistCareSq = Square( ai_radial_max_link_dist.GetFloat() + 0.1 );
  595. for ( int i = 0; i < nNodes; i++ )
  596. {
  597. CAI_Node *pNode = ppNodes[i];
  598. const Vector &nodeOrigin = pNode->GetOrigin();
  599. if ( m_vecAtRestOrigin.DistToSqr(nodeOrigin) < MinDistCareSq )
  600. {
  601. int nLinks = pNode->NumLinks();
  602. for ( int j = 0; j < nLinks; j++ )
  603. {
  604. CAI_Link *pLink = pNode->GetLinkByIndex( j );
  605. int iLinkDest = pLink->DestNodeID( i );
  606. if ( iLinkDest > i )
  607. {
  608. bool bQualify = true;
  609. if( ( (pLink->m_iAcceptedMoveTypes[HULL_HUMAN]||pLink->m_iAcceptedMoveTypes[HULL_WIDE_HUMAN]) & bits_CAP_MOVE_GROUND) == 0 )
  610. {
  611. // Micro-optimization: Ignore any connection that's not a walking connection for humans.(sjb)
  612. bQualify = false;
  613. }
  614. const Vector &originOther = ppNodes[iLinkDest]->GetOrigin();
  615. if ( bQualify && m_vecAtRestOrigin.DistToSqr(originOther) < MinDistCareSq )
  616. {
  617. if ( IsRayIntersectingSphere(nodeOrigin, originOther - nodeOrigin, m_vecAtRestOrigin, m_flRadius) )
  618. {
  619. if( bMakeStale )
  620. {
  621. pLink->m_LinkInfo |= bits_LINK_STALE_SUGGESTED;
  622. pLink->m_timeStaleExpires = FLT_MAX;
  623. }
  624. else
  625. {
  626. pLink->m_LinkInfo &= ~bits_LINK_STALE_SUGGESTED;
  627. }
  628. }
  629. }
  630. }
  631. }
  632. }
  633. }
  634. }