// Suggestion(s):
// - Remove if there are too many traps?

namespace HLWanted_Beartrap
{
const int BEARTRAP_DEFAULT_GIVE = 999;
const int BEARTRAP_MAX_CARRY 	= 999;
const int BEARTRAP_WEIGHT 	= 5;

const float BEARTRAP_DMG = 30.0;

uint WEAPON_BEARTRAP = 16;

class monster_beartrap : ScriptBaseMonsterEntity
{
	private float m_flKillVictimTime;
	private int m_iLifeTime;
	private float m_flNextBounceSound;

	void Spawn()
	{
		Precache( );

		self.pev.movetype = MOVETYPE_BOUNCE;
		self.pev.solid = SOLID_TRIGGER;

		g_EntityFuncs.SetModel( self, "models/wanted/w_beartrap.mdl" );
		g_EntityFuncs.SetSize( self.pev, Vector(-4, -4, -4), Vector(4, 4, 4) );	// Uses point-sized, and can be stepped over
		g_EntityFuncs.SetOrigin( self, self.pev.origin );

		self.pev.sequence = self.LookupSequence( "idle" );
		self.pev.frame = 0;
		self.ResetSequenceInfo();

		self.pev.friction = 0.95f;

		m_iLifeTime = 300 * 10; // life * 10

		m_flNextBounceSound = g_Engine.time;

		SetTouch( TouchFunction( this.BeartrapSlide ) );
		SetThink( ThinkFunction( this.BeartrapThink ) );
		self.pev.nextthink = g_Engine.time + 0.1f;
	}

	void Precache()
	{
		g_Game.PrecacheModel( "models/wanted/w_beartrap.mdl" );

		g_SoundSystem.PrecacheSound( "weapons/g_bounce1.wav" );
		g_SoundSystem.PrecacheSound( "weapons/g_bounce2.wav" );
		g_SoundSystem.PrecacheSound( "weapons/g_bounce3.wav" );

		g_SoundSystem.PrecacheSound( "wanted/weapons/beartrap_sprung.wav" );
		g_Game.PrecacheGeneric( "sound/" + "wanted/weapons/beartrap_sprung.wav" );
	}

	void BeartrapSlide( CBaseEntity@ pOther )
	{
		TraceResult tr;

		g_Utility.TraceLine( pev.origin, pev.origin - Vector(0,0,10), ignore_monsters, self.edict(), tr );

		if( tr.flFraction < 1.0 )
		{
			// add a bit of static friction
			pev.velocity = pev.velocity * 0.95;
			pev.avelocity = pev.avelocity * 0.9;
		}

		if( (pev.flags & FL_ONGROUND) != 0 && pev.velocity.Length2D() > 10 )
		{
			BounceSound();
		}

		self.StudioFrameAdvance();

		if( pev.velocity.Length2D() > 0 || !pOther.IsPlayer() && !pOther.IsMonster() || !pOther.IsAlive() || pOther.pev.takedamage == DAMAGE_NO || pOther.pev.flags & FL_GODMODE != 0 )
			return;

		CBaseEntity@ pOwner = g_EntityFuncs.Instance( pev.owner );
		if( pOwner !is null )
		{
			if( pOther != pOwner && (pOwner.Classify() >= CLASS_TEAM1 && pOwner.Classify() <= CLASS_TEAM4 && pOther.Classify() == pOwner.Classify() || pOwner.IRelationship(pOther) <= R_NO) )
				return;

			int g_npckill = int( g_EngineFuncs.CVarGetFloat( "mp_npckill" ) );
			if( pOwner.Classify() == CLASS_PLAYER && pOther.IsMonster() && pOther.IsPlayerAlly() && (g_npckill == 0 || g_npckill == 2) ) // NPCs are disallowed to be killed
				return;
		}

		self.m_hEnemy = pOther;

		SetTouch( null );

		g_SoundSystem.EmitSoundDyn( self.edict(), CHAN_WEAPON, "wanted/weapons/beartrap_sprung.wav", 1.0f, ATTN_NORM );

		self.StudioFrameAdvance();
	}

