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

471 lines
15 KiB
C++

//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef NPC_METROPOLICE_H
#define NPC_METROPOLICE_H
#ifdef _WIN32
#pragma once
#endif
#include "rope.h"
#include "rope_shared.h"
#include "ai_baseactor.h"
#include "ai_basenpc.h"
#include "ai_goal_police.h"
#include "ai_behavior.h"
#include "ai_behavior_standoff.h"
#include "ai_behavior_assault.h"
#include "ai_behavior_functank.h"
#include "ai_behavior_actbusy.h"
#include "ai_behavior_rappel.h"
#include "ai_behavior_police.h"
#include "ai_behavior_follow.h"
#include "ai_sentence.h"
#include "props.h"
class CNPC_MetroPolice;
class CNPC_MetroPolice : public CAI_BaseActor
{
DECLARE_CLASS( CNPC_MetroPolice, CAI_BaseActor );
DECLARE_DATADESC();
public:
CNPC_MetroPolice() = default;
virtual bool CreateComponents();
bool CreateBehaviors();
void Spawn( void );
void Precache( void );
Class_T Classify( void );
Disposition_t IRelationType(CBaseEntity *pTarget);
float MaxYawSpeed( void );
void HandleAnimEvent( animevent_t *pEvent );
Activity NPC_TranslateActivity( Activity newActivity );
Vector EyeDirection3D( void ) { return CAI_BaseHumanoid::EyeDirection3D(); } // cops don't have eyes
virtual void Event_Killed( const CTakeDamageInfo &info );
virtual void OnScheduleChange();
float GetIdealAccel( void ) const;
int ObjectCaps( void ) { return UsableNPCObjectCaps(BaseClass::ObjectCaps()); }
void PrecriminalUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
// These are overridden so that the cop can shove and move a non-criminal player safely
CBaseEntity *CheckTraceHullAttack( float flDist, const Vector &mins, const Vector &maxs, int iDamage, int iDmgType, float forceScale, bool bDamageAnyNPC );
CBaseEntity *CheckTraceHullAttack( const Vector &vStart, const Vector &vEnd, const Vector &mins, const Vector &maxs, int iDamage, int iDmgType, float flForceScale, bool bDamageAnyNPC );
virtual int SelectSchedule( void );
virtual int SelectFailSchedule( int failedSchedule, int failedTask, AI_TaskFailureCode_t taskFailCode );
virtual int TranslateSchedule( int scheduleType );
void StartTask( const Task_t *pTask );
void RunTask( const Task_t *pTask );
virtual Vector GetActualShootTrajectory( const Vector &shootOrigin );
virtual void FireBullets( const FireBulletsInfo_t &info );
virtual bool HandleInteraction(int interactionType, void *data, CBaseCombatCharacter* sourceEnt);
virtual void Weapon_Equip( CBaseCombatWeapon *pWeapon );
//virtual bool OverrideMoveFacing( const AILocalMoveGoal_t &move, float flInterval );
bool OnObstructionPreSteer( AILocalMoveGoal_t *pMoveGoal, float distClear, AIMoveResult_t *pResult );
bool ShouldBruteForceFailedNav() { return false; }
virtual void GatherConditions( void );
virtual bool OverrideMoveFacing( const AILocalMoveGoal_t &move, float flInterval );
// Can't move and shoot when the enemy is an airboat
virtual bool ShouldMoveAndShoot();
// TraceAttack
virtual void TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator );
// Speaking
virtual void SpeakSentence( int nSentenceType );
// Set up the shot regulator based on the equipped weapon
virtual void OnUpdateShotRegulator( );
bool ShouldKnockOutTarget( CBaseEntity *pTarget );
void KnockOutTarget( CBaseEntity *pTarget );
void StunnedTarget( CBaseEntity *pTarget );
void AdministerJustice( void );
bool QueryHearSound( CSound *pSound );
void SetBatonState( bool state );
bool BatonActive( void );
CAI_Sentence< CNPC_MetroPolice > *GetSentences() { return &m_Sentences; }
virtual bool AllowedToIgnite( void ) { return true; }
void PlayFlinchGesture( void );
protected:
// Determines the best type of flinch anim to play.
virtual Activity GetFlinchActivity( bool bHeavyDamage, bool bGesture );
// Only move and shoot when attacking
virtual bool OnBeginMoveAndShoot();
virtual void OnEndMoveAndShoot();
private:
bool PlayerIsCriminal( void );
void ReleaseManhack( void );
// Speech-related methods
void AnnounceTakeCoverFromDanger( CSound *pSound );
void AnnounceEnemyType( CBaseEntity *pEnemy );
void AnnounceEnemyKill( CBaseEntity *pEnemy );
void AnnounceHarrassment( );
void AnnounceOutOfAmmo( );
// Behavior-related sentences
void SpeakFuncTankSentence( int nSentenceType );
void SpeakAssaultSentence( int nSentenceType );
void SpeakStandoffSentence( int nSentenceType );
virtual void LostEnemySound( void );
virtual void FoundEnemySound( void );
virtual void AlertSound( void );
virtual void PainSound( const CTakeDamageInfo &info );
virtual void DeathSound( const CTakeDamageInfo &info );
virtual void IdleSound( void );
virtual bool ShouldPlayIdleSound( void );
// Burst mode!
void SetBurstMode( bool bEnable );
int OnTakeDamage_Alive( const CTakeDamageInfo &info );
int GetSoundInterests( void );
void BuildScheduleTestBits( void );
bool CanDeployManhack( void );
bool ShouldHitPlayer( const Vector &targetDir, float targetDist );
void PrescheduleThink( void );
void SetPlayerCriminalDuration( float time );
void IncrementPlayerCriminalStatus( void );
virtual bool UseAttackSquadSlots() { return true; }
WeaponProficiency_t CalcWeaponProficiency( CBaseCombatWeapon *pWeapon );
// Inputs
void InputEnableManhackToss( inputdata_t &inputdata );
void InputSetPoliceGoal( inputdata_t &inputdata );
void InputActivateBaton( inputdata_t &inputdata );
void NotifyDeadFriend ( CBaseEntity* pFriend );
// Stitch aiming!
void AimBurstRandomly( int nMinCount, int nMaxCount, float flMinDelay, float flMaxDelay );
void AimBurstAtEnemy( float flReactionTime );
void AimBurstInFrontOfEnemy( float flReactionTime );
void AimBurstAlongSideOfEnemy( float flFollowTime );
void AimBurstBehindEnemy( float flFollowTime );
void AimBurstTightGrouping( float flShotTime );
// Anim event handlers
void OnAnimEventDeployManhack( animevent_t *pEvent );
void OnAnimEventShove( void );
void OnAnimEventBatonOn( void );
void OnAnimEventBatonOff( void );
void OnAnimEventStartDeployManhack( void );
void OnAnimEventPreDeployManhack( void );
bool HasBaton( void );
// Normal schedule selection
int SelectCombatSchedule();
int SelectScheduleNewEnemy();
int SelectScheduleArrestEnemy();
int SelectRangeAttackSchedule();
int SelectScheduleNoDirectEnemy();
int SelectScheduleInvestigateSound();
int SelectShoveSchedule( void );
bool TryToEnterPistolSlot( int nSquadSlot );
// Airboat schedule selection
int SelectAirboatCombatSchedule();
int SelectAirboatRangeAttackSchedule();
// Handle flinching
bool IsHeavyDamage( const CTakeDamageInfo &info );
// Is my enemy currently in an airboat?
bool IsEnemyInAnAirboat() const;
// Returns the airboat
CBaseEntity *GetEnemyAirboat() const;
// Compute a predicted enemy position n seconds into the future
void PredictShootTargetPosition( float flDeltaTime, float flMinLeadDist, float flAddVelocity, Vector *pVecTarget, Vector *pVecTargetVel );
// Compute a predicted velocity n seconds into the future (given a known acceleration rate)
void PredictShootTargetVelocity( float flDeltaTime, Vector *pVecTargetVel );
// How many shots will I fire in a particular amount of time?
int CountShotsInTime( float flDeltaTime ) const;
float GetTimeForShots( int nShotCount ) const;
// Visualize stitch
void VisualizeStitch( const Vector &vecStart, const Vector &vecEnd );
// Visualize line of death
void VisualizeLineOfDeath( );
// Modify the stitch length
float ComputeDistanceStitchModifier( float flDistanceToTarget ) const;
// Adjusts the burst toward the target as it's being fired.
void SteerBurstTowardTarget( );
// Methods to compute shot trajectory based on burst mode
Vector ComputeBurstLockOnTrajectory( const Vector &shootOrigin );
Vector ComputeBurstDeliberatelyMissTrajectory( const Vector &shootOrigin );
Vector ComputeBurstTrajectory( const Vector &shootOrigin );
Vector ComputeTightBurstTrajectory( const Vector &shootOrigin );
// Are we currently firing a burst?
bool IsCurrentlyFiringBurst() const;
// Which entity are we actually trying to shoot at?
CBaseEntity *GetShootTarget();
// Different burst steering modes
void SteerBurstTowardTargetUseSpeedOnly( const Vector &vecShootAt, const Vector &vecShootAtVelocity, float flPredictTime, int nShotsTillPredict );
void SteerBurstTowardTargetUseVelocity( const Vector &vecShootAt, const Vector &vecShootAtVelocity, int nShotsTillPredict );
void SteerBurstTowardTargetUsePosition( const Vector &vecShootAt, const Vector &vecShootAtVelocity, int nShotsTillPredict );
void SteerBurstTowardPredictedPoint( const Vector &vecShootAt, const Vector &vecShootAtVelocity, int nShotsTillPredict );
void SteerBurstWithinLineOfDeath( );
// Set up the shot regulator
int SetupBurstShotRegulator( float flReactionTime );
// Choose a random vector somewhere between the two specified vectors
void RandomDirectionBetweenVectors( const Vector &vecStart, const Vector &vecEnd, Vector *pResult );
// Stitch selector
float StitchAtWeight( float flDist, float flSpeed, float flDot, float flReactionTime, const Vector &vecTargetToGun );
float StitchAcrossWeight( float flDist, float flSpeed, float flDot, float flReactionTime );
float StitchAlongSideWeight( float flDist, float flSpeed, float flDot );
float StitchBehindWeight( float flDist, float flSpeed, float flDot );
float StitchTightWeight( float flDist, float flSpeed, const Vector &vecTargetToGun, const Vector &vecVelocity );
int SelectStitchSchedule();
// Can me enemy see me?
bool CanEnemySeeMe( );
// Combat schedule selection
int SelectMoveToLedgeSchedule();
// position to shoot at
Vector StitchAimTarget( const Vector &posSrc, bool bNoisy );
// Should we attempt to stitch?
bool ShouldAttemptToStitch();
// Deliberately aims as close as possible w/o hitting
Vector AimCloseToTargetButMiss( CBaseEntity *pTarget, const Vector &shootOrigin );
// Compute the actual reaction time based on distance + speed modifiers
float AimBurstAtReactionTime( float flReactonTime, float flDistToTargetSqr, float flCurrentSpeed );
int AimBurstAtSetupHitCount( float flDistToTargetSqr, float flCurrentSpeed );
// How many squad members are trying to arrest the player?
int SquadArrestCount();
// He's resisting arrest!
void EnemyResistingArrest();
void VPhysicsCollision( int index, gamevcollisionevent_t *pEvent );
// Rappel
virtual bool IsWaitingToRappel( void ) { return m_RappelBehavior.IsWaitingToRappel(); }
void BeginRappel() { m_RappelBehavior.BeginRappel(); }
private:
enum
{
BURST_NOT_ACTIVE = 0,
BURST_ACTIVE,
BURST_LOCK_ON_AFTER_HIT,
BURST_LOCKED_ON,
BURST_DELIBERATELY_MISS,
BURST_TIGHT_GROUPING,
};
enum
{
BURST_STEER_NONE = 0,
BURST_STEER_TOWARD_PREDICTED_POINT,
BURST_STEER_WITHIN_LINE_OF_DEATH,
BURST_STEER_ADJUST_FOR_SPEED_CHANGES,
BURST_STEER_EXACTLY_TOWARD_TARGET,
};
enum
{
COND_METROPOLICE_ON_FIRE = BaseClass::NEXT_CONDITION,
COND_METROPOLICE_ENEMY_RESISTING_ARREST,
COND_METROPOLICE_PLAYER_TOO_CLOSE,
COND_METROPOLICE_CHANGE_BATON_STATE,
COND_METROPOLICE_PHYSOBJECT_ASSAULT,
};
enum
{
SCHED_METROPOLICE_WALK = BaseClass::NEXT_SCHEDULE,
SCHED_METROPOLICE_WAKE_ANGRY,
SCHED_METROPOLICE_HARASS,
SCHED_METROPOLICE_CHASE_ENEMY,
SCHED_METROPOLICE_ESTABLISH_LINE_OF_FIRE,
SCHED_METROPOLICE_DRAW_PISTOL,
SCHED_METROPOLICE_DEPLOY_MANHACK,
SCHED_METROPOLICE_ADVANCE,
SCHED_METROPOLICE_CHARGE,
SCHED_METROPOLICE_BURNING_RUN,
SCHED_METROPOLICE_BURNING_STAND,
SCHED_METROPOLICE_SMG_NORMAL_ATTACK,
SCHED_METROPOLICE_SMG_BURST_ATTACK,
SCHED_METROPOLICE_AIM_STITCH_AT_AIRBOAT,
SCHED_METROPOLICE_AIM_STITCH_IN_FRONT_OF_AIRBOAT,
SCHED_METROPOLICE_AIM_STITCH_TIGHTLY,
SCHED_METROPOLICE_AIM_STITCH_ALONG_SIDE_OF_AIRBOAT,
SCHED_METROPOLICE_AIM_STITCH_BEHIND_AIRBOAT,
SCHED_METROPOLICE_ESTABLISH_STITCH_LINE_OF_FIRE,
SCHED_METROPOLICE_INVESTIGATE_SOUND,
SCHED_METROPOLICE_WARN_AND_ARREST_ENEMY,
SCHED_METROPOLICE_ARREST_ENEMY,
SCHED_METROPOLICE_ENEMY_RESISTING_ARREST,
SCHED_METROPOLICE_WARN_TARGET,
SCHED_METROPOLICE_HARASS_TARGET,
SCHED_METROPOLICE_SUPPRESS_TARGET,
SCHED_METROPOLICE_RETURN_FROM_HARASS,
SCHED_METROPOLICE_SHOVE,
SCHED_METROPOLICE_ACTIVATE_BATON,
SCHED_METROPOLICE_DEACTIVATE_BATON,
SCHED_METROPOLICE_ALERT_FACE_BESTSOUND,
SCHED_METROPOLICE_RETURN_TO_PRECHASE,
SCHED_METROPOLICE_SMASH_PROP,
};
enum
{
TASK_METROPOLICE_HARASS = BaseClass::NEXT_TASK,
TASK_METROPOLICE_DIE_INSTANTLY,
TASK_METROPOLICE_BURST_ATTACK,
TASK_METROPOLICE_STOP_FIRE_BURST,
TASK_METROPOLICE_AIM_STITCH_AT_PLAYER,
TASK_METROPOLICE_AIM_STITCH_AT_AIRBOAT,
TASK_METROPOLICE_AIM_STITCH_TIGHTLY,
TASK_METROPOLICE_AIM_STITCH_IN_FRONT_OF_AIRBOAT,
TASK_METROPOLICE_AIM_STITCH_ALONG_SIDE_OF_AIRBOAT,
TASK_METROPOLICE_AIM_STITCH_BEHIND_AIRBOAT,
TASK_METROPOLICE_RELOAD_FOR_BURST,
TASK_METROPOLICE_GET_PATH_TO_STITCH,
TASK_METROPOLICE_RESET_LEDGE_CHECK_TIME,
TASK_METROPOLICE_GET_PATH_TO_BESTSOUND_LOS,
TASK_METROPOLICE_AIM_WEAPON_AT_ENEMY,
TASK_METROPOLICE_ARREST_ENEMY,
TASK_METROPOLICE_LEAD_ARREST_ENEMY,
TASK_METROPOLICE_SIGNAL_FIRING_TIME,
TASK_METROPOLICE_ACTIVATE_BATON,
TASK_METROPOLICE_WAIT_FOR_SENTENCE,
TASK_METROPOLICE_GET_PATH_TO_PRECHASE,
TASK_METROPOLICE_CLEAR_PRECHASE,
};
private:
int m_iPistolClips; // How many clips the cop has in reserve
int m_iManhacks; // How many manhacks the cop has
bool m_fWeaponDrawn; // Is my weapon drawn? (ready to use)
bool m_bSimpleCops; // The easy version of the cops
int m_LastShootSlot;
CRandSimTimer m_TimeYieldShootSlot;
CSimpleSimTimer m_BatonSwingTimer;
CSimpleSimTimer m_NextChargeTimer;
// All related to burst firing
Vector m_vecBurstTargetPos;
Vector m_vecBurstDelta;
int m_nBurstHits;
int m_nMaxBurstHits;
int m_nBurstReloadCount;
Vector m_vecBurstLineOfDeathDelta;
Vector m_vecBurstLineOfDeathOrigin;
int m_nBurstMode;
int m_nBurstSteerMode;
float m_flBurstSteerDistance;
float m_flBurstPredictTime;
Vector m_vecBurstPredictedVelocityDir;
float m_vecBurstPredictedSpeed;
float m_flValidStitchTime;
float m_flNextLedgeCheckTime;
float m_flTaskCompletionTime;
bool m_bShouldActivateBaton;
float m_flBatonDebounceTime; // Minimum amount of time before turning the baton off
float m_flLastPhysicsFlinchTime;
float m_flLastDamageFlinchTime;
// Sentences
float m_flNextPainSoundTime;
float m_flNextLostSoundTime;
int m_nIdleChatterType;
bool m_bPlayerIsNear;
// Policing state
bool m_bPlayerTooClose;
bool m_bKeepFacingPlayer;
float m_flChasePlayerTime;
Vector m_vecPreChaseOrigin;
float m_flPreChaseYaw;
int m_nNumWarnings;
int m_iNumPlayerHits;
// Outputs
COutputEvent m_OnStunnedPlayer;
COutputEvent m_OnCupCopped;
AIHANDLE m_hManhack;
CHandle<CPhysicsProp> m_hBlockingProp;
CAI_ActBusyBehavior m_ActBusyBehavior;
CAI_StandoffBehavior m_StandoffBehavior;
CAI_AssaultBehavior m_AssaultBehavior;
CAI_FuncTankBehavior m_FuncTankBehavior;
CAI_RappelBehavior m_RappelBehavior;
CAI_PolicingBehavior m_PolicingBehavior;
CAI_FollowBehavior m_FollowBehavior;
CAI_Sentence< CNPC_MetroPolice > m_Sentences;
int m_nRecentDamage;
float m_flRecentDamageTime;
// The last hit direction, measured as a yaw relative to our orientation
float m_flLastHitYaw;
static float gm_flTimeLastSpokePeek;
public:
DEFINE_CUSTOM_AI;
};
#endif // NPC_METROPOLICE_H