aboutsummaryrefslogtreecommitdiff
path: root/mp/src/game/server/hl2/npc_metropolice.h
blob: 544fc68b7eb394c86fa3d17b635f663a56e99938 (plain) (blame)
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