1921 lines
62 KiB
C++
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
|