/***
*
*    Copyright (c) 1996-2001, Valve LLC. All rights reserved.
*    
*    This product contains software technology licensed from Id 
*    Software, Inc. ("Id Technology").  Id Technology (c) 1996 Id Software, Inc. 
*    All Rights Reserved.
*
*    Use, distribution, and modification of this source code and/or resulting
*    object code is restricted to non-commercial enhancements to products from
*    Valve LLC.  All other use, distribution, or modification is prohibited
*    without written permission from Valve LLC.
*
****/

/* 
* The original Half-Life version of the glock
* modified to include the silenced variation. // Rzlx
* Use attack3 key to toggle between variations. // Rzlx
*/

const int GLOCK_DEFAULT_GIVE = 34;
const int _9MM_MAX_CARRY = 250;
const int GLOCK_MAX_CLIP = 17;
const int GLOCK_WEIGHT = 10;

enum GlockAnimation
{
	GLOCK_IDLE1 = 0,
	GLOCK_IDLE2,
	GLOCK_IDLE3,
	GLOCK_SHOOT,
	GLOCK_SHOOT_EMPTY,
	GLOCK_RELOAD,
	GLOCK_RELOAD_NOT_EMPTY,
	GLOCK_DRAW,
	GLOCK_HOLSTER,
	GLOCK_ADD_SILENCER
};

enum SilencedOptions
{
	SILENCED_OFF = 0,
	SILENCED_ON
};

class weapon_hlglock : ScriptBasePlayerWeaponEntity
{
	CBasePlayer@ m_pPlayer = null;

	int m_iShell;
	int m_iSilenced;
	
	void Spawn()
	{
		Precache();
		g_EntityFuncs.SetModel( self, "models/hlclassic/w_9mmhandgun.mdl" );
		m_iSilenced = SILENCED_OFF;

		self.m_iDefaultAmmo = GLOCK_DEFAULT_GIVE;

		self.FallInit();
	}

	void Precache()
	{
		self.PrecacheCustomModels();
		
		g_Game.PrecacheModel("models/hlclassic/v_9mmhandgun.mdl");
		g_Game.PrecacheModel("models/hlclassic/w_9mmhandgun.mdl");
		g_Game.PrecacheModel("models/hlclassic/p_9mmhandgun.mdl");

		m_iShell = g_Game.PrecacheModel ("models/hlclassic/shell.mdl");// brass shell

		g_SoundSystem.PrecacheSound("hlclassic/items/9mmclip1.wav");
		g_SoundSystem.PrecacheSound("hlclassic/items/9mmclip2.wav");

		g_SoundSystem.PrecacheSound ("hlclassic/weapons/pl_gun1.wav");//silenced handgun
		g_SoundSystem.PrecacheSound ("hlclassic/weapons/pl_gun2.wav");//silenced handgun
		g_SoundSystem.PrecacheSound ("hlclassic/weapons/pl_gun3.wav");//handgun

		g_Game.PrecacheGeneric( "sprites/hl_weapons/weapon_hlglock.txt" );
	}

	bool GetItemInfo( ItemInfo& out info )
	{
		info.iMaxAmmo1 	= _9MM_MAX_CARRY;
		info.iMaxAmmo2 	= -1;
		info.iMaxClip 	= GLOCK_MAX_CLIP;
		info.iSlot 	= 1;
		info.iPosition 	= 4;
		info.iFlags 	= 0;
		info.iWeight 	= GLOCK_WEIGHT;

		return true;
	}

	bool AddToPlayer( CBasePlayer@ pPlayer )
	{
		if( !BaseClass.AddToPlayer( pPlayer ) )
			return false;
			
		@m_pPlayer = pPlayer;
			
		NetworkMessage message( MSG_ONE, NetworkMessages::WeapPickup, pPlayer.edict() );
			message.WriteLong( self.m_iId );
		message.End();

		return true;
	}
	
	bool PlayEmptySound()
	{
		if( self.m_bPlayEmptySound )
		{
			self.m_bPlayEmptySound = false;
		
			g_SoundSystem.EmitSoundDyn( m_pPlayer.edict(), CHAN_WEAPON, "weapons/357_cock1.wav", 0.8, ATTN_NORM, 0, PITCH_NORM );
		}
		
		return false;
	}

