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.

812 lines
19 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Squad classes
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "ai_squad.h"
  8. #include "ai_squadslot.h"
  9. #include "ai_basenpc.h"
  10. #include "saverestore_bitstring.h"
  11. #include "saverestore_utlvector.h"
  12. // memdbgon must be the last include file in a .cpp file!!!
  13. #include "tier0/memdbgon.h"
  14. //-----------------------------------------------------------------------------
  15. CAI_SquadManager g_AI_SquadManager;
  16. //-----------------------------------------------------------------------------
  17. // CAI_SquadManager
  18. //
  19. // Purpose: Manages all the squads in the system
  20. //
  21. //-----------------------------------------------------------------------------
  22. CAI_Squad *CAI_SquadManager::FindSquad( string_t squadName )
  23. {
  24. CAI_Squad* pSquad = m_pSquads;
  25. while (pSquad)
  26. {
  27. if (FStrEq(STRING(squadName),pSquad->GetName()))
  28. {
  29. return pSquad;
  30. }
  31. pSquad = pSquad->m_pNextSquad;
  32. }
  33. return NULL;
  34. }
  35. //-------------------------------------
  36. CAI_Squad *CAI_SquadManager::CreateSquad(string_t squadName)
  37. {
  38. CAI_Squad *pResult = new CAI_Squad(squadName);
  39. // ---------------------------------
  40. // Only named squads get added to the squad list
  41. if ( squadName != NULL_STRING )
  42. {
  43. pResult->m_pNextSquad = m_pSquads;
  44. m_pSquads = pResult;
  45. }
  46. else
  47. pResult->m_pNextSquad = NULL;
  48. return pResult;
  49. }
  50. //-------------------------------------
  51. int CAI_SquadManager::NumSquads()
  52. {
  53. int nSquads = 0;
  54. CAI_Squad* pSquad = m_pSquads;
  55. while (pSquad)
  56. {
  57. nSquads++;
  58. pSquad = pSquad->GetNext();
  59. }
  60. return nSquads;
  61. }
  62. //-------------------------------------
  63. void CAI_SquadManager::DeleteSquad( CAI_Squad *pSquad )
  64. {
  65. CAI_Squad *pCurSquad = m_pSquads;
  66. if (pCurSquad == pSquad)
  67. {
  68. g_AI_SquadManager.m_pSquads = pCurSquad->m_pNextSquad;
  69. }
  70. else
  71. {
  72. while (pCurSquad)
  73. {
  74. if (pCurSquad->m_pNextSquad == pSquad)
  75. {
  76. pCurSquad->m_pNextSquad = pCurSquad->m_pNextSquad->m_pNextSquad;
  77. break;
  78. }
  79. pCurSquad= pCurSquad->m_pNextSquad;
  80. }
  81. }
  82. delete pSquad;
  83. }
  84. //-------------------------------------
  85. // Purpose: Delete all the squads (called between levels / loads)
  86. //-------------------------------------
  87. void CAI_SquadManager::DeleteAllSquads(void)
  88. {
  89. CAI_Squad *squad = CAI_SquadManager::m_pSquads;
  90. while (squad)
  91. {
  92. CAI_Squad *temp = squad->m_pNextSquad;
  93. delete squad;
  94. squad = temp;
  95. }
  96. CAI_SquadManager::m_pSquads = NULL;
  97. }
  98. //-----------------------------------------------------------------------------
  99. // CAI_Squad
  100. //
  101. // Purpose: Tracks enemies, squad slots, squad members
  102. //
  103. //-----------------------------------------------------------------------------
  104. #ifdef PER_ENEMY_SQUADSLOTS
  105. BEGIN_SIMPLE_DATADESC( AISquadEnemyInfo_t )
  106. DEFINE_FIELD( hEnemy, FIELD_EHANDLE ),
  107. DEFINE_BITSTRING( slots),
  108. END_DATADESC()
  109. #endif
  110. BEGIN_SIMPLE_DATADESC( CAI_Squad )
  111. // m_pNextSquad (rebuilt)
  112. // m_Name (rebuilt)
  113. // m_SquadMembers (rebuilt)
  114. // m_SquadMembers.Count() (rebuilt)
  115. DEFINE_FIELD( m_flSquadSoundWaitTime, FIELD_TIME ),
  116. DEFINE_FIELD( m_nSquadSoundPriority, FIELD_INTEGER ),
  117. DEFINE_FIELD( m_hSquadInflictor, FIELD_EHANDLE ),
  118. DEFINE_AUTO_ARRAY( m_SquadData, FIELD_INTEGER ),
  119. // m_pLastFoundEnemyInfo (think transient)
  120. #ifdef PER_ENEMY_SQUADSLOTS
  121. DEFINE_UTLVECTOR(m_EnemyInfos, FIELD_EMBEDDED ),
  122. DEFINE_FIELD( m_flEnemyInfoCleanupTime, FIELD_TIME ),
  123. #else
  124. DEFINE_EMBEDDED( m_squadSlotsUsed ),
  125. #endif
  126. END_DATADESC()
  127. //-------------------------------------
  128. CAI_Squad::CAI_Squad(string_t newName)
  129. #ifndef PER_ENEMY_SQUADSLOTS
  130. : m_squadSlotsUsed(MAX_SQUADSLOTS)
  131. #endif
  132. {
  133. Init( newName );
  134. }
  135. //-------------------------------------
  136. CAI_Squad::CAI_Squad()
  137. #ifndef PER_ENEMY_SQUADSLOTS
  138. : m_squadSlotsUsed(MAX_SQUADSLOTS)
  139. #endif
  140. {
  141. Init( NULL_STRING );
  142. }
  143. //-------------------------------------
  144. void CAI_Squad::Init(string_t newName)
  145. {
  146. m_Name = AllocPooledString( STRING(newName) );
  147. m_pNextSquad = NULL;
  148. m_flSquadSoundWaitTime = 0;
  149. m_SquadMembers.RemoveAll();
  150. m_flSquadSoundWaitTime = 0;
  151. SetSquadInflictor( NULL );
  152. #ifdef PER_ENEMY_SQUADSLOTS
  153. m_flEnemyInfoCleanupTime = 0;
  154. m_pLastFoundEnemyInfo = NULL;
  155. #endif
  156. }
  157. //-------------------------------------
  158. CAI_Squad::~CAI_Squad(void)
  159. {
  160. }
  161. //-------------------------------------
  162. bool CAI_Squad::IsSilentMember( const CAI_BaseNPC *pNPC )
  163. {
  164. if ( !pNPC || ( pNPC->GetMoveType() == MOVETYPE_NONE && pNPC->GetSolid() == SOLID_NONE ) ) // a.k.a., enemy finder
  165. return true;
  166. return pNPC->IsSilentSquadMember();
  167. }
  168. //-------------------------------------
  169. // Purpose: Removes an NPC from a squad
  170. //-------------------------------------
  171. void CAI_Squad::RemoveFromSquad( CAI_BaseNPC *pNPC, bool bDeath )
  172. {
  173. if ( !pNPC )
  174. return;
  175. // Find the index of this squad member
  176. int member;
  177. int myIndex = m_SquadMembers.Find( pNPC );
  178. if (myIndex == -1)
  179. {
  180. DevMsg("ERROR: Attempting to remove non-existing squad membmer!\n");
  181. return;
  182. }
  183. m_SquadMembers.Remove(myIndex);
  184. // Notify squad members of death
  185. if ( bDeath )
  186. {
  187. for (member = 0; member < m_SquadMembers.Count(); member++)
  188. {
  189. CAI_BaseNPC* pSquadMem = m_SquadMembers[member];
  190. if (pSquadMem)
  191. {
  192. pSquadMem->NotifyDeadFriend(pNPC);
  193. }
  194. }
  195. }
  196. pNPC->SetSquad(NULL);
  197. pNPC->SetSquadName( NULL_STRING );
  198. }
  199. //-------------------------------------
  200. // Purpose: Addes the given NPC to the squad
  201. //-------------------------------------
  202. void CAI_Squad::AddToSquad(CAI_BaseNPC *pNPC)
  203. {
  204. if ( !pNPC || !pNPC->IsAlive() )
  205. {
  206. Assert(0);
  207. return;
  208. }
  209. if ( pNPC->GetSquad() == this )
  210. return;
  211. if ( pNPC->GetSquad() )
  212. {
  213. pNPC->GetSquad()->RemoveFromSquad(pNPC);
  214. }
  215. if (m_SquadMembers.Count() == MAX_SQUAD_MEMBERS)
  216. {
  217. DevMsg("Error!! Squad %s is too big!!! Replacing last member\n", STRING(this->m_Name) );
  218. m_SquadMembers.Remove(m_SquadMembers.Count()-1);
  219. }
  220. m_SquadMembers.AddToTail( pNPC );
  221. pNPC->SetSquad( this );
  222. pNPC->SetSquadName( m_Name );
  223. if ( m_SquadMembers.Count() > 1 )
  224. {
  225. CAI_BaseNPC *pCopyFrom = m_SquadMembers[0];
  226. Assert( pCopyFrom != NULL );
  227. CAI_Enemies *pEnemies = pCopyFrom->GetEnemies();
  228. AIEnemiesIter_t iter;
  229. AI_EnemyInfo_t *pInfo = pEnemies->GetFirst( &iter );
  230. while ( pInfo )
  231. {
  232. pNPC->UpdateEnemyMemory( pInfo->hEnemy, pInfo->vLastKnownLocation, pCopyFrom );
  233. pInfo = pEnemies->GetNext( &iter );
  234. }
  235. }
  236. }
  237. //-------------------------------------
  238. CAI_BaseNPC *CAI_Squad::SquadMemberInRange( const Vector &vecLocation, float flDist )
  239. {
  240. for (int i = 0; i < m_SquadMembers.Count(); i++)
  241. {
  242. if (m_SquadMembers[i] != NULL && (vecLocation - m_SquadMembers[i]->GetAbsOrigin() ).Length2D() <= flDist)
  243. return m_SquadMembers[i];
  244. }
  245. return NULL;
  246. }
  247. //-------------------------------------
  248. // Purpose: Returns the nearest squad member to the given squad member
  249. //-------------------------------------
  250. CAI_BaseNPC *CAI_Squad::NearestSquadMember( CAI_BaseNPC *pMember )
  251. {
  252. float fBestDist = MAX_COORD_RANGE;
  253. CAI_BaseNPC *fNearestEnt = NULL;
  254. Vector fStartLoc = pMember->GetAbsOrigin();
  255. for (int i = 0; i < m_SquadMembers.Count(); i++)
  256. {
  257. if (m_SquadMembers[i] != NULL)
  258. {
  259. float fDist = (fStartLoc - m_SquadMembers[i]->GetAbsOrigin()).Length();
  260. if (m_SquadMembers[i] != pMember &&
  261. fDist < fBestDist )
  262. {
  263. fBestDist = fDist;
  264. fNearestEnt = m_SquadMembers[i];
  265. }
  266. }
  267. }
  268. return fNearestEnt;
  269. }
  270. //-------------------------------------
  271. // Purpose: Return the number of squad members visible to the specified member
  272. //-------------------------------------
  273. int CAI_Squad::GetVisibleSquadMembers( CAI_BaseNPC *pMember )
  274. {
  275. int iCount = 0;
  276. for (int i = 0; i < m_SquadMembers.Count(); i++)
  277. {
  278. // Make sure it's not the specified member
  279. if ( m_SquadMembers[i] != NULL && pMember != m_SquadMembers[i] )
  280. {
  281. if ( pMember->FVisible( m_SquadMembers[i] ) )
  282. {
  283. iCount++;
  284. }
  285. }
  286. }
  287. return iCount;
  288. }
  289. //-------------------------------------
  290. //
  291. //-------------------------------------
  292. CAI_BaseNPC *CAI_Squad::GetSquadMemberNearestTo( const Vector &vecLocation )
  293. {
  294. CAI_BaseNPC *pNearest = NULL;
  295. float flNearest = FLT_MAX;
  296. for ( int i = 0; i < m_SquadMembers.Count(); i++ )
  297. {
  298. float flDist;
  299. flDist = m_SquadMembers[i]->GetAbsOrigin().DistToSqr( vecLocation );
  300. if( flDist < flNearest )
  301. {
  302. flNearest = flDist;
  303. pNearest = m_SquadMembers[i];
  304. }
  305. }
  306. Assert( pNearest != NULL );
  307. return pNearest;
  308. }
  309. //-------------------------------------
  310. // Purpose: Returns true if given entity is in the squad
  311. //-------------------------------------
  312. bool CAI_Squad::SquadIsMember( CBaseEntity *pMember )
  313. {
  314. CAI_BaseNPC *pNPC = pMember->MyNPCPointer();
  315. if ( pNPC && pNPC->GetSquad() == this )
  316. return true;
  317. return false;
  318. }
  319. //-------------------------------------
  320. bool CAI_Squad::IsLeader( CAI_BaseNPC *pNPC )
  321. {
  322. if ( IsSilentMember( pNPC ) )
  323. return false;
  324. if ( !pNPC )
  325. return false;
  326. if ( GetLeader() == pNPC )
  327. return true;
  328. return false;
  329. }
  330. //-------------------------------------
  331. CAI_BaseNPC *CAI_Squad::GetLeader( void )
  332. {
  333. CAI_BaseNPC *pLeader = NULL;
  334. int nSilentMembers = 0;
  335. for ( int i = 0; i < m_SquadMembers.Count(); i++ )
  336. {
  337. if ( !IsSilentMember( m_SquadMembers[i] ) )
  338. {
  339. if ( !pLeader )
  340. pLeader = m_SquadMembers[i];
  341. }
  342. else
  343. {
  344. nSilentMembers++;
  345. }
  346. }
  347. return ( m_SquadMembers.Count() - nSilentMembers > 1) ? pLeader : NULL;
  348. }
  349. //-----------------------------------------------------------------------------
  350. CAI_BaseNPC *CAI_Squad::GetFirstMember( AISquadIter_t *pIter, bool bIgnoreSilentMembers )
  351. {
  352. int i = 0;
  353. if ( bIgnoreSilentMembers )
  354. {
  355. for ( ; i < m_SquadMembers.Count(); i++ )
  356. {
  357. if ( !IsSilentMember( m_SquadMembers[i] ) )
  358. break;
  359. }
  360. }
  361. if ( pIter )
  362. *pIter = (AISquadIter_t)i;
  363. if ( i >= m_SquadMembers.Count() )
  364. return NULL;
  365. return m_SquadMembers[i];
  366. }
  367. //-------------------------------------
  368. CAI_BaseNPC *CAI_Squad::GetNextMember( AISquadIter_t *pIter, bool bIgnoreSilentMembers )
  369. {
  370. int &i = (int &)*pIter;
  371. i++;
  372. if ( bIgnoreSilentMembers )
  373. {
  374. for ( ; i < m_SquadMembers.Count(); i++ )
  375. {
  376. if ( !IsSilentMember( m_SquadMembers[i] ) )
  377. break;
  378. }
  379. }
  380. if ( i >= m_SquadMembers.Count() )
  381. return NULL;
  382. return m_SquadMembers[i];
  383. }
  384. //-------------------------------------
  385. // Purpose: Returns the average of the
  386. // positions of all squad members.
  387. // Optionally, you may exclude one
  388. // member.
  389. //-------------------------------------
  390. Vector CAI_Squad::ComputeSquadCentroid( bool bIncludeSilentMembers, CBaseCombatCharacter *pExcludeMember )
  391. {
  392. int count = 0;
  393. Vector vecSumOfOrigins = Vector( 0, 0, 0 );
  394. for ( int i = 0; i < m_SquadMembers.Count(); i++ )
  395. {
  396. if ( (m_SquadMembers[i] != pExcludeMember) && (bIncludeSilentMembers||!IsSilentMember(m_SquadMembers[i]) ) )
  397. {
  398. count++;
  399. vecSumOfOrigins+= m_SquadMembers[i]->GetAbsOrigin();
  400. }
  401. }
  402. return vecSumOfOrigins / count;
  403. }
  404. //-------------------------------------
  405. // Purpose: Alert everyone in the squad to the presence of a new enmey
  406. //-------------------------------------
  407. int CAI_Squad::NumMembers( bool bIgnoreSilentMembers )
  408. {
  409. int nSilentMembers = 0;
  410. if ( bIgnoreSilentMembers )
  411. {
  412. for ( int i = 0; i < m_SquadMembers.Count(); i++ )
  413. {
  414. if ( IsSilentMember( m_SquadMembers[i] ) )
  415. nSilentMembers++;
  416. }
  417. }
  418. return ( m_SquadMembers.Count() - nSilentMembers );
  419. }
  420. //-------------------------------------
  421. // Purpose: Alert everyone in the squad to the presence of a new enmey
  422. //-------------------------------------
  423. void CAI_Squad::SquadNewEnemy( CBaseEntity *pEnemy )
  424. {
  425. if ( !pEnemy )
  426. {
  427. DevMsg( "ERROR: SquadNewEnemy() - pEnemy is NULL!\n" );
  428. return;
  429. }
  430. for (int i = 0; i < m_SquadMembers.Count(); i++)
  431. {
  432. CAI_BaseNPC *pMember = m_SquadMembers[i];
  433. if (pMember)
  434. {
  435. // reset members who aren't activly engaged in fighting (only do this if the NPC's using the squad memory, or it'll fail)
  436. if ( !pMember->GetEnemy() ||
  437. ( pMember->GetEnemy() != pEnemy &&
  438. !pMember->HasCondition( COND_SEE_ENEMY) &&
  439. gpGlobals->curtime - pMember->GetEnemyLastTimeSeen() > 3.0 ) )
  440. {
  441. // give them a new enemy
  442. if( !hl2_episodic.GetBool() || pMember->IsValidEnemy(pEnemy) )
  443. {
  444. pMember->SetEnemy( pEnemy );
  445. }
  446. // pMember->SetLastAttackTime( 0 );
  447. }
  448. }
  449. }
  450. }
  451. //-------------------------------------
  452. // Purpose: Broadcast a message to all squad members
  453. // Input: messageID - generic message handle
  454. // data - generic data handle
  455. // sender - who sent the message (NULL by default, if not, will not resend to the sender)
  456. //-------------------------------------
  457. int CAI_Squad::BroadcastInteraction( int interactionType, void *data, CBaseCombatCharacter *sender )
  458. {
  459. //Must have a squad
  460. if ( m_SquadMembers.Count() == 0 )
  461. return false;
  462. //Broadcast to all members of the squad
  463. for ( int i = 0; i < m_SquadMembers.Count(); i++ )
  464. {
  465. CAI_BaseNPC *pMember = m_SquadMembers[i]->MyNPCPointer();
  466. //Validate and don't send again to the sender
  467. if ( ( pMember != NULL) && ( pMember != sender ) )
  468. {
  469. //Send it
  470. pMember->DispatchInteraction( interactionType, data, sender );
  471. }
  472. }
  473. return true;
  474. }
  475. //-----------------------------------------------------------------------------
  476. // Purpose: is it ok to make a sound of the given priority? Check for conflicts
  477. // Input : soundPriority -
  478. // Output : Returns true on success, false on failure.
  479. //-----------------------------------------------------------------------------
  480. bool CAI_Squad::FOkToMakeSound( int soundPriority )
  481. {
  482. if (gpGlobals->curtime <= m_flSquadSoundWaitTime)
  483. {
  484. if ( soundPriority <= m_nSquadSoundPriority )
  485. return false;
  486. }
  487. return true;
  488. }
  489. //-----------------------------------------------------------------------------
  490. // Purpose: A squad member made an exclusive sound. Keep track so other squad
  491. // members don't talk over it
  492. // Input : soundPriority - for sorting
  493. // time -
  494. //-----------------------------------------------------------------------------
  495. void CAI_Squad::JustMadeSound( int soundPriority, float time )
  496. {
  497. m_flSquadSoundWaitTime = time;
  498. m_nSquadSoundPriority = soundPriority;
  499. }
  500. //-----------------------------------------------------------------------------
  501. // Purpose: Try to get one of a contiguous range of slots
  502. // Input : slotIDStart - start of slot range
  503. // slotIDEnd - end of slot range
  504. // hEnemy - enemy this slot is for
  505. // Output : Returns true on success, false on failure.
  506. //-----------------------------------------------------------------------------
  507. bool CAI_Squad::OccupyStrategySlotRange( CBaseEntity *pEnemy, int slotIDStart, int slotIDEnd, int *pSlot )
  508. {
  509. #ifndef PER_ENEMY_SQUADSLOTS
  510. // FIXME: combat slots need to be per enemy, not per squad.
  511. // As it is, once a squad is occupied it stops making even simple attacks to other things nearby.
  512. // This code may make soldiers too aggressive
  513. if (GetLeader() && pEnemy != GetLeader()->GetEnemy())
  514. {
  515. *pSlot = SQUAD_SLOT_NONE;
  516. return true;
  517. }
  518. #endif
  519. // If I'm already occupying this slot
  520. if ( *pSlot >= slotIDStart && *pSlot <= slotIDEnd)
  521. return true;
  522. for ( int i = slotIDStart; i <= slotIDEnd; i++ )
  523. {
  524. // Check enemy to see if slot already occupied
  525. if (!IsSlotOccupied(pEnemy, i))
  526. {
  527. // Clear any previous spot;
  528. if (*pSlot != SQUAD_SLOT_NONE)
  529. {
  530. // As a debug measure check to see if slot was filled
  531. if (!IsSlotOccupied(pEnemy, *pSlot))
  532. {
  533. DevMsg( "ERROR! Vacating an empty slot!\n");
  534. }
  535. // Free the slot
  536. VacateSlot(pEnemy, *pSlot);
  537. }
  538. // Fill the slot
  539. OccupySlot(pEnemy, i);
  540. *pSlot = i;
  541. return true;
  542. }
  543. }
  544. return false;
  545. }
  546. //------------------------------------------------------------------------------
  547. bool CAI_Squad::IsStrategySlotRangeOccupied( CBaseEntity *pEnemy, int slotIDStart, int slotIDEnd )
  548. {
  549. for ( int i = slotIDStart; i <= slotIDEnd; i++ )
  550. {
  551. if (!IsSlotOccupied(pEnemy, i))
  552. return false;
  553. }
  554. return true;
  555. }
  556. //------------------------------------------------------------------------------
  557. void CAI_Squad::VacateStrategySlot( CBaseEntity *pEnemy, int slot)
  558. {
  559. // If I wasn't taking up a squad slot I'm done
  560. if (slot == SQUAD_SLOT_NONE)
  561. return;
  562. // As a debug measure check to see if slot was filled
  563. if (!IsSlotOccupied(pEnemy, slot))
  564. {
  565. DevMsg( "ERROR! Vacating an empty slot!\n");
  566. }
  567. // Free the slot
  568. VacateSlot(pEnemy, slot);
  569. }
  570. //------------------------------------------------------------------------------
  571. void CAI_Squad::UpdateEnemyMemory( CAI_BaseNPC *pUpdater, CBaseEntity *pEnemy, const Vector &position )
  572. {
  573. //Broadcast to all members of the squad
  574. for ( int i = 0; i < m_SquadMembers.Count(); i++ )
  575. {
  576. if ( m_SquadMembers[i] != pUpdater )
  577. {
  578. m_SquadMembers[i]->UpdateEnemyMemory( pEnemy, position, pUpdater );
  579. }
  580. }
  581. }
  582. //------------------------------------------------------------------------------
  583. #ifdef PER_ENEMY_SQUADSLOTS
  584. AISquadEnemyInfo_t *CAI_Squad::FindEnemyInfo( CBaseEntity *pEnemy )
  585. {
  586. int i;
  587. if ( gpGlobals->curtime > m_flEnemyInfoCleanupTime )
  588. {
  589. if ( m_EnemyInfos.Count() )
  590. {
  591. m_pLastFoundEnemyInfo = NULL;
  592. CUtlRBTree<CBaseEntity *> activeEnemies;
  593. SetDefLessFunc( activeEnemies );
  594. // Gather up the set of active enemies
  595. for ( i = 0; i < m_SquadMembers.Count(); i++ )
  596. {
  597. CBaseEntity *pMemberEnemy = m_SquadMembers[i]->GetEnemy();
  598. if ( pMemberEnemy && activeEnemies.Find( pMemberEnemy ) == activeEnemies.InvalidIndex() )
  599. {
  600. activeEnemies.Insert( pMemberEnemy );
  601. }
  602. }
  603. // Remove the records for deleted or unused enemies
  604. for ( i = m_EnemyInfos.Count() - 1; i >= 0; --i )
  605. {
  606. if ( m_EnemyInfos[i].hEnemy == NULL || activeEnemies.Find( m_EnemyInfos[i].hEnemy ) == activeEnemies.InvalidIndex() )
  607. {
  608. m_EnemyInfos.FastRemove( i );
  609. }
  610. }
  611. }
  612. m_flEnemyInfoCleanupTime = gpGlobals->curtime + 30;
  613. }
  614. if ( m_pLastFoundEnemyInfo && m_pLastFoundEnemyInfo->hEnemy == pEnemy )
  615. return m_pLastFoundEnemyInfo;
  616. for ( i = 0; i < m_EnemyInfos.Count(); i++ )
  617. {
  618. if ( m_EnemyInfos[i].hEnemy == pEnemy )
  619. {
  620. m_pLastFoundEnemyInfo = &m_EnemyInfos[i];
  621. return &m_EnemyInfos[i];
  622. }
  623. }
  624. m_pLastFoundEnemyInfo = NULL;
  625. i = m_EnemyInfos.AddToTail();
  626. m_EnemyInfos[i].hEnemy = pEnemy;
  627. m_pLastFoundEnemyInfo = &m_EnemyInfos[i];
  628. return &m_EnemyInfos[i];
  629. }
  630. #endif
  631. //------------------------------------------------------------------------------
  632. void CAI_Squad::OccupySlot( CBaseEntity *pEnemy, int i )
  633. {
  634. #ifdef PER_ENEMY_SQUADSLOTS
  635. AISquadEnemyInfo_t *pInfo = FindEnemyInfo( pEnemy );
  636. pInfo->slots.Set(i);
  637. #else
  638. m_squadSlotsUsed.Set(i);
  639. #endif
  640. }
  641. //------------------------------------------------------------------------------
  642. void CAI_Squad::VacateSlot( CBaseEntity *pEnemy, int i )
  643. {
  644. #ifdef PER_ENEMY_SQUADSLOTS
  645. AISquadEnemyInfo_t *pInfo = FindEnemyInfo( pEnemy );
  646. pInfo->slots.Clear(i);
  647. #else
  648. m_squadSlotsUsed.Clear(i);
  649. #endif
  650. }
  651. //------------------------------------------------------------------------------
  652. bool CAI_Squad::IsSlotOccupied( CBaseEntity *pEnemy, int i ) const
  653. {
  654. #ifdef PER_ENEMY_SQUADSLOTS
  655. const AISquadEnemyInfo_t *pInfo = FindEnemyInfo( pEnemy );
  656. return pInfo->slots.IsBitSet(i);
  657. #else
  658. return m_squadSlotsUsed.IsBitSet(i);
  659. #endif
  660. }
  661. void CAI_Squad::SquadRemember( int iMemory )
  662. {
  663. for (int i = 0; i < m_SquadMembers.Count(); i++)
  664. {
  665. if (m_SquadMembers[i] != NULL )
  666. {
  667. m_SquadMembers[i]->Remember( iMemory );
  668. }
  669. }
  670. }
  671. //------------------------------------------------------------------------------
  672. void CAI_Squad::SetSquadInflictor( CBaseEntity *pInflictor )
  673. {
  674. m_hSquadInflictor.Set(pInflictor);
  675. }
  676. //------------------------------------------------------------------------------
  677. bool CAI_Squad::IsSquadInflictor( CBaseEntity *pInflictor )
  678. {
  679. return (m_hSquadInflictor.Get() == pInflictor);
  680. }
  681. //=============================================================================