text: #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<CAI_BaseNPC>, public CDefaultPlayerPickupVPhysics
  {
  	DECLARE_CLASS( CNPC_FloorTurret, CNPCBaseInteractive<CAI_BaseNPC> );
  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<CBaseCombatCharacter> 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<CSprite>		m_hEyeGlow;
  	CHandle<CBeam>			m_hLaser;
  	CHandle<CTurretTipController>	m_pMotionController;
  
  	CHandle<CParticleSystem>	m_hFizzleEffect;
  	Vector	m_vecEnemyLKP;
  
  	// physics influence
  	CHandle<CBasePlayer>	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
  