1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
|
//========= 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
|