2023-10-03 14:23:56 +00:00
//========= Copyright <20> 1996-2005, Valve Corporation, All rights reserved. ============//
2020-04-22 16:56:21 +00:00
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
# ifndef AI_BEHAVIOR_H
# define AI_BEHAVIOR_H
# include "ai_component.h"
# include "ai_basenpc.h"
# include "ai_default.h"
# include "AI_Criteria.h"
# include "networkvar.h"
2023-10-03 14:23:56 +00:00
# include "delegates.h"
# include "tier1/utlvector.h"
# include "generic_classmap.h"
2020-04-22 16:56:21 +00:00
# ifdef DEBUG
# pragma warning(push)
# include <typeinfo>
# pragma warning(pop)
# pragma warning(disable:4290)
# endif
# if defined( _WIN32 )
# pragma once
# endif
//-----------------------------------------------------------------------------
// CAI_Behavior...
//
// Purpose: The core component that defines a behavior in an NPC by selecting
// schedules and running tasks
//
// Intended to be used as an organizational tool as well as a way
// for various NPCs to share behaviors without sharing an inheritance
// relationship, and without cramming those behaviors into the base
// NPC class.
//-----------------------------------------------------------------------------
2023-10-03 14:23:56 +00:00
struct AIChannelScheduleState_t
{
AIChannelScheduleState_t ( ) { memset ( this , 0 , sizeof ( * this ) ) ; }
bool bActive ;
CAI_Schedule * pSchedule ;
int idealSchedule ;
int failSchedule ;
int iCurTask ;
TaskStatus_e fTaskStatus ;
float timeStarted ;
float timeCurTaskStarted ;
AI_TaskFailureCode_t taskFailureCode ;
bool bScheduleWasInterrupted ;
DECLARE_SIMPLE_DATADESC ( ) ;
} ;
2020-04-22 16:56:21 +00:00
//-----------------------------------------------------------------------------
// Purpose: Base class defines interface to behaviors and provides bridging
// methods
//-----------------------------------------------------------------------------
2023-10-03 14:23:56 +00:00
class CAI_BehaviorBase : public CAI_Component , public IAI_BehaviorBridge
2020-04-22 16:56:21 +00:00
{
DECLARE_CLASS ( CAI_BehaviorBase , CAI_Component )
public :
CAI_BehaviorBase ( CAI_BaseNPC * pOuter = NULL )
: CAI_Component ( pOuter ) ,
m_pBackBridge ( NULL )
{
2023-10-03 14:23:56 +00:00
m_bAllocated = false ;
2020-04-22 16:56:21 +00:00
}
2023-10-03 14:23:56 +00:00
void SetAllocated ( ) { m_bAllocated = true ; }
bool IsAllocated ( ) { return m_bAllocated ; }
# define AI_GENERATE_BEHAVIOR_BRIDGES
# include "ai_behavior_template.h"
# define AI_GENERATE_BASE_METHODS
# include "ai_behavior_template.h"
virtual const char * GetClassNameV ( ) { return " " ; }
2020-04-22 16:56:21 +00:00
virtual const char * GetName ( ) = 0 ;
2023-10-03 14:23:56 +00:00
virtual bool DeleteOnHostDestroy ( ) { return m_bAllocated ; } // @QUESTION: should switch to reference count?
2020-04-22 16:56:21 +00:00
virtual bool KeyValue ( const char * szKeyName , const char * szValue )
{
return false ;
}
2023-10-03 14:23:56 +00:00
bool IsRunning ( ) { Assert ( GetOuter ( ) ) ; return ( GetOuter ( ) - > GetPrimaryBehavior ( ) = = this ) ; }
2020-04-22 16:56:21 +00:00
virtual bool CanSelectSchedule ( ) { return true ; }
virtual void BeginScheduleSelection ( ) { }
virtual void EndScheduleSelection ( ) { }
2023-10-03 14:23:56 +00:00
void SetBackBridge ( IAI_BehaviorBridge * pBackBridge )
2020-04-22 16:56:21 +00:00
{
Assert ( m_pBackBridge = = NULL | | pBackBridge = = NULL ) ;
m_pBackBridge = pBackBridge ;
}
2023-10-03 14:23:56 +00:00
virtual void Precache ( ) { }
virtual void Spawn ( ) { }
virtual void UpdateOnRemove ( ) { }
virtual void Event_Killed ( const CTakeDamageInfo & info ) { }
virtual void CleanupOnDeath ( CBaseEntity * pCulprit , bool bFireDeathOutput ) { }
2020-04-22 16:56:21 +00:00
2023-10-03 14:23:56 +00:00
virtual void OnChangeHintGroup ( string_t oldGroup , string_t newGroup ) { }
2020-04-22 16:56:21 +00:00
void BridgeOnStartSchedule ( int scheduleType ) ;
int BridgeSelectSchedule ( ) ;
bool BridgeSelectFailSchedule ( int failedSchedule , int failedTask , AI_TaskFailureCode_t taskFailCode , int * pResult ) ;
bool BridgeStartTask ( const Task_t * pTask ) ;
bool BridgeRunTask ( const Task_t * pTask ) ;
2023-10-03 14:23:56 +00:00
2020-04-22 16:56:21 +00:00
int BridgeTranslateSchedule ( int scheduleType ) ;
bool BridgeGetSchedule ( int localScheduleID , CAI_Schedule * * ppResult ) ;
bool BridgeTaskName ( int taskID , const char * * ) ;
2023-10-03 14:23:56 +00:00
virtual void BuildScheduleTestBits ( ) { }
virtual void BuildScheduleTestBitsNotActive ( ) { }
2020-04-22 16:56:21 +00:00
virtual void GatherConditions ( ) ;
virtual void GatherConditionsNotActive ( ) { return ; } // Override this and your behavior will call this in place of GatherConditions() when your behavior is NOT the active one.
virtual void OnUpdateShotRegulator ( ) { }
2023-10-03 14:23:56 +00:00
virtual float GetJumpGravity ( ) const ;
virtual bool IsJumpLegal ( const Vector & startPos , const Vector & apex , const Vector & endPos , float maxUp , float maxDown , float maxDist ) const ;
virtual bool MovementCost ( int moveType , const Vector & vecStart , const Vector & vecEnd , float * pCost ) ;
virtual void OnChangeActiveWeapon ( CBaseCombatWeapon * pOldWeapon , CBaseCombatWeapon * pNewWeapon ) { } ;
2020-04-22 16:56:21 +00:00
virtual CAI_ClassScheduleIdSpace * GetClassScheduleIdSpace ( ) ;
virtual int DrawDebugTextOverlays ( int text_offset ) ;
2023-10-03 14:23:56 +00:00
virtual bool ShouldNPCSave ( ) { return true ; }
2020-04-22 16:56:21 +00:00
virtual int Save ( ISave & save ) ;
virtual int Restore ( IRestore & restore ) ;
2023-10-03 14:23:56 +00:00
virtual void OnRestore ( ) { }
2020-04-22 16:56:21 +00:00
2023-10-03 14:23:56 +00:00
static void SaveBehaviors ( ISave & save , CAI_BehaviorBase * pCurrentBehavior , CAI_BehaviorBase * * ppBehavior , int nBehaviors , bool bTestIfNPCSave = true ) ;
static int RestoreBehaviors ( IRestore & restore , CAI_BehaviorBase * * ppBehavior , int nBehaviors , bool bTestIfNPCSave = true ) ; // returns index of "current" behavior, or -1
2020-04-22 16:56:21 +00:00
2023-10-03 14:23:56 +00:00
public :
//
// Secondary schedule channel support
//
void StartChannel ( int channel ) ;
void StopChannel ( int channel ) ;
void MaintainChannelSchedules ( ) ;
void MaintainSchedule ( int channel ) ;
void SetSchedule ( int channel , CAI_Schedule * pNewSchedule ) ;
bool SetSchedule ( int channel , int localScheduleID ) ;
void ClearSchedule ( int channel , const char * szReason ) ;
2020-04-22 16:56:21 +00:00
2023-10-03 14:23:56 +00:00
CAI_Schedule * GetCurSchedule ( int channel ) ;
bool IsCurSchedule ( int channel , int schedId , bool fIdeal = true ) ;
virtual void OnScheduleChange ( int channel ) ;
virtual void OnStartSchedule ( int channel , int scheduleType ) ;
virtual int SelectSchedule ( int channel ) ;
virtual int SelectFailSchedule ( int channel , int failedSchedule , int failedTask , AI_TaskFailureCode_t taskFailCode ) ;
virtual int TranslateSchedule ( int channel , int scheduleType ) { return scheduleType ; }
virtual void StartTask ( int channel , const Task_t * pTask ) ;
virtual void RunTask ( int channel , const Task_t * pTask ) ;
const Task_t * GetCurTask ( void ) { return BaseClass : : GetCurTask ( ) ; }
const Task_t * GetCurTask ( int channel ) ;
bool TaskIsComplete ( int channel ) { return ( m_ScheduleChannels [ channel ] . fTaskStatus = = TASKSTATUS_COMPLETE ) ; }
int TaskIsComplete ( ) { return BaseClass : : TaskIsComplete ( ) ; }
virtual void TaskFail ( AI_TaskFailureCode_t code ) { BaseClass : : TaskFail ( code ) ; }
void TaskFail ( const char * pszGeneralFailText ) { BaseClass : : TaskFail ( pszGeneralFailText ) ; }
void TaskComplete ( bool fIgnoreSetFailedCondition = false ) { BaseClass : : TaskComplete ( fIgnoreSetFailedCondition ) ; }
virtual void TaskFail ( int channel , AI_TaskFailureCode_t code ) ;
void TaskFail ( int channel , const char * pszGeneralFailText ) { TaskFail ( channel , MakeFailCode ( pszGeneralFailText ) ) ; }
void TaskComplete ( int channel , bool fIgnoreSetFailedCondition = false ) ;
private :
bool IsScheduleValid ( AIChannelScheduleState_t * pScheduleState ) ;
CAI_Schedule * GetNewSchedule ( int channel ) ;
CAI_Schedule * GetFailSchedule ( AIChannelScheduleState_t * pScheduleState ) ;
const Task_t * GetTask ( AIChannelScheduleState_t * pScheduleState ) ;
void SaveChannels ( ISave & save ) ;
void RestoreChannels ( IRestore & restore ) ;
CUtlVector < AIChannelScheduleState_t > m_ScheduleChannels ;
protected :
2020-04-22 16:56:21 +00:00
int GetNpcState ( ) { return GetOuter ( ) - > m_NPCState ; }
virtual void OnStartSchedule ( int scheduleType ) ;
virtual int SelectSchedule ( ) ;
virtual int SelectFailSchedule ( int failedSchedule , int failedTask , AI_TaskFailureCode_t taskFailCode ) ;
virtual void StartTask ( const Task_t * pTask ) ;
virtual void RunTask ( const Task_t * pTask ) ;
virtual int TranslateSchedule ( int scheduleType ) ;
virtual CAI_Schedule * GetSchedule ( int schedule ) ;
virtual const char * GetSchedulingErrorName ( ) ;
bool IsCurSchedule ( int schedId , bool fIdeal = true ) ;
CAI_Hint * GetHintNode ( ) { return GetOuter ( ) - > GetHintNode ( ) ; }
const CAI_Hint * GetHintNode ( ) const { return GetOuter ( ) - > GetHintNode ( ) ; }
void SetHintNode ( CAI_Hint * pHintNode ) { GetOuter ( ) - > SetHintNode ( pHintNode ) ; }
void ClearHintNode ( float reuseDelay = 0.0 ) { GetOuter ( ) - > ClearHintNode ( reuseDelay ) ; }
2023-10-03 14:23:56 +00:00
string_t GetHintGroup ( ) { return GetOuter ( ) - > GetHintGroup ( ) ; }
void ClearHintGroup ( ) { GetOuter ( ) - > ClearHintGroup ( ) ; }
void SetHintGroup ( string_t name ) { GetOuter ( ) - > SetHintGroup ( name ) ; }
// For now, only support simple behavior stack:
DELEGATE_TO_OBJECT_0V ( BehaviorBridge_GatherConditions , m_pBackBridge ) ;
DELEGATE_TO_OBJECT_0 ( int , BehaviorBridge_SelectSchedule , m_pBackBridge ) ;
DELEGATE_TO_OBJECT_1 ( int , BehaviorBridge_TranslateSchedule , int , m_pBackBridge ) ;
2020-04-22 16:56:21 +00:00
protected :
// Used by derived classes to chain a task to a task that might not be the
// one they are currently handling:
void ChainStartTask ( int task , float taskData = 0 ) ;
void ChainRunTask ( int task , float taskData = 0 ) ;
protected :
2023-10-03 14:23:56 +00:00
2020-04-22 16:56:21 +00:00
bool NotifyChangeBehaviorStatus ( bool fCanFinishSchedule = false ) ;
bool HaveSequenceForActivity ( Activity activity ) { return GetOuter ( ) - > HaveSequenceForActivity ( activity ) ; }
//---------------------------------
//
// These allow derived classes to implement custom schedules
//
static CAI_GlobalScheduleNamespace * GetSchedulingSymbols ( ) { return CAI_BaseNPC : : GetSchedulingSymbols ( ) ; }
static bool LoadSchedules ( ) { return true ; }
virtual bool IsBehaviorSchedule ( int scheduleType ) { return false ; }
CAI_Navigator * GetNavigator ( ) { return GetOuter ( ) - > GetNavigator ( ) ; }
CAI_Motor * GetMotor ( ) { return GetOuter ( ) - > GetMotor ( ) ; }
CAI_TacticalServices * GetTacticalServices ( ) { return GetOuter ( ) - > GetTacticalServices ( ) ; }
bool m_fOverrode ;
2023-10-03 14:23:56 +00:00
IAI_BehaviorBridge * m_pBackBridge ;
bool m_bAllocated ;
public :
static CGenericClassmap < CAI_BehaviorBase > m_BehaviorClasses ;
2020-04-22 16:56:21 +00:00
2023-10-03 14:23:56 +00:00
private :
2020-04-22 16:56:21 +00:00
DECLARE_DATADESC ( ) ;
} ;
2023-10-03 14:23:56 +00:00
# define LINK_BEHAVIOR_TO_CLASS( localName, className ) \
static CAI_BehaviorBase * C # # className # # Factory ( void ) \
{ \
return static_cast < CAI_BehaviorBase * > ( new className ) ; \
} ; \
class C # # localName # # Foo \
{ \
public : \
C # # localName # # Foo ( void ) \
{ \
CAI_BehaviorBase : : m_BehaviorClasses . Add ( # localName , # className , \
sizeof ( className ) , & C # # className # # Factory ) ; \
} \
} ; \
static C # # localName # # Foo g_C # # localName # # Foo ;
# define LINK_BEHAVIOR_TO_CLASSNAME( className ) \
static CAI_BehaviorBase * C # # className # # Factory ( void ) \
{ \
return static_cast < CAI_BehaviorBase * > ( new className ) ; \
} ; \
class C # # className # # Foo \
{ \
public : \
C # # className # # Foo ( void ) \
{ \
CAI_BehaviorBase : : m_BehaviorClasses . Add ( # # className : : GetClassName ( ) , # className , \
sizeof ( className ) , & C # # className # # Factory ) ; \
} \
} ; \
static C # # className # # Foo g_C # # className # # Foo ;
2020-04-22 16:56:21 +00:00
//-----------------------------------------------------------------------------
// Purpose: Template provides provides back bridge to owning class and
// establishes namespace settings
//-----------------------------------------------------------------------------
template < class NPC_CLASS = CAI_BaseNPC , const int ID_SPACE_OFFSET = 100000 >
class CAI_Behavior : public CAI_ComponentWithOuter < NPC_CLASS , CAI_BehaviorBase >
{
public :
DECLARE_CLASS_NOFRIEND ( CAI_Behavior , NPC_CLASS ) ;
enum
{
NEXT_TASK = ID_SPACE_OFFSET ,
NEXT_SCHEDULE = ID_SPACE_OFFSET ,
2023-10-03 14:23:56 +00:00
NEXT_CONDITION = ID_SPACE_OFFSET ,
NEXT_CHANNEL = ID_SPACE_OFFSET ,
2020-04-22 16:56:21 +00:00
} ;
void SetCondition ( int condition )
{
if ( condition > = ID_SPACE_OFFSET & & condition < ID_SPACE_OFFSET + 10000 ) // it's local to us
condition = GetClassScheduleIdSpace ( ) - > ConditionLocalToGlobal ( condition ) ;
this - > GetOuter ( ) - > SetCondition ( condition ) ;
}
bool HasCondition ( int condition )
{
if ( condition > = ID_SPACE_OFFSET & & condition < ID_SPACE_OFFSET + 10000 ) // it's local to us
condition = GetClassScheduleIdSpace ( ) - > ConditionLocalToGlobal ( condition ) ;
return this - > GetOuter ( ) - > HasCondition ( condition ) ;
}
bool HasInterruptCondition ( int condition )
{
if ( condition > = ID_SPACE_OFFSET & & condition < ID_SPACE_OFFSET + 10000 ) // it's local to us
condition = GetClassScheduleIdSpace ( ) - > ConditionLocalToGlobal ( condition ) ;
return this - > GetOuter ( ) - > HasInterruptCondition ( condition ) ;
}
void ClearCondition ( int condition )
{
if ( condition > = ID_SPACE_OFFSET & & condition < ID_SPACE_OFFSET + 10000 ) // it's local to us
condition = GetClassScheduleIdSpace ( ) - > ConditionLocalToGlobal ( condition ) ;
this - > GetOuter ( ) - > ClearCondition ( condition ) ;
}
protected :
CAI_Behavior ( NPC_CLASS * pOuter = NULL )
: CAI_ComponentWithOuter < NPC_CLASS , CAI_BehaviorBase > ( pOuter )
{
}
static CAI_GlobalScheduleNamespace * GetSchedulingSymbols ( )
{
return NPC_CLASS : : GetSchedulingSymbols ( ) ;
}
virtual CAI_ClassScheduleIdSpace * GetClassScheduleIdSpace ( )
{
return this - > GetOuter ( ) - > GetClassScheduleIdSpace ( ) ;
}
static CAI_ClassScheduleIdSpace & AccessClassScheduleIdSpaceDirect ( )
{
return NPC_CLASS : : AccessClassScheduleIdSpaceDirect ( ) ;
}
private :
virtual bool IsBehaviorSchedule ( int scheduleType ) { return ( scheduleType > = ID_SPACE_OFFSET & & scheduleType < ID_SPACE_OFFSET + 10000 ) ; }
} ;
//-----------------------------------------------------------------------------
// Purpose: The common instantiation of the above template
//-----------------------------------------------------------------------------
typedef CAI_Behavior < > CAI_SimpleBehavior ;
//-----------------------------------------------------------------------------
// Purpose: Base class for AIs that want to act as a host for CAI_Behaviors
// NPCs aren't required to use this, but probably want to.
//-----------------------------------------------------------------------------
template < class BASE_NPC >
2023-10-03 14:23:56 +00:00
class CAI_BehaviorHostBase : public BASE_NPC
{
DECLARE_CLASS ( CAI_BehaviorHostBase , BASE_NPC ) ;
protected :
CAI_BehaviorHostBase ( )
{
}
} ;
template < class BASE_NPC >
class CAI_BehaviorHost : public CAI_BehaviorHostBase < BASE_NPC >
2020-04-22 16:56:21 +00:00
{
2023-10-03 14:23:56 +00:00
DECLARE_CLASS ( CAI_BehaviorHost , CAI_BehaviorHostBase < BASE_NPC > ) ;
2020-04-22 16:56:21 +00:00
public :
CAI_BehaviorHost ( )
{
}
2023-10-03 14:23:56 +00:00
# define AI_GENERATE_BRIDGES
# include "ai_behavior_template.h"
# define AI_GENERATE_HOST_METHODS
# include "ai_behavior_template.h"
2020-04-22 16:56:21 +00:00
void CleanupOnDeath ( CBaseEntity * pCulprit = NULL , bool bFireDeathOutput = true ) ;
virtual int Save ( ISave & save ) ;
virtual int Restore ( IRestore & restore ) ;
// Bridges
void Precache ( ) ;
void UpdateOnRemove ( ) ;
void Event_Killed ( const CTakeDamageInfo & info ) ;
void GatherConditions ( ) ;
int SelectSchedule ( ) ;
void KeepRunningBehavior ( ) ;
int SelectFailSchedule ( int failedSchedule , int failedTask , AI_TaskFailureCode_t taskFailCode ) ;
void OnStartSchedule ( int scheduleType ) ;
int TranslateSchedule ( int scheduleType ) ;
void StartTask ( const Task_t * pTask ) ;
void RunTask ( const Task_t * pTask ) ;
CAI_Schedule * GetSchedule ( int localScheduleID ) ;
const char * TaskName ( int taskID ) ;
void BuildScheduleTestBits ( ) ;
2023-10-03 14:23:56 +00:00
void BuildScheduleTestBitsNotActive ( ) ;
2020-04-22 16:56:21 +00:00
void OnChangeHintGroup ( string_t oldGroup , string_t newGroup ) ;
void OnChangeActiveWeapon ( CBaseCombatWeapon * pOldWeapon , CBaseCombatWeapon * pNewWeapon ) ;
void OnRestore ( ) ;
2023-10-03 14:23:56 +00:00
float GetJumpGravity ( ) const ;
bool IsJumpLegal ( const Vector & startPos , const Vector & apex , const Vector & endPos , float maxUp , float maxDown , float maxDist ) const ;
bool MovementCost ( int moveType , const Vector & vecStart , const Vector & vecEnd , float * pCost ) ;
2020-04-22 16:56:21 +00:00
//---------------------------------
protected :
CAI_Schedule * GetNewSchedule ( ) ;
CAI_Schedule * GetFailSchedule ( ) ;
private :
2023-10-03 14:23:56 +00:00
void BehaviorBridge_GatherConditions ( ) ;
int BehaviorBridge_SelectSchedule ( ) ;
int BehaviorBridge_TranslateSchedule ( int scheduleType ) ;
float BehaviorBridge_GetJumpGravity ( ) const ;
bool BehaviorBridge_IsJumpLegal ( const Vector & startPos , const Vector & apex , const Vector & endPos , float maxUp , float maxDown , float maxDist ) const ;
bool BehaviorBridge_MovementCost ( int moveType , const Vector & vecStart , const Vector & vecEnd , float * pCost ) ;
2020-04-22 16:56:21 +00:00
bool m_bCalledBehaviorSelectSchedule ;
} ;
//-----------------------------------------------------------------------------
// The first frame a behavior begins schedule selection, it won't have had it's GatherConditions()
// called. To fix this, BeginScheduleSelection() manually calls the new behavior's GatherConditions(),
// but sets this global so that the baseclass GatherConditions() isn't called as well.
extern bool g_bBehaviorHost_PreventBaseClassGatherConditions ;
//-----------------------------------------------------------------------------
inline void CAI_BehaviorBase : : BridgeOnStartSchedule ( int scheduleType )
{
int localId = AI_IdIsGlobal ( scheduleType ) ? GetClassScheduleIdSpace ( ) - > ScheduleGlobalToLocal ( scheduleType ) : scheduleType ;
OnStartSchedule ( localId ) ;
}
//-------------------------------------
inline int CAI_BehaviorBase : : BridgeSelectSchedule ( )
{
int result = SelectSchedule ( ) ;
if ( IsBehaviorSchedule ( result ) )
return GetClassScheduleIdSpace ( ) - > ScheduleLocalToGlobal ( result ) ;
return result ;
}
//-------------------------------------
inline bool CAI_BehaviorBase : : BridgeSelectFailSchedule ( int failedSchedule , int failedTask , AI_TaskFailureCode_t taskFailCode , int * pResult )
{
m_fOverrode = true ;
int result = SelectFailSchedule ( failedSchedule , failedTask , taskFailCode ) ;
if ( m_fOverrode )
{
if ( result ! = SCHED_NONE )
{
if ( IsBehaviorSchedule ( result ) )
* pResult = GetClassScheduleIdSpace ( ) - > ScheduleLocalToGlobal ( result ) ;
else
* pResult = result ;
return true ;
}
Warning ( " An AI behavior is in control but has no recommended schedule \n " ) ;
}
return false ;
}
//-------------------------------------
inline bool CAI_BehaviorBase : : BridgeStartTask ( const Task_t * pTask )
{
m_fOverrode = true ;
StartTask ( pTask ) ;
return m_fOverrode ;
}
//-------------------------------------
inline bool CAI_BehaviorBase : : BridgeRunTask ( const Task_t * pTask )
{
m_fOverrode = true ;
RunTask ( pTask ) ;
return m_fOverrode ;
}
//-------------------------------------
inline void CAI_BehaviorBase : : ChainStartTask ( int task , float taskData )
{
Task_t tempTask = { task , taskData } ;
bool fPrevOverride = m_fOverrode ;
2023-10-03 14:23:56 +00:00
this - > GetOuter ( ) - > StartTask ( ( const Task_t * ) & tempTask ) ;
2020-04-22 16:56:21 +00:00
m_fOverrode = fPrevOverride ; ;
}
//-------------------------------------
inline void CAI_BehaviorBase : : ChainRunTask ( int task , float taskData )
{
Task_t tempTask = { task , taskData } ;
bool fPrevOverride = m_fOverrode ;
2023-10-03 14:23:56 +00:00
this - > GetOuter ( ) - > RunTask ( ( const Task_t * ) & tempTask ) ;
2020-04-22 16:56:21 +00:00
m_fOverrode = fPrevOverride ; ;
}
//-------------------------------------
inline int CAI_BehaviorBase : : BridgeTranslateSchedule ( int scheduleType )
{
int localId = AI_IdIsGlobal ( scheduleType ) ? GetClassScheduleIdSpace ( ) - > ScheduleGlobalToLocal ( scheduleType ) : scheduleType ;
int result = TranslateSchedule ( localId ) ;
return result ;
}
//-------------------------------------
inline bool CAI_BehaviorBase : : BridgeGetSchedule ( int localScheduleID , CAI_Schedule * * ppResult )
{
* ppResult = GetSchedule ( localScheduleID ) ;
return ( * ppResult ! = NULL ) ;
}
//-------------------------------------
inline bool CAI_BehaviorBase : : BridgeTaskName ( int taskID , const char * * ppResult )
{
if ( AI_IdIsLocal ( taskID ) )
{
* ppResult = GetSchedulingSymbols ( ) - > TaskIdToSymbol ( GetClassScheduleIdSpace ( ) - > TaskLocalToGlobal ( taskID ) ) ;
return ( * ppResult ! = NULL ) ;
}
return false ;
}
2023-10-03 14:23:56 +00:00
//-----------------------------------------------------------------------------
2020-04-22 16:56:21 +00:00
2023-10-03 14:23:56 +00:00
template < class BASE_NPC >
inline void CAI_BehaviorHost < BASE_NPC > : : CleanupOnDeath ( CBaseEntity * pCulprit , bool bFireDeathOutput )
2020-04-22 16:56:21 +00:00
{
2023-10-03 14:23:56 +00:00
this - > DeferSchedulingToBehavior ( NULL ) ;
for ( int i = 0 ; i < this - > m_Behaviors . Count ( ) ; i + + )
{
this - > m_Behaviors [ i ] - > CleanupOnDeath ( pCulprit , bFireDeathOutput ) ;
}
BaseClass : : CleanupOnDeath ( pCulprit , bFireDeathOutput ) ;
2020-04-22 16:56:21 +00:00
}
//-------------------------------------
2023-10-03 14:23:56 +00:00
template < class BASE_NPC >
inline void CAI_BehaviorHost < BASE_NPC > : : GatherConditions ( )
{
// Iterate over behaviors and call GatherConditionsNotActive() on each behavior
// not currently active.
for ( int i = 0 ; i < this - > m_Behaviors . Count ( ) ; i + + )
{
if ( this - > m_Behaviors [ i ] ! = this - > m_pPrimaryBehavior )
{
this - > m_Behaviors [ i ] - > GatherConditionsNotActive ( ) ;
}
}
if ( this - > m_pPrimaryBehavior )
this - > m_pPrimaryBehavior - > GatherConditions ( ) ;
else
BaseClass : : GatherConditions ( ) ;
2020-04-22 16:56:21 +00:00
}
//-------------------------------------
2023-10-03 14:23:56 +00:00
template < class BASE_NPC >
inline void CAI_BehaviorHost < BASE_NPC > : : BehaviorBridge_GatherConditions ( )
2020-04-22 16:56:21 +00:00
{
2023-10-03 14:23:56 +00:00
if ( g_bBehaviorHost_PreventBaseClassGatherConditions )
return ;
BaseClass : : GatherConditions ( ) ;
2020-04-22 16:56:21 +00:00
}
//-------------------------------------
2023-10-03 14:23:56 +00:00
template < class BASE_NPC >
inline void CAI_BehaviorHost < BASE_NPC > : : OnStartSchedule ( int scheduleType )
2020-04-22 16:56:21 +00:00
{
2023-10-03 14:23:56 +00:00
if ( this - > m_pPrimaryBehavior )
this - > m_pPrimaryBehavior - > BridgeOnStartSchedule ( scheduleType ) ;
BaseClass : : OnStartSchedule ( scheduleType ) ;
2020-04-22 16:56:21 +00:00
}
//-------------------------------------
2023-10-03 14:23:56 +00:00
template < class BASE_NPC >
inline int CAI_BehaviorHost < BASE_NPC > : : BehaviorBridge_SelectSchedule ( )
2020-04-22 16:56:21 +00:00
{
2023-10-03 14:23:56 +00:00
return BaseClass : : SelectSchedule ( ) ;
2020-04-22 16:56:21 +00:00
}
//-------------------------------------
2023-10-03 14:23:56 +00:00
template < class BASE_NPC >
inline CAI_Schedule * CAI_BehaviorHost < BASE_NPC > : : GetNewSchedule ( )
2020-04-22 16:56:21 +00:00
{
2023-10-03 14:23:56 +00:00
m_bCalledBehaviorSelectSchedule = false ;
CAI_Schedule * pResult = BaseClass : : GetNewSchedule ( ) ;
if ( ! m_bCalledBehaviorSelectSchedule & & this - > m_pPrimaryBehavior )
this - > DeferSchedulingToBehavior ( NULL ) ;
return pResult ;
2020-04-22 16:56:21 +00:00
}
//-------------------------------------
2023-10-03 14:23:56 +00:00
template < class BASE_NPC >
inline CAI_Schedule * CAI_BehaviorHost < BASE_NPC > : : GetFailSchedule ( )
2020-04-22 16:56:21 +00:00
{
2023-10-03 14:23:56 +00:00
m_bCalledBehaviorSelectSchedule = false ;
CAI_Schedule * pResult = BaseClass : : GetFailSchedule ( ) ;
if ( ! m_bCalledBehaviorSelectSchedule & & this - > m_pPrimaryBehavior )
this - > DeferSchedulingToBehavior ( NULL ) ;
return pResult ;
2020-04-22 16:56:21 +00:00
}
//-------------------------------------
2023-10-03 14:23:56 +00:00
template < class BASE_NPC >
inline int CAI_BehaviorHost < BASE_NPC > : : BehaviorBridge_TranslateSchedule ( int scheduleType )
2020-04-22 16:56:21 +00:00
{
2023-10-03 14:23:56 +00:00
return BaseClass : : TranslateSchedule ( scheduleType ) ;
2020-04-22 16:56:21 +00:00
}
//-------------------------------------
2023-10-03 14:23:56 +00:00
template < class BASE_NPC >
inline int CAI_BehaviorHost < BASE_NPC > : : TranslateSchedule ( int scheduleType )
2020-04-22 16:56:21 +00:00
{
2023-10-03 14:23:56 +00:00
if ( this - > m_pPrimaryBehavior )
{
return this - > m_pPrimaryBehavior - > BridgeTranslateSchedule ( scheduleType ) ;
}
return BaseClass : : TranslateSchedule ( scheduleType ) ;
2020-04-22 16:56:21 +00:00
}
//-------------------------------------
2023-10-03 14:23:56 +00:00
template < class BASE_NPC >
inline int CAI_BehaviorHost < BASE_NPC > : : SelectSchedule ( )
2020-04-22 16:56:21 +00:00
{
2023-10-03 14:23:56 +00:00
m_bCalledBehaviorSelectSchedule = true ;
if ( this - > m_pPrimaryBehavior )
{
return this - > m_pPrimaryBehavior - > BridgeSelectSchedule ( ) ;
}
return BaseClass : : SelectSchedule ( ) ;
2020-04-22 16:56:21 +00:00
}
//-------------------------------------
2023-10-03 14:23:56 +00:00
template < class BASE_NPC >
inline void CAI_BehaviorHost < BASE_NPC > : : KeepRunningBehavior ( )
2020-04-22 16:56:21 +00:00
{
2023-10-03 14:23:56 +00:00
if ( this - > m_pPrimaryBehavior )
m_bCalledBehaviorSelectSchedule = true ;
2020-04-22 16:56:21 +00:00
}
//-------------------------------------
2023-10-03 14:23:56 +00:00
template < class BASE_NPC >
inline int CAI_BehaviorHost < BASE_NPC > : : SelectFailSchedule ( int failedSchedule , int failedTask , AI_TaskFailureCode_t taskFailCode )
2020-04-22 16:56:21 +00:00
{
2023-10-03 14:23:56 +00:00
m_bCalledBehaviorSelectSchedule = true ;
int result = 0 ;
if ( this - > m_pPrimaryBehavior & & this - > m_pPrimaryBehavior - > BridgeSelectFailSchedule ( failedSchedule , failedTask , taskFailCode , & result ) )
return result ;
return BaseClass : : SelectFailSchedule ( failedSchedule , failedTask , taskFailCode ) ;
2020-04-22 16:56:21 +00:00
}
//-------------------------------------
2023-10-03 14:23:56 +00:00
template < class BASE_NPC >
inline void CAI_BehaviorHost < BASE_NPC > : : StartTask ( const Task_t * pTask )
2020-04-22 16:56:21 +00:00
{
2023-10-03 14:23:56 +00:00
if ( this - > m_pPrimaryBehavior & & this - > m_pPrimaryBehavior - > BridgeStartTask ( pTask ) )
return ;
BaseClass : : StartTask ( pTask ) ;
2020-04-22 16:56:21 +00:00
}
//-------------------------------------
2023-10-03 14:23:56 +00:00
template < class BASE_NPC >
inline void CAI_BehaviorHost < BASE_NPC > : : RunTask ( const Task_t * pTask )
2020-04-22 16:56:21 +00:00
{
2023-10-03 14:23:56 +00:00
if ( this - > m_pPrimaryBehavior & & this - > m_pPrimaryBehavior - > BridgeRunTask ( pTask ) )
return ;
BaseClass : : RunTask ( pTask ) ;
2020-04-22 16:56:21 +00:00
}
//-------------------------------------
2023-10-03 14:23:56 +00:00
template < class BASE_NPC >
inline CAI_Schedule * CAI_BehaviorHost < BASE_NPC > : : GetSchedule ( int localScheduleID )
2020-04-22 16:56:21 +00:00
{
2023-10-03 14:23:56 +00:00
CAI_Schedule * pResult ;
if ( this - > m_pPrimaryBehavior & & this - > m_pPrimaryBehavior - > BridgeGetSchedule ( localScheduleID , & pResult ) )
return pResult ;
return BaseClass : : GetSchedule ( localScheduleID ) ;
2020-04-22 16:56:21 +00:00
}
//-------------------------------------
2023-10-03 14:23:56 +00:00
template < class BASE_NPC >
inline const char * CAI_BehaviorHost < BASE_NPC > : : TaskName ( int taskID )
2020-04-22 16:56:21 +00:00
{
2023-10-03 14:23:56 +00:00
const char * pszResult = NULL ;
if ( this - > m_pPrimaryBehavior & & this - > m_pPrimaryBehavior - > BridgeTaskName ( taskID , & pszResult ) )
return pszResult ;
return BaseClass : : TaskName ( taskID ) ;
2020-04-22 16:56:21 +00:00
}
//-------------------------------------
2023-10-03 14:23:56 +00:00
template < class BASE_NPC >
inline void CAI_BehaviorHost < BASE_NPC > : : BuildScheduleTestBits ( )
2020-04-22 16:56:21 +00:00
{
2023-10-03 14:23:56 +00:00
// Iterate over behaviors and call BuildScheduleTestBitsNotActive() on each behavior
// not currently active.
for ( int i = 0 ; i < this - > m_Behaviors . Count ( ) ; i + + )
{
if ( this - > m_Behaviors [ i ] ! = this - > m_pPrimaryBehavior )
{
this - > m_Behaviors [ i ] - > BuildScheduleTestBitsNotActive ( ) ;
}
}
if ( this - > m_pPrimaryBehavior )
this - > m_pPrimaryBehavior - > BuildScheduleTestBits ( ) ;
BaseClass : : BuildScheduleTestBits ( ) ;
2020-04-22 16:56:21 +00:00
}
//-------------------------------------
2023-10-03 14:23:56 +00:00
template < class BASE_NPC >
inline void CAI_BehaviorHost < BASE_NPC > : : OnChangeHintGroup ( string_t oldGroup , string_t newGroup )
2020-04-22 16:56:21 +00:00
{
2023-10-03 14:23:56 +00:00
for ( int i = 0 ; i < this - > m_Behaviors . Count ( ) ; i + + )
{
this - > m_Behaviors [ i ] - > OnChangeHintGroup ( oldGroup , newGroup ) ;
}
BaseClass : : OnChangeHintGroup ( oldGroup , newGroup ) ;
2020-04-22 16:56:21 +00:00
}
//-------------------------------------
2023-10-03 14:23:56 +00:00
template < class BASE_NPC >
inline float CAI_BehaviorHost < BASE_NPC > : : BehaviorBridge_GetJumpGravity ( ) const
2020-04-22 16:56:21 +00:00
{
2023-10-03 14:23:56 +00:00
return BaseClass : : GetJumpGravity ( ) ;
2020-04-22 16:56:21 +00:00
}
//-------------------------------------
2023-10-03 14:23:56 +00:00
template < class BASE_NPC >
inline bool CAI_BehaviorHost < BASE_NPC > : : BehaviorBridge_IsJumpLegal ( const Vector & startPos , const Vector & apex , const Vector & endPos , float maxUp , float maxDown , float maxDist ) const
2020-04-22 16:56:21 +00:00
{
2023-10-03 14:23:56 +00:00
return BaseClass : : IsJumpLegal ( startPos , apex , endPos , maxUp , maxDown , maxDist ) ;
2020-04-22 16:56:21 +00:00
}
//-------------------------------------
2023-10-03 14:23:56 +00:00
template < class BASE_NPC >
inline bool CAI_BehaviorHost < BASE_NPC > : : BehaviorBridge_MovementCost ( int moveType , const Vector & vecStart , const Vector & vecEnd , float * pCost )
2020-04-22 16:56:21 +00:00
{
2023-10-03 14:23:56 +00:00
return BaseClass : : MovementCost ( moveType , vecStart , vecEnd , pCost ) ;
2020-04-22 16:56:21 +00:00
}
//-------------------------------------
2023-10-03 14:23:56 +00:00
template < class BASE_NPC >
inline void CAI_BehaviorHost < BASE_NPC > : : OnChangeActiveWeapon ( CBaseCombatWeapon * pOldWeapon , CBaseCombatWeapon * pNewWeapon )
2020-04-22 16:56:21 +00:00
{
2023-10-03 14:23:56 +00:00
for ( int i = 0 ; i < this - > m_Behaviors . Count ( ) ; i + + )
{
this - > m_Behaviors [ i ] - > OnChangeActiveWeapon ( pOldWeapon , pNewWeapon ) ;
}
BaseClass : : OnChangeActiveWeapon ( pOldWeapon , pNewWeapon ) ;
2020-04-22 16:56:21 +00:00
}
//-------------------------------------
2023-10-03 14:23:56 +00:00
template < class BASE_NPC >
inline void CAI_BehaviorHost < BASE_NPC > : : OnRestore ( )
2020-04-22 16:56:21 +00:00
{
2023-10-03 14:23:56 +00:00
for ( int i = 0 ; i < this - > m_Behaviors . Count ( ) ; i + + )
{
this - > m_Behaviors [ i ] - > OnRestore ( ) ;
}
BaseClass : : OnRestore ( ) ;
2020-04-22 16:56:21 +00:00
}
//-------------------------------------
2023-10-03 14:23:56 +00:00
template < class BASE_NPC >
inline void CAI_BehaviorHost < BASE_NPC > : : Precache ( )
2020-04-22 16:56:21 +00:00
{
2023-10-03 14:23:56 +00:00
BaseClass : : Precache ( ) ;
for ( int i = 0 ; i < this - > m_Behaviors . Count ( ) ; i + + )
{
this - > m_Behaviors [ i ] - > Precache ( ) ;
}
2020-04-22 16:56:21 +00:00
}
//-------------------------------------
2023-10-03 14:23:56 +00:00
template < class BASE_NPC >
inline void CAI_BehaviorHost < BASE_NPC > : : UpdateOnRemove ( )
2020-04-22 16:56:21 +00:00
{
2023-10-03 14:23:56 +00:00
for ( int i = 0 ; i < this - > m_Behaviors . Count ( ) ; i + + )
{
this - > m_Behaviors [ i ] - > UpdateOnRemove ( ) ;
}
BaseClass : : UpdateOnRemove ( ) ;
2020-04-22 16:56:21 +00:00
}
2023-10-03 14:23:56 +00:00
//-------------------------------------
2020-04-22 16:56:21 +00:00
2023-10-03 14:23:56 +00:00
template < class BASE_NPC >
inline void CAI_BehaviorHost < BASE_NPC > : : Event_Killed ( const CTakeDamageInfo & info )
2020-04-22 16:56:21 +00:00
{
2023-10-03 14:23:56 +00:00
for ( int i = 0 ; i < this - > m_Behaviors . Count ( ) ; i + + )
{
this - > m_Behaviors [ i ] - > Event_Killed ( info ) ;
}
BaseClass : : Event_Killed ( info ) ;
2020-04-22 16:56:21 +00:00
}
//-----------------------------------------------------------------------------
2023-10-03 14:23:56 +00:00
template < class BASE_NPC >
inline float CAI_BehaviorHost < BASE_NPC > : : GetJumpGravity ( ) const
2020-04-22 16:56:21 +00:00
{
2023-10-03 14:23:56 +00:00
// @HACKHACK
float base = BaseClass : : GetJumpGravity ( ) ;
for ( int i = 0 ; i < this - > m_Behaviors . Count ( ) ; i + + )
{
float current = this - > m_Behaviors [ i ] - > GetJumpGravity ( ) ;
if ( current ! = base )
{
return current ;
}
}
return BaseClass : : GetJumpGravity ( ) ;
2020-04-22 16:56:21 +00:00
}
2023-10-03 14:23:56 +00:00
//-------------------------------------
2020-04-22 16:56:21 +00:00
2023-10-03 14:23:56 +00:00
template < class BASE_NPC >
inline bool CAI_BehaviorHost < BASE_NPC > : : IsJumpLegal ( const Vector & startPos , const Vector & apex , const Vector & endPos , float maxUp , float maxDown , float maxDist ) const
2020-04-22 16:56:21 +00:00
{
2023-10-03 14:23:56 +00:00
// @HACKHACK
bool base = BaseClass : : IsJumpLegal ( startPos , apex , endPos , maxUp , maxDown , maxDist ) ;
for ( int i = 0 ; i < this - > m_Behaviors . Count ( ) ; i + + )
2020-04-22 16:56:21 +00:00
{
2023-10-03 14:23:56 +00:00
bool current = this - > m_Behaviors [ i ] - > IsJumpLegal ( startPos , apex , endPos , maxUp , maxDown , maxDist ) ;
if ( current ! = base )
{
return current ;
}
2020-04-22 16:56:21 +00:00
}
2023-10-03 14:23:56 +00:00
return base ;
2020-04-22 16:56:21 +00:00
}
template < class BASE_NPC >
2023-10-03 14:23:56 +00:00
inline bool CAI_BehaviorHost < BASE_NPC > : : MovementCost ( int moveType , const Vector & vecStart , const Vector & vecEnd , float * pCost )
2020-04-22 16:56:21 +00:00
{
2023-10-03 14:23:56 +00:00
// @HACKHACK
bool base = BaseClass : : MovementCost ( moveType , vecStart , vecEnd , pCost ) ;
2020-04-22 16:56:21 +00:00
2023-10-03 14:23:56 +00:00
for ( int i = 0 ; i < this - > m_Behaviors . Count ( ) ; i + + )
2020-04-22 16:56:21 +00:00
{
2023-10-03 14:23:56 +00:00
bool current = this - > m_Behaviors [ i ] - > MovementCost ( moveType , vecStart , vecEnd , pCost ) ;
if ( current ! = base )
{
return current ;
}
2020-04-22 16:56:21 +00:00
}
2023-10-03 14:23:56 +00:00
return base ;
2020-04-22 16:56:21 +00:00
}
//-------------------------------------
template < class BASE_NPC >
inline int CAI_BehaviorHost < BASE_NPC > : : Save ( ISave & save )
{
int result = BaseClass : : Save ( save ) ;
if ( result )
2023-10-03 14:23:56 +00:00
CAI_BehaviorBase : : SaveBehaviors ( save , this - > m_pPrimaryBehavior , this - > AccessBehaviors ( ) , this - > NumBehaviors ( ) ) ;
2020-04-22 16:56:21 +00:00
return result ;
}
//-------------------------------------
template < class BASE_NPC >
inline int CAI_BehaviorHost < BASE_NPC > : : Restore ( IRestore & restore )
{
int result = BaseClass : : Restore ( restore ) ;
if ( result )
{
2023-10-03 14:23:56 +00:00
int iCurrent = CAI_BehaviorBase : : RestoreBehaviors ( restore , this - > AccessBehaviors ( ) , this - > NumBehaviors ( ) ) ;
2020-04-22 16:56:21 +00:00
if ( iCurrent ! = - 1 )
2023-10-03 14:23:56 +00:00
this - > m_pPrimaryBehavior = this - > AccessBehaviors ( ) [ iCurrent ] ;
2020-04-22 16:56:21 +00:00
else
2023-10-03 14:23:56 +00:00
this - > m_pPrimaryBehavior = NULL ;
2020-04-22 16:56:21 +00:00
}
return result ;
}
//-----------------------------------------------------------------------------
# endif // AI_BEHAVIOR_H