source-engine/game/server/hl2/npc_playercompanion.h

440 lines
14 KiB
C
Raw Normal View History

2020-04-22 16:56:21 +00:00
//========= Copyright 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"
#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_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