diff options
| author | Jørgen P. Tjernø <[email protected]> | 2013-12-02 19:31:46 -0800 |
|---|---|---|
| committer | Jørgen P. Tjernø <[email protected]> | 2013-12-02 19:46:31 -0800 |
| commit | f56bb35301836e56582a575a75864392a0177875 (patch) | |
| tree | de61ddd39de3e7df52759711950b4c288592f0dc /mp/src/game/server/ai_memory.cpp | |
| parent | Mark some more files as text. (diff) | |
| download | source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.tar.xz source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.zip | |
Fix line endings. WHAMMY.
Diffstat (limited to 'mp/src/game/server/ai_memory.cpp')
| -rw-r--r-- | mp/src/game/server/ai_memory.cpp | 1312 |
1 files changed, 656 insertions, 656 deletions
diff --git a/mp/src/game/server/ai_memory.cpp b/mp/src/game/server/ai_memory.cpp index 2464a825..7ac69311 100644 --- a/mp/src/game/server/ai_memory.cpp +++ b/mp/src/game/server/ai_memory.cpp @@ -1,656 +1,656 @@ -//========= Copyright 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;
- 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( 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 && pEnemyNPC->GetState() == NPC_STATE_DEAD )
- 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 postion of an enmey of just a danger position
- pAddMemory->hEnemy = pEnemy;
- pAddMemory->bDangerMemory = ( pEnemy == NULL );
-
- // 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;
- }
-}
+//========= Copyright 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; + 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( 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 && pEnemyNPC->GetState() == NPC_STATE_DEAD ) + 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 postion of an enmey of just a danger position + pAddMemory->hEnemy = pEnemy; + pAddMemory->bDangerMemory = ( pEnemy == NULL ); + + // 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; + } +} |