	bool Deploy()
	{
		return self.DefaultDeploy( self.GetV_Model( "models/hlclassic/v_9mmhandgun.mdl" ), self.GetP_Model( "models/hlclassic/p_9mmhandgun.mdl" ), GLOCK_DRAW, "onehanded", 0, m_iSilenced == SILENCED_ON ? 1 : 0 );
	}

	void PrimaryAttack()
	{
		GlockFire( 0.01, 0.3, true );
	}

	void SecondaryAttack()
	{
		GlockFire( 0.1, 0.2, false );
	}

	void TertiaryAttack() //new animations would be needed to make them fit better
	{
		switch( m_iSilenced )
		{
			case SILENCED_ON:
			{
				m_iSilenced = SILENCED_OFF;
				self.SendWeaponAnim( GLOCK_ADD_SILENCER, 0, m_iSilenced == SILENCED_ON ? 1 : 0 );
				break;
			}
			case SILENCED_OFF:
			{
				m_iSilenced = SILENCED_ON;
				self.SendWeaponAnim( GLOCK_ADD_SILENCER, 0, m_iSilenced == SILENCED_ON ? 1 : 0 );
				break;
			}
	}
		self.m_flTimeWeaponIdle = self.m_flNextSecondaryAttack = self.m_flNextPrimaryAttack = self.m_flNextTertiaryAttack = g_Engine.time + 3.39;
    	}

	void GlockFire( float flSpread , float flCycleTime, const bool fUseAutoAim )
	{
		if (self.m_iClip <= 0)
		{
			PlayEmptySound();
			self.m_flNextPrimaryAttack = g_Engine.time + 0.2;
			return;
		}

		self.m_iClip--;

		m_pPlayer.pev.effects |= EF_MUZZLEFLASH;

		// player "shoot" animation
		m_pPlayer.SetAnimation( PLAYER_ATTACK1 );

		m_pPlayer.m_iWeaponVolume = m_iSilenced == SILENCED_ON ? QUIET_GUN_VOLUME : NORMAL_GUN_VOLUME;
		m_pPlayer.m_iWeaponFlash = m_iSilenced == SILENCED_ON ? DIM_GUN_FLASH : NORMAL_GUN_FLASH;

		// silenced
		if( m_iSilenced == SILENCED_ON )
		{
			switch( Math.RandomLong( 0, 1 ) ){
			case 0:
				g_SoundSystem.EmitSoundDyn( m_pPlayer.edict(), CHAN_WEAPON, "hlclassic/weapons/pl_gun1.wav", 1, ATTN_NORM, 0, PITCH_NORM );
				break;
			case 1:
				g_SoundSystem.EmitSoundDyn( m_pPlayer.edict(), CHAN_WEAPON, "hlclassic/weapons/pl_gun2.wav", 1, ATTN_NORM, 0, PITCH_NORM );
				break;
			}
		}
		else
		{
			// non-silenced
			g_SoundSystem.EmitSoundDyn( m_pPlayer.edict(), CHAN_WEAPON, "hlclassic/weapons/pl_gun3.wav", 1, ATTN_NORM, 0, PITCH_NORM );
		}
		
		self.SendWeaponAnim( self.m_iClip <= 0 ? GLOCK_SHOOT_EMPTY : GLOCK_SHOOT, 0, m_iSilenced == SILENCED_ON ? 1 : 0 );
		
		Vector vecSrc	 = m_pPlayer.GetGunPosition( );
		Vector vecAiming;
		
		if ( fUseAutoAim )
		{
			vecAiming = m_pPlayer.GetAutoaimVector( AUTOAIM_10DEGREES );
		}
		else
		{
			vecAiming = g_Engine.v_forward;
		}

		m_pPlayer.FireBullets( 1, vecSrc, vecAiming, Vector( flSpread, flSpread, flSpread ), 8192, BULLET_PLAYER_9MM, 0 );
				
		Vector vecOrigin;
		vecOrigin = m_pPlayer.pev.origin + m_pPlayer.pev.view_ofs + g_Engine.v_up * -12 + g_Engine.v_forward * 25 + g_Engine.v_right * 6;

		Vector vecVelocity = m_pPlayer.pev.velocity 
							+ g_Engine.v_right * Math.RandomFloat(50,70) 
							+ g_Engine.v_up * Math.RandomFloat(100,150) 
							+ g_Engine.v_forward * 25;
		g_EntityFuncs.EjectBrass( vecOrigin, vecVelocity, m_pPlayer.pev.angles.y, m_iShell, TE_BOUNCE_SHELL );

		self.m_flNextPrimaryAttack = self.m_flNextSecondaryAttack = g_Engine.time + flCycleTime;

		if( self.m_iClip == 0 && m_pPlayer.m_rgAmmo( self.m_iPrimaryAmmoType ) <= 0 )
			// HEV suit - indicate out of ammo condition
			m_pPlayer.SetSuitUpdate( "!HEV_AMO0", false, 0 );

		self.m_flTimeWeaponIdle = g_Engine.time + g_PlayerFuncs.SharedRandomFloat( m_pPlayer.random_seed, 10, 15 );

		TraceResult tr;
		float x, y;
		g_Utility.GetCircularGaussianSpread( x, y );
		Vector vecDir = vecAiming + x * flSpread * g_Engine.v_right + y * flSpread  * g_Engine.v_up;
		Vector vecEnd = vecSrc + vecDir * 4096;
		g_Utility.TraceLine( vecSrc, vecEnd, dont_ignore_monsters, m_pPlayer.edict(), tr );

		if( tr.flFraction < 1.0f )
		{
			if( tr.pHit !is null )
			{
				CBaseEntity@ pHit = g_EntityFuncs.Instance( tr.pHit );
			
				if( pHit is null || pHit.IsBSPModel() )
					g_WeaponFuncs.DecalGunshot( tr, BULLET_PLAYER_9MM );
			}
		}
	}

