//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Base NPC character with AI
//
//=============================================================================//
# ifndef AI_BASENPC_H
# define AI_BASENPC_H
# ifdef _WIN32
# pragma once
# endif
# include "simtimer.h"
# include "basecombatcharacter.h"
# include "ai_debug.h"
# include "ai_default.h"
# include "ai_schedule.h"
# include "ai_condition.h"
# include "ai_component.h"
# include "ai_task.h"
# include "ai_movetypes.h"
# include "ai_navtype.h"
# include "ai_namespaces.h"
# include "ai_npcstate.h"
# include "ai_hull.h"
# include "ai_utils.h"
# include "ai_moveshoot.h"
# include "entityoutput.h"
# include "utlvector.h"
# include "activitylist.h"
# include "bitstring.h"
# include "ai_basenpc.h"
# include "ai_navgoaltype.h" //GoalType_t enum
# include "eventlist.h"
# include "soundent.h"
# include "ai_navigator.h"
# include "tier1/functors.h"
# define PLAYER_SQUADNAME "player_squad"
class CAI_Schedule ;
class CAI_Network ;
class CAI_Route ;
class CAI_Hint ;
class CAI_Node ;
class CAI_Navigator ;
class CAI_Pathfinder ;
class CAI_Senses ;
class CAI_Enemies ;
class CAI_Squad ;
class CAI_Expresser ;
class CAI_BehaviorBase ;
class CAI_GoalEntity ;
class CAI_Motor ;
class CAI_MoveProbe ;
class CAI_LocalNavigator ;
class CAI_TacticalServices ;
class CVarBitVec ;
class CAI_ScriptedSequence ;
class CSceneEntity ;
class CBaseGrenade ;
class CBaseDoor ;
class CBasePropDoor ;
struct AI_Waypoint_t ;
class AI_Response ;
class CBaseFilter ;
typedef CBitVec < MAX_CONDITIONS > CAI_ScheduleBits ;
// Used to control optimizations mostly dealing with pathfinding for NPCs
extern ConVar ai_strong_optimizations ;
extern bool AIStrongOpt ( void ) ;
// AI_MONITOR_FOR_OSCILLATION defaults to OFF. If you build with this ON, you can flag
// NPC's and monitor them to detect oscillations in their schedule (circular logic and conditions bugs)
// DO NOT SHIP WITH THIS ON!
# undef AI_MONITOR_FOR_OSCILLATION
//=============================================================================
//
// Constants & enumerations
//
//=============================================================================
# define TURRET_CLOSE_RANGE 200
# define TURRET_MEDIUM_RANGE 500
# define COMMAND_GOAL_TOLERANCE 48 // 48 inches.
# define TIME_CARE_ABOUT_DAMAGE 3.0
# define ITEM_PICKUP_TOLERANCE 48.0f
// Max's of the box used to search for a weapon to pick up. 45x45x~8 ft.
# define WEAPON_SEARCH_DELTA Vector( 540, 540, 100 )
enum Interruptability_t
{
GENERAL_INTERRUPTABILITY ,
DAMAGEORDEATH_INTERRUPTABILITY ,
DEATH_INTERRUPTABILITY
} ;
//-------------------------------------
// Memory
//-------------------------------------
# define MEMORY_CLEAR 0
# define bits_MEMORY_PROVOKED ( 1 << 0 ) // right now only used for houndeyes.
# define bits_MEMORY_INCOVER ( 1 << 1 ) // npc knows it is in a covered position.
# define bits_MEMORY_SUSPICIOUS ( 1 << 2 ) // Ally is suspicious of the player, and will move to provoked more easily
# define bits_MEMORY_TASK_EXPENSIVE ( 1 << 3 ) // NPC has completed a task which is considered costly, so don't do another task this frame
//#define bits_MEMORY_ ( 1 << 4 )
# define bits_MEMORY_PATH_FAILED ( 1 << 5 ) // Failed to find a path
# define bits_MEMORY_FLINCHED ( 1 << 6 ) // Has already flinched
//#define bits_MEMORY_ ( 1 << 7 )
# define bits_MEMORY_TOURGUIDE ( 1 << 8 ) // I have been acting as a tourguide.
//#define bits_MEMORY_ ( 1 << 9 )//
# define bits_MEMORY_LOCKED_HINT ( 1 << 10 ) //
//#define bits_MEMORY_ ( 1 << 12 )
# define bits_MEMORY_TURNING ( 1 << 13 ) // Turning, don't interrupt me.
# define bits_MEMORY_TURNHACK ( 1 << 14 )
# define bits_MEMORY_HAD_ENEMY ( 1 << 15 ) // Had an enemy
# define bits_MEMORY_HAD_PLAYER ( 1 << 16 ) // Had player
# define bits_MEMORY_HAD_LOS ( 1 << 17 ) // Had LOS to enemy
# define bits_MEMORY_MOVED_FROM_SPAWN ( 1 << 18 ) // Has moved since spawning.
# define bits_MEMORY_CUSTOM4 ( 1 << 28 ) // NPC-specific memory
# define bits_MEMORY_CUSTOM3 ( 1 << 29 ) // NPC-specific memory
# define bits_MEMORY_CUSTOM2 ( 1 << 30 ) // NPC-specific memory
# define bits_MEMORY_CUSTOM1 ( 1 << 31 ) // NPC-specific memory
//-------------------------------------
// Spawn flags
//-------------------------------------
# define SF_NPC_WAIT_TILL_SEEN ( 1 << 0 ) // spawnflag that makes npcs wait until player can see them before attacking.
# define SF_NPC_GAG ( 1 << 1 ) // no idle noises from this npc
# define SF_NPC_FALL_TO_GROUND ( 1 << 2 ) // used my NPC_Maker
# define SF_NPC_DROP_HEALTHKIT ( 1 << 3 ) // Drop a healthkit upon death
# define SF_NPC_START_EFFICIENT ( 1 << 4 ) // Set into efficiency mode from spawn
// ( 1 << 5 )
// ( 1 << 6 )
# define SF_NPC_WAIT_FOR_SCRIPT ( 1 << 7 ) // spawnflag that makes npcs wait to check for attacking until the script is done or they've been attacked
# define SF_NPC_LONG_RANGE ( 1 << 8 ) // makes npcs look far and relaxes weapon range limit
# define SF_NPC_FADE_CORPSE ( 1 << 9 ) // Fade out corpse after death
# define SF_NPC_ALWAYSTHINK ( 1 << 10 ) // Simulate even when player isn't in PVS.
# define SF_NPC_TEMPLATE ( 1 << 11 ) // This NPC will be used as a template by an npc_maker -- do not spawn.
# define SF_NPC_ALTCOLLISION ( 1 << 12 )
# define SF_NPC_NO_WEAPON_DROP ( 1 << 13 ) // This NPC will not actually drop a weapon that can be picked up
# define SF_NPC_NO_PLAYER_PUSHAWAY ( 1 << 14 )
// ( 1 << 15 )
// !! Flags above ( 1 << 15 ) are reserved for NPC sub-classes
//-------------------------------------
//
// Return codes from CanPlaySequence.
//
//-------------------------------------
enum CanPlaySequence_t
{
CANNOT_PLAY = 0 , // Can't play for any number of reasons.
CAN_PLAY_NOW , // Can play the script immediately.
CAN_PLAY_ENQUEUED , // Can play the script after I finish playing my current script.
} ;
//-------------------------------------
// Weapon holstering
//-------------------------------------
enum DesiredWeaponState_t
{
DESIREDWEAPONSTATE_IGNORE = 0 ,
DESIREDWEAPONSTATE_HOLSTERED ,
DESIREDWEAPONSTATE_HOLSTERED_DESTROYED , // Put the weapon away, then destroy it.
DESIREDWEAPONSTATE_UNHOLSTERED ,
DESIREDWEAPONSTATE_CHANGING ,
DESIREDWEAPONSTATE_CHANGING_DESTROY , // Destroy the weapon when this change is complete.
} ;
//-------------------------------------
//
// Efficiency modes
//
//-------------------------------------
enum AI_Efficiency_t
{
// Run at full tilt
AIE_NORMAL ,
// Run decision process less often
AIE_EFFICIENT ,
// Run decision process even less often, ignore other NPCs
AIE_VERY_EFFICIENT ,
// Run decision process even less often, ignore other NPCs
AIE_SUPER_EFFICIENT ,
// Don't run at all
AIE_DORMANT ,
} ;
enum AI_MoveEfficiency_t
{
AIME_NORMAL ,
AIME_EFFICIENT ,
} ;
//-------------------------------------
//
// Sleep state
//
//-------------------------------------
enum AI_SleepState_t
{
AISS_AWAKE ,
AISS_WAITING_FOR_THREAT ,
AISS_WAITING_FOR_PVS ,
AISS_WAITING_FOR_INPUT ,
AISS_AUTO_PVS ,
AISS_AUTO_PVS_AFTER_PVS , // Same as AUTO_PVS, except doesn't activate until/unless the NPC is IN the player's PVS.
} ;
# define AI_SLEEP_FLAGS_NONE 0x00000000
# define AI_SLEEP_FLAG_AUTO_PVS 0x00000001
# define AI_SLEEP_FLAG_AUTO_PVS_AFTER_PVS 0x00000002
//-------------------------------------
//
// Debug bits
//
//-------------------------------------
enum DebugBaseNPCBits_e
{
bits_debugDisableAI = 0x00000001 , // disable AI
bits_debugStepAI = 0x00000002 , // step AI
} ;
//-------------------------------------
//
// Base Sentence index for behaviors
//
//-------------------------------------
enum SentenceIndex_t
{
SENTENCE_BASE_BEHAVIOR_INDEX = 1000 ,
} ;
# ifdef AI_MONITOR_FOR_OSCILLATION
struct AIScheduleChoice_t
{
float m_flTimeSelected ;
CAI_Schedule * m_pScheduleSelected ;
} ;
# endif //AI_MONITOR_FOR_OSCILLATION
# define MARK_TASK_EXPENSIVE() \
if ( GetOuter ( ) ) \
{ \
GetOuter ( ) - > Remember ( bits_MEMORY_TASK_EXPENSIVE ) ; \
}
//=============================================================================
//
// Types used by CAI_BaseNPC
//
//=============================================================================
struct AIScheduleState_t
{
int iCurTask ;
TaskStatus_e fTaskStatus ;
float timeStarted ;
float timeCurTaskStarted ;
AI_TaskFailureCode_t taskFailureCode ;
int iTaskInterrupt ;
bool bTaskRanAutomovement ;
bool bTaskUpdatedYaw ;
bool bScheduleWasInterrupted ;
DECLARE_SIMPLE_DATADESC ( ) ;
} ;
// -----------------------------------------
// An entity that this NPC can't reach
// -----------------------------------------
struct UnreachableEnt_t
{
EHANDLE hUnreachableEnt ; // Entity that's unreachable
float fExpireTime ; // Time to forget this information
Vector vLocationWhenUnreachable ;
DECLARE_SIMPLE_DATADESC ( ) ;
} ;
//=============================================================================
// SCRIPTED NPC INTERACTIONS
//=============================================================================
// -----------------------------------------
// Scripted NPC interaction flags
// -----------------------------------------
# define SCNPC_FLAG_TEST_OTHER_ANGLES ( 1 << 1 )
# define SCNPC_FLAG_TEST_OTHER_VELOCITY ( 1 << 2 )
# define SCNPC_FLAG_LOOP_IN_ACTION ( 1 << 3 )
# define SCNPC_FLAG_NEEDS_WEAPON_ME ( 1 << 4 )
# define SCNPC_FLAG_NEEDS_WEAPON_THEM ( 1 << 5 )
# define SCNPC_FLAG_DONT_TELEPORT_AT_END_ME ( 1 << 6 )
# define SCNPC_FLAG_DONT_TELEPORT_AT_END_THEM ( 1 << 7 )
// -----------------------------------------
// Scripted NPC interaction trigger methods
// -----------------------------------------
enum
{
SNPCINT_CODE = 0 ,
SNPCINT_AUTOMATIC_IN_COMBAT = 1 ,
} ;
// -----------------------------------------
// Scripted NPC interaction loop breaking trigger methods
// -----------------------------------------
# define SNPCINT_LOOPBREAK_ON_DAMAGE ( 1 << 1 )
# define SNPCINT_LOOPBREAK_ON_FLASHLIGHT_ILLUM ( 1 << 2 )
// -----------------------------------------
// Scripted NPC interaction anim phases
// -----------------------------------------
enum
{
SNPCINT_ENTRY = 0 ,
SNPCINT_SEQUENCE ,
SNPCINT_EXIT ,
SNPCINT_NUM_PHASES
} ;
struct ScriptedNPCInteraction_Phases_t
{
string_t iszSequence ;
int iActivity ;
DECLARE_SIMPLE_DATADESC ( ) ;
} ;
// Allowable delta from the desired dynamic scripted sequence point
# define DSS_MAX_DIST 6
# define DSS_MAX_ANGLE_DIFF 4
// Interaction Logic States
enum
{
NPCINT_NOT_RUNNING = 0 ,
NPCINT_RUNNING_ACTIVE , // I'm in an interaction that I initiated
NPCINT_RUNNING_PARTNER , // I'm in an interaction that was initiated by the other NPC
NPCINT_MOVING_TO_MARK , // I'm moving to a position to do an interaction
} ;
# define NPCINT_NONE -1
# define MAXTACLAT_IGNORE -1
// -----------------------------------------
// A scripted interaction between NPCs
// -----------------------------------------
struct ScriptedNPCInteraction_t
{
ScriptedNPCInteraction_t ( )
{
iszInteractionName = NULL_STRING ;
iFlags = 0 ;
iTriggerMethod = SNPCINT_CODE ;
iLoopBreakTriggerMethod = 0 ;
vecRelativeOrigin = vec3_origin ;
bValidOnCurrentEnemy = false ;
flDelay = 5.0 ;
flDistSqr = ( DSS_MAX_DIST * DSS_MAX_DIST ) ;
flNextAttemptTime = 0 ;
iszMyWeapon = NULL_STRING ;
iszTheirWeapon = NULL_STRING ;
for ( int i = 0 ; i < SNPCINT_NUM_PHASES ; i + + )
{
sPhases [ i ] . iszSequence = NULL_STRING ;
sPhases [ i ] . iActivity = ACT_INVALID ;
}
}
// Fill out these when passing to AddScriptedNPCInteraction
string_t iszInteractionName ;
int iFlags ;
int iTriggerMethod ;
int iLoopBreakTriggerMethod ;
Vector vecRelativeOrigin ; // (forward, right, up)
QAngle angRelativeAngles ;
Vector vecRelativeVelocity ; // Desired relative velocity of the other NPC
float flDelay ; // Delay before interaction can be used again
float flDistSqr ; // Max distance sqr from the relative origin the NPC is allowed to be to trigger
string_t iszMyWeapon ; // Classname of the weapon I'm holding, if any
string_t iszTheirWeapon ; // Classname of the weapon my interaction partner is holding, if any
ScriptedNPCInteraction_Phases_t sPhases [ SNPCINT_NUM_PHASES ] ;
// These will be filled out for you in AddScriptedNPCInteraction
VMatrix matDesiredLocalToWorld ; // Desired relative position / angles of the other NPC
bool bValidOnCurrentEnemy ;
float flNextAttemptTime ;
DECLARE_SIMPLE_DATADESC ( ) ;
} ;
//=============================================================================
//
// Utility functions
//
//=============================================================================
Vector VecCheckToss ( CBaseEntity * pEdict , Vector vecSpot1 , Vector vecSpot2 , float flHeightMaxRatio , float flGravityAdj , bool bRandomize , Vector * vecMins = NULL , Vector * vecMaxs = NULL ) ;
Vector VecCheckToss ( CBaseEntity * pEntity , ITraceFilter * pFilter , Vector vecSpot1 , Vector vecSpot2 , float flHeightMaxRatio , float flGravityAdj , bool bRandomize , Vector * vecMins = NULL , Vector * vecMaxs = NULL ) ;
Vector VecCheckThrow ( CBaseEntity * pEdict , const Vector & vecSpot1 , Vector vecSpot2 , float flSpeed , float flGravityAdj = 1.0f , Vector * vecMins = NULL , Vector * vecMaxs = NULL ) ;
extern Vector g_vecAttackDir ;
bool FBoxVisible ( CBaseEntity * pLooker , CBaseEntity * pTarget ) ;
bool FBoxVisible ( CBaseEntity * pLooker , CBaseEntity * pTarget , Vector & vecTargetOrigin , float flSize = 0.0 ) ;
// FIXME: move to utils?
float DeltaV ( float v0 , float v1 , float d ) ;
float ChangeDistance ( float flInterval , float flGoalDistance , float flGoalVelocity , float flCurVelocity , float flIdealVelocity , float flAccelRate , float & flNewDistance , float & flNewVelocity ) ;
//=============================================================================
//
// class CAI_Manager
//
// Central location for components of the AI to operate across all AIs without
// iterating over the global list of entities.
//
//=============================================================================
class CAI_Manager
{
public :
CAI_Manager ( ) ;
CAI_BaseNPC * * AccessAIs ( ) ;
int NumAIs ( ) ;
void AddAI ( CAI_BaseNPC * pAI ) ;
void RemoveAI ( CAI_BaseNPC * pAI ) ;
bool FindAI ( CAI_BaseNPC * pAI ) { return ( m_AIs . Find ( pAI ) ! = m_AIs . InvalidIndex ( ) ) ; }
private :
enum
{
MAX_AIS = 256
} ;
typedef CUtlVector < CAI_BaseNPC * > CAIArray ;
CAIArray m_AIs ;
} ;
//-------------------------------------
extern CAI_Manager g_AI_Manager ;
//=============================================================================
//
// class CAI_BaseNPC
//
//=============================================================================
class CAI_BaseNPC : public CBaseCombatCharacter ,
public CAI_DefMovementSink
{
DECLARE_CLASS ( CAI_BaseNPC , CBaseCombatCharacter ) ;
public :
//-----------------------------------------------------
//
// Initialization, cleanup, serialization, identity
//
CAI_BaseNPC ( ) ;
~ CAI_BaseNPC ( ) ;
//---------------------------------
DECLARE_DATADESC ( ) ;
DECLARE_SERVERCLASS ( ) ;
virtual int Save ( ISave & save ) ;
virtual int Restore ( IRestore & restore ) ;
virtual void OnRestore ( ) ;
void SaveConditions ( ISave & save , const CAI_ScheduleBits & conditions ) ;
void RestoreConditions ( IRestore & restore , CAI_ScheduleBits * pConditions ) ;
bool ShouldSavePhysics ( ) { return false ; }
virtual unsigned int PhysicsSolidMaskForEntity ( void ) const ;
virtual bool KeyValue ( const char * szKeyName , const char * szValue ) ;
//---------------------------------
virtual void PostConstructor ( const char * szClassname ) ;
virtual void Activate ( void ) ;
virtual void Precache ( void ) ; // derived calls at start of Spawn()
virtual bool CreateVPhysics ( ) ;
virtual void NPCInit ( void ) ; // derived calls after Spawn()
void NPCInitThink ( void ) ;
virtual void PostNPCInit ( ) { } ; // called after NPC_InitThink
virtual void StartNPC ( void ) ;
virtual bool IsTemplate ( void ) ;
virtual void CleanupOnDeath ( CBaseEntity * pCulprit = NULL , bool bFireDeathOutput = true ) ;
virtual void UpdateOnRemove ( void ) ;
virtual int UpdateTransmitState ( ) ;
//---------------------------------
// Component creation factories
//
// The master call, override if you introduce new component types. Call base first
virtual bool CreateComponents ( ) ;
// Components defined by the base AI class
virtual CAI_Senses * CreateSenses ( ) ;
virtual CAI_MoveProbe * CreateMoveProbe ( ) ;
virtual CAI_Motor * CreateMotor ( ) ;
virtual CAI_LocalNavigator * CreateLocalNavigator ( ) ;
virtual CAI_Navigator * CreateNavigator ( ) ;
virtual CAI_Pathfinder * CreatePathfinder ( ) ;
virtual CAI_TacticalServices * CreateTacticalServices ( ) ;
//---------------------------------
virtual bool IsNPC ( void ) const { return true ; }
//---------------------------------
void TestPlayerPushing ( CBaseEntity * pPlayer ) ;
void CascadePlayerPush ( const Vector & push , const Vector & pushOrigin ) ;
void NotifyPushMove ( ) ;
public :
//-----------------------------------------------------
//
// AI processing - thinking, schedule selection and task running
//
//-----------------------------------------------------
void CallNPCThink ( void ) ;
// Thinking, including core thinking, movement, animation
virtual void NPCThink ( void ) ;
// Core thinking (schedules & tasks)
virtual void RunAI ( void ) ; // core ai function!
// Called to gather up all relevant conditons
virtual void GatherConditions ( void ) ;
// Called immediately prior to schedule processing
virtual void PrescheduleThink ( void ) ;
// Called immediately after schedule processing
virtual void PostscheduleThink ( void ) { return ; } ;
// Notification that the current schedule, if any, is ending and a new one is being selected
virtual void OnScheduleChange ( void ) ;
// Notification that a new schedule is about to run its first task
virtual void OnStartSchedule ( int scheduleType ) { } ;
// This function implements a decision tree for the NPC. It is responsible for choosing the next behavior (schedule)
// based on the current conditions and state.
virtual int SelectSchedule ( void ) ;
virtual int SelectFailSchedule ( int failedSchedule , int failedTask , AI_TaskFailureCode_t taskFailCode ) ;
// After the schedule has been selected, it will be processed by this function so child NPC classes can
// remap base schedules into child-specific behaviors
virtual int TranslateSchedule ( int scheduleType ) ;
virtual void StartTask ( const Task_t * pTask ) ;
virtual void RunTask ( const Task_t * pTask ) ;
void ClearTransientConditions ( ) ;
virtual void HandleAnimEvent ( animevent_t * pEvent ) ;
virtual bool IsInterruptable ( ) ;
virtual void OnStartScene ( void ) { } // Called when an NPC begins a cine scene (useful for clean-up)
virtual bool ShouldPlayerAvoid ( void ) ;
virtual void SetPlayerAvoidState ( void ) ;
virtual void PlayerPenetratingVPhysics ( void ) ;
virtual bool ShouldAlwaysThink ( ) ;
void ForceGatherConditions ( ) { m_bForceConditionsGather = true ; SetEfficiency ( AIE_NORMAL ) ; } // Force an NPC out of PVS to call GatherConditions on next think
virtual float LineOfSightDist ( const Vector & vecDir = vec3_invalid , float zEye = FLT_MAX ) ;
virtual void MakeTracer ( const Vector & vecTracerSrc , const trace_t & tr , int iTracerType ) ;
virtual const char * GetTracerType ( void ) ;
virtual void DoImpactEffect ( trace_t & tr , int nDamageType ) ;
enum
{
NEXT_SCHEDULE = LAST_SHARED_SCHEDULE ,
NEXT_TASK = LAST_SHARED_TASK ,
NEXT_CONDITION = LAST_SHARED_CONDITION ,
} ;
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 ) { Task_t tempTask = { task , taskData } ; StartTask ( ( const Task_t * ) & tempTask ) ; }
void ChainRunTask ( int task , float taskData = 0 ) { Task_t tempTask = { task , taskData } ; RunTask ( ( const Task_t * ) & tempTask ) ; }
void StartTaskOverlay ( ) ;
void RunTaskOverlay ( ) ;
void EndTaskOverlay ( ) ;
virtual void PostRunStopMoving ( ) ;
bool CheckPVSCondition ( ) ;
private :
bool CanThinkRebalance ( ) ;
void RebalanceThinks ( ) ;
bool PreNPCThink ( ) ;
void PostNPCThink ( ) ;
bool PreThink ( void ) ;
void PerformSensing ( ) ;
void CheckOnGround ( void ) ;
void MaintainSchedule ( void ) ;
void RunAnimation ( void ) ;
void PostRun ( void ) ;
void PerformMovement ( ) ;
void PostMovement ( ) ;
virtual int StartTask ( Task_t * pTask ) { DevMsg ( " Called wrong StartTask() \n " ) ; StartTask ( ( const Task_t * ) pTask ) ; return 0 ; } // to ensure correct signature in derived classes
virtual int RunTask ( Task_t * pTask ) { DevMsg ( " Called wrong RunTask() \n " ) ; RunTask ( ( const Task_t * ) pTask ) ; return 0 ; } // to ensure correct signature in derived classes
public :
//-----------------------------------------------------
//
// Schedules & tasks
//
//-----------------------------------------------------
void SetSchedule ( CAI_Schedule * pNewSchedule ) ;
bool SetSchedule ( int localScheduleID ) ;
void SetDefaultFailSchedule ( int failSchedule ) { m_failSchedule = failSchedule ; }
void ClearSchedule ( const char * szReason ) ;
CAI_Schedule * GetCurSchedule ( ) { return m_pSchedule ; }
bool IsCurSchedule ( int schedId , bool fIdeal = true ) ;
virtual CAI_Schedule * GetSchedule ( int localScheduleID ) ;
virtual int GetLocalScheduleId ( int globalScheduleID ) { return AI_IdIsLocal ( globalScheduleID ) ? globalScheduleID : GetClassScheduleIdSpace ( ) - > ScheduleGlobalToLocal ( globalScheduleID ) ; }
virtual int GetGlobalScheduleId ( int localScheduleID ) { return AI_IdIsGlobal ( localScheduleID ) ? localScheduleID : GetClassScheduleIdSpace ( ) - > ScheduleLocalToGlobal ( localScheduleID ) ; }
float GetTimeScheduleStarted ( ) const { return m_ScheduleState . timeStarted ; }
//---------------------------------
const Task_t * GetTask ( void ) ;
int TaskIsRunning ( void ) ;
virtual void TaskFail ( AI_TaskFailureCode_t ) ;
void TaskFail ( const char * pszGeneralFailText ) { TaskFail ( MakeFailCode ( pszGeneralFailText ) ) ; }
void TaskComplete ( bool fIgnoreSetFailedCondition = false ) ;
void TaskInterrupt ( ) { m_ScheduleState . iTaskInterrupt + + ; }
void ClearTaskInterrupt ( ) { m_ScheduleState . iTaskInterrupt = 0 ; }
int GetTaskInterrupt ( ) const { return m_ScheduleState . iTaskInterrupt ; }
void TaskMovementComplete ( void ) ;
inline int TaskIsComplete ( void ) { return ( GetTaskStatus ( ) = = TASKSTATUS_COMPLETE ) ; }
virtual const char * TaskName ( int taskID ) ;
float GetTimeTaskStarted ( ) const { return m_ScheduleState . timeCurTaskStarted ; }
virtual int GetLocalTaskId ( int globalTaskId ) { return GetClassScheduleIdSpace ( ) - > TaskGlobalToLocal ( globalTaskId ) ; }
virtual const char * GetSchedulingErrorName ( ) { return " CAI_BaseNPC " ; }
protected :
static bool LoadSchedules ( void ) ;
virtual bool LoadedSchedules ( void ) ;
virtual void BuildScheduleTestBits ( void ) ;
//---------------------------------
// This is the main call to select/translate a schedule
virtual CAI_Schedule * GetNewSchedule ( void ) ;
virtual CAI_Schedule * GetFailSchedule ( void ) ;
//---------------------------------
virtual bool CanFlinch ( void ) ;
virtual void CheckFlinches ( void ) ;
virtual void PlayFlinchGesture ( void ) ;
int SelectFlinchSchedule ( void ) ;
virtual bool IsAllowedToDodge ( void ) ;
bool IsInChoreo ( ) const ;
private :
// This function maps the type through TranslateSchedule() and then retrieves the pointer
// to the actual CAI_Schedule from the database of schedules available to this class.
CAI_Schedule * GetScheduleOfType ( int scheduleType ) ;
bool FHaveSchedule ( void ) ;
bool FScheduleDone ( void ) ;
CAI_Schedule * ScheduleInList ( const char * pName , CAI_Schedule * * pList , int listCount ) ;
int GetScheduleCurTaskIndex ( ) const { return m_ScheduleState . iCurTask ; }
inline int IncScheduleCurTaskIndex ( ) ;
inline void ResetScheduleCurTaskIndex ( ) ;
void NextScheduledTask ( void ) ;
bool IsScheduleValid ( void ) ;
bool ShouldSelectIdealState ( void ) ;
// Selecting the ideal state
NPC_STATE SelectIdleIdealState ( ) ;
NPC_STATE SelectAlertIdealState ( ) ;
NPC_STATE SelectScriptIdealState ( ) ;
// Various schedule selections based on NPC_STATE
int SelectIdleSchedule ( ) ;
int SelectAlertSchedule ( ) ;
int SelectCombatSchedule ( ) ;
virtual int SelectDeadSchedule ( ) ;
int SelectScriptSchedule ( ) ;
int SelectInteractionSchedule ( ) ;
void OnStartTask ( void ) { SetTaskStatus ( TASKSTATUS_RUN_MOVE_AND_TASK ) ; }
void SetTaskStatus ( TaskStatus_e status ) { m_ScheduleState . fTaskStatus = status ; }
TaskStatus_e GetTaskStatus ( ) const { return m_ScheduleState . fTaskStatus ; }
void DiscardScheduleState ( ) ;
//---------------------------------
CAI_Schedule * m_pSchedule ;
int m_IdealSchedule ;
AIScheduleState_t m_ScheduleState ;
int m_failSchedule ; // Schedule type to choose if current schedule fails
bool m_bDoPostRestoreRefindPath ;
bool m_bUsingStandardThinkTime ;
float m_flLastRealThinkTime ;
int m_iFrameBlocked ;
bool m_bInChoreo ;
static int gm_iNextThinkRebalanceTick ;
static float gm_flTimeLastSpawn ;
static int gm_nSpawnedThisFrame ;
protected : // pose parameters
int m_poseAim_Pitch ;
int m_poseAim_Yaw ;
int m_poseMove_Yaw ;
virtual void PopulatePoseParameters ( void ) ;
public :
inline bool HasPoseMoveYaw ( ) { return ( m_poseMove_Yaw > = 0 ) ; }
// Return the stored pose parameter for "move_yaw"
inline int LookupPoseMoveYaw ( ) { return m_poseMove_Yaw ; }
//-----------------------------------------------------
//
// Hooks for CAI_Behaviors, *if* derived class supports them
//
//-----------------------------------------------------
template < class BEHAVIOR_TYPE >
bool GetBehavior ( BEHAVIOR_TYPE * * ppBehavior )
{
CAI_BehaviorBase * * ppBehaviors = AccessBehaviors ( ) ;
* ppBehavior = NULL ;
for ( int i = 0 ; i < NumBehaviors ( ) ; i + + )
{
* ppBehavior = dynamic_cast < BEHAVIOR_TYPE * > ( ppBehaviors [ i ] ) ;
if ( * ppBehavior )
return true ;
}
return false ;
}
virtual CAI_BehaviorBase * GetRunningBehavior ( ) { return NULL ; }
virtual bool ShouldAcceptGoal ( CAI_BehaviorBase * pBehavior , CAI_GoalEntity * pGoal ) { return true ; }
virtual void OnClearGoal ( CAI_BehaviorBase * pBehavior , CAI_GoalEntity * pGoal ) { }
// Notification that the status behavior ability to select schedules has changed.
// Return "true" to signal a schedule interrupt is desired
virtual bool OnBehaviorChangeStatus ( CAI_BehaviorBase * pBehavior , bool fCanFinishSchedule ) { return false ; }
private :
virtual CAI_BehaviorBase * * AccessBehaviors ( ) { return NULL ; }
virtual int NumBehaviors ( ) { return 0 ; }
public :
//-----------------------------------------------------
//
// Conditions
//
//-----------------------------------------------------
virtual const char * ConditionName ( int conditionID ) ;
virtual void RemoveIgnoredConditions ( void ) ;
void SetCondition ( int iCondition /*, bool state = true*/ ) ;
bool HasCondition ( int iCondition ) ;
bool HasCondition ( int iCondition , bool bUseIgnoreConditions ) ;
bool HasInterruptCondition ( int iCondition ) ;
bool HasConditionsToInterruptSchedule ( int nLocalScheduleID ) ;
void ClearCondition ( int iCondition ) ;
void ClearConditions ( int * pConditions , int nConditions ) ;
void SetIgnoreConditions ( int * pConditions , int nConditions ) ;
void ClearIgnoreConditions ( int * pConditions , int nConditions ) ;
bool ConditionInterruptsCurSchedule ( int iCondition ) ;
bool ConditionInterruptsSchedule ( int schedule , int iCondition ) ;
void SetCustomInterruptCondition ( int nCondition ) ;
bool IsCustomInterruptConditionSet ( int nCondition ) ;
void ClearCustomInterruptCondition ( int nCondition ) ;
void ClearCustomInterruptConditions ( void ) ;
bool ConditionsGathered ( ) const { return m_bConditionsGathered ; }
const CAI_ScheduleBits & AccessConditionBits ( ) const { return m_Conditions ; }
CAI_ScheduleBits & AccessConditionBits ( ) { return m_Conditions ; }
bool DidChooseEnemy ( ) const { return ! m_bSkippedChooseEnemy ; }
private :
CAI_ScheduleBits m_Conditions ;
CAI_ScheduleBits m_CustomInterruptConditions ; //Bit string assembled by the schedule running, then
//modified by leaf classes to suit their needs
CAI_ScheduleBits m_ConditionsPreIgnore ;
CAI_ScheduleBits m_InverseIgnoreConditions ;
bool m_bForceConditionsGather ;
bool m_bConditionsGathered ;
bool m_bSkippedChooseEnemy ;
public :
//-----------------------------------------------------
//
// NPC State
//
//-----------------------------------------------------
inline void SetIdealState ( NPC_STATE eIdealState ) ;
inline NPC_STATE GetIdealState ( ) ;
virtual NPC_STATE SelectIdealState ( void ) ;
void SetState ( NPC_STATE State ) ;
virtual bool ShouldGoToIdleState ( void ) { return ( false ) ; }
virtual void OnStateChange ( NPC_STATE OldState , NPC_STATE NewState ) { /*Base class doesn't care*/ } ;
NPC_STATE GetState ( void ) { return m_NPCState ; }
AI_Efficiency_t GetEfficiency ( ) const { return m_Efficiency ; }
void SetEfficiency ( AI_Efficiency_t efficiency ) { m_Efficiency = efficiency ; }
AI_MoveEfficiency_t GetMoveEfficiency ( ) const { return m_MoveEfficiency ; }
void SetMoveEfficiency ( AI_MoveEfficiency_t efficiency ) { m_MoveEfficiency = efficiency ; }
virtual void UpdateEfficiency ( bool bInPVS ) ;
void ForceDecisionThink ( ) { m_flNextDecisionTime = 0 ; SetEfficiency ( AIE_NORMAL ) ; }
bool IsFlaggedEfficient ( ) const { return HasSpawnFlags ( SF_NPC_START_EFFICIENT ) ; }
AI_SleepState_t GetSleepState ( ) const { return m_SleepState ; }
void SetSleepState ( AI_SleepState_t sleepState ) { m_SleepState = sleepState ; }
void AddSleepFlags ( int flags ) { m_SleepFlags | = flags ; }
void RemoveSleepFlags ( int flags ) { m_SleepFlags & = ~ flags ; }
bool HasSleepFlags ( int flags ) { return ( m_SleepFlags & flags ) = = flags ; }
void UpdateSleepState ( bool bInPVS ) ;
virtual void Wake ( bool bFireOutput = true ) ;
void Sleep ( ) ;
bool WokeThisTick ( ) const ;
//---------------------------------
NPC_STATE m_NPCState ; // npc's current state
float m_flLastStateChangeTime ;
private :
NPC_STATE m_IdealNPCState ; // npc should change to this state
AI_Efficiency_t m_Efficiency ;
AI_MoveEfficiency_t m_MoveEfficiency ;
float m_flNextDecisionTime ;
AI_SleepState_t m_SleepState ;
int m_SleepFlags ;
float m_flWakeRadius ;
bool m_bWakeSquad ;
int m_nWakeTick ;
public :
//-----------------------------------------------------
//
// Activities
//
//-----------------------------------------------------
Activity TranslateActivity ( Activity idealActivity , Activity * pIdealWeaponActivity = NULL ) ;
Activity NPC_TranslateActivity ( Activity eNewActivity ) ;
Activity GetActivity ( void ) { return m_Activity ; }
virtual void SetActivity ( Activity NewActivity ) ;
Activity GetIdealActivity ( void ) { return m_IdealActivity ; }
void SetIdealActivity ( Activity NewActivity ) ;
void ResetIdealActivity ( Activity newIdealActivity ) ;
void SetSequenceByName ( const char * szSequence ) ;
void SetSequenceById ( int iSequence ) ;
Activity GetScriptCustomMoveActivity ( void ) ;
int GetScriptCustomMoveSequence ( void ) ;
Activity GetStoppedActivity ( void ) ;
inline bool HaveSequenceForActivity ( Activity activity ) ;
inline bool IsActivityStarted ( void ) ;
virtual bool IsActivityFinished ( void ) ;
virtual bool IsActivityMovementPhased ( Activity activity ) ;
virtual void OnChangeActivity ( Activity eNewActivity ) ;
void MaintainActivity ( void ) ;
void ResetActivity ( void ) { m_Activity = ACT_RESET ; }
void SetActivityAndSequence ( Activity NewActivity , int iSequence , Activity translatedActivity , Activity weaponActivity ) ;
private :
void AdvanceToIdealActivity ( void ) ;
void ResolveActivityToSequence ( Activity NewActivity , int & iSequence , Activity & translatedActivity , Activity & weaponActivity ) ;
Activity m_Activity ; // Current animation state
Activity m_translatedActivity ; // Current actual translated animation
Activity m_IdealActivity ; // Desired animation state
int m_nIdealSequence ; // Desired animation sequence
Activity m_IdealTranslatedActivity ; // Desired actual translated animation state
Activity m_IdealWeaponActivity ; // Desired weapon animation state
CNetworkVar ( int , m_iDeathPose ) ;
CNetworkVar ( int , m_iDeathFrame ) ;
public :
//-----------------------------------------------------
//
// Senses
//
//-----------------------------------------------------
CAI_Senses * GetSenses ( ) { return m_pSenses ; }
const CAI_Senses * GetSenses ( ) const { return m_pSenses ; }
void SetDistLook ( float flDistLook ) ;
virtual bool QueryHearSound ( CSound * pSound ) ;
virtual bool QuerySeeEntity ( CBaseEntity * pEntity , bool bOnlyHateOrFearIfNPC = false ) ;
virtual void OnLooked ( int iDistance ) ;
virtual void OnListened ( ) ;
virtual void OnSeeEntity ( CBaseEntity * pEntity ) { }
// If true, AI will try to see this entity regardless of distance.
virtual bool ShouldNotDistanceCull ( ) { return false ; }
virtual int GetSoundInterests ( void ) ;
virtual int GetSoundPriority ( CSound * pSound ) ;
CSound * GetLoudestSoundOfType ( int iType ) ;
virtual CSound * GetBestSound ( int validTypes = ALL_SOUNDS ) ;
virtual CSound * GetBestScent ( void ) ;
virtual float HearingSensitivity ( void ) { return 1.0 ; }
virtual bool ShouldIgnoreSound ( CSound * ) { return false ; }
bool SoundIsVisible ( CSound * pSound ) ;
protected :
virtual void ClearSenseConditions ( void ) ;
private :
void LockBestSound ( ) ;
void UnlockBestSound ( ) ;
CAI_Senses * m_pSenses ;
CSound * m_pLockedBestSound ;
public :
//-----------------------------------------------------
//
// Enemy and target
//
//-----------------------------------------------------
Vector GetSmoothedVelocity ( void ) ;
CBaseEntity * GetEnemy ( ) { return m_hEnemy . Get ( ) ; }
CBaseEntity * GetEnemy ( ) const { return m_hEnemy . Get ( ) ; }
float GetTimeEnemyAcquired ( ) { return m_flTimeEnemyAcquired ; }
void SetEnemy ( CBaseEntity * pEnemy , bool bSetCondNewEnemy = true ) ;
const Vector & GetEnemyLKP ( ) const ;
float GetEnemyLastTimeSeen ( ) const ;
void MarkEnemyAsEluded ( ) ;
void ClearEnemyMemory ( ) ;
bool EnemyHasEludedMe ( ) const ;
virtual CBaseEntity * BestEnemy ( ) ; // returns best enemy in memory list
virtual bool IsValidEnemy ( CBaseEntity * pEnemy ) ;
virtual bool CanBeAnEnemyOf ( CBaseEntity * pEnemy ) ;
void ForceChooseNewEnemy ( ) { m_EnemiesSerialNumber = - 1 ; }
bool ChooseEnemy ( ) ;
virtual bool ShouldChooseNewEnemy ( ) ;
virtual void GatherEnemyConditions ( CBaseEntity * pEnemy ) ;
virtual float EnemyDistTolerance ( ) { return 0 ; } // Enemy distances within this tolerance of each other are considered equivalent.
float EnemyDistance ( CBaseEntity * pEnemy ) ;
CBaseCombatCharacter * GetEnemyCombatCharacterPointer ( ) ;
void SetEnemyOccluder ( CBaseEntity * pBlocker ) ;
CBaseEntity * GetEnemyOccluder ( void ) ;
virtual void StartTargetHandling ( CBaseEntity * pTargetEnt ) ;
//---------------------------------
CBaseEntity * GetTarget ( ) { return m_hTargetEnt . Get ( ) ; }
void SetTarget ( CBaseEntity * pTarget ) ;
void CheckTarget ( CBaseEntity * pTarget ) ;
float GetAcceptableTimeSeenEnemy ( void ) { return m_flAcceptableTimeSeenEnemy ; }
virtual CAI_BaseNPC * CreateCustomTarget ( const Vector & vecOrigin , float duration = - 1 ) ;
void SetDeathPose ( const int & iDeathPose ) { m_iDeathPose = iDeathPose ; }
void SetDeathPoseFrame ( const int & iDeathPoseFrame ) { m_iDeathFrame = iDeathPoseFrame ; }
void SelectDeathPose ( const CTakeDamageInfo & info ) ;
virtual bool ShouldPickADeathPose ( void ) { return true ; }
virtual bool AllowedToIgnite ( void ) { return false ; }
protected :
virtual float GetGoalRepathTolerance ( CBaseEntity * pGoalEnt , GoalType_t type , const Vector & curGoal , const Vector & curTargetPos ) ;
private :
void * CheckEnemy ( CBaseEntity * pEnemy ) { return NULL ; } // OBSOLETE, replaced by GatherEnemyConditions(), left here to make derived code not compile
// Updates the goal position in case of GOALTYPE_ENEMY
void UpdateEnemyPos ( ) ;
// Updates the goal position in case of GOALTYPE_TARGETENT
void UpdateTargetPos ( ) ;
//---------------------------------
EHANDLE m_hEnemy ; // the entity that the npc is fighting.
float m_flTimeEnemyAcquired ; // The time at which the entity the NPC is fighting became the NPC's enemy.
EHANDLE m_hTargetEnt ; // the entity that the npc is trying to reach
CRandStopwatch m_GiveUpOnDeadEnemyTimer ;
CSimpleSimTimer m_FailChooseEnemyTimer ;
int m_EnemiesSerialNumber ;
float m_flAcceptableTimeSeenEnemy ;
CSimpleSimTimer m_UpdateEnemyPosTimer ;
static CSimpleSimTimer m_AnyUpdateEnemyPosTimer ;
public :
//-----------------------------------------------------
//
// Commander mode stuff.
//
//-----------------------------------------------------
virtual bool IsCommandable ( ) { return false ; }
virtual bool IsPlayerAlly ( CBasePlayer * pPlayer = NULL ) ;
virtual bool IsMedic ( ) { return false ; }
virtual bool IsCommandMoving ( ) { return false ; }
virtual bool ShouldAutoSummon ( ) { return false ; }
virtual void SetCommandGoal ( const Vector & vecGoal ) ;
virtual void ClearCommandGoal ( ) ;
virtual void OnTargetOrder ( ) { }
virtual void OnMoveOrder ( ) { }
virtual bool IsValidCommandTarget ( CBaseEntity * pTarget ) { return false ; }
const Vector & GetCommandGoal ( ) const { return m_vecCommandGoal ; }
virtual void OnMoveToCommandGoalFailed ( ) { }
string_t GetPlayerSquadName ( ) const { Assert ( gm_iszPlayerSquad ! = NULL_STRING ) ; return gm_iszPlayerSquad ; }
bool IsInPlayerSquad ( ) const ;
virtual CAI_BaseNPC * GetSquadCommandRepresentative ( ) { return NULL ; }
virtual bool TargetOrder ( CBaseEntity * pTarget , CAI_BaseNPC * * Allies , int numAllies ) { OnTargetOrder ( ) ; return true ; }
virtual void MoveOrder ( const Vector & vecDest , CAI_BaseNPC * * Allies , int numAllies ) { SetCommandGoal ( vecDest ) ; SetCondition ( COND_RECEIVED_ORDERS ) ; OnMoveOrder ( ) ; }
// Return true if you're willing to be idly talked to by other friends.
virtual bool CanBeUsedAsAFriend ( void ) ;
private :
Vector m_vecCommandGoal ;
static string_t gm_iszPlayerSquad ;
public :
CAI_MoveMonitor m_CommandMoveMonitor ;
//-----------------------------------------------------
// Dynamic scripted NPC interactions
//-----------------------------------------------------
public :
float GetInteractionYaw ( void ) const { return m_flInteractionYaw ; }
protected :
void ParseScriptedNPCInteractions ( void ) ;
void AddScriptedNPCInteraction ( ScriptedNPCInteraction_t * pInteraction ) ;
const char * GetScriptedNPCInteractionSequence ( ScriptedNPCInteraction_t * pInteraction , int iPhase ) ;
void StartRunningInteraction ( CAI_BaseNPC * pOtherNPC , bool bActive ) ;
void StartScriptedNPCInteraction ( CAI_BaseNPC * pOtherNPC , ScriptedNPCInteraction_t * pInteraction , Vector vecOtherOrigin , QAngle angOtherAngles ) ;
void CheckForScriptedNPCInteractions ( void ) ;
void CalculateValidEnemyInteractions ( void ) ;
void CheckForcedNPCInteractions ( void ) ;
bool InteractionCouldStart ( CAI_BaseNPC * pOtherNPC , ScriptedNPCInteraction_t * pInteraction , Vector & vecOrigin , QAngle & angAngles ) ;
virtual bool CanRunAScriptedNPCInteraction ( bool bForced = false ) ;
bool IsRunningDynamicInteraction ( void ) { return ( m_iInteractionState ! = NPCINT_NOT_RUNNING & & ( m_hCine ! = NULL ) ) ; }
bool IsActiveDynamicInteraction ( void ) { return ( m_iInteractionState = = NPCINT_RUNNING_ACTIVE & & ( m_hCine ! = NULL ) ) ; }
ScriptedNPCInteraction_t * GetRunningDynamicInteraction ( void ) { return & ( m_ScriptedInteractions [ m_iInteractionPlaying ] ) ; }
void SetInteractionCantDie ( bool bCantDie ) { m_bCannotDieDuringInteraction = bCantDie ; }
bool HasInteractionCantDie ( void ) ;
void InputForceInteractionWithNPC ( inputdata_t & inputdata ) ;
void StartForcedInteraction ( CAI_BaseNPC * pNPC , int iInteraction ) ;
void CleanupForcedInteraction ( void ) ;
void CalculateForcedInteractionPosition ( void ) ;
CAI_BaseNPC * GetInteractionPartner ( void ) ;
private :
// Forced interactions
CHandle < CAI_BaseNPC > m_hForcedInteractionPartner ;
Vector m_vecForcedWorldPosition ;
float m_flForcedInteractionTimeout ; // Abort the interaction if it hasn't started by this time.
CHandle < CAI_BaseNPC > m_hInteractionPartner ;
EHANDLE m_hLastInteractionTestTarget ;
bool m_bCannotDieDuringInteraction ;
int m_iInteractionState ;
int m_iInteractionPlaying ;
CUtlVector < ScriptedNPCInteraction_t > m_ScriptedInteractions ;
float m_flInteractionYaw ;
public :
//-----------------------------------------------------
//
// Sounds
//
//-----------------------------------------------------
virtual CanPlaySequence_t CanPlaySequence ( bool fDisregardState , int interruptLevel ) ;
virtual bool CanPlaySentence ( bool fDisregardState ) { return IsAlive ( ) ; }
virtual int PlaySentence ( const char * pszSentence , float delay , float volume , soundlevel_t soundlevel , CBaseEntity * pListener = NULL ) ;
virtual int PlayScriptedSentence ( const char * pszSentence , float delay , float volume , soundlevel_t soundlevel , bool bConcurrent , CBaseEntity * pListener ) ;
virtual bool FOkToMakeSound ( int soundPriority = 0 ) ;
virtual void JustMadeSound ( int soundPriority = 0 , float flSoundLength = 0.0f ) ;
virtual void DeathSound ( const CTakeDamageInfo & info ) { return ; } ;
virtual void AlertSound ( void ) { return ; } ;
virtual void IdleSound ( void ) { return ; } ;
virtual void PainSound ( const CTakeDamageInfo & info ) { return ; } ;
virtual void FearSound ( void ) { return ; } ;
virtual void LostEnemySound ( void ) { return ; } ;
virtual void FoundEnemySound ( void ) { return ; } ;
virtual void BarnacleDeathSound ( void ) { CTakeDamageInfo info ; PainSound ( info ) ; }
virtual void SpeakSentence ( int sentenceType ) { return ; } ;
virtual bool ShouldPlayIdleSound ( void ) ;
virtual void MakeAIFootstepSound ( float volume , float duration = 0.5f ) ;
//---------------------------------
virtual CAI_Expresser * GetExpresser ( ) { return NULL ; }
const CAI_Expresser * GetExpresser ( ) const { return const_cast < CAI_BaseNPC * > ( this ) - > GetExpresser ( ) ; }
//---------------------------------
// NPC Event Response System
virtual bool CanRespondToEvent ( const char * ResponseConcept ) { return false ; }
virtual bool RespondedTo ( const char * ResponseConcept , bool bForce , bool bCancelScene ) { return false ; }
virtual void PlayerHasIlluminatedNPC ( CBasePlayer * pPlayer , float flDot ) ;
virtual void ModifyOrAppendCriteria ( AI_CriteriaSet & set ) ;
protected :
float SoundWaitTime ( ) const { return m_flSoundWaitTime ; }
public :
//-----------------------------------------------------
//
// Capabilities report (from CBaseCombatCharacter)
//
//-----------------------------------------------------
virtual int CapabilitiesGet ( void ) const ;
// local capabilities access
int CapabilitiesAdd ( int capabilities ) ;
int CapabilitiesRemove ( int capabilities ) ;
void CapabilitiesClear ( void ) ;
private :
int m_afCapability ; // tells us what a npc can/can't do.
public :
//-----------------------------------------------------
//
// Pathfinding, navigation & movement
//
//-----------------------------------------------------
CAI_Navigator * GetNavigator ( ) { return m_pNavigator ; }
const CAI_Navigator * GetNavigator ( ) const { return m_pNavigator ; }
CAI_LocalNavigator * GetLocalNavigator ( ) { return m_pLocalNavigator ; }
const CAI_LocalNavigator * GetLocalNavigator ( ) const { return m_pLocalNavigator ; }
CAI_Pathfinder * GetPathfinder ( ) { return m_pPathfinder ; }
const CAI_Pathfinder * GetPathfinder ( ) const { return m_pPathfinder ; }
CAI_MoveProbe * GetMoveProbe ( ) { return m_pMoveProbe ; }
const CAI_MoveProbe * GetMoveProbe ( ) const { return m_pMoveProbe ; }
CAI_Motor * GetMotor ( ) { return m_pMotor ; }
const CAI_Motor * GetMotor ( ) const { return m_pMotor ; }
//---------------------------------
static bool FindSpotForNPCInRadius ( Vector * pResult , const Vector & vStartPos , CAI_BaseNPC * pNPC , float radius , bool bOutOfPlayerViewcone = false ) ;
//---------------------------------
virtual bool IsNavigationUrgent ( ) ;
virtual bool ShouldFailNav ( bool bMovementFailed ) ;
virtual bool ShouldBruteForceFailedNav ( ) { return false ; }
// The current navigation (movement) mode (e.g. fly, swim, locomote, etc)
Navigation_t GetNavType ( ) const ;
void SetNavType ( Navigation_t navType ) ;
CBaseEntity * GetNavTargetEntity ( void ) ;
bool IsMoving ( void ) ;
virtual float GetTimeToNavGoal ( ) ;
// NPCs can override this to tweak with how costly particular movements are
virtual bool MovementCost ( int moveType , const Vector & vecStart , const Vector & vecEnd , float * pCost ) ;
// Turns a directional vector into a yaw value that points down that vector.
float VecToYaw ( const Vector & vecDir ) ;
// Turning
virtual float CalcIdealYaw ( const Vector & vecTarget ) ;
virtual float MaxYawSpeed ( void ) ; // Get max yaw speed
bool FacingIdeal ( void ) ;
void SetUpdatedYaw ( ) { m_ScheduleState . bTaskUpdatedYaw = true ; }
// Add multiple facing goals while moving/standing still.
virtual void AddFacingTarget ( CBaseEntity * pTarget , float flImportance , float flDuration , float flRamp = 0.0 ) ;
virtual void AddFacingTarget ( const Vector & vecPosition , float flImportance , float flDuration , float flRamp = 0.0 ) ;
virtual void AddFacingTarget ( CBaseEntity * pTarget , const Vector & vecPosition , float flImportance , float flDuration , float flRamp = 0.0 ) ;
virtual float GetFacingDirection ( Vector & vecDir ) ;
// ------------
// Methods used by motor to query properties/preferences/move-related state
// ------------
virtual bool CanStandOn ( CBaseEntity * pSurface ) const ;
virtual bool IsJumpLegal ( const Vector & startPos , const Vector & apex , const Vector & endPos ) const ; // Override for specific creature types
bool IsJumpLegal ( const Vector & startPos , const Vector & apex , const Vector & endPos , float maxUp , float maxDown , float maxDist ) const ;
bool ShouldMoveWait ( ) ;
virtual float StepHeight ( ) const { return 18.0f ; }
float GetStepDownMultiplier ( ) const ;
virtual float GetMaxJumpSpeed ( ) const { return 350.0f ; }
virtual float GetJumpGravity ( ) const { return 1.0f ; }
//---------------------------------
virtual bool OverrideMove ( float flInterval ) ; // Override to take total control of movement (return true if done so)
virtual bool OverrideMoveFacing ( const AILocalMoveGoal_t & move , float flInterval ) ;
//---------------------------------
virtual bool IsUnusableNode ( int iNodeID , CAI_Hint * pHint ) ; // Override for special NPC behavior
virtual bool ValidateNavGoal ( ) ;
virtual bool IsCurTaskContinuousMove ( ) ;
virtual bool IsValidMoveAwayDest ( const Vector & vecDest ) { return true ; }
//---------------------------------
//
// Notifications from navigator
//
virtual void OnMovementFailed ( ) { } ;
virtual void OnMovementComplete ( ) { } ;
//---------------------------------
bool FindNearestValidGoalPos ( const Vector & vTestPoint , Vector * pResult ) ;
void RememberUnreachable ( CBaseEntity * pEntity , float duration = - 1 ) ; // Remember that entity is unreachable
virtual bool IsUnreachable ( CBaseEntity * pEntity ) ; // Is entity is unreachable?
//---------------------------------
// Inherited from IAI_MotorMovementServices
virtual float CalcYawSpeed ( void ) ;
virtual bool OnCalcBaseMove ( AILocalMoveGoal_t * pMoveGoal ,
float distClear ,
AIMoveResult_t * pResult ) ;
virtual bool OnObstructionPreSteer ( AILocalMoveGoal_t * pMoveGoal ,
float distClear ,
AIMoveResult_t * pResult ) ;
// Translations of the above into some useful game terms
virtual bool OnObstructingDoor ( AILocalMoveGoal_t * pMoveGoal ,
CBaseDoor * pDoor ,
float distClear ,
AIMoveResult_t * pResult ) ;
virtual bool OnUpcomingPropDoor ( AILocalMoveGoal_t * pMoveGoal ,
CBasePropDoor * pDoor ,
float distClear ,
AIMoveResult_t * pResult ) ;
void OpenPropDoorBegin ( CBasePropDoor * pDoor ) ;
void OpenPropDoorNow ( CBasePropDoor * pDoor ) ;
//---------------------------------
void DelayMoveStart ( float delay ) { m_flMoveWaitFinished = gpGlobals - > curtime + delay ; }
float m_flMoveWaitFinished ;
//
// Stuff for opening doors.
//
void OnDoorFullyOpen ( CBasePropDoor * pDoor ) ;
void OnDoorBlocked ( CBasePropDoor * pDoor ) ;
CHandle < CBasePropDoor > m_hOpeningDoor ; // The CBasePropDoor that we are in the midst of opening for navigation.
protected :
// BRJ 4/11
// Semi-obsolete-looking Lars code I moved out of the engine and into here
int FlyMove ( const Vector & vecPosition , unsigned int mask ) ;
int WalkMove ( const Vector & vecPosition , unsigned int mask ) ;
// Unreachable Entities
CUtlVector < UnreachableEnt_t > m_UnreachableEnts ; // Array of unreachable entities
private :
CAI_Navigator * m_pNavigator ;
CAI_LocalNavigator * m_pLocalNavigator ;
CAI_Pathfinder * m_pPathfinder ;
CAI_MoveProbe * m_pMoveProbe ;
CAI_Motor * m_pMotor ;
EHANDLE m_hGoalEnt ; // path corner we are heading towards
float m_flTimeLastMovement ;
CSimpleSimTimer m_CheckOnGroundTimer ;
public :
//-----------------------------------------------------
//
// Eye position, view offset, head direction, eye direction
//
//-----------------------------------------------------
void SetDefaultEyeOffset ( void ) ;
const Vector & GetDefaultEyeOffset ( void ) { return m_vDefaultEyeOffset ; }
virtual Vector GetNodeViewOffset ( ) { return GetViewOffset ( ) ; }
virtual Vector EyeOffset ( Activity nActivity ) ;
virtual Vector EyePosition ( void ) ;
//---------------------------------
virtual Vector HeadDirection2D ( void ) ;
virtual Vector HeadDirection3D ( void ) ;
virtual Vector EyeDirection2D ( void ) ;
virtual Vector EyeDirection3D ( void ) ;
virtual CBaseEntity * EyeLookTarget ( void ) ; // Overridden by subclass to force look at an entity
virtual void AddLookTarget ( CBaseEntity * pTarget , float flImportance , float flDuration , float flRamp = 0.0 ) { } ;
virtual void AddLookTarget ( const Vector & vecPosition , float flImportance , float flDuration , float flRamp = 0.0 ) { } ;
virtual void SetHeadDirection ( const Vector & vTargetPos , float flInterval ) ;
virtual void MaintainLookTargets ( float flInterval ) ;
virtual bool ValidEyeTarget ( const Vector & lookTargetPos ) ;
virtual Vector FacingPosition ( void ) { return EyePosition ( ) ; } ; // position that other npc's use when facing you
virtual void MaintainTurnActivity ( void ) ;
virtual bool FInAimCone ( const Vector & vecSpot ) ;
virtual void AimGun ( ) ;
virtual void SetAim ( const Vector & aimDir ) ;
virtual void RelaxAim ( void ) ;
virtual CBaseEntity * GetAlternateMoveShootTarget ( ) { return NULL ; }
protected :
Vector m_vDefaultEyeOffset ;
float m_flNextEyeLookTime ; // Next time a pick a new place to look
float m_flEyeIntegRate ; // How fast does eye move to target
private :
Vector m_vEyeLookTarget ; // Where I want to be looking
Vector m_vCurEyeTarget ; // Direction I'm looking at
EHANDLE m_hEyeLookTarget ; // What I want to be looking at
float m_flHeadYaw ; // Current head yaw
float m_flHeadPitch ; // Current head pitch
protected :
float m_flOriginalYaw ; // This is the direction facing when the level designer placed the NPC in the level.
public :
//-----------------------------------------------------
// Mapmaker Scripting
//
// Set when the NPC is being scripted by a mapmaker, and
// shouldn't be responding to external stimuli that would
// break him out of his "script". NOT a scripted sequence.
//-----------------------------------------------------
inline bool IsInAScript ( void ) { return m_bInAScript ; }
inline void SetInAScript ( bool bScript ) { m_bInAScript = bScript ; }
void InputStartScripting ( inputdata_t & inputdata ) { m_bInAScript = true ; }
void InputStopScripting ( inputdata_t & inputdata ) { m_bInAScript = false ; }
void InputGagEnable ( inputdata_t & inputdata ) { AddSpawnFlags ( SF_NPC_GAG ) ; }
void InputGagDisable ( inputdata_t & inputdata ) { RemoveSpawnFlags ( SF_NPC_GAG ) ; }
bool HandleInteraction ( int interactionType , void * data , CBaseCombatCharacter * sourceEnt ) ;
virtual void InputOutsideTransition ( inputdata_t & inputdata ) ;
virtual void InputInsideTransition ( inputdata_t & inputdata ) ;
void CleanupScriptsOnTeleport ( bool bEnrouteAsWell ) ;
virtual void SetScriptedScheduleIgnoreConditions ( Interruptability_t interrupt ) ;
private :
bool m_bInAScript ;
public :
//-----------------------------------------------------
//
// Scripting
//
//-----------------------------------------------------
// Scripted sequence Info
enum SCRIPTSTATE
{
SCRIPT_PLAYING = 0 , // Playing the action animation.
SCRIPT_WAIT , // Waiting on everyone in the script to be ready. Plays the pre idle animation if there is one.
SCRIPT_POST_IDLE , // Playing the post idle animation after playing the action animation.
SCRIPT_CLEANUP , // Cancelling the script / cleaning up.
SCRIPT_WALK_TO_MARK , // Walking to the scripted sequence position.
SCRIPT_RUN_TO_MARK , // Running to the scripted sequence position.
SCRIPT_CUSTOM_MOVE_TO_MARK , // Moving to the scripted sequence position while playing a custom movement animation.
} ;
bool ExitScriptedSequence ( ) ;
bool CineCleanup ( ) ;
virtual void Teleport ( const Vector * newPosition , const QAngle * newAngles , const Vector * newVelocity ) ;
// 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 ) ;
static void ForceSelectedGo ( CBaseEntity * pPlayer , const Vector & targetPos , const Vector & traceDir , bool bRun ) ;
static void ForceSelectedGoRandom ( void ) ;
bool AutoMovement ( CBaseEntity * pTarget = NULL , AIMoveTrace_t * pTraceResult = NULL ) ;
bool AutoMovement ( float flInterval , CBaseEntity * pTarget = NULL , AIMoveTrace_t * pTraceResult = NULL ) ;
bool TaskRanAutomovement ( void ) { return m_ScheduleState . bTaskRanAutomovement ; }
SCRIPTSTATE m_scriptState ; // internal cinematic state
CHandle < CAI_ScriptedSequence > m_hCine ;
Activity m_ScriptArrivalActivity ;
string_t m_strScriptArrivalSequence ;
//-----------------------------------------------------
//
// Scenes
//
//-----------------------------------------------------
void AddSceneLock ( float flDuration = 0.2f ) { m_flSceneTime = MAX ( gpGlobals - > curtime + flDuration , m_flSceneTime ) ; } ;
void ClearSceneLock ( float flDuration = 0.2f ) { m_flSceneTime = gpGlobals - > curtime + flDuration ; } ;
bool IsInLockedScene ( void ) { return m_flSceneTime > gpGlobals - > curtime ; } ;
float m_flSceneTime ;
string_t m_iszSceneCustomMoveSeq ;
public :
//-----------------------------------------------------
//
// Memory
//
//-----------------------------------------------------
inline void Remember ( int iMemory ) { m_afMemory | = iMemory ; }
inline void Forget ( int iMemory ) { m_afMemory & = ~ iMemory ; }
inline bool HasMemory ( int iMemory ) { if ( m_afMemory & iMemory ) return TRUE ; return FALSE ; }
inline bool HasAllMemories ( int iMemory ) { if ( ( m_afMemory & iMemory ) = = iMemory ) return TRUE ; return FALSE ; }
virtual CAI_Enemies * GetEnemies ( void ) ;
virtual void RemoveMemory ( void ) ;
virtual bool UpdateEnemyMemory ( CBaseEntity * pEnemy , const Vector & position , CBaseEntity * pInformer = NULL ) ;
virtual float GetReactionDelay ( CBaseEntity * pEnemy ) ;
void SetLastAttackTime ( float time ) { m_flLastAttackTime = time ; }
float GetLastAttackTime ( ) const { return m_flLastAttackTime ; }
float GetLastDamageTime ( ) const { return m_flLastDamageTime ; }
float GetLastPlayerDamageTime ( ) const { return m_flLastPlayerDamageTime ; }
float GetLastEnemyTime ( ) const { return m_flLastEnemyTime ; }
// Set up the shot regulator based on the equipped weapon
virtual void OnChangeActiveWeapon ( CBaseCombatWeapon * pOldWeapon , CBaseCombatWeapon * pNewWeapon ) ;
// Weapon holstering
virtual bool CanHolsterWeapon ( void ) ;
virtual int HolsterWeapon ( void ) ;
virtual int UnholsterWeapon ( void ) ;
void InputHolsterWeapon ( inputdata_t & inputdata ) ;
void InputHolsterAndDestroyWeapon ( inputdata_t & inputdata ) ;
void InputUnholsterWeapon ( inputdata_t & inputdata ) ;
bool IsWeaponHolstered ( void ) ;
bool IsWeaponStateChanging ( void ) ;
void SetDesiredWeaponState ( DesiredWeaponState_t iState ) { m_iDesiredWeaponState = iState ; }
// NOTE: The Shot Regulator is used to manage the RangeAttack1 weapon.
inline CAI_ShotRegulator * GetShotRegulator ( ) { return & m_ShotRegulator ; }
virtual void OnRangeAttack1 ( ) ;
protected :
// Shot regulator code
virtual void OnUpdateShotRegulator ( ) ;
protected :
CAI_Enemies * m_pEnemies ; // Holds information about enemies / danger positions / shared between sqaud members
int m_afMemory ;
EHANDLE m_hEnemyOccluder ; // The entity my enemy is hiding behind.
float m_flSumDamage ; // How much consecutive damage I've received
float m_flLastDamageTime ; // Last time I received damage
float m_flLastPlayerDamageTime ; // Last time I received damage from the player
float m_flLastSawPlayerTime ; // Last time I saw the player
float m_flLastAttackTime ; // Last time that I attacked my current enemy
float m_flLastEnemyTime ;
float m_flNextWeaponSearchTime ; // next time to search for a better weapon
string_t m_iszPendingWeapon ; // THe NPC should create and equip this weapon.
bool m_bIgnoreUnseenEnemies ;
private :
CAI_ShotRegulator m_ShotRegulator ; // When should I shoot next?
DesiredWeaponState_t m_iDesiredWeaponState ;
public :
//-----------------------------------------------------
//
// Squads & tactics
//
//-----------------------------------------------------
virtual bool InitSquad ( void ) ;
virtual const char * SquadSlotName ( int slotID ) { return gm_SquadSlotNamespace . IdToSymbol ( slotID ) ; }
bool OccupyStrategySlot ( int squadSlotID ) ;
bool OccupyStrategySlotRange ( int slotIDStart , int slotIDEnd ) ;
bool HasStrategySlot ( int squadSlotID ) ;
bool HasStrategySlotRange ( int slotIDStart , int slotIDEnd ) ;
int GetMyStrategySlot ( ) { return m_iMySquadSlot ; }
void VacateStrategySlot ( void ) ;
bool IsStrategySlotRangeOccupied ( int slotIDStart , int slotIDEnd ) ; // Returns true if all in the range are occupied
CAI_Squad * GetSquad ( ) { return m_pSquad ; }
virtual void SetSquad ( CAI_Squad * pSquad ) ;
void AddToSquad ( string_t name ) ;
void RemoveFromSquad ( ) ;
void CheckSquad ( ) ;
void SetSquadName ( string_t name ) { m_SquadName = name ; }
bool IsInSquad ( ) const { return m_pSquad ! = NULL ; }
virtual bool IsSilentSquadMember ( ) const { return false ; }
int NumWeaponsInSquad ( const char * pszWeaponClassname ) ;
string_t GetHintGroup ( void ) { return m_strHintGroup ; }
void ClearHintGroup ( void ) { SetHintGroup ( NULL_STRING ) ; }
void SetHintGroup ( string_t name , bool bHintGroupNavLimiting = false ) ;
bool IsLimitingHintGroups ( void ) { return m_bHintGroupNavLimiting ; }
//---------------------------------
CAI_TacticalServices * GetTacticalServices ( ) { return m_pTacticalServices ; }
const CAI_TacticalServices * GetTacticalServices ( ) const { return m_pTacticalServices ; }
//---------------------------------
// Cover
virtual bool FindCoverPos ( CBaseEntity * pEntity , Vector * pResult ) ;
virtual bool FindCoverPosInRadius ( CBaseEntity * pEntity , const Vector & goalPos , float coverRadius , Vector * pResult ) ;
virtual bool FindCoverPos ( CSound * pSound , Vector * pResult ) ;
virtual bool IsValidCover ( const Vector & vecCoverLocation , CAI_Hint const * pHint ) ;
virtual bool IsValidShootPosition ( const Vector & vecCoverLocation , CAI_Node * pNode , CAI_Hint const * pHint ) ;
virtual bool TestShootPosition ( const Vector & vecShootPos , const Vector & targetPos ) { return WeaponLOSCondition ( vecShootPos , targetPos , false ) ; }
virtual bool IsCoverPosition ( const Vector & vecThreat , const Vector & vecPosition ) ;
virtual float CoverRadius ( void ) { return 1024 ; } // Default cover radius
virtual float GetMaxTacticalLateralMovement ( void ) { return MAXTACLAT_IGNORE ; }
protected :
virtual void OnChangeHintGroup ( string_t oldGroup , string_t newGroup ) { }
CAI_Squad * m_pSquad ; // The squad that I'm on
string_t m_SquadName ;
int m_iMySquadSlot ; // this is the behaviour slot that the npc currently holds in the squad.
private :
string_t m_strHintGroup ;
bool m_bHintGroupNavLimiting ;
CAI_TacticalServices * m_pTacticalServices ;
public :
//-----------------------------------------------------
//
// Base schedule & task support; Miscellaneous
//
//-----------------------------------------------------
void InitRelationshipTable ( void ) ;
void AddRelationship ( const char * pszRelationship , CBaseEntity * pActivator ) ;
virtual void AddEntityRelationship ( CBaseEntity * pEntity , Disposition_t nDisposition , int nPriority ) ;
virtual void AddClassRelationship ( Class_T nClass , Disposition_t nDisposition , int nPriority ) ;
void NPCUse ( CBaseEntity * pActivator , CBaseEntity * pCaller , USE_TYPE useType , float value ) ;
CBaseGrenade * IncomingGrenade ( void ) ;
virtual bool ShouldFadeOnDeath ( void ) ;
void NPCInitDead ( void ) ; // Call after animation/pose is set up
void CorpseFallThink ( void ) ;
float ThrowLimit ( const Vector & vecStart , const Vector & vecEnd , float fGravity , float fArcSize , const Vector & mins , const Vector & maxs , CBaseEntity * pTarget , Vector * jumpVel , CBaseEntity * * pBlocker ) ;
// these functions will survey conditions and set appropriate conditions bits for attack types.
virtual int RangeAttack1Conditions ( float flDot , float flDist ) ;
virtual int RangeAttack2Conditions ( float flDot , float flDist ) ;
virtual int MeleeAttack1Conditions ( float flDot , float flDist ) ;
virtual int MeleeAttack2Conditions ( float flDot , float flDist ) ;
virtual float InnateRange1MinRange ( void ) { return 0.0f ; }
virtual float InnateRange1MaxRange ( void ) { return FLT_MAX ; }
virtual bool OnBeginMoveAndShoot ( void ) { return true ; }
virtual void OnEndMoveAndShoot ( void ) { }
virtual bool UseAttackSquadSlots ( ) { return false ; }
//---------------------------------
virtual CBaseEntity * FindNamedEntity ( const char * pszName , IEntityFindFilter * pFilter = NULL ) ;
//---------------------------------
// States
//---------------------------------
virtual void ClearAttackConditions ( void ) ;
void GatherAttackConditions ( CBaseEntity * pTarget , float flDist ) ;
virtual bool ShouldLookForBetterWeapon ( ) ;
bool Weapon_IsBetterAvailable ( void ) ;
virtual Vector Weapon_ShootPosition ( void ) ;
virtual void GiveWeapon ( string_t iszWeaponName ) ;
virtual void OnGivenWeapon ( CBaseCombatWeapon * pNewWeapon ) { }
bool IsMovingToPickupWeapon ( ) ;
virtual bool WeaponLOSCondition ( const Vector & ownerPos , const Vector & targetPos , bool bSetConditions ) ;
virtual bool CurrentWeaponLOSCondition ( const Vector & targetPos , bool bSetConditions ) { return WeaponLOSCondition ( GetAbsOrigin ( ) , targetPos , bSetConditions ) ; }
virtual bool IsWaitingToRappel ( void ) { return false ; }
virtual void BeginRappel ( ) { }
// override to change the chase location of an enemy
// This is where your origin should go when you are chasing pEnemy when his origin is at chasePosition
// by default, leave this alone to make your origin coincide with his.
virtual void TranslateNavGoal ( CBaseEntity * pEnemy , Vector & chasePosition ) ;
virtual float GetDefaultNavGoalTolerance ( ) { return ( GetHullWidth ( ) * 2.0 ) ; }
virtual bool FCanCheckAttacks ( void ) ;
virtual void CheckAmmo ( void ) { }
virtual bool FValidateHintType ( CAI_Hint * pHint ) ;
virtual Activity GetHintActivity ( short sHintType , Activity HintsActivity ) ;
virtual float GetHintDelay ( short sHintType ) ;
virtual Activity GetCoverActivity ( CAI_Hint * pHint ) ;
virtual Activity GetReloadActivity ( CAI_Hint * pHint ) ;
virtual void SetTurnActivity ( void ) ;
bool UpdateTurnGesture ( void ) ;
// Returns the time when the door will be open
float OpenDoorAndWait ( CBaseEntity * pDoor ) ;
bool BBoxFlat ( void ) ;
//---------------------------------
virtual void Ignite ( float flFlameLifetime , bool bNPCOnly = true , float flSize = 0.0f , bool bCalledByLevelDesigner = false ) ;
virtual bool PassesDamageFilter ( const CTakeDamageInfo & info ) ;
//---------------------------------
void MakeDamageBloodDecal ( int cCount , float flNoise , trace_t * ptr , Vector vecDir ) ;
virtual float GetHitgroupDamageMultiplier ( int iHitGroup , const CTakeDamageInfo & info ) ;
void TraceAttack ( const CTakeDamageInfo & info , const Vector & vecDir , trace_t * ptr , CDmgAccumulator * pAccumulator ) ;
void DecalTrace ( trace_t * pTrace , char const * decalName ) ;
void ImpactTrace ( trace_t * pTrace , int iDamageType , const char * pCustomImpactName ) ;
virtual bool PlayerInSpread ( const Vector & sourcePos , const Vector & targetPos , float flSpread , float maxDistOffCenter , bool ignoreHatedPlayers = true ) ;
CBaseEntity * PlayerInRange ( const Vector & vecLocation , float flDist ) ;
bool PointInSpread ( CBaseCombatCharacter * pCheckEntity , const Vector & sourcePos , const Vector & targetPos , const Vector & testPoint , float flSpread , float maxDistOffCenter ) ;
bool IsSquadmateInSpread ( const Vector & sourcePos , const Vector & targetPos , float flSpread , float maxDistOffCenter ) ;
//---------------------------------
// combat functions
//---------------------------------
virtual bool InnateWeaponLOSCondition ( const Vector & ownerPos , const Vector & targetPos , bool bSetConditions ) ;
virtual Activity GetFlinchActivity ( bool bHeavyDamage , bool bGesture ) ;
virtual bool ShouldGib ( const CTakeDamageInfo & info ) { return false ; } // Always ragdoll, unless specified by the leaf class
virtual bool Event_Gibbed ( const CTakeDamageInfo & info ) ;
virtual void Event_Killed ( const CTakeDamageInfo & info ) ;
virtual Vector GetShootEnemyDir ( const Vector & shootOrigin , bool bNoisy = true ) ;
# ifdef HL2_DLL
virtual Vector GetActualShootPosition ( const Vector & shootOrigin ) ;
virtual Vector GetActualShootTrajectory ( const Vector & shootOrigin ) ;
virtual Vector GetAttackSpread ( CBaseCombatWeapon * pWeapon , CBaseEntity * pTarget = NULL ) ;
virtual float GetSpreadBias ( CBaseCombatWeapon * pWeapon , CBaseEntity * pTarget ) ;
# endif //HL2_DLL
virtual void CollectShotStats ( const Vector & vecShootOrigin , const Vector & vecShootDir ) ;
virtual Vector BodyTarget ( const Vector & posSrc , bool bNoisy = true ) ;
virtual Vector GetAutoAimCenter ( ) { return BodyTarget ( vec3_origin , false ) ; }
virtual void FireBullets ( const FireBulletsInfo_t & info ) ;
// OLD VERSION! Use the struct version
void FireBullets ( int cShots , const Vector & vecSrc , const Vector & vecDirShooting ,
const Vector & vecSpread , float flDistance , int iAmmoType , int iTracerFreq = 4 ,
int firingEntID = - 1 , int attachmentID = - 1 , int iDamage = 0 ,
CBaseEntity * pAttacker = NULL , bool bFirstShotAccurate = false ) ;
virtual bool ShouldMoveAndShoot ( void ) ;
//---------------------------------
// Damage
//---------------------------------
virtual int OnTakeDamage_Alive ( const CTakeDamageInfo & info ) ;
virtual int OnTakeDamage_Dying ( const CTakeDamageInfo & info ) ;
virtual int OnTakeDamage_Dead ( const CTakeDamageInfo & info ) ;
virtual void NotifyFriendsOfDamage ( CBaseEntity * pAttackerEntity ) ;
virtual void OnFriendDamaged ( CBaseCombatCharacter * pSquadmate , CBaseEntity * pAttacker ) ;
virtual bool IsLightDamage ( const CTakeDamageInfo & info ) ;
virtual bool IsHeavyDamage ( const CTakeDamageInfo & info ) ;
void DoRadiusDamage ( const CTakeDamageInfo & info , int iClassIgnore , CBaseEntity * pEntityIgnore ) ;
void DoRadiusDamage ( const CTakeDamageInfo & info , const Vector & vecSrc , int iClassIgnore , CBaseEntity * pEntityIgnore ) ;
//---------------------------------
virtual void PickupWeapon ( CBaseCombatWeapon * pWeapon ) ;
virtual void PickupItem ( CBaseEntity * pItem ) { } ;
CBaseEntity * DropItem ( const char * pszItemName , Vector vecPos , QAngle vecAng ) ; // drop an item.
//---------------------------------
// Inputs
//---------------------------------
void InputSetRelationship ( inputdata_t & inputdata ) ;
void InputSetEnemyFilter ( inputdata_t & inputdata ) ;
void InputSetHealth ( inputdata_t & inputdata ) ;
void InputBeginRappel ( inputdata_t & inputdata ) ;
void InputSetSquad ( inputdata_t & inputdata ) ;
void InputWake ( inputdata_t & inputdata ) ;
void InputForgetEntity ( inputdata_t & inputdata ) ;
void InputIgnoreDangerSounds ( inputdata_t & inputdata ) ;
void InputUpdateEnemyMemory ( inputdata_t & inputdata ) ;
//---------------------------------
virtual void NotifyDeadFriend ( CBaseEntity * pFriend ) { return ; }
//---------------------------------
// Utility methods
static Vector CalcThrowVelocity ( const Vector & startPos , const Vector & endPos , float fGravity , float fArcSize ) ;
//---------------------------------
float SetWait ( float minWait , float maxWait = 0.0 ) ;
void ClearWait ( ) ;
float GetWaitFinishTime ( ) { return m_flWaitFinished ; }
bool IsWaitFinished ( ) ;
bool IsWaitSet ( ) ;
CBaseEntity * GetGoalEnt ( ) { return m_hGoalEnt ; }
void SetGoalEnt ( CBaseEntity * pGoalEnt ) { m_hGoalEnt . Set ( pGoalEnt ) ; }
CAI_Hint * GetHintNode ( ) { return m_pHintNode ; }
const CAI_Hint * GetHintNode ( ) const { return m_pHintNode ; }
void SetHintNode ( CAI_Hint * pHintNode ) ;
void ClearHintNode ( float reuseDelay = 0.0 ) ;
float m_flWaitFinished ; // if we're told to wait, this is the time that the wait will be over.
float m_flNextFlinchTime ; // Time at which we'll flinch fully again (as opposed to just doing gesture flinches)
float m_flNextDodgeTime ; // Time at which I can dodge again. Used so that the behavior doesn't happen over and over.
CAI_MoveAndShootOverlay m_MoveAndShootOverlay ;
Vector m_vecLastPosition ; // npc sometimes wants to return to where it started after an operation.
Vector m_vSavePosition ; // position stored by code that called this schedules
Vector m_vInterruptSavePosition ; // position stored by a task that was interrupted
private :
CHandle < CAI_Hint > m_pHintNode ; // this is the hint that the npc is moving towards or performing active idle on.
public :
int m_cAmmoLoaded ; // how much ammo is in the weapon (used to trigger reload anim sequences)
float m_flDistTooFar ; // if enemy farther away than this, bits_COND_ENEMY_TOOFAR set in GatherEnemyConditions
string_t m_spawnEquipment ;
bool m_fNoDamageDecal ;
EHANDLE m_hStoredPathTarget ; // For TASK_SET_GOAL
Vector m_vecStoredPathGoal ; //
GoalType_t m_nStoredPathType ; //
int m_fStoredPathFlags ; //
CHandle < CBaseFilter > m_hEnemyFilter ;
string_t m_iszEnemyFilterName ;
bool m_bDidDeathCleanup ;
IMPLEMENT_NETWORK_VAR_FOR_DERIVED ( m_lifeState ) ;
//---------------------------------
// Outputs
//---------------------------------
COutputEvent m_OnDamaged ;
COutputEvent m_OnDeath ;
COutputEvent m_OnHalfHealth ;
COutputEHANDLE m_OnFoundEnemy ;
COutputEvent m_OnLostEnemyLOS ;
COutputEvent m_OnLostEnemy ;
COutputEHANDLE m_OnFoundPlayer ;
COutputEvent m_OnLostPlayerLOS ;
COutputEvent m_OnLostPlayer ;
COutputEvent m_OnHearWorld ;
COutputEvent m_OnHearPlayer ;
COutputEvent m_OnHearCombat ;
COutputEvent m_OnDamagedByPlayer ;
COutputEvent m_OnDamagedByPlayerSquad ;
COutputEvent m_OnDenyCommanderUse ;
COutputEvent m_OnRappelTouchdown ;
COutputEvent m_OnSleep ;
COutputEvent m_OnWake ;
COutputEvent m_OnForcedInteractionStarted ;
COutputEvent m_OnForcedInteractionAborted ;
COutputEvent m_OnForcedInteractionFinished ;
public :
// use this to shrink the bbox temporarily
void SetHullSizeNormal ( bool force = false ) ;
bool SetHullSizeSmall ( bool force = false ) ;
bool IsUsingSmallHull ( ) const { return m_fIsUsingSmallHull ; }
const Vector & GetHullMins ( ) const { return NAI_Hull : : Mins ( GetHullType ( ) ) ; }
const Vector & GetHullMaxs ( ) const { return NAI_Hull : : Maxs ( GetHullType ( ) ) ; }
float GetHullWidth ( ) const { return NAI_Hull : : Width ( GetHullType ( ) ) ; }
float GetHullHeight ( ) const { return NAI_Hull : : Height ( GetHullType ( ) ) ; }
void SetupVPhysicsHull ( ) ;
virtual void StartTouch ( CBaseEntity * pOther ) ;
void CheckPhysicsContacts ( ) ;
private :
void TryRestoreHull ( void ) ;
bool m_fIsUsingSmallHull ;
bool m_bCheckContacts ;
private :
// Task implementation helpers
void StartTurn ( float flDeltaYaw ) ;
bool FindCoverFromEnemy ( bool bNodesOnly = false , float flMinDistance = 0 , float flMaxDistance = FLT_MAX ) ;
bool FindCoverFromBestSound ( Vector * pCoverPos ) ;
void StartScriptMoveToTargetTask ( int task ) ;
void RunDieTask ( ) ;
void RunAttackTask ( int task ) ;
protected :
virtual float CalcReasonableFacing ( bool bIgnoreOriginalFacing = false ) ;
virtual bool IsValidReasonableFacing ( const Vector & vecSightDir , float sightDist ) { return true ; }
virtual float GetReasonableFacingDist ( void ) ;
public :
inline int UsableNPCObjectCaps ( int baseCaps )
{
if ( IsAlive ( ) )
baseCaps | = FCAP_IMPULSE_USE ;
return baseCaps ;
}
virtual int ObjectCaps ( ) { return ( BaseClass : : ObjectCaps ( ) | FCAP_NOTIFY_ON_TRANSITION ) ; }
//-----------------------------------------------------
//
// Core mapped data structures
//
// String Registries for default AI Shared by all CBaseNPCs
// These are used only during initialization and in debug
//-----------------------------------------------------
static void InitSchedulingTables ( ) ;
static CAI_GlobalScheduleNamespace * GetSchedulingSymbols ( ) { return & gm_SchedulingSymbols ; }
static CAI_ClassScheduleIdSpace & AccessClassScheduleIdSpaceDirect ( ) { return gm_ClassScheduleIdSpace ; }
virtual CAI_ClassScheduleIdSpace * GetClassScheduleIdSpace ( ) { return & gm_ClassScheduleIdSpace ; }
static int GetScheduleID ( const char * schedName ) ;
static int GetActivityID ( const char * actName ) ;
static int GetConditionID ( const char * condName ) ;
static int GetTaskID ( const char * taskName ) ;
static int GetSquadSlotID ( const char * slotName ) ;
virtual const char * GetSquadSlotDebugName ( int iSquadSlot ) ;
static const char * GetActivityName ( int actID ) ;
static void AddActivityToSR ( const char * actName , int conID ) ;
static void AddEventToSR ( const char * eventName , int conID ) ;
static const char * GetEventName ( int actID ) ;
static int GetEventID ( const char * actName ) ;
public :
//-----------------------------------------------------
// Crouch handling
//-----------------------------------------------------
bool CrouchIsDesired ( void ) const ;
virtual bool IsCrouching ( void ) ;
inline void ForceCrouch ( void ) ;
inline void ClearForceCrouch ( void ) ;
protected :
virtual bool Crouch ( void ) ;
virtual bool Stand ( void ) ;
virtual void DesireCrouch ( void ) ;
inline void DesireStand ( void ) ;
bool CouldShootIfCrouching ( CBaseEntity * pTarget ) ;
virtual bool IsCrouchedActivity ( Activity activity ) ;
protected :
// Override these in your derived NPC class
virtual Vector GetCrouchEyeOffset ( void ) { return Vector ( 0 , 0 , 40 ) ; }
virtual Vector GetCrouchGunOffset ( void ) { return Vector ( 0 , 0 , 36 ) ; }
private :
bool m_bCrouchDesired ;
bool m_bForceCrouch ;
bool m_bIsCrouching ;
//-----------------------------------------------------
//-----------------------------------------------------
// ai_post_frame_navigation
//-----------------------------------------------------
private :
bool m_bDeferredNavigation ; // This NPCs has a navigation query that's being deferred until later in the frame
public :
void SetNavigationDeferred ( bool bState ) { m_bDeferredNavigation = bState ; }
bool IsNavigationDeferred ( void ) { return m_bDeferredNavigation ; }
//-----------------------------------------------------
protected :
static CAI_GlobalNamespace gm_SquadSlotNamespace ;
static CAI_LocalIdSpace gm_SquadSlotIdSpace ;
private :
// Checks to see that the nav hull is valid for the NPC
bool IsNavHullValid ( ) const ;
friend class CAI_SystemHook ;
friend class CAI_SchedulesManager ;
static bool LoadDefaultSchedules ( void ) ;
static void InitDefaultScheduleSR ( void ) ;
static void InitDefaultTaskSR ( void ) ;
static void InitDefaultConditionSR ( void ) ;
static void InitDefaultActivitySR ( void ) ;
static void InitDefaultSquadSlotSR ( void ) ;
static CStringRegistry * m_pActivitySR ;
static int m_iNumActivities ;
static CStringRegistry * m_pEventSR ;
static int m_iNumEvents ;
static CAI_GlobalScheduleNamespace gm_SchedulingSymbols ;
static CAI_ClassScheduleIdSpace gm_ClassScheduleIdSpace ;
public :
//----------------------------------------------------
// Debugging tools
//
// -----------------------------
// Debuging Fields and Methods
// -----------------------------
const char * m_failText ; // Text of why it failed
const char * m_interruptText ; // Text of why schedule interrupted
CAI_Schedule * m_failedSchedule ; // The schedule that failed last
CAI_Schedule * m_interuptSchedule ; // The schedule that was interrupted last
int m_nDebugCurIndex ; // Index used for stepping through AI
virtual void ReportAIState ( void ) ;
virtual void ReportOverThinkLimit ( float time ) ;
void DumpTaskTimings ( ) ;
void DrawDebugGeometryOverlays ( void ) ;
virtual int DrawDebugTextOverlays ( void ) ;
void ToggleFreeze ( void ) ;
static void ClearAllSchedules ( void ) ;
static int m_nDebugBits ;
static CAI_BaseNPC * m_pDebugNPC ;
static int m_nDebugPauseIndex ; // Current step
static inline void SetDebugNPC ( CAI_BaseNPC * pNPC ) { m_pDebugNPC = pNPC ; }
static inline bool IsDebugNPC ( CAI_BaseNPC * pNPC ) { return ( pNPC = = m_pDebugNPC ) ; }
float m_LastShootAccuracy ;
int m_TotalShots ;
int m_TotalHits ;
# ifdef _DEBUG
bool m_bSelected ;
# endif
float m_flSoundWaitTime ; // Time when I'm allowed to make another sound
int m_nSoundPriority ;
float m_flIgnoreDangerSoundsUntil ;
# ifdef AI_MONITOR_FOR_OSCILLATION
CUtlVector < AIScheduleChoice_t > m_ScheduleHistory ;
# endif //AI_MONITOR_FOR_OSCILLATION
private :
// Break into pieces!
void Break ( CBaseEntity * pBreaker ) ;
void InputBreak ( inputdata_t & inputdata ) ;
friend void CC_NPC_Go ( ) ;
friend void CC_NPC_GoRandom ( ) ;
friend void CC_NPC_Freeze ( const CCommand & args ) ;
public :
CNetworkVar ( bool , m_bPerformAvoidance ) ;
CNetworkVar ( bool , m_bIsMoving ) ;
CNetworkVar ( bool , m_bFadeCorpse ) ;
CNetworkVar ( bool , m_bImportanRagdoll ) ;
CNetworkVar ( bool , m_bSpeedModActive ) ;
CNetworkVar ( int , m_iSpeedModRadius ) ;
CNetworkVar ( int , m_iSpeedModSpeed ) ;
CNetworkVar ( float , m_flTimePingEffect ) ; // Display the pinged effect until this time
void InputActivateSpeedModifier ( inputdata_t & inputdata ) { m_bSpeedModActive = true ; }
void InputDisableSpeedModifier ( inputdata_t & inputdata ) { m_bSpeedModActive = false ; }
void InputSetSpeedModifierRadius ( inputdata_t & inputdata ) ;
void InputSetSpeedModifierSpeed ( inputdata_t & inputdata ) ;
virtual bool ShouldProbeCollideAgainstEntity ( CBaseEntity * pEntity ) ;
bool m_bPlayerAvoidState ;
void GetPlayerAvoidBounds ( Vector * pMins , Vector * pMaxs ) ;
void StartPingEffect ( void ) { m_flTimePingEffect = gpGlobals - > curtime + 2.0f ; DispatchUpdateTransmitState ( ) ; }
} ;
//-----------------------------------------------------------------------------
// Purpose: Returns whether our ideal activity has started. If not, we are in
// a transition sequence.
//-----------------------------------------------------------------------------
inline bool CAI_BaseNPC : : IsActivityStarted ( void )
{
return ( GetSequence ( ) = = m_nIdealSequence ) ;
}
//-----------------------------------------------------------------------------
// Bullet firing (legacy)...
//-----------------------------------------------------------------------------
inline void CAI_BaseNPC : : FireBullets ( int cShots , const Vector & vecSrc ,
const Vector & vecDirShooting , const Vector & vecSpread , float flDistance ,
int iAmmoType , int iTracerFreq , int firingEntID , int attachmentID ,
int iDamage , CBaseEntity * pAttacker , bool bFirstShotAccurate )
{
FireBulletsInfo_t info ;
info . m_iShots = cShots ;
info . m_vecSrc = vecSrc ;
info . m_vecDirShooting = vecDirShooting ;
info . m_vecSpread = vecSpread ;
info . m_flDistance = flDistance ;
info . m_iAmmoType = iAmmoType ;
info . m_iTracerFreq = iTracerFreq ;
info . m_flDamage = iDamage ;
info . m_pAttacker = pAttacker ;
info . m_nFlags = bFirstShotAccurate ? FIRE_BULLETS_FIRST_SHOT_ACCURATE : 0 ;
FireBullets ( info ) ;
}
//-----------------------------------------------------------------------------
// Purpose: Sets the ideal state of this NPC.
//-----------------------------------------------------------------------------
inline void CAI_BaseNPC : : SetIdealState ( NPC_STATE eIdealState )
{
if ( eIdealState ! = m_IdealNPCState )
{
/*switch (eIdealState)
{
case NPC_STATE_NONE :
Msg ( " %s.SetIdealState: NPC_STATE_NONE \n " , GetDebugName ( ) ) ;
break ;
case NPC_STATE_IDLE :
Msg ( " %s.SetIdealState: NPC_STATE_IDLE \n " , GetDebugName ( ) ) ;
break ;
case NPC_STATE_ALERT :
Msg ( " %s.SetIdealState: NPC_STATE_ALERT \n " , GetDebugName ( ) ) ;
break ;
case NPC_STATE_COMBAT :
Msg ( " %s.SetIdealState: NPC_STATE_COMBAT \n " , GetDebugName ( ) ) ;
break ;
case NPC_STATE_SCRIPT :
Msg ( " %s.SetIdealState: NPC_STATE_SCRIPT \n " , GetDebugName ( ) ) ;
break ;
case NPC_STATE_PLAYDEAD :
Msg ( " %s.SetIdealState: NPC_STATE_PLAYDEAD \n " , GetDebugName ( ) ) ;
break ;
case NPC_STATE_PRONE :
Msg ( " %s.SetIdealState: NPC_STATE_PRONE \n " , GetDebugName ( ) ) ;
break ;
case NPC_STATE_DEAD :
Msg ( " %s.SetIdealState: NPC_STATE_DEAD \n " , GetDebugName ( ) ) ;
break ;
default :
Msg ( " %s.SetIdealState: <Unknown> \n " , GetDebugName ( ) ) ;
break ;
} */
m_IdealNPCState = eIdealState ;
}
}
//-----------------------------------------------------------------------------
// Purpose: Returns the current ideal state the NPC will try to achieve.
//-----------------------------------------------------------------------------
inline NPC_STATE CAI_BaseNPC : : GetIdealState ( )
{
return m_IdealNPCState ;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
inline int CAI_BaseNPC : : IncScheduleCurTaskIndex ( )
{
m_ScheduleState . iTaskInterrupt = 0 ;
m_ScheduleState . bTaskRanAutomovement = false ;
m_ScheduleState . bTaskUpdatedYaw = false ;
return + + m_ScheduleState . iCurTask ;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
inline void CAI_BaseNPC : : ResetScheduleCurTaskIndex ( )
{
m_ScheduleState . iCurTask = 0 ;
m_ScheduleState . iTaskInterrupt = 0 ;
m_ScheduleState . bTaskRanAutomovement = false ;
m_ScheduleState . bTaskUpdatedYaw = false ;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
inline bool CAI_BaseNPC : : CrouchIsDesired ( void ) const
{
return ( ( CapabilitiesGet ( ) & bits_CAP_DUCK ) & & ( m_bCrouchDesired | m_bForceCrouch ) ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
inline void CAI_BaseNPC : : DesireStand ( void )
{
m_bCrouchDesired = false ;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
inline void CAI_BaseNPC : : ForceCrouch ( void )
{
m_bForceCrouch = true ;
Crouch ( ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
inline void CAI_BaseNPC : : ClearForceCrouch ( void )
{
m_bForceCrouch = false ;
if ( IsCrouching ( ) )
{
Stand ( ) ;
}
}
inline bool CAI_BaseNPC : : HaveSequenceForActivity ( Activity activity )
{
# if STUDIO_SEQUENCE_ACTIVITY_LOOKUPS_ARE_SLOW
return ( ( GetModelPtr ( ) ) ? ( SelectWeightedSequence ( activity ) ! = ACTIVITY_NOT_AVAILABLE ) : false ) ;
# else
return ( ( GetModelPtr ( ) ) ? GetModelPtr ( ) - > HaveSequenceForActivity ( activity ) : false ) ;
# endif
}
typedef CHandle < CAI_BaseNPC > AIHANDLE ;
// ============================================================================
// Macros for introducing new schedules in sub-classes
//
// Strings registries and schedules use unique ID's for each item, but
// sub-class enumerations are non-unique, so we translate between the
// enumerations and unique ID's
// ============================================================================
# define AI_BEGIN_CUSTOM_SCHEDULE_PROVIDER( derivedClass ) \
IMPLEMENT_CUSTOM_SCHEDULE_PROVIDER ( derivedClass ) \
void derivedClass : : InitCustomSchedules ( void ) \
{ \
typedef derivedClass CNpc ; \
const char * pszClassName = # derivedClass ; \
\
CUtlVector < const char * > schedulesToLoad ; \
CUtlVector < AIScheduleLoadFunc_t > reqiredOthers ; \
CAI_NamespaceInfos scheduleIds ; \
CAI_NamespaceInfos taskIds ; \
CAI_NamespaceInfos conditionIds ;
//-----------------
# define AI_BEGIN_CUSTOM_NPC( className, derivedClass ) \
IMPLEMENT_CUSTOM_AI ( className , derivedClass ) \
void derivedClass : : InitCustomSchedules ( void ) \
{ \
typedef derivedClass CNpc ; \
const char * pszClassName = # derivedClass ; \
\
CUtlVector < const char * > schedulesToLoad ; \
CUtlVector < AIScheduleLoadFunc_t > reqiredOthers ; \
CAI_NamespaceInfos scheduleIds ; \
CAI_NamespaceInfos taskIds ; \
CAI_NamespaceInfos conditionIds ; \
CAI_NamespaceInfos squadSlotIds ;
//-----------------
# define EXTERN_SCHEDULE( id ) \
scheduleIds . PushBack ( # id , id ) ; \
extern const char * g_psz # # id ; \
schedulesToLoad . AddToTail ( g_psz # # id ) ;
//-----------------
# define DEFINE_SCHEDULE( id, text ) \
scheduleIds . PushBack ( # id , id ) ; \
const char * g_psz # # id = \
" \n Schedule " \
" \n " # id \
text \
" \n " ; \
schedulesToLoad . AddToTail ( g_psz # # id ) ;
//-----------------
# define DECLARE_CONDITION( id ) \
conditionIds . PushBack ( # id , id ) ;
//-----------------
# define DECLARE_TASK( id ) \
taskIds . PushBack ( # id , id ) ;
//-----------------
# define DECLARE_ACTIVITY( id ) \
ADD_CUSTOM_ACTIVITY ( CNpc , id ) ;
//-----------------
# define DECLARE_SQUADSLOT( id ) \
squadSlotIds . PushBack ( # id , id ) ;
//-----------------
# define DECLARE_INTERACTION( interaction ) \
ADD_CUSTOM_INTERACTION ( interaction ) ;
//-----------------
# define DECLARE_ANIMEVENT( id ) \
ADD_CUSTOM_ANIMEVENT ( CNpc , id ) ;
//-----------------
# define DECLARE_USES_SCHEDULE_PROVIDER( classname ) reqiredOthers.AddToTail( ScheduleLoadHelper(classname) );
//-----------------
// IDs are stored and then added in order due to constraints in the namespace implementation
# define AI_END_CUSTOM_SCHEDULE_PROVIDER() \
\
int i ; \
\
CNpc : : AccessClassScheduleIdSpaceDirect ( ) . Init ( pszClassName , BaseClass : : GetSchedulingSymbols ( ) , & BaseClass : : AccessClassScheduleIdSpaceDirect ( ) ) ; \
\
scheduleIds . Sort ( ) ; \
taskIds . Sort ( ) ; \
conditionIds . Sort ( ) ; \
\
for ( i = 0 ; i < scheduleIds . Count ( ) ; i + + ) \
{ \
ADD_CUSTOM_SCHEDULE_NAMED ( CNpc , scheduleIds [ i ] . pszName , scheduleIds [ i ] . localId ) ; \
} \
\
for ( i = 0 ; i < taskIds . Count ( ) ; i + + ) \
{ \
ADD_CUSTOM_TASK_NAMED ( CNpc , taskIds [ i ] . pszName , taskIds [ i ] . localId ) ; \
} \
\
for ( i = 0 ; i < conditionIds . Count ( ) ; i + + ) \
{ \
if ( ValidateConditionLimits ( conditionIds [ i ] . pszName ) ) \
{ \
ADD_CUSTOM_CONDITION_NAMED ( CNpc , conditionIds [ i ] . pszName , conditionIds [ i ] . localId ) ; \
} \
} \
\
for ( i = 0 ; i < reqiredOthers . Count ( ) ; i + + ) \
{ \
( * reqiredOthers [ i ] ) ( ) ; \
} \
\
for ( i = 0 ; i < schedulesToLoad . Count ( ) ; i + + ) \
{ \
if ( CNpc : : gm_SchedLoadStatus . fValid ) \
{ \
CNpc : : gm_SchedLoadStatus . fValid = g_AI_SchedulesManager . LoadSchedulesFromBuffer ( pszClassName , schedulesToLoad [ i ] , & AccessClassScheduleIdSpaceDirect ( ) ) ; \
} \
else \
break ; \
} \
}
inline bool ValidateConditionLimits ( const char * pszNewCondition )
{
int nGlobalConditions = CAI_BaseNPC : : GetSchedulingSymbols ( ) - > NumConditions ( ) ;
if ( nGlobalConditions > = MAX_CONDITIONS )
{
AssertMsg2 ( 0 , " Exceeded max number of conditions (%d), ignoring condition %s \n " , MAX_CONDITIONS , pszNewCondition ) ;
DevWarning ( " Exceeded max number of conditions (%d), ignoring condition %s \n " , MAX_CONDITIONS , pszNewCondition ) ;
return false ;
}
return true ;
}
//-------------------------------------
// IDs are stored and then added in order due to constraints in the namespace implementation
# define AI_END_CUSTOM_NPC() \
\
int i ; \
\
CNpc : : AccessClassScheduleIdSpaceDirect ( ) . Init ( pszClassName , BaseClass : : GetSchedulingSymbols ( ) , & BaseClass : : AccessClassScheduleIdSpaceDirect ( ) ) ; \
CNpc : : gm_SquadSlotIdSpace . Init ( & BaseClass : : gm_SquadSlotNamespace , & BaseClass : : gm_SquadSlotIdSpace ) ; \
\
scheduleIds . Sort ( ) ; \
taskIds . Sort ( ) ; \
conditionIds . Sort ( ) ; \
squadSlotIds . Sort ( ) ; \
\
for ( i = 0 ; i < scheduleIds . Count ( ) ; i + + ) \
{ \
ADD_CUSTOM_SCHEDULE_NAMED ( CNpc , scheduleIds [ i ] . pszName , scheduleIds [ i ] . localId ) ; \
} \
\
for ( i = 0 ; i < taskIds . Count ( ) ; i + + ) \
{ \
ADD_CUSTOM_TASK_NAMED ( CNpc , taskIds [ i ] . pszName , taskIds [ i ] . localId ) ; \
} \
\
for ( i = 0 ; i < conditionIds . Count ( ) ; i + + ) \
{ \
if ( ValidateConditionLimits ( conditionIds [ i ] . pszName ) ) \
{ \
ADD_CUSTOM_CONDITION_NAMED ( CNpc , conditionIds [ i ] . pszName , conditionIds [ i ] . localId ) ; \
} \
} \
\
for ( i = 0 ; i < squadSlotIds . Count ( ) ; i + + ) \
{ \
ADD_CUSTOM_SQUADSLOT_NAMED ( CNpc , squadSlotIds [ i ] . pszName , squadSlotIds [ i ] . localId ) ; \
} \
\
for ( i = 0 ; i < reqiredOthers . Count ( ) ; i + + ) \
{ \
( * reqiredOthers [ i ] ) ( ) ; \
} \
\
for ( i = 0 ; i < schedulesToLoad . Count ( ) ; i + + ) \
{ \
if ( CNpc : : gm_SchedLoadStatus . fValid ) \
{ \
CNpc : : gm_SchedLoadStatus . fValid = g_AI_SchedulesManager . LoadSchedulesFromBuffer ( pszClassName , schedulesToLoad [ i ] , & AccessClassScheduleIdSpaceDirect ( ) ) ; \
} \
else \
break ; \
} \
}
//-------------------------------------
struct AI_NamespaceAddInfo_t
{
AI_NamespaceAddInfo_t ( const char * pszName , int localId )
: pszName ( pszName ) ,
localId ( localId )
{
}
const char * pszName ;
int localId ;
} ;
class CAI_NamespaceInfos : public CUtlVector < AI_NamespaceAddInfo_t >
{
public :
void PushBack ( const char * pszName , int localId )
{
AddToTail ( AI_NamespaceAddInfo_t ( pszName , localId ) ) ;
}
void Sort ( )
{
CUtlVector < AI_NamespaceAddInfo_t > : : Sort ( Compare ) ;
}
private :
static int __cdecl Compare ( const AI_NamespaceAddInfo_t * pLeft , const AI_NamespaceAddInfo_t * pRight )
{
return pLeft - > localId - pRight - > localId ;
}
} ;
//-------------------------------------
// Declares the static variables that hold the string registry offset for the new subclass
// as well as the initialization in schedule load functions
struct AI_SchedLoadStatus_t
{
bool fValid ;
int signature ;
} ;
// Load schedules pulled out to support stepping through with debugger
inline bool AI_DoLoadSchedules ( bool ( * pfnBaseLoad ) ( ) , void ( * pfnInitCustomSchedules ) ( ) ,
AI_SchedLoadStatus_t * pLoadStatus )
{
( * pfnBaseLoad ) ( ) ;
if ( pLoadStatus - > signature ! = g_AI_SchedulesManager . GetScheduleLoadSignature ( ) )
{
( * pfnInitCustomSchedules ) ( ) ;
pLoadStatus - > fValid = true ;
pLoadStatus - > signature = g_AI_SchedulesManager . GetScheduleLoadSignature ( ) ;
}
return pLoadStatus - > fValid ;
}
//-------------------------------------
typedef bool ( * AIScheduleLoadFunc_t ) ( ) ;
// @Note (toml 02-16-03): The following class exists to allow us to establish an anonymous friendship
// in DEFINE_CUSTOM_SCHEDULE_PROVIDER. The particulars of this implementation is almost entirely
// defined by bugs in MSVC 6.0
class ScheduleLoadHelperImpl
{
public :
template < typename T >
static AIScheduleLoadFunc_t AccessScheduleLoadFunc ( T * )
{
return ( & T : : LoadSchedules ) ;
}
} ;
# define ScheduleLoadHelper( type ) (ScheduleLoadHelperImpl::AccessScheduleLoadFunc((type *)0))
//-------------------------------------
# define DEFINE_CUSTOM_SCHEDULE_PROVIDER\
static AI_SchedLoadStatus_t gm_SchedLoadStatus ; \
static CAI_ClassScheduleIdSpace gm_ClassScheduleIdSpace ; \
static const char * gm_pszErrorClassName ; \
\
static CAI_ClassScheduleIdSpace & AccessClassScheduleIdSpaceDirect ( ) { return gm_ClassScheduleIdSpace ; } \
virtual CAI_ClassScheduleIdSpace * GetClassScheduleIdSpace ( ) { return & gm_ClassScheduleIdSpace ; } \
virtual const char * GetSchedulingErrorName ( ) { return gm_pszErrorClassName ; } \
\
static void InitCustomSchedules ( void ) ; \
\
static bool LoadSchedules ( void ) ; \
virtual bool LoadedSchedules ( void ) ; \
\
friend class ScheduleLoadHelperImpl ; \
\
class CScheduleLoader \
{ \
public : \
CScheduleLoader ( ) ; \
} m_ScheduleLoader ; \
\
friend class CScheduleLoader ;
//-------------------------------------
# define DEFINE_CUSTOM_AI\
DEFINE_CUSTOM_SCHEDULE_PROVIDER \
\
static CAI_LocalIdSpace gm_SquadSlotIdSpace ; \
\
const char * SquadSlotName ( int squadSlotID ) ;
//-------------------------------------
# define IMPLEMENT_CUSTOM_SCHEDULE_PROVIDER(derivedClass)\
AI_SchedLoadStatus_t derivedClass : : gm_SchedLoadStatus = { true , - 1 } ; \
CAI_ClassScheduleIdSpace derivedClass : : gm_ClassScheduleIdSpace ; \
const char * derivedClass : : gm_pszErrorClassName = # derivedClass ; \
\
derivedClass : : CScheduleLoader : : CScheduleLoader ( ) \
{ \
derivedClass : : LoadSchedules ( ) ; \
} \
\
/* --------------------------------------------- */ \
/* Load schedules for this type of NPC */ \
/* --------------------------------------------- */ \
bool derivedClass : : LoadSchedules ( void ) \
{ \
return AI_DoLoadSchedules ( derivedClass : : BaseClass : : LoadSchedules , \
derivedClass : : InitCustomSchedules , \
& derivedClass : : gm_SchedLoadStatus ) ; \
} \
\
bool derivedClass : : LoadedSchedules ( void ) \
{ \
return derivedClass : : gm_SchedLoadStatus . fValid ; \
}
//-------------------------------------
// Initialize offsets and implement methods for loading and getting squad info for the subclass
# define IMPLEMENT_CUSTOM_AI(className, derivedClass)\
IMPLEMENT_CUSTOM_SCHEDULE_PROVIDER ( derivedClass ) \
\
CAI_LocalIdSpace derivedClass : : gm_SquadSlotIdSpace ; \
\
/* -------------------------------------------------- */ \
/* Given squadSlot enumeration return squadSlot name */ \
/* -------------------------------------------------- */ \
const char * derivedClass : : SquadSlotName ( int slotEN ) \
{ \
return gm_SquadSlotNamespace . IdToSymbol ( derivedClass : : gm_SquadSlotIdSpace . LocalToGlobal ( slotEN ) ) ; \
}
//-------------------------------------
# define ADD_CUSTOM_SCHEDULE_NAMED(derivedClass,schedName,schedEN)\
if ( ! derivedClass : : AccessClassScheduleIdSpaceDirect ( ) . AddSchedule ( schedName , schedEN , derivedClass : : gm_pszErrorClassName ) ) return ;
# define ADD_CUSTOM_SCHEDULE(derivedClass,schedEN) ADD_CUSTOM_SCHEDULE_NAMED(derivedClass,#schedEN,schedEN)
# define ADD_CUSTOM_TASK_NAMED(derivedClass,taskName,taskEN)\
if ( ! derivedClass : : AccessClassScheduleIdSpaceDirect ( ) . AddTask ( taskName , taskEN , derivedClass : : gm_pszErrorClassName ) ) return ;
# define ADD_CUSTOM_TASK(derivedClass,taskEN) ADD_CUSTOM_TASK_NAMED(derivedClass,#taskEN,taskEN)
# define ADD_CUSTOM_CONDITION_NAMED(derivedClass,condName,condEN)\
if ( ! derivedClass : : AccessClassScheduleIdSpaceDirect ( ) . AddCondition ( condName , condEN , derivedClass : : gm_pszErrorClassName ) ) return ;
# define ADD_CUSTOM_CONDITION(derivedClass,condEN) ADD_CUSTOM_CONDITION_NAMED(derivedClass,#condEN,condEN)
//-------------------------------------
# define INIT_CUSTOM_AI(derivedClass)\
derivedClass : : AccessClassScheduleIdSpaceDirect ( ) . Init ( # derivedClass , BaseClass : : GetSchedulingSymbols ( ) , & BaseClass : : AccessClassScheduleIdSpaceDirect ( ) ) ; \
derivedClass : : gm_SquadSlotIdSpace . Init ( & CAI_BaseNPC : : gm_SquadSlotNamespace , & BaseClass : : gm_SquadSlotIdSpace ) ;
# define ADD_CUSTOM_INTERACTION( interaction ) { interaction = CBaseCombatCharacter::GetInteractionID(); }
# define ADD_CUSTOM_SQUADSLOT_NAMED(derivedClass,squadSlotName,squadSlotEN)\
if ( ! derivedClass : : gm_SquadSlotIdSpace . AddSymbol ( squadSlotName , squadSlotEN , " squadslot " , derivedClass : : gm_pszErrorClassName ) ) return ;
# define ADD_CUSTOM_SQUADSLOT(derivedClass,squadSlotEN) ADD_CUSTOM_SQUADSLOT_NAMED(derivedClass,#squadSlotEN,squadSlotEN)
# define ADD_CUSTOM_ACTIVITY_NAMED(derivedClass,activityName,activityEnum)\
REGISTER_PRIVATE_ACTIVITY ( activityEnum ) ; \
CAI_BaseNPC : : AddActivityToSR ( activityName , activityEnum ) ;
# define ADD_CUSTOM_ACTIVITY(derivedClass,activityEnum) ADD_CUSTOM_ACTIVITY_NAMED(derivedClass,#activityEnum,activityEnum)
# define ADD_CUSTOM_ANIMEVENT_NAMED(derivedClass,eventName,eventEnum)\
REGISTER_PRIVATE_ANIMEVENT ( eventEnum ) ; \
CAI_BaseNPC : : AddEventToSR ( eventName , eventEnum ) ;
# define ADD_CUSTOM_ANIMEVENT(derivedClass,eventEnum) ADD_CUSTOM_ANIMEVENT_NAMED(derivedClass,#eventEnum,eventEnum)
//=============================================================================
// class CAI_Component
//=============================================================================
inline const Vector & CAI_Component : : GetLocalOrigin ( ) const
{
return GetOuter ( ) - > GetLocalOrigin ( ) ;
}
//-----------------------------------------------------------------------------
inline void CAI_Component : : SetLocalOrigin ( const Vector & origin )
{
GetOuter ( ) - > SetLocalOrigin ( origin ) ;
}
//-----------------------------------------------------------------------------
inline const Vector & CAI_Component : : GetAbsOrigin ( ) const
{
return GetOuter ( ) - > GetAbsOrigin ( ) ;
}
//-----------------------------------------------------------------------------
inline const QAngle & CAI_Component : : GetAbsAngles ( ) const
{
return GetOuter ( ) - > GetAbsAngles ( ) ;
}
//-----------------------------------------------------------------------------
inline void CAI_Component : : SetSolid ( SolidType_t val )
{
GetOuter ( ) - > SetSolid ( val ) ;
}
//-----------------------------------------------------------------------------
inline SolidType_t CAI_Component : : GetSolid ( ) const
{
return GetOuter ( ) - > GetSolid ( ) ;
}
//-----------------------------------------------------------------------------
inline const Vector & CAI_Component : : WorldAlignMins ( ) const
{
return GetOuter ( ) - > WorldAlignMins ( ) ;
}
//-----------------------------------------------------------------------------
inline const Vector & CAI_Component : : WorldAlignMaxs ( ) const
{
return GetOuter ( ) - > WorldAlignMaxs ( ) ;
}
//-----------------------------------------------------------------------------
inline Hull_t CAI_Component : : GetHullType ( ) const
{
return GetOuter ( ) - > GetHullType ( ) ;
}
//-----------------------------------------------------------------------------
inline Vector CAI_Component : : WorldSpaceCenter ( ) const
{
return GetOuter ( ) - > WorldSpaceCenter ( ) ;
}
//-----------------------------------------------------------------------------
inline float CAI_Component : : GetGravity ( ) const
{
return GetOuter ( ) - > GetGravity ( ) ;
}
//-----------------------------------------------------------------------------
inline void CAI_Component : : SetGravity ( float flGravity )
{
GetOuter ( ) - > SetGravity ( flGravity ) ;
}
//-----------------------------------------------------------------------------
inline float CAI_Component : : GetHullWidth ( ) const
{
return NAI_Hull : : Width ( GetOuter ( ) - > GetHullType ( ) ) ;
}
//-----------------------------------------------------------------------------
inline float CAI_Component : : GetHullHeight ( ) const
{
return NAI_Hull : : Height ( GetOuter ( ) - > GetHullType ( ) ) ;
}
//-----------------------------------------------------------------------------
inline const Vector & CAI_Component : : GetHullMins ( ) const
{
return NAI_Hull : : Mins ( GetOuter ( ) - > GetHullType ( ) ) ;
}
//-----------------------------------------------------------------------------
inline const Vector & CAI_Component : : GetHullMaxs ( ) const
{
return NAI_Hull : : Maxs ( GetOuter ( ) - > GetHullType ( ) ) ;
}
//-----------------------------------------------------------------------------
inline int CAI_Component : : GetCollisionGroup ( ) const
{
return GetOuter ( ) - > GetCollisionGroup ( ) ;
}
//-----------------------------------------------------------------------------
inline CBaseEntity * CAI_Component : : GetEnemy ( )
{
return GetOuter ( ) - > GetEnemy ( ) ;
}
//-----------------------------------------------------------------------------
inline const Vector & CAI_Component : : GetEnemyLKP ( ) const
{
return GetOuter ( ) - > GetEnemyLKP ( ) ;
}
//-----------------------------------------------------------------------------
inline void CAI_Component : : TranslateNavGoal ( CBaseEntity * pEnemy , Vector & chasePosition )
{
GetOuter ( ) - > TranslateNavGoal ( pEnemy , chasePosition ) ;
}
//-----------------------------------------------------------------------------
inline CBaseEntity * CAI_Component : : GetTarget ( )
{
return GetOuter ( ) - > GetTarget ( ) ;
}
//-----------------------------------------------------------------------------
inline void CAI_Component : : SetTarget ( CBaseEntity * pTarget )
{
GetOuter ( ) - > SetTarget ( pTarget ) ;
}
//-----------------------------------------------------------------------------
inline const Task_t * CAI_Component : : GetCurTask ( )
{
return GetOuter ( ) - > GetTask ( ) ;
}
//-----------------------------------------------------------------------------
inline void CAI_Component : : TaskFail ( AI_TaskFailureCode_t code )
{
GetOuter ( ) - > TaskFail ( code ) ;
}
//-----------------------------------------------------------------------------
inline void CAI_Component : : TaskFail ( const char * pszGeneralFailText )
{
GetOuter ( ) - > TaskFail ( pszGeneralFailText ) ;
}
//-----------------------------------------------------------------------------
inline void CAI_Component : : TaskComplete ( bool fIgnoreSetFailedCondition )
{
GetOuter ( ) - > TaskComplete ( fIgnoreSetFailedCondition ) ;
}
//-----------------------------------------------------------------------------
inline int CAI_Component : : TaskIsRunning ( )
{
return GetOuter ( ) - > TaskIsRunning ( ) ;
}
//-----------------------------------------------------------------------------
inline int CAI_Component : : TaskIsComplete ( )
{
return GetOuter ( ) - > TaskIsComplete ( ) ;
}
//-----------------------------------------------------------------------------
inline Activity CAI_Component : : GetActivity ( )
{
return GetOuter ( ) - > GetActivity ( ) ;
}
//-----------------------------------------------------------------------------
inline void CAI_Component : : SetActivity ( Activity NewActivity )
{
GetOuter ( ) - > SetActivity ( NewActivity ) ;
}
//-----------------------------------------------------------------------------
inline float CAI_Component : : GetIdealSpeed ( ) const
{
return GetOuter ( ) - > GetIdealSpeed ( ) ;
}
//-----------------------------------------------------------------------------
inline float CAI_Component : : GetIdealAccel ( ) const
{
return GetOuter ( ) - > GetIdealAccel ( ) ;
}
//-----------------------------------------------------------------------------
inline int CAI_Component : : GetSequence ( )
{
return GetOuter ( ) - > GetSequence ( ) ;
}
//-----------------------------------------------------------------------------
inline int CAI_Component : : GetEntFlags ( ) const
{
return GetOuter ( ) - > GetFlags ( ) ;
}
//-----------------------------------------------------------------------------
inline void CAI_Component : : AddEntFlag ( int flags )
{
GetOuter ( ) - > AddFlag ( flags ) ;
}
//-----------------------------------------------------------------------------
inline void CAI_Component : : RemoveEntFlag ( int flagsToRemove )
{
GetOuter ( ) - > RemoveFlag ( flagsToRemove ) ;
}
//-----------------------------------------------------------------------------
// Purpose: Change the ground entity for the outer
// Input : *ground -
// Output : inline void
//-----------------------------------------------------------------------------
inline void CAI_Component : : SetGroundEntity ( CBaseEntity * ground )
{
GetOuter ( ) - > SetGroundEntity ( ground ) ;
}
//-----------------------------------------------------------------------------
inline void CAI_Component : : ToggleEntFlag ( int flagToToggle )
{
GetOuter ( ) - > ToggleFlag ( flagToToggle ) ;
}
//-----------------------------------------------------------------------------
inline CBaseEntity * CAI_Component : : GetGoalEnt ( )
{
return GetOuter ( ) - > GetGoalEnt ( ) ;
}
//-----------------------------------------------------------------------------
inline void CAI_Component : : SetGoalEnt ( CBaseEntity * pGoalEnt )
{
GetOuter ( ) - > SetGoalEnt ( pGoalEnt ) ;
}
//-----------------------------------------------------------------------------
inline void CAI_Component : : Remember ( int iMemory )
{
GetOuter ( ) - > Remember ( iMemory ) ;
}
//-----------------------------------------------------------------------------
inline void CAI_Component : : Forget ( int iMemory )
{
GetOuter ( ) - > Forget ( iMemory ) ;
}
//-----------------------------------------------------------------------------
inline bool CAI_Component : : HasMemory ( int iMemory )
{
return GetOuter ( ) - > HasMemory ( iMemory ) ;
}
//-----------------------------------------------------------------------------
inline CAI_Enemies * CAI_Component : : GetEnemies ( )
{
return GetOuter ( ) - > GetEnemies ( ) ;
}
//-----------------------------------------------------------------------------
inline const char * CAI_Component : : GetEntClassname ( )
{
return GetOuter ( ) - > GetClassname ( ) ;
}
//-----------------------------------------------------------------------------
inline int CAI_Component : : CapabilitiesGet ( )
{
return GetOuter ( ) - > CapabilitiesGet ( ) ;
}
//-----------------------------------------------------------------------------
inline void CAI_Component : : SetLocalAngles ( const QAngle & angles )
{
GetOuter ( ) - > SetLocalAngles ( angles ) ;
}
//-----------------------------------------------------------------------------
inline const QAngle & CAI_Component : : GetLocalAngles ( void ) const
{
return GetOuter ( ) - > GetLocalAngles ( ) ;
}
//-----------------------------------------------------------------------------
inline edict_t * CAI_Component : : GetEdict ( )
{
return GetOuter ( ) - > NetworkProp ( ) - > edict ( ) ;
}
//-----------------------------------------------------------------------------
inline float CAI_Component : : GetLastThink ( const char * szContext )
{
return GetOuter ( ) - > GetLastThink ( szContext ) ;
}
// ============================================================================
abstract_class INPCInteractive
{
public :
virtual bool CanInteractWith ( CAI_BaseNPC * pUser ) = 0 ;
virtual bool HasBeenInteractedWith ( ) = 0 ;
virtual void NotifyInteraction ( CAI_BaseNPC * pUser ) = 0 ;
// Alyx specific interactions
virtual void AlyxStartedInteraction ( void ) = 0 ;
virtual void AlyxFinishedInteraction ( void ) = 0 ;
} ;
// Base Class for any NPC that wants to be interactable by other NPCS (i.e. Alyx Hackable)
// NOTE: YOU MUST DEFINE THE OUTPUTS IN YOUR CLASS'S DATADESC!
// THE DO SO, INSERT THE FOLLOWING MACRO INTO YOUR CLASS'S DATADESC.
//
# define DEFINE_BASENPCINTERACTABLE_DATADESC() \
DEFINE_OUTPUT ( m_OnAlyxStartedInteraction , " OnAlyxStartedInteraction " ) , \
DEFINE_OUTPUT ( m_OnAlyxFinishedInteraction , " OnAlyxFinishedInteraction " ) , \
DEFINE_INPUTFUNC ( FIELD_VOID , " InteractivePowerDown " , InputPowerdown )
template < class NPC_CLASS >
class CNPCBaseInteractive : public NPC_CLASS , public INPCInteractive
{
DECLARE_CLASS ( CNPCBaseInteractive , NPC_CLASS ) ;
public :
virtual bool CanInteractWith ( CAI_BaseNPC * pUser ) { return false ; } ;
virtual bool HasBeenInteractedWith ( ) { return false ; } ;
virtual void NotifyInteraction ( CAI_BaseNPC * pUser ) { return ; } ;
virtual void InputPowerdown ( inputdata_t & inputdata )
{
}
// Alyx specific interactions
virtual void AlyxStartedInteraction ( void )
{
m_OnAlyxStartedInteraction . FireOutput ( this , this ) ;
}
virtual void AlyxFinishedInteraction ( void )
{
m_OnAlyxFinishedInteraction . FireOutput ( this , this ) ;
}
public :
// Outputs
// Alyx specific interactions
COutputEvent m_OnAlyxStartedInteraction ;
COutputEvent m_OnAlyxFinishedInteraction ;
} ;
//
// Deferred Navigation calls go here
//
extern ConVar ai_post_frame_navigation ;
class CPostFrameNavigationHook : public CBaseGameSystemPerFrame
{
public :
virtual const char * Name ( void ) { return " CPostFrameNavigationHook " ; }
virtual bool Init ( void ) ;
virtual void FrameUpdatePostEntityThink ( void ) ;
virtual void FrameUpdatePreEntityThink ( void ) ;
bool IsGameFrameRunning ( void ) { return m_bGameFrameRunning ; }
void SetGrameFrameRunning ( bool bState ) { m_bGameFrameRunning = bState ; }
void EnqueueEntityNavigationQuery ( CAI_BaseNPC * pNPC , CFunctor * functor ) ;
private :
CUtlVector < CFunctor * > m_Functors ;
bool m_bGameFrameRunning ;
} ;
extern CPostFrameNavigationHook * PostFrameNavigationSystem ( void ) ;
# endif // AI_BASENPC_H