//========= Copyright Valve Corporation, All rights reserved. ============// #ifndef NPC_TURRET_FLOOR_H #define NPC_TURRET_FLOOR_H #ifdef _WIN32 #pragma once #endif #include "ai_basenpc.h" #include "player_pickup.h" #include "particle_system.h" //Turret states enum turretState_e { TURRET_SEARCHING, TURRET_AUTO_SEARCHING, TURRET_ACTIVE, TURRET_SUPPRESSING, TURRET_DEPLOYING, TURRET_RETIRING, TURRET_TIPPED, TURRET_SELF_DESTRUCTING, TURRET_STATE_TOTAL }; //Eye states enum eyeState_t { TURRET_EYE_SEE_TARGET, //Sees the target, bright and big TURRET_EYE_SEEKING_TARGET, //Looking for a target, blinking (bright) TURRET_EYE_DORMANT, //Not active TURRET_EYE_DEAD, //Completely invisible TURRET_EYE_DISABLED, //Turned off, must be reactivated before it'll deploy again (completely invisible) TURRET_EYE_ALARM, // On side, but warning player to pick it back up }; //Spawnflags // BUG: These all stomp Base NPC spawnflags. Any Base NPC code called by this // this class may have undesired side effects due to these being set. #define SF_FLOOR_TURRET_AUTOACTIVATE 0x00000020 #define SF_FLOOR_TURRET_STARTINACTIVE 0x00000040 #define SF_FLOOR_TURRET_FASTRETIRE 0x00000080 #define SF_FLOOR_TURRET_OUT_OF_AMMO 0x00000100 #define SF_FLOOR_TURRET_CITIZEN 0x00000200 // Citizen modified turret class CTurretTipController; class CBeam; class CSprite; //----------------------------------------------------------------------------- // Purpose: Floor turret //----------------------------------------------------------------------------- class CNPC_FloorTurret : public CNPCBaseInteractive, public CDefaultPlayerPickupVPhysics { DECLARE_CLASS( CNPC_FloorTurret, CNPCBaseInteractive ); public: CNPC_FloorTurret( void ); virtual void Precache( void ); virtual void Spawn( void ); virtual void Activate( void ); virtual bool CreateVPhysics( void ); virtual void UpdateOnRemove( void ); virtual int OnTakeDamage( const CTakeDamageInfo &info ); virtual void PlayerPenetratingVPhysics( void ); virtual int VPhysicsTakeDamage( const CTakeDamageInfo &info ); virtual bool CanBecomeServerRagdoll( void ) { return false; } #ifdef HL2_EPISODIC // We don't want to be NPCSOLID because we'll collide with NPC clips virtual unsigned int PhysicsSolidMaskForEntity( void ) const { return MASK_SOLID; } #endif // HL2_EPISODIC // Player pickup virtual void OnPhysGunPickup( CBasePlayer *pPhysGunUser, PhysGunPickup_t reason ); virtual void OnPhysGunDrop( CBasePlayer *pPhysGunUser, PhysGunDrop_t Reason ); virtual bool HasPreferredCarryAnglesForPlayer( CBasePlayer *pPlayer ); virtual QAngle PreferredCarryAngles( void ); virtual bool OnAttemptPhysGunPickup( CBasePlayer *pPhysGunUser, PhysGunPickup_t reason ); const char *GetTracerType( void ) { return "AR2Tracer"; } bool ShouldSavePhysics() { return true; } bool HandleInteraction( int interactionType, void *data, CBaseCombatCharacter *sourceEnt ); // Think functions virtual void Retire( void ); virtual void Deploy( void ); virtual void ActiveThink( void ); virtual void SearchThink( void ); virtual void AutoSearchThink( void ); virtual void TippedThink( void ); virtual void InactiveThink( void ); virtual void SuppressThink( void ); virtual void DisabledThink( void ); virtual void SelfDestructThink( void ); virtual void BreakThink( void ); virtual void HackFindEnemy( void ); virtual float GetAttackDamageScale( CBaseEntity *pVictim ); virtual Vector GetAttackSpread( CBaseCombatWeapon *pWeapon, CBaseEntity *pTarget ); // Do we have a physics attacker? CBasePlayer *HasPhysicsAttacker( float dt ); bool IsHeldByPhyscannon( ) { return VPhysicsGetObject() && (VPhysicsGetObject()->GetGameFlags() & FVPHYSICS_PLAYER_HELD); } // Use functions void ToggleUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); int ObjectCaps() { return BaseClass::ObjectCaps() | FCAP_IMPULSE_USE; } void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { CBasePlayer *pPlayer = ToBasePlayer( pActivator ); if ( pPlayer ) { pPlayer->PickupObject( this, false ); } } // Inputs void InputToggle( inputdata_t &inputdata ); void InputEnable( inputdata_t &inputdata ); void InputDisable( inputdata_t &inputdata ); void InputDepleteAmmo( inputdata_t &inputdata ); void InputRestoreAmmo( inputdata_t &inputdata ); void InputSelfDestruct( inputdata_t &inputdata ); virtual bool IsValidEnemy( CBaseEntity *pEnemy ); bool CanBeAnEnemyOf( CBaseEntity *pEnemy ); bool IsBeingCarriedByPlayer( void ) { return m_bCarriedByPlayer; } bool WasJustDroppedByPlayer( void ); int BloodColor( void ) { return DONT_BLEED; } float MaxYawSpeed( void ); virtual Class_T Classify( void ); Vector EyePosition( void ) { UpdateMuzzleMatrix(); Vector vecOrigin; MatrixGetColumn( m_muzzleToWorld, 3, vecOrigin ); Vector vecForward; MatrixGetColumn( m_muzzleToWorld, 0, vecForward ); // Note: We back up into the model to avoid an edge case where the eyes clip out of the world and // cause problems with the PVS calculations -- jdw vecOrigin -= vecForward * 8.0f; return vecOrigin; } Vector EyeOffset( Activity nActivity ) { return Vector( 0, 0, 58 ); } // Restore the turret to working operation after falling over void ReturnToLife( void ); int DrawDebugTextOverlays( void ); // 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 ) { // For now, turn green so we can tell who is hacked. SetRenderColor( 0, 255, 0 ); m_bHackedByAlyx = true; } static float fMaxTipControllerVelocity; static float fMaxTipControllerAngularVelocity; protected: virtual bool PreThink( turretState_e state ); virtual void Shoot( const Vector &vecSrc, const Vector &vecDirToEnemy, bool bStrict = false ); virtual void SetEyeState( eyeState_t state ); void Ping( void ); void Toggle( void ); void Enable( void ); void Disable( void ); void SpinUp( void ); void SpinDown( void ); virtual bool OnSide( void ); bool IsCitizenTurret( void ) { return HasSpawnFlags( SF_FLOOR_TURRET_CITIZEN ); } bool UpdateFacing( void ); void DryFire( void ); void UpdateMuzzleMatrix(); protected: matrix3x4_t m_muzzleToWorld; int m_muzzleToWorldTick; int m_iAmmoType; bool m_bAutoStart; bool m_bActive; //Denotes the turret is deployed and looking for targets bool m_bBlinkState; bool m_bEnabled; //Denotes whether the turret is able to deploy or not bool m_bNoAlarmSounds; bool m_bSelfDestructing; // Going to blow up float m_flDestructStartTime; float m_flShotTime; float m_flLastSight; float m_flThrashTime; float m_flPingTime; float m_flNextActivateSoundTime; bool m_bCarriedByPlayer; bool m_bUseCarryAngles; float m_flPlayerDropTime; int m_iKeySkin; CHandle m_hLastNPCToKickMe; // Stores the last NPC who tried to knock me over float m_flKnockOverFailedTime; // Time at which we should tell the NPC that he failed to knock me over QAngle m_vecGoalAngles; int m_iEyeAttachment; int m_iMuzzleAttachment; eyeState_t m_iEyeState; CHandle m_hEyeGlow; CHandle m_hLaser; CHandle m_pMotionController; CHandle m_hFizzleEffect; Vector m_vecEnemyLKP; // physics influence CHandle m_hPhysicsAttacker; float m_flLastPhysicsInfluenceTime; static const char *m_pShotSounds[]; COutputEvent m_OnDeploy; COutputEvent m_OnRetire; COutputEvent m_OnTipped; COutputEvent m_OnPhysGunPickup; COutputEvent m_OnPhysGunDrop; bool m_bHackedByAlyx; HSOUNDSCRIPTHANDLE m_ShotSounds; DECLARE_DATADESC(); DEFINE_CUSTOM_AI; }; // // Tip controller // class CTurretTipController : public CPointEntity, public IMotionEvent { DECLARE_CLASS( CTurretTipController, CPointEntity ); DECLARE_DATADESC(); public: ~CTurretTipController( void ); void Spawn( void ); void Activate( void ); void Enable( bool state = true ); void Suspend( float time ); float SuspendedTill( void ); bool Enabled( void ); static CTurretTipController *CreateTipController( CNPC_FloorTurret *pOwner ) { if ( pOwner == NULL ) return NULL; CTurretTipController *pController = (CTurretTipController *) Create( "floorturret_tipcontroller", pOwner->GetAbsOrigin(), pOwner->GetAbsAngles() ); if ( pController != NULL ) { pController->m_pParentTurret = pOwner; } return pController; } // IMotionEvent virtual simresult_e Simulate( IPhysicsMotionController *pController, IPhysicsObject *pObject, float deltaTime, Vector &linear, AngularImpulse &angular ); private: bool m_bEnabled; float m_flSuspendTime; Vector m_worldGoalAxis; Vector m_localTestAxis; IPhysicsMotionController *m_pController; float m_angularLimit; CNPC_FloorTurret *m_pParentTurret; }; #endif //#ifndef NPC_TURRET_FLOOR_H