	void BeartrapThink()
	{
		pev.nextthink = g_Engine.time + 0.1f;

		//CBaseEntity@ pEnemy = g_EntityFuncs.Instance( pev.enemy );
		CBaseEntity@ pEnemy = self.m_hEnemy.GetEntity();
		if( pEnemy !is null )
		{
			if( pev.sequence == 1 && self.m_fSequenceFinished && pev.frame >= 255 )
			{
				pev.sequence = self.LookupSequence( "closed" );
				pev.frame = 0;
				self.ResetSequenceInfo();
			}

			if( !pEnemy.IsAlive() )
			{
				@pEnemy = null;
				SetThink( ThinkFunction( FadeOut ) );
				pev.nextthink = g_Engine.time + 15.0f;
				return;
			}

			if( pEnemy.pev.takedamage <= DAMAGE_NO || pEnemy.pev.flags & FL_GODMODE != 0 )
			{
				@pEnemy = null;
				SetThink( null );
				g_EntityFuncs.Remove( self );
				return;
			}

			pEnemy.pev.velocity = g_vecZero;

			pEnemy.pev.basevelocity = g_vecZero;
			pEnemy.pev.origin.x = pev.origin.x;
			pEnemy.pev.origin.y = pev.origin.y;

			// has trapped somebody!
			if( m_flKillVictimTime != -1 && g_Engine.time > m_flKillVictimTime )
			{
				if( pev.sequence != 1 && pev.sequence != 2 )
				{
					pev.sequence = self.LookupSequence( "fire" );
					pev.frame = 0;
					self.ResetSequenceInfo();
				}

				if( pev.owner !is null )
					pEnemy.TakeDamage( self.pev, self.pev.owner.vars, BEARTRAP_DMG, DMG_NEVERGIB );
				else
					pEnemy.TakeDamage( self.pev, self.pev, BEARTRAP_DMG, DMG_NEVERGIB );

				SetTouch( null );

				if( !pEnemy.IsAlive() )
				{
					@pEnemy = null;
					SetThink( ThinkFunction( FadeOut ) );
					pev.nextthink = g_Engine.time + 15.0f;
					return;
				}

				m_flKillVictimTime = g_Engine.time + 0.25f; // damage every 0.25 sec

				return;
			}
		}

		if( !self.IsInWorld() || m_iLifeTime <= 0 )
		{
			g_EntityFuncs.Remove( self );
			return;
		}

		m_iLifeTime--;

		if( (pev.flags & FL_ONGROUND) != 0 )
		{
			pev.movetype = MOVETYPE_BOUNCE;
			pev.velocity = pev.velocity * 0.5;
		}
	}

	void BounceSound()
	{
		if( m_flNextBounceSound > g_Engine.time )
			return;

		m_flNextBounceSound = g_Engine.time + 0.3;

		switch( Math.RandomLong( 0, 2 ) )
		{
		case 0:	g_SoundSystem.EmitSoundDyn( self.edict(), CHAN_VOICE, "weapons/g_bounce1.wav", 1, ATTN_NORM); break;
		case 1:	g_SoundSystem.EmitSoundDyn( self.edict(), CHAN_VOICE, "weapons/g_bounce2.wav", 1, ATTN_NORM); break;
		case 2:	g_SoundSystem.EmitSoundDyn( self.edict(), CHAN_VOICE, "weapons/g_bounce3.wav", 1, ATTN_NORM); break;
		}
	}

	void DestroyThink( void )
	{
		g_EntityFuncs.Remove( self );
	}

	void FadeOut()
	{
		pev.nextthink = g_Engine.time + 0.1;

		if( pev.rendermode == kRenderNormal )
		{
			pev.renderamt = 255;
			pev.rendermode = kRenderTransTexture;
		}

		if( pev.renderamt > 7 )
		{
			pev.renderamt -= 7;
		}
		else
		{
			pev.renderamt = 0;
			pev.nextthink = g_Engine.time + 0.1f;
			SetThink( ThinkFunction( this.DestroyThink ) );
			return;
		}
	}
}

enum beartrap_e
{
	BEARTRAP_DRAW = 0,
	BEARTRAP_HOLSTER,
	BEARTRAP_IDLE,
	BEARTRAP_FIDGET,
	BEARTRAP_THROW
};

class weapon_beartrap : CBaseCustomWeapon
{
	void Spawn()
	{
		Precache();
		g_EntityFuncs.SetModel( self, "models/wanted/w_beartrap.mdl" );

		self.m_iDefaultAmmo = BEARTRAP_DEFAULT_GIVE;

		self.FallInit();
	}

