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.

730 lines
20 KiB

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