This repository has been archived on 2024-06-13. You can view files and clone it, but cannot push or open issues or pull requests.
2020-08-04 13:13:01 -04:00

1921 lines
62 KiB
C++

//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef AI_BEHAVIOR_H
#define AI_BEHAVIOR_H
#include "AI_Criteria.h"
#include "ai_basenpc.h"
#include "ai_component.h"
#include "ai_default.h"
#include "networkvar.h"
#ifdef DEBUG
#pragma warning(push)
#include <typeinfo>
#pragma warning(pop)
#pragma warning(disable : 4290)
#endif
#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