//========= Copyright <EFBFBD> 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: Base class for humanoid NPCs intended to fight along side player in close
// environments
//
//=============================================================================//
# ifndef NPC_PLAYERCOMPANION_H
# define NPC_PLAYERCOMPANION_H
# include "ai_playerally.h"
# include "ai_behavior_follow.h"
# include "ai_behavior_standoff.h"
# include "ai_behavior_assault.h"
# include "ai_behavior_lead.h"
# include "ai_behavior_actbusy.h"
# include "ai_behavior_fear.h"
# include "ai_behavior_fightfromcover.h"
# ifdef HL2_EPISODIC
# include "ai_behavior_operator.h"
# include "ai_behavior_passenger_companion.h"
# endif
# if defined( _WIN32 )
# pragma once
# endif
enum AIReadiness_t
{
AIRL_PANIC = - 2 ,
AIRL_STEALTH = - 1 ,
AIRL_RELAXED = 0 ,
AIRL_STIMULATED ,
AIRL_AGITATED ,
} ;
enum AIReadinessUse_t
{
AIRU_NEVER ,
AIRU_ALWAYS ,
AIRU_ONLY_PLAYER_SQUADMATES ,
} ;
class CCompanionActivityRemap : public CActivityRemap
{
public :
CCompanionActivityRemap ( void ) :
m_fUsageBits ( 0 ) ,
m_readiness ( AIRL_RELAXED ) ,
m_bAiming ( false ) ,
m_bWeaponRequired ( false ) ,
m_bInVehicle ( false ) { }
// This bitfield maps which bits of data are being utilized by this data structure, since not all criteria
// in the parsed file are essential. You must add corresponding bits to the definitions below and maintain
// their state in the parsing of the file, as well as check the bitfield before accessing the data. This
// could be encapsulated into this class, but we'll probably move away from this model and closer to something
// more akin to the response rules -- jdw
int m_fUsageBits ;
AIReadiness_t m_readiness ;
bool m_bAiming ;
bool m_bWeaponRequired ;
bool m_bInVehicle ; // For future expansion, this needs to speak more to the exact seat, role, and vehicle
} ;
// Usage bits for remap "extra" parsing - if these bits are set, the associated data has changed
# define bits_REMAP_READINESS (1<<0)
# define bits_REMAP_AIMING (1<<1)
# define bits_REMAP_WEAPON_REQUIRED (1<<2)
# define bits_REMAP_IN_VEHICLE (1<<3)
// Readiness modes that only change due to mapmaker scripts
# define READINESS_MIN_VALUE -2
# define READINESS_MODE_PANIC -2
# define READINESS_MODE_STEALTH -1
// Readiness modes that change normally
# define READINESS_VALUE_RELAXED 0.1f
# define READINESS_VALUE_STIMULATED 0.95f
# define READINESS_VALUE_AGITATED 1.0f
class CPhysicsProp ;
//-----------------------------------------------------------------------------
//
// CLASS: CNPC_PlayerCompanion
//
//-----------------------------------------------------------------------------
class CNPC_PlayerCompanion : public CAI_PlayerAlly
{
DECLARE_CLASS ( CNPC_PlayerCompanion , CAI_PlayerAlly ) ;
public :
//---------------------------------
bool CreateBehaviors ( ) ;
void Precache ( ) ;
void Spawn ( ) ;
virtual void SelectModel ( ) { } ;
virtual int Restore ( IRestore & restore ) ;
virtual void DoCustomSpeechAI ( void ) ;
//---------------------------------
int ObjectCaps ( ) ;
bool ShouldAlwaysThink ( ) ;
Disposition_t IRelationType ( CBaseEntity * pTarget ) ;
bool IsSilentSquadMember ( ) const ;
//---------------------------------
// Behavior
//---------------------------------
void GatherConditions ( ) ;
virtual void PredictPlayerPush ( ) ;
void BuildScheduleTestBits ( ) ;
CSound * GetBestSound ( int validTypes = ALL_SOUNDS ) ;
bool QueryHearSound ( CSound * pSound ) ;
bool QuerySeeEntity ( CBaseEntity * pEntity , bool bOnlyHateOrFearIfNPC = false ) ;
bool ShouldIgnoreSound ( CSound * ) ;
int SelectSchedule ( ) ;
virtual int SelectScheduleDanger ( ) ;
virtual int SelectSchedulePriorityAction ( ) ;
virtual int SelectScheduleNonCombat ( ) { return SCHED_NONE ; }
virtual int SelectScheduleCombat ( ) ;
int SelectSchedulePlayerPush ( ) ;
virtual bool CanReload ( void ) ;
virtual bool ShouldDeferToFollowBehavior ( ) ;
bool ShouldDeferToPassengerBehavior ( void ) ;
bool IsValidReasonableFacing ( const Vector & vecSightDir , float sightDist ) ;
int TranslateSchedule ( int scheduleType ) ;
void StartTask ( const Task_t * pTask ) ;
void RunTask ( const Task_t * pTask ) ;
Activity TranslateActivityReadiness ( Activity activity ) ;
Activity NPC_TranslateActivity ( Activity eNewActivity ) ;
void HandleAnimEvent ( animevent_t * pEvent ) ;
bool HandleInteraction ( int interactionType , void * data , CBaseCombatCharacter * sourceEnt ) ;
int GetSoundInterests ( ) ;
void Touch ( CBaseEntity * pOther ) ;
virtual bool IgnorePlayerPushing ( void ) ;
void ModifyOrAppendCriteria ( AI_CriteriaSet & set ) ;
void Activate ( void ) ;
void PrepareReadinessRemap ( void ) ;
virtual bool IsNavigationUrgent ( void ) ;
//---------------------------------
// Readiness
//---------------------------------
protected :
virtual bool IsReadinessCapable ( ) ;
bool IsReadinessLocked ( ) { return gpGlobals - > curtime < m_flReadinessLockedUntil ; }
void AddReadiness ( float flAdd , bool bOverrideLock = false ) ;
void SubtractReadiness ( float flAdd , bool bOverrideLock = false ) ;
void SetReadinessValue ( float flSet ) ;
void SetReadinessSensitivity ( float flSensitivity ) { m_flReadinessSensitivity = flSensitivity ; }
virtual void UpdateReadiness ( ) ;
virtual float GetReadinessDecay ( ) ;
bool IsInScriptedReadinessState ( void ) { return ( m_flReadiness < 0 ) ; }
CUtlVector < CCompanionActivityRemap > m_activityMappings ;
public :
float GetReadinessValue ( ) { return m_flReadiness ; }
int GetReadinessLevel ( ) ;
void SetReadinessLevel ( int iLevel , bool bOverrideLock , bool bSlam ) ;
void LockReadiness ( float duration = - 1.0f ) ; // Defaults to indefinitely locked
void UnlockReadiness ( void ) ;
virtual void ReadinessLevelChanged ( int iPriorLevel ) { }
void InputGiveWeapon ( inputdata_t & inputdata ) ;
# ifdef HL2_EPISODIC
//---------------------------------
// Vehicle passenger
//---------------------------------
void InputEnterVehicle ( inputdata_t & inputdata ) ;
void InputEnterVehicleImmediately ( inputdata_t & inputdata ) ;
void InputCancelEnterVehicle ( inputdata_t & inputdata ) ;
void InputExitVehicle ( inputdata_t & inputdata ) ;
bool CanEnterVehicle ( void ) ;
bool CanExitVehicle ( void ) ;
void EnterVehicle ( CBaseEntity * pEntityVehicle , bool bImmediately ) ;
virtual bool ExitVehicle ( void ) ;
virtual void UpdateEfficiency ( bool bInPVS ) ;
virtual bool IsInAVehicle ( void ) const ;
virtual IServerVehicle * GetVehicle ( void ) ;
virtual CBaseEntity * GetVehicleEntity ( void ) ;
virtual bool CanRunAScriptedNPCInteraction ( bool bForced = false ) ;
virtual bool IsAllowedToDodge ( void ) ;
# endif // HL2_EPISODIC
public :
virtual void OnPlayerKilledOther ( CBaseEntity * pVictim , const CTakeDamageInfo & info ) ;
//---------------------------------
//---------------------------------
bool PickTacticalLookTarget ( AILookTargetArgs_t * pArgs ) ;
//---------------------------------
// Aiming
//---------------------------------
CBaseEntity * GetAimTarget ( ) { return m_hAimTarget ; }
void SetAimTarget ( CBaseEntity * pTarget ) ;
void StopAiming ( char * pszReason = NULL ) ;
bool FindNewAimTarget ( ) ;
void OnNewLookTarget ( ) ;
bool ShouldBeAiming ( ) ;
virtual bool IsAllowedToAim ( ) ;
bool HasAimLOS ( CBaseEntity * pAimTarget ) ;
void AimGun ( ) ;
CBaseEntity * GetAlternateMoveShootTarget ( ) ;
//---------------------------------
// Combat
//---------------------------------
virtual void LocateEnemySound ( ) { } ;
bool IsValidEnemy ( CBaseEntity * pEnemy ) ;
bool IsSafeFromFloorTurret ( const Vector & vecLocation , CBaseEntity * pTurret ) ;
bool ShouldMoveAndShoot ( void ) ;
void OnUpdateShotRegulator ( ) ;
void DecalTrace ( trace_t * pTrace , char const * decalName ) ;
bool FCanCheckAttacks ( ) ;
Vector GetActualShootPosition ( const Vector & shootOrigin ) ;
WeaponProficiency_t CalcWeaponProficiency ( CBaseCombatWeapon * pWeapon ) ;
bool ShouldLookForBetterWeapon ( ) ;
bool Weapon_CanUse ( CBaseCombatWeapon * pWeapon ) ;
void Weapon_Equip ( CBaseCombatWeapon * pWeapon ) ;
void PickupWeapon ( CBaseCombatWeapon * pWeapon ) ;
bool FindCoverPos ( CBaseEntity * pEntity , Vector * pResult ) ;
bool FindCoverPosInRadius ( CBaseEntity * pEntity , const Vector & goalPos , float coverRadius , Vector * pResult ) ;
bool FindCoverPos ( CSound * pSound , Vector * pResult ) ;
bool FindMortarCoverPos ( CSound * pSound , Vector * pResult ) ;
bool IsCoverPosition ( const Vector & vecThreat , const Vector & vecPosition ) ;
bool IsEnemyTurret ( ) { return ( GetEnemy ( ) & & IsTurret ( GetEnemy ( ) ) ) ; }
static bool IsMortar ( CBaseEntity * pEntity ) ;
static bool IsSniper ( CBaseEntity * pEntity ) ;
static bool IsTurret ( CBaseEntity * pEntity ) ;
static bool IsGunship ( CBaseEntity * pEntity ) ;
//---------------------------------
// Damage handling
//---------------------------------
int OnTakeDamage_Alive ( const CTakeDamageInfo & info ) ;
void OnFriendDamaged ( CBaseCombatCharacter * pSquadmate , CBaseEntity * pAttacker ) ;
//---------------------------------
// Hints
//---------------------------------
bool FValidateHintType ( CAI_Hint * pHint ) ;
//---------------------------------
// Navigation
//---------------------------------
bool IsValidMoveAwayDest ( const Vector & vecDest ) ;
bool ValidateNavGoal ( ) ;
bool OverrideMove ( float flInterval ) ; // Override to take total control of movement (return true if done so)
bool MovementCost ( int moveType , const Vector & vecStart , const Vector & vecEnd , float * pCost ) ;
float GetIdealSpeed ( ) const ;
float GetIdealAccel ( ) const ;
bool OnObstructionPreSteer ( AILocalMoveGoal_t * pMoveGoal , float distClear , AIMoveResult_t * pResult ) ;
//---------------------------------
// Inputs
//---------------------------------
void InputOutsideTransition ( inputdata_t & inputdata ) ;
void InputSetReadinessPanic ( inputdata_t & inputdata ) ;
void InputSetReadinessStealth ( inputdata_t & inputdata ) ;
void InputSetReadinessLow ( inputdata_t & inputdata ) ;
void InputSetReadinessMedium ( inputdata_t & inputdata ) ;
void InputSetReadinessHigh ( inputdata_t & inputdata ) ;
void InputLockReadiness ( inputdata_t & inputdata ) ;
# if HL2_EPISODIC
void InputClearAllOuputs ( inputdata_t & inputdata ) ; ///< annihilate every output on this npc
# endif
bool AllowReadinessValueChange ( void ) ;
protected :
//-----------------------------------------------------
// Conditions, Schedules, Tasks
//-----------------------------------------------------
enum
{
COND_PC_HURTBYFIRE = BaseClass : : NEXT_CONDITION ,
COND_PC_SAFE_FROM_MORTAR ,
COND_PC_BECOMING_PASSENGER ,
NEXT_CONDITION ,
SCHED_PC_COWER = BaseClass : : NEXT_SCHEDULE ,
SCHED_PC_MOVE_TOWARDS_COVER_FROM_BEST_SOUND ,
SCHED_PC_TAKE_COVER_FROM_BEST_SOUND ,
SCHED_PC_FLEE_FROM_BEST_SOUND ,
SCHED_PC_FAIL_TAKE_COVER_TURRET ,
SCHED_PC_FAKEOUT_MORTAR ,
SCHED_PC_GET_OFF_COMPANION ,
NEXT_SCHEDULE ,
TASK_PC_WAITOUT_MORTAR = BaseClass : : NEXT_TASK ,
TASK_PC_GET_PATH_OFF_COMPANION ,
NEXT_TASK ,
} ;
private :
void SetupCoverSearch ( CBaseEntity * pEntity ) ;
void CleanupCoverSearch ( ) ;
//-----------------------------------------------------
bool m_bMovingAwayFromPlayer ;
bool m_bWeightPathsInCover ;
enum eCoverType
{
CT_NORMAL ,
CT_TURRET ,
CT_MORTAR
} ;
static eCoverType gm_fCoverSearchType ;
static bool gm_bFindingCoverFromAllEnemies ;
CSimpleSimTimer m_FakeOutMortarTimer ;
// Derived classes should not use the expresser directly
virtual CAI_Expresser * GetExpresser ( ) { return BaseClass : : GetExpresser ( ) ; }
protected :
//-----------------------------------------------------
virtual CAI_FollowBehavior & GetFollowBehavior ( void ) { return m_FollowBehavior ; }
CAI_FightFromCoverBehavior m_FightFromCoverBehavior ;
CAI_AssaultBehavior m_AssaultBehavior ;
CAI_FollowBehavior m_FollowBehavior ;
CAI_StandoffBehavior m_StandoffBehavior ;
CAI_LeadBehavior m_LeadBehavior ;
CAI_ActBusyBehavior m_ActBusyBehavior ;
# ifdef HL2_EPISODIC
CAI_OperatorBehavior m_OperatorBehavior ;
CAI_PassengerBehaviorCompanion m_PassengerBehavior ;
CAI_FearBehavior m_FearBehavior ;
# endif
//-----------------------------------------------------
bool ShouldAlwaysTransition ( void ) ;
// Readiness is a value that's fed by various events in the NPC's AI. It is used
// to make decisions about what type of posture the NPC should be in (relaxed, agitated).
// It is not used to make decisions about what to do in the AI.
float m_flReadiness ;
float m_flReadinessSensitivity ;
bool m_bReadinessCapable ;
float m_flReadinessLockedUntil ;
float m_fLastBarrelExploded ;
float m_fLastPlayerKill ;
int m_iNumConsecutiveBarrelsExploded ; // Companions keep track of the # of consecutive barrels exploded by the player and speaks a response as it increases
int m_iNumConsecutivePlayerKills ; // Alyx keeps track of the # of consecutive kills by the player and speaks a response as it increases
//-----------------------------------------------------
float m_flBoostSpeed ;
//-----------------------------------------------------
CSimpleSimTimer m_AnnounceAttackTimer ;
//-----------------------------------------------------
EHANDLE m_hAimTarget ;
# ifdef HL2_EPISODIC
CHandle < CPhysicsProp > m_hFlare ;
# endif // HL2_EPISODIC
//-----------------------------------------------------
static string_t gm_iszMortarClassname ;
static string_t gm_iszFloorTurretClassname ;
static string_t gm_iszGroundTurretClassname ;
static string_t gm_iszShotgunClassname ;
static string_t gm_iszRollerMineClassname ;
//-----------------------------------------------------
void InputEnableAlwaysTransition ( inputdata_t & inputdata ) ;
void InputDisableAlwaysTransition ( inputdata_t & inputdata ) ;
bool m_bAlwaysTransition ;
bool m_bDontPickupWeapons ;
void InputEnableWeaponPickup ( inputdata_t & inputdata ) ;
void InputDisableWeaponPickup ( inputdata_t & inputdata ) ;
COutputEvent m_OnWeaponPickup ;
CStopwatch m_SpeechWatch_PlayerLooking ;
DECLARE_DATADESC ( ) ;
DEFINE_CUSTOM_AI ;
} ;
// Used for quick override move searches against certain types of entities
void OverrideMoveCache_ForceRepopulateList ( void ) ;
CBaseEntity * OverrideMoveCache_FindTargetsInRadius ( CBaseEntity * pFirstEntity , const Vector & vecOrigin , float flRadius ) ;
void OverrideMoveCache_LevelInitPreEntity ( void ) ;
void OverrideMoveCache_LevelShutdownPostEntity ( void ) ;
# endif // NPC_PLAYERCOMPANION_H