//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // //============================================================================= #ifndef NPC_BASESCANNER_H #define NPC_BASESCANNER_H #ifdef _WIN32 #pragma once #endif #include "ai_basenpc_physicsflyer.h" #include "cbase.h" #include "hl2_player.h" #include "player_pickup.h" #include "smoke_trail.h" #include "weapon_physcannon.h" //----------------------------------------------------------------------------- // States for the scanner's sound. //----------------------------------------------------------------------------- enum ScannerFlyMode_t { SCANNER_FLY_PHOTO = 0, // Fly close to photograph entity SCANNER_FLY_PATROL, // Fly slowly around the enviroment SCANNER_FLY_FAST, // Fly quickly around the enviroment SCANNER_FLY_CHASE, // Fly quickly around the enviroment SCANNER_FLY_SPOT, // Fly above enity in spotlight position SCANNER_FLY_ATTACK, // Get in my enemies face for spray or flash SCANNER_FLY_DIVE, // Divebomb - only done when dead SCANNER_FLY_FOLLOW, // Following a target }; enum ScannerInspectAct_t { SCANNER_INSACT_HANDS_UP, SCANNER_INSACT_SHOWARMBAND, }; // Sentences #define SCANNER_SENTENCE_ATTENTION 0 #define SCANNER_SENTENCE_HANDSUP 1 #define SCANNER_SENTENCE_PROCEED 2 #define SCANNER_SENTENCE_CURIOUS 3 // Scanner attack distances #define SCANNER_ATTACK_NEAR_DIST 150 // Fly attack min distance #define SCANNER_ATTACK_FAR_DIST 300 // Fly attack max distance #define SCANNER_ATTACK_RANGE 350 // Attack max distance #define SCANNER_ATTACK_MIN_DELAY 8 // Min time between attacks #define SCANNER_ATTACK_MAX_DELAY 12 // Max time between attacks #define SCANNER_EVADE_TIME 1 // How long to evade after take damage // Scanner movement vars #define SCANNER_BANK_RATE 30 #define SCANNER_MAX_SPEED 250 #define SCANNER_MAX_DIVE_BOMB_SPEED 2500 #define SCANNER_SQUAD_FLY_DIST 500 // How far to scanners stay apart #define SCANNER_SQUAD_HELP_DIST 4000 // How far will I fly to help //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- class CNPC_BaseScanner : public CAI_BasePhysicsFlyingBot, public CDefaultPlayerPickupVPhysics { DECLARE_CLASS(CNPC_BaseScanner, CAI_BasePhysicsFlyingBot); public: CNPC_BaseScanner(); void Spawn(void); virtual void UpdateEfficiency(bool bInPVS); Class_T Classify(void) { return (CLASS_SCANNER); } virtual float GetAutoAimRadius(); 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 Gib(void); void OnStateChange(NPC_STATE eOldState, NPC_STATE eNewState); void ClampMotorForces(Vector &linear, AngularImpulse &angular); int DrawDebugTextOverlays(void); virtual float GetHeadTurnRate(void); virtual void VPhysicsCollision(int index, gamevcollisionevent_t *pEvent); // CDefaultPlayerPickupVPhysics void OnPhysGunPickup(CBasePlayer *pPhysGunUser, PhysGunPickup_t reason); void OnPhysGunDrop(CBasePlayer *pPhysGunUser, PhysGunDrop_t Reason); bool ShouldPlayIdleSound(void); void IdleSound(void); void DeathSound(const CTakeDamageInfo &info); void AlertSound(void); void PainSound(const CTakeDamageInfo &info); virtual char *GetScannerSoundPrefix(void) { return ""; } void ScannerEmitSound(const char *pszSoundName); int MeleeAttack1Conditions(float flDot, float flDist); int SelectSchedule(void); void StartTask(const Task_t *pTask); void OnScheduleChange(void); void UpdateOnRemove(void); virtual float GetMaxSpeed(void); void PostRunStopMoving() { } // scanner can use "movement" activities but not be moving virtual bool CanBecomeServerRagdoll(void) { return false; } void SpeakSentence(int sentenceType); bool IsHeldByPhyscannon(void); // Inputs void InputSetFlightSpeed(inputdata_t &inputdata); void InputSetDistanceOverride(inputdata_t &inputdata); protected: virtual char *GetEngineSound(void) { return NULL; } void PlayFlySound(void); void SetBanking(float flInterval); void UpdateHead(float flInterval); inline CBaseEntity *EntityToWatch(void); bool IsEnemyPlayerInSuit(void); // Movement virtual bool OverridePathMove(CBaseEntity *pMoveTarget, float flInterval); virtual bool OverrideMove(float flInterval); Vector IdealGoalForMovement(const Vector &goalPos, const Vector &startPos, float idealRange, float idealHeight); virtual void AdjustScannerVelocity(void) { return; } virtual void MoveToAttack(float flInterval); virtual void MoveToTarget(float flInterval, const Vector &vecMoveTarget); virtual void MoveExecute_Alive(float flInterval); virtual float MinGroundDist(void) { return 64; } Vector VelocityToEvade(CBaseCombatCharacter *pEnemy); virtual float GetGoalDistance(void); // Divebombing virtual void AttackDivebomb(void); void DiveBombSoundThink(); void AttackDivebombCollide(float flInterval); void MoveToDivebomb(float flInterval); void BlendPhyscannonLaunchSpeed(); private: bool GetGoalDirection(Vector *vOut); void StartSmokeTrail(void); // Take damage from being thrown by a physcannon void TakeDamageFromPhyscannon(CBasePlayer *pPlayer); // Take damage from physics impacts void TakeDamageFromPhysicsImpact(int index, gamevcollisionevent_t *pEvent); // Do we have a physics attacker? CBasePlayer *HasPhysicsAttacker(float dt); virtual void StopLoopingSounds(void); public: // ------------------------ // Death Cleanup // ------------------------ CTakeDamageInfo m_KilledInfo; protected: ScannerFlyMode_t m_nFlyMode; // Pose parameters int m_nPoseTail; int m_nPoseDynamo; int m_nPoseFlare; int m_nPoseFaceVert; int m_nPoseFaceHoriz; bool m_bHasSpoken; // Movement float m_flFlyNoiseBase; float m_flEngineStallTime; float m_fNextFlySoundTime; Vector m_vecDiveBombDirection; // The direction we dive bomb. Calculated at // the moment of death. float m_flDiveBombRollForce; // Used for roll while dive bombing. float m_flGoalOverrideDistance; // Deriver scanner variables float m_flAttackNearDist; float m_flAttackFarDist; float m_flAttackRange; private: CSoundPatch *m_pEngineSound; // physics influence CHandle m_hPhysicsAttacker; float m_flLastPhysicsInfluenceTime; // Attacks SmokeTrail *m_pSmokeTrail; protected: DEFINE_CUSTOM_AI; // Custom interrupt conditions enum { COND_SCANNER_FLY_CLEAR = BaseClass::NEXT_CONDITION, COND_SCANNER_FLY_BLOCKED, COND_SCANNER_GRABBED_BY_PHYSCANNON, COND_SCANNER_RELEASED_FROM_PHYSCANNON, NEXT_CONDITION, }; // Custom schedules enum { SCHED_SCANNER_PATROL = BaseClass::NEXT_SCHEDULE, SCHED_SCANNER_ATTACK, SCHED_SCANNER_ATTACK_HOVER, SCHED_SCANNER_ATTACK_DIVEBOMB, SCHED_SCANNER_CHASE_ENEMY, SCHED_SCANNER_CHASE_TARGET, SCHED_SCANNER_FOLLOW_HOVER, SCHED_SCANNER_HELD_BY_PHYSCANNON, NEXT_SCHEDULE, }; // Custom tasks enum { TASK_SCANNER_SET_FLY_PATROL = BaseClass::NEXT_TASK, TASK_SCANNER_SET_FLY_CHASE, TASK_SCANNER_SET_FLY_ATTACK, TASK_SCANNER_SET_FLY_DIVE, NEXT_TASK, }; DECLARE_DATADESC(); }; #endif // NPC_BASESCANNER_H