enum BUSPAnimation
{
	BUSP_IDLE = 0,
	BUSP_SHOOT1,
	BUSP_SHOOT2,
	BUSP_SHOOT3,
	BUSP_SHOOTLAST,
	BUSP_RELOAD,
	BUSP_DRAW,
	BUSP_ADD_SILENCER,
	BUSP_IDLE_UNSIL,
	BUSP_SHOOT1_UNSIL,
	BUSP_SHOOT2_UNSIL,
	BUSP_SHOOT3_UNSIL,
	BUSP_SHOOTLAST_UNSIL,
	BUSP_RELOAD_UNSIL,
	BUSP_DRAW_UNSIL,
	BUSP_DETACH_SILENCER
};

const int BUSP_DEFAULT_GIVE	= 112;
const int BUSP_MAX_CARRY 	= 100;
const int BUSP_MAX_CLIP  	= 12;
const int BUSP_WEIGHT    	= 5;

class weapon_busp45 : ScriptBasePlayerWeaponEntity
{
	float m_flNextAnimTime;
	int g_iCurrentMode;
	int m_iShotsFired;
	int m_iShell;
	
	void Spawn()
	{
		Precache();
		g_EntityFuncs.SetModel( self, "models/CSOZBS/z4/weapons/w_busp45.mdl" );
		
		self.m_iDefaultAmmo = BUSP_DEFAULT_GIVE;
		m_iShotsFired = 0;
		g_iCurrentMode = 0;
		
		self.FallInit();
	}
	
	void Precache()
	{
		self.PrecacheCustomModels();
		g_Game.PrecacheModel( "models/CSOZBS/z4/weapons/v_busp45.mdl");
		g_Game.PrecacheModel( "models/CSOZBS/z4/weapons/w_busp45.mdl");
		g_Game.PrecacheModel( "models/CSOZBS/z4/weapons/p_busp45.mdl");
		g_Game.PrecacheModel( "models/cs16ammo/45acp/w_45acp.mdl" );
		g_Game.PrecacheModel( "models/cs16ammo/45acp/w_45acpt.mdl" );
		
		m_iShell = g_Game.PrecacheModel ( "models/cs16shells/pshell.mdl");
		
		g_Game.PrecacheGeneric( "sound/" + "weapons/dryfire_pistol.wav" );
		g_Game.PrecacheGeneric( "sound/" + "weapons/usp_unsil-1.wav" );
		g_Game.PrecacheGeneric( "sound/" + "weapons/usp2.wav" );
		g_Game.PrecacheGeneric( "sound/" + "weapons/usp1.wav" );
		g_Game.PrecacheGeneric( "sound/" + "weapons/usp_silencer_off.wav" );
		g_Game.PrecacheGeneric( "sound/" + "weapons/usp_silencer_on.wav" );
		g_Game.PrecacheGeneric( "sound/" + "weapons/usp_clipout.wav" );
		g_Game.PrecacheGeneric( "sound/" + "weapons/usp_clipin.wav" );
		g_Game.PrecacheGeneric( "sound/" + "weapons/usp_slideback.wav" );
		g_Game.PrecacheGeneric( "sound/" + "weapons/usp_sliderelease.wav" );
		
		g_SoundSystem.PrecacheSound( "items/9mmclip1.wav" );
		
		g_SoundSystem.PrecacheSound( "weapons/dryfire_pistol.wav" );
		g_SoundSystem.PrecacheSound( "weapons/usp_unsil-1.wav" );
		g_SoundSystem.PrecacheSound( "weapons/usp2.wav" );
		g_SoundSystem.PrecacheSound( "weapons/usp1.wav" );
		g_SoundSystem.PrecacheSound( "weapons/usp_silencer_off.wav");
		g_SoundSystem.PrecacheSound( "weapons/usp_silencer_on.wav" );
		g_SoundSystem.PrecacheSound( "weapons/usp_slideback.wav" );
		g_SoundSystem.PrecacheSound( "weapons/usp_sliderelease.wav" );
		g_SoundSystem.PrecacheSound( "weapons/usp_clipout.wav" );
		g_SoundSystem.PrecacheSound( "weapons/usp_clipin.wav" );
		
		g_Game.PrecacheGeneric( "sprites/" + "customweapons/640hud7.spr" );
		g_Game.PrecacheGeneric( "sprites/" + "customweapons/640hud1.spr" );
		g_Game.PrecacheGeneric( "sprites/" + "customweapons/640hud4.spr" );
		g_Game.PrecacheGeneric( "sprites/" + "customweapons/crosshairs.spr" );
		g_Game.PrecacheGeneric( "sprites/" + "customweapons/weapon_usp.txt" );
	}
	
