//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // //=============================================================================// #ifndef NPC_MANHACK_H #define NPC_MANHACK_H #ifdef _WIN32 #pragma once #endif #include "Sprite.h" #include "SpriteTrail.h" #include "ai_basenpc_physicsflyer.h" #include "player_pickup.h" // Start with the engine off and folded up. #define SF_MANHACK_PACKED_UP (1 << 16) #define SF_MANHACK_NO_DAMAGE_EFFECTS (1 << 17) #define SF_MANHACK_USE_AIR_NODES (1 << 18) #define SF_MANHACK_CARRIED (1 << 19) // Being carried by a metrocop #define SF_MANHACK_NO_DANGER_SOUNDS (1 << 20) enum { MANHACK_EYE_STATE_IDLE, MANHACK_EYE_STATE_CHASE, MANHACK_EYE_STATE_CHARGE, MANHACK_EYE_STATE_STUNNED, }; //----------------------------------------------------------------------------- // Attachment points. //----------------------------------------------------------------------------- #define MANHACK_GIB_HEALTH 30 #define MANHACK_INACTIVE_HEALTH 25 #define MANHACK_MAX_SPEED 500 #define MANHACK_BURST_SPEED 650 #define MANHACK_NPC_BURST_SPEED 800 //----------------------------------------------------------------------------- // Movement parameters. //----------------------------------------------------------------------------- #define MANHACK_WAYPOINT_DISTANCE \ 25 // Distance from waypoint that counts as arrival. class CSprite; class SmokeTrail; class CSoundPatch; //----------------------------------------------------------------------------- // Manhack //----------------------------------------------------------------------------- class CNPC_Manhack : public CNPCBaseInteractive, public CDefaultPlayerPickupVPhysics { DECLARE_CLASS(CNPC_Manhack, CNPCBaseInteractive); DECLARE_SERVERCLASS(); public: CNPC_Manhack(); ~CNPC_Manhack(); Class_T Classify(void); bool CorpseGib(const CTakeDamageInfo &info); void Event_Dying(void); void Event_Killed(const CTakeDamageInfo &info); int OnTakeDamage_Alive(const CTakeDamageInfo &info); int OnTakeDamage_Dying(const CTakeDamageInfo &info); void TraceAttack(const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator); void TranslateNavGoal(CBaseEntity *pEnemy, Vector &chasePosition); float GetDefaultNavGoalTolerance(); void UpdateOnRemove(void); void KillSprites(float flDelay); void OnStateChange(NPC_STATE OldState, NPC_STATE NewState); virtual bool CreateVPhysics(void); virtual void DeathSound(const CTakeDamageInfo &info); virtual bool ShouldGib(const CTakeDamageInfo &info); Activity NPC_TranslateActivity(Activity baseAct); virtual int TranslateSchedule(int scheduleType); int MeleeAttack1Conditions(float flDot, float flDist); void HandleAnimEvent(animevent_t *pEvent); bool OverrideMove(float flInterval); void MoveToTarget(float flInterval, const Vector &MoveTarget); void MoveExecute_Alive(float flInterval); void MoveExecute_Dead(float flInterval); int MoveCollisionMask(void); void TurnHeadRandomly(float flInterval); void CrashTouch(CBaseEntity *pOther); void StartEngine(bool fStartSound); virtual Vector BodyTarget(const Vector &posSrc, bool bNoisy = true) { return WorldSpaceCenter(); } virtual float GetHeadTurnRate(void) { return 45.0f; } // Degrees per second void CheckCollisions(float flInterval); virtual void GatherEnemyConditions(CBaseEntity *pEnemy); void PlayFlySound(void); virtual void StopLoopingSounds(void); void Precache(void); void RunTask(const Task_t *pTask); void Spawn(void); void Activate(); void StartTask(const Task_t *pTask); void BladesInit(); void SoundInit(void); void StartEye(void); bool HandleInteraction(int interactionType, void *data, CBaseCombatCharacter *sourceEnt); void PostNPCInit(void); void GatherConditions(); void PrescheduleThink(void); void SpinBlades(float flInterval); void Slice(CBaseEntity *pHitEntity, float flInterval, trace_t &tr); void Bump(CBaseEntity *pHitEntity, float flInterval, trace_t &tr); void Splash(const Vector &vecSplashPos); float ManhackMaxSpeed(void); virtual void VPhysicsShadowCollision(int index, gamevcollisionevent_t *pEvent); void VPhysicsCollision(int index, gamevcollisionevent_t *pEvent); void HitPhysicsObject(CBaseEntity *pOther); virtual void ClampMotorForces(Vector &linear, AngularImpulse &angular); unsigned int PhysicsSolidMaskForEntity(void) const; // Create smoke trail! void CreateSmokeTrail(); void DestroySmokeTrail(); void Ignite(float flFlameLifetime, bool bNPCOnly, float flSize, bool bCalledByLevelDesigner) { return; } void InputDisableSwarm(inputdata_t &inputdata); void InputUnpack(inputdata_t &inputdata); // CDefaultPlayerPickupVPhysics virtual void OnPhysGunPickup(CBasePlayer *pPhysGunUser, PhysGunPickup_t reason); virtual void OnPhysGunDrop(CBasePlayer *pPhysGunUser, PhysGunDrop_t Reason); CBasePlayer *HasPhysicsAttacker(float dt); float GetMaxEnginePower(); // INPCInteractive Functions virtual bool CanInteractWith(CAI_BaseNPC *pUser) { return false; } // Disabled for now (sjb) virtual bool HasBeenInteractedWith() { return m_bHackedByAlyx; } virtual void NotifyInteraction(CAI_BaseNPC *pUser) { // Turn the sprites off and on again so their colors will change. KillSprites(0.0f); m_bHackedByAlyx = true; StartEye(); } virtual void InputPowerdown(inputdata_t &inputdata) { m_iHealth = 0; } DEFINE_CUSTOM_AI; DECLARE_DATADESC(); private: bool IsInEffectiveTargetZone(CBaseEntity *pTarget); void MaintainGroundHeight(void); void StartBurst(const Vector &vecDirection); void StopBurst(bool bInterruptSchedule = false); void UpdatePanels(void); void SetEyeState(int state); void ShowHostile(bool hostile = true); bool IsFlyingActivity(Activity baseAct); // Computes the slice bounce velocity void ComputeSliceBounceVelocity(CBaseEntity *pHitEntity, trace_t &tr); // Take damage from being thrown by a physcannon void TakeDamageFromPhyscannon(CBasePlayer *pPlayer); // Take damage from a vehicle: void TakeDamageFromVehicle(int index, gamevcollisionevent_t *pEvent); // Take damage from physics impacts void TakeDamageFromPhysicsImpact(int index, gamevcollisionevent_t *pEvent); // Are we being held by the physcannon? bool IsHeldByPhyscannon(); void StartLoitering(const Vector &vecLoiterPosition); void StopLoitering() { m_vecLoiterPosition = vec3_invalid; m_fTimeNextLoiterPulse = gpGlobals->curtime; } bool IsLoitering() { return m_vecLoiterPosition != vec3_invalid; } void Loiter(); // // Movement variables. // Vector m_vForceVelocity; // Someone forced me to move Vector m_vTargetBanking; Vector m_vForceMoveTarget; // Will fly here float m_fForceMoveTime; // If time is less than this Vector m_vSwarmMoveTarget; // Will fly here float m_fSwarmMoveTime; // If time is less than this float m_fEnginePowerScale; // scale all thrust by this amount (usually 1.0!) float m_flNextEngineSoundTime; float m_flEngineStallTime; float m_flNextBurstTime; float m_flBurstDuration; Vector m_vecBurstDirection; float m_flWaterSuspendTime; int m_nLastSpinSound; // physics influence CHandle m_hPhysicsAttacker; float m_flLastPhysicsInfluenceTime; // Death float m_fSparkTime; float m_fSmokeTime; bool m_bDirtyPitch; // indicates whether we want the sound pitch // updated.(sjb) bool m_bShowingHostile; bool m_bBladesActive; bool m_bIgnoreClipbrushes; float m_flBladeSpeed; CSprite *m_pEyeGlow; CSprite *m_pLightGlow; CHandle m_hSmokeTrail; int m_iPanel1; int m_iPanel2; int m_iPanel3; int m_iPanel4; int m_nLastWaterLevel; bool m_bDoSwarmBehavior; bool m_bGib; bool m_bHeld; bool m_bHackedByAlyx; Vector m_vecLoiterPosition; float m_fTimeNextLoiterPulse; float m_flBumpSuppressTime; CNetworkVar(int, m_nEnginePitch1); CNetworkVar(int, m_nEnginePitch2); CNetworkVar(float, m_flEnginePitch1Time); CNetworkVar(float, m_flEnginePitch2Time); }; #endif // NPC_MANHACK_H