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.
672 lines
20 KiB
672 lines
20 KiB
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: An NPC's memory of potential enemies |
|
// |
|
//=============================================================================// |
|
|
|
#include "cbase.h" |
|
#include "isaverestore.h" |
|
#include "ai_debug.h" |
|
#include "ai_memory.h" |
|
#include "ai_basenpc.h" |
|
|
|
// memdbgon must be the last include file in a .cpp file!!! |
|
#include "tier0/memdbgon.h" |
|
|
|
#define EMEMORY_POOL_SIZE 64 |
|
#define AI_FREE_KNOWLEDGE_DURATION 1.75 |
|
|
|
//----------------------------------------------------------------------------- |
|
// AI_EnemyInfo_t |
|
// |
|
//----------------------------------------------------------------------------- |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
|
|
AI_EnemyInfo_t::AI_EnemyInfo_t(void) |
|
{ |
|
hEnemy = NULL; |
|
vLastKnownLocation = vec3_origin; |
|
vLastSeenLocation = vec3_origin; |
|
timeLastSeen = 0; |
|
timeFirstSeen = 0; |
|
timeLastReacquired = 0; |
|
timeValidEnemy = 0; |
|
timeLastReceivedDamageFrom = 0; |
|
timeAtFirstHand = AI_INVALID_TIME; |
|
nFaction = FACTION_NONE; |
|
bDangerMemory = 0; |
|
bEludedMe = 0; |
|
bUnforgettable = 0; |
|
bMobbedMe = 0; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// CAI_EnemiesListSaveRestoreOps |
|
// |
|
// Purpose: Handles save and load for enemy memories |
|
// |
|
//----------------------------------------------------------------------------- |
|
|
|
class CAI_EnemiesListSaveRestoreOps : public CDefSaveRestoreOps |
|
{ |
|
public: |
|
CAI_EnemiesListSaveRestoreOps() |
|
{ |
|
} |
|
|
|
virtual void Save( const SaveRestoreFieldInfo_t &fieldInfo, ISave *pSave ) |
|
{ |
|
CAI_Enemies::CMemMap *pMemMap = (CAI_Enemies::CMemMap *)fieldInfo.pField; |
|
|
|
int nMemories = pMemMap->Count(); |
|
pSave->WriteInt( &nMemories ); |
|
|
|
for ( CAI_Enemies::CMemMap::IndexType_t i = pMemMap->FirstInorder(); i != pMemMap->InvalidIndex(); i = pMemMap->NextInorder( i ) ) |
|
{ |
|
pSave->WriteAll( (*pMemMap)[i] ); |
|
} |
|
} |
|
|
|
virtual void Restore( const SaveRestoreFieldInfo_t &fieldInfo, IRestore *pRestore ) |
|
{ |
|
CAI_Enemies::CMemMap *pMemMap = (CAI_Enemies::CMemMap *)fieldInfo.pField; |
|
Assert( pMemMap->Count() == 0 ); |
|
|
|
int nMemories = pRestore->ReadInt(); |
|
|
|
while ( nMemories-- ) |
|
{ |
|
AI_EnemyInfo_t *pAddMemory = new AI_EnemyInfo_t; |
|
|
|
pRestore->ReadAll( pAddMemory ); |
|
|
|
if ( pAddMemory->hEnemy != NULL ) |
|
{ |
|
pMemMap->Insert( pAddMemory->hEnemy, pAddMemory ); |
|
} |
|
else |
|
delete pAddMemory; |
|
} |
|
} |
|
|
|
virtual void MakeEmpty( const SaveRestoreFieldInfo_t &fieldInfo ) |
|
{ |
|
CAI_Enemies::CMemMap *pMemMap = (CAI_Enemies::CMemMap *)fieldInfo.pField; |
|
|
|
for ( CAI_Enemies::CMemMap::IndexType_t i = pMemMap->FirstInorder(); i != pMemMap->InvalidIndex(); i = pMemMap->NextInorder( i ) ) |
|
{ |
|
delete (*pMemMap)[i]; |
|
} |
|
|
|
pMemMap->RemoveAll(); |
|
} |
|
|
|
virtual bool IsEmpty( const SaveRestoreFieldInfo_t &fieldInfo ) |
|
{ |
|
CAI_Enemies::CMemMap *pMemMap = (CAI_Enemies::CMemMap *)fieldInfo.pField; |
|
return ( pMemMap->Count() == 0 ); |
|
} |
|
|
|
} g_AI_MemoryListSaveRestoreOps; |
|
|
|
//----------------------------------------------------------------------------- |
|
// CAI_Enemies |
|
// |
|
// Purpose: Stores a set of AI_EnemyInfo_t's |
|
// |
|
//----------------------------------------------------------------------------- |
|
|
|
BEGIN_SIMPLE_DATADESC( CAI_Enemies ) |
|
|
|
DEFINE_CUSTOM_FIELD( m_Map, &g_AI_MemoryListSaveRestoreOps ), |
|
DEFINE_FIELD( m_flFreeKnowledgeDuration, FIELD_FLOAT ), |
|
DEFINE_FIELD( m_flEnemyDiscardTime, FIELD_FLOAT ), |
|
DEFINE_FIELD( m_vecDefaultLKP, FIELD_POSITION_VECTOR ), |
|
DEFINE_FIELD( m_vecDefaultLSP, FIELD_POSITION_VECTOR ), |
|
DEFINE_FIELD( m_serial, FIELD_INTEGER ), |
|
|
|
END_DATADESC() |
|
|
|
BEGIN_SIMPLE_DATADESC( AI_EnemyInfo_t ) |
|
DEFINE_FIELD( vLastKnownLocation, FIELD_POSITION_VECTOR ), |
|
DEFINE_FIELD( vLastSeenLocation, FIELD_POSITION_VECTOR ), |
|
DEFINE_FIELD( hEnemy, FIELD_EHANDLE ), |
|
DEFINE_FIELD( timeLastSeen, FIELD_TIME ), |
|
DEFINE_FIELD( timeFirstSeen, FIELD_TIME ), |
|
DEFINE_FIELD( timeLastReacquired, FIELD_TIME ), |
|
DEFINE_FIELD( timeValidEnemy, FIELD_TIME ), |
|
DEFINE_FIELD( timeLastReceivedDamageFrom, FIELD_TIME ), |
|
DEFINE_FIELD( timeAtFirstHand, FIELD_TIME ), |
|
DEFINE_FIELD( nFaction, FIELD_INTEGER ), |
|
DEFINE_FIELD( bDangerMemory, FIELD_BOOLEAN ), |
|
DEFINE_FIELD( bEludedMe, FIELD_BOOLEAN ), |
|
DEFINE_FIELD( bUnforgettable, FIELD_BOOLEAN ), |
|
DEFINE_FIELD( bMobbedMe, FIELD_BOOLEAN ), |
|
// NOT SAVED nextEMemory |
|
END_DATADESC() |
|
|
|
//----------------------------------------------------------------------------- |
|
|
|
CAI_Enemies::CAI_Enemies(void) |
|
{ |
|
m_flFreeKnowledgeDuration = AI_FREE_KNOWLEDGE_DURATION; |
|
m_flEnemyDiscardTime = AI_DEF_ENEMY_DISCARD_TIME; |
|
m_vecDefaultLKP = vec3_invalid; |
|
m_vecDefaultLSP = vec3_invalid; |
|
m_serial = 0; |
|
SetDefLessFunc( m_Map ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
|
|
CAI_Enemies::~CAI_Enemies() |
|
{ |
|
for ( CMemMap::IndexType_t i = m_Map.FirstInorder(); i != m_Map.InvalidIndex(); i = m_Map.NextInorder( i ) ) |
|
{ |
|
delete m_Map[i]; |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Purges any dead enemies from memory |
|
//----------------------------------------------------------------------------- |
|
|
|
AI_EnemyInfo_t *CAI_Enemies::GetFirst( AIEnemiesIter_t *pIter ) |
|
{ |
|
CMemMap::IndexType_t i = m_Map.FirstInorder(); |
|
*pIter = (AIEnemiesIter_t)(unsigned)i; |
|
|
|
if ( i == m_Map.InvalidIndex() ) |
|
return NULL; |
|
|
|
if ( m_Map[i]->hEnemy == NULL ) |
|
return GetNext( pIter ); |
|
|
|
return m_Map[i]; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
|
|
AI_EnemyInfo_t *CAI_Enemies::GetNext( AIEnemiesIter_t *pIter ) |
|
{ |
|
CMemMap::IndexType_t i = (CMemMap::IndexType_t)((unsigned)(*pIter)); |
|
|
|
if ( i == m_Map.InvalidIndex() ) |
|
return NULL; |
|
|
|
i = m_Map.NextInorder( i ); |
|
*pIter = (AIEnemiesIter_t)(unsigned)i; |
|
if ( i == m_Map.InvalidIndex() ) |
|
return NULL; |
|
|
|
if ( m_Map[i]->hEnemy == NULL ) |
|
return GetNext( pIter ); |
|
|
|
return m_Map[i]; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
|
|
AI_EnemyInfo_t *CAI_Enemies::Find( CBaseEntity *pEntity, bool bTryDangerMemory ) |
|
{ |
|
if ( pEntity == AI_UNKNOWN_ENEMY ) |
|
pEntity = NULL; |
|
|
|
CMemMap::IndexType_t i = m_Map.Find( pEntity ); |
|
if ( i == m_Map.InvalidIndex() ) |
|
{ |
|
if ( !bTryDangerMemory || ( i = m_Map.Find( NULL ) ) == m_Map.InvalidIndex() ) |
|
return NULL; |
|
Assert(m_Map[i]->bDangerMemory == true); |
|
} |
|
return m_Map[i]; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
|
|
AI_EnemyInfo_t *CAI_Enemies::GetDangerMemory() |
|
{ |
|
CMemMap::IndexType_t i = m_Map.Find( NULL ); |
|
if ( i == m_Map.InvalidIndex() ) |
|
return NULL; |
|
Assert(m_Map[i]->bDangerMemory == true); |
|
return m_Map[i]; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
|
|
bool CAI_Enemies::ShouldDiscardMemory( AI_EnemyInfo_t *pMemory ) |
|
{ |
|
CBaseEntity *pEnemy = pMemory->hEnemy; |
|
|
|
if ( pEnemy ) |
|
{ |
|
CAI_BaseNPC *pEnemyNPC = pEnemy->MyNPCPointer(); |
|
if ( pEnemyNPC ) |
|
{ |
|
if ( pEnemyNPC->GetState() == NPC_STATE_DEAD ) |
|
return true; |
|
|
|
// forget about the enemy if he changes faction |
|
if ( pEnemyNPC->GetFaction() != pMemory->nFaction ) |
|
return true; |
|
} |
|
} |
|
else |
|
{ |
|
if ( !pMemory->bDangerMemory ) |
|
return true; |
|
} |
|
|
|
if ( !pMemory->bUnforgettable && |
|
gpGlobals->curtime > pMemory->timeLastSeen + m_flEnemyDiscardTime ) |
|
{ |
|
return true; |
|
} |
|
|
|
return false; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
|
|
void CAI_Enemies::RefreshMemories(void) |
|
{ |
|
AI_PROFILE_SCOPE(CAI_Enemies_RefreshMemories); |
|
|
|
if ( m_flFreeKnowledgeDuration >= m_flEnemyDiscardTime ) |
|
{ |
|
m_flFreeKnowledgeDuration = m_flEnemyDiscardTime - .1; |
|
} |
|
|
|
// ------------------- |
|
// Check each record |
|
// ------------------- |
|
|
|
CMemMap::IndexType_t i = m_Map.FirstInorder(); |
|
while ( i != m_Map.InvalidIndex() ) |
|
{ |
|
AI_EnemyInfo_t *pMemory = m_Map[i]; |
|
|
|
CMemMap::IndexType_t iNext = m_Map.NextInorder( i ); // save so can remove |
|
if ( ShouldDiscardMemory( pMemory ) ) |
|
{ |
|
delete pMemory; |
|
m_Map.RemoveAt(i); |
|
} |
|
else if ( pMemory->hEnemy ) |
|
{ |
|
if ( gpGlobals->curtime <= pMemory->timeLastSeen + m_flFreeKnowledgeDuration ) |
|
{ |
|
// Free knowledge is ignored if the target has notarget on |
|
if ( !(pMemory->hEnemy->GetFlags() & FL_NOTARGET) ) |
|
{ |
|
pMemory->vLastKnownLocation = pMemory->hEnemy->GetAbsOrigin(); |
|
} |
|
} |
|
|
|
if ( gpGlobals->curtime <= pMemory->timeLastSeen ) |
|
{ |
|
pMemory->vLastSeenLocation = pMemory->hEnemy->GetAbsOrigin(); |
|
} |
|
} |
|
i = iNext; |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Updates information about our enemies |
|
// Output : Returns true if new enemy, false if already know of enemy |
|
//----------------------------------------------------------------------------- |
|
|
|
bool CAI_Enemies::UpdateMemory(CAI_Network* pAINet, CBaseEntity *pEnemy, const Vector &vPosition, float reactionDelay, bool firstHand ) |
|
{ |
|
if ( pEnemy == AI_UNKNOWN_ENEMY ) |
|
pEnemy = NULL; |
|
|
|
const float DIST_TRIGGER_REACQUIRE_SQ = Square(20.0 * 12.0); |
|
const float TIME_TRIGGER_REACQUIRE = 4.0; |
|
const float MIN_DIST_TIME_TRIGGER_REACQUIRE_SQ = Square(4.0 * 12.0); |
|
|
|
AI_EnemyInfo_t *pMemory = Find( pEnemy ); |
|
// ------------------------------------------- |
|
// Otherwise just update my own |
|
// ------------------------------------------- |
|
// Update enemy information |
|
if ( pMemory ) |
|
{ |
|
Assert(pEnemy || pMemory->bDangerMemory == true); |
|
|
|
if ( firstHand ) |
|
pMemory->timeLastSeen = gpGlobals->curtime; |
|
pMemory->bEludedMe = false; |
|
|
|
float deltaDist = (pMemory->vLastKnownLocation - vPosition).LengthSqr(); |
|
|
|
if (deltaDist>DIST_TRIGGER_REACQUIRE_SQ || ( deltaDist>MIN_DIST_TIME_TRIGGER_REACQUIRE_SQ && ( gpGlobals->curtime - pMemory->timeLastSeen ) > TIME_TRIGGER_REACQUIRE ) ) |
|
{ |
|
pMemory->timeLastReacquired = gpGlobals->curtime; |
|
} |
|
|
|
// Only update if the enemy has moved |
|
if (deltaDist>Square(12.0)) |
|
{ |
|
pMemory->vLastKnownLocation = vPosition; |
|
|
|
} |
|
|
|
// Update the time at which we first saw him firsthand |
|
if ( firstHand && pMemory->timeAtFirstHand == AI_INVALID_TIME ) |
|
{ |
|
pMemory->timeAtFirstHand = gpGlobals->curtime; |
|
} |
|
|
|
return false; |
|
} |
|
|
|
// If not on my list of enemies add it |
|
AI_EnemyInfo_t *pAddMemory = new AI_EnemyInfo_t; |
|
pAddMemory->vLastKnownLocation = vPosition; |
|
|
|
if ( firstHand ) |
|
{ |
|
pAddMemory->timeLastReacquired = pAddMemory->timeFirstSeen = pAddMemory->timeLastSeen = pAddMemory->timeAtFirstHand = gpGlobals->curtime; |
|
} |
|
else |
|
{ |
|
// Block free knowledge |
|
pAddMemory->timeLastReacquired = pAddMemory->timeFirstSeen = pAddMemory->timeLastSeen = ( gpGlobals->curtime - (m_flFreeKnowledgeDuration + 0.01) ); |
|
pAddMemory->timeAtFirstHand = AI_INVALID_TIME; |
|
} |
|
|
|
if ( reactionDelay > 0.0 ) |
|
pAddMemory->timeValidEnemy = gpGlobals->curtime + reactionDelay; |
|
|
|
pAddMemory->bEludedMe = false; |
|
|
|
// I'm either remembering a position of an enemy or just a danger position |
|
pAddMemory->hEnemy = pEnemy; |
|
pAddMemory->bDangerMemory = ( pEnemy == NULL ); |
|
|
|
if ( pEnemy ) |
|
{ |
|
CAI_BaseNPC *pEnemyNPC = pEnemy->MyNPCPointer(); |
|
if ( pEnemyNPC ) |
|
pAddMemory->nFaction = pEnemyNPC->GetFaction(); |
|
} |
|
|
|
// add to the list |
|
m_Map.Insert( pEnemy, pAddMemory ); |
|
m_serial++; |
|
|
|
return true; |
|
} |
|
|
|
//------------------------------------------------------------------------------ |
|
// Purpose : Returns true if this enemy is part of my memory |
|
//------------------------------------------------------------------------------ |
|
void CAI_Enemies::OnTookDamageFrom( CBaseEntity *pEnemy ) |
|
{ |
|
AI_EnemyInfo_t *pMemory = Find( pEnemy, true ); |
|
if ( pMemory ) |
|
pMemory->timeLastReceivedDamageFrom = gpGlobals->curtime; |
|
} |
|
|
|
//------------------------------------------------------------------------------ |
|
// Purpose : Returns true if this enemy is part of my memory |
|
//------------------------------------------------------------------------------ |
|
bool CAI_Enemies::HasMemory( CBaseEntity *pEnemy ) |
|
{ |
|
return ( Find( pEnemy ) != NULL ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Clear information about our enemy |
|
//----------------------------------------------------------------------------- |
|
void CAI_Enemies::ClearMemory(CBaseEntity *pEnemy) |
|
{ |
|
CMemMap::IndexType_t i = m_Map.Find( pEnemy ); |
|
if ( i != m_Map.InvalidIndex() ) |
|
{ |
|
delete m_Map[i]; |
|
m_Map.RemoveAt( i ); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Notes that the given enemy has eluded me |
|
//----------------------------------------------------------------------------- |
|
void CAI_Enemies::MarkAsEluded( CBaseEntity *pEnemy ) |
|
{ |
|
AI_EnemyInfo_t *pMemory = Find( pEnemy ); |
|
if ( pMemory ) |
|
{ |
|
pMemory->bEludedMe = true; |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Returns last known posiiton of given enemy |
|
//----------------------------------------------------------------------------- |
|
const Vector &CAI_Enemies::LastKnownPosition( CBaseEntity *pEnemy ) |
|
{ |
|
AI_EnemyInfo_t *pMemory = Find( pEnemy, true ); |
|
if ( pMemory ) |
|
{ |
|
m_vecDefaultLKP = pMemory->vLastKnownLocation; |
|
} |
|
else |
|
{ |
|
DevWarning( 2,"Asking LastKnownPosition for enemy that's not in my memory!!\n"); |
|
} |
|
return m_vecDefaultLKP; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Returns the last position the enemy was SEEN at. This will always be |
|
// different than LastKnownPosition() when the enemy is out of sight, because |
|
// the last KNOWN position will be updated for a number of seconds after the |
|
// player disappears. |
|
//----------------------------------------------------------------------------- |
|
const Vector &CAI_Enemies::LastSeenPosition( CBaseEntity *pEnemy ) |
|
{ |
|
AI_EnemyInfo_t *pMemory = Find( pEnemy, true ); |
|
if ( pMemory ) |
|
{ |
|
m_vecDefaultLSP = pMemory->vLastSeenLocation; |
|
} |
|
else |
|
{ |
|
DevWarning( 2,"Asking LastSeenPosition for enemy that's not in my memory!!\n"); |
|
} |
|
return m_vecDefaultLSP; |
|
} |
|
|
|
float CAI_Enemies::TimeLastReacquired( CBaseEntity *pEnemy ) |
|
{ |
|
// I've never seen something that doesn't exist |
|
if (!pEnemy) |
|
return 0; |
|
|
|
AI_EnemyInfo_t *pMemory = Find( pEnemy, true ); |
|
if ( pMemory ) |
|
return pMemory->timeLastReacquired; |
|
|
|
if ( pEnemy != AI_UNKNOWN_ENEMY ) |
|
DevWarning( 2,"Asking TimeLastReacquired for enemy that's not in my memory!!\n"); |
|
return AI_INVALID_TIME; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Sets position to the last known position of an enemy. If enemy |
|
// was not found returns last memory of danger position if it exists |
|
// Output : Returns false is no position is known |
|
//----------------------------------------------------------------------------- |
|
float CAI_Enemies::LastTimeSeen( CBaseEntity *pEnemy, bool bCheckDangerMemory /*= true*/ ) |
|
{ |
|
// I've never seen something that doesn't exist |
|
if (!pEnemy) |
|
return 0; |
|
|
|
AI_EnemyInfo_t *pMemory = Find( pEnemy, bCheckDangerMemory ); |
|
if ( pMemory ) |
|
return pMemory->timeLastSeen; |
|
|
|
if ( pEnemy != AI_UNKNOWN_ENEMY ) |
|
DevWarning( 2,"Asking LastTimeSeen for enemy that's not in my memory!!\n"); |
|
return AI_INVALID_TIME; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Get the time at which the enemy was first seen. |
|
// Output : Returns false is no position is known |
|
//----------------------------------------------------------------------------- |
|
float CAI_Enemies::FirstTimeSeen( CBaseEntity *pEnemy) |
|
{ |
|
// I've never seen something that doesn't exist |
|
if (!pEnemy) |
|
return 0; |
|
|
|
AI_EnemyInfo_t *pMemory = Find( pEnemy, true ); |
|
if ( pMemory ) |
|
return pMemory->timeFirstSeen; |
|
|
|
if ( pEnemy != AI_UNKNOWN_ENEMY ) |
|
DevWarning( 2,"Asking FirstTimeSeen for enemy that's not in my memory!!\n"); |
|
return AI_INVALID_TIME; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : *pEnemy - |
|
// Output : Returns true on success, false on failure. |
|
//----------------------------------------------------------------------------- |
|
bool CAI_Enemies::HasFreeKnowledgeOf( CBaseEntity *pEnemy ) |
|
{ |
|
// I've never seen something that doesn't exist |
|
if (!pEnemy) |
|
return 0; |
|
|
|
AI_EnemyInfo_t *pMemory = Find( pEnemy, true ); |
|
if ( pMemory ) |
|
{ |
|
float flFreeKnowledgeTime = pMemory->timeLastSeen + m_flFreeKnowledgeDuration; |
|
return ( gpGlobals->curtime < flFreeKnowledgeTime ); |
|
} |
|
|
|
if ( pEnemy != AI_UNKNOWN_ENEMY ) |
|
DevWarning( 2,"Asking HasFreeKnowledgeOf for enemy that's not in my memory!!\n"); |
|
return AI_INVALID_TIME; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
float CAI_Enemies::LastTimeTookDamageFrom( CBaseEntity *pEnemy) |
|
{ |
|
// I've never seen something that doesn't exist |
|
if (!pEnemy) |
|
return 0; |
|
|
|
AI_EnemyInfo_t *pMemory = Find( pEnemy, true ); |
|
if ( pMemory ) |
|
return pMemory->timeLastReceivedDamageFrom; |
|
|
|
if ( pEnemy != AI_UNKNOWN_ENEMY ) |
|
DevWarning( 2,"Asking LastTimeTookDamageFrom for enemy that's not in my memory!!\n"); |
|
return AI_INVALID_TIME; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Returns the time at which the enemy was first seen firsthand |
|
// Input : *pEnemy - |
|
// Output : float |
|
//----------------------------------------------------------------------------- |
|
float CAI_Enemies::TimeAtFirstHand( CBaseEntity *pEnemy ) |
|
{ |
|
// I've never seen something that doesn't exist |
|
if (!pEnemy) |
|
return 0; |
|
|
|
AI_EnemyInfo_t *pMemory = Find( pEnemy, true ); |
|
if ( pMemory ) |
|
return pMemory->timeAtFirstHand; |
|
|
|
if ( pEnemy != AI_UNKNOWN_ENEMY ) |
|
DevWarning( 2,"Asking TimeAtFirstHand for enemy that's not in my memory!!\n"); |
|
return AI_INVALID_TIME; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Sets position to the last known position of an enemy. If enemy |
|
// was not found returns last memory of danger position if it exists |
|
// Output : Returns false is no position is known |
|
//----------------------------------------------------------------------------- |
|
bool CAI_Enemies::HasEludedMe( CBaseEntity *pEnemy ) |
|
{ |
|
AI_EnemyInfo_t *pMemory = Find( pEnemy ); |
|
if ( pMemory ) |
|
return pMemory->bEludedMe; |
|
return false; |
|
} |
|
|
|
void CAI_Enemies::SetTimeValidEnemy( CBaseEntity *pEnemy, float flTime ) |
|
{ |
|
AI_EnemyInfo_t *pMemory = Find( pEnemy ); |
|
if ( pMemory ) |
|
pMemory->timeValidEnemy = flTime; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
void CAI_Enemies::SetUnforgettable( CBaseEntity *pEnemy, bool bUnforgettable ) |
|
{ |
|
AI_EnemyInfo_t *pMemory = Find( pEnemy ); |
|
if ( pMemory ) |
|
pMemory->bUnforgettable = bUnforgettable; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
void CAI_Enemies::SetMobbedMe( CBaseEntity *pEnemy, bool bMobbedMe ) |
|
{ |
|
AI_EnemyInfo_t *pMemory = Find( pEnemy ); |
|
if ( pMemory ) |
|
pMemory->bMobbedMe = bMobbedMe; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
|
|
void CAI_Enemies::SetFreeKnowledgeDuration( float flDuration ) |
|
{ |
|
m_flFreeKnowledgeDuration = flDuration; |
|
|
|
if ( m_flFreeKnowledgeDuration >= m_flEnemyDiscardTime ) |
|
{ |
|
// If your free knowledge time is greater than your discard time, |
|
// you'll forget about secondhand enemies passed to you by squadmates |
|
// as soon as you're given them. |
|
Assert( m_flFreeKnowledgeDuration < m_flEnemyDiscardTime ); |
|
|
|
m_flFreeKnowledgeDuration = m_flEnemyDiscardTime - .1; |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
|
|
void CAI_Enemies::SetEnemyDiscardTime( float flTime ) |
|
{ |
|
m_flEnemyDiscardTime = flTime; |
|
|
|
if ( m_flFreeKnowledgeDuration >= m_flEnemyDiscardTime ) |
|
{ |
|
// If your free knowledge time is greater than your discard time, |
|
// you'll forget about secondhand enemies passed to you by squadmates |
|
// as soon as you're given them. |
|
Assert( m_flFreeKnowledgeDuration < m_flEnemyDiscardTime ); |
|
|
|
m_flFreeKnowledgeDuration = m_flEnemyDiscardTime - .1; |
|
} |
|
}
|
|
|