	void Precache()
	{
		self.PrecacheCustomModels();
		g_Game.PrecacheModel("models/wanted/v_beartrap.mdl");
		g_Game.PrecacheModel("models/wanted/w_beartrap.mdl");
		g_Game.PrecacheModel("models/wanted/p_beartrap.mdl");

		g_SoundSystem.PrecacheSound( "items/gunpickup2.wav" );

		g_Game.PrecacheGeneric( "sprites/" + "wanted/320hud1.spr" );
		g_Game.PrecacheGeneric( "sprites/" + "wanted/320hud2.spr" );
		g_Game.PrecacheGeneric( "sprites/" + "wanted/640hud3.spr" );
		g_Game.PrecacheGeneric( "sprites/" + "wanted/640hud6.spr" );
		g_Game.PrecacheGeneric( "sprites/" + "wanted/640hud7.spr" );

		g_Game.PrecacheGeneric( "sprites/" + "wanted/weapon_beartrap.txt" );

		g_Game.PrecacheOther( "monster_beartrap" );
	}

	bool AddToPlayer( CBasePlayer@ pPlayer )
	{
		if( !BaseClass.AddToPlayer( pPlayer ) )
			return false;

		@m_pPlayer = pPlayer;

		NetworkMessage message( MSG_ONE, NetworkMessages::WeapPickup, pPlayer.edict() );
			message.WriteLong( g_ItemRegistry.GetIdForName( self.pev.classname ) );
		message.End();

		return true;
	}

	bool GetItemInfo( ItemInfo& out info )
	{
		info.iMaxAmmo1 = BEARTRAP_MAX_CARRY;
		info.iAmmo1Drop	= 1;
		info.iMaxAmmo2 = -1;
		info.iAmmo2Drop	= -1;
		info.iMaxClip = WEAPON_NOCLIP;
		info.iSlot = 4;
		info.iPosition = 17;
		info.iFlags = ITEM_FLAG_LIMITINWORLD | ITEM_FLAG_EXHAUSTIBLE;
		info.iId = g_ItemRegistry.GetIdForName( self.pev.classname );
		info.iWeight = BEARTRAP_WEIGHT;

		return true;
	}

	bool Deploy()
	{
		bool bResult;
		{
			m_fDropped = false;
			bResult = self.DefaultDeploy( self.GetV_Model( "models/wanted/v_beartrap.mdl" ), self.GetP_Model( "models/wanted/p_beartrap.mdl" ), BEARTRAP_DRAW, "trip" );
			self.m_flNextPrimaryAttack = g_Engine.time + 1.0f;
			self.m_flTimeWeaponIdle = g_Engine.time + 3.0f;
			return bResult;
		}
	}

	bool CanDeploy()
	{
		return m_pPlayer.m_rgAmmo( self.m_iPrimaryAmmoType) != 0;
	}

	void DestroyThink( void )
	{
		SetThink( null );
		self.DestroyItem();
	}

	void Holster( int skiplocal /* = 0 */ )
	{
		self.m_fInReload = false;

		m_pPlayer.m_flNextAttack = g_Engine.time + 0.5;

		if( m_pPlayer.m_rgAmmo( self.m_iPrimaryAmmoType ) == 0 && !m_fDropped )
		{
			m_pPlayer.pev.weapons &= ~( 0 << g_ItemRegistry.GetIdForName( self.pev.classname ) );
			SetThink( ThinkFunction( DestroyThink ) );
			self.pev.nextthink = g_Engine.time + 0.1;
		}
		else
		{
			self.SendWeaponAnim( BEARTRAP_HOLSTER );
			g_SoundSystem.EmitSound( m_pPlayer.edict(), CHAN_WEAPON, "common/null.wav", 1.0f, ATTN_NORM );
		}

		BaseClass.Holster( skiplocal );
	}

