|
|
//========= 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();
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
|