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
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
|
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef NPC_STRIDER_H
#define NPC_STRIDER_H
#include "ai_blended_movement.h"
#include "ai_pathfinder.h"
#include "ai_navigator.h"
#include "ai_utils.h"
#include "smoke_trail.h"
#include "physics_bone_follower.h"
#include "physics_prop_ragdoll.h"
#if defined( _WIN32 )
#pragma once
#endif
#include "tier0/memdbgon.h"
class CNPC_Strider;
class CNPC_Bullseye;
class CStriderMinigun;
//-----------------------------------------------------------------------------
//
// Support for moving Strider air nodes to the correct Z for the Strider
// regardless of Hammer placement
//
//-----------------------------------------------------------------------------
class CAI_Network;
class CAI_Node;
struct StriderMinigunViewcone_t;
struct AI_EnemyInfo_t;
void AdjustStriderNodePosition( CAI_Network *pNetwork, CAI_Node *pNode );
//-----------------------------------------------------------------------------
//
// Strider Minigun
//
//-----------------------------------------------------------------------------
abstract_class IMinigunHost
{
public:
virtual void ShootMinigun( const Vector *pTarget, float aimError, const Vector &vecSpread = vec3_origin ) = 0;
virtual void UpdateMinigunControls( float &yaw, float &pitch ) = 0;
virtual void GetViewCone( StriderMinigunViewcone_t &cone ) = 0;
virtual void NewTarget() = 0;
virtual void OnMinigunStartShooting( CBaseEntity *pTarget ) = 0;
virtual void OnMinigunStopShooting( CBaseEntity *pTarget ) = 0;
virtual CAI_BaseNPC *GetEntity() = 0;
};
abstract_class IStriderMinigunHost : public IMinigunHost
{
public:
virtual float GetMinigunRateOfFire() = 0;
virtual float GetMinigunOnTargetTime() = 0;
virtual float GetMinigunShootDuration() = 0;
virtual float GetMinigunShootDowntime() = 0;
virtual float GetMinigunShootVariation() = 0;
};
//-----------------------------------------------------------------------------
//
// npc_strider
//
//-----------------------------------------------------------------------------
const int NUM_STRIDER_IK_TARGETS = 6;
//---------------------------------------------------------
class CNPC_Strider : public CAI_BlendingHost<CAI_BaseNPC>,
public IStriderMinigunHost
{
DECLARE_CLASS( CNPC_Strider, CAI_BaseNPC );
DECLARE_SERVERCLASS();
public:
CNPC_Strider();
~CNPC_Strider();
//---------------------------------
void Precache();
void Spawn();
bool CreateVPhysics();
void InitBoneFollowers( void );
void PostNPCInit();
void Activate();
void UpdateOnRemove();
void InitBoneControllers();
void OnRestore();
Class_T Classify();
bool ShouldAttractAutoAim( CBaseEntity *pAimingEnt );
virtual float GetAutoAimRadius() { return 80.0f; }
int DrawDebugTextOverlays();
void UpdateEfficiency( bool bInPVS ) { SetEfficiency( ( GetSleepState() != AISS_AWAKE ) ? AIE_DORMANT : AIE_NORMAL ); SetMoveEfficiency( AIME_NORMAL ); }
virtual bool ShouldProbeCollideAgainstEntity( CBaseEntity *pEntity );
//---------------------------------
virtual Vector GetNodeViewOffset() { return BaseClass::GetDefaultEyeOffset(); }
Vector EyePosition();
const Vector & GetViewOffset();
Vector EyePositionCrouched() { return GetAbsOrigin() - Vector( 0, 0, 330 ); }
//---------------------------------
// CBaseAnimating
void CalculateIKLocks( float currentTime );
float GetIdealAccel() const { return GetIdealSpeed(); }
//---------------------------------
// Behavior
//---------------------------------
void NPCThink();
void PrescheduleThink();
void GatherConditions();
void CheckFlinches() {} // Strider handles on own
void GatherHeightConditions( const Vector &vTestPos, CBaseEntity *pEntity );
void OnStateChange( NPC_STATE oldState, NPC_STATE newState );
void BuildScheduleTestBits();
int SelectSchedule();
int TranslateSchedule( int scheduleType );
void StartTask( const Task_t *pTask );
void RunTask( const Task_t *pTask );
bool HandleInteraction( int interactionType, void *data, CBaseCombatCharacter* sourceEnt );
void HandleAnimEvent( animevent_t *pEvent );
Disposition_t IRelationType( CBaseEntity *pTarget );
void AddEntityRelationship( CBaseEntity *pEntity, Disposition_t nDisposition, int nPriority );
bool ScheduledMoveToGoalEntity( int scheduleType, CBaseEntity *pGoalEntity, Activity movementActivity );
bool ScheduledFollowPath( int scheduleType, CBaseEntity *pPathStart, Activity movementActivity );
//---------------------------------
// Inputs
//---------------------------------
void InputSetMinigunTime( inputdata_t &inputdata );
void InputSetMinigunTarget( inputdata_t &inputdata );
void InputDisableMinigun( inputdata_t &inputdata );
void InputEnableMinigun( inputdata_t &inputdata );
void InputSetCannonTarget( inputdata_t &inputdata );
void InputFlickRagdoll( inputdata_t &inputdata );
void InputDisableCollisionWith( inputdata_t &inputdata );
void InputEnableCollisionWith( inputdata_t &inputdata );
void InputCrouch( inputdata_t &inputdata );
void InputCrouchInstantly( inputdata_t &inputdata );
void InputStand( inputdata_t &inputdata );
void InputSetHeight( inputdata_t &inputdata );
void InputSetTargetPath( inputdata_t &inputdata );
void InputClearTargetPath( inputdata_t &inputdata );
void InputDisableCrouchWalk( inputdata_t &inputdata );
void InputEnableCrouchWalk( inputdata_t &inputdata );
void InputEnableAggressiveBehavior( inputdata_t &inputdata );
void InputDisableAggressiveBehavior( inputdata_t &inputdata );
void InputStopShootingMinigunForSeconds( inputdata_t &inputdata );
void InputDisableCrouch( inputdata_t &inputdata );
void InputDisableMoveToLOS( inputdata_t &inputdata );
void InputExplode( inputdata_t &inputdata );
void InputScaleGroundSpeed( inputdata_t &inputdata );
//---------------------------------
// Combat
//---------------------------------
bool HasPass() { return m_PlayerFreePass.HasPass(); }
bool FVisible( CBaseEntity *pEntity, int traceMask = MASK_BLOCKLOS, CBaseEntity **ppBlocker = NULL );
Vector BodyTarget( const Vector &posSrc, bool bNoisy );
bool IsValidEnemy( CBaseEntity *pTarget );
bool UpdateEnemyMemory( CBaseEntity *pEnemy, const Vector &position, CBaseEntity *pInformer = NULL );
float StriderEnemyDistance( CBaseEntity *pEnemy );
bool FCanCheckAttacks();
int RangeAttack2Conditions( float flDot, float flDist );
int MeleeAttack1Conditions( float flDot, float flDist );
int MeleeAttack2Conditions( float flDot, float flDist );
bool WeaponLOSCondition(const Vector &ownerPos, const Vector &targetPos, bool bSetConditions);
bool CurrentWeaponLOSCondition(const Vector &targetPos, bool bSetConditions);
bool IsValidShootPosition ( const Vector &vecCoverLocation, CAI_Node *pNode, CAI_Hint const *pHint );
bool TestShootPosition(const Vector &vecShootPos, const Vector &targetPos );
Vector Weapon_ShootPosition();
void MakeTracer( const Vector &vecTracerSrc, const trace_t &tr, int iTracerType );
void DoImpactEffect( trace_t &tr, int nDamageType );
void DoMuzzleFlash( void );
bool CanShootThrough( const trace_t &tr, const Vector &vecTarget );
void CreateFocus();
CNPC_Bullseye * GetFocus();
bool GetWeaponLosZ( const Vector &vOrigin, float minZ, float maxZ, float increment, CBaseEntity *pTarget, float *pResult );
//---------------------------------
// Sounds & speech
//---------------------------------
void AlertSound();
void PainSound( const CTakeDamageInfo &info );
void DeathSound( const CTakeDamageInfo &info );
void HuntSound();
//---------------------------------
// Damage handling
//---------------------------------
void TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator );
int OnTakeDamage_Alive( const CTakeDamageInfo &info );
int TakeDamageFromCombineBall( const CTakeDamageInfo &info );
void Event_Killed( const CTakeDamageInfo &info );
void RagdollDeathEffect( CRagdollProp *pRagdoll, float flDuration );
bool BecomeRagdoll( const CTakeDamageInfo &info, const Vector &forceVector );
void StartSmoking();
void StopSmoking( float flDelay = 0.1 );
bool IsSmoking() { return m_hSmoke != NULL; }
void Explode();
//---------------------------------
// Posture
//---------------------------------
float GetMaxHeightModel() const { return 500.0; }
float GetMaxHeight() const { return 490.0; }
float GetMinHeight() const { return 200.0; }
float GetHeightRange() const { return GetMaxHeight() - GetMinHeight(); }
void SetHeight( float h );
float GetHeight() { return GetPoseParameter( gm_BodyHeightPoseParam ); }
void SetIdealHeight( float h );
void SetAbsIdealHeight( float z );
float GetIdealHeight() { return m_idealHeight; }
Vector GetAdjustedOrigin() { Vector result = GetAbsOrigin(); result.z -= GetMaxHeightModel() - GetHeight(); return result; }
bool IsInCrouchedPosture() { return GetIdealHeight() < GetMaxHeight() * .5; }
bool IsInStandingPosture() { return !IsInCrouchedPosture(); }
bool IsStriderCrouching();
bool IsStriderStanding();
void SetupGlobalModelData();
virtual bool CanBecomeServerRagdoll( void ) { return false; }
//---------------------------------
// Navigation & Movement
//---------------------------------
class CNavigator : public CAI_ComponentWithOuter<CNPC_Strider, CAI_Navigator>
{
typedef CAI_ComponentWithOuter<CNPC_Strider, CAI_Navigator> BaseClass;
public:
CNavigator( CNPC_Strider *pOuter )
: BaseClass( pOuter )
{
}
void MoveCalcBaseGoal( AILocalMoveGoal_t *pMoveGoal );
bool MoveUpdateWaypoint( AIMoveResult_t *pResult );
bool DoFindPathToPos();
bool ShouldOptimizeInitialPathSegment( AI_Waypoint_t *pFirstWaypoint );
bool GetStoppingPath( CAI_WaypointList *pClippedWaypoints );
};
class CPathfinder : public CAI_Pathfinder
{
typedef CAI_Pathfinder BaseClass;
public:
CPathfinder( CNPC_Strider *pOuter ) : BaseClass( pOuter ) {}
virtual bool CanUseLocalNavigation() { return false; }
};
friend class CNavigator;
friend void AdjustStriderNodePosition( CAI_Network *pNetwork, CAI_Node *pNode );
bool OverrideMove( float flInterval );
void MaintainTurnActivity( void );
bool IsUnusableNode(int iNodeID, CAI_Hint *pHint); // Override for special NPC behavior
void TranslateNavGoal( CBaseEntity *pEnemy, Vector &chasePosition );
bool HasPendingTargetPath();
void SetTargetPath();
float GetDefaultNavGoalTolerance();
void OnMovementComplete();
float GetSequenceGroundSpeed( CStudioHdr *pStudioHdr, int iSequence );
float MaxYawSpeed();
CAI_Navigator * CreateNavigator() { return new CNavigator( this ); }
CAI_Pathfinder *CreatePathfinder() { return new CPathfinder( this ); }
//---------------------------------
// Minigun
//---------------------------------
void ShootMinigun( const Vector *pTarget, float aimError, const Vector &vecSpread = vec3_origin );
void UpdateMinigunControls( float &yaw, float &pitch );
void GetViewCone( StriderMinigunViewcone_t &cone );
void NewTarget() { m_flTargetAcquiredTime = gpGlobals->curtime; }
void OnMinigunStartShooting( CBaseEntity *pTarget ) {};
void OnMinigunStopShooting( CBaseEntity *pTarget );
float GetMinigunRateOfFire();
float GetMinigunOnTargetTime();
float GetMinigunShootDuration();
float GetMinigunShootDowntime();
float GetMinigunShootVariation();
CAI_BaseNPC * GetEntity() { return this; }
bool IsUsingAggressiveBehavior() { return m_bUseAggressiveBehavior; }
//---------------------------------
// Cannon
//---------------------------------
Vector CannonPosition();
CBaseEntity * GetCannonTarget();
bool HasCannonTarget() const;
bool IsCannonTarget( CBaseEntity *pTarget ) const;
bool AimCannonAt( CBaseEntity *pEntity, float flInterval );
void FireCannon();
void CannonHitThink();
//---------------------------------
// Collision handling
//---------------------------------
void VPhysicsShadowCollision( int index, gamevcollisionevent_t *pEvent );
bool TestCollision( const Ray_t &ray, unsigned int mask, trace_t& trace );
// Conservative collision volumes
static float gm_strideLength;
#ifdef HL2_EPISODIC
void StriderBusterAttached( CBaseEntity *pAttached );
void StriderBusterDetached( CBaseEntity *pAttached );
#endif // HL2_EPISODIC
public:
//---------------------------------
// Misc
//---------------------------------
bool CarriedByDropship();
void CarriedThink();
//---------------------------------
// Foot handling
//---------------------------------
Vector LeftFootHit( float eventtime );
Vector RightFootHit( float eventtime );
Vector BackFootHit( float eventtime );
void StompHit( int followerBoneIndex );
void FootFX( const Vector &origin );
Vector CalculateStompHitPosition( CBaseEntity *pEnemy );
bool IsLegBoneFollower( CBoneFollower *pFollower );
CBoneFollower *GetBoneFollowerByIndex( int nIndex );
int GetBoneFollowerIndex( CBoneFollower *pFollower );
protected:
// Because the strider is a leaf class, we can use
// static variables to store this information, and save some memory.
// Should the strider end up having inheritors, their activate may
// stomp these numbers, in which case you should make these ordinary members
// again.
//
// The strider also caches some pose parameters in SetupGlobalModelData().
static int m_poseMiniGunYaw, m_poseMiniGunPitch;
static bool m_sbStaticPoseParamsLoaded;
virtual void PopulatePoseParameters( void );
private:
bool ShouldExplodeFromDamage( const CTakeDamageInfo &info );
bool m_bExploding;
//-----------------------------------------------------
// Conditions, Schedules, Tasks
//-----------------------------------------------------
enum
{
SCHED_STRIDER_RANGE_ATTACK1 = BaseClass::NEXT_SCHEDULE,
SCHED_STRIDER_RANGE_ATTACK2, // Immolator
SCHED_STRIDER_CROUCH,
SCHED_STRIDER_STAND,
SCHED_STRIDER_DODGE,
SCHED_STRIDER_STOMPL,
SCHED_STRIDER_STOMPR,
SCHED_STRIDER_FLICKL,
SCHED_STRIDER_FLICKR,
SCHED_STRIDER_HUNT,
SCHED_STRIDER_DIE,
SCHED_STRIDER_ATTACK_CANNON_TARGET,
SCHED_STRIDER_CHASE_ENEMY,
SCHED_STRIDER_COMBAT_FACE,
SCHED_STRIDER_AGGRESSIVE_COMBAT_STAND,
SCHED_STRIDER_ESTABLISH_LINE_OF_FIRE_CANNON,
SCHED_STRIDER_FALL_TO_GROUND,
TASK_STRIDER_AIM = BaseClass::NEXT_TASK,
TASK_STRIDER_DODGE,
TASK_STRIDER_STOMP,
TASK_STRIDER_BREAKDOWN,
TASK_STRIDER_START_MOVING,
TASK_STRIDER_REFRESH_HUNT_PATH,
TASK_STRIDER_GET_PATH_TO_CANNON_TARGET,
TASK_STRIDER_FACE_CANNON_TARGET,
TASK_STRIDER_SET_HEIGHT,
TASK_STRIDER_GET_PATH_TO_CANNON_LOS,
TASK_STRIDER_SET_CANNON_HEIGHT,
TASK_STRIDER_FIRE_CANNON,
TASK_STRIDER_FALL_TO_GROUND,
COND_STRIDER_DO_FLICK = BaseClass::NEXT_CONDITION,
COND_TRACK_PATH_GO,
COND_STRIDER_SHOULD_CROUCH,
COND_STRIDER_SHOULD_STAND,
COND_STRIDER_MINIGUN_SHOOTING,
COND_STRIDER_MINIGUN_NOT_SHOOTING,
COND_STRIDER_HAS_CANNON_TARGET,
COND_STRIDER_ENEMY_UPDATED,
COND_STRIDER_HAS_LOS_Z,
};
string_t m_iszStriderBusterName;
string_t m_iszMagnadeClassname;
string_t m_iszHunterClassname;
CStriderMinigun *m_pMinigun;
int m_miniGunAmmo;
int m_miniGunDirectAmmo;
float m_nextShootTime;
float m_nextStompTime;
float m_ragdollTime;
float m_miniGunShootDuration;
float m_aimYaw;
float m_aimPitch;
Vector m_blastHit;
Vector m_blastNormal;
CNetworkVector( m_vecHitPos );
CNetworkArray( Vector, m_vecIKTarget, NUM_STRIDER_IK_TARGETS );
CRandSimTimer m_PostureAnimationTimer;
EHANDLE m_hRagdoll;
EHANDLE m_hCannonTarget;
CSimpleSimTimer m_AttemptCannonLOSTimer;
float m_flSpeedScale;
float m_flTargetSpeedScale;
CSimpleSimTimer m_LowZCorrectionTimer;
// Contained Bone Follower manager
CBoneFollowerManager m_BoneFollowerManager;
int m_BodyTargetBone;
bool m_bDisableBoneFollowers;
int m_iVisibleEnemies;
float m_flTargetAcquiredTime;
bool m_bCrouchLocked; // Designer made the strider crouch. Don't let the AI stand him up.
bool m_bNoCrouchWalk;
bool m_bDontCrouch;
bool m_bNoMoveToLOS;
bool m_bFastCrouch;
bool m_bMinigunEnabled; // If false, minigun disabled by level designer until further notice.
float m_idealHeight;
float m_HeightVelocity;
// FIXME: move to a base class to handle turning for blended movement derived characters
float m_prevYaw;
float m_doTurn;
float m_doLeft;
float m_doRight;
float m_flNextTurnAct;
string_t m_strTrackName;
EHANDLE m_hFocus;
float m_flTimeLastAlertSound;
float m_flTimeNextHuntSound;
bool m_bUseAggressiveBehavior;
float m_flTimePlayerMissileDetected;
EHANDLE m_hPlayersMissile;
bool m_bMinigunUseDirectFire;
CHandle<SmokeTrail> m_hSmoke;
CSimpleSimTimer m_EnemyUpdatedTimer;
CAI_FreePass m_PlayerFreePass;
#ifdef HL2_EPISODIC
CUtlVector< EHANDLE > m_hAttachedBusters; // List of busters attached to us
#endif // HL2_EPISODIC
static float gm_zCannonDist;
static float gm_zMinigunDist;
static Vector gm_vLocalRelativePositionCannon;
static Vector gm_vLocalRelativePositionMinigun;
static int gm_YawControl;
static int gm_PitchControl;
static int gm_CannonAttachment;
static int gm_BodyHeightPoseParam;
DEFINE_CUSTOM_AI;
DECLARE_DATADESC();
};
//-----------------------------------------------------------------------------
//---------------------------------------------------------
enum StriderMinigunPeg_t
{
MINIGUN_PEGGED_DONT_CARE = 0,
MINIGUN_PEGGED_UP,
MINIGUN_PEGGED_DOWN,
MINIGUN_PEGGED_LEFT,
MINIGUN_PEGGED_RIGHT,
};
//---------------------------------------------------------
struct StriderMinigunViewcone_t
{
Vector origin;
Vector axis;
float cosAngle;
float length;
};
//---------------------------------------------------------
struct StriderMinigunAnimController_t
{
float current;
float target;
float rate;
void Update( float dt, bool approach = true )
{
if( approach )
{
current = Approach( target, current, rate * dt );
}
else
{
current = target;
}
}
void Random( float minTarget, float maxTarget, float minRate, float maxRate )
{
target = random->RandomFloat( minTarget, maxTarget );
rate = random->RandomFloat( minRate, maxRate );
}
};
//---------------------------------------------------------
class CStriderMinigun
{
public:
DECLARE_DATADESC();
void Init();
void SetTarget( IStriderMinigunHost *pHost, CBaseEntity *pTarget, bool bOverrideEnemy = false );
CBaseEntity *GetTarget() { return m_hTarget.Get(); }
void Think( IStriderMinigunHost *pHost, float dt );
void SetState( int newState );
bool ShouldFindTarget( IMinigunHost *pHost );
void AimAtPoint( IStriderMinigunHost *pHost, const Vector &vecPoint, bool bSnap = false );
void AimAtTarget( IStriderMinigunHost *pHost, CBaseEntity *pTarget, bool bSnap = false );
void ShootAtTarget( IStriderMinigunHost *pHost, CBaseEntity *pTarget, float shootTime );
void StartShooting( IStriderMinigunHost *pHost, CBaseEntity *pTarget, float duration );
void ExtendShooting( float timeExtend );
void SetShootDuration( float duration );
void StopShootingForSeconds( IStriderMinigunHost *pHost, CBaseEntity *pTarget, float duration );
bool IsPegged( int dir = MINIGUN_PEGGED_DONT_CARE );
bool CanStartShooting( IStriderMinigunHost *pHost, CBaseEntity *pTargetEnt );
float GetBurstTimeRemaining() { return m_burstTime - gpGlobals->curtime; }
void RecordShotOnTarget() { m_iOnTargetShots++; }
void ClearOnTarget() { m_iOnTargetShots = 0; }
bool IsOnTarget( int numShots = 0 ) { return ( numShots == 0 ) ? (m_iOnTargetShots > 0) : (m_iOnTargetShots >= numShots); }
void Enable( IMinigunHost *pHost, bool enable );
float GetAimError();
enum minigunstates_t
{
MINIGUN_OFF = 0,
MINIGUN_SHOOTING = 1,
};
int GetState() { return m_minigunState; }
bool IsShooting() { return GetState() == MINIGUN_SHOOTING; }
private:
bool m_enable;
int m_minigunState;
float m_nextBulletTime; // Minigun is shooting, when can I fire my next bullet?
float m_burstTime; // If firing, how long till done? If not, how long till I can?
float m_nextTwitchTime;
int m_randomState;
EHANDLE m_hTarget;
StriderMinigunAnimController_t m_yaw;
StriderMinigunAnimController_t m_pitch;
bool m_bWarnedAI;
float m_shootDuration;
Vector m_vecAnchor; // A burst starts here and goes to the target's orgin.
bool m_bOverrideEnemy; // The minigun wants something other than the Strider's enemy as a target right now.
Vector m_vecLastTargetPos; // Last place minigun saw the target.
int m_iOnTargetShots;
};
class CSparkTrail : public CPointEntity
{
DECLARE_CLASS( CSparkTrail, CPointEntity );
void Spawn( void );
void SparkThink( void );
virtual void Precache();
DECLARE_DATADESC();
};
#include "tier0/memdbgoff.h"
#endif // NPC_STRIDER_H
//=============================================================================
|