	bool GetItemInfo( ItemInfo& out info )
	{
		info.iMaxAmmo1	= BUSP_MAX_CARRY;
		info.iMaxAmmo2	= -1;
		info.iMaxClip	= BUSP_MAX_CLIP;
		info.iSlot		= 1;
		info.iPosition	= 7;
		info.iFlags		= 0;
		info.iWeight	= BUSP_WEIGHT;
		
		return true;
	}
	
	CBasePlayer@ getPlayer()
	{
		CBaseEntity@ e_plr = self.m_hPlayer;
		return cast<CBasePlayer@>(e_plr);
	}
	
	bool PlayEmptySound()
	{
		if( self.m_bPlayEmptySound )
		{
			self.m_bPlayEmptySound = false;
			
			g_SoundSystem.EmitSoundDyn( getPlayer().edict(), CHAN_WEAPON, "weapons/dryfire_pistol.wav", 0.9, ATTN_NORM, 0, PITCH_NORM );
		}
		
		return false;
	}
	
	bool AddToPlayer( CBasePlayer@ pPlayer )
	{
		if( BaseClass.AddToPlayer ( pPlayer ) )
		{
			NetworkMessage cs12( MSG_ONE, NetworkMessages::WeapPickup, pPlayer.edict() );
				cs12.WriteLong( self.m_iId );
			cs12.End();
			return true;
		}
		
		return false;
	}
	
	float WeaponTimeBase()
	{
		return g_Engine.time;
	}
	
	bool Deploy()
	{
		bool bResult;
		{

		if ( g_iCurrentMode == CS16_MODE_SILENCER )
		{
			bResult = self.DefaultDeploy ( self.GetV_Model( "models/CSOZBS/z4/weapons/v_busp45.mdl" ), self.GetP_Model( "models/CSOZBS/z4/weapons/p_busp45.mdl" ), BUSP_DRAW, "onehanded" );
		}
		else
		{
			bResult = self.DefaultDeploy ( self.GetV_Model( "models/CSOZBS/z4/weapons/v_busp45.mdl" ), self.GetP_Model( "models/CSOZBS/z4/weapons/p_busp45.mdl" ), BUSP_DRAW_UNSIL, "onehanded" );
		}
		
		float deployTime = 1;
		self.m_flTimeWeaponIdle = self.m_flNextPrimaryAttack = self.m_flNextSecondaryAttack = g_Engine.time + deployTime;

		return bResult;
		}
	}
	