	void PrimaryAttack()
	{
		if( m_pPlayer.m_rgAmmo( self.m_iPrimaryAmmoType ) > 0 )
		{
			Vector vecThrow = g_Engine.v_forward * 274 + m_pPlayer.pev.velocity;
			CBaseEntity@ pBeartrap = g_EntityFuncs.Create( "monster_beartrap", m_pPlayer.pev.origin, g_vecZero, false, m_pPlayer.edict() );
			pBeartrap.pev.velocity = vecThrow;
			pBeartrap.pev.avelocity.y = 400;

			self.SendWeaponAnim( BEARTRAP_THROW );

			// player "shoot" animation
			m_pPlayer.SetAnimation( PLAYER_ATTACK1 );

			m_pPlayer.m_rgAmmo( self.m_iPrimaryAmmoType, m_pPlayer.m_rgAmmo( self.m_iPrimaryAmmoType ) - 1 );

			self.m_flNextPrimaryAttack = g_Engine.time + 0.5f;
			self.m_flTimeWeaponIdle = g_Engine.time + 1.0f;
		}
	}

	void WeaponIdle()
	{
		if( self.m_flTimeWeaponIdle > g_Engine.time )
			return;

		if( m_pPlayer.m_rgAmmo(self.m_iPrimaryAmmoType) <= 0 )
		{
			self.RetireWeapon();
			return;
		}

		int iAnim;
		float flRand = g_PlayerFuncs.SharedRandomFloat( m_pPlayer.random_seed, 0, 1 );
		switch( Math.RandomLong(0,1) )
		{
		case 0: iAnim = BEARTRAP_IDLE;
			self.m_flTimeWeaponIdle = g_Engine.time + 3.6;
			break;
		case 1: iAnim = BEARTRAP_FIDGET;
			self.m_flTimeWeaponIdle = g_Engine.time + 2.6;
			break;
		}

		self.SendWeaponAnim( iAnim );
	}

	//=========================================================
	// DeactivateBeartraps - removes all beartraps owned by
	// the provided player. Should only be used upon death.
	//
	// Made this global on purpose.
	//=========================================================
	/*void DeactivateBeartraps( CBasePlayer@ pOwner )
	{
		edict_t@ pFind; 

		pFind = g_EntityFuncs.FindEntityByClassname( null, "monster_beartrap" );

		while( !FNullEnt( pFind ) )
		{
			CBaseEntity@ pEnt = g_EntityFuncs.Instance( pFind );
			CBeartrapCharge@ pBeartrap = (CBeartrapCharge@)pEnt;

			if( pBeartrap )
			{
				if ( pBeartrap.pev.owner == pOwner.edict() )
				{
					pBeartrap.pev.solid = SOLID_NOT;
					g_EntityFuncs.Remove( pBeartrap );
				}
			}

			pFind = g_EntityFuncs.FindEntityByClassname( pFind, "monster_beartrap" );
		}
	}*/

	void Materialize()
	{
		BaseClass.Materialize();
		//SetTouch( TouchFunction( CustomTouch ) );
	}

	bool CanHaveDuplicates()
	{
		return true;
	}

/*	void CustomTouch( CBaseEntity@ pOther ) 
	{
		if( !pOther.IsPlayer() )
			return;

		CBasePlayer@ pPlayer = cast<CBasePlayer@>( pOther );

		if( pPlayer.HasNamedPlayerItem( GetBeartrapName() ) !is null )
		{
	  		if( pPlayer.GiveAmmo( BEARTRAP_DEFAULT_GIVE, GetBeartrapName(), BEARTRAP_MAX_CARRY ) != -1 )
			{
				self.CheckRespawn();
				g_SoundSystem.EmitSound( self.edict(), CHAN_ITEM, "items/gunpickup2.wav", 1, ATTN_NORM );

				g_EntityFuncs.Remove( self );
	  		}

	  		return;
		}
		else if( pPlayer.AddPlayerItem( self ) != APIR_NotAdded )
		{
	  		self.AttachToPlayer( pPlayer );
	  		g_SoundSystem.EmitSound( self.edict(), CHAN_ITEM, "items/gunpickup2.wav", 1, ATTN_NORM );
		}
	}*/
}

string GetBeartrapName()
{
	return "weapon_beartrap";
}

void Register()
{
	g_CustomEntityFuncs.RegisterCustomEntity( "HLWanted_Beartrap::monster_beartrap", "monster_beartrap" );
	g_CustomEntityFuncs.RegisterCustomEntity( "HLWanted_Beartrap::weapon_beartrap", GetBeartrapName() );
	g_ItemRegistry.RegisterWeapon( GetBeartrapName(), "wanted", GetBeartrapName(), "", GetBeartrapName() );
}

} //namespace HLWanted_Beartrap END