Quick, Incredibly stupid, Question

Where can I find “Lua/entities/npc_turret_floor.lua” ?
What GCF or file?
I want to use it as a base for a new npc.


(User was banned for this post ("Undescriptive thread title" - mahalis))

That’s not a file that comes with GMod.

i know, is it in source content.gcf or halflife2.gcf or episode one.gcf?

>Implying all Source engine NPC’s are coded in Lua and not C++

how do I get it in text format? can you post it here so i can paste it into a Lua file or something?

Haha, oh wow.

Good one OP, I havent had a laugh like that in a while. Oh wait, you’re serious o_o

Not that I’m a whiz on C++ in any manner, but the NPC you’re looking for is part of the Source engine. Source engine is coded in C++ and so is its contents, like the NPC. C++ is compiled and then ran to out put the given results of the code.

You cant take one language (Especially a hardcoded one like C++) and then paste it into a Lua file (A completely different language that doesnt have all of the Source funcitons included…) and then magically make it work.

What you CAN do is take one of the many turret NPC’s from Garrysmod.org and use that as a base.

But thanks anyways OP, had a good laugh.

I was just there looking and all of them seem to use the same class: npc_turret_floor.
edit: OP?

There’s no stupid questions, just stupid people.


(User was banned for this post ("Trolling" - mahalis))

why even post?

OP == Original Poster.
In this thread, it is you.

and if you want to make a turret, then try messing around with another person’s code to see how it works, then write your own. Do NOT copy/paste without giving credit to the original author.

It’s coded in C++.
Here it is, straight from the orangebox SDK.

Header:



#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


Actual code:



//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: 
//
// $NoKeywords: $
//=============================================================================//

#include "cbase.h"
#include "npc_turret_floor.h"
#include "ai_senses.h"
#include "ai_memory.h"
#include "engine/IEngineSound.h"
#include "ammodef.h"
#include "hl2/hl2_player.h"
#include "soundenvelope.h"
#include "physics_saverestore.h"
#include "IEffects.h"
#include "basehlcombatweapon_shared.h"
#include "phys_controller.h"
#include "ai_interactions.h"
#include "Sprite.h"
#include "beam_shared.h"
#include "props.h"
#include "particle_parse.h"

#ifdef PORTAL
	#include "prop_portal_shared.h"
	#include "portal_util_shared.h"
#endif

// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"

const char *GetMassEquivalent(float flMass);

#define	DISABLE_SHOT	0

//Debug visualization
ConVar	g_debug_turret( "g_debug_turret", "0" );

extern ConVar physcannon_tracelength;

// Interactions
int	g_interactionTurretStillStanding	= 0;

float CNPC_FloorTurret::fMaxTipControllerVelocity = 300.0f * 300.0f;
float CNPC_FloorTurret::fMaxTipControllerAngularVelocity = 90.0f * 90.0f;

#define	LASER_BEAM_SPRITE			"effects/laser1.vmt"

#define	FLOOR_TURRET_MODEL			"models/combine_turrets/floor_turret.mdl"
#define	FLOOR_TURRET_MODEL_CITIZEN	"models/combine_turrets/citizen_turret.mdl"
#define FLOOR_TURRET_GLOW_SPRITE	"sprites/glow1.vmt"
// #define FLOOR_TURRET_BC_YAW			"aim_yaw"
// #define FLOOR_TURRET_BC_PITCH		"aim_pitch"
#define	FLOOR_TURRET_RANGE			1200
#define	FLOOR_TURRET_MAX_WAIT		5
#define FLOOR_TURRET_SHORT_WAIT		2.0		// Used for FAST_RETIRE spawnflag
#define	FLOOR_TURRET_PING_TIME		1.0f	//LPB!!

#define	FLOOR_TURRET_VOICE_PITCH_LOW	45
#define	FLOOR_TURRET_VOICE_PITCH_HIGH	100

//Aiming variables
#define	FLOOR_TURRET_MAX_NOHARM_PERIOD		0.0f
#define	FLOOR_TURRET_MAX_GRACE_PERIOD		3.0f

//Activities
int ACT_FLOOR_TURRET_OPEN;
int ACT_FLOOR_TURRET_CLOSE;
int ACT_FLOOR_TURRET_OPEN_IDLE;
int ACT_FLOOR_TURRET_CLOSED_IDLE;
int ACT_FLOOR_TURRET_FIRE;

//Datatable
BEGIN_DATADESC( CNPC_FloorTurret )

	DEFINE_FIELD( m_iAmmoType,	FIELD_INTEGER ),
	DEFINE_FIELD( m_bAutoStart,	FIELD_BOOLEAN ),
	DEFINE_FIELD( m_bActive,		FIELD_BOOLEAN ),
	DEFINE_FIELD( m_bBlinkState,	FIELD_BOOLEAN ),
	DEFINE_FIELD( m_bEnabled,		FIELD_BOOLEAN ),
	DEFINE_FIELD( m_bNoAlarmSounds,	FIELD_BOOLEAN ),

	DEFINE_FIELD( m_flShotTime,	FIELD_TIME ),
	DEFINE_FIELD( m_flLastSight,	FIELD_TIME ),
	DEFINE_FIELD( m_flThrashTime,	FIELD_TIME ),
	DEFINE_FIELD( m_flPingTime,	FIELD_TIME ),
	DEFINE_FIELD( m_flNextActivateSoundTime, FIELD_TIME ),
	DEFINE_FIELD( m_bCarriedByPlayer, FIELD_BOOLEAN ),
	DEFINE_FIELD( m_bUseCarryAngles, FIELD_BOOLEAN ),
	DEFINE_FIELD( m_flPlayerDropTime, FIELD_TIME ),
	DEFINE_FIELD( m_hLastNPCToKickMe, FIELD_EHANDLE ),
	DEFINE_FIELD( m_flKnockOverFailedTime, FIELD_TIME ),
	DEFINE_FIELD( m_flDestructStartTime, FIELD_TIME ),
	DEFINE_FIELD( m_hFizzleEffect, FIELD_EHANDLE ),

	DEFINE_FIELD( m_vecGoalAngles,FIELD_VECTOR ),
	DEFINE_FIELD( m_iEyeAttachment,	FIELD_INTEGER ),
	DEFINE_FIELD( m_iMuzzleAttachment,	FIELD_INTEGER ),
	DEFINE_FIELD( m_iEyeState,		FIELD_INTEGER ),
	DEFINE_FIELD( m_hEyeGlow,		FIELD_EHANDLE ),
	DEFINE_FIELD( m_pMotionController,FIELD_EHANDLE),
	DEFINE_FIELD( m_vecEnemyLKP,	FIELD_VECTOR ),
	DEFINE_FIELD( m_hLaser,			FIELD_EHANDLE ),
	DEFINE_FIELD( m_bSelfDestructing,	FIELD_BOOLEAN ),

	DEFINE_FIELD( m_hPhysicsAttacker, FIELD_EHANDLE ),
	DEFINE_FIELD( m_flLastPhysicsInfluenceTime, FIELD_TIME ),

	DEFINE_FIELD( m_bHackedByAlyx, FIELD_BOOLEAN ),

	DEFINE_KEYFIELD( m_iKeySkin, FIELD_INTEGER, "SkinNumber" ),
	
	DEFINE_THINKFUNC( Retire ),
	DEFINE_THINKFUNC( Deploy ),
	DEFINE_THINKFUNC( ActiveThink ),
	DEFINE_THINKFUNC( SearchThink ),
	DEFINE_THINKFUNC( AutoSearchThink ),
	DEFINE_THINKFUNC( TippedThink ),
	DEFINE_THINKFUNC( InactiveThink ),
	DEFINE_THINKFUNC( SuppressThink ),
	DEFINE_THINKFUNC( DisabledThink ),
	DEFINE_THINKFUNC( SelfDestructThink ),
	DEFINE_THINKFUNC( BreakThink ),

	DEFINE_USEFUNC( ToggleUse ),

	// Inputs
	DEFINE_INPUTFUNC( FIELD_VOID, "Toggle", InputToggle ),
	DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ),
	DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ),
	DEFINE_INPUTFUNC( FIELD_VOID, "DepleteAmmo", InputDepleteAmmo ),
	DEFINE_INPUTFUNC( FIELD_VOID, "RestoreAmmo", InputRestoreAmmo ),
	DEFINE_INPUTFUNC( FIELD_VOID, "SelfDestruct", InputSelfDestruct ),

	DEFINE_OUTPUT( m_OnDeploy, "OnDeploy" ),
	DEFINE_OUTPUT( m_OnRetire, "OnRetire" ),
	DEFINE_OUTPUT( m_OnTipped, "OnTipped" ),
	DEFINE_OUTPUT( m_OnPhysGunPickup, "OnPhysGunPickup" ),
	DEFINE_OUTPUT( m_OnPhysGunDrop, "OnPhysGunDrop" ),

	DEFINE_BASENPCINTERACTABLE_DATADESC(),

	// DEFINE_FIELD( m_ShotSounds, FIELD_SHORT ),

END_DATADESC()

LINK_ENTITY_TO_CLASS( npc_turret_floor, CNPC_FloorTurret );