	void Reload()
	{
		if( m_pPlayer.m_rgAmmo( self.m_iPrimaryAmmoType ) <= 0 || self.m_iClip == GLOCK_MAX_CLIP )
			return;
		bool bResult;
		if (self.m_iClip == 0)
			bResult = self.DefaultReload( GLOCK_MAX_CLIP, GLOCK_RELOAD, 1.5, m_iSilenced == SILENCED_ON ? 1 : 0 );
		else
			bResult = self.DefaultReload( GLOCK_MAX_CLIP, GLOCK_RELOAD_NOT_EMPTY, 1.5, m_iSilenced == SILENCED_ON ? 1 : 0 );

		if ( bResult )
		{
			self.m_flTimeWeaponIdle = g_Engine.time + g_PlayerFuncs.SharedRandomFloat( m_pPlayer.random_seed, 10, 15 );
		}
		
		BaseClass.Reload();
	}

	void WeaponIdle()
	{
		self.ResetEmptySound();

		m_pPlayer.GetAutoaimVector( AUTOAIM_10DEGREES );

		if ( self.m_flTimeWeaponIdle > g_Engine.time )
			return;

		// only idle if the slid isn't back
		if (self.m_iClip != 0)
		{
			int iAnim;
			float flRand = g_PlayerFuncs.SharedRandomFloat( m_pPlayer.random_seed, 0.0, 1.0 );

			if (flRand <= 0.3 + 0 * 0.75)
			{
				iAnim = GLOCK_IDLE3;
				self.m_flTimeWeaponIdle = g_Engine.time + 49.0 / 16.0;
			}
			else if (flRand <= 0.6 + 0 * 0.875)
			{
				iAnim = GLOCK_IDLE1;
				self.m_flTimeWeaponIdle = g_Engine.time + 60.0 / 16.0;
			}
			else
			{
				iAnim = GLOCK_IDLE2;
				self.m_flTimeWeaponIdle = g_Engine.time + 40.0 / 16.0;
			}
			self.SendWeaponAnim( iAnim, 0, m_iSilenced == SILENCED_ON ? 1 : 0 );
		}
	}
}

string GetHLGLOCKName()
{
	return "weapon_hlglock";
}

void RegisterHLGLOCK()
{
	g_CustomEntityFuncs.RegisterCustomEntity( "weapon_hlglock", GetHLGLOCKName() );
	g_ItemRegistry.RegisterWeapon( GetHLGLOCKName(), "hl_weapons", "9mm", "", "ammo_9mmclip", "" );
}
