aboutsummaryrefslogtreecommitdiff
path: root/mp/src/game/server/ai_relationship.cpp
diff options
context:
space:
mode:
authorJørgen P. Tjernø <[email protected]>2013-12-02 19:31:46 -0800
committerJørgen P. Tjernø <[email protected]>2013-12-02 19:46:31 -0800
commitf56bb35301836e56582a575a75864392a0177875 (patch)
treede61ddd39de3e7df52759711950b4c288592f0dc /mp/src/game/server/ai_relationship.cpp
parentMark some more files as text. (diff)
downloadsource-sdk-2013-f56bb35301836e56582a575a75864392a0177875.tar.xz
source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.zip
Fix line endings. WHAMMY.
Diffstat (limited to 'mp/src/game/server/ai_relationship.cpp')
-rw-r--r--mp/src/game/server/ai_relationship.cpp992
1 files changed, 496 insertions, 496 deletions
diff --git a/mp/src/game/server/ai_relationship.cpp b/mp/src/game/server/ai_relationship.cpp
index 884349bc..eec28d99 100644
--- a/mp/src/game/server/ai_relationship.cpp
+++ b/mp/src/game/server/ai_relationship.cpp
@@ -1,496 +1,496 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose: Entity which alters the relationships between entities via entity I/O
-//
-//=====================================================================================//
-
-#include "cbase.h"
-#include "ndebugoverlay.h"
-#include "ai_basenpc.h"
-
-// memdbgon must be the last include file in a .cpp file!!!
-#include "tier0/memdbgon.h"
-
-#define SF_RELATIONSHIP_NOTIFY_SUBJECT (1<<0) // Alert the subject of the change and give them a memory of the target entity
-#define SF_RELATIONSHIP_NOTIFY_TARGET (1<<1) // Alert the target of the change and give them a memory of the subject entity
-
-enum
-{
- NOT_REVERTING,
- REVERTING_TO_PREV,
- REVERTING_TO_DEFAULT,
-};
-
-//=========================================================
-//=========================================================
-class CAI_Relationship : public CBaseEntity, public IEntityListener
-{
- DECLARE_CLASS( CAI_Relationship, CBaseEntity );
-
-public:
- CAI_Relationship() : m_iPreviousDisposition( -1 ) { }
-
- void Spawn();
- void Activate();
-
- void SetActive( bool bActive );
- void ChangeRelationships( int disposition, int iReverting, CBaseEntity *pActivator = NULL, CBaseEntity *pCaller = NULL );
-
- void ApplyRelationship( CBaseEntity *pActivator = NULL, CBaseEntity *pCaller = NULL );
- void RevertRelationship( CBaseEntity *pActivator = NULL, CBaseEntity *pCaller = NULL );
- void RevertToDefaultRelationship( CBaseEntity *pActivator = NULL, CBaseEntity *pCaller = NULL );
-
- void UpdateOnRemove();
- void OnRestore();
-
- bool IsASubject( CBaseEntity *pEntity );
- bool IsATarget( CBaseEntity *pEntity );
-
- void OnEntitySpawned( CBaseEntity *pEntity );
- void OnEntityDeleted( CBaseEntity *pEntity );
-
-private:
-
- void ApplyRelationshipThink( void );
- CBaseEntity *FindEntityForProceduralName( string_t iszName, CBaseEntity *pActivator, CBaseEntity *pCaller );
- void DiscloseNPCLocation( CBaseCombatCharacter *pSubject, CBaseCombatCharacter *pTarget );
-
- string_t m_iszSubject;
- int m_iDisposition;
- int m_iRank;
- bool m_fStartActive;
- bool m_bIsActive;
- int m_iPreviousDisposition;
- float m_flRadius;
- int m_iPreviousRank;
- bool m_bReciprocal;
-
-public:
- // Input functions
- void InputApplyRelationship( inputdata_t &inputdata );
- void InputRevertRelationship( inputdata_t &inputdata );
- void InputRevertToDefaultRelationship( inputdata_t &inputdata );
-
- DECLARE_DATADESC();
-};
-
-LINK_ENTITY_TO_CLASS( ai_relationship, CAI_Relationship );
-
-BEGIN_DATADESC( CAI_Relationship )
- DEFINE_THINKFUNC( ApplyRelationshipThink ),
-
- DEFINE_KEYFIELD( m_iszSubject, FIELD_STRING, "subject" ),
- DEFINE_KEYFIELD( m_iDisposition, FIELD_INTEGER, "disposition" ),
- DEFINE_KEYFIELD( m_iRank, FIELD_INTEGER, "rank" ),
- DEFINE_KEYFIELD( m_fStartActive, FIELD_BOOLEAN, "StartActive" ),
- DEFINE_FIELD( m_bIsActive, FIELD_BOOLEAN ),
- DEFINE_KEYFIELD( m_flRadius, FIELD_FLOAT, "radius" ),
- DEFINE_FIELD( m_iPreviousDisposition, FIELD_INTEGER ),
- DEFINE_FIELD( m_iPreviousRank, FIELD_INTEGER ),
- DEFINE_KEYFIELD( m_bReciprocal, FIELD_BOOLEAN, "reciprocal" ),
-
- // Inputs
- DEFINE_INPUTFUNC( FIELD_VOID, "ApplyRelationship", InputApplyRelationship ),
- DEFINE_INPUTFUNC( FIELD_VOID, "RevertRelationship", InputRevertRelationship ),
- DEFINE_INPUTFUNC( FIELD_VOID, "RevertToDefaultRelationship", InputRevertToDefaultRelationship ),
-END_DATADESC()
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void CAI_Relationship::Spawn()
-{
- m_bIsActive = false;
-
- if (m_iszSubject == NULL_STRING)
- {
- DevWarning("ai_relationship '%s' with no subject specified, removing.\n", GetDebugName());
- UTIL_Remove(this);
- }
- else if (m_target == NULL_STRING)
- {
- DevWarning("ai_relationship '%s' with no target specified, removing.\n", GetDebugName());
- UTIL_Remove(this);
- }
-}
-
-//---------------------------------------------------------
-//---------------------------------------------------------
-void CAI_Relationship::Activate()
-{
- if ( m_fStartActive )
- {
- ApplyRelationship();
-
- // Clear this flag so that nothing happens when the level is loaded (which calls activate again)
- m_fStartActive = false;
- }
-
- BaseClass::Activate();
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : bActive -
-//-----------------------------------------------------------------------------
-void CAI_Relationship::SetActive( bool bActive )
-{
- if ( bActive && !m_bIsActive )
- {
- // Start getting entity updates!
- gEntList.AddListenerEntity( this );
- }
- else if ( !bActive && m_bIsActive )
- {
- // Stop getting entity updates!
- gEntList.RemoveListenerEntity( this );
- }
-
- m_bIsActive = bActive;
-}
-
-//---------------------------------------------------------
-//---------------------------------------------------------
-void CAI_Relationship::InputApplyRelationship( inputdata_t &inputdata )
-{
- ApplyRelationship( inputdata.pActivator, inputdata.pCaller );
-}
-
-//---------------------------------------------------------
-//---------------------------------------------------------
-void CAI_Relationship::InputRevertRelationship( inputdata_t &inputdata )
-{
- RevertRelationship( inputdata.pActivator, inputdata.pCaller );
-}
-
-//---------------------------------------------------------
-//---------------------------------------------------------
-void CAI_Relationship::InputRevertToDefaultRelationship( inputdata_t &inputdata )
-{
- RevertToDefaultRelationship( inputdata.pActivator, inputdata.pCaller );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: This think function is used to wait until the player has properly
-// spawned, after all the NPCs have spawned. Once that occurs, this
-// function terminates.
-//-----------------------------------------------------------------------------
-void CAI_Relationship::ApplyRelationshipThink( void )
-{
- // Call down to the base until the player has properly spawned
- ApplyRelationship();
-}
-
-//---------------------------------------------------------
-// Purpose: Applies the desired relationships to an entity
-//---------------------------------------------------------
-void CAI_Relationship::ApplyRelationship( CBaseEntity *pActivator, CBaseEntity *pCaller )
-{
- // @TODO (toml 10-22-04): sort out MP relationships
-
- // The player spawns slightly after the NPCs, meaning that if we don't wait, the
- // player will miss any relationships placed on them.
- if ( AI_IsSinglePlayer() && !UTIL_GetLocalPlayer() )
- {
- SetThink( &CAI_Relationship::ApplyRelationshipThink );
- SetNextThink( gpGlobals->curtime );
- }
-
- if ( !m_bIsActive )
- {
- SetActive( true );
- }
-
- ChangeRelationships( m_iDisposition, NOT_REVERTING, pActivator, pCaller );
-}
-
-//---------------------------------------------------------
-//---------------------------------------------------------
-void CAI_Relationship::RevertRelationship( CBaseEntity *pActivator, CBaseEntity *pCaller )
-{
- if ( m_bIsActive )
- {
- ChangeRelationships( m_iPreviousDisposition, REVERTING_TO_PREV, pActivator, pCaller );
- SetActive( false );
- }
-}
-
-//---------------------------------------------------------
-//---------------------------------------------------------
-void CAI_Relationship::RevertToDefaultRelationship( CBaseEntity *pActivator, CBaseEntity *pCaller )
-{
- if ( m_bIsActive )
- {
- ChangeRelationships( -1, REVERTING_TO_DEFAULT, pActivator, pCaller );
- SetActive( false );
- }
-}
-
-//---------------------------------------------------------
-//---------------------------------------------------------
-void CAI_Relationship::UpdateOnRemove()
-{
- gEntList.RemoveListenerEntity( this );
- // @TODO (toml 07-21-04): Should this actually revert on kill?
- // RevertRelationship();
- BaseClass::UpdateOnRemove();
-}
-
-//---------------------------------------------------------
-//---------------------------------------------------------
-void CAI_Relationship::OnRestore()
-{
- BaseClass::OnRestore();
- if ( m_bIsActive )
- {
- gEntList.AddListenerEntity( this );
- }
-}
-
-
-//---------------------------------------------------------
-//---------------------------------------------------------
-bool CAI_Relationship::IsASubject( CBaseEntity *pEntity )
-{
- if( pEntity->NameMatches( m_iszSubject ) )
- return true;
-
- if( pEntity->ClassMatches( m_iszSubject ) )
- return true;
-
- return false;
-}
-
-//---------------------------------------------------------
-//---------------------------------------------------------
-bool CAI_Relationship::IsATarget( CBaseEntity *pEntity )
-{
- if( pEntity->NameMatches( m_target ) )
- return true;
-
- if( pEntity->ClassMatches( m_target ) )
- return true;
-
- return false;
-}
-
-//---------------------------------------------------------
-//---------------------------------------------------------
-void CAI_Relationship::OnEntitySpawned( CBaseEntity *pEntity )
-{
- // NOTE: This cannot use the procedural entity finding code since that only occurs on
- // inputs and not passively.
-
- if ( IsATarget( pEntity ) || IsASubject( pEntity ) )
- {
- ApplyRelationship();
- }
-}
-
-//---------------------------------------------------------
-//---------------------------------------------------------
-void CAI_Relationship::OnEntityDeleted( CBaseEntity *pEntity )
-{
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Translate special tokens for inputs
-// Input : iszName - Name to check
-// *pActivator - Activator
-// *pCaller - Caller
-// Output : CBaseEntity - Entity that matches (NULL if none)
-//-----------------------------------------------------------------------------
-#define ACTIVATOR_KEYNAME "!activator"
-#define CALLER_KEYNAME "!caller"
-
-CBaseEntity *CAI_Relationship::FindEntityForProceduralName( string_t iszName, CBaseEntity *pActivator, CBaseEntity *pCaller )
-{
- // Handle the activator token
- if ( iszName == AllocPooledString( ACTIVATOR_KEYNAME ) )
- return pActivator;
-
- // Handle the caller token
- if ( iszName == AllocPooledString( CALLER_KEYNAME ) )
- return pCaller;
-
- return NULL;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Disclose the location of the target entity to the subject via a memory
-// Input : *pSubject - Entity to gain the memory of the target's location
-// *pTarget - Entity who's location will be disclosed
-//-----------------------------------------------------------------------------
-void CAI_Relationship::DiscloseNPCLocation( CBaseCombatCharacter *pSubject, CBaseCombatCharacter *pTarget )
-{
- if ( pSubject == NULL || pTarget == NULL )
- return;
-
- CAI_BaseNPC *pNPC = pSubject->MyNPCPointer();
- if ( pNPC != NULL )
- {
- pNPC->UpdateEnemyMemory( pTarget, pTarget->GetAbsOrigin() );
- }
-}
-
-//---------------------------------------------------------
-//---------------------------------------------------------
-void CAI_Relationship::ChangeRelationships( int disposition, int iReverting, CBaseEntity *pActivator, CBaseEntity *pCaller )
-{
- if( iReverting != NOT_REVERTING && m_iPreviousDisposition == -1 )
- {
- // Trying to revert without having ever set the relationships!
- DevMsg( 2, "ai_relationship cannot revert changes before they are applied!\n");
- return;
- }
-
- const int MAX_HANDLED = 512;
- CUtlVectorFixed<CBaseCombatCharacter *, MAX_HANDLED> subjectList;
- CUtlVectorFixed<CBaseCombatCharacter *, MAX_HANDLED> targetList;
-
- // Add any special subjects we found
- CBaseEntity *pSpecialSubject = FindEntityForProceduralName( m_iszSubject, pActivator, pCaller );
- if ( pSpecialSubject && pSpecialSubject->MyCombatCharacterPointer() )
- {
- subjectList.AddToTail( pSpecialSubject->MyCombatCharacterPointer() );
- }
-
- // Add any special targets we found
- CBaseEntity *pSpecialTarget = FindEntityForProceduralName( m_target, pActivator, pCaller );
- if ( pSpecialTarget && pSpecialTarget->MyCombatCharacterPointer() )
- {
- targetList.AddToTail( pSpecialTarget->MyCombatCharacterPointer() );
- }
-
- // -------------------------------
- // Search for targets and subjects
- // -------------------------------
-
- float radiusSq = Square( m_flRadius );
-
- // Search players first
- for ( int i = 1; i <= gpGlobals->maxClients; i++ )
- {
- if ( subjectList.Count() == MAX_HANDLED || targetList.Count() == MAX_HANDLED )
- {
- DevMsg( "Too many entities handled by ai_relationship %s\n", GetDebugName() );
- break;
- }
-
- CBasePlayer *pPlayer = UTIL_PlayerByIndex( i );
- if ( pPlayer )
- {
- if( IsASubject( pPlayer ) )
- {
- if ( m_flRadius == 0.0 || GetAbsOrigin().DistToSqr( pPlayer->GetAbsOrigin() ) <= radiusSq )
- subjectList.AddToTail( pPlayer );
- }
- else if( IsATarget( pPlayer ) )
- {
- targetList.AddToTail( pPlayer );
- }
- }
- }
-
- // Search NPCs
- for ( int i = 0; i < g_AI_Manager.NumAIs(); i++ )
- {
- if ( subjectList.Count() == MAX_HANDLED || targetList.Count() == MAX_HANDLED )
- {
- DevMsg( "Too many entities handled by ai_relationship %s\n", GetDebugName() );
- break;
- }
-
- CAI_BaseNPC *pNPC = (g_AI_Manager.AccessAIs())[i];
- if ( pNPC )
- {
- if( IsASubject( pNPC ) )
- {
- if ( m_flRadius == 0.0 || GetAbsOrigin().DistToSqr( pNPC->GetAbsOrigin() ) <= radiusSq )
- subjectList.AddToTail( pNPC );
- }
- else if( IsATarget( pNPC ) )
- {
- targetList.AddToTail( pNPC );
- }
- }
- }
-
- // If either list is still empty, we have a problem.
- if( subjectList.Count() == 0 )
- {
- DevMsg( 2, "ai_relationship '%s' finds no subject(s) called: %s\n", GetDebugName(), STRING( m_iszSubject ) );
- return;
- }
- else if ( targetList.Count() == 0 )
- {
- DevMsg( 2, "ai_relationship '%s' finds no target(s) called: %s\n", GetDebugName(), STRING( m_target ) );
- return;
- }
-
- // Ok, lists are populated. Apply all relationships.
- for ( int i = 0 ; i < subjectList.Count(); i++ )
- {
- CBaseCombatCharacter *pSubject = subjectList[ i ];
-
- for ( int j = 0 ; j < targetList.Count(); j++ )
- {
- CBaseCombatCharacter *pTarget = targetList[ j ];
-
- if ( m_iPreviousDisposition == -1 && iReverting == NOT_REVERTING )
- {
- // Set previous disposition.
- m_iPreviousDisposition = pSubject->IRelationType( pTarget );
- m_iPreviousRank = pSubject->IRelationPriority( pTarget );
- }
-
- if ( iReverting == REVERTING_TO_PREV )
- {
- pSubject->AddEntityRelationship( pTarget, (Disposition_t)m_iPreviousDisposition, m_iPreviousRank );
-
- if( m_bReciprocal )
- {
- pTarget->AddEntityRelationship( pSubject, (Disposition_t)m_iPreviousDisposition, m_iPreviousRank );
- }
- }
- else if ( iReverting == REVERTING_TO_DEFAULT )
- {
- pSubject->RemoveEntityRelationship( pTarget );
-
- if( m_bReciprocal )
- {
- pTarget->RemoveEntityRelationship( pSubject );
- }
- }
- else if( pSubject->IRelationType(pTarget) != disposition ||
- pSubject->IRelationPriority(pTarget) != m_iRank ||
- HasSpawnFlags( SF_RELATIONSHIP_NOTIFY_SUBJECT ) ||
- HasSpawnFlags( SF_RELATIONSHIP_NOTIFY_TARGET ) )
- {
- // Apply the relationship to the subject
- pSubject->AddEntityRelationship( pTarget, (Disposition_t)disposition, m_iRank );
-
- // Make the subject aware of the target
- if ( HasSpawnFlags( SF_RELATIONSHIP_NOTIFY_SUBJECT ) )
- {
- DiscloseNPCLocation( pSubject, pTarget );
- }
-
- // Make the target aware of the subject
- if ( HasSpawnFlags( SF_RELATIONSHIP_NOTIFY_TARGET ) )
- {
- DiscloseNPCLocation( pTarget, pSubject );
- }
-
- // This relationship is applied to target and subject alike
- if ( m_bReciprocal )
- {
- // Apply the relationship to the target
- pTarget->AddEntityRelationship( pSubject, (Disposition_t)disposition, m_iRank );
- }
- }
- }
- }
-}
-
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Entity which alters the relationships between entities via entity I/O
+//
+//=====================================================================================//
+
+#include "cbase.h"
+#include "ndebugoverlay.h"
+#include "ai_basenpc.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+#define SF_RELATIONSHIP_NOTIFY_SUBJECT (1<<0) // Alert the subject of the change and give them a memory of the target entity
+#define SF_RELATIONSHIP_NOTIFY_TARGET (1<<1) // Alert the target of the change and give them a memory of the subject entity
+
+enum
+{
+ NOT_REVERTING,
+ REVERTING_TO_PREV,
+ REVERTING_TO_DEFAULT,
+};
+
+//=========================================================
+//=========================================================
+class CAI_Relationship : public CBaseEntity, public IEntityListener
+{
+ DECLARE_CLASS( CAI_Relationship, CBaseEntity );
+
+public:
+ CAI_Relationship() : m_iPreviousDisposition( -1 ) { }
+
+ void Spawn();
+ void Activate();
+
+ void SetActive( bool bActive );
+ void ChangeRelationships( int disposition, int iReverting, CBaseEntity *pActivator = NULL, CBaseEntity *pCaller = NULL );
+
+ void ApplyRelationship( CBaseEntity *pActivator = NULL, CBaseEntity *pCaller = NULL );
+ void RevertRelationship( CBaseEntity *pActivator = NULL, CBaseEntity *pCaller = NULL );
+ void RevertToDefaultRelationship( CBaseEntity *pActivator = NULL, CBaseEntity *pCaller = NULL );
+
+ void UpdateOnRemove();
+ void OnRestore();
+
+ bool IsASubject( CBaseEntity *pEntity );
+ bool IsATarget( CBaseEntity *pEntity );
+
+ void OnEntitySpawned( CBaseEntity *pEntity );
+ void OnEntityDeleted( CBaseEntity *pEntity );
+
+private:
+
+ void ApplyRelationshipThink( void );
+ CBaseEntity *FindEntityForProceduralName( string_t iszName, CBaseEntity *pActivator, CBaseEntity *pCaller );
+ void DiscloseNPCLocation( CBaseCombatCharacter *pSubject, CBaseCombatCharacter *pTarget );
+
+ string_t m_iszSubject;
+ int m_iDisposition;
+ int m_iRank;
+ bool m_fStartActive;
+ bool m_bIsActive;
+ int m_iPreviousDisposition;
+ float m_flRadius;
+ int m_iPreviousRank;
+ bool m_bReciprocal;
+
+public:
+ // Input functions
+ void InputApplyRelationship( inputdata_t &inputdata );
+ void InputRevertRelationship( inputdata_t &inputdata );
+ void InputRevertToDefaultRelationship( inputdata_t &inputdata );
+
+ DECLARE_DATADESC();
+};
+
+LINK_ENTITY_TO_CLASS( ai_relationship, CAI_Relationship );
+
+BEGIN_DATADESC( CAI_Relationship )
+ DEFINE_THINKFUNC( ApplyRelationshipThink ),
+
+ DEFINE_KEYFIELD( m_iszSubject, FIELD_STRING, "subject" ),
+ DEFINE_KEYFIELD( m_iDisposition, FIELD_INTEGER, "disposition" ),
+ DEFINE_KEYFIELD( m_iRank, FIELD_INTEGER, "rank" ),
+ DEFINE_KEYFIELD( m_fStartActive, FIELD_BOOLEAN, "StartActive" ),
+ DEFINE_FIELD( m_bIsActive, FIELD_BOOLEAN ),
+ DEFINE_KEYFIELD( m_flRadius, FIELD_FLOAT, "radius" ),
+ DEFINE_FIELD( m_iPreviousDisposition, FIELD_INTEGER ),
+ DEFINE_FIELD( m_iPreviousRank, FIELD_INTEGER ),
+ DEFINE_KEYFIELD( m_bReciprocal, FIELD_BOOLEAN, "reciprocal" ),
+
+ // Inputs
+ DEFINE_INPUTFUNC( FIELD_VOID, "ApplyRelationship", InputApplyRelationship ),
+ DEFINE_INPUTFUNC( FIELD_VOID, "RevertRelationship", InputRevertRelationship ),
+ DEFINE_INPUTFUNC( FIELD_VOID, "RevertToDefaultRelationship", InputRevertToDefaultRelationship ),
+END_DATADESC()
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CAI_Relationship::Spawn()
+{
+ m_bIsActive = false;
+
+ if (m_iszSubject == NULL_STRING)
+ {
+ DevWarning("ai_relationship '%s' with no subject specified, removing.\n", GetDebugName());
+ UTIL_Remove(this);
+ }
+ else if (m_target == NULL_STRING)
+ {
+ DevWarning("ai_relationship '%s' with no target specified, removing.\n", GetDebugName());
+ UTIL_Remove(this);
+ }
+}
+
+//---------------------------------------------------------
+//---------------------------------------------------------
+void CAI_Relationship::Activate()
+{
+ if ( m_fStartActive )
+ {
+ ApplyRelationship();
+
+ // Clear this flag so that nothing happens when the level is loaded (which calls activate again)
+ m_fStartActive = false;
+ }
+
+ BaseClass::Activate();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : bActive -
+//-----------------------------------------------------------------------------
+void CAI_Relationship::SetActive( bool bActive )
+{
+ if ( bActive && !m_bIsActive )
+ {
+ // Start getting entity updates!
+ gEntList.AddListenerEntity( this );
+ }
+ else if ( !bActive && m_bIsActive )
+ {
+ // Stop getting entity updates!
+ gEntList.RemoveListenerEntity( this );
+ }
+
+ m_bIsActive = bActive;
+}
+
+//---------------------------------------------------------
+//---------------------------------------------------------
+void CAI_Relationship::InputApplyRelationship( inputdata_t &inputdata )
+{
+ ApplyRelationship( inputdata.pActivator, inputdata.pCaller );
+}
+
+//---------------------------------------------------------
+//---------------------------------------------------------
+void CAI_Relationship::InputRevertRelationship( inputdata_t &inputdata )
+{
+ RevertRelationship( inputdata.pActivator, inputdata.pCaller );
+}
+
+//---------------------------------------------------------
+//---------------------------------------------------------
+void CAI_Relationship::InputRevertToDefaultRelationship( inputdata_t &inputdata )
+{
+ RevertToDefaultRelationship( inputdata.pActivator, inputdata.pCaller );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: This think function is used to wait until the player has properly
+// spawned, after all the NPCs have spawned. Once that occurs, this
+// function terminates.
+//-----------------------------------------------------------------------------
+void CAI_Relationship::ApplyRelationshipThink( void )
+{
+ // Call down to the base until the player has properly spawned
+ ApplyRelationship();
+}
+
+//---------------------------------------------------------
+// Purpose: Applies the desired relationships to an entity
+//---------------------------------------------------------
+void CAI_Relationship::ApplyRelationship( CBaseEntity *pActivator, CBaseEntity *pCaller )
+{
+ // @TODO (toml 10-22-04): sort out MP relationships
+
+ // The player spawns slightly after the NPCs, meaning that if we don't wait, the
+ // player will miss any relationships placed on them.
+ if ( AI_IsSinglePlayer() && !UTIL_GetLocalPlayer() )
+ {
+ SetThink( &CAI_Relationship::ApplyRelationshipThink );
+ SetNextThink( gpGlobals->curtime );
+ }
+
+ if ( !m_bIsActive )
+ {
+ SetActive( true );
+ }
+
+ ChangeRelationships( m_iDisposition, NOT_REVERTING, pActivator, pCaller );
+}
+
+//---------------------------------------------------------
+//---------------------------------------------------------
+void CAI_Relationship::RevertRelationship( CBaseEntity *pActivator, CBaseEntity *pCaller )
+{
+ if ( m_bIsActive )
+ {
+ ChangeRelationships( m_iPreviousDisposition, REVERTING_TO_PREV, pActivator, pCaller );
+ SetActive( false );
+ }
+}
+
+//---------------------------------------------------------
+//---------------------------------------------------------
+void CAI_Relationship::RevertToDefaultRelationship( CBaseEntity *pActivator, CBaseEntity *pCaller )
+{
+ if ( m_bIsActive )
+ {
+ ChangeRelationships( -1, REVERTING_TO_DEFAULT, pActivator, pCaller );
+ SetActive( false );
+ }
+}
+
+//---------------------------------------------------------
+//---------------------------------------------------------
+void CAI_Relationship::UpdateOnRemove()
+{
+ gEntList.RemoveListenerEntity( this );
+ // @TODO (toml 07-21-04): Should this actually revert on kill?
+ // RevertRelationship();
+ BaseClass::UpdateOnRemove();
+}
+
+//---------------------------------------------------------
+//---------------------------------------------------------
+void CAI_Relationship::OnRestore()
+{
+ BaseClass::OnRestore();
+ if ( m_bIsActive )
+ {
+ gEntList.AddListenerEntity( this );
+ }
+}
+
+
+//---------------------------------------------------------
+//---------------------------------------------------------
+bool CAI_Relationship::IsASubject( CBaseEntity *pEntity )
+{
+ if( pEntity->NameMatches( m_iszSubject ) )
+ return true;
+
+ if( pEntity->ClassMatches( m_iszSubject ) )
+ return true;
+
+ return false;
+}
+
+//---------------------------------------------------------
+//---------------------------------------------------------
+bool CAI_Relationship::IsATarget( CBaseEntity *pEntity )
+{
+ if( pEntity->NameMatches( m_target ) )
+ return true;
+
+ if( pEntity->ClassMatches( m_target ) )
+ return true;
+
+ return false;
+}
+
+//---------------------------------------------------------
+//---------------------------------------------------------
+void CAI_Relationship::OnEntitySpawned( CBaseEntity *pEntity )
+{
+ // NOTE: This cannot use the procedural entity finding code since that only occurs on
+ // inputs and not passively.
+
+ if ( IsATarget( pEntity ) || IsASubject( pEntity ) )
+ {
+ ApplyRelationship();
+ }
+}
+
+//---------------------------------------------------------
+//---------------------------------------------------------
+void CAI_Relationship::OnEntityDeleted( CBaseEntity *pEntity )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Translate special tokens for inputs
+// Input : iszName - Name to check
+// *pActivator - Activator
+// *pCaller - Caller
+// Output : CBaseEntity - Entity that matches (NULL if none)
+//-----------------------------------------------------------------------------
+#define ACTIVATOR_KEYNAME "!activator"
+#define CALLER_KEYNAME "!caller"
+
+CBaseEntity *CAI_Relationship::FindEntityForProceduralName( string_t iszName, CBaseEntity *pActivator, CBaseEntity *pCaller )
+{
+ // Handle the activator token
+ if ( iszName == AllocPooledString( ACTIVATOR_KEYNAME ) )
+ return pActivator;
+
+ // Handle the caller token
+ if ( iszName == AllocPooledString( CALLER_KEYNAME ) )
+ return pCaller;
+
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Disclose the location of the target entity to the subject via a memory
+// Input : *pSubject - Entity to gain the memory of the target's location
+// *pTarget - Entity who's location will be disclosed
+//-----------------------------------------------------------------------------
+void CAI_Relationship::DiscloseNPCLocation( CBaseCombatCharacter *pSubject, CBaseCombatCharacter *pTarget )
+{
+ if ( pSubject == NULL || pTarget == NULL )
+ return;
+
+ CAI_BaseNPC *pNPC = pSubject->MyNPCPointer();
+ if ( pNPC != NULL )
+ {
+ pNPC->UpdateEnemyMemory( pTarget, pTarget->GetAbsOrigin() );
+ }
+}
+
+//---------------------------------------------------------
+//---------------------------------------------------------
+void CAI_Relationship::ChangeRelationships( int disposition, int iReverting, CBaseEntity *pActivator, CBaseEntity *pCaller )
+{
+ if( iReverting != NOT_REVERTING && m_iPreviousDisposition == -1 )
+ {
+ // Trying to revert without having ever set the relationships!
+ DevMsg( 2, "ai_relationship cannot revert changes before they are applied!\n");
+ return;
+ }
+
+ const int MAX_HANDLED = 512;
+ CUtlVectorFixed<CBaseCombatCharacter *, MAX_HANDLED> subjectList;
+ CUtlVectorFixed<CBaseCombatCharacter *, MAX_HANDLED> targetList;
+
+ // Add any special subjects we found
+ CBaseEntity *pSpecialSubject = FindEntityForProceduralName( m_iszSubject, pActivator, pCaller );
+ if ( pSpecialSubject && pSpecialSubject->MyCombatCharacterPointer() )
+ {
+ subjectList.AddToTail( pSpecialSubject->MyCombatCharacterPointer() );
+ }
+
+ // Add any special targets we found
+ CBaseEntity *pSpecialTarget = FindEntityForProceduralName( m_target, pActivator, pCaller );
+ if ( pSpecialTarget && pSpecialTarget->MyCombatCharacterPointer() )
+ {
+ targetList.AddToTail( pSpecialTarget->MyCombatCharacterPointer() );
+ }
+
+ // -------------------------------
+ // Search for targets and subjects
+ // -------------------------------
+
+ float radiusSq = Square( m_flRadius );
+
+ // Search players first
+ for ( int i = 1; i <= gpGlobals->maxClients; i++ )
+ {
+ if ( subjectList.Count() == MAX_HANDLED || targetList.Count() == MAX_HANDLED )
+ {
+ DevMsg( "Too many entities handled by ai_relationship %s\n", GetDebugName() );
+ break;
+ }
+
+ CBasePlayer *pPlayer = UTIL_PlayerByIndex( i );
+ if ( pPlayer )
+ {
+ if( IsASubject( pPlayer ) )
+ {
+ if ( m_flRadius == 0.0 || GetAbsOrigin().DistToSqr( pPlayer->GetAbsOrigin() ) <= radiusSq )
+ subjectList.AddToTail( pPlayer );
+ }
+ else if( IsATarget( pPlayer ) )
+ {
+ targetList.AddToTail( pPlayer );
+ }
+ }
+ }
+
+ // Search NPCs
+ for ( int i = 0; i < g_AI_Manager.NumAIs(); i++ )
+ {
+ if ( subjectList.Count() == MAX_HANDLED || targetList.Count() == MAX_HANDLED )
+ {
+ DevMsg( "Too many entities handled by ai_relationship %s\n", GetDebugName() );
+ break;
+ }
+
+ CAI_BaseNPC *pNPC = (g_AI_Manager.AccessAIs())[i];
+ if ( pNPC )
+ {
+ if( IsASubject( pNPC ) )
+ {
+ if ( m_flRadius == 0.0 || GetAbsOrigin().DistToSqr( pNPC->GetAbsOrigin() ) <= radiusSq )
+ subjectList.AddToTail( pNPC );
+ }
+ else if( IsATarget( pNPC ) )
+ {
+ targetList.AddToTail( pNPC );
+ }
+ }
+ }
+
+ // If either list is still empty, we have a problem.
+ if( subjectList.Count() == 0 )
+ {
+ DevMsg( 2, "ai_relationship '%s' finds no subject(s) called: %s\n", GetDebugName(), STRING( m_iszSubject ) );
+ return;
+ }
+ else if ( targetList.Count() == 0 )
+ {
+ DevMsg( 2, "ai_relationship '%s' finds no target(s) called: %s\n", GetDebugName(), STRING( m_target ) );
+ return;
+ }
+
+ // Ok, lists are populated. Apply all relationships.
+ for ( int i = 0 ; i < subjectList.Count(); i++ )
+ {
+ CBaseCombatCharacter *pSubject = subjectList[ i ];
+
+ for ( int j = 0 ; j < targetList.Count(); j++ )
+ {
+ CBaseCombatCharacter *pTarget = targetList[ j ];
+
+ if ( m_iPreviousDisposition == -1 && iReverting == NOT_REVERTING )
+ {
+ // Set previous disposition.
+ m_iPreviousDisposition = pSubject->IRelationType( pTarget );
+ m_iPreviousRank = pSubject->IRelationPriority( pTarget );
+ }
+
+ if ( iReverting == REVERTING_TO_PREV )
+ {
+ pSubject->AddEntityRelationship( pTarget, (Disposition_t)m_iPreviousDisposition, m_iPreviousRank );
+
+ if( m_bReciprocal )
+ {
+ pTarget->AddEntityRelationship( pSubject, (Disposition_t)m_iPreviousDisposition, m_iPreviousRank );
+ }
+ }
+ else if ( iReverting == REVERTING_TO_DEFAULT )
+ {
+ pSubject->RemoveEntityRelationship( pTarget );
+
+ if( m_bReciprocal )
+ {
+ pTarget->RemoveEntityRelationship( pSubject );
+ }
+ }
+ else if( pSubject->IRelationType(pTarget) != disposition ||
+ pSubject->IRelationPriority(pTarget) != m_iRank ||
+ HasSpawnFlags( SF_RELATIONSHIP_NOTIFY_SUBJECT ) ||
+ HasSpawnFlags( SF_RELATIONSHIP_NOTIFY_TARGET ) )
+ {
+ // Apply the relationship to the subject
+ pSubject->AddEntityRelationship( pTarget, (Disposition_t)disposition, m_iRank );
+
+ // Make the subject aware of the target
+ if ( HasSpawnFlags( SF_RELATIONSHIP_NOTIFY_SUBJECT ) )
+ {
+ DiscloseNPCLocation( pSubject, pTarget );
+ }
+
+ // Make the target aware of the subject
+ if ( HasSpawnFlags( SF_RELATIONSHIP_NOTIFY_TARGET ) )
+ {
+ DiscloseNPCLocation( pTarget, pSubject );
+ }
+
+ // This relationship is applied to target and subject alike
+ if ( m_bReciprocal )
+ {
+ // Apply the relationship to the target
+ pTarget->AddEntityRelationship( pSubject, (Disposition_t)disposition, m_iRank );
+ }
+ }
+ }
+ }
+}
+