source-sdk-2013-mapbase/sp/src/game/server/ai_scriptconditions.cpp
Blixibon c448f194ae Mapbase v5.0
- Added keyvalue to hl2_gamerules which allows respawning in singleplayer
- Added the game instructor system (including env_instructor_hint) from later Valve games using a VDC tutorial which adjusts the version from the Alien Swarm SDK to FPS rules and a Source 2013 environment; Also added new KV and icons for further control from mappers (tutorial mentioned by Maestra Fenix)
- Added L4D/TF2 glows + point_glow entity as an all-purpose SDK-based off-shoot of tf_glow
- Fixed weapon pickup sound not playing (reported by Sl0th and later Cvoxulary)
- Fixed env_projectedtextures not updating on save/load
- Added func_fake_worldportal, a spatial point_camera inspired by linked_portal_door based on SDK code alone (WIP, may be changed a lot in future updates)
- Added option for point_camera and func_reflective_glass to use different render targets, therefore allowing multiple cameras and mirrors to be active at the same time
- Added additional RT camera textures to choose from with a default of 3, but also controllable through a -numcameratextures command line param
- Added adjustable convars for main view NearZ and skybox NearZ (suggested by someone recently, also suggested by Klems over a year ago)
- Fixed map-specific localization files, cleaned up map-specific file code
- Added a new block to gameinfo.txt which allows mods to automatically append their own command line parameters
- Fixed math_lightpattern corruption when setting pattern/style while active
- Fixed the "Touch" input crashing when given no entity
- Added a way to add EFlags via keyvalue (suggested by Niker107)
- Fixed ai_script_conditions not working without a NPC actor (reported by MetroHam)
- Fixed point_radiation_source causing huge problems when intensity is 0, even though it was already advised against (reported by beefbacon)
- Added "Mapbase" header to Mapbase-specific code files
- Fixed an issue with updating sky_camera not obtaining area correctly, causing some entities to not draw in the skybox
- Added "CopyFogController" and "CopyFogControllerWithScale" inputs to sky_camera, which copy fog parameters directly from a fog controller
- Added "SetScale" input to sky_camera for live scale changing
- Added convar to control player crouch speed multiplier (suggested by ArtyIF)
- Added a ton of fixes for people running the Debug configuration of the codebase (partial credit to stepa2)
- Added support for pre-defined enums and constants in VScript, starting with various values from the SDK code (damage types, trace masks, etc.)
- Added limited support for Valve's Quaternion class in VScript
- Added new instance helper capabilities, destructible game instances, and other misc. changes to VScript library
- Replaced most of the VScript "accessor" classes with direct references to the original classes, as they were getting complicated fast and adding new VScript-only functions to the original classes might not be as bad as previously thought
- Added base NPC hooks for AI sensing in VScript (allows control over sight and hearing), also exposed CSound for it
- Added various functions and hooks for VPhysics integration in VScript
- Added VScript-based custom suit devices
- Expanded trace info exposed to VScript to allow plane and surface access (suggested by krassell)
- Added ability to insert localization strings through VScript
- Added various misc. VScript functions with various purposes, including reading/writing EFlags, movetypes, collision groups, etc.
- Fixed VBSP not being able to correctly parse parallax corrected cubemaps in maps with instances
2020-08-14 21:21:25 +00:00

882 lines
22 KiB
C++

//========= 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 ),
#ifdef MAPBASE
DEFINE_INPUTFUNC( FIELD_EHANDLE, "SatisfyConditions", InputSatisfyConditions ),
#endif
//---------------------------------
// 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
#ifdef MAPBASE
3, // A "Don't care" for the maximum value
#endif
};
int valState = stateVals[pNpc->m_NPCState];
if ( valState < 0 )
{
#ifdef MAPBASE
if (m_fMinState == 0)
return true;
#endif
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();
}
#ifdef MAPBASE
//-----------------------------------------------------------------------------
void CAI_ScriptConditions::InputSatisfyConditions( inputdata_t &inputdata )
{
// This satisfies things.
CBaseEntity *pActivator = HasSpawnFlags(SF_ACTOR_AS_ACTIVATOR) ? inputdata.value.Entity() : this;
m_OnConditionsSatisfied.FireOutput(pActivator, this);
//All done!
if ( m_ElementList.Count() == 1 )
{
Disable();
m_ElementList.Purge();
}
}
#endif
//-----------------------------------------------------------------------------
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;
#ifdef MAPBASE
if ( m_Actor == NULL_STRING )
return;
#endif
if ( pEntity->NameMatches( m_Actor ) )
{
if ( ActorInList( pEntity ) == false )
{
AddNewElement( pEntity );
if ( m_fDisabled == true && m_bLeaveAsleep == false )
{
Enable();
}
}
}
}
//=============================================================================