//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // //=============================================================================// #include "cbase.h" #include "utlrbtree.h" #include "saverestore_utlvector.h" #include "ai_goalentity.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" //----------------------------------------------------------------------------- // // CAI_GoalEntity implementation // BEGIN_DATADESC( CAI_GoalEntity ) DEFINE_KEYFIELD( m_iszActor, FIELD_STRING, "Actor" ), DEFINE_KEYFIELD( m_iszGoal, FIELD_STRING, "Goal" ), DEFINE_KEYFIELD( m_fStartActive, FIELD_BOOLEAN, "StartActive" ), DEFINE_KEYFIELD( m_iszConceptModifiers, FIELD_STRING, "BaseConceptModifiers" ), DEFINE_KEYFIELD( m_SearchType, FIELD_INTEGER, "SearchType" ), DEFINE_UTLVECTOR( m_actors, FIELD_EHANDLE ), DEFINE_FIELD( m_hGoalEntity, FIELD_EHANDLE ), DEFINE_FIELD( m_flags, FIELD_INTEGER ), DEFINE_THINKFUNC( DelayedRefresh ), // Inputs DEFINE_INPUTFUNC( FIELD_VOID, "Activate", InputActivate ), DEFINE_INPUTFUNC( FIELD_VOID, "UpdateActors", InputUpdateActors ), DEFINE_INPUTFUNC( FIELD_VOID, "Deactivate", InputDeactivate ), END_DATADESC() //------------------------------------- void CAI_GoalEntity::Spawn() { SetContextThink( &CAI_GoalEntity::DelayedRefresh, gpGlobals->curtime + 0.1f, "Refresh" ); } //------------------------------------- void CAI_GoalEntity::OnRestore() { BaseClass::OnRestore(); ExitDormant(); if ( ( m_flags & ACTIVE ) ) gEntList.AddListenerEntity( this ); } //------------------------------------- void CAI_GoalEntity::DelayedRefresh() { inputdata_t ignored; if ( m_fStartActive ) { Assert( !(m_flags & ACTIVE) ); InputActivate( ignored ); m_fStartActive = false; } else InputUpdateActors( ignored ); SetContextThink( NULL, 0, "Refresh" ); } //------------------------------------- void CAI_GoalEntity::PruneActors() { for ( int i = m_actors.Count() - 1; i >= 0; i-- ) { if ( m_actors[i] == NULL || m_actors[i]->IsMarkedForDeletion() || m_actors[i]->GetState() == NPC_STATE_DEAD ) m_actors.FastRemove( i ); } } //------------------------------------- void CAI_GoalEntity::ResolveNames() { m_actors.SetCount( 0 ); CBaseEntity *pEntity = NULL; for (;;) { switch ( m_SearchType ) { case ST_ENTNAME: { pEntity = gEntList.FindEntityByName( pEntity, m_iszActor ); break; } case ST_CLASSNAME: { pEntity = gEntList.FindEntityByClassname( pEntity, STRING( m_iszActor ) ); break; } } if ( !pEntity ) break; CAI_BaseNPC *pActor = pEntity->MyNPCPointer(); if ( pActor && pActor->GetState() != NPC_STATE_DEAD ) { AIHANDLE temp; temp = pActor; m_actors.AddToTail( temp ); } } m_hGoalEntity = gEntList.FindEntityByName( NULL, m_iszGoal ); } //------------------------------------- void CAI_GoalEntity::InputActivate( inputdata_t &inputdata ) { if ( !( m_flags & ACTIVE ) ) { OnActivate(); gEntList.AddListenerEntity( this ); UpdateActors(); m_flags |= ACTIVE; for ( int i = 0; i < m_actors.Count(); i++ ) { EnableGoal( m_actors[i] ); } } } //------------------------------------- void CAI_GoalEntity::InputUpdateActors( inputdata_t &inputdata ) { int i; CUtlRBTree prevActors; CUtlRBTree::IndexType_t index; SetDefLessFunc( prevActors ); PruneActors(); for ( i = 0; i < m_actors.Count(); i++ ) { prevActors.Insert( m_actors[i] ); } ResolveNames(); for ( i = 0; i < m_actors.Count(); i++ ) { index = prevActors.Find( m_actors[i] ); if ( index == prevActors.InvalidIndex() ) { if ( m_flags & ACTIVE ) EnableGoal( m_actors[i] ); } else prevActors.Remove( m_actors[i] ); } for ( index = prevActors.FirstInorder(); index != prevActors.InvalidIndex(); index = prevActors.NextInorder( index ) ) { if ( m_flags & ACTIVE ) DisableGoal( prevActors[ index ] ); } } //------------------------------------- void CAI_GoalEntity::InputDeactivate( inputdata_t &inputdata ) { if ( m_flags & ACTIVE ) { OnDeactivate(); gEntList.RemoveListenerEntity( this ); UpdateActors(); m_flags &= ~ACTIVE; for ( int i = 0; i < m_actors.Count(); i++ ) { DisableGoal( m_actors[i] ); } } } //------------------------------------- void CAI_GoalEntity::EnterDormant( void ) { if ( m_flags & ACTIVE ) { m_flags |= DORMANT; for ( int i = 0; i < m_actors.Count(); i++ ) { DisableGoal( m_actors[i] ); } } } //------------------------------------- void CAI_GoalEntity::ExitDormant( void ) { if ( m_flags & DORMANT ) { m_flags &= ~DORMANT; inputdata_t ignored; InputUpdateActors( ignored ); } } //------------------------------------- void CAI_GoalEntity::UpdateOnRemove() { if ( m_flags & ACTIVE ) { inputdata_t inputdata; InputDeactivate( inputdata ); } BaseClass::UpdateOnRemove(); } //------------------------------------- void CAI_GoalEntity::OnEntityCreated( CBaseEntity *pEntity ) { Assert( m_flags & ACTIVE ); if ( pEntity->MyNPCPointer() ) { SetContextThink( &CAI_GoalEntity::DelayedRefresh, gpGlobals->curtime + 0.1f, "Refresh" ); } } //------------------------------------- void CAI_GoalEntity::OnEntityDeleted( CBaseEntity *pEntity ) { Assert( pEntity != this ); } //----------------------------------------------------------------------------- int CAI_GoalEntity::DrawDebugTextOverlays() { char tempstr[512]; int offset = BaseClass::DrawDebugTextOverlays(); Q_snprintf( tempstr, sizeof(tempstr), "Active: %s", IsActive() ? "yes" : "no" ); EntityText( offset, tempstr, 0 ); offset++; return offset; }