	void PrimaryAttack()
	{
		if( getPlayer().pev.waterlevel == WATERLEVEL_HEAD || self.m_iClip <= 0 )
		{
			self.PlayEmptySound();
			self.m_flNextPrimaryAttack = WeaponTimeBase() + 0.15f;
			return;
		}

		m_iShotsFired++;
		if( m_iShotsFired > 1 )
		{
			return;
		}
		
		self.m_flNextPrimaryAttack = self.m_flNextSecondaryAttack = WeaponTimeBase() + 0.11;
		
		if( g_iCurrentMode == CS16_MODE_NOSILENCER )
		{
			getPlayer().m_iWeaponVolume = NORMAL_GUN_VOLUME;
			getPlayer().m_iWeaponFlash = BRIGHT_GUN_FLASH;
		}
		else if ( g_iCurrentMode == CS16_MODE_SILENCER )
		{
			getPlayer().m_iWeaponVolume = 0;
			getPlayer().m_iWeaponFlash = 0;
		}
		
		--self.m_iClip;
		
		getPlayer().pev.effects |= EF_MUZZLEFLASH;
		getPlayer().SetAnimation( PLAYER_ATTACK1 );
		
		if ( g_iCurrentMode == CS16_MODE_SILENCER )
		{
			if ( self.m_iClip <= 0 )
			{
				self.SendWeaponAnim( BUSP_SHOOTLAST, 0, 0 );
			}
			else
			{
				switch ( g_PlayerFuncs.SharedRandomLong( getPlayer().random_seed, 0, 2 ) )
				{
					case 0: self.SendWeaponAnim( BUSP_SHOOT1, 0, 0 ); break;
					case 1: self.SendWeaponAnim( BUSP_SHOOT2, 0, 0 ); break;
					case 2: self.SendWeaponAnim( BUSP_SHOOT3, 0, 0 ); break;
				}
			}
		}
		else if ( g_iCurrentMode == CS16_MODE_NOSILENCER )
		{
			if ( self.m_iClip <= 0 )
			{
				self.SendWeaponAnim( BUSP_SHOOTLAST_UNSIL, 0, 0 );
			}
			else
			{
				switch ( g_PlayerFuncs.SharedRandomLong( getPlayer().random_seed, 0, 2 ) )
				{
					case 0: self.SendWeaponAnim( BUSP_SHOOT1_UNSIL, 0, 0 ); break;
					case 1: self.SendWeaponAnim( BUSP_SHOOT2_UNSIL, 0, 0 ); break;
					case 2: self.SendWeaponAnim( BUSP_SHOOT3_UNSIL, 0, 0 ); break;
				}
			}
		}

		int m_iBulletDamage;
		
		if ( g_iCurrentMode == CS16_MODE_SILENCER )
		{
			switch ( Math.RandomLong (0, 1) )
			{
				case 0: g_SoundSystem.EmitSoundDyn( getPlayer().edict(), CHAN_WEAPON, "weapons/usp1.wav", 0.9, ATTN_NORM, 0, PITCH_NORM ); break;
				case 1: g_SoundSystem.EmitSoundDyn( getPlayer().edict(), CHAN_WEAPON, "weapons/usp2.wav", 0.9, ATTN_NORM, 0, PITCH_NORM ); break;
			}
			m_iBulletDamage = 18;
		}
		else if ( g_iCurrentMode == CS16_MODE_NOSILENCER )
		{
			g_SoundSystem.EmitSoundDyn( getPlayer().edict(), CHAN_WEAPON, "weapons/usp_unsil-1.wav", 1.0, ATTN_NORM, 0, PITCH_NORM );
			m_iBulletDamage = 21;
		}
		
		Vector vecSrc	 = getPlayer().GetGunPosition();
		Vector vecAiming = getPlayer().GetAutoaimVector( AUTOAIM_5DEGREES );
		
		getPlayer().FireBullets( 1, vecSrc, vecAiming, VECTOR_CONE_6DEGREES, 8192, BULLET_PLAYER_CUSTOMDAMAGE, 2, m_iBulletDamage );

		if( self.m_iClip == 0 && getPlayer().m_rgAmmo( self.m_iPrimaryAmmoType ) <= 0 )
			getPlayer().SetSuitUpdate( "!HEV_AMO0", false, 0 );
			
		getPlayer().pev.punchangle.x = Math.RandomLong( -2, -1 );

		//self.m_flNextPrimaryAttack = self.m_flNextPrimaryAttack + 0.15f;
		if( self.m_flNextPrimaryAttack < WeaponTimeBase() )
			self.m_flNextPrimaryAttack = WeaponTimeBase() + 0.15f;

		self.m_flTimeWeaponIdle = WeaponTimeBase() + Math.RandomFloat( 10, 15 );
		
		TraceResult tr;
		
		float x, y;
		
		g_Utility.GetCircularGaussianSpread( x, y );
		
		Vector vecDir = vecAiming + x * VECTOR_CONE_2DEGREES.x * g_Engine.v_right + y * VECTOR_CONE_2DEGREES.y * g_Engine.v_up;

		Vector vecEnd	= vecSrc + vecDir * 4096;

		g_Utility.TraceLine( vecSrc, vecEnd, dont_ignore_monsters, getPlayer().edict(), tr );
		
		if( tr.flFraction < 1.0 )
		{
			if( tr.pHit !is null )
			{
				CBaseEntity@ pHit = g_EntityFuncs.Instance( tr.pHit );
				
				if( pHit is null || pHit.IsBSPModel() == true )
					g_WeaponFuncs.DecalGunshot( tr, BULLET_PLAYER_MP5 );
			}
		}
		Vector vecShellVelocity, vecShellOrigin;
       
		//The last 3 parameters are unique for each weapon (this should be using an attachment in the model to get the correct position, but most models don't have that).
		CS16GetDefaultShellInfo( getPlayer(), vecShellVelocity, vecShellOrigin, 16, 7, -6, true, false );
       
		//Lefthanded weapon, so invert the Y axis velocity to match.
		vecShellVelocity.y *= 1;
       
		g_EntityFuncs.EjectBrass( vecShellOrigin, vecShellVelocity, getPlayer().pev.angles[ 1 ], m_iShell, TE_BOUNCE_SHELL );
	}