//-----------------------------------------------------------------------------
// Constructor
//-----------------------------------------------------------------------------
CNPC_FloorTurret::CNPC_FloorTurret( void ) : 
	m_bActive( false ),
	m_hEyeGlow( NULL ),
	m_hLaser( NULL ),
	m_iAmmoType( -1 ),
	m_bAutoStart( false ),
	m_flPingTime( 0.0f ),
	m_flNextActivateSoundTime( 0.0f ),
	m_bCarriedByPlayer( false ),
	m_bUseCarryAngles( false ),
	m_flPlayerDropTime( 0.0f ),
	m_flShotTime( 0.0f ),
	m_flLastSight( 0.0f ),
	m_bBlinkState( false ),
	m_flThrashTime( 0.0f ),
	m_pMotionController( NULL ),
	m_bEnabled( false ),
	m_bSelfDestructing( false )
{
	m_vecGoalAngles.Init();

	m_vecEnemyLKP = vec3_invalid;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
Class_T	CNPC_FloorTurret::Classify( void ) 
{
	if ( m_bEnabled ) 
	{
		// Hacked or friendly turrets don't attack players
		if( m_bHackedByAlyx || IsCitizenTurret() )
			return CLASS_PLAYER_ALLY;

		return CLASS_COMBINE;
	}

	return CLASS_NONE;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CNPC_FloorTurret::UpdateOnRemove( void )
{
	if ( m_pMotionController != NULL )
	{
		UTIL_Remove( m_pMotionController );
		m_pMotionController = NULL;
	}

	if ( m_hLaser != NULL )
	{
		UTIL_Remove( m_hLaser );
		m_hLaser = NULL;
	}

	if ( m_hEyeGlow != NULL )
	{
		UTIL_Remove( m_hEyeGlow );
		m_hEyeGlow = NULL;
	}

	BaseClass::UpdateOnRemove();
}

//-----------------------------------------------------------------------------
// Purpose: Precache
//-----------------------------------------------------------------------------
void CNPC_FloorTurret::Precache( void )
{
	const char *pModelName = STRING( GetModelName() );
	pModelName = ( pModelName && pModelName[ 0 ] != '\0' ) ? pModelName : FLOOR_TURRET_MODEL;
	PrecacheModel( pModelName );
	PrecacheModel( FLOOR_TURRET_GLOW_SPRITE );

	PropBreakablePrecacheAll( MAKE_STRING( pModelName ) );

	if ( IsCitizenTurret() )
	{
		PrecacheModel( LASER_BEAM_SPRITE );
		PrecacheScriptSound( "NPC_FloorTurret.AlarmPing");
	}

	// Activities
	ADD_CUSTOM_ACTIVITY( CNPC_FloorTurret, ACT_FLOOR_TURRET_OPEN );
	ADD_CUSTOM_ACTIVITY( CNPC_FloorTurret, ACT_FLOOR_TURRET_CLOSE );
	ADD_CUSTOM_ACTIVITY( CNPC_FloorTurret, ACT_FLOOR_TURRET_CLOSED_IDLE );
	ADD_CUSTOM_ACTIVITY( CNPC_FloorTurret, ACT_FLOOR_TURRET_OPEN_IDLE );
	ADD_CUSTOM_ACTIVITY( CNPC_FloorTurret, ACT_FLOOR_TURRET_FIRE );
	
	PrecacheScriptSound( "NPC_FloorTurret.Retire" );
	PrecacheScriptSound( "NPC_FloorTurret.Deploy" );
	PrecacheScriptSound( "NPC_FloorTurret.Move" );
	PrecacheScriptSound( "NPC_Combine.WeaponBash" );
	PrecacheScriptSound( "NPC_FloorTurret.Activate" );
	PrecacheScriptSound( "NPC_FloorTurret.Alert" );
	m_ShotSounds = PrecacheScriptSound( "NPC_FloorTurret.ShotSounds" );
	PrecacheScriptSound( "NPC_FloorTurret.Die" );
	PrecacheScriptSound( "NPC_FloorTurret.Retract");
	PrecacheScriptSound( "NPC_FloorTurret.Alarm");
	PrecacheScriptSound( "NPC_FloorTurret.Ping");
	PrecacheScriptSound( "NPC_FloorTurret.DryFire");
	PrecacheScriptSound( "NPC_FloorTurret.Destruct" );

#ifdef HL2_EPISODIC
	PrecacheParticleSystem( "explosion_turret_break" );
#endif // HL2_EPISODIC
	
	BaseClass::Precache();
}

//-----------------------------------------------------------------------------
// Purpose: Spawn the entity
//-----------------------------------------------------------------------------
void CNPC_FloorTurret::Spawn( void )
{ 
	Precache();

	const char *pModelName = STRING( GetModelName() );
	SetModel( ( pModelName && pModelName[ 0 ] != '\0' ) ? pModelName : FLOOR_TURRET_MODEL );
	
	// If we're a citizen turret, we use a different skin
	if ( IsCitizenTurret() )
	{
		if (m_iKeySkin == 0)
		{	// select a "random" skin -- rather than being truly random, use a static variable
			// to cycle through them evenly. The static won't be saved across save/load, but 
			// frankly I don't care so much about that.
			// m_nSkin = random->RandomInt( 1, 4 );
			static unsigned int nextSkin = 0;
			m_nSkin = nextSkin + 1;

			// add one mod 4
			nextSkin = (nextSkin + 1) & 0x03;
		}
		else
		{	// at least make sure that it's in the right range
			m_nSkin = clamp(m_iKeySkin,1,4);
		}
	}

	BaseClass::Spawn();

	SetBlocksLOS( false );

	m_HackedGunPos	= Vector( 0, 0, 12.75 );
	SetViewOffset( EyeOffset( ACT_IDLE ) );
	m_flFieldOfView	= 0.4f; // 60 degrees
	m_takedamage	= DAMAGE_EVENTS_ONLY;
	m_iHealth		= 100;
	m_iMaxHealth	= 100;

	AddEFlags( EFL_NO_DISSOLVE );

	SetPoseParameter( m_poseAim_Yaw, 0 );
	SetPoseParameter( m_poseAim_Pitch, 0 );

	m_iAmmoType = GetAmmoDef()->Index( "PISTOL" );

	m_iMuzzleAttachment = LookupAttachment( "eyes" );
	m_iEyeAttachment = LookupAttachment( "light" );

	// FIXME: Do we ever need m_bAutoStart? (Sawyer)
	m_spawnflags |= SF_FLOOR_TURRET_AUTOACTIVATE;

	//Set our autostart state
	m_bAutoStart = !!( m_spawnflags & SF_FLOOR_TURRET_AUTOACTIVATE );
	m_bEnabled	 = ( ( m_spawnflags & SF_FLOOR_TURRET_STARTINACTIVE ) == false );

	//Do we start active?
	if ( m_bAutoStart && m_bEnabled )
	{
		SetThink( &CNPC_FloorTurret::AutoSearchThink );
		SetEyeState( TURRET_EYE_DORMANT );
	}
	else
	{
		SetThink( &CNPC_FloorTurret::DisabledThink );
		SetEyeState( TURRET_EYE_DISABLED );
	}

	// Start 
	if ( OnSide() )
	{
		SetThink( &CNPC_FloorTurret::DisabledThink );
		SetEyeState( TURRET_EYE_DISABLED );
	}

	//Stagger our starting times
	SetNextThink( gpGlobals->curtime + random->RandomFloat( 0.1f, 0.3f ) );

	SetUse( &CNPC_FloorTurret::ToggleUse );

	// Don't allow us to skip animation setup because our attachments are critical to us!
	SetBoneCacheFlags( BCF_NO_ANIMATION_SKIP );

	CreateVPhysics();

	SetState(NPC_STATE_IDLE);
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CNPC_FloorTurret::Activate( void )
{
	BaseClass::Activate();

	// Force the eye state to the current state so that our glows are recreated after transitions
	SetEyeState( m_iEyeState );

	if ( !m_pMotionController )
	{
		// Create the motion controller
		m_pMotionController = CTurretTipController::CreateTipController( this );

		// Enable the controller
		if ( m_pMotionController != NULL )
		{
			m_pMotionController->Enable();
		}
	}
}

//-----------------------------------------------------------------------------

bool CNPC_FloorTurret::CreateVPhysics( void )
{
	//Spawn our physics hull
	if ( VPhysicsInitNormal( SOLID_VPHYSICS, 0, false ) == NULL )
	{
		DevMsg( "npc_turret_floor unable to spawn physics object!
" );
	}

	return true;
}

//-----------------------------------------------------------------------------
// Purpose: Retract and stop attacking
//-----------------------------------------------------------------------------
void CNPC_FloorTurret::Retire( void )
{
	if ( PreThink( TURRET_RETIRING ) )
		return;

	//Level out the turret
	m_vecGoalAngles = GetAbsAngles();
	SetNextThink( gpGlobals->curtime + 0.05f );

	//Set ourselves to close
	if ( GetActivity() != ACT_FLOOR_TURRET_CLOSE )
	{
		//Set our visible state to dormant
		SetEyeState( TURRET_EYE_DORMANT );

		SetActivity( (Activity) ACT_FLOOR_TURRET_OPEN_IDLE );
		
		//If we're done moving to our desired facing, close up
		if ( UpdateFacing() == false )
		{
			SetActivity( (Activity) ACT_FLOOR_TURRET_CLOSE );
			EmitSound( "NPC_FloorTurret.Retire" );

			//Notify of the retraction
			m_OnRetire.FireOutput( NULL, this );
		}
	}
	else if ( IsActivityFinished() )
	{	
		m_bActive		= false;
		m_flLastSight	= 0;

		SetActivity( (Activity) ACT_FLOOR_TURRET_CLOSED_IDLE );

		//Go back to auto searching
		if ( m_bAutoStart )
		{
			SetThink( &CNPC_FloorTurret::AutoSearchThink );
			SetNextThink( gpGlobals->curtime + 0.05f );
		}
		else
		{
			//Set our visible state to dormant
			SetEyeState( TURRET_EYE_DISABLED );
			SetThink( &CNPC_FloorTurret::DisabledThink );
		}
	}
}

//-----------------------------------------------------------------------------
// Purpose: Deploy and start attacking
//-----------------------------------------------------------------------------
void CNPC_FloorTurret::Deploy( void )
{
	if ( PreThink( TURRET_DEPLOYING ) )
		return;

	m_vecGoalAngles = GetAbsAngles();

	SetNextThink( gpGlobals->curtime + 0.05f );

	//Show we've seen a target
	SetEyeState( TURRET_EYE_SEE_TARGET );

	//Open if we're not already
	if ( GetActivity() != ACT_FLOOR_TURRET_OPEN )
	{
		m_bActive = true;
		SetActivity( (Activity) ACT_FLOOR_TURRET_OPEN );
		EmitSound( "NPC_FloorTurret.Deploy" );

		//Notify we're deploying
		m_OnDeploy.FireOutput( NULL, this );
	}

	//If we're done, then start searching
	if ( IsActivityFinished() )
	{
		SetActivity( (Activity) ACT_FLOOR_TURRET_OPEN_IDLE );

		m_flShotTime  = gpGlobals->curtime + 1.0f;

		m_flPlaybackRate = 0;
		SetThink( &CNPC_FloorTurret::SearchThink );

		EmitSound( "NPC_FloorTurret.Move" );
	}

	m_flLastSight = gpGlobals->curtime + FLOOR_TURRET_MAX_WAIT;	
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CNPC_FloorTurret::OnPhysGunPickup( CBasePlayer *pPhysGunUser, PhysGunPickup_t reason )
{
	m_hPhysicsAttacker = pPhysGunUser;
	m_flLastPhysicsInfluenceTime = gpGlobals->curtime;

	// Drop our mass a lot so that we can be moved easily with +USE
	if ( reason != PUNTED_BY_CANNON )
	{
		Assert( VPhysicsGetObject() );

		m_bCarriedByPlayer = true;
		m_OnPhysGunPickup.FireOutput( this, this );

		// We want to use preferred carry angles if we're not nicely upright
		Vector vecToTurret = pPhysGunUser->GetAbsOrigin() - GetAbsOrigin();
		vecToTurret.z = 0;
		VectorNormalize( vecToTurret );

		// We want to use preferred carry angles if we're not nicely upright
		Vector	forward, up;
		GetVectors( &forward, NULL, &up );

		bool bUpright = DotProduct( up, Vector(0,0,1) ) > 0.9f;
		bool bBehind = DotProduct( vecToTurret, forward ) < 0.85f;

		// Correct our angles only if we're not upright or we're mostly behind the turret
		if ( hl2_episodic.GetBool() )
		{
			m_bUseCarryAngles = ( bUpright == false || bBehind );
		}
		else
		{
			m_bUseCarryAngles = ( bUpright == false );
		}
	}

	// Clear out our last NPC to kick me, because it makes no sense now
	m_hLastNPCToKickMe = NULL;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CNPC_FloorTurret::OnPhysGunDrop( CBasePlayer *pPhysGunUser, PhysGunDrop_t Reason )
{
	m_hPhysicsAttacker = pPhysGunUser;
	m_flLastPhysicsInfluenceTime = gpGlobals->curtime;
	
	m_bCarriedByPlayer = false;
	m_bUseCarryAngles = false;
	m_OnPhysGunDrop.FireOutput( this, this );

	// If this is a friendly turret, remember that it was just dropped
	if ( IRelationType( pPhysGunUser ) != D_HT )
	{
		m_flPlayerDropTime = gpGlobals->curtime + 2.0;
	}

	// Restore our mass to the original value
	Assert( VPhysicsGetObject() );
}

//-----------------------------------------------------------------------------
// Purpose: Whether this should return carry angles
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CNPC_FloorTurret::HasPreferredCarryAnglesForPlayer( CBasePlayer *pPlayer )
{
	// Don't use preferred angles on enemy turrets
	if ( IRelationType( pPlayer ) == D_HT )
		return false;

	return m_bUseCarryAngles;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
bool CNPC_FloorTurret::OnAttemptPhysGunPickup( CBasePlayer *pPhysGunUser, PhysGunPickup_t reason )
{
	// Prevent players pulling enemy turrets from afar if they're in front of the turret
	if ( reason == PICKED_UP_BY_CANNON && IRelationType( pPhysGunUser ) == D_HT )
	{
		Vector vecForward;
		GetVectors( &vecForward, NULL, NULL );
		Vector vecForce = (pPhysGunUser->GetAbsOrigin() - GetAbsOrigin());
		float flDistance = VectorNormalize( vecForce );

		// If it's over the physcannon tracelength, we're pulling it
		if ( flDistance > physcannon_tracelength.GetFloat() )
		{
			float flDot = DotProduct( vecForward, vecForce );
			if ( flDot > 0.5 )
				return false;
		}
	}

	return true;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
bool CNPC_FloorTurret::HandleInteraction(int interactionType, void *data, CBaseCombatCharacter *sourceEnt)
{
	if ( interactionType == g_interactionCombineBash )
	{
		// We've been bashed by a combine soldier. Remember who it was, if we haven't got an active kicker
		if ( !m_hLastNPCToKickMe )
		{
			m_hLastNPCToKickMe = sourceEnt;
			m_flKnockOverFailedTime = gpGlobals->curtime + 3.0;
		}

		// Get knocked away
		Vector forward, up;
		AngleVectors( sourceEnt->GetLocalAngles(), &forward, NULL, &up );
		ApplyAbsVelocityImpulse( forward * 100 + up * 50 );
		CTakeDamageInfo info( sourceEnt, sourceEnt, 30, DMG_CLUB );
		CalculateMeleeDamageForce( &info, forward, GetAbsOrigin() );
		TakeDamage( info );

		EmitSound( "NPC_Combine.WeaponBash" );
		return true;
	}

	return BaseClass::HandleInteraction( interactionType, data, sourceEnt );
}

//-----------------------------------------------------------------------------
// Purpose: Returns the speed at which the turret can face a target
//-----------------------------------------------------------------------------
float CNPC_FloorTurret::MaxYawSpeed( void )
{
	//TODO: Scale by difficulty?
	return 360.0f;
}

//-----------------------------------------------------------------------------
// Purpose: Return true if this turret was recently dropped by a player
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CNPC_FloorTurret::WasJustDroppedByPlayer( void )
{
	if ( m_flPlayerDropTime > gpGlobals->curtime )
		return true;

	return false;
}

//-----------------------------------------------------------------------------
// Purpose: Causes the turret to face its desired angles
//-----------------------------------------------------------------------------
bool CNPC_FloorTurret::UpdateFacing( void )
{
	bool  bMoved = false;
	UpdateMuzzleMatrix();

	Vector vecGoalDir;
	AngleVectors( m_vecGoalAngles, &vecGoalDir );

	Vector vecGoalLocalDir;
	VectorIRotate( vecGoalDir, m_muzzleToWorld, vecGoalLocalDir );

	if ( g_debug_turret.GetBool() )
	{
		Vector	vecMuzzle, vecMuzzleDir;

		MatrixGetColumn( m_muzzleToWorld, 3, vecMuzzle );
		MatrixGetColumn( m_muzzleToWorld, 0, vecMuzzleDir );

		NDebugOverlay::Cross3D( vecMuzzle, -Vector(2,2,2), Vector(2,2,2), 255, 255, 0, false, 0.05 );
		NDebugOverlay::Cross3D( vecMuzzle+(vecMuzzleDir*256), -Vector(2,2,2), Vector(2,2,2), 255, 255, 0, false, 0.05 );
		NDebugOverlay::Line( vecMuzzle, vecMuzzle+(vecMuzzleDir*256), 255, 255, 0, false, 0.05 );
		
		NDebugOverlay::Cross3D( vecMuzzle, -Vector(2,2,2), Vector(2,2,2), 255, 0, 0, false, 0.05 );
		NDebugOverlay::Cross3D( vecMuzzle+(vecGoalDir*256), -Vector(2,2,2), Vector(2,2,2), 255, 0, 0, false, 0.05 );
		NDebugOverlay::Line( vecMuzzle, vecMuzzle+(vecGoalDir*256), 255, 0, 0, false, 0.05 );
	}

	QAngle vecGoalLocalAngles;
	VectorAngles( vecGoalLocalDir, vecGoalLocalAngles );

	// Update pitch
	float flDiff = AngleNormalize( UTIL_ApproachAngle(  vecGoalLocalAngles.x, 0.0, 0.05f * MaxYawSpeed() ) );
	
	SetPoseParameter( m_poseAim_Pitch, GetPoseParameter( m_poseAim_Pitch ) + ( flDiff / 1.5f ) );

	if ( fabs( flDiff ) > 0.1f )
	{
		bMoved = true;
	}

	// Update yaw
	flDiff = AngleNormalize( UTIL_ApproachAngle(  vecGoalLocalAngles.y, 0.0, 0.05f * MaxYawSpeed() ) );

	SetPoseParameter( m_poseAim_Yaw, GetPoseParameter( m_poseAim_Yaw ) + ( flDiff / 1.5f ) );

	if ( fabs( flDiff ) > 0.1f )
	{
		bMoved = true;
	}

	// You're going to make decisions based on this info.  So bump the bone cache after you calculate everything
	InvalidateBoneCache();

	return bMoved;
}

void CNPC_FloorTurret::DryFire( void )
{
	EmitSound( "NPC_FloorTurret.DryFire");
	EmitSound( "NPC_FloorTurret.Activate" );

 	if ( RandomFloat( 0, 1 ) > 0.5 )
	{
		m_flShotTime = gpGlobals->curtime + random->RandomFloat( 1, 2.5 );
	}
	else
	{
		m_flShotTime = gpGlobals->curtime;
	}
}

//-----------------------------------------------------------------------------
// Purpose: Turret will continue to fire on a target's position when it loses sight of it
//-----------------------------------------------------------------------------
void CNPC_FloorTurret::SuppressThink( void )
{
	//Allow descended classes a chance to do something before the think function
	if ( PreThink( TURRET_SUPPRESSING ) )
		return;

	//Update our think time
	SetNextThink( gpGlobals->curtime + 0.1f );

	// Look for a new enemy
	HackFindEnemy();

	//If we've acquired an enemy, start firing at it
	if ( !GetEnemy() )
	{
		SetThink( &CNPC_FloorTurret::ActiveThink );
		return;
	}

	//See if we're done suppressing
	if ( gpGlobals->curtime > m_flLastSight )
	{
		// Should we look for a new target?
		ClearEnemyMemory();
		SetEnemy( NULL );
		SetThink( &CNPC_FloorTurret::SearchThink );
		m_vecGoalAngles = GetAbsAngles();
		
		SpinDown();

		if ( m_spawnflags & SF_FLOOR_TURRET_FASTRETIRE )
		{
			// Retire quickly in this case. (The case where we saw the player, but he hid again).
			m_flLastSight = gpGlobals->curtime + FLOOR_TURRET_SHORT_WAIT;
		}
		else
		{
			m_flLastSight = gpGlobals->curtime + FLOOR_TURRET_MAX_WAIT;
		}

		return;
	}

	//Get our shot positions
	Vector vecMid = EyePosition();
	Vector vecMidEnemy = m_vecEnemyLKP;

	//Calculate dir and dist to enemy
	Vector	vecDirToEnemy = vecMidEnemy - vecMid;	

	//We want to look at the enemy's eyes so we don't jitter
	Vector	vecDirToEnemyEyes = vecMidEnemy - vecMid;
	VectorNormalize( vecDirToEnemyEyes );

	QAngle vecAnglesToEnemy;
	VectorAngles( vecDirToEnemyEyes, vecAnglesToEnemy );

	//Draw debug info
	if ( g_debug_turret.GetBool() )
	{
		NDebugOverlay::Cross3D( vecMid, -Vector(2,2,2), Vector(2,2,2), 0, 255, 0, false, 0.05 );
		NDebugOverlay::Cross3D( vecMidEnemy, -Vector(2,2,2), Vector(2,2,2), 0, 255, 0, false, 0.05 );
		NDebugOverlay::Line( vecMid, vecMidEnemy, 0, 255, 0, false, 0.05f );
	}

	if ( m_flShotTime < gpGlobals->curtime && m_vecEnemyLKP != vec3_invalid )
	{
		Vector vecMuzzle, vecMuzzleDir;
		UpdateMuzzleMatrix();
		MatrixGetColumn( m_muzzleToWorld, 0, vecMuzzleDir );
		MatrixGetColumn( m_muzzleToWorld, 3, vecMuzzle );

		//Fire the gun
		if ( DotProduct( vecDirToEnemy, vecMuzzleDir ) >= 0.9848 ) // 10 degree slop
		{
			if( m_spawnflags & SF_FLOOR_TURRET_OUT_OF_AMMO )
			{
				DryFire();
			}
			else
			{
				ResetActivity();
				SetActivity( (Activity) ACT_FLOOR_TURRET_FIRE );

				//Fire the weapon
#if !DISABLE_SHOT
				Shoot( vecMuzzle, vecMuzzleDir );
#endif
			}
		} 
	}
	else
	{
		SetActivity( (Activity) ACT_FLOOR_TURRET_OPEN_IDLE );
	}

	//If we can see our enemy, face it
	m_vecGoalAngles.y = vecAnglesToEnemy.y;
	m_vecGoalAngles.x = vecAnglesToEnemy.x;

	//Turn to face
	UpdateFacing();
}

//-----------------------------------------------------------------------------
// Purpose: Allows the turret to fire on targets if they're visible
//-----------------------------------------------------------------------------
void CNPC_FloorTurret::ActiveThink( void )
{
	//Allow descended classes a chance to do something before the think function
	if ( PreThink( TURRET_ACTIVE ) )
		return;

	HackFindEnemy();
	
	//Update our think time
	SetNextThink( gpGlobals->curtime + 0.1f );

	//If we've become inactive, go back to searching
	if ( ( m_bActive == false ) || ( GetEnemy() == NULL ) )
	{
		SetEnemy( NULL );
		m_flLastSight = gpGlobals->curtime + FLOOR_TURRET_MAX_WAIT;
		SetThink( &CNPC_FloorTurret::SearchThink );
		m_vecGoalAngles = GetAbsAngles();
		return;
	}
	
	//Get our shot positions
	Vector vecMid = EyePosition();
	Vector vecMidEnemy = GetEnemy()->BodyTarget( vecMid );

	// Store off our last seen location so we can suppress it later
	m_vecEnemyLKP = vecMidEnemy;

	//Look for our current enemy
	bool bEnemyInFOV = FInViewCone( GetEnemy() );
	bool bEnemyVisible = FVisible( GetEnemy() ) && GetEnemy()->IsAlive();	

	// Robin: This is a hack to get around the fact that the muzzle for the turret
	// is outside it's vcollide. This means that if it leans against a thin wall, 
	// the muzzle can be on the other side of the wall, where it's then able to see
	// and shoot at targets. This check ensures that nothing has come between the
	// center of the turret and the muzzle.
	if ( bEnemyVisible )
	{
		trace_t tr;
		Vector vecCenter;
		CollisionProp()->CollisionToWorldSpace( Vector(0,0,52), &vecCenter );
		UTIL_TraceLine( vecCenter, vecMid, MASK_SHOT, this, COLLISION_GROUP_NONE, &tr );
		if ( tr.fraction != 1.0 )
		{
			bEnemyVisible = false;
		}
	}

	//Calculate dir and dist to enemy
	Vector	vecDirToEnemy = vecMidEnemy - vecMid;	
	float	flDistToEnemy = VectorNormalize( vecDirToEnemy );

	//Draw debug info
	if ( g_debug_turret.GetBool() )
	{
		NDebugOverlay::Cross3D( vecMid, -Vector(2,2,2), Vector(2,2,2), 0, 255, 0, false, 0.05 );
		NDebugOverlay::Cross3D( GetEnemy()->WorldSpaceCenter(), -Vector(2,2,2), Vector(2,2,2), 0, 255, 0, false, 0.05 );
		NDebugOverlay::Line( vecMid, GetEnemy()->WorldSpaceCenter(), 0, 255, 0, false, 0.05 );

		NDebugOverlay::Cross3D( vecMid, -Vector(2,2,2), Vector(2,2,2), 0, 255, 0, false, 0.05 );
		NDebugOverlay::Cross3D( vecMidEnemy, -Vector(2,2,2), Vector(2,2,2), 0, 255, 0, false, 0.05 );
		NDebugOverlay::Line( vecMid, vecMidEnemy, 0, 255, 0, false, 0.05f );
	}

	//See if they're past our FOV of attack
	if ( bEnemyInFOV == false )
	{
		// Should we look for a new target?
		ClearEnemyMemory();
		SetEnemy( NULL );
		
		if ( m_spawnflags & SF_FLOOR_TURRET_FASTRETIRE )
		{
			// Retire quickly in this case. (The case where we saw the player, but he hid again).
			m_flLastSight = gpGlobals->curtime + FLOOR_TURRET_SHORT_WAIT;
		}
		else
		{
			m_flLastSight = gpGlobals->curtime + FLOOR_TURRET_MAX_WAIT;
		}

		SetThink( &CNPC_FloorTurret::SearchThink );
		m_vecGoalAngles = GetAbsAngles();
		
		SpinDown();

		return;
	}

	//Current enemy is not visible
	if ( ( bEnemyVisible == false ) || ( flDistToEnemy > FLOOR_TURRET_RANGE ))
	{
		m_flLastSight = gpGlobals->curtime + 2.0f;

		ClearEnemyMemory();
		SetEnemy( NULL );
		SetThink( &CNPC_FloorTurret::SuppressThink );

		return;
	}

	if ( g_debug_turret.GetBool() )
	{
		Vector vecMuzzle, vecMuzzleDir;

		UpdateMuzzleMatrix();
		MatrixGetColumn( m_muzzleToWorld, 0, vecMuzzleDir );
		MatrixGetColumn( m_muzzleToWorld, 3, vecMuzzle );

		// Visualize vertical firing ranges
		for ( int i = 0; i < 4; i++ )
		{
			QAngle angMaxDownPitch = GetAbsAngles();

			switch( i )
			{
			case 0:	angMaxDownPitch.x -= 15; break;
			case 1:	angMaxDownPitch.x += 15; break;
			case 2:	angMaxDownPitch.x -= 25; break;
			case 3:	angMaxDownPitch.x += 25; break;
			default:
				break;
			}

			Vector vecMaxDownPitch;
			AngleVectors( angMaxDownPitch, &vecMaxDownPitch );
			NDebugOverlay::Line( vecMuzzle, vecMuzzle + (vecMaxDownPitch*256), 255, 255, 255, false, 0.1 );
		}
	}

	if ( m_flShotTime < gpGlobals->curtime )
	{
		Vector vecMuzzle, vecMuzzleDir;

		UpdateMuzzleMatrix();
		MatrixGetColumn( m_muzzleToWorld, 0, vecMuzzleDir );
		MatrixGetColumn( m_muzzleToWorld, 3, vecMuzzle );

		Vector2D vecDirToEnemy2D = vecDirToEnemy.AsVector2D();
		Vector2D vecMuzzleDir2D = vecMuzzleDir.AsVector2D();

		bool bCanShoot = true;
		float minCos3d = DOT_10DEGREE; // 10 degrees slop

		if ( flDistToEnemy < 60.0 )
		{
			vecDirToEnemy2D.NormalizeInPlace();
			vecMuzzleDir2D.NormalizeInPlace();

			bCanShoot = ( vecDirToEnemy2D.Dot(vecMuzzleDir2D) >= DOT_10DEGREE );
			minCos3d = 0.7071; // 45 degrees
		}

		//Fire the gun
		if ( bCanShoot ) // 10 degree slop XY
		{
			float dot3d = DotProduct( vecDirToEnemy, vecMuzzleDir );

			if( m_spawnflags & SF_FLOOR_TURRET_OUT_OF_AMMO )
			{
				DryFire();
			}
			else
			{
				if ( dot3d >= minCos3d ) 
				{
					ResetActivity();
					SetActivity( (Activity) ACT_FLOOR_TURRET_FIRE );

					//Fire the weapon
#if !DISABLE_SHOT
					Shoot( vecMuzzle, vecMuzzleDir, (dot3d < DOT_10DEGREE) );
#endif
				}
			}
		} 
	}
	else
	{
		SetActivity( (Activity) ACT_FLOOR_TURRET_OPEN_IDLE );
	}

	//If we can see our enemy, face it
	if ( bEnemyVisible )
	{
		//We want to look at the enemy's eyes so we don't jitter
		Vector	vecDirToEnemyEyes = GetEnemy()->WorldSpaceCenter() - vecMid;
		VectorNormalize( vecDirToEnemyEyes );

		QAngle vecAnglesToEnemy;
		VectorAngles( vecDirToEnemyEyes, vecAnglesToEnemy );

		m_vecGoalAngles.y = vecAnglesToEnemy.y;
		m_vecGoalAngles.x = vecAnglesToEnemy.x;
	}

	//Turn to face
	UpdateFacing();
}

//-----------------------------------------------------------------------------
// Purpose: Target doesn't exist or has eluded us, so search for one
//-----------------------------------------------------------------------------
void CNPC_FloorTurret::SearchThink( void )
{
	//Allow descended classes a chance to do something before the think function
	if ( PreThink( TURRET_SEARCHING ) )
		return;

	SetNextThink( gpGlobals->curtime + 0.05f );

	SetActivity( (Activity) ACT_FLOOR_TURRET_OPEN_IDLE );

	//If our enemy has died, pick a new enemy
	if ( ( GetEnemy() != NULL ) && ( GetEnemy()->IsAlive() == false ) )
	{
		SetEnemy( NULL );
	}

	//Acquire the target
	if ( GetEnemy() == NULL )
	{
		HackFindEnemy();
	}

	//If we've found a target, spin up the barrel and start to attack
	if ( GetEnemy() != NULL )
	{
		//Give players a grace period
		if ( GetEnemy()->IsPlayer() )
		{
			m_flShotTime  = gpGlobals->curtime + 0.5f;
		}
		else
		{
			m_flShotTime  = gpGlobals->curtime + 0.1f;
		}

		m_flLastSight = 0;
		SetThink( &CNPC_FloorTurret::ActiveThink );
		SetEyeState( TURRET_EYE_SEE_TARGET );

		SpinUp();
 
		if ( gpGlobals->curtime > m_flNextActivateSoundTime )
		{
			EmitSound( "NPC_FloorTurret.Activate" );
			m_flNextActivateSoundTime = gpGlobals->curtime + 3.0;
		}
		return;
	}

	//Are we out of time and need to retract?
 	if ( gpGlobals->curtime > m_flLastSight )
	{
		//Before we retrace, make sure that we are spun down.
		m_flLastSight = 0;
		SetThink( &CNPC_FloorTurret::Retire );
		return;
	}
	
	//Display that we're scanning
	m_vecGoalAngles.x = GetAbsAngles().x + ( sin( gpGlobals->curtime * 1.0f ) * 15.0f );
	m_vecGoalAngles.y = GetAbsAngles().y + ( sin( gpGlobals->curtime * 2.0f ) * 60.0f );

	//Turn and ping
	UpdateFacing();
	Ping();
}

//-----------------------------------------------------------------------------
// Purpose: Watch for a target to wander into our view
//-----------------------------------------------------------------------------
void CNPC_FloorTurret::AutoSearchThink( void )
{
	//Allow descended classes a chance to do something before the think function
	if ( PreThink( TURRET_AUTO_SEARCHING ) )
		return; 

	//Spread out our thinking
	SetNextThink( gpGlobals->curtime + random->RandomFloat( 0.2f, 0.4f ) );

	//If the enemy is dead, find a new one
	if ( ( GetEnemy() != NULL ) && ( GetEnemy()->IsAlive() == false ) )
	{
		SetEnemy( NULL );
	}

	//Acquire Target
	if ( GetEnemy() == NULL )
	{
		HackFindEnemy();
	}

	//Deploy if we've got an active target
	if ( GetEnemy() != NULL )
	{
		SetThink( &CNPC_FloorTurret::Deploy );
		if ( !m_bNoAlarmSounds )
		{
			EmitSound( "NPC_FloorTurret.Alert" );
		}
	}
}

//-----------------------------------------------------------------------------
// Purpose: Fire!
//-----------------------------------------------------------------------------
void CNPC_FloorTurret::Shoot( const Vector &vecSrc, const Vector &vecDirToEnemy, bool bStrict )
{
	FireBulletsInfo_t info;

	if ( !bStrict && GetEnemy() != NULL )
	{
		Vector vecDir = GetActualShootTrajectory( vecSrc );

		info.m_vecSrc = vecSrc;
		info.m_vecDirShooting = vecDir;
		info.m_iTracerFreq = 1;
		info.m_iShots = 1;
		info.m_pAttacker = this;
		info.m_vecSpread = VECTOR_CONE_PRECALCULATED;
		info.m_flDistance = MAX_COORD_RANGE;
		info.m_iAmmoType = m_iAmmoType;
	}
	else
	{
		info.m_vecSrc = vecSrc;
		info.m_vecDirShooting = vecDirToEnemy;
		info.m_iTracerFreq = 1;
		info.m_iShots = 1;
		info.m_pAttacker = this;
		info.m_vecSpread = GetAttackSpread( NULL, GetEnemy() );
		info.m_flDistance = MAX_COORD_RANGE;
		info.m_iAmmoType = m_iAmmoType;
	}

	FireBullets( info );
	EmitSound( "NPC_FloorTurret.ShotSounds", m_ShotSounds );
	DoMuzzleFlash();
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  : *pEnemy - 
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CNPC_FloorTurret::IsValidEnemy( CBaseEntity *pEnemy )
{
	if ( m_NPCState == NPC_STATE_DEAD )
		return false;

	// Don't shoot at other turrets.
	if ( pEnemy->m_iClassname == m_iClassname )
		return false;

	// If our eye is stuck in something, don't shoot
	if ( UTIL_PointContents(EyePosition()) & MASK_SHOT )
		return false;

	// Turrets have limited vertical aim capability
	//	- Can only aim +-15 degrees, + the 10 degree slop they're allowed.
	Vector vEnemyPos = pEnemy->EyePosition();

#ifdef PORTAL
	if ( !FInViewCone( pEnemy ) || !FVisible( pEnemy ) )
	{
		CProp_Portal *pPortal = FInViewConeThroughPortal( pEnemy );

		if ( pPortal )
		{
			// Translate our target across the portal
			UTIL_Portal_PointTransform( pPortal->m_hLinkedPortal->MatrixThisToLinked(), vEnemyPos, vEnemyPos );
		}
	}
#endif

	Vector los = ( vEnemyPos - EyePosition() );

	QAngle angleToTarget;
	VectorAngles( los, angleToTarget );
	float flZDiff = fabs( AngleNormalize( angleToTarget.x - GetAbsAngles().x) );
	if ( flZDiff > 28.0f && los.LengthSqr() > 4096.0f )
		return false;

	return BaseClass::IsValidEnemy( pEnemy );
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  : *pEnemy - 
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CNPC_FloorTurret::CanBeAnEnemyOf( CBaseEntity *pEnemy )
{
	// If we're out of ammo, make friendly companions ignore us
	if ( m_spawnflags & SF_FLOOR_TURRET_OUT_OF_AMMO )
	{
		if ( pEnemy->Classify() == CLASS_PLAYER_ALLY_VITAL )
			return false;
	} 

	// If we're on the side, we're never anyone's enemy
	if ( OnSide() )
		return false;

	return BaseClass::CanBeAnEnemyOf( pEnemy );
}

//-----------------------------------------------------------------------------
// Purpose: The turret has been tipped over and will thrash for awhile
//-----------------------------------------------------------------------------
void CNPC_FloorTurret::TippedThink( void )
{
	// Update our PVS state
	CheckPVSCondition();

	//Animate
	StudioFrameAdvance();

	SetNextThink( gpGlobals->curtime + 0.05f );
	SetEnemy( NULL );

	// If we're not on side anymore, stop thrashing
	if ( !OnSide() )
	{
		ReturnToLife();
		return;
	}

	//See if we should continue to thrash
	if ( gpGlobals->curtime < m_flThrashTime )
	{
		if ( m_flShotTime < gpGlobals->curtime )
		{
			if( m_spawnflags & SF_FLOOR_TURRET_OUT_OF_AMMO )
			{
				DryFire();
			}
			else if ( IsCitizenTurret() == false )	// Citizen turrets don't wildly fire
			{
				Vector vecMuzzle, vecMuzzleDir;
				UpdateMuzzleMatrix();
				MatrixGetColumn( m_muzzleToWorld, 0, vecMuzzleDir );
				MatrixGetColumn( m_muzzleToWorld, 3, vecMuzzle );

				ResetActivity();
				SetActivity( (Activity) ACT_FLOOR_TURRET_FIRE );

#if !DISABLE_SHOT
				Shoot( vecMuzzle, vecMuzzleDir );
#endif
			}

			m_flShotTime = gpGlobals->curtime + 0.05f;
		}

		m_vecGoalAngles.x = GetAbsAngles().x + random->RandomFloat( -60, 60 );
		m_vecGoalAngles.y = GetAbsAngles().y + random->RandomFloat( -60, 60 );

		UpdateFacing();
	}
	else
	{
		//Face forward
		m_vecGoalAngles = GetAbsAngles();

		//Set ourselves to close
		if ( GetActivity() != ACT_FLOOR_TURRET_CLOSE )
		{
			SetActivity( (Activity) ACT_FLOOR_TURRET_OPEN_IDLE );
			
			//If we're done moving to our desired facing, close up
			if ( UpdateFacing() == false )
			{
				//Make any last death noises and anims
				EmitSound( "NPC_FloorTurret.Die" );
				SpinDown();

				SetActivity( (Activity) ACT_FLOOR_TURRET_CLOSE );
				EmitSound( "NPC_FloorTurret.Retract" );

				CTakeDamageInfo	info;
				info.SetDamage( 1 );
				info.SetDamageType( DMG_CRUSH );
				Event_Killed( info );
			}
		}
		else if ( IsActivityFinished() )
		{	
			m_bActive		= false;
			m_flLastSight	= 0;

			SetActivity( (Activity) ACT_FLOOR_TURRET_CLOSED_IDLE );

			// Don't need to store last NPC anymore, because I've been knocked over
			if ( m_hLastNPCToKickMe )
			{
				m_hLastNPCToKickMe = NULL;
				m_flKnockOverFailedTime = 0;
			}

			//Try to look straight
			if ( UpdateFacing() == false )
			{
				m_OnTipped.FireOutput( this, this );
				SetEyeState( TURRET_EYE_DEAD );
				SetCollisionGroup( COLLISION_GROUP_DEBRIS_TRIGGER );

				// Start thinking slowly to see if we're ever set upright somehow
				SetThink( &CNPC_FloorTurret::InactiveThink );
				SetNextThink( gpGlobals->curtime + 1.0f );
			}
		}
	}
}

//-----------------------------------------------------------------------------
// Purpose: This turret is dead. See if it ever becomes upright again, and if 
//			so, become active again.
//-----------------------------------------------------------------------------
void CNPC_FloorTurret::InactiveThink( void )
{
	// Update our PVS state
	CheckPVSCondition();

	// Wake up if we're not on our side
	if ( !OnSide() && m_bEnabled )
	{
		ReturnToLife();
		return;
	}

	if ( IsCitizenTurret() )
	{
		// Blink if we have ammo or our current blink is "on" and we need to turn it off again
		if ( HasSpawnFlags( SF_FLOOR_TURRET_OUT_OF_AMMO ) == false || m_bBlinkState )
		{
			// If we're on our side, ping and complain to the player
			if ( m_bBlinkState == false )
			{
				// Ping when the light is going to come back on
				EmitSound( "NPC_FloorTurret.AlarmPing" );
			}

			SetEyeState( TURRET_EYE_ALARM );
			SetNextThink( gpGlobals->curtime + 0.25f );
		}
	}
	else
	{
		SetNextThink( gpGlobals->curtime + 1.0f );
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CNPC_FloorTurret::ReturnToLife( void )
{
	m_flThrashTime = 0;

	// Enable the tip controller
	m_pMotionController->Enable( true );

	// Return to life
	SetState( NPC_STATE_IDLE );
	m_lifeState = LIFE_ALIVE;
	SetCollisionGroup( COLLISION_GROUP_NONE );

	// Become active again
	Enable();
}	

//-----------------------------------------------------------------------------
// Purpose: The turret is not doing anything at all
//-----------------------------------------------------------------------------
void CNPC_FloorTurret::DisabledThink( void )
{
	SetNextThink( gpGlobals->curtime + 0.5 );
	if ( OnSide() )
	{
		m_OnTipped.FireOutput( this, this );
		SetEyeState( TURRET_EYE_DEAD );
		SetCollisionGroup( COLLISION_GROUP_DEBRIS );
		SetThink( NULL );
	}
}

//-----------------------------------------------------------------------------
// Purpose: The turret doesn't run base AI properly, which is a bad decision.
//			As a result, it has to manually find enemies.
//-----------------------------------------------------------------------------
void CNPC_FloorTurret::HackFindEnemy( void )
{
	// We have to refresh our memories before finding enemies, so
	// dead enemies are cleared out before new ones are added.
	GetEnemies()->RefreshMemories();

	GetSenses()->Look( FLOOR_TURRET_RANGE );
	SetEnemy( BestEnemy() );
}

//-----------------------------------------------------------------------------
// Purpose: Determines whether the turret is upright enough to function
// Output : Returns true if the turret is tipped over
//-----------------------------------------------------------------------------
inline bool CNPC_FloorTurret::OnSide( void )
{
	Vector	up;
	GetVectors( NULL, NULL, &up );

	return ( DotProduct( up, Vector(0,0,1) ) < 0.5f );
}

//-----------------------------------------------------------------------------
// Purpose: Allows a generic think function before the others are called
// Input  : state - which state the turret is currently in
//-----------------------------------------------------------------------------
bool CNPC_FloorTurret::PreThink( turretState_e state )
{
	// Hack to disable turrets when ai is disabled
	if ( CAI_BaseNPC::m_nDebugBits & bits_debugDisableAI )
	{
		// Push our think out into the future
		SetNextThink( gpGlobals->curtime + 0.1f );
		return true;
	}
 
	CheckPVSCondition();

	//Animate
	StudioFrameAdvance();

	// We're gonna blow up, so don't interrupt us
	if ( state == TURRET_SELF_DESTRUCTING )
		return false;

	//See if we've tipped, but only do this if we're not being carried
	if ( !IsBeingCarriedByPlayer() )
	{
		if ( OnSide() == false )
		{
			// If I still haven't fallen over after an NPC has tried to knock me down, let them know
			if ( m_hLastNPCToKickMe && m_flKnockOverFailedTime < gpGlobals->curtime )
			{
				m_hLastNPCToKickMe->DispatchInteraction( g_interactionTurretStillStanding, NULL, this );
				m_hLastNPCToKickMe = NULL;
			}

			//Debug visualization
			if ( g_debug_turret.GetBool() )
			{
				Vector	up;
				GetVectors( NULL, NULL, &up );

				NDebugOverlay::Line( GetAbsOrigin()+(up*32), GetAbsOrigin()+(up*128), 0, 255, 0, false, 2.0f );
				NDebugOverlay::Cross3D( GetAbsOrigin()+(up*32), -Vector(2,2,2), Vector(2,2,2), 0, 255, 0, false, 2.0f );
				NDebugOverlay::Cross3D( GetAbsOrigin()+(up*128), -Vector(2,2,2), Vector(2,2,2), 0, 255, 0, false, 2.0f );
			}
		}
		else
		{
			if ( HasSpawnFlags( SF_FLOOR_TURRET_OUT_OF_AMMO ) == false )
			{
				//Thrash around for a bit
				m_flThrashTime = gpGlobals->curtime + random->RandomFloat( 2.0f, 2.5f );
				SetNextThink( gpGlobals->curtime + 0.05f );

				SetThink( &CNPC_FloorTurret::TippedThink );
				SetEyeState( TURRET_EYE_SEE_TARGET );
				
				SpinUp();
				if ( !m_bNoAlarmSounds )
				{
					EmitSound( "NPC_FloorTurret.Alarm" );
				}
			}
			else
			{
				// Take away the laser
				UTIL_Remove( m_hLaser );
				m_hLaser = NULL;

				// Become inactive
				SetThink( &CNPC_FloorTurret::InactiveThink );
				SetEyeState( TURRET_EYE_DEAD );
			}

			//Stop being targetted
			SetState( NPC_STATE_DEAD );
			m_lifeState = LIFE_DEAD;

			//Disable the tip controller
			m_pMotionController->Enable( false );

			//Debug visualization
			if ( g_debug_turret.GetBool() )
			{
				Vector	up;
				GetVectors( NULL, NULL, &up );

				NDebugOverlay::Line( GetAbsOrigin()+(up*32), GetAbsOrigin()+(up*128), 255, 0, 0, false, 2.0f );
				NDebugOverlay::Cross3D( GetAbsOrigin()+(up*32), -Vector(2,2,2), Vector(2,2,2), 255, 0, 0, false, 2.0f );
				NDebugOverlay::Cross3D( GetAbsOrigin()+(up*128), -Vector(2,2,2), Vector(2,2,2), 255, 0, 0, false, 2.0f );
			}

			//Interrupt current think function
			return true;
		}
	}

	//Do not interrupt current think function
	return false;
}

//-----------------------------------------------------------------------------
// Purpose: Sets the state of the glowing eye attached to the turret
// Input  : state - state the eye should be in
//-----------------------------------------------------------------------------
void CNPC_FloorTurret::SetEyeState( eyeState_t state )
{
	// Must have a valid eye to affect
	if ( !m_hEyeGlow )
	{
		// Create our eye sprite
		m_hEyeGlow = CSprite::SpriteCreate( FLOOR_TURRET_GLOW_SPRITE, GetLocalOrigin(), false );
		if ( !m_hEyeGlow )
			return;

		m_hEyeGlow->SetTransparency( kRenderWorldGlow, 255, 0, 0, 128, kRenderFxNoDissipation );
		m_hEyeGlow->SetAttachment( this, m_iEyeAttachment );
	}

	// Add the laser if it doesn't already exist
	if ( IsCitizenTurret() && HasSpawnFlags( SF_FLOOR_TURRET_OUT_OF_AMMO ) == false && m_hLaser == NULL )
	{
		m_hLaser = CBeam::BeamCreate( LASER_BEAM_SPRITE, 1.0f );
		if ( m_hLaser == NULL )
			return;

		m_hLaser->EntsInit( this, this );
		m_hLaser->FollowEntity( this );
		m_hLaser->SetStartAttachment( LookupAttachment( "laser_start" ) );
		m_hLaser->SetEndAttachment( LookupAttachment( "laser_end" ) );
		m_hLaser->SetNoise( 0 );
		m_hLaser->SetColor( 255, 0, 0 );
		m_hLaser->SetScrollRate( 0 );
		m_hLaser->SetWidth( 1.0f );
		m_hLaser->SetEndWidth( 1.0f );
		m_hLaser->SetBrightness( 160 );
		m_hLaser->SetBeamFlags( SF_BEAM_SHADEIN );
	}

	m_iEyeState = state;

	//Set the state
	switch( state )
	{
	default:
	case TURRET_EYE_SEE_TARGET: //Fade in and scale up
		m_hEyeGlow->SetColor( 255, 0, 0 );
		m_hEyeGlow->SetBrightness( 164, 0.1f );
		m_hEyeGlow->SetScale( 0.4f, 0.1f );
		break;

	case TURRET_EYE_SEEKING_TARGET: //Ping-pongs
		
		//Toggle our state
		m_bBlinkState = !m_bBlinkState;
		m_hEyeGlow->SetColor( 255, 128, 0 );

		if ( m_bBlinkState )
		{
			//Fade up and scale up
			m_hEyeGlow->SetScale( 0.25f, 0.1f );
			m_hEyeGlow->SetBrightness( 164, 0.1f );
		}
		else
		{
			//Fade down and scale down
			m_hEyeGlow->SetScale( 0.2f, 0.1f );
			m_hEyeGlow->SetBrightness( 64, 0.1f );
		}

		break;

	case TURRET_EYE_DORMANT: //Fade out and scale down
		m_hEyeGlow->SetColor( 0, 255, 0 );
		m_hEyeGlow->SetScale( 0.1f, 0.5f );
		m_hEyeGlow->SetBrightness( 64, 0.5f );
		break;

	case TURRET_EYE_DEAD: //Fade out slowly
		m_hEyeGlow->SetColor( 255, 0, 0 );
		m_hEyeGlow->SetScale( 0.1f, 3.0f );
		m_hEyeGlow->SetBrightness( 0, 3.0f );
		break;

	case TURRET_EYE_DISABLED:
		m_hEyeGlow->SetColor( 0, 255, 0 );
		m_hEyeGlow->SetScale( 0.1f, 1.0f );
		m_hEyeGlow->SetBrightness( 0, 1.0f );
		break;
	
	case TURRET_EYE_ALARM:
		{
			//Toggle our state
			m_bBlinkState = !m_bBlinkState;
			m_hEyeGlow->SetColor( 255, 0, 0 );

			if ( m_bBlinkState )
			{
				//Fade up and scale up
				m_hEyeGlow->SetScale( 0.75f, 0.05f );
				m_hEyeGlow->SetBrightness( 192, 0.05f );
			}
			else
			{
				//Fade down and scale down
				m_hEyeGlow->SetScale( 0.25f, 0.25f );
				m_hEyeGlow->SetBrightness( 64, 0.25f );
			}
		}
		break;
	}
}

//-----------------------------------------------------------------------------
// Purpose: Make a pinging noise so the player knows where we are
//-----------------------------------------------------------------------------
void CNPC_FloorTurret::Ping( void )
{
	//See if it's time to ping again
	if ( m_flPingTime > gpGlobals->curtime )
		return;

	//Ping!
	EmitSound( "NPC_FloorTurret.Ping" );

	SetEyeState( TURRET_EYE_SEEKING_TARGET );

	m_flPingTime = gpGlobals->curtime + FLOOR_TURRET_PING_TIME;
}

//-----------------------------------------------------------------------------
// Purpose: Toggle the turret's state
//-----------------------------------------------------------------------------
void CNPC_FloorTurret::Toggle( void )
{
	//This turret is on its side, it can't function
	if ( OnSide() || ( IsAlive() == false ) )
		return;

	//Toggle the state
	if ( m_bEnabled )
	{
		Disable();
	}
	else 
	{
		Enable();
	}
}

//-----------------------------------------------------------------------------
// Purpose: Enable the turret and deploy
//-----------------------------------------------------------------------------
void CNPC_FloorTurret::Enable( void )
{
	// Don't interrupt blowing up!
	if ( m_bSelfDestructing )
		return;

	// Always allow us to come back to life, even if not right now
	m_bEnabled = true;

	//This turret is on its side, it can't function
	if ( OnSide() || ( IsAlive() == false ) )
		return;

	// if the turret is flagged as an autoactivate turret, re-enable its ability open self.
	if ( m_spawnflags & SF_FLOOR_TURRET_AUTOACTIVATE )
	{
		m_bAutoStart = true;
	}

	SetThink( &CNPC_FloorTurret::Deploy );
	SetNextThink( gpGlobals->curtime + 0.05f );
}

//-----------------------------------------------------------------------------
// Purpose: Retire the turret until enabled again
//-----------------------------------------------------------------------------
void CNPC_FloorTurret::Disable( void )
{
	//This turret is on its side, it can't function
	if ( OnSide() || ( IsAlive() == false ) || m_bSelfDestructing )
		return;

	if ( m_bEnabled )
	{
		m_bEnabled = false;
		m_bAutoStart = false;

		SetEnemy( NULL );
		SetThink( &CNPC_FloorTurret::Retire );
		SetNextThink( gpGlobals->curtime + 0.1f );
	}
	else
		SetThink( &CNPC_FloorTurret::DisabledThink );
}

//-----------------------------------------------------------------------------
// Purpose: Toggle the turret's state via input function
//-----------------------------------------------------------------------------
void CNPC_FloorTurret::InputToggle( inputdata_t &inputdata )
{
	Toggle();
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CNPC_FloorTurret::InputEnable( inputdata_t &inputdata )
{
	Enable();
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CNPC_FloorTurret::InputDisable( inputdata_t &inputdata )
{
	Disable();
}

//-----------------------------------------------------------------------------
// Purpose: Stops the turret from firing live rounds (still attempts to though)
//-----------------------------------------------------------------------------
void CNPC_FloorTurret::InputDepleteAmmo( inputdata_t &inputdata )
{
	AddSpawnFlags( SF_FLOOR_TURRET_OUT_OF_AMMO );
}

//-----------------------------------------------------------------------------
// Purpose: Allows the turret to fire live rounds again
//-----------------------------------------------------------------------------
void CNPC_FloorTurret::InputRestoreAmmo( inputdata_t &inputdata )
{
	RemoveSpawnFlags( SF_FLOOR_TURRET_OUT_OF_AMMO );
}

//-----------------------------------------------------------------------------
// Purpose: Allow players and npc's to turn the turret on and off
//-----------------------------------------------------------------------------
void CNPC_FloorTurret::ToggleUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
	switch( useType )
	{
	case USE_OFF:
		Disable();
		break;
	case USE_ON:
		Enable();
		break;
	case USE_SET:
		break;
	case USE_TOGGLE:
		Toggle( );
		break;
	}
}

//-----------------------------------------------------------------------------
// Purpose: Reduce physics forces from the front
//-----------------------------------------------------------------------------
int CNPC_FloorTurret::VPhysicsTakeDamage( const CTakeDamageInfo &info )
{
	bool bShouldIgnoreFromFront = false;

	// Ignore crossbow bolts hitting us from the front
	bShouldIgnoreFromFront = ( info.GetDamageType() & DMG_BULLET ) != 0;

	// Ignore bullets from the front
	if ( !bShouldIgnoreFromFront )
	{
		bShouldIgnoreFromFront = FClassnameIs( info.GetInflictor(), "crossbow_bolt" );
	}

	// Did it hit us on the front?
	if ( bShouldIgnoreFromFront )
	{
		Vector vecForward;
		GetVectors( &vecForward, NULL, NULL );
		Vector vecForce = info.GetDamageForce();
		VectorNormalize( vecForce );
		float flDot = DotProduct( vecForward, vecForce );
		if ( flDot < -0.85 )
			return 0;
	}

	return BaseClass::VPhysicsTakeDamage( info );
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  : &info - 
//-----------------------------------------------------------------------------
int CNPC_FloorTurret::OnTakeDamage( const CTakeDamageInfo &info )
{
	CTakeDamageInfo	newInfo = info;

	if ( info.GetDamageType() & (DMG_SLASH|DMG_CLUB) )
	{
		// Take extra force from melee hits
		newInfo.ScaleDamageForce( 2.0f );
		
		// Disable our upright controller for some time
		if ( m_pMotionController != NULL )
		{
			m_pMotionController->Suspend( 2.0f );
		}
	}
	else if ( info.GetDamageType() & DMG_BLAST )
	{
		newInfo.ScaleDamageForce( 2.0f );
	}
	else if ( (info.GetDamageType() & DMG_BULLET) && !(info.GetDamageType() & DMG_BUCKSHOT) )
	{
		// Bullets, but not buckshot, do extra push
		newInfo.ScaleDamageForce( 2.5f );
	}

	// Manually apply vphysics because AI_BaseNPC takedamage doesn't call back to CBaseEntity OnTakeDamage
	VPhysicsTakeDamage( newInfo );

	// Bump up our search time
	m_flLastSight = gpGlobals->curtime + FLOOR_TURRET_MAX_WAIT;

	// Start looking around in anger if we were idle
	if ( IsAlive() && m_bEnabled && m_bAutoStart && GetActivity() == ACT_FLOOR_TURRET_CLOSED_IDLE && m_bSelfDestructing == false )
	{
		SetThink( &CNPC_FloorTurret::Deploy );
	}

	return BaseClass::OnTakeDamage( newInfo );
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CNPC_FloorTurret::SpinUp( void )
{
}

#define	FLOOR_TURRET_MIN_SPIN_DOWN	1.0f

//-----------------------------------------------------------------------------
// Purpose: 
// Output : const QAngle
//-----------------------------------------------------------------------------
QAngle CNPC_FloorTurret::PreferredCarryAngles( void )
{
	// FIXME: Embed this into the class
	static QAngle g_prefAngles;

	Vector vecUserForward;
	CBasePlayer *pPlayer = AI_GetSinglePlayer();
	pPlayer->EyeVectors( &vecUserForward );

	// If we're looking up, then face directly forward
	if ( vecUserForward.z >= 0.0f )
		return vec3_angle;

	// Otherwise, stay "upright"
	g_prefAngles.Init();
	g_prefAngles.x = -pPlayer->EyeAngles().x;
	
	return g_prefAngles;
}


//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CNPC_FloorTurret::SpinDown( void )
{
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  : *pVictim - 
// Output : float
//-----------------------------------------------------------------------------
float CNPC_FloorTurret::GetAttackDamageScale( CBaseEntity *pVictim )
{
	CBaseCombatCharacter *pBCC = pVictim->MyCombatCharacterPointer();

	// Do extra damage to antlions & combine
	if ( pBCC )
	{
		if ( pBCC->Classify() == CLASS_ANTLION )
			return 2.0;
			
		if ( pBCC->Classify() == CLASS_COMBINE )
			return 2.0;
	}

	return BaseClass::GetAttackDamageScale( pVictim );
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
Vector CNPC_FloorTurret::GetAttackSpread( CBaseCombatWeapon *pWeapon, CBaseEntity *pTarget ) 
{
	WeaponProficiency_t weaponProficiency = WEAPON_PROFICIENCY_AVERAGE;

	// Switch our weapon proficiency based upon our target
	if ( pTarget )
	{
		if ( pTarget->Classify() == CLASS_PLAYER || pTarget->Classify() == CLASS_ANTLION || pTarget->Classify() == CLASS_ZOMBIE )
		{
			// Make me much more accurate
			weaponProficiency = WEAPON_PROFICIENCY_PERFECT;
		}
		else if ( pTarget->Classify() == CLASS_COMBINE )
		{
			// Make me more accurate
			weaponProficiency = WEAPON_PROFICIENCY_VERY_GOOD;
		}
	}

	return VECTOR_CONE_10DEGREES * ((CBaseHLCombatWeapon::GetDefaultProficiencyValues())[ weaponProficiency ].spreadscale);
}

//------------------------------------------------------------------------------
// Do we have a physics attacker?
//------------------------------------------------------------------------------
CBasePlayer *CNPC_FloorTurret::HasPhysicsAttacker( float dt )
{
	// If the player is holding me now, or I've been recently thrown
	// then return a pointer to that player
	if ( IsHeldByPhyscannon( ) || (gpGlobals->curtime - dt <= m_flLastPhysicsInfluenceTime) )
	{
		return m_hPhysicsAttacker;
	}
	return NULL;
}
//-----------------------------------------------------------------------------
// Purpose: Draw any debug text overlays
// Output : Current text offset from the top
//-----------------------------------------------------------------------------
int CNPC_FloorTurret::DrawDebugTextOverlays( void ) 
{
	int text_offset = BaseClass::DrawDebugTextOverlays();

	if (m_debugOverlays & OVERLAY_TEXT_BIT) 
	{
		if (VPhysicsGetObject())
		{
			char tempstr[512];
			Q_snprintf(tempstr, sizeof(tempstr),"Mass: %.2f kg / %.2f lb (%s)", VPhysicsGetObject()->GetMass(), kg2lbs(VPhysicsGetObject()->GetMass()), GetMassEquivalent(VPhysicsGetObject()->GetMass()));
			EntityText( text_offset, tempstr, 0);
			text_offset++;
		}
	}

	return text_offset;
}

void CNPC_FloorTurret::UpdateMuzzleMatrix()
{
	if ( gpGlobals->tickcount != m_muzzleToWorldTick )
	{
		m_muzzleToWorldTick = gpGlobals->tickcount;
		GetAttachment( m_iMuzzleAttachment, m_muzzleToWorld );
	}
}

//-----------------------------------------------------------------------------
// Purpose: We override this code because otherwise we start to move into the
//			tricky realm of player avoidance.  Since we don't go through the
//			normal NPC thinking but we ARE an NPC (...) we miss a bunch of 
//			book keeping.  This means we can become invisible and then never
//			reappear.
//-----------------------------------------------------------------------------
void CNPC_FloorTurret::PlayerPenetratingVPhysics( void )
{
	// We don't care!
}

#define SELF_DESTRUCT_DURATION			4.0f
#define SELF_DESTRUCT_BEEP_MIN_DELAY	0.1f
#define SELF_DESTRUCT_BEEP_MAX_DELAY	0.75f
#define SELF_DESTRUCT_BEEP_MIN_PITCH	100.0f
#define SELF_DESTRUCT_BEEP_MAX_PITCH	225.0f

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CNPC_FloorTurret::BreakThink( void )
{
	Vector vecUp;
	GetVectors( NULL, NULL, &vecUp );
	Vector vecOrigin = WorldSpaceCenter() + ( vecUp * 12.0f );

	// Our effect
#ifdef HL2_EPISODIC
	DispatchParticleEffect( "explosion_turret_break", vecOrigin, GetAbsAngles() );
#endif // HL2_EPISODIC

	// K-boom
	RadiusDamage( CTakeDamageInfo( this, this, 15.0f, DMG_BLAST ), vecOrigin, (10*12), CLASS_NONE, this );

	EmitSound( "NPC_FloorTurret.Destruct" );

	breakablepropparams_t params( GetAbsOrigin(), GetAbsAngles(), vec3_origin, RandomAngularImpulse( -800.0f, 800.0f ) );
	params.impactEnergyScale = 1.0f;
	params.defCollisionGroup = COLLISION_GROUP_INTERACTIVE;

	// no damage/damage force? set a burst of 100 for some movement
	params.defBurstScale = 100;
	PropBreakableCreateAll( GetModelIndex(), VPhysicsGetObject(), params, this, -1, true );

	// Throw out some small chunks too obscure the explosion even more
	CPVSFilter filter( vecOrigin );
	for ( int i = 0; i < 4; i++ )
	{
		Vector gibVelocity = RandomVector(-100,100);
		int iModelIndex = modelinfo->GetModelIndex( g_PropDataSystem.GetRandomChunkModel( "MetalChunks" ) );	
		te->BreakModel( filter, 0.0, vecOrigin, GetAbsAngles(), Vector(40,40,40), gibVelocity, iModelIndex, 150, 4, 2.5, BREAK_METAL );
	}

	// We're done!
	UTIL_Remove( this );
}

//-----------------------------------------------------------------------------
// Purpose: The countdown to destruction!
//-----------------------------------------------------------------------------
void CNPC_FloorTurret::SelfDestructThink( void )
{
	// Continue to animate
	PreThink( TURRET_SELF_DESTRUCTING );

	// If we're done, explode
	if ( ( gpGlobals->curtime - m_flDestructStartTime ) >= SELF_DESTRUCT_DURATION )
	{
		SetThink( &CNPC_FloorTurret::BreakThink );
		SetNextThink( gpGlobals->curtime + 0.1f );
		UTIL_Remove( m_hFizzleEffect );
		m_hFizzleEffect = NULL;
		return;
	}

	// Find out where we are in the cycle of our destruction
	float flDestructPerc = clamp( ( gpGlobals->curtime - m_flDestructStartTime ) / SELF_DESTRUCT_DURATION, 0.0f, 1.0f );

	// Figure out when our next beep should occur
	float flBeepTime = SELF_DESTRUCT_BEEP_MAX_DELAY + ( ( SELF_DESTRUCT_BEEP_MIN_DELAY - SELF_DESTRUCT_BEEP_MAX_DELAY ) * flDestructPerc );

	// If it's time to beep again, do so
	if ( gpGlobals->curtime > ( m_flPingTime + flBeepTime ) )
	{
		// Figure out what our beep pitch will be
		float flBeepPitch = SELF_DESTRUCT_BEEP_MIN_PITCH + ( ( SELF_DESTRUCT_BEEP_MAX_PITCH - SELF_DESTRUCT_BEEP_MIN_PITCH ) * flDestructPerc );
		
		StopSound( "NPC_FloorTurret.AlarmPing" );

		// Play the beep
		CPASAttenuationFilter filter( this, "NPC_FloorTurret.AlarmPing" );
		EmitSound_t params;
		params.m_pSoundName = "NPC_FloorTurret.AlarmPing";
		params.m_nPitch = floor( flBeepPitch );
		params.m_nFlags = SND_CHANGE_PITCH;
		EmitSound( filter, entindex(), params );
		
		// Flash our eye
		SetEyeState( TURRET_EYE_ALARM );
		
		// Save this as the last time we pinged
		m_flPingTime = gpGlobals->curtime;
		
		// Randomly twitch
		m_vecGoalAngles.x = GetAbsAngles().x + random->RandomFloat( -60*flDestructPerc, 60*flDestructPerc );
		m_vecGoalAngles.y = GetAbsAngles().y + random->RandomFloat( -60*flDestructPerc, 60*flDestructPerc );
	}
	
	UpdateFacing();

	// Think again!
	SetNextThink( gpGlobals->curtime + 0.05f );
}

//-----------------------------------------------------------------------------
// Purpose: Make us explode
//-----------------------------------------------------------------------------
void CNPC_FloorTurret::InputSelfDestruct( inputdata_t &inputdata )
{
	// Ka-boom!
	m_flDestructStartTime = gpGlobals->curtime;
	m_flPingTime = gpGlobals->curtime;
	m_bSelfDestructing = true;

	SetThink( &CNPC_FloorTurret::SelfDestructThink );
	SetNextThink( gpGlobals->curtime + 0.1f );

	// Create the dust effect in place
	m_hFizzleEffect = (CParticleSystem *) CreateEntityByName( "info_particle_system" );
	if ( m_hFizzleEffect != NULL )
	{
		Vector vecUp;
		GetVectors( NULL, NULL, &vecUp );

		// Setup our basic parameters
		m_hFizzleEffect->KeyValue( "start_active", "1" );
		m_hFizzleEffect->KeyValue( "effect_name", "explosion_turret_fizzle" );
		m_hFizzleEffect->SetParent( this );
		m_hFizzleEffect->SetAbsOrigin( WorldSpaceCenter() + ( vecUp * 12.0f ) );
		DispatchSpawn( m_hFizzleEffect );
		m_hFizzleEffect->Activate();
	}
}

// 
// Tip controller
//

LINK_ENTITY_TO_CLASS( floorturret_tipcontroller, CTurretTipController );


//---------------------------------------------------------
// Save/Restore
//---------------------------------------------------------
BEGIN_DATADESC( CTurretTipController )

	DEFINE_FIELD( m_bEnabled,			FIELD_BOOLEAN ),
	DEFINE_FIELD( m_flSuspendTime,	FIELD_TIME ),
	DEFINE_FIELD( m_worldGoalAxis,	FIELD_VECTOR ),
	DEFINE_FIELD( m_localTestAxis,	FIELD_VECTOR ),
	DEFINE_PHYSPTR( m_pController ),
	DEFINE_FIELD( m_angularLimit,		FIELD_FLOAT ),
	DEFINE_FIELD( m_pParentTurret,	FIELD_CLASSPTR ),

END_DATADESC()



CTurretTipController::~CTurretTipController()
{
	if ( m_pController )
	{
		physenv->DestroyMotionController( m_pController );
		m_pController = NULL;
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CTurretTipController::Spawn( void )
{
	m_bEnabled = true;

	// align the object's local Z axis
	m_localTestAxis.Init( 0, 0, 1 );
	// with the world's Z axis
	m_worldGoalAxis.Init( 0, 0, 1 );

	// recover from up to 25 degrees / sec angular velocity
	m_angularLimit	= 25;
	m_flSuspendTime	= 0;

	SetMoveType( MOVETYPE_NONE );
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CTurretTipController::Activate( void )
{
	BaseClass::Activate();

	if ( m_pParentTurret == NULL )
	{
		UTIL_Remove(this);
		return;
	}

	IPhysicsObject *pPhys = m_pParentTurret->VPhysicsGetObject();

	if ( pPhys == NULL )
	{
		UTIL_Remove(this);
		return;
	}

	//Setup the motion controller
	if ( !m_pController )
	{
		m_pController = physenv->CreateMotionController( (IMotionEvent *)this );
		m_pController->AttachObject( pPhys, true );
	}
	else
	{
		m_pController->SetEventHandler( this );
	}
}


//-----------------------------------------------------------------------------
// Purpose: Actual simulation for tip controller
//-----------------------------------------------------------------------------
IMotionEvent::simresult_e CTurretTipController::Simulate( IPhysicsMotionController *pController, IPhysicsObject *pObject, float deltaTime, Vector &linear, AngularImpulse &angular )
{
	if ( Enabled() == false )
		return SIM_NOTHING;

	// Don't simulate if we're being carried by the player
	if ( m_pParentTurret->IsBeingCarriedByPlayer() )
		return SIM_NOTHING;

	float flAngularLimit = m_angularLimit;

	// If we were just dropped by a friendly player, stabilise better
	if ( m_pParentTurret->WasJustDroppedByPlayer() )
	{
		// Increase the controller strength a little
		flAngularLimit += 20;
	}
	else
	{
		// If the turret has some vertical velocity, don't simulate
		Vector vecVelocity;
		AngularImpulse angImpulse;
		pObject->GetVelocity( &vecVelocity, &angImpulse );
		if ( (vecVelocity.LengthSqr() > CNPC_FloorTurret::fMaxTipControllerVelocity) || (angImpulse.LengthSqr() > CNPC_FloorTurret::fMaxTipControllerAngularVelocity) )
			return SIM_NOTHING;
	}

	linear.Init();

	AngularImpulse angVel;
	pObject->GetVelocity( NULL, &angVel );

	matrix3x4_t matrix;
	// get the object's local to world transform
	pObject->GetPositionMatrix( &matrix );

	// Get the alignment axis in object space
	Vector currentLocalTargetAxis;
	VectorIRotate( m_worldGoalAxis, matrix, currentLocalTargetAxis );

	float invDeltaTime = (1/deltaTime);
	angular = ComputeRotSpeedToAlignAxes( m_localTestAxis, currentLocalTargetAxis, angVel, 1.0, invDeltaTime * invDeltaTime, flAngularLimit * invDeltaTime );

	return SIM_LOCAL_ACCELERATION;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CTurretTipController::Enable( bool state )
{
	m_bEnabled = state;
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  : time - 
//-----------------------------------------------------------------------------
void CTurretTipController::Suspend( float time )
{
	m_flSuspendTime = gpGlobals->curtime + time;
}


float CTurretTipController::SuspendedTill( void )
{
	return m_flSuspendTime;
}

//-----------------------------------------------------------------------------
// Purpose: 
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CTurretTipController::Enabled( void )
{
	if ( m_flSuspendTime > gpGlobals->curtime )
		return false;

	return m_bEnabled;
}

//-----------------------------------------------------------------------------
//
// Schedules
//
//-----------------------------------------------------------------------------
AI_BEGIN_CUSTOM_NPC( npc_turret_floor, CNPC_FloorTurret )

	DECLARE_INTERACTION( g_interactionTurretStillStanding );	

AI_END_CUSTOM_NPC()


thank you, also @Copperbotte i’m using valve’s origional code to create a new one by modifying it.

edit: I expected something with a list of


ENT.Model = 
ENT.health = 100000
ENT.Alerted = false

and ENT. things.

Banshee. Since you clearly cannot read. Valve does not, and never has used Lua to code anything. Garry’s Mod, created by Garry Newman, not Valve, inserted a Lua engine into the source engine, again in C++. Therefore, your asking for us to pull something out of thin air that doesn’t exist. There is no Valve made .lua file, that will give you a floor turret. As said by everyone in here, go to www.garrysmod.org, and download one and change it to how you like.

Note. The code you posted, is in Lua, not C++ which once again would have to be a user generated file, not a Valve made one.

Please stop being stupid.

Good god I hate you.

LUA AND C++ ARE TWO DIFFERENT LANGUAGES.

You cant just edit the C++ that Copperbotte posted and put it in a Lua file, please dear sweet jesus, either stop trolling or start reading.


(User was banned for this post ("Why reply?" - mahalis))

Quit feeding the troll?

I never posted anything.
He is probably wanting to make a NPC base for his custom NPC, then use Lua to implement it.
Unfortunately, this will not work, because you cannot edit the source code.
you are stuck using Lua for this project.