//========= 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 *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 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 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