aboutsummaryrefslogtreecommitdiff
path: root/mp/src/game/server/ai_scriptconditions.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_scriptconditions.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_scriptconditions.cpp')
-rw-r--r--mp/src/game/server/ai_scriptconditions.cpp1692
1 files changed, 846 insertions, 846 deletions
diff --git a/mp/src/game/server/ai_scriptconditions.cpp b/mp/src/game/server/ai_scriptconditions.cpp
index 06d42bd9..9f10c0c3 100644
--- a/mp/src/game/server/ai_scriptconditions.cpp
+++ b/mp/src/game/server/ai_scriptconditions.cpp
@@ -1,846 +1,846 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-// $NoKeywords: $
-//=============================================================================//
-
-#include "cbase.h"
-
-#include "IEffects.h"
-#include "collisionutils.h"
-
-#include "ai_basenpc.h"
-#include "ai_scriptconditions.h"
-#include "saverestore_utlvector.h"
-
-// memdbgon must be the last include file in a .cpp file!!!
-#include "tier0/memdbgon.h"
-
-#define SF_ACTOR_AS_ACTIVATOR ( 1 << 0 )
-
-ConVar debugscriptconditions( "ai_debugscriptconditions", "0" );
-
-#define ScrCondDbgMsg( msg ) \
- do \
-{ \
- if ( debugscriptconditions.GetBool() ) \
-{ \
- DevMsg msg; \
-} \
-} \
- while (0)
-
-
-//=============================================================================
-//
-// CAI_ScriptConditions
-//
-//=============================================================================
-
-LINK_ENTITY_TO_CLASS(ai_script_conditions, CAI_ScriptConditions);
-
-BEGIN_DATADESC( CAI_ScriptConditions )
-
- DEFINE_THINKFUNC( EvaluationThink ),
-
- DEFINE_OUTPUT( m_OnConditionsSatisfied, "OnConditionsSatisfied" ),
- DEFINE_OUTPUT( m_OnConditionsTimeout, "OnConditionsTimeout" ),
- DEFINE_OUTPUT( m_NoValidActors, "NoValidActors" ),
-
- //---------------------------------
-
- DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ),
- DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ),
-
- //---------------------------------
-
- // Inputs
- DEFINE_KEYFIELD(m_fDisabled, FIELD_BOOLEAN, "StartDisabled" ),
-
- DEFINE_FIELD( m_hTarget, FIELD_EHANDLE ),
- DEFINE_KEYFIELD(m_Actor, FIELD_STRING, "Actor" ),
-
- DEFINE_KEYFIELD(m_flRequiredTime, FIELD_FLOAT, "RequiredTime" ),
-
-#ifndef HL2_EPISODIC
- DEFINE_FIELD( m_hActor, FIELD_EHANDLE ),
- DEFINE_EMBEDDED(m_Timer ),
- DEFINE_EMBEDDED(m_Timeout ),
-#endif
-
- DEFINE_KEYFIELD(m_fMinState, FIELD_INTEGER, "MinimumState" ),
- DEFINE_KEYFIELD(m_fMaxState, FIELD_INTEGER, "MaximumState" ),
-
- DEFINE_KEYFIELD(m_fScriptStatus, FIELD_INTEGER, "ScriptStatus" ),
- DEFINE_KEYFIELD(m_fActorSeePlayer, FIELD_INTEGER, "ActorSeePlayer" ),
-
-
- DEFINE_KEYFIELD(m_flPlayerActorProximity, FIELD_FLOAT, "PlayerActorProximity" ),
- DEFINE_EMBEDDED(m_PlayerActorProxTester),
-
- DEFINE_KEYFIELD(m_flPlayerActorFOV, FIELD_FLOAT, "PlayerActorFOV" ),
- DEFINE_KEYFIELD(m_bPlayerActorFOVTrueCone, FIELD_BOOLEAN, "PlayerActorFOVTrueCone" ),
-
- DEFINE_KEYFIELD(m_fPlayerActorLOS, FIELD_INTEGER, "PlayerActorLOS" ),
- DEFINE_KEYFIELD(m_fActorSeeTarget, FIELD_INTEGER, "ActorSeeTarget" ),
-
- DEFINE_KEYFIELD(m_flActorTargetProximity, FIELD_FLOAT, "ActorTargetProximity" ),
- DEFINE_EMBEDDED(m_ActorTargetProxTester),
-
- DEFINE_KEYFIELD(m_flPlayerTargetProximity, FIELD_FLOAT, "PlayerTargetProximity" ),
- DEFINE_EMBEDDED(m_PlayerTargetProxTester),
-
- DEFINE_KEYFIELD(m_flPlayerTargetFOV, FIELD_FLOAT, "PlayerTargetFOV" ),
- DEFINE_KEYFIELD(m_bPlayerTargetFOVTrueCone, FIELD_BOOLEAN, "PlayerTargetFOVTrueCone" ),
-
- DEFINE_KEYFIELD(m_fPlayerTargetLOS, FIELD_INTEGER, "PlayerTargetLOS" ),
- DEFINE_KEYFIELD(m_fPlayerBlockingActor, FIELD_INTEGER, "PlayerBlockingActor" ),
-
- DEFINE_KEYFIELD(m_flMinTimeout, FIELD_FLOAT, "MinTimeout" ),
- DEFINE_KEYFIELD(m_flMaxTimeout, FIELD_FLOAT, "MaxTimeout" ),
-
- DEFINE_KEYFIELD(m_fActorInPVS, FIELD_INTEGER, "ActorInPVS" ),
-
- DEFINE_KEYFIELD(m_fActorInVehicle, FIELD_INTEGER, "ActorInVehicle" ),
- DEFINE_KEYFIELD(m_fPlayerInVehicle, FIELD_INTEGER, "PlayerInVehicle" ),
-
- DEFINE_UTLVECTOR( m_ElementList, FIELD_EMBEDDED ),
- DEFINE_FIELD( m_bLeaveAsleep, FIELD_BOOLEAN ),
-
-END_DATADESC()
-
-BEGIN_SIMPLE_DATADESC( CAI_ProxTester )
- DEFINE_FIELD( m_distSq, FIELD_FLOAT ),
- DEFINE_FIELD( m_fInside, FIELD_BOOLEAN ),
-END_DATADESC()
-
-BEGIN_SIMPLE_DATADESC( CAI_ScriptConditionsElement )
- DEFINE_FIELD( m_hActor, FIELD_EHANDLE ),
- DEFINE_EMBEDDED(m_Timer ),
- DEFINE_EMBEDDED(m_Timeout ),
-END_DATADESC()
-
-
-//-----------------------------------------------------------------------------
-
-#define EVALUATOR( name ) { &CAI_ScriptConditions::Eval##name, #name }
-
-CAI_ScriptConditions::EvaluatorInfo_t CAI_ScriptConditions::gm_Evaluators[] =
-{
- EVALUATOR( ActorSeePlayer ),
- EVALUATOR( State ),
- EVALUATOR( PlayerActorProximity ),
- EVALUATOR( PlayerTargetProximity ),
- EVALUATOR( ActorTargetProximity ),
- EVALUATOR( PlayerBlockingActor ),
- EVALUATOR( PlayerActorLook ),
- EVALUATOR( PlayerTargetLook ),
- EVALUATOR( ActorSeeTarget),
- EVALUATOR( PlayerActorLOS ),
- EVALUATOR( PlayerTargetLOS ),
-
-#ifdef HL2_EPISODIC
- EVALUATOR( ActorInPVS ),
- EVALUATOR( PlayerInVehicle ),
- EVALUATOR( ActorInVehicle ),
-#endif
-
-};
-
-void CAI_ScriptConditions::OnRestore( void )
-{
- BaseClass::OnRestore();
-
-#ifndef HL2_EPISODIC
- //Old HL2 save game! Fix up to new system.
- if ( m_hActor )
- {
- CAI_ScriptConditionsElement conditionactor;
-
- conditionactor.SetActor( m_hActor );
- conditionactor.SetTimeOut( m_Timeout );
- conditionactor.SetTimer( m_Timer );
-
- m_ElementList.AddToTail( conditionactor );
-
- m_hActor = NULL;
- }
-
- if ( m_ElementList.Count() == 0 && m_Actor == NULL_STRING && m_fDisabled == false )
- {
- AddNewElement( NULL );
- }
-#endif
-}
-
-//-----------------------------------------------------------------------------
-
-bool CAI_ScriptConditions::EvalState( const EvalArgs_t &args )
-{
- if ( !args.pActor )
- return true;
-
- CAI_BaseNPC *pNpc = args.pActor->MyNPCPointer();
-
- // !!!LATER - fix this code, we shouldn't need the table anymore
- // now that we've placed the NPC state defs in a logical order (sjb)
- static int stateVals[] =
- {
- -1, // NPC_STATE_NONE
- 0, // NPC_STATE_IDLE
- 1, // NPC_STATE_ALERT
- 2, // NPC_STATE_COMBAT
- -1, // NPC_STATE_SCRIPT
- -1, // NPC_STATE_PLAYDEAD
- -1, // NPC_STATE_PRONE
- -1, // NPC_STATE_DEAD
- };
-
- int valState = stateVals[pNpc->m_NPCState];
-
- if ( valState < 0 )
- {
- if ( pNpc->m_NPCState == NPC_STATE_SCRIPT && m_fScriptStatus >= TRS_TRUE )
- return true;
-
- return false;
- }
-
- const int valLow = stateVals[m_fMinState];
- const int valHigh = stateVals[m_fMaxState];
-
- if ( valLow > valHigh )
- {
- DevMsg( "Script condition warning: Invalid setting for Maximum/Minimum state\n" );
- Disable();
- return false;
- }
-
- return ( valState >= valLow && valState <= valHigh );
-}
-
-//-----------------------------------------------------------------------------
-
-bool CAI_ScriptConditions::EvalActorSeePlayer( const EvalArgs_t &args )
-{
- if( m_fActorSeePlayer == TRS_NONE )
- {
- // Don't care, so don't do any work.
- return true;
- }
-
- if ( !args.pActor )
- return true;
-
- bool fCanSeePlayer = args.pActor->MyNPCPointer()->HasCondition( COND_SEE_PLAYER );
- return ( (int)m_fActorSeePlayer == (int)fCanSeePlayer );
-}
-
-//-----------------------------------------------------------------------------
-
-bool CAI_ScriptConditions::EvalActorSeeTarget( const EvalArgs_t &args )
-{
- if( m_fActorSeeTarget == TRS_NONE )
- {
- // Don't care, so don't do any work.
- return true;
- }
-
- if ( args.pTarget )
- {
- if ( !args.pActor )
- return true;
-
- CAI_BaseNPC *pNPCActor = args.pActor->MyNPCPointer();
-
-#ifdef HL2_EPISODIC
- // This is the code we want to have written for HL2, but HL2 shipped without the QuerySeeEntity() call. This #ifdef really wants to be
- // something like #ifndef HL2_RETAIL, since this change does want to be in any products that are built henceforth. (sjb)
- bool fSee = pNPCActor->FInViewCone( args.pTarget ) && pNPCActor->FVisible( args.pTarget ) && pNPCActor->QuerySeeEntity( args.pTarget );
-#else
- bool fSee = pNPCActor->FInViewCone( args.pTarget ) && pNPCActor->FVisible( args.pTarget );
-#endif//HL2_EPISODIC
-
- if( fSee )
- {
- if( m_fActorSeeTarget == TRS_TRUE )
- {
- return true;
- }
-
- return false;
- }
- else
- {
- if( m_fActorSeeTarget == TRS_FALSE )
- {
- return true;
- }
-
- return false;
- }
- }
-
- return true;
-}
-
-
-//-----------------------------------------------------------------------------
-
-bool CAI_ScriptConditions::EvalPlayerActorProximity( const EvalArgs_t &args )
-{
- return ( !args.pActor || m_PlayerActorProxTester.Check( args.pPlayer, args.pActor ) );
-}
-
-//-----------------------------------------------------------------------------
-
-bool CAI_ScriptConditions::EvalPlayerTargetProximity( const EvalArgs_t &args )
-{
- return ( !args.pTarget ||
- m_PlayerTargetProxTester.Check( args.pPlayer, args.pTarget ) );
-}
-
-
-//-----------------------------------------------------------------------------
-
-bool CAI_ScriptConditions::EvalActorTargetProximity( const EvalArgs_t &args )
-{
- return ( !args.pTarget || !args.pActor ||
- m_ActorTargetProxTester.Check( args.pActor, args.pTarget ) );
-}
-
-//-----------------------------------------------------------------------------
-
-bool CAI_ScriptConditions::EvalPlayerActorLook( const EvalArgs_t &args )
-{
- return ( !args.pActor ||
- IsInFOV( args.pPlayer, args.pActor, m_flPlayerActorFOV, m_bPlayerActorFOVTrueCone ) );
-}
-
-//-----------------------------------------------------------------------------
-
-bool CAI_ScriptConditions::EvalPlayerTargetLook( const EvalArgs_t &args )
-{
- return ( !args.pTarget || IsInFOV( args.pPlayer, args.pTarget, m_flPlayerTargetFOV, m_bPlayerTargetFOVTrueCone ) );
-}
-
-//-----------------------------------------------------------------------------
-
-bool CAI_ScriptConditions::EvalPlayerActorLOS( const EvalArgs_t &args )
-{
- if( m_fPlayerActorLOS == TRS_NONE )
- {
- // Don't execute expensive code if we don't care.
- return true;
- }
-
- return ( !args.pActor || PlayerHasLineOfSight( args.pPlayer, args.pActor, m_fPlayerActorLOS == TRS_FALSE ) );
-}
-
-//-----------------------------------------------------------------------------
-
-bool CAI_ScriptConditions::EvalPlayerTargetLOS( const EvalArgs_t &args )
-{
- if( m_fPlayerTargetLOS == TRS_NONE )
- {
- // Don't execute expensive code if we don't care.
- return true;
- }
-
- return ( !args.pTarget || PlayerHasLineOfSight( args.pPlayer, args.pTarget, m_fPlayerTargetLOS == TRS_FALSE ) );
-}
-
-bool CAI_ScriptConditions::EvalActorInPVS( const EvalArgs_t &args )
-{
- if( m_fActorInPVS == TRS_NONE )
- {
- // Don't execute expensive code if we don't care.
- return true;
- }
-
- return ( !args.pActor || ActorInPlayersPVS( args.pActor, m_fActorInPVS == TRS_FALSE ) );
-}
-
-//-----------------------------------------------------------------------------
-
-bool CAI_ScriptConditions::EvalPlayerBlockingActor( const EvalArgs_t &args )
-{
- if ( m_fPlayerBlockingActor == TRS_NONE )
- return true;
-
-#if 0
- CAI_BaseNPC *pNpc = args.pActor->MyNPCPointer();
-
- const float testDist = 30.0;
-
- Vector origin = args.pActor->WorldSpaceCenter();
- Vector delta = UTIL_YawToVector( args.pActor->GetAngles().y ) * testDist;
-
- Vector vecAbsMins, vecAbsMaxs;
- args.pActor->CollisionProp()->WorldSpaceAABB( &vecAbsMins, &vecAbsMaxs );
- bool intersect = IsBoxIntersectingRay( vecAbsMins, vecAbsMaxs, origin, delta );
-#endif
-
- if ( m_fPlayerBlockingActor == TRS_FALSE )
- return true;
-
- return false; // for now, never say player is blocking
-}
-
-//-----------------------------------------------------------------------------
-
-bool CAI_ScriptConditions::EvalPlayerInVehicle( const EvalArgs_t &args )
-{
- // We don't care
- if ( m_fPlayerInVehicle == TRS_NONE )
- return true;
-
- // Need a player to test
- if ( args.pPlayer == NULL )
- return false;
-
- // Desired states must match
- return ( !!args.pPlayer->IsInAVehicle() == m_fPlayerInVehicle );
-}
-
-//-----------------------------------------------------------------------------
-
-bool CAI_ScriptConditions::EvalActorInVehicle( const EvalArgs_t &args )
-{
- // We don't care
- if ( m_fActorInVehicle == TRS_NONE )
- return true;
-
- if ( !args.pActor )
- return true;
-
- // Must be able to be in a vehicle at all
- CBaseCombatCharacter *pBCC = args.pActor->MyCombatCharacterPointer();
- if ( pBCC == NULL )
- return false;
-
- // Desired states must match
- return ( !!pBCC->IsInAVehicle() == m_fActorInVehicle );
-}
-
-//-----------------------------------------------------------------------------
-
-void CAI_ScriptConditions::Spawn()
-{
- Assert( ( m_fMinState == NPC_STATE_IDLE || m_fMinState == NPC_STATE_COMBAT || m_fMinState == NPC_STATE_ALERT ) &&
- ( m_fMaxState == NPC_STATE_IDLE || m_fMaxState == NPC_STATE_COMBAT || m_fMaxState == NPC_STATE_ALERT ) );
-
- m_PlayerActorProxTester.Init( m_flPlayerActorProximity );
- m_PlayerTargetProxTester.Init( m_flPlayerTargetProximity );
- m_ActorTargetProxTester.Init( m_flActorTargetProximity );
-
- m_bLeaveAsleep = m_fDisabled;
-}
-
-//-----------------------------------------------------------------------------
-
-void CAI_ScriptConditions::Activate()
-{
- BaseClass::Activate();
-
- // When we spawn, m_fDisabled is initial state as given by worldcraft.
- // following that, we keep it updated and it reflects current state.
- if( !m_fDisabled )
- Enable();
-
-#ifdef HL2_EPISODIC
- gEntList.AddListenerEntity( this );
-#endif
-}
-
-//-----------------------------------------------------------------------------
-
-void CAI_ScriptConditions::UpdateOnRemove( void )
-{
- gEntList.RemoveListenerEntity( this );
- BaseClass::UpdateOnRemove();
-
- m_ElementList.Purge();
-}
-
-//-----------------------------------------------------------------------------
-
-void CAI_ScriptConditions::EvaluationThink()
-{
- if ( m_fDisabled == true )
- return;
-
- int iActorsDone = 0;
-
-#ifdef HL2_DLL
- if( AI_GetSinglePlayer()->GetFlags() & FL_NOTARGET )
- {
- ScrCondDbgMsg( ("%s WARNING: Player is NOTARGET. This will affect all LOS conditiosn involving the player!\n", GetDebugName()) );
- }
-#endif
-
-
- for ( int i = 0; i < m_ElementList.Count(); )
- {
- CAI_ScriptConditionsElement *pConditionElement = &m_ElementList[i];
-
- if ( pConditionElement == NULL )
- {
- i++;
- continue;
- }
-
- CBaseEntity *pActor = pConditionElement->GetActor();
- CBaseEntity *pActivator = this;
-
-#ifdef HL2_EPISODIC
- if ( pActor && HasSpawnFlags( SF_ACTOR_AS_ACTIVATOR ) )
- {
- pActivator = pActor;
- }
-#endif
-
- AssertMsg( !m_fDisabled, ("Violated invariant between CAI_ScriptConditions disabled state and think func setting") );
-
- if ( m_Actor != NULL_STRING && !pActor )
- {
- if ( m_ElementList.Count() == 1 )
- {
- DevMsg( "Warning: Active AI script conditions associated with an non-existant or destroyed NPC\n" );
- m_NoValidActors.FireOutput( this, this, 0 );
- }
-
- iActorsDone++;
- m_ElementList.Remove( i );
- continue;
- }
-
- i++;
-
- if( m_flMinTimeout > 0 && pConditionElement->GetTimeOut()->Expired() )
- {
- ScrCondDbgMsg( ( "%s firing output OnConditionsTimeout (%f seconds)\n", STRING( GetEntityName() ), pConditionElement->GetTimeOut()->GetInterval() ) );
-
- iActorsDone++;
- m_OnConditionsTimeout.FireOutput( pActivator, this );
- continue;
- }
-
- bool result = true;
- const int nEvaluators = sizeof( gm_Evaluators ) / sizeof( gm_Evaluators[0] );
-
- EvalArgs_t args =
- {
- pActor,
- GetPlayer(),
- m_hTarget.Get()
- };
-
- for ( int i = 0; i < nEvaluators; ++i )
- {
- if ( !(this->*gm_Evaluators[i].pfnEvaluator)( args ) )
- {
- pConditionElement->GetTimer()->Reset();
- result = false;
-
- ScrCondDbgMsg( ( "%s failed on: %s\n", GetDebugName(), gm_Evaluators[ i ].pszName ) );
-
- break;
- }
- }
-
- if ( result )
- {
- ScrCondDbgMsg( ( "%s waiting... %f\n", GetDebugName(), pConditionElement->GetTimer()->GetRemaining() ) );
- }
-
- if ( result && pConditionElement->GetTimer()->Expired() )
- {
- ScrCondDbgMsg( ( "%s firing output OnConditionsSatisfied\n", GetDebugName() ) );
-
- // Default behavior for now, provide worldcraft option later.
- iActorsDone++;
- m_OnConditionsSatisfied.FireOutput( pActivator, this );
- }
- }
-
- //All done!
- if ( iActorsDone == m_ElementList.Count() )
- {
- Disable();
- m_ElementList.Purge();
- }
-
- SetThinkTime();
-}
-
-//-----------------------------------------------------------------------------
-
-int CAI_ScriptConditions::AddNewElement( CBaseEntity *pActor )
-{
- CAI_ScriptConditionsElement conditionelement;
- conditionelement.SetActor( pActor );
-
- if( m_flMaxTimeout > 0 )
- {
- conditionelement.GetTimeOut()->Set( random->RandomFloat( m_flMinTimeout, m_flMaxTimeout ), false );
- }
- else
- {
- conditionelement.GetTimeOut()->Set( m_flMinTimeout, false );
- }
-
- conditionelement.GetTimer()->Set( m_flRequiredTime );
-
- if ( m_flRequiredTime > 0 )
- {
- conditionelement.GetTimer()->Reset();
- }
-
- return m_ElementList.AddToTail( conditionelement );
-}
-
-//-----------------------------------------------------------------------------
-
-void CAI_ScriptConditions::Enable( void )
-{
- m_hTarget = gEntList.FindEntityByName( NULL, m_target );
-
- CBaseEntity *pActor = gEntList.FindEntityByName( NULL, m_Actor );
- if ( m_ElementList.Count() == 0 )
- {
- if ( m_Actor != NULL_STRING && pActor == NULL )
- {
- DevMsg( "Warning: Spawning AI script conditions (%s) associated with an non-existant NPC\n", GetDebugName() );
- m_NoValidActors.FireOutput( this, this, 0 );
- Disable();
- return;
- }
-
- if ( pActor && pActor->MyNPCPointer() == NULL )
- {
- Warning( "Script condition warning: warning actor is not an NPC\n" );
- Disable();
- return;
- }
- }
-
- while( pActor != NULL )
- {
- if( !ActorInList(pActor) )
- {
- AddNewElement( pActor );
- }
-
- pActor = gEntList.FindEntityByName( pActor, m_Actor );
- }
-
- //If we are hitting this it means we are using a Target->Player condition
- if ( m_Actor == NULL_STRING )
- {
- if( !ActorInList(pActor) )
- {
- AddNewElement( NULL );
- }
- }
-
- m_fDisabled = false;
-
- SetThink( &CAI_ScriptConditions::EvaluationThink );
- SetThinkTime();
-}
-
-//-----------------------------------------------------------------------------
-
-void CAI_ScriptConditions::Disable( void )
-{
- SetThink( NULL );
-
- m_fDisabled = true;
-}
-
-//-----------------------------------------------------------------------------
-
-void CAI_ScriptConditions::InputEnable( inputdata_t &inputdata )
-{
- m_bLeaveAsleep = false;
- Enable();
-}
-
-//-----------------------------------------------------------------------------
-
-void CAI_ScriptConditions::InputDisable( inputdata_t &inputdata )
-{
- m_bLeaveAsleep = true;
- Disable();
-}
-
-//-----------------------------------------------------------------------------
-
-bool CAI_ScriptConditions::IsInFOV( CBaseEntity *pViewer, CBaseEntity *pViewed, float fov, bool bTrueCone )
-{
- CBaseCombatCharacter *pCombatantViewer = (pViewer) ? pViewer->MyCombatCharacterPointer() : NULL;
-
- if ( fov < 360 && pCombatantViewer /*&& pViewed*/ )
- {
- Vector vLookDir;
- Vector vActorDir;
-
- // Halve the fov. As expressed here, fov is the full size of the viewcone.
- float flFovDotResult;
- flFovDotResult = cos( DEG2RAD( fov / 2 ) );
- float fDotPr = 1;
-
- if( bTrueCone )
- {
- // 3D Check
- vLookDir = pCombatantViewer->EyeDirection3D( );
- vActorDir = pViewed->EyePosition() - pViewer->EyePosition();
- vActorDir.NormalizeInPlace();
- fDotPr = vLookDir.Dot(vActorDir);
- }
- else
- {
- // 2D Check
- vLookDir = pCombatantViewer->EyeDirection2D( );
- vActorDir = pViewed->EyePosition() - pViewer->EyePosition();
- vActorDir.z = 0.0;
- vActorDir.AsVector2D().NormalizeInPlace();
- fDotPr = vLookDir.AsVector2D().Dot(vActorDir.AsVector2D());
- }
-
- if ( fDotPr < flFovDotResult )
- {
- if( fov < 0 )
- {
- // Designer has requested that the player
- // NOT be looking at this place.
- return true;
- }
-
- return false;
- }
- }
-
- if( fov < 0 )
- {
- return false;
- }
-
- return true;
-}
-
-//-----------------------------------------------------------------------------
-
-bool CAI_ScriptConditions::PlayerHasLineOfSight( CBaseEntity *pViewer, CBaseEntity *pViewed, bool fNot )
-{
- CBaseCombatCharacter *pCombatantViewer = pViewer->MyCombatCharacterPointer();
-
- if( pCombatantViewer )
- {
- // We always trace towards the player, so we handle players-in-vehicles
- if ( pViewed->FVisible( pCombatantViewer ) )
- {
- // Line of sight exists.
- if( fNot )
- {
- return false;
- }
- else
- {
- return true;
- }
- }
- else
- {
- // No line of sight.
- if( fNot )
- {
- return true;
- }
- else
- {
- return false;
- }
- }
- }
-
- return true;
-}
-
-//-----------------------------------------------------------------------------
-
-bool CAI_ScriptConditions::ActorInPlayersPVS( CBaseEntity *pActor, bool bNot )
-{
- if ( pActor == NULL )
- return true;
-
- bool bInPVS = !!UTIL_FindClientInPVS( pActor->edict());
-
- if ( bInPVS )
- {
- if( bNot )
- {
- return false;
- }
- else
- {
- return true;
- }
- }
- else
- {
- if( bNot )
- {
- return true;
- }
- else
- {
- return false;
- }
- }
-}
-
-//-----------------------------------------------------------------------------
-
-bool CAI_ScriptConditions::ActorInList( CBaseEntity *pActor )
-{
- for ( int i = 0; i < m_ElementList.Count(); i++ )
- {
- if ( m_ElementList[i].GetActor() == pActor )
- return true;
- }
-
- return false;
-}
-
-//-----------------------------------------------------------------------------
-
-void CAI_ScriptConditions::OnEntitySpawned( CBaseEntity *pEntity )
-{
- if( m_fDisabled && m_bLeaveAsleep )
- {
- // Don't add elements if we're not currently running and don't want to automatically wake up.
- // Any spawning NPC's we miss during this time will be found and added when manually Enabled().
- return;
- }
-
- if ( pEntity->MyNPCPointer() == NULL )
- return;
-
- if ( pEntity->NameMatches( m_Actor ) )
- {
- if ( ActorInList( pEntity ) == false )
- {
- AddNewElement( pEntity );
-
- if ( m_fDisabled == true && m_bLeaveAsleep == false )
- {
- Enable();
- }
- }
- }
-}
-
-//=============================================================================
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "cbase.h"
+
+#include "IEffects.h"
+#include "collisionutils.h"
+
+#include "ai_basenpc.h"
+#include "ai_scriptconditions.h"
+#include "saverestore_utlvector.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+#define SF_ACTOR_AS_ACTIVATOR ( 1 << 0 )
+
+ConVar debugscriptconditions( "ai_debugscriptconditions", "0" );
+
+#define ScrCondDbgMsg( msg ) \
+ do \
+{ \
+ if ( debugscriptconditions.GetBool() ) \
+{ \
+ DevMsg msg; \
+} \
+} \
+ while (0)
+
+
+//=============================================================================
+//
+// CAI_ScriptConditions
+//
+//=============================================================================
+
+LINK_ENTITY_TO_CLASS(ai_script_conditions, CAI_ScriptConditions);
+
+BEGIN_DATADESC( CAI_ScriptConditions )
+
+ DEFINE_THINKFUNC( EvaluationThink ),
+
+ DEFINE_OUTPUT( m_OnConditionsSatisfied, "OnConditionsSatisfied" ),
+ DEFINE_OUTPUT( m_OnConditionsTimeout, "OnConditionsTimeout" ),
+ DEFINE_OUTPUT( m_NoValidActors, "NoValidActors" ),
+
+ //---------------------------------
+
+ DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ),
+ DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ),
+
+ //---------------------------------
+
+ // Inputs
+ DEFINE_KEYFIELD(m_fDisabled, FIELD_BOOLEAN, "StartDisabled" ),
+
+ DEFINE_FIELD( m_hTarget, FIELD_EHANDLE ),
+ DEFINE_KEYFIELD(m_Actor, FIELD_STRING, "Actor" ),
+
+ DEFINE_KEYFIELD(m_flRequiredTime, FIELD_FLOAT, "RequiredTime" ),
+
+#ifndef HL2_EPISODIC
+ DEFINE_FIELD( m_hActor, FIELD_EHANDLE ),
+ DEFINE_EMBEDDED(m_Timer ),
+ DEFINE_EMBEDDED(m_Timeout ),
+#endif
+
+ DEFINE_KEYFIELD(m_fMinState, FIELD_INTEGER, "MinimumState" ),
+ DEFINE_KEYFIELD(m_fMaxState, FIELD_INTEGER, "MaximumState" ),
+
+ DEFINE_KEYFIELD(m_fScriptStatus, FIELD_INTEGER, "ScriptStatus" ),
+ DEFINE_KEYFIELD(m_fActorSeePlayer, FIELD_INTEGER, "ActorSeePlayer" ),
+
+
+ DEFINE_KEYFIELD(m_flPlayerActorProximity, FIELD_FLOAT, "PlayerActorProximity" ),
+ DEFINE_EMBEDDED(m_PlayerActorProxTester),
+
+ DEFINE_KEYFIELD(m_flPlayerActorFOV, FIELD_FLOAT, "PlayerActorFOV" ),
+ DEFINE_KEYFIELD(m_bPlayerActorFOVTrueCone, FIELD_BOOLEAN, "PlayerActorFOVTrueCone" ),
+
+ DEFINE_KEYFIELD(m_fPlayerActorLOS, FIELD_INTEGER, "PlayerActorLOS" ),
+ DEFINE_KEYFIELD(m_fActorSeeTarget, FIELD_INTEGER, "ActorSeeTarget" ),
+
+ DEFINE_KEYFIELD(m_flActorTargetProximity, FIELD_FLOAT, "ActorTargetProximity" ),
+ DEFINE_EMBEDDED(m_ActorTargetProxTester),
+
+ DEFINE_KEYFIELD(m_flPlayerTargetProximity, FIELD_FLOAT, "PlayerTargetProximity" ),
+ DEFINE_EMBEDDED(m_PlayerTargetProxTester),
+
+ DEFINE_KEYFIELD(m_flPlayerTargetFOV, FIELD_FLOAT, "PlayerTargetFOV" ),
+ DEFINE_KEYFIELD(m_bPlayerTargetFOVTrueCone, FIELD_BOOLEAN, "PlayerTargetFOVTrueCone" ),
+
+ DEFINE_KEYFIELD(m_fPlayerTargetLOS, FIELD_INTEGER, "PlayerTargetLOS" ),
+ DEFINE_KEYFIELD(m_fPlayerBlockingActor, FIELD_INTEGER, "PlayerBlockingActor" ),
+
+ DEFINE_KEYFIELD(m_flMinTimeout, FIELD_FLOAT, "MinTimeout" ),
+ DEFINE_KEYFIELD(m_flMaxTimeout, FIELD_FLOAT, "MaxTimeout" ),
+
+ DEFINE_KEYFIELD(m_fActorInPVS, FIELD_INTEGER, "ActorInPVS" ),
+
+ DEFINE_KEYFIELD(m_fActorInVehicle, FIELD_INTEGER, "ActorInVehicle" ),
+ DEFINE_KEYFIELD(m_fPlayerInVehicle, FIELD_INTEGER, "PlayerInVehicle" ),
+
+ DEFINE_UTLVECTOR( m_ElementList, FIELD_EMBEDDED ),
+ DEFINE_FIELD( m_bLeaveAsleep, FIELD_BOOLEAN ),
+
+END_DATADESC()
+
+BEGIN_SIMPLE_DATADESC( CAI_ProxTester )
+ DEFINE_FIELD( m_distSq, FIELD_FLOAT ),
+ DEFINE_FIELD( m_fInside, FIELD_BOOLEAN ),
+END_DATADESC()
+
+BEGIN_SIMPLE_DATADESC( CAI_ScriptConditionsElement )
+ DEFINE_FIELD( m_hActor, FIELD_EHANDLE ),
+ DEFINE_EMBEDDED(m_Timer ),
+ DEFINE_EMBEDDED(m_Timeout ),
+END_DATADESC()
+
+
+//-----------------------------------------------------------------------------
+
+#define EVALUATOR( name ) { &CAI_ScriptConditions::Eval##name, #name }
+
+CAI_ScriptConditions::EvaluatorInfo_t CAI_ScriptConditions::gm_Evaluators[] =
+{
+ EVALUATOR( ActorSeePlayer ),
+ EVALUATOR( State ),
+ EVALUATOR( PlayerActorProximity ),
+ EVALUATOR( PlayerTargetProximity ),
+ EVALUATOR( ActorTargetProximity ),
+ EVALUATOR( PlayerBlockingActor ),
+ EVALUATOR( PlayerActorLook ),
+ EVALUATOR( PlayerTargetLook ),
+ EVALUATOR( ActorSeeTarget),
+ EVALUATOR( PlayerActorLOS ),
+ EVALUATOR( PlayerTargetLOS ),
+
+#ifdef HL2_EPISODIC
+ EVALUATOR( ActorInPVS ),
+ EVALUATOR( PlayerInVehicle ),
+ EVALUATOR( ActorInVehicle ),
+#endif
+
+};
+
+void CAI_ScriptConditions::OnRestore( void )
+{
+ BaseClass::OnRestore();
+
+#ifndef HL2_EPISODIC
+ //Old HL2 save game! Fix up to new system.
+ if ( m_hActor )
+ {
+ CAI_ScriptConditionsElement conditionactor;
+
+ conditionactor.SetActor( m_hActor );
+ conditionactor.SetTimeOut( m_Timeout );
+ conditionactor.SetTimer( m_Timer );
+
+ m_ElementList.AddToTail( conditionactor );
+
+ m_hActor = NULL;
+ }
+
+ if ( m_ElementList.Count() == 0 && m_Actor == NULL_STRING && m_fDisabled == false )
+ {
+ AddNewElement( NULL );
+ }
+#endif
+}
+
+//-----------------------------------------------------------------------------
+
+bool CAI_ScriptConditions::EvalState( const EvalArgs_t &args )
+{
+ if ( !args.pActor )
+ return true;
+
+ CAI_BaseNPC *pNpc = args.pActor->MyNPCPointer();
+
+ // !!!LATER - fix this code, we shouldn't need the table anymore
+ // now that we've placed the NPC state defs in a logical order (sjb)
+ static int stateVals[] =
+ {
+ -1, // NPC_STATE_NONE
+ 0, // NPC_STATE_IDLE
+ 1, // NPC_STATE_ALERT
+ 2, // NPC_STATE_COMBAT
+ -1, // NPC_STATE_SCRIPT
+ -1, // NPC_STATE_PLAYDEAD
+ -1, // NPC_STATE_PRONE
+ -1, // NPC_STATE_DEAD
+ };
+
+ int valState = stateVals[pNpc->m_NPCState];
+
+ if ( valState < 0 )
+ {
+ if ( pNpc->m_NPCState == NPC_STATE_SCRIPT && m_fScriptStatus >= TRS_TRUE )
+ return true;
+
+ return false;
+ }
+
+ const int valLow = stateVals[m_fMinState];
+ const int valHigh = stateVals[m_fMaxState];
+
+ if ( valLow > valHigh )
+ {
+ DevMsg( "Script condition warning: Invalid setting for Maximum/Minimum state\n" );
+ Disable();
+ return false;
+ }
+
+ return ( valState >= valLow && valState <= valHigh );
+}
+
+//-----------------------------------------------------------------------------
+
+bool CAI_ScriptConditions::EvalActorSeePlayer( const EvalArgs_t &args )
+{
+ if( m_fActorSeePlayer == TRS_NONE )
+ {
+ // Don't care, so don't do any work.
+ return true;
+ }
+
+ if ( !args.pActor )
+ return true;
+
+ bool fCanSeePlayer = args.pActor->MyNPCPointer()->HasCondition( COND_SEE_PLAYER );
+ return ( (int)m_fActorSeePlayer == (int)fCanSeePlayer );
+}
+
+//-----------------------------------------------------------------------------
+
+bool CAI_ScriptConditions::EvalActorSeeTarget( const EvalArgs_t &args )
+{
+ if( m_fActorSeeTarget == TRS_NONE )
+ {
+ // Don't care, so don't do any work.
+ return true;
+ }
+
+ if ( args.pTarget )
+ {
+ if ( !args.pActor )
+ return true;
+
+ CAI_BaseNPC *pNPCActor = args.pActor->MyNPCPointer();
+
+#ifdef HL2_EPISODIC
+ // This is the code we want to have written for HL2, but HL2 shipped without the QuerySeeEntity() call. This #ifdef really wants to be
+ // something like #ifndef HL2_RETAIL, since this change does want to be in any products that are built henceforth. (sjb)
+ bool fSee = pNPCActor->FInViewCone( args.pTarget ) && pNPCActor->FVisible( args.pTarget ) && pNPCActor->QuerySeeEntity( args.pTarget );
+#else
+ bool fSee = pNPCActor->FInViewCone( args.pTarget ) && pNPCActor->FVisible( args.pTarget );
+#endif//HL2_EPISODIC
+
+ if( fSee )
+ {
+ if( m_fActorSeeTarget == TRS_TRUE )
+ {
+ return true;
+ }
+
+ return false;
+ }
+ else
+ {
+ if( m_fActorSeeTarget == TRS_FALSE )
+ {
+ return true;
+ }
+
+ return false;
+ }
+ }
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+
+bool CAI_ScriptConditions::EvalPlayerActorProximity( const EvalArgs_t &args )
+{
+ return ( !args.pActor || m_PlayerActorProxTester.Check( args.pPlayer, args.pActor ) );
+}
+
+//-----------------------------------------------------------------------------
+
+bool CAI_ScriptConditions::EvalPlayerTargetProximity( const EvalArgs_t &args )
+{
+ return ( !args.pTarget ||
+ m_PlayerTargetProxTester.Check( args.pPlayer, args.pTarget ) );
+}
+
+
+//-----------------------------------------------------------------------------
+
+bool CAI_ScriptConditions::EvalActorTargetProximity( const EvalArgs_t &args )
+{
+ return ( !args.pTarget || !args.pActor ||
+ m_ActorTargetProxTester.Check( args.pActor, args.pTarget ) );
+}
+
+//-----------------------------------------------------------------------------
+
+bool CAI_ScriptConditions::EvalPlayerActorLook( const EvalArgs_t &args )
+{
+ return ( !args.pActor ||
+ IsInFOV( args.pPlayer, args.pActor, m_flPlayerActorFOV, m_bPlayerActorFOVTrueCone ) );
+}
+
+//-----------------------------------------------------------------------------
+
+bool CAI_ScriptConditions::EvalPlayerTargetLook( const EvalArgs_t &args )
+{
+ return ( !args.pTarget || IsInFOV( args.pPlayer, args.pTarget, m_flPlayerTargetFOV, m_bPlayerTargetFOVTrueCone ) );
+}
+
+//-----------------------------------------------------------------------------
+
+bool CAI_ScriptConditions::EvalPlayerActorLOS( const EvalArgs_t &args )
+{
+ if( m_fPlayerActorLOS == TRS_NONE )
+ {
+ // Don't execute expensive code if we don't care.
+ return true;
+ }
+
+ return ( !args.pActor || PlayerHasLineOfSight( args.pPlayer, args.pActor, m_fPlayerActorLOS == TRS_FALSE ) );
+}
+
+//-----------------------------------------------------------------------------
+
+bool CAI_ScriptConditions::EvalPlayerTargetLOS( const EvalArgs_t &args )
+{
+ if( m_fPlayerTargetLOS == TRS_NONE )
+ {
+ // Don't execute expensive code if we don't care.
+ return true;
+ }
+
+ return ( !args.pTarget || PlayerHasLineOfSight( args.pPlayer, args.pTarget, m_fPlayerTargetLOS == TRS_FALSE ) );
+}
+
+bool CAI_ScriptConditions::EvalActorInPVS( const EvalArgs_t &args )
+{
+ if( m_fActorInPVS == TRS_NONE )
+ {
+ // Don't execute expensive code if we don't care.
+ return true;
+ }
+
+ return ( !args.pActor || ActorInPlayersPVS( args.pActor, m_fActorInPVS == TRS_FALSE ) );
+}
+
+//-----------------------------------------------------------------------------
+
+bool CAI_ScriptConditions::EvalPlayerBlockingActor( const EvalArgs_t &args )
+{
+ if ( m_fPlayerBlockingActor == TRS_NONE )
+ return true;
+
+#if 0
+ CAI_BaseNPC *pNpc = args.pActor->MyNPCPointer();
+
+ const float testDist = 30.0;
+
+ Vector origin = args.pActor->WorldSpaceCenter();
+ Vector delta = UTIL_YawToVector( args.pActor->GetAngles().y ) * testDist;
+
+ Vector vecAbsMins, vecAbsMaxs;
+ args.pActor->CollisionProp()->WorldSpaceAABB( &vecAbsMins, &vecAbsMaxs );
+ bool intersect = IsBoxIntersectingRay( vecAbsMins, vecAbsMaxs, origin, delta );
+#endif
+
+ if ( m_fPlayerBlockingActor == TRS_FALSE )
+ return true;
+
+ return false; // for now, never say player is blocking
+}
+
+//-----------------------------------------------------------------------------
+
+bool CAI_ScriptConditions::EvalPlayerInVehicle( const EvalArgs_t &args )
+{
+ // We don't care
+ if ( m_fPlayerInVehicle == TRS_NONE )
+ return true;
+
+ // Need a player to test
+ if ( args.pPlayer == NULL )
+ return false;
+
+ // Desired states must match
+ return ( !!args.pPlayer->IsInAVehicle() == m_fPlayerInVehicle );
+}
+
+//-----------------------------------------------------------------------------
+
+bool CAI_ScriptConditions::EvalActorInVehicle( const EvalArgs_t &args )
+{
+ // We don't care
+ if ( m_fActorInVehicle == TRS_NONE )
+ return true;
+
+ if ( !args.pActor )
+ return true;
+
+ // Must be able to be in a vehicle at all
+ CBaseCombatCharacter *pBCC = args.pActor->MyCombatCharacterPointer();
+ if ( pBCC == NULL )
+ return false;
+
+ // Desired states must match
+ return ( !!pBCC->IsInAVehicle() == m_fActorInVehicle );
+}
+
+//-----------------------------------------------------------------------------
+
+void CAI_ScriptConditions::Spawn()
+{
+ Assert( ( m_fMinState == NPC_STATE_IDLE || m_fMinState == NPC_STATE_COMBAT || m_fMinState == NPC_STATE_ALERT ) &&
+ ( m_fMaxState == NPC_STATE_IDLE || m_fMaxState == NPC_STATE_COMBAT || m_fMaxState == NPC_STATE_ALERT ) );
+
+ m_PlayerActorProxTester.Init( m_flPlayerActorProximity );
+ m_PlayerTargetProxTester.Init( m_flPlayerTargetProximity );
+ m_ActorTargetProxTester.Init( m_flActorTargetProximity );
+
+ m_bLeaveAsleep = m_fDisabled;
+}
+
+//-----------------------------------------------------------------------------
+
+void CAI_ScriptConditions::Activate()
+{
+ BaseClass::Activate();
+
+ // When we spawn, m_fDisabled is initial state as given by worldcraft.
+ // following that, we keep it updated and it reflects current state.
+ if( !m_fDisabled )
+ Enable();
+
+#ifdef HL2_EPISODIC
+ gEntList.AddListenerEntity( this );
+#endif
+}
+
+//-----------------------------------------------------------------------------
+
+void CAI_ScriptConditions::UpdateOnRemove( void )
+{
+ gEntList.RemoveListenerEntity( this );
+ BaseClass::UpdateOnRemove();
+
+ m_ElementList.Purge();
+}
+
+//-----------------------------------------------------------------------------
+
+void CAI_ScriptConditions::EvaluationThink()
+{
+ if ( m_fDisabled == true )
+ return;
+
+ int iActorsDone = 0;
+
+#ifdef HL2_DLL
+ if( AI_GetSinglePlayer()->GetFlags() & FL_NOTARGET )
+ {
+ ScrCondDbgMsg( ("%s WARNING: Player is NOTARGET. This will affect all LOS conditiosn involving the player!\n", GetDebugName()) );
+ }
+#endif
+
+
+ for ( int i = 0; i < m_ElementList.Count(); )
+ {
+ CAI_ScriptConditionsElement *pConditionElement = &m_ElementList[i];
+
+ if ( pConditionElement == NULL )
+ {
+ i++;
+ continue;
+ }
+
+ CBaseEntity *pActor = pConditionElement->GetActor();
+ CBaseEntity *pActivator = this;
+
+#ifdef HL2_EPISODIC
+ if ( pActor && HasSpawnFlags( SF_ACTOR_AS_ACTIVATOR ) )
+ {
+ pActivator = pActor;
+ }
+#endif
+
+ AssertMsg( !m_fDisabled, ("Violated invariant between CAI_ScriptConditions disabled state and think func setting") );
+
+ if ( m_Actor != NULL_STRING && !pActor )
+ {
+ if ( m_ElementList.Count() == 1 )
+ {
+ DevMsg( "Warning: Active AI script conditions associated with an non-existant or destroyed NPC\n" );
+ m_NoValidActors.FireOutput( this, this, 0 );
+ }
+
+ iActorsDone++;
+ m_ElementList.Remove( i );
+ continue;
+ }
+
+ i++;
+
+ if( m_flMinTimeout > 0 && pConditionElement->GetTimeOut()->Expired() )
+ {
+ ScrCondDbgMsg( ( "%s firing output OnConditionsTimeout (%f seconds)\n", STRING( GetEntityName() ), pConditionElement->GetTimeOut()->GetInterval() ) );
+
+ iActorsDone++;
+ m_OnConditionsTimeout.FireOutput( pActivator, this );
+ continue;
+ }
+
+ bool result = true;
+ const int nEvaluators = sizeof( gm_Evaluators ) / sizeof( gm_Evaluators[0] );
+
+ EvalArgs_t args =
+ {
+ pActor,
+ GetPlayer(),
+ m_hTarget.Get()
+ };
+
+ for ( int i = 0; i < nEvaluators; ++i )
+ {
+ if ( !(this->*gm_Evaluators[i].pfnEvaluator)( args ) )
+ {
+ pConditionElement->GetTimer()->Reset();
+ result = false;
+
+ ScrCondDbgMsg( ( "%s failed on: %s\n", GetDebugName(), gm_Evaluators[ i ].pszName ) );
+
+ break;
+ }
+ }
+
+ if ( result )
+ {
+ ScrCondDbgMsg( ( "%s waiting... %f\n", GetDebugName(), pConditionElement->GetTimer()->GetRemaining() ) );
+ }
+
+ if ( result && pConditionElement->GetTimer()->Expired() )
+ {
+ ScrCondDbgMsg( ( "%s firing output OnConditionsSatisfied\n", GetDebugName() ) );
+
+ // Default behavior for now, provide worldcraft option later.
+ iActorsDone++;
+ m_OnConditionsSatisfied.FireOutput( pActivator, this );
+ }
+ }
+
+ //All done!
+ if ( iActorsDone == m_ElementList.Count() )
+ {
+ Disable();
+ m_ElementList.Purge();
+ }
+
+ SetThinkTime();
+}
+
+//-----------------------------------------------------------------------------
+
+int CAI_ScriptConditions::AddNewElement( CBaseEntity *pActor )
+{
+ CAI_ScriptConditionsElement conditionelement;
+ conditionelement.SetActor( pActor );
+
+ if( m_flMaxTimeout > 0 )
+ {
+ conditionelement.GetTimeOut()->Set( random->RandomFloat( m_flMinTimeout, m_flMaxTimeout ), false );
+ }
+ else
+ {
+ conditionelement.GetTimeOut()->Set( m_flMinTimeout, false );
+ }
+
+ conditionelement.GetTimer()->Set( m_flRequiredTime );
+
+ if ( m_flRequiredTime > 0 )
+ {
+ conditionelement.GetTimer()->Reset();
+ }
+
+ return m_ElementList.AddToTail( conditionelement );
+}
+
+//-----------------------------------------------------------------------------
+
+void CAI_ScriptConditions::Enable( void )
+{
+ m_hTarget = gEntList.FindEntityByName( NULL, m_target );
+
+ CBaseEntity *pActor = gEntList.FindEntityByName( NULL, m_Actor );
+ if ( m_ElementList.Count() == 0 )
+ {
+ if ( m_Actor != NULL_STRING && pActor == NULL )
+ {
+ DevMsg( "Warning: Spawning AI script conditions (%s) associated with an non-existant NPC\n", GetDebugName() );
+ m_NoValidActors.FireOutput( this, this, 0 );
+ Disable();
+ return;
+ }
+
+ if ( pActor && pActor->MyNPCPointer() == NULL )
+ {
+ Warning( "Script condition warning: warning actor is not an NPC\n" );
+ Disable();
+ return;
+ }
+ }
+
+ while( pActor != NULL )
+ {
+ if( !ActorInList(pActor) )
+ {
+ AddNewElement( pActor );
+ }
+
+ pActor = gEntList.FindEntityByName( pActor, m_Actor );
+ }
+
+ //If we are hitting this it means we are using a Target->Player condition
+ if ( m_Actor == NULL_STRING )
+ {
+ if( !ActorInList(pActor) )
+ {
+ AddNewElement( NULL );
+ }
+ }
+
+ m_fDisabled = false;
+
+ SetThink( &CAI_ScriptConditions::EvaluationThink );
+ SetThinkTime();
+}
+
+//-----------------------------------------------------------------------------
+
+void CAI_ScriptConditions::Disable( void )
+{
+ SetThink( NULL );
+
+ m_fDisabled = true;
+}
+
+//-----------------------------------------------------------------------------
+
+void CAI_ScriptConditions::InputEnable( inputdata_t &inputdata )
+{
+ m_bLeaveAsleep = false;
+ Enable();
+}
+
+//-----------------------------------------------------------------------------
+
+void CAI_ScriptConditions::InputDisable( inputdata_t &inputdata )
+{
+ m_bLeaveAsleep = true;
+ Disable();
+}
+
+//-----------------------------------------------------------------------------
+
+bool CAI_ScriptConditions::IsInFOV( CBaseEntity *pViewer, CBaseEntity *pViewed, float fov, bool bTrueCone )
+{
+ CBaseCombatCharacter *pCombatantViewer = (pViewer) ? pViewer->MyCombatCharacterPointer() : NULL;
+
+ if ( fov < 360 && pCombatantViewer /*&& pViewed*/ )
+ {
+ Vector vLookDir;
+ Vector vActorDir;
+
+ // Halve the fov. As expressed here, fov is the full size of the viewcone.
+ float flFovDotResult;
+ flFovDotResult = cos( DEG2RAD( fov / 2 ) );
+ float fDotPr = 1;
+
+ if( bTrueCone )
+ {
+ // 3D Check
+ vLookDir = pCombatantViewer->EyeDirection3D( );
+ vActorDir = pViewed->EyePosition() - pViewer->EyePosition();
+ vActorDir.NormalizeInPlace();
+ fDotPr = vLookDir.Dot(vActorDir);
+ }
+ else
+ {
+ // 2D Check
+ vLookDir = pCombatantViewer->EyeDirection2D( );
+ vActorDir = pViewed->EyePosition() - pViewer->EyePosition();
+ vActorDir.z = 0.0;
+ vActorDir.AsVector2D().NormalizeInPlace();
+ fDotPr = vLookDir.AsVector2D().Dot(vActorDir.AsVector2D());
+ }
+
+ if ( fDotPr < flFovDotResult )
+ {
+ if( fov < 0 )
+ {
+ // Designer has requested that the player
+ // NOT be looking at this place.
+ return true;
+ }
+
+ return false;
+ }
+ }
+
+ if( fov < 0 )
+ {
+ return false;
+ }
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+
+bool CAI_ScriptConditions::PlayerHasLineOfSight( CBaseEntity *pViewer, CBaseEntity *pViewed, bool fNot )
+{
+ CBaseCombatCharacter *pCombatantViewer = pViewer->MyCombatCharacterPointer();
+
+ if( pCombatantViewer )
+ {
+ // We always trace towards the player, so we handle players-in-vehicles
+ if ( pViewed->FVisible( pCombatantViewer ) )
+ {
+ // Line of sight exists.
+ if( fNot )
+ {
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+ }
+ else
+ {
+ // No line of sight.
+ if( fNot )
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+
+bool CAI_ScriptConditions::ActorInPlayersPVS( CBaseEntity *pActor, bool bNot )
+{
+ if ( pActor == NULL )
+ return true;
+
+ bool bInPVS = !!UTIL_FindClientInPVS( pActor->edict());
+
+ if ( bInPVS )
+ {
+ if( bNot )
+ {
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+ }
+ else
+ {
+ if( bNot )
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+bool CAI_ScriptConditions::ActorInList( CBaseEntity *pActor )
+{
+ for ( int i = 0; i < m_ElementList.Count(); i++ )
+ {
+ if ( m_ElementList[i].GetActor() == pActor )
+ return true;
+ }
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+
+void CAI_ScriptConditions::OnEntitySpawned( CBaseEntity *pEntity )
+{
+ if( m_fDisabled && m_bLeaveAsleep )
+ {
+ // Don't add elements if we're not currently running and don't want to automatically wake up.
+ // Any spawning NPC's we miss during this time will be found and added when manually Enabled().
+ return;
+ }
+
+ if ( pEntity->MyNPCPointer() == NULL )
+ return;
+
+ if ( pEntity->NameMatches( m_Actor ) )
+ {
+ if ( ActorInList( pEntity ) == false )
+ {
+ AddNewElement( pEntity );
+
+ if ( m_fDisabled == true && m_bLeaveAsleep == false )
+ {
+ Enable();
+ }
+ }
+ }
+}
+
+//=============================================================================