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.

656 lines
19 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: An NPC's memory of potential enemies
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "isaverestore.h"
  8. #include "ai_debug.h"
  9. #include "ai_memory.h"
  10. #include "ai_basenpc.h"
  11. // memdbgon must be the last include file in a .cpp file!!!
  12. #include "tier0/memdbgon.h"
  13. #define EMEMORY_POOL_SIZE 64
  14. #define AI_FREE_KNOWLEDGE_DURATION 1.75
  15. //-----------------------------------------------------------------------------
  16. // AI_EnemyInfo_t
  17. //
  18. //-----------------------------------------------------------------------------
  19. //-----------------------------------------------------------------------------
  20. AI_EnemyInfo_t::AI_EnemyInfo_t(void)
  21. {
  22. hEnemy = NULL;
  23. vLastKnownLocation = vec3_origin;
  24. vLastSeenLocation = vec3_origin;
  25. timeLastSeen = 0;
  26. timeFirstSeen = 0;
  27. timeLastReacquired = 0;
  28. timeValidEnemy = 0;
  29. timeLastReceivedDamageFrom = 0;
  30. timeAtFirstHand = AI_INVALID_TIME;
  31. bDangerMemory = 0;
  32. bEludedMe = 0;
  33. bUnforgettable = 0;
  34. bMobbedMe = 0;
  35. }
  36. //-----------------------------------------------------------------------------
  37. // CAI_EnemiesListSaveRestoreOps
  38. //
  39. // Purpose: Handles save and load for enemy memories
  40. //
  41. //-----------------------------------------------------------------------------
  42. class CAI_EnemiesListSaveRestoreOps : public CDefSaveRestoreOps
  43. {
  44. public:
  45. CAI_EnemiesListSaveRestoreOps()
  46. {
  47. }
  48. virtual void Save( const SaveRestoreFieldInfo_t &fieldInfo, ISave *pSave )
  49. {
  50. CAI_Enemies::CMemMap *pMemMap = (CAI_Enemies::CMemMap *)fieldInfo.pField;
  51. int nMemories = pMemMap->Count();
  52. pSave->WriteInt( &nMemories );
  53. for ( CAI_Enemies::CMemMap::IndexType_t i = pMemMap->FirstInorder(); i != pMemMap->InvalidIndex(); i = pMemMap->NextInorder( i ) )
  54. {
  55. pSave->WriteAll( (*pMemMap)[i] );
  56. }
  57. }
  58. virtual void Restore( const SaveRestoreFieldInfo_t &fieldInfo, IRestore *pRestore )
  59. {
  60. CAI_Enemies::CMemMap *pMemMap = (CAI_Enemies::CMemMap *)fieldInfo.pField;
  61. Assert( pMemMap->Count() == 0 );
  62. int nMemories = pRestore->ReadInt();
  63. while ( nMemories-- )
  64. {
  65. AI_EnemyInfo_t *pAddMemory = new AI_EnemyInfo_t;
  66. pRestore->ReadAll( pAddMemory );
  67. if ( pAddMemory->hEnemy != NULL )
  68. {
  69. pMemMap->Insert( pAddMemory->hEnemy, pAddMemory );
  70. }
  71. else
  72. delete pAddMemory;
  73. }
  74. }
  75. virtual void MakeEmpty( const SaveRestoreFieldInfo_t &fieldInfo )
  76. {
  77. CAI_Enemies::CMemMap *pMemMap = (CAI_Enemies::CMemMap *)fieldInfo.pField;
  78. for ( CAI_Enemies::CMemMap::IndexType_t i = pMemMap->FirstInorder(); i != pMemMap->InvalidIndex(); i = pMemMap->NextInorder( i ) )
  79. {
  80. delete (*pMemMap)[i];
  81. }
  82. pMemMap->RemoveAll();
  83. }
  84. virtual bool IsEmpty( const SaveRestoreFieldInfo_t &fieldInfo )
  85. {
  86. CAI_Enemies::CMemMap *pMemMap = (CAI_Enemies::CMemMap *)fieldInfo.pField;
  87. return ( pMemMap->Count() == 0 );
  88. }
  89. } g_AI_MemoryListSaveRestoreOps;
  90. //-----------------------------------------------------------------------------
  91. // CAI_Enemies
  92. //
  93. // Purpose: Stores a set of AI_EnemyInfo_t's
  94. //
  95. //-----------------------------------------------------------------------------
  96. BEGIN_SIMPLE_DATADESC( CAI_Enemies )
  97. DEFINE_CUSTOM_FIELD( m_Map, &g_AI_MemoryListSaveRestoreOps ),
  98. DEFINE_FIELD( m_flFreeKnowledgeDuration, FIELD_FLOAT ),
  99. DEFINE_FIELD( m_flEnemyDiscardTime, FIELD_FLOAT ),
  100. DEFINE_FIELD( m_vecDefaultLKP, FIELD_POSITION_VECTOR ),
  101. DEFINE_FIELD( m_vecDefaultLSP, FIELD_POSITION_VECTOR ),
  102. DEFINE_FIELD( m_serial, FIELD_INTEGER ),
  103. END_DATADESC()
  104. BEGIN_SIMPLE_DATADESC( AI_EnemyInfo_t )
  105. DEFINE_FIELD( vLastKnownLocation, FIELD_POSITION_VECTOR ),
  106. DEFINE_FIELD( vLastSeenLocation, FIELD_POSITION_VECTOR ),
  107. DEFINE_FIELD( hEnemy, FIELD_EHANDLE ),
  108. DEFINE_FIELD( timeLastSeen, FIELD_TIME ),
  109. DEFINE_FIELD( timeFirstSeen, FIELD_TIME ),
  110. DEFINE_FIELD( timeLastReacquired, FIELD_TIME ),
  111. DEFINE_FIELD( timeValidEnemy, FIELD_TIME ),
  112. DEFINE_FIELD( timeLastReceivedDamageFrom, FIELD_TIME ),
  113. DEFINE_FIELD( timeAtFirstHand, FIELD_TIME ),
  114. DEFINE_FIELD( bDangerMemory, FIELD_BOOLEAN ),
  115. DEFINE_FIELD( bEludedMe, FIELD_BOOLEAN ),
  116. DEFINE_FIELD( bUnforgettable, FIELD_BOOLEAN ),
  117. DEFINE_FIELD( bMobbedMe, FIELD_BOOLEAN ),
  118. // NOT SAVED nextEMemory
  119. END_DATADESC()
  120. //-----------------------------------------------------------------------------
  121. CAI_Enemies::CAI_Enemies(void)
  122. {
  123. m_flFreeKnowledgeDuration = AI_FREE_KNOWLEDGE_DURATION;
  124. m_flEnemyDiscardTime = AI_DEF_ENEMY_DISCARD_TIME;
  125. m_vecDefaultLKP = vec3_invalid;
  126. m_vecDefaultLSP = vec3_invalid;
  127. m_serial = 0;
  128. SetDefLessFunc( m_Map );
  129. }
  130. //-----------------------------------------------------------------------------
  131. CAI_Enemies::~CAI_Enemies()
  132. {
  133. for ( CMemMap::IndexType_t i = m_Map.FirstInorder(); i != m_Map.InvalidIndex(); i = m_Map.NextInorder( i ) )
  134. {
  135. delete m_Map[i];
  136. }
  137. }
  138. //-----------------------------------------------------------------------------
  139. // Purpose: Purges any dead enemies from memory
  140. //-----------------------------------------------------------------------------
  141. AI_EnemyInfo_t *CAI_Enemies::GetFirst( AIEnemiesIter_t *pIter )
  142. {
  143. CMemMap::IndexType_t i = m_Map.FirstInorder();
  144. *pIter = (AIEnemiesIter_t)(unsigned)i;
  145. if ( i == m_Map.InvalidIndex() )
  146. return NULL;
  147. if ( m_Map[i]->hEnemy == NULL )
  148. return GetNext( pIter );
  149. return m_Map[i];
  150. }
  151. //-----------------------------------------------------------------------------
  152. AI_EnemyInfo_t *CAI_Enemies::GetNext( AIEnemiesIter_t *pIter )
  153. {
  154. CMemMap::IndexType_t i = (CMemMap::IndexType_t)((unsigned)(*pIter));
  155. if ( i == m_Map.InvalidIndex() )
  156. return NULL;
  157. i = m_Map.NextInorder( i );
  158. *pIter = (AIEnemiesIter_t)(unsigned)i;
  159. if ( i == m_Map.InvalidIndex() )
  160. return NULL;
  161. if ( m_Map[i]->hEnemy == NULL )
  162. return GetNext( pIter );
  163. return m_Map[i];
  164. }
  165. //-----------------------------------------------------------------------------
  166. AI_EnemyInfo_t *CAI_Enemies::Find( CBaseEntity *pEntity, bool bTryDangerMemory )
  167. {
  168. if ( pEntity == AI_UNKNOWN_ENEMY )
  169. pEntity = NULL;
  170. CMemMap::IndexType_t i = m_Map.Find( pEntity );
  171. if ( i == m_Map.InvalidIndex() )
  172. {
  173. if ( !bTryDangerMemory || ( i = m_Map.Find( NULL ) ) == m_Map.InvalidIndex() )
  174. return NULL;
  175. Assert(m_Map[i]->bDangerMemory == true);
  176. }
  177. return m_Map[i];
  178. }
  179. //-----------------------------------------------------------------------------
  180. AI_EnemyInfo_t *CAI_Enemies::GetDangerMemory()
  181. {
  182. CMemMap::IndexType_t i = m_Map.Find( NULL );
  183. if ( i == m_Map.InvalidIndex() )
  184. return NULL;
  185. Assert(m_Map[i]->bDangerMemory == true);
  186. return m_Map[i];
  187. }
  188. //-----------------------------------------------------------------------------
  189. bool CAI_Enemies::ShouldDiscardMemory( AI_EnemyInfo_t *pMemory )
  190. {
  191. CBaseEntity *pEnemy = pMemory->hEnemy;
  192. if ( pEnemy )
  193. {
  194. CAI_BaseNPC *pEnemyNPC = pEnemy->MyNPCPointer();
  195. if ( pEnemyNPC && pEnemyNPC->GetState() == NPC_STATE_DEAD )
  196. return true;
  197. }
  198. else
  199. {
  200. if ( !pMemory->bDangerMemory )
  201. return true;
  202. }
  203. if ( !pMemory->bUnforgettable &&
  204. gpGlobals->curtime > pMemory->timeLastSeen + m_flEnemyDiscardTime )
  205. {
  206. return true;
  207. }
  208. return false;
  209. }
  210. //-----------------------------------------------------------------------------
  211. void CAI_Enemies::RefreshMemories(void)
  212. {
  213. AI_PROFILE_SCOPE(CAI_Enemies_RefreshMemories);
  214. if ( m_flFreeKnowledgeDuration >= m_flEnemyDiscardTime )
  215. {
  216. m_flFreeKnowledgeDuration = m_flEnemyDiscardTime - .1;
  217. }
  218. // -------------------
  219. // Check each record
  220. // -------------------
  221. CMemMap::IndexType_t i = m_Map.FirstInorder();
  222. while ( i != m_Map.InvalidIndex() )
  223. {
  224. AI_EnemyInfo_t *pMemory = m_Map[i];
  225. CMemMap::IndexType_t iNext = m_Map.NextInorder( i ); // save so can remove
  226. if ( ShouldDiscardMemory( pMemory ) )
  227. {
  228. delete pMemory;
  229. m_Map.RemoveAt(i);
  230. }
  231. else if ( pMemory->hEnemy )
  232. {
  233. if ( gpGlobals->curtime <= pMemory->timeLastSeen + m_flFreeKnowledgeDuration )
  234. {
  235. // Free knowledge is ignored if the target has notarget on
  236. if ( !(pMemory->hEnemy->GetFlags() & FL_NOTARGET) )
  237. {
  238. pMemory->vLastKnownLocation = pMemory->hEnemy->GetAbsOrigin();
  239. }
  240. }
  241. if ( gpGlobals->curtime <= pMemory->timeLastSeen )
  242. {
  243. pMemory->vLastSeenLocation = pMemory->hEnemy->GetAbsOrigin();
  244. }
  245. }
  246. i = iNext;
  247. }
  248. }
  249. //-----------------------------------------------------------------------------
  250. // Purpose: Updates information about our enemies
  251. // Output : Returns true if new enemy, false if already know of enemy
  252. //-----------------------------------------------------------------------------
  253. bool CAI_Enemies::UpdateMemory(CAI_Network* pAINet, CBaseEntity *pEnemy, const Vector &vPosition, float reactionDelay, bool firstHand )
  254. {
  255. if ( pEnemy == AI_UNKNOWN_ENEMY )
  256. pEnemy = NULL;
  257. const float DIST_TRIGGER_REACQUIRE_SQ = Square(20.0 * 12.0);
  258. const float TIME_TRIGGER_REACQUIRE = 4.0;
  259. const float MIN_DIST_TIME_TRIGGER_REACQUIRE_SQ = Square(4.0 * 12.0);
  260. AI_EnemyInfo_t *pMemory = Find( pEnemy );
  261. // -------------------------------------------
  262. // Otherwise just update my own
  263. // -------------------------------------------
  264. // Update enemy information
  265. if ( pMemory )
  266. {
  267. Assert(pEnemy || pMemory->bDangerMemory == true);
  268. if ( firstHand )
  269. pMemory->timeLastSeen = gpGlobals->curtime;
  270. pMemory->bEludedMe = false;
  271. float deltaDist = (pMemory->vLastKnownLocation - vPosition).LengthSqr();
  272. if (deltaDist>DIST_TRIGGER_REACQUIRE_SQ || ( deltaDist>MIN_DIST_TIME_TRIGGER_REACQUIRE_SQ && ( gpGlobals->curtime - pMemory->timeLastSeen ) > TIME_TRIGGER_REACQUIRE ) )
  273. {
  274. pMemory->timeLastReacquired = gpGlobals->curtime;
  275. }
  276. // Only update if the enemy has moved
  277. if (deltaDist>Square(12.0))
  278. {
  279. pMemory->vLastKnownLocation = vPosition;
  280. }
  281. // Update the time at which we first saw him firsthand
  282. if ( firstHand && pMemory->timeAtFirstHand == AI_INVALID_TIME )
  283. {
  284. pMemory->timeAtFirstHand = gpGlobals->curtime;
  285. }
  286. return false;
  287. }
  288. // If not on my list of enemies add it
  289. AI_EnemyInfo_t *pAddMemory = new AI_EnemyInfo_t;
  290. pAddMemory->vLastKnownLocation = vPosition;
  291. if ( firstHand )
  292. {
  293. pAddMemory->timeLastReacquired = pAddMemory->timeFirstSeen = pAddMemory->timeLastSeen = pAddMemory->timeAtFirstHand = gpGlobals->curtime;
  294. }
  295. else
  296. {
  297. // Block free knowledge
  298. pAddMemory->timeLastReacquired = pAddMemory->timeFirstSeen = pAddMemory->timeLastSeen = ( gpGlobals->curtime - (m_flFreeKnowledgeDuration + 0.01) );
  299. pAddMemory->timeAtFirstHand = AI_INVALID_TIME;
  300. }
  301. if ( reactionDelay > 0.0 )
  302. pAddMemory->timeValidEnemy = gpGlobals->curtime + reactionDelay;
  303. pAddMemory->bEludedMe = false;
  304. // I'm either remembering a postion of an enmey of just a danger position
  305. pAddMemory->hEnemy = pEnemy;
  306. pAddMemory->bDangerMemory = ( pEnemy == NULL );
  307. // add to the list
  308. m_Map.Insert( pEnemy, pAddMemory );
  309. m_serial++;
  310. return true;
  311. }
  312. //------------------------------------------------------------------------------
  313. // Purpose : Returns true if this enemy is part of my memory
  314. //------------------------------------------------------------------------------
  315. void CAI_Enemies::OnTookDamageFrom( CBaseEntity *pEnemy )
  316. {
  317. AI_EnemyInfo_t *pMemory = Find( pEnemy, true );
  318. if ( pMemory )
  319. pMemory->timeLastReceivedDamageFrom = gpGlobals->curtime;
  320. }
  321. //------------------------------------------------------------------------------
  322. // Purpose : Returns true if this enemy is part of my memory
  323. //------------------------------------------------------------------------------
  324. bool CAI_Enemies::HasMemory( CBaseEntity *pEnemy )
  325. {
  326. return ( Find( pEnemy ) != NULL );
  327. }
  328. //-----------------------------------------------------------------------------
  329. // Purpose: Clear information about our enemy
  330. //-----------------------------------------------------------------------------
  331. void CAI_Enemies::ClearMemory(CBaseEntity *pEnemy)
  332. {
  333. CMemMap::IndexType_t i = m_Map.Find( pEnemy );
  334. if ( i != m_Map.InvalidIndex() )
  335. {
  336. delete m_Map[i];
  337. m_Map.RemoveAt( i );
  338. }
  339. }
  340. //-----------------------------------------------------------------------------
  341. // Purpose: Notes that the given enemy has eluded me
  342. //-----------------------------------------------------------------------------
  343. void CAI_Enemies::MarkAsEluded( CBaseEntity *pEnemy )
  344. {
  345. AI_EnemyInfo_t *pMemory = Find( pEnemy );
  346. if ( pMemory )
  347. {
  348. pMemory->bEludedMe = true;
  349. }
  350. }
  351. //-----------------------------------------------------------------------------
  352. // Purpose: Returns last known posiiton of given enemy
  353. //-----------------------------------------------------------------------------
  354. const Vector &CAI_Enemies::LastKnownPosition( CBaseEntity *pEnemy )
  355. {
  356. AI_EnemyInfo_t *pMemory = Find( pEnemy, true );
  357. if ( pMemory )
  358. {
  359. m_vecDefaultLKP = pMemory->vLastKnownLocation;
  360. }
  361. else
  362. {
  363. DevWarning( 2,"Asking LastKnownPosition for enemy that's not in my memory!!\n");
  364. }
  365. return m_vecDefaultLKP;
  366. }
  367. //-----------------------------------------------------------------------------
  368. // Purpose: Returns the last position the enemy was SEEN at. This will always be
  369. // different than LastKnownPosition() when the enemy is out of sight, because
  370. // the last KNOWN position will be updated for a number of seconds after the
  371. // player disappears.
  372. //-----------------------------------------------------------------------------
  373. const Vector &CAI_Enemies::LastSeenPosition( CBaseEntity *pEnemy )
  374. {
  375. AI_EnemyInfo_t *pMemory = Find( pEnemy, true );
  376. if ( pMemory )
  377. {
  378. m_vecDefaultLSP = pMemory->vLastSeenLocation;
  379. }
  380. else
  381. {
  382. DevWarning( 2,"Asking LastSeenPosition for enemy that's not in my memory!!\n");
  383. }
  384. return m_vecDefaultLSP;
  385. }
  386. float CAI_Enemies::TimeLastReacquired( CBaseEntity *pEnemy )
  387. {
  388. // I've never seen something that doesn't exist
  389. if (!pEnemy)
  390. return 0;
  391. AI_EnemyInfo_t *pMemory = Find( pEnemy, true );
  392. if ( pMemory )
  393. return pMemory->timeLastReacquired;
  394. if ( pEnemy != AI_UNKNOWN_ENEMY )
  395. DevWarning( 2,"Asking TimeLastReacquired for enemy that's not in my memory!!\n");
  396. return AI_INVALID_TIME;
  397. }
  398. //-----------------------------------------------------------------------------
  399. // Purpose: Sets position to the last known position of an enemy. If enemy
  400. // was not found returns last memory of danger position if it exists
  401. // Output : Returns false is no position is known
  402. //-----------------------------------------------------------------------------
  403. float CAI_Enemies::LastTimeSeen( CBaseEntity *pEnemy, bool bCheckDangerMemory /*= true*/ )
  404. {
  405. // I've never seen something that doesn't exist
  406. if (!pEnemy)
  407. return 0;
  408. AI_EnemyInfo_t *pMemory = Find( pEnemy, bCheckDangerMemory );
  409. if ( pMemory )
  410. return pMemory->timeLastSeen;
  411. if ( pEnemy != AI_UNKNOWN_ENEMY )
  412. DevWarning( 2,"Asking LastTimeSeen for enemy that's not in my memory!!\n");
  413. return AI_INVALID_TIME;
  414. }
  415. //-----------------------------------------------------------------------------
  416. // Purpose: Get the time at which the enemy was first seen.
  417. // Output : Returns false is no position is known
  418. //-----------------------------------------------------------------------------
  419. float CAI_Enemies::FirstTimeSeen( CBaseEntity *pEnemy)
  420. {
  421. // I've never seen something that doesn't exist
  422. if (!pEnemy)
  423. return 0;
  424. AI_EnemyInfo_t *pMemory = Find( pEnemy, true );
  425. if ( pMemory )
  426. return pMemory->timeFirstSeen;
  427. if ( pEnemy != AI_UNKNOWN_ENEMY )
  428. DevWarning( 2,"Asking FirstTimeSeen for enemy that's not in my memory!!\n");
  429. return AI_INVALID_TIME;
  430. }
  431. //-----------------------------------------------------------------------------
  432. // Purpose:
  433. // Input : *pEnemy -
  434. // Output : Returns true on success, false on failure.
  435. //-----------------------------------------------------------------------------
  436. bool CAI_Enemies::HasFreeKnowledgeOf( CBaseEntity *pEnemy )
  437. {
  438. // I've never seen something that doesn't exist
  439. if (!pEnemy)
  440. return 0;
  441. AI_EnemyInfo_t *pMemory = Find( pEnemy, true );
  442. if ( pMemory )
  443. {
  444. float flFreeKnowledgeTime = pMemory->timeLastSeen + m_flFreeKnowledgeDuration;
  445. return ( gpGlobals->curtime < flFreeKnowledgeTime );
  446. }
  447. if ( pEnemy != AI_UNKNOWN_ENEMY )
  448. DevWarning( 2,"Asking HasFreeKnowledgeOf for enemy that's not in my memory!!\n");
  449. return AI_INVALID_TIME;
  450. }
  451. //-----------------------------------------------------------------------------
  452. float CAI_Enemies::LastTimeTookDamageFrom( CBaseEntity *pEnemy)
  453. {
  454. // I've never seen something that doesn't exist
  455. if (!pEnemy)
  456. return 0;
  457. AI_EnemyInfo_t *pMemory = Find( pEnemy, true );
  458. if ( pMemory )
  459. return pMemory->timeLastReceivedDamageFrom;
  460. if ( pEnemy != AI_UNKNOWN_ENEMY )
  461. DevWarning( 2,"Asking LastTimeTookDamageFrom for enemy that's not in my memory!!\n");
  462. return AI_INVALID_TIME;
  463. }
  464. //-----------------------------------------------------------------------------
  465. // Purpose: Returns the time at which the enemy was first seen firsthand
  466. // Input : *pEnemy -
  467. // Output : float
  468. //-----------------------------------------------------------------------------
  469. float CAI_Enemies::TimeAtFirstHand( CBaseEntity *pEnemy )
  470. {
  471. // I've never seen something that doesn't exist
  472. if (!pEnemy)
  473. return 0;
  474. AI_EnemyInfo_t *pMemory = Find( pEnemy, true );
  475. if ( pMemory )
  476. return pMemory->timeAtFirstHand;
  477. if ( pEnemy != AI_UNKNOWN_ENEMY )
  478. DevWarning( 2,"Asking TimeAtFirstHand for enemy that's not in my memory!!\n");
  479. return AI_INVALID_TIME;
  480. }
  481. //-----------------------------------------------------------------------------
  482. // Purpose: Sets position to the last known position of an enemy. If enemy
  483. // was not found returns last memory of danger position if it exists
  484. // Output : Returns false is no position is known
  485. //-----------------------------------------------------------------------------
  486. bool CAI_Enemies::HasEludedMe( CBaseEntity *pEnemy )
  487. {
  488. AI_EnemyInfo_t *pMemory = Find( pEnemy );
  489. if ( pMemory )
  490. return pMemory->bEludedMe;
  491. return false;
  492. }
  493. void CAI_Enemies::SetTimeValidEnemy( CBaseEntity *pEnemy, float flTime )
  494. {
  495. AI_EnemyInfo_t *pMemory = Find( pEnemy );
  496. if ( pMemory )
  497. pMemory->timeValidEnemy = flTime;
  498. }
  499. //-----------------------------------------------------------------------------
  500. void CAI_Enemies::SetUnforgettable( CBaseEntity *pEnemy, bool bUnforgettable )
  501. {
  502. AI_EnemyInfo_t *pMemory = Find( pEnemy );
  503. if ( pMemory )
  504. pMemory->bUnforgettable = bUnforgettable;
  505. }
  506. //-----------------------------------------------------------------------------
  507. void CAI_Enemies::SetMobbedMe( CBaseEntity *pEnemy, bool bMobbedMe )
  508. {
  509. AI_EnemyInfo_t *pMemory = Find( pEnemy );
  510. if ( pMemory )
  511. pMemory->bMobbedMe = bMobbedMe;
  512. }
  513. //-----------------------------------------------------------------------------
  514. void CAI_Enemies::SetFreeKnowledgeDuration( float flDuration )
  515. {
  516. m_flFreeKnowledgeDuration = flDuration;
  517. if ( m_flFreeKnowledgeDuration >= m_flEnemyDiscardTime )
  518. {
  519. // If your free knowledge time is greater than your discard time,
  520. // you'll forget about secondhand enemies passed to you by squadmates
  521. // as soon as you're given them.
  522. Assert( m_flFreeKnowledgeDuration < m_flEnemyDiscardTime );
  523. m_flFreeKnowledgeDuration = m_flEnemyDiscardTime - .1;
  524. }
  525. }
  526. //-----------------------------------------------------------------------------
  527. void CAI_Enemies::SetEnemyDiscardTime( float flTime )
  528. {
  529. m_flEnemyDiscardTime = flTime;
  530. if ( m_flFreeKnowledgeDuration >= m_flEnemyDiscardTime )
  531. {
  532. // If your free knowledge time is greater than your discard time,
  533. // you'll forget about secondhand enemies passed to you by squadmates
  534. // as soon as you're given them.
  535. Assert( m_flFreeKnowledgeDuration < m_flEnemyDiscardTime );
  536. m_flFreeKnowledgeDuration = m_flEnemyDiscardTime - .1;
  537. }
  538. }