//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ //=============================================================================// #ifndef AI_BEHAVIOR_H #define AI_BEHAVIOR_H #include "ai_component.h" #include "ai_basenpc.h" #include "ai_default.h" #include "AI_Criteria.h" #include "networkvar.h" #ifdef DEBUG #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