diff options
Diffstat (limited to 'game/server/hl2/npc_strider.h')
| -rw-r--r-- | game/server/hl2/npc_strider.h | 645 |
1 files changed, 645 insertions, 0 deletions
diff --git a/game/server/hl2/npc_strider.h b/game/server/hl2/npc_strider.h new file mode 100644 index 0000000..dd64578 --- /dev/null +++ b/game/server/hl2/npc_strider.h @@ -0,0 +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 + +//============================================================================= |