1
0
mirror of https://github.com/alliedmodders/hl2sdk.git synced 2024-12-23 01:59:43 +08:00
hl2sdk/game/server/ai_behavior.h

1978 lines
60 KiB
C++

//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef AI_BEHAVIOR_H
#define AI_BEHAVIOR_H
#include "ai_component.h"
#include "ai_basenpc.h"
#include "ai_default.h"
#include "AI_Criteria.h"
#include "networkvar.h"
#ifdef DEBUG
#ifdef _WIN32
#pragma warning(push)
#endif // _WIN32
#include <typeinfo>
#ifdef _WIN32
#pragma warning(pop)
#pragma warning(disable:4290)
#endif // _WIN32
#endif // DEBUG
#if defined( _WIN32 )
#pragma once
#endif
//-----------------------------------------------------------------------------
// CAI_Behavior...
//
// Purpose: The core component that defines a behavior in an NPC by selecting
// schedules and running tasks
//
// Intended to be used as an organizational tool as well as a way
// for various NPCs to share behaviors without sharing an inheritance
// relationship, and without cramming those behaviors into the base
// NPC class.
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Purpose: Base class defines interface to behaviors and provides bridging
// methods
//-----------------------------------------------------------------------------
class IBehaviorBackBridge;
//-------------------------------------
abstract_class CAI_BehaviorBase : public CAI_Component
{
DECLARE_CLASS( CAI_BehaviorBase, CAI_Component )
public:
CAI_BehaviorBase(CAI_BaseNPC *pOuter = NULL)
: CAI_Component(pOuter),
m_pBackBridge(NULL)
{
}
virtual const char *GetName() = 0;
virtual bool KeyValue( const char *szKeyName, const char *szValue )
{
return false;
}
bool IsRunning() { Assert( GetOuter() ); return ( GetOuter()->GetRunningBehavior() == this ); }
virtual bool CanSelectSchedule() { return true; }
virtual void BeginScheduleSelection() {}
virtual void EndScheduleSelection() {}
void SetBackBridge( IBehaviorBackBridge *pBackBridge )
{
Assert( m_pBackBridge == NULL || pBackBridge == NULL );
m_pBackBridge = pBackBridge;
}
void BridgePrecache() { Precache(); }
void BridgeSpawn() { Spawn(); }
void BridgeUpdateOnRemove() { UpdateOnRemove(); }
void BridgeEvent_Killed( const CTakeDamageInfo &info ) { Event_Killed( info ); }
void BridgeCleanupOnDeath( CBaseEntity *pCulprit, bool bFireDeathOutput ) { CleanupOnDeath( pCulprit, bFireDeathOutput ); }
void BridgeOnChangeHintGroup( string_t oldGroup, string_t newGroup ) { OnChangeHintGroup( oldGroup, newGroup ); }
void BridgeGatherConditions() { GatherConditions(); }
void BridgePrescheduleThink() { PrescheduleThink(); }
void BridgeOnScheduleChange() { OnScheduleChange(); }
void BridgeOnStartSchedule( int scheduleType );
int BridgeSelectSchedule();
bool BridgeSelectFailSchedule( int failedSchedule, int failedTask, AI_TaskFailureCode_t taskFailCode, int *pResult );
bool BridgeStartTask( const Task_t *pTask );
bool BridgeRunTask( const Task_t *pTask);
bool BridgeAimGun( void );
int BridgeTranslateSchedule( int scheduleType );
bool BridgeGetSchedule( int localScheduleID, CAI_Schedule **ppResult );
bool BridgeTaskName(int taskID, const char **);
Activity BridgeNPC_TranslateActivity( Activity activity );
void BridgeBuildScheduleTestBits() { BuildScheduleTestBits(); }
bool BridgeIsCurTaskContinuousMove( bool *pResult );
void BridgeOnMovementFailed() { OnMovementFailed(); }
void BridgeOnMovementComplete() { OnMovementComplete(); }
float BridgeGetDefaultNavGoalTolerance();
bool BridgeFValidateHintType( CAI_Hint *pHint, bool *pResult );
bool BridgeIsValidEnemy( CBaseEntity *pEnemy );
CBaseEntity *BridgeBestEnemy();
bool BridgeIsValidCover( const Vector &vLocation, CAI_Hint const *pHint );
bool BridgeIsValidShootPosition( const Vector &vLocation, CAI_Node *pNode, CAI_Hint const *pHint );
float BridgeGetMaxTacticalLateralMovement( void );
bool BridgeShouldIgnoreSound( CSound *pSound );
void BridgeOnSeeEntity( CBaseEntity *pEntity );
void BridgeOnFriendDamaged( CBaseCombatCharacter *pSquadmate, CBaseEntity *pAttacker );
bool BridgeIsInterruptable( void );
bool BridgeIsNavigationUrgent( void );
bool BridgeShouldPlayerAvoid( void );
int BridgeOnTakeDamage_Alive( const CTakeDamageInfo &info );
float BridgeGetReasonableFacingDist( void );
bool BridgeShouldAlwaysThink( bool *pResult );
void BridgeOnChangeActiveWeapon( CBaseCombatWeapon *pOldWeapon, CBaseCombatWeapon *pNewWeapon );
void BridgeOnRestore();
virtual bool BridgeSpeakMapmakerInterruptConcept( string_t iszConcept );
bool BridgeCanFlinch( void );
bool BridgeIsCrouching( void );
bool BridgeIsCrouchedActivity( Activity activity );
bool BridgeQueryHearSound( CSound *pSound );
bool BridgeCanRunAScriptedNPCInteraction( bool bForced );
Activity BridgeGetFlinchActivity( bool bHeavyDamage, bool bGesture );
bool BridgeOnCalcBaseMove( AILocalMoveGoal_t *pMoveGoal, float distClear, AIMoveResult_t *pResult );
void BridgeModifyOrAppendCriteria( AI_CriteriaSet& criteriaSet );
void BridgeTeleport( const Vector *newPosition, const QAngle *newAngles, const Vector *newVelocity );
void BridgeHandleAnimEvent( animevent_t *pEvent );
virtual void GatherConditions();
virtual void GatherConditionsNotActive() { return; } // Override this and your behavior will call this in place of GatherConditions() when your behavior is NOT the active one.
virtual void OnUpdateShotRegulator() {}
virtual CAI_ClassScheduleIdSpace *GetClassScheduleIdSpace();
virtual int DrawDebugTextOverlays( int text_offset );
virtual int Save( ISave &save );
virtual int Restore( IRestore &restore );
static void SaveBehaviors(ISave &save, CAI_BehaviorBase *pCurrentBehavior, CAI_BehaviorBase **ppBehavior, int nBehaviors );
static int RestoreBehaviors(IRestore &restore, CAI_BehaviorBase **ppBehavior, int nBehaviors ); // returns index of "current" behavior, or -1
protected:
int GetNpcState() { return GetOuter()->m_NPCState; }
virtual void Precache() {}
virtual void Spawn() {}
virtual void UpdateOnRemove() {}
virtual void Event_Killed( const CTakeDamageInfo &info ) {}
virtual void CleanupOnDeath( CBaseEntity *pCulprit, bool bFireDeathOutput ) {}
virtual void PrescheduleThink();
virtual void OnScheduleChange();
virtual void OnStartSchedule( int scheduleType );
virtual int SelectSchedule();
virtual int SelectFailSchedule( int failedSchedule, int failedTask, AI_TaskFailureCode_t taskFailCode );
virtual void StartTask( const Task_t *pTask );
virtual void RunTask( const Task_t *pTask );
virtual void AimGun( void );
virtual int TranslateSchedule( int scheduleType );
virtual CAI_Schedule *GetSchedule(int schedule);
virtual const char *GetSchedulingErrorName();
virtual void BuildScheduleTestBits() {}
bool IsCurSchedule( int schedId, bool fIdeal = true );
CAI_Hint * GetHintNode() { return GetOuter()->GetHintNode(); }
const CAI_Hint *GetHintNode() const { return GetOuter()->GetHintNode(); }
void SetHintNode( CAI_Hint *pHintNode ) { GetOuter()->SetHintNode( pHintNode ); }
void ClearHintNode( float reuseDelay = 0.0 ) { GetOuter()->ClearHintNode( reuseDelay ); }
protected:
// Used by derived classes to chain a task to a task that might not be the
// one they are currently handling:
void ChainStartTask( int task, float taskData = 0 );
void ChainRunTask( int task, float taskData = 0 );
protected:
virtual Activity NPC_TranslateActivity( Activity activity );
virtual bool IsCurTaskContinuousMove();
virtual void OnMovementFailed() {};
virtual void OnMovementComplete() {};
virtual float GetDefaultNavGoalTolerance();
virtual bool FValidateHintType( CAI_Hint *pHint );
virtual bool IsValidEnemy( CBaseEntity *pEnemy );
virtual CBaseEntity *BestEnemy();
virtual bool IsValidCover( const Vector &vLocation, CAI_Hint const *pHint );
virtual bool IsValidShootPosition( const Vector &vLocation, CAI_Node *pNode, CAI_Hint const *pHint );
virtual float GetMaxTacticalLateralMovement( void );
virtual bool ShouldIgnoreSound( CSound *pSound );
virtual void OnSeeEntity( CBaseEntity *pEntity );
virtual void OnFriendDamaged( CBaseCombatCharacter *pSquadmate, CBaseEntity *pAttacker );
virtual bool IsInterruptable( void );
virtual bool IsNavigationUrgent( void );
virtual int OnTakeDamage_Alive( const CTakeDamageInfo &info );
virtual float GetReasonableFacingDist( void );
virtual bool ShouldPlayerAvoid( void );
virtual bool CanFlinch( void );
virtual bool IsCrouching( void );
virtual bool IsCrouchedActivity( Activity activity );
virtual bool QueryHearSound( CSound *pSound );
virtual bool CanRunAScriptedNPCInteraction( bool bForced );
virtual Activity GetFlinchActivity( bool bHeavyDamage, bool bGesture );
virtual bool OnCalcBaseMove( AILocalMoveGoal_t *pMoveGoal, float distClear, AIMoveResult_t *pResult );
virtual void ModifyOrAppendCriteria( AI_CriteriaSet& criteriaSet );
virtual void Teleport( const Vector *newPosition, const QAngle *newAngles, const Vector *newVelocity );
virtual void HandleAnimEvent( animevent_t *pEvent );
virtual bool ShouldAlwaysThink();
virtual void OnChangeActiveWeapon( CBaseCombatWeapon *pOldWeapon, CBaseCombatWeapon *pNewWeapon ) {};
virtual bool SpeakMapmakerInterruptConcept( string_t iszConcept ) { return false; };
virtual void OnRestore() {};
bool NotifyChangeBehaviorStatus( bool fCanFinishSchedule = false );
bool HaveSequenceForActivity( Activity activity ) { return GetOuter()->HaveSequenceForActivity( activity ); }
//---------------------------------
string_t GetHintGroup() { return GetOuter()->GetHintGroup(); }
void ClearHintGroup() { GetOuter()->ClearHintGroup(); }
void SetHintGroup( string_t name ) { GetOuter()->SetHintGroup( name ); }
virtual void OnChangeHintGroup( string_t oldGroup, string_t newGroup ) {}
//
// These allow derived classes to implement custom schedules
//
static CAI_GlobalScheduleNamespace *GetSchedulingSymbols() { return CAI_BaseNPC::GetSchedulingSymbols(); }
static bool LoadSchedules() { return true; }
virtual bool IsBehaviorSchedule( int scheduleType ) { return false; }
CAI_Navigator * GetNavigator() { return GetOuter()->GetNavigator(); }
CAI_Motor * GetMotor() { return GetOuter()->GetMotor(); }
CAI_TacticalServices * GetTacticalServices() { return GetOuter()->GetTacticalServices(); }
bool m_fOverrode;
IBehaviorBackBridge *m_pBackBridge;
DECLARE_DATADESC();
};
//-----------------------------------------------------------------------------
// Purpose: Template provides provides back bridge to owning class and
// establishes namespace settings
//-----------------------------------------------------------------------------
template <class NPC_CLASS = CAI_BaseNPC, const int ID_SPACE_OFFSET = 100000>
class CAI_Behavior : public CAI_ComponentWithOuter<NPC_CLASS, CAI_BehaviorBase>
{
public:
DECLARE_CLASS_NOFRIEND( CAI_Behavior, NPC_CLASS );
enum
{
NEXT_TASK = ID_SPACE_OFFSET,
NEXT_SCHEDULE = ID_SPACE_OFFSET,
NEXT_CONDITION = ID_SPACE_OFFSET
};
void SetCondition( int condition )
{
if ( condition >= ID_SPACE_OFFSET && condition < ID_SPACE_OFFSET + 10000 ) // it's local to us
condition = GetClassScheduleIdSpace()->ConditionLocalToGlobal( condition );
this->GetOuter()->SetCondition( condition );
}
bool HasCondition( int condition )
{
if ( condition >= ID_SPACE_OFFSET && condition < ID_SPACE_OFFSET + 10000 ) // it's local to us
condition = GetClassScheduleIdSpace()->ConditionLocalToGlobal( condition );
return this->GetOuter()->HasCondition( condition );
}
bool HasInterruptCondition( int condition )
{
if ( condition >= ID_SPACE_OFFSET && condition < ID_SPACE_OFFSET + 10000 ) // it's local to us
condition = GetClassScheduleIdSpace()->ConditionLocalToGlobal( condition );
return this->GetOuter()->HasInterruptCondition( condition );
}
void ClearCondition( int condition )
{
if ( condition >= ID_SPACE_OFFSET && condition < ID_SPACE_OFFSET + 10000 ) // it's local to us
condition = GetClassScheduleIdSpace()->ConditionLocalToGlobal( condition );
this->GetOuter()->ClearCondition( condition );
}
protected:
CAI_Behavior(NPC_CLASS *pOuter = NULL)
: CAI_ComponentWithOuter<NPC_CLASS, CAI_BehaviorBase>(pOuter)
{
}
static CAI_GlobalScheduleNamespace *GetSchedulingSymbols()
{
return NPC_CLASS::GetSchedulingSymbols();
}
virtual CAI_ClassScheduleIdSpace *GetClassScheduleIdSpace()
{
return this->GetOuter()->GetClassScheduleIdSpace();
}
static CAI_ClassScheduleIdSpace &AccessClassScheduleIdSpaceDirect()
{
return NPC_CLASS::AccessClassScheduleIdSpaceDirect();
}
private:
virtual bool IsBehaviorSchedule( int scheduleType ) { return ( scheduleType >= ID_SPACE_OFFSET && scheduleType < ID_SPACE_OFFSET + 10000 ); }
};
//-----------------------------------------------------------------------------
// Purpose: Some bridges a little more complicated to allow behavior to see
// what base class would do or control order in which it's donw
//-----------------------------------------------------------------------------
abstract_class IBehaviorBackBridge
{
public:
virtual void BackBridge_GatherConditions() = 0;
virtual int BackBridge_SelectSchedule() = 0;
virtual int BackBridge_TranslateSchedule( int scheduleType ) = 0;
virtual Activity BackBridge_NPC_TranslateActivity( Activity activity ) = 0;
virtual bool BackBridge_IsValidEnemy(CBaseEntity *pEnemy) = 0;
virtual CBaseEntity* BackBridge_BestEnemy(void) = 0;
virtual bool BackBridge_IsValidCover( const Vector &vLocation, CAI_Hint const *pHint ) = 0;
virtual bool BackBridge_IsValidShootPosition( const Vector &vLocation, CAI_Node *pNode, CAI_Hint const *pHint ) = 0;
virtual float BackBridge_GetMaxTacticalLateralMovement( void ) = 0;
virtual bool BackBridge_ShouldIgnoreSound( CSound *pSound ) = 0;
virtual void BackBridge_OnSeeEntity( CBaseEntity *pEntity ) = 0;
virtual void BackBridge_OnFriendDamaged( CBaseCombatCharacter *pSquadmate, CBaseEntity *pAttacker ) = 0;
virtual bool BackBridge_IsInterruptable( void ) = 0;
virtual bool BackBridge_IsNavigationUrgent( void ) = 0;
virtual bool BackBridge_ShouldPlayerAvoid( void ) = 0;
virtual int BackBridge_OnTakeDamage_Alive( const CTakeDamageInfo &info ) = 0;
virtual float BackBridge_GetDefaultNavGoalTolerance() = 0;
virtual float BackBridge_GetReasonableFacingDist( void ) = 0;
virtual bool BackBridge_CanFlinch( void ) = 0;
virtual bool BackBridge_IsCrouching( void ) = 0;
virtual bool BackBridge_IsCrouchedActivity( Activity activity ) = 0;
virtual bool BackBridge_QueryHearSound( CSound *pSound ) = 0;
virtual bool BackBridge_CanRunAScriptedNPCInteraction( bool bForced ) = 0;
virtual Activity BackBridge_GetFlinchActivity( bool bHeavyDamage, bool bGesture ) = 0;
virtual bool BackBridge_OnCalcBaseMove( AILocalMoveGoal_t *pMoveGoal, float distClear, AIMoveResult_t *pResult ) = 0;
virtual void BackBridge_ModifyOrAppendCriteria( AI_CriteriaSet& criteriaSet ) = 0;
virtual void BackBridge_Teleport( const Vector *newPosition, const QAngle *newAngles, const Vector *newVelocity ) = 0;
virtual void BackBridge_HandleAnimEvent( animevent_t *pEvent ) = 0;
//-------------------------------------
};
//-----------------------------------------------------------------------------
// Purpose: The common instantiation of the above template
//-----------------------------------------------------------------------------
typedef CAI_Behavior<> CAI_SimpleBehavior;
//-----------------------------------------------------------------------------
// Purpose: Base class for AIs that want to act as a host for CAI_Behaviors
// NPCs aren't required to use this, but probably want to.
//-----------------------------------------------------------------------------
template <class BASE_NPC>
class CAI_BehaviorHost : public BASE_NPC,
private IBehaviorBackBridge
{
public:
DECLARE_CLASS_NOFRIEND( CAI_BehaviorHost, BASE_NPC );
CAI_BehaviorHost()
: m_pCurBehavior(NULL)
{
#ifdef DEBUG
m_fDebugInCreateBehaviors = false;
#endif
}
void CleanupOnDeath( CBaseEntity *pCulprit = NULL, bool bFireDeathOutput = true );
virtual int Save( ISave &save );
virtual int Restore( IRestore &restore );
virtual bool CreateComponents();
// Automatically called during entity construction, derived class calls AddBehavior()
virtual bool CreateBehaviors() { return true; }
// forces movement and sets a new schedule
virtual bool ScheduledMoveToGoalEntity( int scheduleType, CBaseEntity *pGoalEntity, Activity movementActivity );
virtual bool ScheduledFollowPath( int scheduleType, CBaseEntity *pPathStart, Activity movementActivity );
virtual void ForceSelectedGo(CBaseEntity *pPlayer, const Vector &targetPos, const Vector &traceDir, bool bRun);
virtual void ForceSelectedGoRandom(void);
// Bridges
void Precache();
void NPCInit();
void UpdateOnRemove();
void Event_Killed( const CTakeDamageInfo &info );
void GatherConditions();
void PrescheduleThink();
int SelectSchedule();
void KeepRunningBehavior();
int SelectFailSchedule( int failedSchedule, int failedTask, AI_TaskFailureCode_t taskFailCode );
void OnScheduleChange();
void OnStartSchedule( int scheduleType );
int TranslateSchedule( int scheduleType );
void StartTask( const Task_t *pTask );
void RunTask( const Task_t *pTask );
void AimGun( void );
CAI_Schedule * GetSchedule(int localScheduleID);
const char * TaskName(int taskID);
void BuildScheduleTestBits();
void OnChangeHintGroup( string_t oldGroup, string_t newGroup );
Activity NPC_TranslateActivity( Activity activity );
bool IsCurTaskContinuousMove();
void OnMovementFailed();
void OnMovementComplete();
bool FValidateHintType( CAI_Hint *pHint );
float GetDefaultNavGoalTolerance();
bool IsValidEnemy(CBaseEntity *pEnemy);
CBaseEntity* BestEnemy(void);
bool IsValidCover( const Vector &vLocation, CAI_Hint const *pHint );
bool IsValidShootPosition( const Vector &vLocation, CAI_Node *pNode, CAI_Hint const *pHint );
float GetMaxTacticalLateralMovement( void );
bool ShouldIgnoreSound( CSound *pSound );
void OnSeeEntity( CBaseEntity *pEntity );
void OnFriendDamaged( CBaseCombatCharacter *pSquadmate, CBaseEntity *pAttacker );
bool IsInterruptable( void );
bool IsNavigationUrgent( void );
bool ShouldPlayerAvoid( void );
int OnTakeDamage_Alive( const CTakeDamageInfo &info );
float GetReasonableFacingDist( void );
bool CanFlinch( void );
bool IsCrouching( void );
bool IsCrouchedActivity( Activity activity );
bool QueryHearSound( CSound *pSound );
bool CanRunAScriptedNPCInteraction( bool bForced );
Activity GetFlinchActivity( bool bHeavyDamage, bool bGesture );
bool OnCalcBaseMove( AILocalMoveGoal_t *pMoveGoal, float distClear, AIMoveResult_t *pResult );
void HandleAnimEvent( animevent_t *pEvent );
bool ShouldAlwaysThink();
void OnChangeActiveWeapon( CBaseCombatWeapon *pOldWeapon, CBaseCombatWeapon *pNewWeapon );
virtual bool SpeakMapmakerInterruptConcept( string_t iszConcept );
void OnRestore();
void ModifyOrAppendCriteria( AI_CriteriaSet& set );
void Teleport( const Vector *newPosition, const QAngle *newAngles, const Vector *newVelocity );
//---------------------------------
virtual bool OnBehaviorChangeStatus( CAI_BehaviorBase *pBehavior, bool fCanFinishSchedule );
virtual void OnChangeRunningBehavior( CAI_BehaviorBase *pOldBehavior, CAI_BehaviorBase *pNewBehavior );
protected:
void AddBehavior( CAI_BehaviorBase *pBehavior );
bool BehaviorSelectSchedule();
virtual bool ShouldBehaviorSelectSchedule( CAI_BehaviorBase *pBehavior ) { return true; }
bool IsRunningBehavior() const;
CAI_BehaviorBase *GetRunningBehavior();
CAI_BehaviorBase *DeferSchedulingToBehavior( CAI_BehaviorBase *pNewBehavior );
void ChangeBehaviorTo( CAI_BehaviorBase *pNewBehavior );
CAI_Schedule * GetNewSchedule();
CAI_Schedule * GetFailSchedule();
private:
void BackBridge_GatherConditions();
int BackBridge_SelectSchedule();
int BackBridge_TranslateSchedule( int scheduleType );
Activity BackBridge_NPC_TranslateActivity( Activity activity );
bool BackBridge_IsValidEnemy(CBaseEntity *pEnemy);
CBaseEntity* BackBridge_BestEnemy(void);
bool BackBridge_IsValidCover( const Vector &vLocation, CAI_Hint const *pHint );
bool BackBridge_IsValidShootPosition( const Vector &vLocation, CAI_Node *pNode, CAI_Hint const *pHint );
float BackBridge_GetMaxTacticalLateralMovement( void );
bool BackBridge_ShouldIgnoreSound( CSound *pSound );
void BackBridge_OnSeeEntity( CBaseEntity *pEntity );
void BackBridge_OnFriendDamaged( CBaseCombatCharacter *pSquadmate, CBaseEntity *pAttacker );
bool BackBridge_IsInterruptable( void );
bool BackBridge_IsNavigationUrgent( void );
bool BackBridge_ShouldPlayerAvoid( void );
int BackBridge_OnTakeDamage_Alive( const CTakeDamageInfo &info );
float BackBridge_GetDefaultNavGoalTolerance();
float BackBridge_GetReasonableFacingDist( void );
bool BackBridge_CanFlinch( void );
bool BackBridge_IsCrouching( void );
bool BackBridge_IsCrouchedActivity( Activity activity );
bool BackBridge_QueryHearSound( CSound *pSound );
bool BackBridge_CanRunAScriptedNPCInteraction( bool bForced );
Activity BackBridge_GetFlinchActivity( bool bHeavyDamage, bool bGesture );
bool BackBridge_OnCalcBaseMove( AILocalMoveGoal_t *pMoveGoal, float distClear, AIMoveResult_t *pResult );
void BackBridge_ModifyOrAppendCriteria( AI_CriteriaSet& criteriaSet );
void BackBridge_Teleport( const Vector *newPosition, const QAngle *newAngles, const Vector *newVelocity );
void BackBridge_HandleAnimEvent( animevent_t *pEvent );
CAI_BehaviorBase **AccessBehaviors();
int NumBehaviors();
CAI_BehaviorBase * m_pCurBehavior;
CUtlVector<CAI_BehaviorBase *> m_Behaviors;
bool m_bCalledBehaviorSelectSchedule;
#ifdef DEBUG
bool m_fDebugInCreateBehaviors;
#endif
};
//-----------------------------------------------------------------------------
// The first frame a behavior begins schedule selection, it won't have had it's GatherConditions()
// called. To fix this, BeginScheduleSelection() manually calls the new behavior's GatherConditions(),
// but sets this global so that the baseclass GatherConditions() isn't called as well.
extern bool g_bBehaviorHost_PreventBaseClassGatherConditions;
//-----------------------------------------------------------------------------
inline void CAI_BehaviorBase::BridgeOnStartSchedule( int scheduleType )
{
int localId = AI_IdIsGlobal( scheduleType ) ? GetClassScheduleIdSpace()->ScheduleGlobalToLocal( scheduleType ) : scheduleType;
OnStartSchedule( localId );
}
//-------------------------------------
inline int CAI_BehaviorBase::BridgeSelectSchedule()
{
int result = SelectSchedule();
if ( IsBehaviorSchedule( result ) )
return GetClassScheduleIdSpace()->ScheduleLocalToGlobal( result );
return result;
}
//-------------------------------------
inline bool CAI_BehaviorBase::BridgeSelectFailSchedule( int failedSchedule, int failedTask, AI_TaskFailureCode_t taskFailCode, int *pResult )
{
m_fOverrode = true;
int result = SelectFailSchedule( failedSchedule, failedTask, taskFailCode );
if ( m_fOverrode )
{
if ( result != SCHED_NONE )
{
if ( IsBehaviorSchedule( result ) )
*pResult = GetClassScheduleIdSpace()->ScheduleLocalToGlobal( result );
else
*pResult = result;
return true;
}
Warning( "An AI behavior is in control but has no recommended schedule\n" );
}
return false;
}
//-------------------------------------
inline bool CAI_BehaviorBase::BridgeStartTask( const Task_t *pTask )
{
m_fOverrode = true;
StartTask( pTask );
return m_fOverrode;
}
//-------------------------------------
inline bool CAI_BehaviorBase::BridgeRunTask( const Task_t *pTask)
{
m_fOverrode = true;
RunTask( pTask );
return m_fOverrode;
}
//-------------------------------------
inline bool CAI_BehaviorBase::BridgeAimGun( void )
{
m_fOverrode = true;
AimGun();
return m_fOverrode;
}
//-------------------------------------
inline void CAI_BehaviorBase::ChainStartTask( int task, float taskData )
{
Task_t tempTask = { task, taskData };
bool fPrevOverride = m_fOverrode;
GetOuter()->StartTask( (const Task_t *)&tempTask );
m_fOverrode = fPrevOverride;;
}
//-------------------------------------
inline void CAI_BehaviorBase::ChainRunTask( int task, float taskData )
{
Task_t tempTask = { task, taskData };
bool fPrevOverride = m_fOverrode;
GetOuter()->RunTask( (const Task_t *) &tempTask );
m_fOverrode = fPrevOverride;;
}
//-------------------------------------
inline int CAI_BehaviorBase::BridgeTranslateSchedule( int scheduleType )
{
int localId = AI_IdIsGlobal( scheduleType ) ? GetClassScheduleIdSpace()->ScheduleGlobalToLocal( scheduleType ) : scheduleType;
int result = TranslateSchedule( localId );
return result;
}
//-------------------------------------
inline bool CAI_BehaviorBase::BridgeGetSchedule( int localScheduleID, CAI_Schedule **ppResult )
{
*ppResult = GetSchedule( localScheduleID );
return (*ppResult != NULL );
}
//-------------------------------------
inline bool CAI_BehaviorBase::BridgeTaskName( int taskID, const char **ppResult )
{
if ( AI_IdIsLocal( taskID ) )
{
*ppResult = GetSchedulingSymbols()->TaskIdToSymbol( GetClassScheduleIdSpace()->TaskLocalToGlobal( taskID ) );
return (*ppResult != NULL );
}
return false;
}
//-------------------------------------
inline Activity CAI_BehaviorBase::BridgeNPC_TranslateActivity( Activity activity )
{
return NPC_TranslateActivity( activity );
}
//-------------------------------------
inline bool CAI_BehaviorBase::BridgeIsCurTaskContinuousMove( bool *pResult )
{
bool fPrevOverride = m_fOverrode;
m_fOverrode = true;
*pResult = IsCurTaskContinuousMove();
bool result = m_fOverrode;
m_fOverrode = fPrevOverride;
return result;
}
//-------------------------------------
inline bool CAI_BehaviorBase::BridgeFValidateHintType( CAI_Hint *pHint, bool *pResult )
{
bool fPrevOverride = m_fOverrode;
m_fOverrode = true;
*pResult = FValidateHintType( pHint );
bool result = m_fOverrode;
m_fOverrode = fPrevOverride;
return result;
}
//-------------------------------------
inline bool CAI_BehaviorBase::BridgeIsValidEnemy( CBaseEntity *pEnemy )
{
return IsValidEnemy( pEnemy );
}
//-------------------------------------
inline CBaseEntity *CAI_BehaviorBase::BridgeBestEnemy()
{
return BestEnemy();
}
//-------------------------------------
inline bool CAI_BehaviorBase::BridgeIsValidCover( const Vector &vLocation, CAI_Hint const *pHint )
{
return IsValidCover( vLocation, pHint );
}
//-------------------------------------
inline bool CAI_BehaviorBase::BridgeIsValidShootPosition( const Vector &vLocation, CAI_Node *pNode, CAI_Hint const *pHint )
{
return IsValidShootPosition( vLocation, pNode, pHint );
}
//-------------------------------------
inline float CAI_BehaviorBase::BridgeGetMaxTacticalLateralMovement( void )
{
return GetMaxTacticalLateralMovement();
}
//-------------------------------------
inline bool CAI_BehaviorBase::BridgeShouldIgnoreSound( CSound *pSound )
{
return ShouldIgnoreSound( pSound );
}
//-------------------------------------
inline void CAI_BehaviorBase::BridgeOnSeeEntity( CBaseEntity *pEntity )
{
OnSeeEntity( pEntity );
}
//-------------------------------------
inline void CAI_BehaviorBase::BridgeOnFriendDamaged( CBaseCombatCharacter *pSquadmate, CBaseEntity *pAttacker )
{
OnFriendDamaged( pSquadmate, pAttacker );
}
//-------------------------------------
inline bool CAI_BehaviorBase::BridgeIsInterruptable( void )
{
return IsInterruptable();
}
//-------------------------------------
inline bool CAI_BehaviorBase::BridgeIsNavigationUrgent( void )
{
return IsNavigationUrgent();
}
//-------------------------------------
inline bool CAI_BehaviorBase::BridgeCanFlinch( void )
{
return CanFlinch();
}
//-------------------------------------
inline bool CAI_BehaviorBase::BridgeIsCrouching( void )
{
return IsCrouching();
}
//-------------------------------------
inline bool CAI_BehaviorBase::BridgeIsCrouchedActivity( Activity activity )
{
return IsCrouchedActivity( activity );
}
inline bool CAI_BehaviorBase::BridgeQueryHearSound( CSound *pSound )
{
return QueryHearSound( pSound );
}
//-------------------------------------
inline bool CAI_BehaviorBase::BridgeCanRunAScriptedNPCInteraction( bool bForced )
{
return CanRunAScriptedNPCInteraction( bForced );
}
//-------------------------------------
inline bool CAI_BehaviorBase::BridgeShouldPlayerAvoid( void )
{
return ShouldPlayerAvoid();
}
//-------------------------------------
inline int CAI_BehaviorBase::BridgeOnTakeDamage_Alive( const CTakeDamageInfo &info )
{
return OnTakeDamage_Alive( info );
}
//-------------------------------------
inline float CAI_BehaviorBase::BridgeGetReasonableFacingDist( void )
{
return GetReasonableFacingDist();
}
//-------------------------------------
inline bool CAI_BehaviorBase::BridgeShouldAlwaysThink( bool *pResult )
{
bool fPrevOverride = m_fOverrode;
m_fOverrode = true;
*pResult = ShouldAlwaysThink();
bool result = m_fOverrode;
m_fOverrode = fPrevOverride;
return result;
}
//-------------------------------------
inline void CAI_BehaviorBase::BridgeOnChangeActiveWeapon( CBaseCombatWeapon *pOldWeapon, CBaseCombatWeapon *pNewWeapon )
{
OnChangeActiveWeapon( pOldWeapon, pNewWeapon );
}
//-------------------------------------
inline bool CAI_BehaviorBase::BridgeSpeakMapmakerInterruptConcept( string_t iszConcept )
{
return SpeakMapmakerInterruptConcept( iszConcept );
}
//-------------------------------------
inline void CAI_BehaviorBase::BridgeOnRestore()
{
OnRestore();
}
//-------------------------------------
inline float CAI_BehaviorBase::BridgeGetDefaultNavGoalTolerance()
{
return GetDefaultNavGoalTolerance();
}
//-----------------------------------------------------------------------------
inline Activity CAI_BehaviorBase::BridgeGetFlinchActivity( bool bHeavyDamage, bool bGesture )
{
return GetFlinchActivity( bHeavyDamage, bGesture );
}
//-----------------------------------------------------------------------------
inline bool CAI_BehaviorBase::BridgeOnCalcBaseMove( AILocalMoveGoal_t *pMoveGoal, float distClear, AIMoveResult_t *pResult )
{
return OnCalcBaseMove( pMoveGoal, distClear, pResult );
}
//-----------------------------------------------------------------------------
inline void CAI_BehaviorBase::BridgeModifyOrAppendCriteria( AI_CriteriaSet& criteriaSet )
{
ModifyOrAppendCriteria( criteriaSet );
}
//-----------------------------------------------------------------------------
inline void CAI_BehaviorBase::BridgeTeleport( const Vector *newPosition, const QAngle *newAngles, const Vector *newVelocity )
{
Teleport( newPosition, newAngles, newVelocity );
}
//-----------------------------------------------------------------------------
inline void CAI_BehaviorBase::BridgeHandleAnimEvent( animevent_t *pEvent )
{
HandleAnimEvent( pEvent );
}
//-----------------------------------------------------------------------------
template <class BASE_NPC>
inline void CAI_BehaviorHost<BASE_NPC>::CleanupOnDeath( CBaseEntity *pCulprit, bool bFireDeathOutput )
{
DeferSchedulingToBehavior( NULL );
for( int i = 0; i < m_Behaviors.Count(); i++ )
{
m_Behaviors[i]->BridgeCleanupOnDeath( pCulprit, bFireDeathOutput );
}
BaseClass::CleanupOnDeath( pCulprit, bFireDeathOutput );
}
//-------------------------------------
template <class BASE_NPC>
inline void CAI_BehaviorHost<BASE_NPC>::GatherConditions()
{
// Iterate over behaviors and call GatherConditionsNotActive() on each behavior
// not currently active.
for( int i = 0; i < m_Behaviors.Count(); i++ )
{
if( m_Behaviors[i] != m_pCurBehavior )
{
m_Behaviors[i]->GatherConditionsNotActive();
}
}
if ( m_pCurBehavior )
m_pCurBehavior->BridgeGatherConditions();
else
BaseClass::GatherConditions();
}
//-------------------------------------
template <class BASE_NPC>
inline void CAI_BehaviorHost<BASE_NPC>::BackBridge_GatherConditions()
{
if ( g_bBehaviorHost_PreventBaseClassGatherConditions )
return;
BaseClass::GatherConditions();
}
//-------------------------------------
template <class BASE_NPC>
inline void CAI_BehaviorHost<BASE_NPC>::OnScheduleChange()
{
if ( m_pCurBehavior )
m_pCurBehavior->BridgeOnScheduleChange();
BaseClass::OnScheduleChange();
}
//-------------------------------------
template <class BASE_NPC>
inline void CAI_BehaviorHost<BASE_NPC>::OnStartSchedule( int scheduleType )
{
if ( m_pCurBehavior )
m_pCurBehavior->BridgeOnStartSchedule( scheduleType );
BaseClass::OnStartSchedule( scheduleType );
}
//-------------------------------------
template <class BASE_NPC>
inline int CAI_BehaviorHost<BASE_NPC>::BackBridge_SelectSchedule()
{
return BaseClass::SelectSchedule();
}
//-------------------------------------
template <class BASE_NPC>
inline bool CAI_BehaviorHost<BASE_NPC>::BehaviorSelectSchedule()
{
for ( int i = 0; i < m_Behaviors.Count(); i++ )
{
if ( m_Behaviors[i]->CanSelectSchedule() && ShouldBehaviorSelectSchedule( m_Behaviors[i] ) )
{
DeferSchedulingToBehavior( m_Behaviors[i] );
return true;
}
}
DeferSchedulingToBehavior( NULL );
return false;
}
//-------------------------------------
template <class BASE_NPC>
inline bool CAI_BehaviorHost<BASE_NPC>::IsRunningBehavior() const
{
return ( m_pCurBehavior != NULL );
}
//-------------------------------------
template <class BASE_NPC>
inline CAI_BehaviorBase *CAI_BehaviorHost<BASE_NPC>::GetRunningBehavior()
{
return m_pCurBehavior;
}
//-------------------------------------
template <class BASE_NPC>
inline CAI_Schedule *CAI_BehaviorHost<BASE_NPC>::GetNewSchedule()
{
m_bCalledBehaviorSelectSchedule = false;
CAI_Schedule *pResult = BaseClass::GetNewSchedule();
if ( !m_bCalledBehaviorSelectSchedule && m_pCurBehavior )
DeferSchedulingToBehavior( NULL );
return pResult;
}
//-------------------------------------
template <class BASE_NPC>
inline CAI_Schedule *CAI_BehaviorHost<BASE_NPC>::GetFailSchedule()
{
m_bCalledBehaviorSelectSchedule = false;
CAI_Schedule *pResult = BaseClass::GetFailSchedule();
if ( !m_bCalledBehaviorSelectSchedule && m_pCurBehavior )
DeferSchedulingToBehavior( NULL );
return pResult;
}
//------------------------------------
template <class BASE_NPC>
inline void CAI_BehaviorHost<BASE_NPC>::ChangeBehaviorTo( CAI_BehaviorBase *pNewBehavior )
{
bool change = ( m_pCurBehavior != pNewBehavior );
CAI_BehaviorBase *pOldBehavior = m_pCurBehavior;
m_pCurBehavior = pNewBehavior;
if ( change )
{
if ( m_pCurBehavior )
{
m_pCurBehavior->BeginScheduleSelection();
g_bBehaviorHost_PreventBaseClassGatherConditions = true;
m_pCurBehavior->GatherConditions();
g_bBehaviorHost_PreventBaseClassGatherConditions = false;
}
if ( pOldBehavior )
{
pOldBehavior->EndScheduleSelection();
this->VacateStrategySlot();
}
OnChangeRunningBehavior( pOldBehavior, pNewBehavior );
}
}
//-------------------------------------
template <class BASE_NPC>
inline CAI_BehaviorBase *CAI_BehaviorHost<BASE_NPC>::DeferSchedulingToBehavior( CAI_BehaviorBase *pNewBehavior )
{
CAI_BehaviorBase *pOldBehavior = m_pCurBehavior;
ChangeBehaviorTo( pNewBehavior );
return pOldBehavior;
}
//-------------------------------------
template <class BASE_NPC>
inline int CAI_BehaviorHost<BASE_NPC>::BackBridge_TranslateSchedule( int scheduleType )
{
return BaseClass::TranslateSchedule( scheduleType );
}
//-------------------------------------
template <class BASE_NPC>
inline int CAI_BehaviorHost<BASE_NPC>::TranslateSchedule( int scheduleType )
{
if ( m_pCurBehavior )
{
return m_pCurBehavior->BridgeTranslateSchedule( scheduleType );
}
return BaseClass::TranslateSchedule( scheduleType );
}
//-------------------------------------
template <class BASE_NPC>
inline void CAI_BehaviorHost<BASE_NPC>::PrescheduleThink()
{
BaseClass::PrescheduleThink();
if ( m_pCurBehavior )
m_pCurBehavior->BridgePrescheduleThink();
}
//-------------------------------------
template <class BASE_NPC>
inline int CAI_BehaviorHost<BASE_NPC>::SelectSchedule()
{
m_bCalledBehaviorSelectSchedule = true;
if ( m_pCurBehavior )
{
return m_pCurBehavior->BridgeSelectSchedule();
}
return BaseClass::SelectSchedule();
}
//-------------------------------------
template <class BASE_NPC>
inline void CAI_BehaviorHost<BASE_NPC>::KeepRunningBehavior()
{
if ( m_pCurBehavior )
m_bCalledBehaviorSelectSchedule = true;
}
//-------------------------------------
template <class BASE_NPC>
inline int CAI_BehaviorHost<BASE_NPC>::SelectFailSchedule( int failedSchedule, int failedTask, AI_TaskFailureCode_t taskFailCode )
{
m_bCalledBehaviorSelectSchedule = true;
int result = 0;
if ( m_pCurBehavior && m_pCurBehavior->BridgeSelectFailSchedule( failedSchedule, failedTask, taskFailCode, &result ) )
return result;
return BaseClass::SelectFailSchedule( failedSchedule, failedTask, taskFailCode );
}
//-------------------------------------
template <class BASE_NPC>
inline void CAI_BehaviorHost<BASE_NPC>::StartTask( const Task_t *pTask )
{
if ( m_pCurBehavior && m_pCurBehavior->BridgeStartTask( pTask ) )
return;
BaseClass::StartTask( pTask );
}
//-------------------------------------
template <class BASE_NPC>
inline void CAI_BehaviorHost<BASE_NPC>::RunTask( const Task_t *pTask )
{
if ( m_pCurBehavior && m_pCurBehavior->BridgeRunTask( pTask ) )
return;
BaseClass::RunTask( pTask );
}
//-------------------------------------
template <class BASE_NPC>
inline void CAI_BehaviorHost<BASE_NPC>::AimGun( void )
{
if ( m_pCurBehavior && m_pCurBehavior->BridgeAimGun() )
return;
BaseClass::AimGun();
}
//-------------------------------------
template <class BASE_NPC>
inline CAI_Schedule *CAI_BehaviorHost<BASE_NPC>::GetSchedule(int localScheduleID)
{
CAI_Schedule *pResult;
if ( m_pCurBehavior && m_pCurBehavior->BridgeGetSchedule( localScheduleID, &pResult ) )
return pResult;
return BaseClass::GetSchedule( localScheduleID );
}
//-------------------------------------
template <class BASE_NPC>
inline const char *CAI_BehaviorHost<BASE_NPC>::TaskName(int taskID)
{
const char *pszResult = NULL;
if ( m_pCurBehavior && m_pCurBehavior->BridgeTaskName( taskID, &pszResult ) )
return pszResult;
return BaseClass::TaskName( taskID );
}
//-------------------------------------
template <class BASE_NPC>
inline void CAI_BehaviorHost<BASE_NPC>::BuildScheduleTestBits()
{
if ( m_pCurBehavior )
m_pCurBehavior->BridgeBuildScheduleTestBits();
BaseClass::BuildScheduleTestBits();
}
//-------------------------------------
template <class BASE_NPC>
inline void CAI_BehaviorHost<BASE_NPC>::OnChangeHintGroup( string_t oldGroup, string_t newGroup )
{
for( int i = 0; i < m_Behaviors.Count(); i++ )
{
m_Behaviors[i]->BridgeOnChangeHintGroup( oldGroup, newGroup );
}
BaseClass::OnChangeHintGroup( oldGroup, newGroup );
}
//-------------------------------------
template <class BASE_NPC>
inline Activity CAI_BehaviorHost<BASE_NPC>::BackBridge_NPC_TranslateActivity( Activity activity )
{
return BaseClass::NPC_TranslateActivity( activity );
}
//-------------------------------------
template <class BASE_NPC>
inline Activity CAI_BehaviorHost<BASE_NPC>::NPC_TranslateActivity( Activity activity )
{
if ( m_pCurBehavior )
{
return m_pCurBehavior->BridgeNPC_TranslateActivity( activity );
}
return BaseClass::NPC_TranslateActivity( activity );
}
//-------------------------------------
template <class BASE_NPC>
inline bool CAI_BehaviorHost<BASE_NPC>::IsCurTaskContinuousMove()
{
bool result = false;
if ( m_pCurBehavior && m_pCurBehavior->BridgeIsCurTaskContinuousMove( &result ) )
return result;
return BaseClass::IsCurTaskContinuousMove();
}
//-------------------------------------
template <class BASE_NPC>
inline void CAI_BehaviorHost<BASE_NPC>::OnMovementFailed()
{
if ( m_pCurBehavior )
m_pCurBehavior->BridgeOnMovementFailed();
BaseClass::OnMovementFailed();
}
//-------------------------------------
template <class BASE_NPC>
inline void CAI_BehaviorHost<BASE_NPC>::OnMovementComplete()
{
if ( m_pCurBehavior )
m_pCurBehavior->BridgeOnMovementComplete();
BaseClass::OnMovementComplete();
}
//-------------------------------------
template <class BASE_NPC>
inline float CAI_BehaviorHost<BASE_NPC>::GetDefaultNavGoalTolerance()
{
if ( m_pCurBehavior )
return m_pCurBehavior->BridgeGetDefaultNavGoalTolerance();
return BaseClass::GetDefaultNavGoalTolerance();
}
//-------------------------------------
template <class BASE_NPC>
inline float CAI_BehaviorHost<BASE_NPC>::BackBridge_GetDefaultNavGoalTolerance()
{
return BaseClass::GetDefaultNavGoalTolerance();
}
//-------------------------------------
template <class BASE_NPC>
inline bool CAI_BehaviorHost<BASE_NPC>::FValidateHintType( CAI_Hint *pHint )
{
bool result = false;
if ( m_pCurBehavior && m_pCurBehavior->BridgeFValidateHintType( pHint, &result ) )
return result;
return BaseClass::FValidateHintType( pHint );
}
//-------------------------------------
template <class BASE_NPC>
inline bool CAI_BehaviorHost<BASE_NPC>::BackBridge_IsValidEnemy(CBaseEntity *pEnemy)
{
return BaseClass::IsValidEnemy( pEnemy );
}
//-------------------------------------
template <class BASE_NPC>
inline CBaseEntity *CAI_BehaviorHost<BASE_NPC>::BackBridge_BestEnemy(void)
{
return BaseClass::BestEnemy();
}
//-------------------------------------
template <class BASE_NPC>
inline bool CAI_BehaviorHost<BASE_NPC>::BackBridge_IsValidCover( const Vector &vLocation, CAI_Hint const *pHint )
{
return BaseClass::IsValidCover( vLocation, pHint );
}
//-------------------------------------
template <class BASE_NPC>
inline bool CAI_BehaviorHost<BASE_NPC>::BackBridge_IsValidShootPosition( const Vector &vLocation, CAI_Node *pNode, CAI_Hint const *pHint )
{
return BaseClass::IsValidShootPosition( vLocation, pNode, pHint );
}
//-------------------------------------
template <class BASE_NPC>
inline float CAI_BehaviorHost<BASE_NPC>::BackBridge_GetMaxTacticalLateralMovement( void )
{
return BaseClass::GetMaxTacticalLateralMovement();
}
//-------------------------------------
template <class BASE_NPC>
inline bool CAI_BehaviorHost<BASE_NPC>::BackBridge_ShouldIgnoreSound( CSound *pSound )
{
return BaseClass::ShouldIgnoreSound( pSound );
}
//-------------------------------------
template <class BASE_NPC>
inline void CAI_BehaviorHost<BASE_NPC>::BackBridge_OnSeeEntity( CBaseEntity *pEntity )
{
BaseClass::OnSeeEntity( pEntity );
}
//-------------------------------------
template <class BASE_NPC>
inline void CAI_BehaviorHost<BASE_NPC>::BackBridge_OnFriendDamaged( CBaseCombatCharacter *pSquadmate, CBaseEntity *pAttacker )
{
BaseClass::OnFriendDamaged( pSquadmate, pAttacker );
}
//-------------------------------------
template <class BASE_NPC>
inline bool CAI_BehaviorHost<BASE_NPC>::BackBridge_IsInterruptable( void )
{
return BaseClass::IsInterruptable();
}
//-------------------------------------
template <class BASE_NPC>
inline bool CAI_BehaviorHost<BASE_NPC>::BackBridge_IsNavigationUrgent( void )
{
return BaseClass::IsNavigationUrgent();
}
//-------------------------------------
template <class BASE_NPC>
inline bool CAI_BehaviorHost<BASE_NPC>::BackBridge_CanFlinch( void )
{
return BaseClass::CanFlinch();
}
//-------------------------------------
template <class BASE_NPC>
inline bool CAI_BehaviorHost<BASE_NPC>::BackBridge_IsCrouching( void )
{
return BaseClass::IsCrouching();
}
//-------------------------------------
template <class BASE_NPC>
inline bool CAI_BehaviorHost<BASE_NPC>::BackBridge_IsCrouchedActivity( Activity activity )
{
return BaseClass::IsCrouchedActivity( activity );
}
//-------------------------------------
template <class BASE_NPC>
inline bool CAI_BehaviorHost<BASE_NPC>::BackBridge_QueryHearSound( CSound *pSound )
{
return BaseClass::QueryHearSound( pSound );
}
//-------------------------------------
template <class BASE_NPC>
inline bool CAI_BehaviorHost<BASE_NPC>::BackBridge_CanRunAScriptedNPCInteraction( bool bForced )
{
return BaseClass::CanRunAScriptedNPCInteraction( bForced );
}
//-------------------------------------
template <class BASE_NPC>
inline bool CAI_BehaviorHost<BASE_NPC>::BackBridge_ShouldPlayerAvoid( void )
{
return BaseClass::ShouldPlayerAvoid();
}
//-------------------------------------
template <class BASE_NPC>
inline int CAI_BehaviorHost<BASE_NPC>::BackBridge_OnTakeDamage_Alive( const CTakeDamageInfo &info )
{
return BaseClass::OnTakeDamage_Alive( info );
}
//-------------------------------------
template <class BASE_NPC>
inline float CAI_BehaviorHost<BASE_NPC>::BackBridge_GetReasonableFacingDist( void )
{
return BaseClass::GetReasonableFacingDist();
}
//-------------------------------------
template <class BASE_NPC>
inline Activity CAI_BehaviorHost<BASE_NPC>::BackBridge_GetFlinchActivity( bool bHeavyDamage, bool bGesture )
{
return BaseClass::GetFlinchActivity( bHeavyDamage, bGesture );
}
//-------------------------------------
template <class BASE_NPC>
inline bool CAI_BehaviorHost<BASE_NPC>::BackBridge_OnCalcBaseMove( AILocalMoveGoal_t *pMoveGoal, float distClear, AIMoveResult_t *pResult )
{
return BaseClass::OnCalcBaseMove( pMoveGoal, distClear, pResult );
}
//-------------------------------------
template <class BASE_NPC>
inline void CAI_BehaviorHost<BASE_NPC>::BackBridge_ModifyOrAppendCriteria( AI_CriteriaSet &criteriaSet )
{
BaseClass::ModifyOrAppendCriteria( criteriaSet );
}
//-------------------------------------
template <class BASE_NPC>
inline void CAI_BehaviorHost<BASE_NPC>::BackBridge_Teleport( const Vector *newPosition, const QAngle *newAngles, const Vector *newVelocity )
{
BaseClass::Teleport( newPosition, newAngles, newVelocity );
}
//-------------------------------------
template <class BASE_NPC>
inline void CAI_BehaviorHost<BASE_NPC>::BackBridge_HandleAnimEvent( animevent_t *pEvent )
{
BaseClass::HandleAnimEvent( pEvent );
}
//-------------------------------------
template <class BASE_NPC>
inline bool CAI_BehaviorHost<BASE_NPC>::IsValidEnemy( CBaseEntity *pEnemy )
{
if ( m_pCurBehavior )
return m_pCurBehavior->BridgeIsValidEnemy( pEnemy );
return BaseClass::IsValidEnemy( pEnemy );
}
//-------------------------------------
template <class BASE_NPC>
inline CBaseEntity *CAI_BehaviorHost<BASE_NPC>::BestEnemy()
{
if ( m_pCurBehavior )
return m_pCurBehavior->BridgeBestEnemy();
return BaseClass::BestEnemy();
}
//-------------------------------------
template <class BASE_NPC>
inline bool CAI_BehaviorHost<BASE_NPC>::ShouldAlwaysThink()
{
bool result = false;
if ( m_pCurBehavior && m_pCurBehavior->BridgeShouldAlwaysThink( &result ) )
return result;
return BaseClass::ShouldAlwaysThink();
}
//-------------------------------------
template <class BASE_NPC>
inline void CAI_BehaviorHost<BASE_NPC>::OnChangeActiveWeapon( CBaseCombatWeapon *pOldWeapon, CBaseCombatWeapon *pNewWeapon )
{
for( int i = 0; i < m_Behaviors.Count(); i++ )
{
m_Behaviors[i]->BridgeOnChangeActiveWeapon( pOldWeapon, pNewWeapon );
}
BaseClass::OnChangeActiveWeapon( pOldWeapon, pNewWeapon );
}
//-------------------------------------
template <class BASE_NPC>
inline bool CAI_BehaviorHost<BASE_NPC>::SpeakMapmakerInterruptConcept( string_t iszConcept )
{
for( int i = 0; i < m_Behaviors.Count(); i++ )
{
if ( m_Behaviors[i]->BridgeSpeakMapmakerInterruptConcept( iszConcept ) )
return true;
}
return false;
}
//-------------------------------------
template <class BASE_NPC>
inline void CAI_BehaviorHost<BASE_NPC>::OnRestore()
{
for( int i = 0; i < m_Behaviors.Count(); i++ )
{
m_Behaviors[i]->BridgeOnRestore();
}
BaseClass::OnRestore();
}
//-------------------------------------
template <class BASE_NPC>
inline bool CAI_BehaviorHost<BASE_NPC>::IsValidCover( const Vector &vLocation, CAI_Hint const *pHint )
{
if ( m_pCurBehavior )
return m_pCurBehavior->BridgeIsValidCover( vLocation, pHint );
return BaseClass::IsValidCover( vLocation, pHint );
}
//-------------------------------------
template <class BASE_NPC>
inline bool CAI_BehaviorHost<BASE_NPC>::IsValidShootPosition( const Vector &vLocation, CAI_Node *pNode, CAI_Hint const *pHint )
{
if ( m_pCurBehavior )
return m_pCurBehavior->BridgeIsValidShootPosition( vLocation, pNode, pHint );
return BaseClass::IsValidShootPosition( vLocation, pNode, pHint );
}
//-------------------------------------
template <class BASE_NPC>
inline float CAI_BehaviorHost<BASE_NPC>::GetMaxTacticalLateralMovement( void )
{
if ( m_pCurBehavior )
return m_pCurBehavior->BridgeGetMaxTacticalLateralMovement();
return BaseClass::GetMaxTacticalLateralMovement();
}
//-------------------------------------
template <class BASE_NPC>
inline bool CAI_BehaviorHost<BASE_NPC>::ShouldIgnoreSound( CSound *pSound )
{
if ( m_pCurBehavior )
return m_pCurBehavior->BridgeShouldIgnoreSound( pSound );
return BaseClass::ShouldIgnoreSound( pSound );
}
//-------------------------------------
template <class BASE_NPC>
inline void CAI_BehaviorHost<BASE_NPC>::OnSeeEntity( CBaseEntity *pEntity )
{
if ( m_pCurBehavior )
return m_pCurBehavior->BridgeOnSeeEntity( pEntity );
BaseClass::OnSeeEntity( pEntity );
}
//-------------------------------------
template <class BASE_NPC>
inline void CAI_BehaviorHost<BASE_NPC>::OnFriendDamaged( CBaseCombatCharacter *pSquadmate, CBaseEntity *pAttacker )
{
if ( m_pCurBehavior )
return m_pCurBehavior->BridgeOnFriendDamaged( pSquadmate, pAttacker );
BaseClass::OnFriendDamaged( pSquadmate, pAttacker );
}
//-------------------------------------
template <class BASE_NPC>
inline bool CAI_BehaviorHost<BASE_NPC>::IsInterruptable( void )
{
if ( m_pCurBehavior )
return m_pCurBehavior->BridgeIsInterruptable();
return BaseClass::IsInterruptable();
}
//-------------------------------------
template <class BASE_NPC>
inline bool CAI_BehaviorHost<BASE_NPC>::IsNavigationUrgent( void )
{
if ( m_pCurBehavior )
return m_pCurBehavior->BridgeIsNavigationUrgent();
return BaseClass::IsNavigationUrgent();
}
//-------------------------------------
template <class BASE_NPC>
inline bool CAI_BehaviorHost<BASE_NPC>::CanFlinch( void )
{
if ( m_pCurBehavior )
return m_pCurBehavior->BridgeCanFlinch();
return BaseClass::CanFlinch();
}
//-------------------------------------
template <class BASE_NPC>
inline bool CAI_BehaviorHost<BASE_NPC>::IsCrouching( void )
{
if ( m_pCurBehavior )
return m_pCurBehavior->BridgeIsCrouching();
return BaseClass::IsCrouching();
}
//-------------------------------------
template <class BASE_NPC>
inline bool CAI_BehaviorHost<BASE_NPC>::IsCrouchedActivity( Activity activity )
{
if ( m_pCurBehavior )
return m_pCurBehavior->BridgeIsCrouchedActivity( activity );
return BaseClass::IsCrouchedActivity( activity );
}
//-------------------------------------
template <class BASE_NPC>
inline bool CAI_BehaviorHost<BASE_NPC>::QueryHearSound( CSound *pSound )
{
if ( m_pCurBehavior )
return m_pCurBehavior->BridgeQueryHearSound( pSound );
return BaseClass::QueryHearSound( pSound );
}
//-------------------------------------
template <class BASE_NPC>
inline bool CAI_BehaviorHost<BASE_NPC>::CanRunAScriptedNPCInteraction( bool bForced )
{
if ( m_pCurBehavior )
return m_pCurBehavior->BridgeCanRunAScriptedNPCInteraction( bForced );
return BaseClass::CanRunAScriptedNPCInteraction( bForced );
}
//-------------------------------------
template <class BASE_NPC>
inline bool CAI_BehaviorHost<BASE_NPC>::ShouldPlayerAvoid( void )
{
if ( m_pCurBehavior )
return m_pCurBehavior->BridgeShouldPlayerAvoid();
return BaseClass::ShouldPlayerAvoid();
}
//-------------------------------------
template <class BASE_NPC>
inline int CAI_BehaviorHost<BASE_NPC>::OnTakeDamage_Alive( const CTakeDamageInfo &info )
{
if ( m_pCurBehavior )
return m_pCurBehavior->BridgeOnTakeDamage_Alive( info );
return BaseClass::OnTakeDamage_Alive( info );
}
//-------------------------------------
template <class BASE_NPC>
inline float CAI_BehaviorHost<BASE_NPC>::GetReasonableFacingDist( void )
{
if ( m_pCurBehavior )
return m_pCurBehavior->BridgeGetReasonableFacingDist();
return BaseClass::GetReasonableFacingDist();
}
//-------------------------------------
template <class BASE_NPC>
inline void CAI_BehaviorHost<BASE_NPC>::Precache()
{
BaseClass::Precache();
for( int i = 0; i < m_Behaviors.Count(); i++ )
{
m_Behaviors[i]->BridgePrecache();
}
}
//-------------------------------------
template <class BASE_NPC>
inline bool CAI_BehaviorHost<BASE_NPC>::ScheduledMoveToGoalEntity( int scheduleType, CBaseEntity *pGoalEntity, Activity movementActivity )
{
// If a behavior is active, we need to stop running it
ChangeBehaviorTo( NULL );
return BaseClass::ScheduledMoveToGoalEntity( scheduleType, pGoalEntity, movementActivity );
}
//-------------------------------------
template <class BASE_NPC>
inline bool CAI_BehaviorHost<BASE_NPC>::ScheduledFollowPath( int scheduleType, CBaseEntity *pPathStart, Activity movementActivity )
{
// If a behavior is active, we need to stop running it
ChangeBehaviorTo( NULL );
return BaseClass::ScheduledFollowPath( scheduleType, pPathStart, movementActivity );
}
//-------------------------------------
template <class BASE_NPC>
inline void CAI_BehaviorHost<BASE_NPC>::ForceSelectedGo(CBaseEntity *pPlayer, const Vector &targetPos, const Vector &traceDir, bool bRun)
{
// If a behavior is active, we need to stop running it
ChangeBehaviorTo( NULL );
BaseClass::ForceSelectedGo(pPlayer, targetPos, traceDir, bRun);
}
//-------------------------------------
template <class BASE_NPC>
inline void CAI_BehaviorHost<BASE_NPC>::ForceSelectedGoRandom(void)
{
// If a behavior is active, we need to stop running it
ChangeBehaviorTo( NULL );
BaseClass::ForceSelectedGoRandom();
}
//-------------------------------------
template <class BASE_NPC>
inline void CAI_BehaviorHost<BASE_NPC>::NPCInit()
{
BaseClass::NPCInit();
for( int i = 0; i < m_Behaviors.Count(); i++ )
{
m_Behaviors[i]->BridgeSpawn();
}
}
//-------------------------------------
template <class BASE_NPC>
inline void CAI_BehaviorHost<BASE_NPC>::UpdateOnRemove()
{
for( int i = 0; i < m_Behaviors.Count(); i++ )
{
m_Behaviors[i]->BridgeUpdateOnRemove();
}
BaseClass::UpdateOnRemove();
}
//-------------------------------------
template <class BASE_NPC>
inline void CAI_BehaviorHost<BASE_NPC>::Event_Killed( const CTakeDamageInfo &info )
{
for( int i = 0; i < m_Behaviors.Count(); i++ )
{
m_Behaviors[i]->BridgeEvent_Killed( info );
}
BaseClass::Event_Killed( info );
}
//-------------------------------------
template <class BASE_NPC>
inline Activity CAI_BehaviorHost<BASE_NPC>::GetFlinchActivity( bool bHeavyDamage, bool bGesture )
{
if ( m_pCurBehavior )
return m_pCurBehavior->BridgeGetFlinchActivity( bHeavyDamage, bGesture );
return BaseClass::GetFlinchActivity( bHeavyDamage, bGesture );
}
//-------------------------------------
template <class BASE_NPC>
inline bool CAI_BehaviorHost<BASE_NPC>::OnCalcBaseMove( AILocalMoveGoal_t *pMoveGoal, float distClear, AIMoveResult_t *pResult )
{
if ( m_pCurBehavior )
return m_pCurBehavior->BridgeOnCalcBaseMove( pMoveGoal, distClear, pResult );
return BaseClass::OnCalcBaseMove( pMoveGoal, distClear, pResult );
}
//-------------------------------------
template <class BASE_NPC>
inline void CAI_BehaviorHost<BASE_NPC>::ModifyOrAppendCriteria( AI_CriteriaSet &criteriaSet )
{
BaseClass::ModifyOrAppendCriteria( criteriaSet );
if ( m_pCurBehavior )
{
// Append active behavior name
criteriaSet.AppendCriteria( "active_behavior", GetRunningBehavior()->GetName() );
m_pCurBehavior->BridgeModifyOrAppendCriteria( criteriaSet );
return;
}
}
//-------------------------------------
template <class BASE_NPC>
inline void CAI_BehaviorHost<BASE_NPC>::Teleport( const Vector *newPosition, const QAngle *newAngles, const Vector *newVelocity )
{
if ( m_pCurBehavior )
{
m_pCurBehavior->BridgeTeleport( newPosition, newAngles, newVelocity );
return;
}
BaseClass::Teleport( newPosition, newAngles, newVelocity );
}
//-------------------------------------
template <class BASE_NPC>
inline void CAI_BehaviorHost<BASE_NPC>::HandleAnimEvent( animevent_t *pEvent )
{
if ( m_pCurBehavior )
return m_pCurBehavior->BridgeHandleAnimEvent( pEvent );
return BaseClass::HandleAnimEvent( pEvent );
}
//-------------------------------------
template <class BASE_NPC>
inline bool CAI_BehaviorHost<BASE_NPC>::OnBehaviorChangeStatus( CAI_BehaviorBase *pBehavior, bool fCanFinishSchedule )
{
if ( pBehavior == GetRunningBehavior() && !pBehavior->CanSelectSchedule() && !fCanFinishSchedule )
{
DeferSchedulingToBehavior( NULL );
return true;
}
return false;
}
//-------------------------------------
template <class BASE_NPC>
inline void CAI_BehaviorHost<BASE_NPC>::OnChangeRunningBehavior( CAI_BehaviorBase *pOldBehavior, CAI_BehaviorBase *pNewBehavior )
{
}
//-------------------------------------
template <class BASE_NPC>
inline void CAI_BehaviorHost<BASE_NPC>::AddBehavior( CAI_BehaviorBase *pBehavior )
{
#ifdef DEBUG
Assert( m_Behaviors.Find( pBehavior ) == m_Behaviors.InvalidIndex() );
Assert( m_fDebugInCreateBehaviors );
for ( int i = 0; i < m_Behaviors.Count(); i++)
{
Assert( typeid(*m_Behaviors[i]) != typeid(*pBehavior) );
}
#endif
m_Behaviors.AddToTail( pBehavior );
pBehavior->SetOuter( this );
pBehavior->SetBackBridge( this );
}
//-------------------------------------
template <class BASE_NPC>
inline CAI_BehaviorBase **CAI_BehaviorHost<BASE_NPC>::AccessBehaviors()
{
if (m_Behaviors.Count())
return m_Behaviors.Base();
return NULL;
}
//-------------------------------------
template <class BASE_NPC>
inline int CAI_BehaviorHost<BASE_NPC>::NumBehaviors()
{
return m_Behaviors.Count();
}
//-------------------------------------
template <class BASE_NPC>
inline int CAI_BehaviorHost<BASE_NPC>::Save( ISave &save )
{
int result = BaseClass::Save( save );
if ( result )
CAI_BehaviorBase::SaveBehaviors( save, m_pCurBehavior, AccessBehaviors(), NumBehaviors() );
return result;
}
//-------------------------------------
template <class BASE_NPC>
inline int CAI_BehaviorHost<BASE_NPC>::Restore( IRestore &restore )
{
int result = BaseClass::Restore( restore );
if ( result )
{
int iCurrent = CAI_BehaviorBase::RestoreBehaviors( restore, AccessBehaviors(), NumBehaviors() );
if ( iCurrent != -1 )
m_pCurBehavior = AccessBehaviors()[iCurrent];
else
m_pCurBehavior = NULL;
}
return result;
}
//-------------------------------------
template <class BASE_NPC>
inline bool CAI_BehaviorHost<BASE_NPC>::CreateComponents()
{
if ( BaseClass::CreateComponents() )
{
#ifdef DEBUG
m_fDebugInCreateBehaviors = true;
#endif
bool result = CreateBehaviors();
#ifdef DEBUG
m_fDebugInCreateBehaviors = false;
#endif
return result;
}
return false;
}
//-----------------------------------------------------------------------------
#endif // AI_BEHAVIOR_H