|
|
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef AI_BEHAVIOR_ACTBUSY_H
#define AI_BEHAVIOR_ACTBUSY_H
#ifdef _WIN32
#pragma once
#endif
#include "ai_behavior.h"
#include "ai_goalentity.h"
//-----------------------------------------------------------------------------
enum { ACTBUSY_TYPE_DEFAULT = 0, ACTBUSY_TYPE_COMBAT, };
enum busyinterrupt_t { BA_INT_NONE, // Nothing breaks us out of this
BA_INT_DANGER, // Only danger signals interrupts this busy anim. The player will be ignored.
BA_INT_PLAYER, // The Player's presence interrupts this busy anim
BA_INT_AMBUSH, // We're waiting to ambush enemies. Don't break on danger sounds in front of us.
BA_INT_COMBAT, // Only break out if we're shot at.
BA_INT_ZOMBIESLUMP, // Zombies who are slumped on the ground.
BA_INT_SIEGE_DEFENSE, };
enum busyanimparts_t { BA_BUSY, BA_ENTRY, BA_EXIT,
BA_MAX_ANIMS, };
struct busyanim_t { string_t iszName; Activity iActivities[BA_MAX_ANIMS]; string_t iszSequences[BA_MAX_ANIMS]; string_t iszSounds[BA_MAX_ANIMS]; float flMinTime; // Min time spent in this busy animation
float flMaxTime; // Max time spent in this busy animation. 0 means continue until interrupted.
busyinterrupt_t iBusyInterruptType; bool bUseAutomovement; };
struct busysafezone_t { Vector vecMins; Vector vecMaxs; };
#define NO_MAX_TIME -1
class CAI_ActBusyGoal;
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class CAI_ActBusyBehavior : public CAI_SimpleBehavior { DECLARE_CLASS( CAI_ActBusyBehavior, CAI_SimpleBehavior ); public: DECLARE_DATADESC(); CAI_ActBusyBehavior();
enum { // Schedules
SCHED_ACTBUSY_START_BUSYING = BaseClass::NEXT_SCHEDULE, SCHED_ACTBUSY_BUSY, SCHED_ACTBUSY_STOP_BUSYING, SCHED_ACTBUSY_LEAVE, SCHED_ACTBUSY_TELEPORT_TO_BUSY, NEXT_SCHEDULE, // Tasks
TASK_ACTBUSY_PLAY_BUSY_ANIM = BaseClass::NEXT_TASK, TASK_ACTBUSY_PLAY_ENTRY, TASK_ACTBUSY_PLAY_EXIT, TASK_ACTBUSY_TELEPORT_TO_BUSY, TASK_ACTBUSY_WALK_PATH_TO_BUSY, TASK_ACTBUSY_GET_PATH_TO_ACTBUSY, TASK_ACTBUSY_VERIFY_EXIT, NEXT_TASK, // Conditions
COND_ACTBUSY_LOST_SEE_ENTITY = BaseClass::NEXT_CONDITION, COND_ACTBUSY_AWARE_OF_ENEMY_IN_SAFE_ZONE, COND_ACTBUSY_ENEMY_TOO_CLOSE, NEXT_CONDITION, }; virtual const char *GetName() { return "ActBusy"; }
void Enable( CAI_ActBusyGoal *pGoal, float flRange, bool bVisibleOnly ); void OnRestore(); void SetBusySearchRange( float flRange ); void Disable( void ); void ForceActBusy( CAI_ActBusyGoal *pGoal, CAI_Hint *pHintNode = NULL, float flMaxTime = NO_MAX_TIME, bool bVisibleOnly = false, bool bTeleportToBusy = false, bool bUseNearestBusy = false, CBaseEntity *pSeeEntity = NULL, Activity activity = ACT_INVALID ); void ForceActBusyLeave( bool bVisibleOnly = false ); void StopBusying( void ); bool IsStopBusying(); CAI_Hint *FindActBusyHintNode( void ); CAI_Hint *FindCombatActBusyHintNode( void ); CAI_Hint *FindCombatActBusyTeleportHintNode( void ); bool CanSelectSchedule( void ); bool IsCurScheduleOverridable( void ); bool ShouldIgnoreSound( CSound *pSound ); void OnFriendDamaged( CBaseCombatCharacter *pSquadmate, CBaseEntity *pAttacker ); int OnTakeDamage_Alive( const CTakeDamageInfo &info ); void GatherConditions( void ); void BuildScheduleTestBits( void ); void EndScheduleSelection( void ); Activity NPC_TranslateActivity( Activity nActivity ); void HandleAnimEvent( animevent_t *pEvent ); void CheckAndCleanupOnExit( void ); bool FValidateHintType( CAI_Hint *pHint ); bool ActBusyNodeStillActive( void ); bool IsMovingToBusy( void ) { return m_bMovingToBusy; } bool IsEnabled( void ) { return m_bEnabled; } float GetReasonableFacingDist( void ) { return 0; } // Actbusy ignores reasonable facing
bool IsInterruptable( void ); bool ShouldPlayerAvoid( void ); void SetUseRenderBounds( bool bUseBounds ) { m_bUseRenderBoundsForCollision = bUseBounds; } void ComputeAndSetRenderBounds(); bool CanFlinch( void ); bool CanRunAScriptedNPCInteraction( bool bForced ); void OnScheduleChange(); bool QueryHearSound( CSound *pSound ); void OnSeeEntity( CBaseEntity *pEntity ); bool NeedsToPlayExitAnim() { return m_bNeedsToPlayExitAnim; }
// Returns true if the current NPC is acting busy, or moving to an actbusy
bool IsActive( void ); // Returns true if the current NPC is actually acting busy (i.e. inside an act busy anim)
bool IsInsideActBusy( void ) { return m_bBusy; }
// Combat act busy stuff
bool IsCombatActBusy(); void CollectSafeZoneVolumes( CAI_ActBusyGoal *pActBusyGoal ); bool IsInSafeZone( CBaseEntity *pEntity ); int CountEnemiesInSafeZone();
private: virtual int SelectSchedule( void ); int SelectScheduleForLeaving( void ); int SelectScheduleWhileNotBusy( int iBase ); int SelectScheduleWhileBusy( void ); virtual void StartTask( const Task_t *pTask ); virtual void RunTask( const Task_t *pTask ); void NotifyBusyEnding( void ); bool HasAnimForActBusy( int iActBusy, busyanimparts_t AnimPart ); bool PlayAnimForActBusy( busyanimparts_t AnimPart ); void PlaySoundForActBusy( busyanimparts_t AnimPart );
private: bool m_bEnabled; bool m_bForceActBusy; Activity m_ForcedActivity; bool m_bTeleportToBusy; bool m_bUseNearestBusy; bool m_bLeaving; bool m_bVisibleOnly; bool m_bUseRenderBoundsForCollision; float m_flForcedMaxTime; bool m_bBusy; bool m_bMovingToBusy; bool m_bNeedsToPlayExitAnim; float m_flNextBusySearchTime; float m_flEndBusyAt; float m_flBusySearchRange; bool m_bInQueue; int m_iCurrentBusyAnim; CHandle<CAI_ActBusyGoal> m_hActBusyGoal; bool m_bNeedToSetBounds; EHANDLE m_hSeeEntity; float m_fTimeLastSawSeeEntity; bool m_bExitedBusyToDueLostSeeEntity; bool m_bExitedBusyToDueSeeEnemy;
int m_iNumConsecutivePathFailures; // Count how many times we failed to find a path to a node, so we can consider teleporting.
bool m_bAutoFireWeapon; float m_flDeferUntil; int m_iNumEnemiesInSafeZone;
CUtlVector<busysafezone_t>m_SafeZones;
DEFINE_CUSTOM_SCHEDULE_PROVIDER; };
//-----------------------------------------------------------------------------
// Purpose: A level tool to control the actbusy behavior.
//-----------------------------------------------------------------------------
class CAI_ActBusyGoal : public CAI_GoalEntity { DECLARE_CLASS( CAI_ActBusyGoal, CAI_GoalEntity ); public: CAI_ActBusyGoal() { // Support legacy maps, where this value used to be set from a constant (with a value of 1).
// Now designers can specify whatever they want in Hammer. Take care of old maps by setting
// this in the constructor. (sjb)
m_flSeeEntityTimeout = 1; }
virtual void NPCMovingToBusy( CAI_BaseNPC *pNPC ); virtual void NPCAbortedMoveTo( CAI_BaseNPC *pNPC ); virtual void NPCStartedBusy( CAI_BaseNPC *pNPC ); virtual void NPCStartedLeavingBusy( CAI_BaseNPC *pNPC ); virtual void NPCFinishedBusy( CAI_BaseNPC *pNPC ); virtual void NPCLeft( CAI_BaseNPC *pNPC ); virtual void NPCLostSeeEntity( CAI_BaseNPC *pNPC ); virtual void NPCSeeEnemy( CAI_BaseNPC *pNPC );
int GetType() { return m_iType; } bool IsCombatActBusyTeleportAllowed() { return m_bAllowCombatActBusyTeleport; }
protected: CAI_ActBusyBehavior *GetBusyBehaviorForNPC( const char *pszActorName, CBaseEntity *pActivator, CBaseEntity *pCaller, const char *sInputName ); CAI_ActBusyBehavior *GetBusyBehaviorForNPC( CBaseEntity *pEntity, const char *sInputName );
void EnableGoal( CAI_BaseNPC *pAI );
// Inputs
virtual void InputActivate( inputdata_t &inputdata ); virtual void InputDeactivate( inputdata_t &inputdata ); void InputSetBusySearchRange( inputdata_t &inputdata ); void InputForceNPCToActBusy( inputdata_t &inputdata ); void InputForceThisNPCToActBusy( inputdata_t &inputdata ); void InputForceThisNPCToLeave( inputdata_t &inputdata );
DECLARE_DATADESC();
protected: float m_flBusySearchRange; bool m_bVisibleOnly; int m_iType; bool m_bAllowCombatActBusyTeleport;
public: // Let the actbusy behavior query these so we don't have to duplicate the data.
string_t m_iszSeeEntityName; float m_flSeeEntityTimeout; string_t m_iszSafeZoneVolume; int m_iSightMethod;
protected: COutputEHANDLE m_OnNPCStartedBusy; COutputEHANDLE m_OnNPCFinishedBusy; COutputEHANDLE m_OnNPCLeft; COutputEHANDLE m_OnNPCLostSeeEntity; COutputEHANDLE m_OnNPCSeeEnemy; };
// Maximum number of nodes allowed in an actbusy queue
#define MAX_QUEUE_NODES 20
//-----------------------------------------------------------------------------
// Purpose: A level tool to control the actbusy behavior to create NPC queues
//-----------------------------------------------------------------------------
class CAI_ActBusyQueueGoal : public CAI_ActBusyGoal { DECLARE_CLASS( CAI_ActBusyQueueGoal, CAI_ActBusyGoal ); public: virtual void Spawn( void ); virtual void DrawDebugGeometryOverlays( void ); virtual void NPCMovingToBusy( CAI_BaseNPC *pNPC ); virtual void NPCStartedBusy( CAI_BaseNPC *pNPC ); virtual void NPCAbortedMoveTo( CAI_BaseNPC *pNPC ); virtual void NPCFinishedBusy( CAI_BaseNPC *pNPC ); virtual void NPCStartedLeavingBusy( CAI_BaseNPC *pNPC );
virtual void InputActivate( inputdata_t &inputdata ); void InputPlayerStartedBlocking( inputdata_t &inputdata ); void InputPlayerStoppedBlocking( inputdata_t &inputdata ); void InputMoveQueueUp( inputdata_t &inputdata );
void PushNPCBackInQueue( CAI_BaseNPC *pNPC, int iStartingNode ); void RemoveNPCFromQueue( CAI_BaseNPC *pNPC ); void RecalculateQueueCount( void ); void QueueThink( void ); void MoveQueueUp( void ); void MoveQueueUpThink( void ); bool NodeIsOccupied( int i ); CAI_BaseNPC *GetNPCOnNode( int iNode ); CAI_ActBusyBehavior *GetQueueBehaviorForNPC( CAI_BaseNPC *pNPC );
DECLARE_DATADESC();
private: int m_iCurrentQueueCount; CHandle<CAI_Hint> m_hNodes[ MAX_QUEUE_NODES ]; bool m_bPlayerBlockedNodes[ MAX_QUEUE_NODES ]; EHANDLE m_hExitNode; EHANDLE m_hExitingNPC; bool m_bForceReachFront;
// Read from mapdata
string_t m_iszNodes[ MAX_QUEUE_NODES ]; string_t m_iszExitNode;
// Outputs
COutputInt m_OnQueueMoved; COutputEHANDLE m_OnNPCLeftQueue; COutputEHANDLE m_OnNPCStartedLeavingQueue; };
#endif // AI_BEHAVIOR_ACTBUSY_H
|