//========= 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 #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 CAI_Behavior : public CAI_ComponentWithOuter { 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(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 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 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 inline void CAI_BehaviorHost::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 inline void CAI_BehaviorHost::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 inline void CAI_BehaviorHost::BackBridge_GatherConditions() { if (g_bBehaviorHost_PreventBaseClassGatherConditions) return; BaseClass::GatherConditions(); } //------------------------------------- template inline void CAI_BehaviorHost::OnScheduleChange() { if (m_pCurBehavior) m_pCurBehavior->BridgeOnScheduleChange(); BaseClass::OnScheduleChange(); } //------------------------------------- template inline void CAI_BehaviorHost::OnStartSchedule(int scheduleType) { if (m_pCurBehavior) m_pCurBehavior->BridgeOnStartSchedule(scheduleType); BaseClass::OnStartSchedule(scheduleType); } //------------------------------------- template inline int CAI_BehaviorHost::BackBridge_SelectSchedule() { return BaseClass::SelectSchedule(); } //------------------------------------- template inline bool CAI_BehaviorHost::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 inline bool CAI_BehaviorHost::IsRunningBehavior() const { return (m_pCurBehavior != NULL); } //------------------------------------- template inline CAI_BehaviorBase *CAI_BehaviorHost::GetRunningBehavior() { return m_pCurBehavior; } //------------------------------------- template inline CAI_Schedule *CAI_BehaviorHost::GetNewSchedule() { m_bCalledBehaviorSelectSchedule = false; CAI_Schedule *pResult = BaseClass::GetNewSchedule(); if (!m_bCalledBehaviorSelectSchedule && m_pCurBehavior) DeferSchedulingToBehavior(NULL); return pResult; } //------------------------------------- template inline CAI_Schedule *CAI_BehaviorHost::GetFailSchedule() { m_bCalledBehaviorSelectSchedule = false; CAI_Schedule *pResult = BaseClass::GetFailSchedule(); if (!m_bCalledBehaviorSelectSchedule && m_pCurBehavior) DeferSchedulingToBehavior(NULL); return pResult; } //------------------------------------ template inline void CAI_BehaviorHost::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 inline CAI_BehaviorBase *CAI_BehaviorHost::DeferSchedulingToBehavior( CAI_BehaviorBase *pNewBehavior) { CAI_BehaviorBase *pOldBehavior = m_pCurBehavior; ChangeBehaviorTo(pNewBehavior); return pOldBehavior; } //------------------------------------- template inline int CAI_BehaviorHost::BackBridge_TranslateSchedule( int scheduleType) { return BaseClass::TranslateSchedule(scheduleType); } //------------------------------------- template inline int CAI_BehaviorHost::TranslateSchedule(int scheduleType) { if (m_pCurBehavior) { return m_pCurBehavior->BridgeTranslateSchedule(scheduleType); } return BaseClass::TranslateSchedule(scheduleType); } //------------------------------------- template inline void CAI_BehaviorHost::PrescheduleThink() { BaseClass::PrescheduleThink(); if (m_pCurBehavior) m_pCurBehavior->BridgePrescheduleThink(); } //------------------------------------- template inline int CAI_BehaviorHost::SelectSchedule() { m_bCalledBehaviorSelectSchedule = true; if (m_pCurBehavior) { return m_pCurBehavior->BridgeSelectSchedule(); } return BaseClass::SelectSchedule(); } //------------------------------------- template inline void CAI_BehaviorHost::KeepRunningBehavior() { if (m_pCurBehavior) m_bCalledBehaviorSelectSchedule = true; } //------------------------------------- template inline int CAI_BehaviorHost::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 inline void CAI_BehaviorHost::StartTask(const Task_t *pTask) { if (m_pCurBehavior && m_pCurBehavior->BridgeStartTask(pTask)) return; BaseClass::StartTask(pTask); } //------------------------------------- template inline void CAI_BehaviorHost::RunTask(const Task_t *pTask) { if (m_pCurBehavior && m_pCurBehavior->BridgeRunTask(pTask)) return; BaseClass::RunTask(pTask); } //------------------------------------- template inline void CAI_BehaviorHost::AimGun(void) { if (m_pCurBehavior && m_pCurBehavior->BridgeAimGun()) return; BaseClass::AimGun(); } //------------------------------------- template inline CAI_Schedule *CAI_BehaviorHost::GetSchedule( int localScheduleID) { CAI_Schedule *pResult; if (m_pCurBehavior && m_pCurBehavior->BridgeGetSchedule(localScheduleID, &pResult)) return pResult; return BaseClass::GetSchedule(localScheduleID); } //------------------------------------- template inline const char *CAI_BehaviorHost::TaskName(int taskID) { const char *pszResult = NULL; if (m_pCurBehavior && m_pCurBehavior->BridgeTaskName(taskID, &pszResult)) return pszResult; return BaseClass::TaskName(taskID); } //------------------------------------- template inline void CAI_BehaviorHost::BuildScheduleTestBits() { if (m_pCurBehavior) m_pCurBehavior->BridgeBuildScheduleTestBits(); BaseClass::BuildScheduleTestBits(); } //------------------------------------- template inline void CAI_BehaviorHost::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 inline Activity CAI_BehaviorHost::BackBridge_NPC_TranslateActivity( Activity activity) { return BaseClass::NPC_TranslateActivity(activity); } //------------------------------------- template inline Activity CAI_BehaviorHost::NPC_TranslateActivity( Activity activity) { if (m_pCurBehavior) { return m_pCurBehavior->BridgeNPC_TranslateActivity(activity); } return BaseClass::NPC_TranslateActivity(activity); } //------------------------------------- template inline bool CAI_BehaviorHost::IsCurTaskContinuousMove() { bool result = false; if (m_pCurBehavior && m_pCurBehavior->BridgeIsCurTaskContinuousMove(&result)) return result; return BaseClass::IsCurTaskContinuousMove(); } //------------------------------------- template inline void CAI_BehaviorHost::OnMovementFailed() { if (m_pCurBehavior) m_pCurBehavior->BridgeOnMovementFailed(); BaseClass::OnMovementFailed(); } //------------------------------------- template inline void CAI_BehaviorHost::OnMovementComplete() { if (m_pCurBehavior) m_pCurBehavior->BridgeOnMovementComplete(); BaseClass::OnMovementComplete(); } //------------------------------------- template inline float CAI_BehaviorHost::GetDefaultNavGoalTolerance() { if (m_pCurBehavior) return m_pCurBehavior->BridgeGetDefaultNavGoalTolerance(); return BaseClass::GetDefaultNavGoalTolerance(); } //------------------------------------- template inline float CAI_BehaviorHost::BackBridge_GetDefaultNavGoalTolerance() { return BaseClass::GetDefaultNavGoalTolerance(); } //------------------------------------- template inline bool CAI_BehaviorHost::FValidateHintType(CAI_Hint *pHint) { bool result = false; if (m_pCurBehavior && m_pCurBehavior->BridgeFValidateHintType(pHint, &result)) return result; return BaseClass::FValidateHintType(pHint); } //------------------------------------- template inline bool CAI_BehaviorHost::BackBridge_IsValidEnemy( CBaseEntity *pEnemy) { return BaseClass::IsValidEnemy(pEnemy); } //------------------------------------- template inline CBaseEntity *CAI_BehaviorHost::BackBridge_BestEnemy(void) { return BaseClass::BestEnemy(); } //------------------------------------- template inline bool CAI_BehaviorHost::BackBridge_IsValidCover( const Vector &vLocation, CAI_Hint const *pHint) { return BaseClass::IsValidCover(vLocation, pHint); } //------------------------------------- template inline bool CAI_BehaviorHost::BackBridge_IsValidShootPosition( const Vector &vLocation, CAI_Node *pNode, CAI_Hint const *pHint) { return BaseClass::IsValidShootPosition(vLocation, pNode, pHint); } //------------------------------------- template inline float CAI_BehaviorHost::BackBridge_GetMaxTacticalLateralMovement(void) { return BaseClass::GetMaxTacticalLateralMovement(); } //------------------------------------- template inline bool CAI_BehaviorHost::BackBridge_ShouldIgnoreSound( CSound *pSound) { return BaseClass::ShouldIgnoreSound(pSound); } //------------------------------------- template inline void CAI_BehaviorHost::BackBridge_OnSeeEntity( CBaseEntity *pEntity) { BaseClass::OnSeeEntity(pEntity); } //------------------------------------- template inline void CAI_BehaviorHost::BackBridge_OnFriendDamaged( CBaseCombatCharacter *pSquadmate, CBaseEntity *pAttacker) { BaseClass::OnFriendDamaged(pSquadmate, pAttacker); } //------------------------------------- template inline bool CAI_BehaviorHost::BackBridge_IsInterruptable(void) { return BaseClass::IsInterruptable(); } //------------------------------------- template inline bool CAI_BehaviorHost::BackBridge_IsNavigationUrgent(void) { return BaseClass::IsNavigationUrgent(); } //------------------------------------- template inline bool CAI_BehaviorHost::BackBridge_CanFlinch(void) { return BaseClass::CanFlinch(); } //------------------------------------- template inline bool CAI_BehaviorHost::BackBridge_IsCrouching(void) { return BaseClass::IsCrouching(); } //------------------------------------- template inline bool CAI_BehaviorHost::BackBridge_IsCrouchedActivity( Activity activity) { return BaseClass::IsCrouchedActivity(activity); } //------------------------------------- template inline bool CAI_BehaviorHost::BackBridge_QueryHearSound( CSound *pSound) { return BaseClass::QueryHearSound(pSound); } //------------------------------------- template inline bool CAI_BehaviorHost::BackBridge_CanRunAScriptedNPCInteraction( bool bForced) { return BaseClass::CanRunAScriptedNPCInteraction(bForced); } //------------------------------------- template inline bool CAI_BehaviorHost::BackBridge_ShouldPlayerAvoid(void) { return BaseClass::ShouldPlayerAvoid(); } //------------------------------------- template inline int CAI_BehaviorHost::BackBridge_OnTakeDamage_Alive( const CTakeDamageInfo &info) { return BaseClass::OnTakeDamage_Alive(info); } //------------------------------------- template inline float CAI_BehaviorHost::BackBridge_GetReasonableFacingDist( void) { return BaseClass::GetReasonableFacingDist(); } //------------------------------------- template inline Activity CAI_BehaviorHost::BackBridge_GetFlinchActivity( bool bHeavyDamage, bool bGesture) { return BaseClass::GetFlinchActivity(bHeavyDamage, bGesture); } //------------------------------------- template inline bool CAI_BehaviorHost::BackBridge_OnCalcBaseMove( AILocalMoveGoal_t *pMoveGoal, float distClear, AIMoveResult_t *pResult) { return BaseClass::OnCalcBaseMove(pMoveGoal, distClear, pResult); } //------------------------------------- template inline void CAI_BehaviorHost::BackBridge_ModifyOrAppendCriteria( AI_CriteriaSet &criteriaSet) { BaseClass::ModifyOrAppendCriteria(criteriaSet); } //------------------------------------- template inline void CAI_BehaviorHost::BackBridge_Teleport( const Vector *newPosition, const QAngle *newAngles, const Vector *newVelocity) { BaseClass::Teleport(newPosition, newAngles, newVelocity); } //------------------------------------- template inline void CAI_BehaviorHost::BackBridge_HandleAnimEvent( animevent_t *pEvent) { BaseClass::HandleAnimEvent(pEvent); } //------------------------------------- template inline bool CAI_BehaviorHost::IsValidEnemy(CBaseEntity *pEnemy) { if (m_pCurBehavior) return m_pCurBehavior->BridgeIsValidEnemy(pEnemy); return BaseClass::IsValidEnemy(pEnemy); } //------------------------------------- template inline CBaseEntity *CAI_BehaviorHost::BestEnemy() { if (m_pCurBehavior) return m_pCurBehavior->BridgeBestEnemy(); return BaseClass::BestEnemy(); } //------------------------------------- template inline bool CAI_BehaviorHost::ShouldAlwaysThink() { bool result = false; if (m_pCurBehavior && m_pCurBehavior->BridgeShouldAlwaysThink(&result)) return result; return BaseClass::ShouldAlwaysThink(); } //------------------------------------- template inline void CAI_BehaviorHost::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 inline bool CAI_BehaviorHost::SpeakMapmakerInterruptConcept( string_t iszConcept) { for (int i = 0; i < m_Behaviors.Count(); i++) { if (m_Behaviors[i]->BridgeSpeakMapmakerInterruptConcept(iszConcept)) return true; } return false; } //------------------------------------- template inline void CAI_BehaviorHost::OnRestore() { for (int i = 0; i < m_Behaviors.Count(); i++) { m_Behaviors[i]->BridgeOnRestore(); } BaseClass::OnRestore(); } //------------------------------------- template inline bool CAI_BehaviorHost::IsValidCover(const Vector &vLocation, CAI_Hint const *pHint) { if (m_pCurBehavior) return m_pCurBehavior->BridgeIsValidCover(vLocation, pHint); return BaseClass::IsValidCover(vLocation, pHint); } //------------------------------------- template inline bool CAI_BehaviorHost::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 inline float CAI_BehaviorHost::GetMaxTacticalLateralMovement(void) { if (m_pCurBehavior) return m_pCurBehavior->BridgeGetMaxTacticalLateralMovement(); return BaseClass::GetMaxTacticalLateralMovement(); } //------------------------------------- template inline bool CAI_BehaviorHost::ShouldIgnoreSound(CSound *pSound) { if (m_pCurBehavior) return m_pCurBehavior->BridgeShouldIgnoreSound(pSound); return BaseClass::ShouldIgnoreSound(pSound); } //------------------------------------- template inline void CAI_BehaviorHost::OnSeeEntity(CBaseEntity *pEntity) { if (m_pCurBehavior) return m_pCurBehavior->BridgeOnSeeEntity(pEntity); BaseClass::OnSeeEntity(pEntity); } //------------------------------------- template inline void CAI_BehaviorHost::OnFriendDamaged( CBaseCombatCharacter *pSquadmate, CBaseEntity *pAttacker) { if (m_pCurBehavior) return m_pCurBehavior->BridgeOnFriendDamaged(pSquadmate, pAttacker); BaseClass::OnFriendDamaged(pSquadmate, pAttacker); } //------------------------------------- template inline bool CAI_BehaviorHost::IsInterruptable(void) { if (m_pCurBehavior) return m_pCurBehavior->BridgeIsInterruptable(); return BaseClass::IsInterruptable(); } //------------------------------------- template inline bool CAI_BehaviorHost::IsNavigationUrgent(void) { if (m_pCurBehavior) return m_pCurBehavior->BridgeIsNavigationUrgent(); return BaseClass::IsNavigationUrgent(); } //------------------------------------- template inline bool CAI_BehaviorHost::CanFlinch(void) { if (m_pCurBehavior) return m_pCurBehavior->BridgeCanFlinch(); return BaseClass::CanFlinch(); } //------------------------------------- template inline bool CAI_BehaviorHost::IsCrouching(void) { if (m_pCurBehavior) return m_pCurBehavior->BridgeIsCrouching(); return BaseClass::IsCrouching(); } //------------------------------------- template inline bool CAI_BehaviorHost::IsCrouchedActivity(Activity activity) { if (m_pCurBehavior) return m_pCurBehavior->BridgeIsCrouchedActivity(activity); return BaseClass::IsCrouchedActivity(activity); } //------------------------------------- template inline bool CAI_BehaviorHost::QueryHearSound(CSound *pSound) { if (m_pCurBehavior) return m_pCurBehavior->BridgeQueryHearSound(pSound); return BaseClass::QueryHearSound(pSound); } //------------------------------------- template inline bool CAI_BehaviorHost::CanRunAScriptedNPCInteraction( bool bForced) { if (m_pCurBehavior) return m_pCurBehavior->BridgeCanRunAScriptedNPCInteraction(bForced); return BaseClass::CanRunAScriptedNPCInteraction(bForced); } //------------------------------------- template inline bool CAI_BehaviorHost::ShouldPlayerAvoid(void) { if (m_pCurBehavior) return m_pCurBehavior->BridgeShouldPlayerAvoid(); return BaseClass::ShouldPlayerAvoid(); } //------------------------------------- template inline int CAI_BehaviorHost::OnTakeDamage_Alive( const CTakeDamageInfo &info) { if (m_pCurBehavior) return m_pCurBehavior->BridgeOnTakeDamage_Alive(info); return BaseClass::OnTakeDamage_Alive(info); } //------------------------------------- template inline float CAI_BehaviorHost::GetReasonableFacingDist(void) { if (m_pCurBehavior) return m_pCurBehavior->BridgeGetReasonableFacingDist(); return BaseClass::GetReasonableFacingDist(); } //------------------------------------- template inline void CAI_BehaviorHost::Precache() { BaseClass::Precache(); for (int i = 0; i < m_Behaviors.Count(); i++) { m_Behaviors[i]->BridgePrecache(); } } //------------------------------------- template inline bool CAI_BehaviorHost::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 inline bool CAI_BehaviorHost::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 inline void CAI_BehaviorHost::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 inline void CAI_BehaviorHost::ForceSelectedGoRandom(void) { // If a behavior is active, we need to stop running it ChangeBehaviorTo(NULL); BaseClass::ForceSelectedGoRandom(); } //------------------------------------- template inline void CAI_BehaviorHost::NPCInit() { BaseClass::NPCInit(); for (int i = 0; i < m_Behaviors.Count(); i++) { m_Behaviors[i]->BridgeSpawn(); } } //------------------------------------- template inline void CAI_BehaviorHost::UpdateOnRemove() { for (int i = 0; i < m_Behaviors.Count(); i++) { m_Behaviors[i]->BridgeUpdateOnRemove(); } BaseClass::UpdateOnRemove(); } //------------------------------------- template inline void CAI_BehaviorHost::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 inline Activity CAI_BehaviorHost::GetFlinchActivity(bool bHeavyDamage, bool bGesture) { if (m_pCurBehavior) return m_pCurBehavior->BridgeGetFlinchActivity(bHeavyDamage, bGesture); return BaseClass::GetFlinchActivity(bHeavyDamage, bGesture); } //------------------------------------- template inline bool CAI_BehaviorHost::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 inline void CAI_BehaviorHost::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 inline void CAI_BehaviorHost::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 inline void CAI_BehaviorHost::HandleAnimEvent(animevent_t *pEvent) { if (m_pCurBehavior) return m_pCurBehavior->BridgeHandleAnimEvent(pEvent); return BaseClass::HandleAnimEvent(pEvent); } //------------------------------------- template inline bool CAI_BehaviorHost::OnBehaviorChangeStatus( CAI_BehaviorBase *pBehavior, bool fCanFinishSchedule) { if (pBehavior == GetRunningBehavior() && !pBehavior->CanSelectSchedule() && !fCanFinishSchedule) { DeferSchedulingToBehavior(NULL); return true; } return false; } //------------------------------------- template inline void CAI_BehaviorHost::OnChangeRunningBehavior( CAI_BehaviorBase *pOldBehavior, CAI_BehaviorBase *pNewBehavior) {} //------------------------------------- template inline void CAI_BehaviorHost::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 inline CAI_BehaviorBase **CAI_BehaviorHost::AccessBehaviors() { if (m_Behaviors.Count()) return m_Behaviors.Base(); return NULL; } //------------------------------------- template inline int CAI_BehaviorHost::NumBehaviors() { return m_Behaviors.Count(); } //------------------------------------- template inline int CAI_BehaviorHost::Save(ISave &save) { int result = BaseClass::Save(save); if (result) CAI_BehaviorBase::SaveBehaviors(save, m_pCurBehavior, AccessBehaviors(), NumBehaviors()); return result; } //------------------------------------- template inline int CAI_BehaviorHost::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 inline bool CAI_BehaviorHost::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