//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // //=============================================================================// #ifndef AI_BEHAVIOR_FOLLOW_H #define AI_BEHAVIOR_FOLLOW_H #include "simtimer.h" #include "ai_behavior.h" #include "ai_goalentity.h" #include "ai_utils.h" #include "ai_moveshoot.h" #include "tier0/platform.h" #ifdef HL2_EPISODIC #include "hl2_gamerules.h" #endif #if defined( _WIN32 ) #pragma once #endif //----------------------------------------------------------------------------- // NOTE: these must correspond with the AI_FollowFormation_t array in AI_Behavior_Follow.cpp!! //----------------------------------------------------------------------------- enum AI_Formations_t { AIF_SIMPLE, AIF_WIDE, AIF_ANTLION, AIF_COMMANDER, AIF_TIGHT, AIF_MEDIUM, AIF_SIDEKICK, AIF_HUNTER, AIF_VORTIGAUNT, AIF_TOPDOWN_TIGHT, }; enum AI_FollowFormationFlags_t { AIFF_DEFAULT = 0, AIFF_USE_FOLLOW_POINTS = 0x01, AIFF_REQUIRE_LOS_OUTSIDE_COMBAT = 0x02, }; //----------------------------------------------------------------------------- // // CAI_FollowGoal // // Purpose: A level tool to control the follow behavior. Use is not required // in order to use behavior. // //----------------------------------------------------------------------------- class CAI_FollowGoal : public CAI_GoalEntity { DECLARE_CLASS( CAI_FollowGoal, CAI_GoalEntity ); public: virtual void EnableGoal( CAI_BaseNPC *pAI ); virtual void DisableGoal( CAI_BaseNPC *pAI ); #ifdef HL2_EPISODIC virtual void InputOutsideTransition( inputdata_t &inputdata ); #endif int m_iFormation; DECLARE_DATADESC(); }; //----------------------------------------------------------------------------- int AIGetNumFollowers( CBaseEntity *pEntity, string_t iszClassname = NULL_STRING ); //----------------------------------------------------------------------------- struct AI_FollowNavInfo_t { int flags; Vector position; float range; float Zrange; float tolerance; float followPointTolerance; float targetMoveTolerance; float repathOnRouteTolerance; float walkTolerance; float coverTolerance; float enemyLOSTolerance; float chaseEnemyTolerance; DECLARE_SIMPLE_DATADESC(); }; struct AI_FollowGroup_t; struct AI_FollowManagerInfoHandle_t { AI_FollowGroup_t *m_pGroup; intp m_hFollower; }; //------------------------------------- struct AI_FollowParams_t { AI_FollowParams_t( AI_Formations_t formation = AIF_SIMPLE, bool bNormalMemoryDiscard = false ) : formation(formation), bNormalMemoryDiscard( bNormalMemoryDiscard ) { } AI_Formations_t formation; bool bNormalMemoryDiscard; DECLARE_SIMPLE_DATADESC(); }; //------------------------------------- class CAI_FollowBehavior : public CAI_SimpleBehavior { DECLARE_CLASS( CAI_FollowBehavior, CAI_SimpleBehavior ); public: CAI_FollowBehavior( const AI_FollowParams_t ¶ms = AIF_SIMPLE ); ~CAI_FollowBehavior(); virtual int DrawDebugTextOverlays( int text_offset ); virtual void DrawDebugGeometryOverlays(); // Returns true if the NPC is actively following a target. bool IsActive( void ); void SetParameters( const AI_FollowParams_t ¶ms ); virtual const char *GetName() { return "Follow"; } AI_Formations_t GetFormation() const { return m_params.formation; } virtual bool CanSelectSchedule(); const AI_FollowNavInfo_t &GetFollowGoalInfo(); CBaseEntity * GetFollowTarget(); void SetFollowTarget( CBaseEntity *pLeader, bool fFinishCurSchedule = false ); CAI_FollowGoal *GetFollowGoal() { return m_hFollowGoalEnt; } // if any bool SetFollowGoal( CAI_FollowGoal *pGoal, bool fFinishCurSchedule = false ); void ClearFollowGoal( CAI_FollowGoal *pGoal ); void SetFollowGoalDirect( CAI_FollowGoal *pGoal ); virtual bool FarFromFollowTarget() { return ( m_hFollowTarget && (GetAbsOrigin() - m_hFollowTarget->GetAbsOrigin()).LengthSqr() > (75*12)*(75*12) ); } virtual bool TargetIsUnreachable() { return m_bTargetUnreachable; } int GetNumFailedFollowAttempts() { return m_nFailedFollowAttempts; } float GetTimeFailFollowStarted() { return m_flTimeFailFollowStarted; } bool FollowTargetVisible() { return HasCondition( COND_FOLLOW_TARGET_VISIBLE ); }; bool IsMovingToFollowTarget(); float GetGoalRange(); float GetGoalZRange(); virtual Activity NPC_TranslateActivity( Activity activity ); virtual int TranslateSchedule( int scheduleType ); virtual void StartTask( const Task_t *pTask ); virtual int SelectFailSchedule( int failedSchedule, int failedTask, AI_TaskFailureCode_t taskFailCode ); virtual void TaskComplete( bool fIgnoreSetFailedCondition = false ); virtual void GatherConditions(); protected: const Vector &GetGoalPosition(); virtual bool ShouldFollow(); friend class CAI_FollowManager; virtual void BeginScheduleSelection(); virtual void EndScheduleSelection(); virtual void CleanupOnDeath( CBaseEntity *pCulprit, bool bFireDeathOutput ); virtual void Precache(); virtual int SelectSchedule(); virtual int FollowCallBaseSelectSchedule() { return BaseClass::SelectSchedule(); } virtual void OnStartSchedule( int scheduleType ); virtual void RunTask( const Task_t *pTask ); void BuildScheduleTestBits(); bool IsCurScheduleFollowSchedule(); virtual bool IsCurTaskContinuousMove(); virtual void OnMovementFailed(); virtual void OnMovementComplete(); virtual bool FValidateHintType( CAI_Hint *pHint ); bool IsValidCover( const Vector &vLocation, CAI_Hint const *pHint ); bool IsValidShootPosition( const Vector &vLocation, CAI_Node *pNode, CAI_Hint const *pHint ); bool FindCoverFromEnemyAtFollowTarget( float coverRadius, Vector *pResult ); bool ShouldAlwaysThink(); bool ShouldMoveToFollowTarget(); int SelectScheduleManagePosition(); int SelectScheduleFollowPoints(); int SelectScheduleMoveToFormation(); void GetFollowTargetViewLoc( Vector *pResult); bool ValidateFaceTarget( Vector *pFaceTarget ); //---------------------------- bool ShouldUseFollowPoints(); bool HasFollowPoint(); void SetFollowPoint( CAI_Hint *pHintNode ); void ClearFollowPoint(); const Vector & GetFollowPoint(); CAI_Hint * FindFollowPoint(); bool IsFollowPointInRange(); bool ShouldIgnoreFollowPointFacing(); //---------------------------- bool UpdateFollowPosition(); const int GetGoalFlags(); float GetGoalTolerance(); bool PlayerIsPushing(); bool IsFollowTargetInRange( float rangeMultiplier = 1.0 ); bool IsFollowGoalInRange( float tolerance, float zTolerance, int flags ); virtual bool IsChaseGoalInRange(); void NoteFailedFollow(); void NoteSuccessfulFollow(); //---------------------------- protected: enum { SCHED_FOLLOWER_MOVE_AWAY_FAIL = BaseClass::NEXT_SCHEDULE, // Turn back toward player SCHED_FOLLOWER_MOVE_AWAY_END, SCHED_FOLLOW, SCHED_FOLLOWER_IDLE_STAND, SCHED_MOVE_TO_FACE_FOLLOW_TARGET, SCHED_FACE_FOLLOW_TARGET, SCHED_FOLLOWER_GO_TO_WAIT_POINT, SCHED_FOLLOWER_GO_TO_WAIT_POINT_FAIL, SCHED_FOLLOWER_STAND_AT_WAIT_POINT, SCHED_FOLLOWER_COMBAT_FACE, NEXT_SCHEDULE, TASK_CANT_FOLLOW = BaseClass::NEXT_TASK, TASK_FACE_FOLLOW_TARGET, TASK_MOVE_TO_FOLLOW_POSITION, TASK_GET_PATH_TO_FOLLOW_POSITION, TASK_SET_FOLLOW_TARGET_MARK, TASK_FOLLOWER_FACE_TACTICAL, TASK_SET_FOLLOW_DELAY, TASK_GET_PATH_TO_FOLLOW_POINT, TASK_ARRIVE_AT_FOLLOW_POINT, TASK_SET_FOLLOW_POINT_STAND_SCHEDULE, TASK_BEGIN_STAND_AT_WAIT_POINT, NEXT_TASK, COND_TARGET_MOVED_FROM_MARK = BaseClass::NEXT_CONDITION, COND_FOUND_WAIT_POINT, COND_FOLLOW_DELAY_EXPIRED, COND_FOLLOW_TARGET_VISIBLE, COND_FOLLOW_TARGET_NOT_VISIBLE, COND_FOLLOW_WAIT_POINT_INVALID, COND_FOLLOW_PLAYER_IS_LIT, COND_FOLLOW_PLAYER_IS_NOT_LIT, NEXT_CONDITION, }; DEFINE_CUSTOM_SCHEDULE_PROVIDER; protected: //---------------------------- EHANDLE m_hFollowTarget; AI_FollowNavInfo_t m_FollowNavGoal; float m_flTimeUpdatedFollowPosition; bool m_bFirstFacing; float m_flTimeFollowTargetVisible; CAI_MoveMonitor m_TargetMonitor; bool m_bTargetUnreachable; bool m_bFollowNavFailed; // Set when pathfinding fails to limit impact of m_FollowDelay on ShouldFollow int m_nFailedFollowAttempts; float m_flTimeFailFollowStarted; Vector m_vFollowMoveAnchor; bool m_bMovingToCover; float m_flOriginalEnemyDiscardTime; float m_SavedDistTooFar; CRandStopwatch m_FollowDelay; CSimpleSimTimer m_RepathOnFollowTimer; //--------------------------------- Activity m_CurrentFollowActivity; //--------------------------------- CRandSimTimer m_TimeBlockUseWaitPoint; CSimTimer m_TimeCheckForWaitPoint; CAI_Hint * m_pInterruptWaitPoint; //--------------------------------- CRandSimTimer m_TimeBeforeSpreadFacing; CRandSimTimer m_TimeNextSpreadFacing; //--------------------------------- AI_FollowManagerInfoHandle_t m_hFollowManagerInfo; AI_FollowParams_t m_params; //--------------------------------- CHandle m_hFollowGoalEnt; //--------------------------------- DECLARE_DATADESC(); }; //------------------------------------- inline const AI_FollowNavInfo_t &CAI_FollowBehavior::GetFollowGoalInfo() { return m_FollowNavGoal; } //------------------------------------- inline const int CAI_FollowBehavior::GetGoalFlags() { return m_FollowNavGoal.flags; } //------------------------------------- inline const Vector &CAI_FollowBehavior::GetGoalPosition() { return m_FollowNavGoal.position; } //------------------------------------- inline float CAI_FollowBehavior::GetGoalTolerance() { return m_FollowNavGoal.tolerance; } //------------------------------------- inline float CAI_FollowBehavior::GetGoalRange() { return m_FollowNavGoal.range; } //------------------------------------- inline float CAI_FollowBehavior::GetGoalZRange() { return m_FollowNavGoal.Zrange; } //----------------------------------------------------------------------------- #endif // AI_BEHAVIOR_FOLLOW_H