diff options
Diffstat (limited to 'mp/src/game/server/hl2/npc_strider.h')
| -rw-r--r-- | mp/src/game/server/hl2/npc_strider.h | 1290 |
1 files changed, 645 insertions, 645 deletions
diff --git a/mp/src/game/server/hl2/npc_strider.h b/mp/src/game/server/hl2/npc_strider.h index 8673d339..dd645781 100644 --- a/mp/src/game/server/hl2/npc_strider.h +++ b/mp/src/game/server/hl2/npc_strider.h @@ -1,645 +1,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
-
-//=============================================================================
+//========= 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 + +//============================================================================= |