text: /***
  *
  *	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.
  *
  ****/
  #include "extdll.h"
  #include "util.h"
  #include "cbase.h"
  #include "entities/NPCs/Monsters.h"
  #include "Weapons.h"
  #include "CHandGrenade.h"
  #include "nodes/Nodes.h"
  #include "CBasePlayer.h"
  
  
  #define	HANDGRENADE_PRIMARY_VOLUME		450
  
  LINK_ENTITY_TO_CLASS( weapon_handgrenade, CHandGrenade );
  
  CHandGrenade::CHandGrenade()
  	: BaseClass( WEAPON_HANDGRENADE )
  {
  }
  
  void CHandGrenade::Spawn( )
  {
  	Precache( );
  	SetModel( "models/w_grenade.mdl");
  
  #ifndef CLIENT_DLL
  	SetDamage( gSkillData.GetPlrDmgHandGrenade() );
  #endif
  
  	FallInit();// get ready to fall down.
  }
  
  
  void CHandGrenade::Precache( void )
  {
  	BaseClass::Precache();
  
  	PRECACHE_MODEL("models/w_grenade.mdl");
  	PRECACHE_MODEL("models/v_grenade.mdl");
  	PRECACHE_MODEL("models/p_grenade.mdl");
  }
  
  bool CHandGrenade::Deploy()
  {
  	m_flReleaseThrow = -1;
  	return DefaultDeploy( "models/v_grenade.mdl", "models/p_grenade.mdl", HANDGRENADE_DRAW, "crowbar" );
  }
  
  bool CHandGrenade::CanHolster()
  {
  	// can only holster hand grenades when not primed!
  	return ( m_flStartThrow == 0 );
  }
  
  void CHandGrenade::Holster()
  {
  	m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5;
  
  	if ( m_pPlayer->m_rgAmmo[ PrimaryAmmoIndex() ] )
  	{
  		SendWeaponAnim( HANDGRENADE_HOLSTER );
  	}
  	else
  	{
  		// no more grenades!
  		//TODO: should do this through a CBasePlayer method - Solokiller
  		m_pPlayer->GetWeapons().ClearFlags( 1 << m_iId );
  		SetThink( &CHandGrenade::DestroyItem );
  		SetNextThink( 0.1 );
  	}
  
  	EMIT_SOUND( m_pPlayer, CHAN_WEAPON, "common/null.wav", 1.0, ATTN_NORM);
  }
  
  void CHandGrenade::PrimaryAttack()
  {
  	if ( !m_flStartThrow && m_pPlayer->m_rgAmmo[ PrimaryAmmoIndex() ] > 0 )
  	{
  		m_flStartThrow = gpGlobals->time;
  		m_flReleaseThrow = 0;
  
  		SendWeaponAnim( HANDGRENADE_PINPULL );
  		m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.5;
  	}
  }
  
  
  void CHandGrenade::WeaponIdle( void )
  {
  	if ( m_flReleaseThrow == 0 && m_flStartThrow )
  		 m_flReleaseThrow = gpGlobals->time;
  
  	if ( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() )
  		return;
  
  	if ( m_flStartThrow )
  	{
  		Vector angThrow = m_pPlayer->GetViewAngle() + m_pPlayer->GetPunchAngle();
  
  		if ( angThrow.x < 0 )
  			angThrow.x = -10 + angThrow.x * ( ( 90 - 10 ) / 90.0 );
  		else
  			angThrow.x = -10 + angThrow.x * ( ( 90 + 10 ) / 90.0 );
  
  		float flVel = ( 90 - angThrow.x ) * 4;
  		if ( flVel > 500 )
  			flVel = 500;
  
  		UTIL_MakeVectors( angThrow );
  
  		Vector vecSrc = m_pPlayer->GetAbsOrigin() + m_pPlayer->GetViewOffset() + gpGlobals->v_forward * 16;
  
  		Vector vecThrow = gpGlobals->v_forward * flVel + m_pPlayer->GetAbsVelocity();
  
  		// alway explode 3 seconds after the pin was pulled
  		float time = m_flStartThrow - gpGlobals->time + 3.0;
  		if (time < 0)
  			time = 0;
  
  		CGrenade::ShootTimed( m_pPlayer, vecSrc, vecThrow, time );
  
  		if ( flVel < 500 )
  		{
  			SendWeaponAnim( HANDGRENADE_THROW1 );
  		}
  		else if ( flVel < 1000 )
  		{
  			SendWeaponAnim( HANDGRENADE_THROW2 );
  		}
  		else
  		{
  			SendWeaponAnim( HANDGRENADE_THROW3 );
  		}
  
  		// player "shoot" animation
  		m_pPlayer->SetAnimation( PLAYER_ATTACK1 );
  
  		m_flReleaseThrow = 0;
  		m_flStartThrow = 0;
  		m_flNextPrimaryAttack = GetNextAttackDelay(0.5);
  		m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.5;
  
  		m_pPlayer->m_rgAmmo[ PrimaryAmmoIndex() ]--;
  
  		if ( !m_pPlayer->m_rgAmmo[ PrimaryAmmoIndex() ] )
  		{
  			// just threw last grenade
  			// set attack times in the future, and weapon idle in the future so we can see the whole throw
  			// animation, weapon idle will automatically retire the weapon for us.
  			m_flTimeWeaponIdle = m_flNextSecondaryAttack = m_flNextPrimaryAttack = GetNextAttackDelay(0.5);// ensure that the animation can finish playing
  		}
  		return;
  	}
  	else if ( m_flReleaseThrow > 0 )
  	{
  		// we've finished the throw, restart.
  		m_flStartThrow = 0;
  
  		if ( m_pPlayer->m_rgAmmo[ PrimaryAmmoIndex() ] )
  		{
  			SendWeaponAnim( HANDGRENADE_DRAW );
  		}
  		else
  		{
  			RetireWeapon();
  			return;
  		}
  
  		m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 );
  		m_flReleaseThrow = -1;
  		return;
  	}
  
  	if ( m_pPlayer->m_rgAmmo[ PrimaryAmmoIndex() ] )
  	{
  		int iAnim;
  		float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0, 1 );
  		if (flRand <= 0.75)
  		{
  			iAnim = HANDGRENADE_IDLE;
  			m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 );// how long till we do this again.
  		}
  		else 
  		{
  			iAnim = HANDGRENADE_FIDGET;
  			m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 75.0 / 30.0;
  		}
  
  		SendWeaponAnim( iAnim );
  	}
  }
  
  
  
  
  