This repository has been archived on 2024-06-13. You can view files and clone it, but cannot push or open issues or pull requests.
2020-08-04 13:13:01 -04:00

505 lines
17 KiB
C++

//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef NPC_METROPOLICE_H
#define NPC_METROPOLICE_H
#ifdef _WIN32
#pragma once
#endif
#include "ai_baseactor.h"
#include "ai_basenpc.h"
#include "ai_behavior.h"
#include "ai_behavior_actbusy.h"
#include "ai_behavior_assault.h"
#include "ai_behavior_follow.h"
#include "ai_behavior_functank.h"
#include "ai_behavior_police.h"
#include "ai_behavior_rappel.h"
#include "ai_behavior_standoff.h"
#include "ai_goal_police.h"
#include "ai_sentence.h"
#include "props.h"
#include "rope.h"
#include "rope_shared.h"
class CNPC_MetroPolice;
class CNPC_MetroPolice : public CAI_BaseActor {
DECLARE_CLASS(CNPC_MetroPolice, CAI_BaseActor);
DECLARE_DATADESC();
public:
CNPC_MetroPolice();
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