//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // //=============================================================================// #ifndef AI_BEHAVIOR_ASSAULT_H #define AI_BEHAVIOR_ASSAULT_H #ifdef _WIN32 #pragma once #endif #include "simtimer.h" #include "ai_behavior.h" #include "ai_goalentity.h" #include "ai_moveshoot.h" #include "ai_utils.h" #define CUE_POINT_TOLERANCE (3.0*12.0) enum RallySelectMethod_t { RALLY_POINT_SELECT_CLOSEST = 0, RALLY_POINT_SELECT_RANDOM, RALLY_POINT_SELECT_FURTHEST }; enum BranchingMethod_t { BRANCH_RANDOM, BRANCH_CLOSEST, BRANCH_FURTHEST }; enum AssaultCue_t { CUE_NO_ASSAULT = 0, // used to indicate that no assault is being conducted presently CUE_ENTITY_INPUT = 1, CUE_PLAYER_GUNFIRE, CUE_DONT_WAIT, CUE_COMMANDER, CUE_NONE, }; enum { ASSAULT_SENTENCE_HIT_RALLY_POINT = SENTENCE_BASE_BEHAVIOR_INDEX, ASSAULT_SENTENCE_HIT_ASSAULT_POINT, ASSAULT_SENTENCE_SQUAD_ADVANCE_TO_RALLY, ASSAULT_SENTENCE_SQUAD_ADVANCE_TO_ASSAULT, ASSAULT_SENTENCE_COVER_NO_AMMO, ASSAULT_SENTENCE_UNDER_ATTACK, }; // Allow diversion from the assault up to this amount of time after last having an enemy #define ASSAULT_DIVERSION_TIME 4 #define SF_ASSAULTPOINT_CLEARONARRIVAL 0x00000001 //============================================================================= //============================================================================= class CAI_AssaultGoal : public CAI_GoalEntity { typedef CAI_GoalEntity BaseClass; virtual void EnableGoal( CAI_BaseNPC *pAI ); virtual void DisableGoal( CAI_BaseNPC *pAI ); string_t m_RallyPoint; int m_AssaultCue; int m_RallySelectMethod; int m_BranchMethod; void InputBeginAssault( inputdata_t &inputdata ); DECLARE_DATADESC(); friend class CAI_AssaultBehavior; }; //============================================================================= //============================================================================= class CRallyPoint : public CPointEntity { DECLARE_CLASS( CRallyPoint, CPointEntity ); public: CRallyPoint() { m_hLockedBy.Set(NULL); m_sExclusivity = RALLY_EXCLUSIVE_NOT_EVALUATED; } bool Lock( CBaseEntity *pLocker ) { if( IsLocked() ) { // Already locked. return false; } m_hLockedBy.Set( pLocker ); return true; } bool Unlock( CBaseEntity *pUnlocker ) { if( IsLocked() ) { if( m_hLockedBy.Get() != pUnlocker ) { // Refuse! Only the locker may unlock. return false; } } m_hLockedBy.Set( NULL ); return true; } bool IsLocked( void ) { return (m_hLockedBy.Get() != NULL); } bool ShouldBeLocked( void ) { return m_bShouldLock; } int DrawDebugTextOverlays(); bool IsExclusive(); enum { RALLY_EXCLUSIVE_NOT_EVALUATED = -1, RALLY_EXCLUSIVE_NO, RALLY_EXCLUSIVE_YES, }; string_t m_AssaultPointName; string_t m_RallySequenceName; float m_flAssaultDelay; int m_iPriority; int m_iStrictness; bool m_bForceCrouch; bool m_bIsUrgent; short m_sExclusivity; bool m_bShouldLock; COutputEvent m_OnArrival; DECLARE_DATADESC(); private: EHANDLE m_hLockedBy; }; //============================================================================= //============================================================================= class CAssaultPoint : public CPointEntity { DECLARE_CLASS( CAssaultPoint, CPointEntity ); public: CAssaultPoint() { // This used to be a constant in code. Now it's a keyfield in hammer. // So in the constructor, we set this value to the former constant // default value, for legacy maps. (sjb) m_flAssaultPointTolerance = CUE_POINT_TOLERANCE; } void InputSetClearOnContact( inputdata_t &inputdata ) { m_bClearOnContact = inputdata.value.Bool(); } void InputSetAllowDiversion( inputdata_t &inputdata ) { m_bAllowDiversion = inputdata.value.Bool(); } void InputSetForceClear( inputdata_t &inputdata ) { m_bInputForcedClear = inputdata.value.Bool(); } public: string_t m_AssaultHintGroup; string_t m_NextAssaultPointName; COutputEvent m_OnAssaultClear; float m_flAssaultTimeout; bool m_bClearOnContact; bool m_bAllowDiversion; float m_flAllowDiversionRadius; bool m_bNeverTimeout; int m_iStrictness; bool m_bForceCrouch; bool m_bIsUrgent; bool m_bInputForcedClear; float m_flAssaultPointTolerance; float m_flTimeLastUsed; COutputEvent m_OnArrival; DECLARE_DATADESC(); }; //============================================================================= //============================================================================= class CAI_AssaultBehavior : public CAI_SimpleBehavior { DECLARE_CLASS( CAI_AssaultBehavior, CAI_SimpleBehavior ); public: CAI_AssaultBehavior(); virtual const char *GetName() { return "Assault"; } virtual int DrawDebugTextOverlays( int text_offset ); virtual void OnRestore(); void SetGoal( CAI_AssaultGoal *pGoal ) { m_hGoal = pGoal; } bool CanRunAScriptedNPCInteraction( bool bForced ); virtual bool CanSelectSchedule(); virtual void BeginScheduleSelection(); virtual void EndScheduleSelection(); bool HasHitRallyPoint() { return m_bHitRallyPoint; } bool HasHitAssaultPoint() { return m_bHitAssaultPoint; } void ClearAssaultPoint( void ); void OnHitAssaultPoint( void ); bool PollAssaultCue( void ); void ReceiveAssaultCue( AssaultCue_t cue ); bool HasAssaultCue( void ) { return m_AssaultCue != CUE_NO_ASSAULT; } bool AssaultHasBegun(); CAssaultPoint *FindAssaultPoint( string_t iszAssaultPointName ); void SetAssaultPoint( CAssaultPoint *pAssaultPoint ); void GatherConditions( void ); void StartTask( const Task_t *pTask ); void RunTask( const Task_t *pTask ); void BuildScheduleTestBits(); int TranslateSchedule( int scheduleType ); void OnStartSchedule( int scheduleType ); void ClearSchedule( const char *szReason ); void InitializeBehavior(); void SetParameters( string_t rallypointname, AssaultCue_t assaultcue, int rallySelectMethod ); void SetParameters( CBaseEntity *pRallyEnt, AssaultCue_t assaultcue ); bool IsAllowedToDivert( void ); bool IsValidShootPosition( const Vector &vLocation, CAI_Node *pNode, CAI_Hint const *pHint ); float GetMaxTacticalLateralMovement( void ); void UpdateOnRemove(); bool OnStrictAssault( void ); bool UpdateForceCrouch( void ); bool IsForcingCrouch( void ); bool IsUrgent( void ); CRallyPoint *FindBestRallyPointInRadius( const Vector &vecCenter, float flRadius );; void Disable( void ) { m_AssaultCue = CUE_NO_ASSAULT; m_bHitRallyPoint = false; m_bHitAssaultPoint = false; } enum { SCHED_MOVE_TO_RALLY_POINT = BaseClass::NEXT_SCHEDULE, // Try to get out of the player's way SCHED_ASSAULT_FAILED_TO_MOVE, SCHED_FAIL_MOVE_TO_RALLY_POINT, SCHED_MOVE_TO_ASSAULT_POINT, SCHED_AT_ASSAULT_POINT, SCHED_HOLD_RALLY_POINT, SCHED_HOLD_ASSAULT_POINT, SCHED_WAIT_AND_CLEAR, SCHED_ASSAULT_MOVE_AWAY, SCHED_CLEAR_ASSAULT_POINT, NEXT_SCHEDULE, TASK_GET_PATH_TO_RALLY_POINT = BaseClass::NEXT_TASK, TASK_FACE_RALLY_POINT, TASK_GET_PATH_TO_ASSAULT_POINT, TASK_FACE_ASSAULT_POINT, TASK_HIT_ASSAULT_POINT, TASK_HIT_RALLY_POINT, TASK_AWAIT_CUE, TASK_AWAIT_ASSAULT_TIMEOUT, TASK_ANNOUNCE_CLEAR, TASK_WAIT_ASSAULT_DELAY, TASK_ASSAULT_MOVE_AWAY_PATH, TASK_ASSAULT_DEFER_SCHEDULE_SELECTION, NEXT_TASK, /* COND_PUT_CONDITIONS_HERE = BaseClass::NEXT_CONDITION, NEXT_CONDITION, */ }; DEFINE_CUSTOM_SCHEDULE_PROVIDER; public: CHandle m_hAssaultPoint; CHandle m_hRallyPoint; public: void UnlockRallyPoint( void ); private: void OnScheduleChange(); virtual int SelectSchedule(); AssaultCue_t m_AssaultCue; // the cue we're waiting for to begin the assault AssaultCue_t m_ReceivedAssaultCue; // the last assault cue we received from someone/thing external. bool m_bHitRallyPoint; bool m_bHitAssaultPoint; // Diversion bool m_bDiverting; float m_flLastSawAnEnemyAt; float m_flTimeDeferScheduleSelection; string_t m_AssaultPointName; CHandle m_hGoal; //--------------------------------- DECLARE_DATADESC(); }; #endif // AI_BEHAVIOR_ASSAULT_H