text: //========= Copyright Valve Corporation, All rights reserved. ============//
  //
  // Purpose:
  //
  // $NoKeywords: $
  //=============================================================================//
  
  #ifndef AI_SCRIPTCONDITIONS_H
  #define AI_SCRIPTCONDITIONS_H
  
  #include "baseentity.h"
  #include "entityoutput.h"
  #include "simtimer.h"
  #include "ai_npcstate.h"
  
  #if defined( _WIN32 )
  #pragma once
  #endif
  
  //-----------------------------------------------------------------------------
  
  class CAI_ProxTester
  {
  public:
  	CAI_ProxTester()
  		: m_distSq( 0 ),
  		m_fInside( false )
  	{
  	}
  
  	void Init( float dist )
  	{
  		m_fInside = ( dist > 0 );
  		m_distSq = dist * dist;
  	}
  
  	bool Check( CBaseEntity *pEntity1, CBaseEntity *pEntity2 )
  	{
  		if ( m_distSq != 0 )
  		{
  			float distSq = ( pEntity1->GetAbsOrigin() - pEntity2->GetAbsOrigin() ).LengthSqr();
  			bool fInside = ( distSq < m_distSq );
  
  			return ( m_fInside == fInside );
  		}
  		return true;
  	}
  
  	DECLARE_SIMPLE_DATADESC();
  
  private:
  
  	float m_distSq;
  	bool  m_fInside;
  };
  
  //-----------------------------------------------------------------------------
  class CAI_ScriptConditionsElement
  {
  public:
  
  	DECLARE_SIMPLE_DATADESC();
  
  	void			SetActor( CBaseEntity *pEntity ) { m_hActor = pEntity; }
  	CBaseEntity		*GetActor( void ){ return m_hActor.Get(); }
  
  	void			SetTimer( CSimTimer timer ) { m_Timer = timer;	}
  	CSimTimer		*GetTimer( void ) { return &m_Timer;	}
  	
  	void			SetTimeOut( CSimTimer timeout) { m_Timeout = timeout;	}
  	CSimTimer		*GetTimeOut( void ) { return &m_Timeout;	}
  
  private:
  	EHANDLE			m_hActor;
  	CSimTimer		m_Timer;
  	CSimTimer		m_Timeout;
  };
  
  //-----------------------------------------------------------------------------
  // class CAI_ScriptConditions
  //
  // Purpose: Watches a set of conditions relative to a given NPC, and when they
  //			are all satisfied, fires the relevant output
  //-----------------------------------------------------------------------------
  
  class CAI_ScriptConditions : public CBaseEntity, public IEntityListener
  {
  	DECLARE_CLASS( CAI_ScriptConditions, CBaseEntity );
  
  public:
  	CAI_ScriptConditions()
  		:	m_fDisabled( true ),
  		m_flRequiredTime( 0 ),
  		m_fMinState( NPC_STATE_IDLE ),
  		m_fMaxState( NPC_STATE_IDLE ),
  		m_fScriptStatus( TRS_NONE ),
  		m_fActorSeePlayer( TRS_NONE ),
  		m_flPlayerActorProximity( 0 ),
  		m_flPlayerActorFOV( -1 ),
  		m_fPlayerActorLOS( TRS_NONE ),
  		m_fActorSeeTarget( TRS_NONE ),
  		m_flActorTargetProximity( 0 ),
  		m_flPlayerTargetProximity( 0 ),
  		m_flPlayerTargetFOV( 0 ),
  		m_fPlayerTargetLOS( TRS_NONE ),
  		m_fPlayerBlockingActor( TRS_NONE ),
  		m_flMinTimeout( 0 ),
  		m_flMaxTimeout( 0 ),
  		m_fActorInPVS( TRS_NONE ),
  		m_fActorInVehicle( TRS_NONE ),
  		m_fPlayerInVehicle( TRS_NONE )
  	{
  #ifndef HL2_EPISODIC
  		m_hActor = NULL;
  #endif
  	}
  
  private:
  	void Spawn();
  	void Activate();
  
  	void EvaluationThink();
  
  	void Enable();
  	void Disable();
  
  	void SetThinkTime()			{ SetNextThink( gpGlobals->curtime + 0.250 ); }
  
  	// Evaluators
  	struct EvalArgs_t
  	{
  		CBaseEntity *pActor; 
  		CBasePlayer *pPlayer; 
  		CBaseEntity *pTarget;
  	};
  
  	bool EvalState( const EvalArgs_t &args );
  	bool EvalActorSeePlayer( const EvalArgs_t &args );
  	bool EvalPlayerActorLook( const EvalArgs_t &args );
  	bool EvalPlayerTargetLook( const EvalArgs_t &args );
  	bool EvalPlayerActorProximity( const EvalArgs_t &args );
  	bool EvalPlayerTargetProximity( const EvalArgs_t &args );
  	bool EvalActorTargetProximity( const EvalArgs_t &args );
  	bool EvalActorSeeTarget( const EvalArgs_t &args );
  	bool EvalPlayerActorLOS( const EvalArgs_t &args );
  	bool EvalPlayerTargetLOS( const EvalArgs_t &args );
  	bool EvalPlayerBlockingActor( const EvalArgs_t &args );
  	bool EvalActorInPVS( const EvalArgs_t &args );
  	bool EvalPlayerInVehicle( const EvalArgs_t &args );
  	bool EvalActorInVehicle( const EvalArgs_t &args );
  
  	void OnEntitySpawned( CBaseEntity *pEntity );
  
  	int AddNewElement( CBaseEntity *pActor );
  
  	bool ActorInList( CBaseEntity *pActor );
  	void UpdateOnRemove( void );
  
  	// Input handlers
  	void InputEnable( inputdata_t &inputdata );
  	void InputDisable( inputdata_t &inputdata );
  
  	// Output handlers
  	COutputEvent	m_OnConditionsSatisfied;
  	COutputEvent	m_OnConditionsTimeout;
  	COutputEvent	m_NoValidActors;
  
  	//---------------------------------
  
  #ifndef HL2_EPISODIC
  	CBaseEntity *GetActor()		{ return m_hActor.Get();			}
  #endif
  //Get the player closest to our target if we have one, followed by NPC
  	CBasePlayer *GetPlayer()
  	{
  		CBasePlayer* pPlayer = NULL;
  		//start with our Target. If we have one, try to get the nearest player with LOS
  		if (m_hTarget.IsValid())
  			pPlayer = UTIL_GetNearestPlayer(m_hTarget.Get(), true);
  
  		//if we don't have a player yet, try the nearest player to our Actor, with LOS
  		if (!pPlayer)
  		{
  			if (GetActor())
  			{
  				pPlayer = UTIL_GetNearestPlayer(GetActor(), true);
  				//we don't have a player in the Actor's LOS, try nearest to Target
  				if (!pPlayer)
  				{
  					if (m_hTarget.IsValid())
  						pPlayer = UTIL_GetNearestPlayer(m_hTarget.Get());
  					//if we don't have a Target, get the player nearest to our Actor.
  					else
  						pPlayer = UTIL_GetNearestPlayer(GetActor());
  				}
  			}
  			//we don't have an Actor, so just try nearest to Target, no LOS
  			else if (m_hTarget.IsValid())
  				pPlayer = UTIL_GetNearestPlayer(m_hTarget.Get());
  		}
  		//technically by this point if we don't have a player we shouldn't be able to find one at all,
  		//but we need to return *something* and it's not impossible that something wound up screwy before now
  		if (!pPlayer)
  			pPlayer = UTIL_GetNearestPlayer(this, true);
  		if (!pPlayer)
  			pPlayer = UTIL_GetNearestPlayer(this);
  
  		if (pPlayer)
  			return pPlayer/*UTIL_GetLocalPlayer()*/;
  
  		return UTIL_PlayerByIndex(1); //last ditch effort, if we're a listen server, give us the host.
  	}
  
  	//---------------------------------
  
  	// @Note (toml 07-17-02): At some point, it may be desireable to switch to using function objects instead of functions. Probably
  	// if support for NPCs addiing custom conditions becomes necessary
  	typedef bool (CAI_ScriptConditions::*EvaluationFunc_t)( const EvalArgs_t &args );
  
  	struct EvaluatorInfo_t
  	{
  		EvaluationFunc_t	pfnEvaluator;
  		const char			*pszName;
  	};
  
  	static EvaluatorInfo_t gm_Evaluators[];
  
  	//---------------------------------
  	// Evaluation helpers
  
  	static bool IsInFOV( CBaseEntity *pViewer, CBaseEntity *pViewed, float fov, bool bTrueCone );
  	static bool PlayerHasLineOfSight( CBaseEntity *pViewer, CBaseEntity *pViewed, bool fNot );
  	static bool ActorInPlayersPVS( CBaseEntity *pActor, bool bNot );
  
  	virtual void OnRestore( void );
  
  	//---------------------------------
  	// General conditions info
  
  	bool			m_fDisabled;
  	bool			m_bLeaveAsleep;
  	EHANDLE			m_hTarget;
  
  	float			m_flRequiredTime;	// How long should the conditions me true
  
  #ifndef HL2_EPISODIC
  	EHANDLE 		m_hActor;
  	CSimTimer		m_Timer; 			// @TODO (toml 07-16-02): save/load of timer once Jay has save/load of contained objects
  	CSimTimer		m_Timeout;
  #endif
  
  	//---------------------------------
  	// Specific conditions data
  	NPC_STATE		m_fMinState;
  	NPC_STATE		m_fMaxState;
  	ThreeState_t 	m_fScriptStatus;
  	ThreeState_t 	m_fActorSeePlayer;
  	string_t		m_Actor;
  
  	float 			m_flPlayerActorProximity;
  	CAI_ProxTester	m_PlayerActorProxTester;
  
  	float			m_flPlayerActorFOV;
  	bool			m_bPlayerActorFOVTrueCone;
  	ThreeState_t	m_fPlayerActorLOS;
  	ThreeState_t 	m_fActorSeeTarget;
  
  	float 			m_flActorTargetProximity;
  	CAI_ProxTester	m_ActorTargetProxTester;
  
  	float 			m_flPlayerTargetProximity;
  	CAI_ProxTester	m_PlayerTargetProxTester;
  
  	float 			m_flPlayerTargetFOV;
  	bool			m_bPlayerTargetFOVTrueCone;
  	ThreeState_t	m_fPlayerTargetLOS;
  	ThreeState_t	m_fPlayerBlockingActor;
  	ThreeState_t	m_fActorInPVS;
  
  	float			m_flMinTimeout;
  	float			m_flMaxTimeout;
  
  	ThreeState_t	m_fActorInVehicle;
  	ThreeState_t	m_fPlayerInVehicle;
  
  	CUtlVector< CAI_ScriptConditionsElement > m_ElementList;
  
  	//---------------------------------
  
  	DECLARE_DATADESC();
  };
  
  //=============================================================================
  
  #endif // AI_SCRIPTCONDITIONS_H