	void SecondaryAttack()
	{
		self.m_flNextSecondaryAttack = self.m_flNextPrimaryAttack = WeaponTimeBase() + 3.135f;
		switch ( g_iCurrentMode )
		{
			case CS16_MODE_NOSILENCER:
			{
				g_iCurrentMode = CS16_MODE_SILENCER;
				self.SendWeaponAnim( BUSP_ADD_SILENCER, 0, 0 );
				g_SoundSystem.EmitSoundDyn( getPlayer().edict(), CHAN_WEAPON, "sound/weapons/usp_silencer_on.wav", 0.9, ATTN_NORM, 0, PITCH_NORM);
				break;
			}
			case CS16_MODE_SILENCER:
			{
				g_iCurrentMode = CS16_MODE_NOSILENCER;
				self.SendWeaponAnim( BUSP_DETACH_SILENCER, 0, 0 );
				g_SoundSystem.EmitSoundDyn( getPlayer().edict(), CHAN_WEAPON, "sound/weapons/usp_silencer_off.wav", 0.9, ATTN_NORM, 0, PITCH_NORM);
				break;
			}
		}
		
	}
	
	void Reload()
	{
		if( self.m_iClip < BUSP_MAX_CLIP )
			BaseClass.Reload();
		
		if ( g_iCurrentMode == CS16_MODE_SILENCER )
		{
			self.DefaultReload( BUSP_MAX_CLIP, BUSP_RELOAD, 2.73, 0 );
		}
		else
		{
			self.DefaultReload( BUSP_MAX_CLIP, BUSP_RELOAD_UNSIL, 2.73, 0 );
		}
	}
	
	void WeaponIdle()
	{
		// Can we fire?
		if ( self.m_flNextPrimaryAttack < WeaponTimeBase() )
		{
		// If the player is still holding the attack button, m_iShotsFired won't reset to 0
		// Preventing the automatic firing of the weapon
			if ( !( ( getPlayer().pev.button & IN_ATTACK ) != 0 ) )
			{
				// Player released the button, reset now
				m_iShotsFired = 0;
			}
		}

		self.ResetEmptySound();

		getPlayer().GetAutoaimVector( AUTOAIM_10DEGREES );
		
		if( self.m_flTimeWeaponIdle > WeaponTimeBase() )
		{
			return;
		}
		
		int iAnim;
		switch ( Math.RandomLong ( 0, 0 ) )
		{
			case 0:
			if( g_iCurrentMode == CS16_MODE_SILENCER )
			{
				iAnim = BUSP_IDLE; break;
			}
			else
			{
				iAnim = BUSP_IDLE_UNSIL; break;
			}
		}
		
		self.SendWeaponAnim( iAnim );
		self.m_flTimeWeaponIdle = WeaponTimeBase() + Math.RandomFloat( 10, 15 );
	}
}

class BUSPAmmoBox : ScriptBasePlayerAmmoEntity
{
	void Spawn()
	{
		Precache();
		g_EntityFuncs.SetModel( self, "models/cs16ammo/45acp/w_45acp.mdl" );
		BaseClass.Spawn();
	}
	
	void Precache()
	{
		g_Game.PrecacheModel( "models/cs16ammo/45acp/w_45acp.mdl" );
		g_Game.PrecacheModel( "models/cs16ammo/45acp/w_45acpt.mdl" );
		g_SoundSystem.PrecacheSound( "items/9mmclip1.wav" );
	}

	bool AddAmmo( CBaseEntity@ pither )
	{
		int iGive;
		
		iGive = BUSP_DEFAULT_GIVE;
		
		if( pither.GiveAmmo( iGive, "ammo_45acpb", BUSP_MAX_CARRY ) != -1 )
		{
			g_SoundSystem.EmitSound( self.edict(), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM );
			return true;
		}
		return false;
	}
}

string GetBUSPName()
{
	return "weapon_busp45";
}

void RegisterBUSP()
{
	g_CustomEntityFuncs.RegisterCustomEntity( GetBUSPName(), GetBUSPName() );
	g_ItemRegistry.RegisterWeapon( GetBUSPName(), "wpn", "ammo_45acpb" );
}

string GetBUSPAmmoBoxName()
{
	return "ammo_45acpb";
}

void RegisterBUSPAmmoBox()
{
	g_CustomEntityFuncs.RegisterCustomEntity( "BUSPAmmoBox", GetBUSPAmmoBoxName() );
}