/***********************************************************************

weapon_handgrenade.script

***********************************************************************/

#define HANDGRENADE_MINRELEASETIME		0.05
#define HANDGRENADE_FUSE				3
#define HANDGRENADE_QUICKTHROWTIME		.2
#define HANDGRENADE_MINPOWER			1.5
#define HANDGRENADE_MAXPOWER			6
#define HANDGRENADE_QUICKTHROWLAUNCH	0.55
#define HANDGRENADE_NORMALTHROWLAUNCH	0.3
#define HANDGRENADE_NUMPROJECTILES		1

// blend times
#define HANDGRENADE_IDLE_TO_LOWER		4
#define HANDGRENADE_IDLE_TO_FIRE		4
#define HANDGRENADE_RAISE_TO_IDLE		4
#define HANDGRENADE_FIRE_TO_IDLE		4

object weapon_handgrenade : weapon_base {
	float		spread;
	float		fuse_start;
	string		skin_nade;
	string		skin_nade_invis;
	string		skin_nonade;
	string		skin_nonade_invis;
	entity		projectile;
	
	boolean		show_grenade;
	
	void		init();
	
	void		Lower();
	void		Raise();
	void		Idle();
	void		Fire();
	void		EnterCinematic();
	void		ExitCinematic();
	void		WeaponStolen();
	void		OwnerDied();
	void		ExplodeInHand();
	
				// called by the game
	void		UpdateSkin();
	
				// used by anim frame commands
	void		GrenadeNade();
	void		GrenadeNoNade();
};

void weapon_handgrenade::init() {
	spread				= getFloatKey( "spread" );
	skin_nade			= getKey( "skin_nade" );
	skin_nade_invis		= getKey( "skin_nade_invis" );
	skin_nonade			= getKey( "skin_nonade" );
	skin_nonade_invis	= getKey( "skin_nonade_invis" );
	
	GrenadeNade();
	
	weaponState( "Raise", 0 );
}

void weapon_handgrenade::Raise() {
	if ( !ammoAvailable() ) {
		weaponHolstered();
		nextWeapon();
		return;
	}
	
	weaponRising();
	playAnim( ANIMCHANNEL_ALL, "raise" );
	waitUntil( animDone( ANIMCHANNEL_ALL, HANDGRENADE_RAISE_TO_IDLE ) );
	weaponState( "Idle", HANDGRENADE_RAISE_TO_IDLE );
}

void weapon_handgrenade::Lower() {
	weaponLowering();
	playAnim( ANIMCHANNEL_ALL, "putaway" );
	waitUntil( animDone( ANIMCHANNEL_ALL, 0 ) );
	weaponHolstered();
	waitUntil( WEAPON_RAISEWEAPON );
	weaponState( "Raise", 0 );
}

void weapon_handgrenade::Idle() {
	weaponReady();
	playCycle( ANIMCHANNEL_ALL, "idle" );
	while( 1 ) {
		if ( WEAPON_LOWERWEAPON ) {
			weaponState( "Lower", HANDGRENADE_IDLE_TO_LOWER );
		}
		if ( WEAPON_ATTACK ) {
			weaponState( "Fire", HANDGRENADE_IDLE_TO_FIRE );
		}
		waitFrame();
	}
}

void weapon_handgrenade::Fire() {
	float fuse_end;
	float current_time;
	float time_held;
	float power;
	boolean exploded;
	
	projectile = createProjectile();

	if ( projectile ) {
		projectile.startSound( "snd_throw", SND_CHANNEL_BODY, true );
	}
	
	playAnim( ANIMCHANNEL_ALL, "throw_start" );
	
	current_time = sys.getTime();
	fuse_start = current_time;
	fuse_end = current_time + HANDGRENADE_FUSE;
	while( current_time < fuse_end ) {
		if ( ( current_time > fuse_start + HANDGRENADE_MINRELEASETIME ) && !WEAPON_ATTACK ) {
			break;
		}
		waitFrame();
		current_time = sys.getTime();
	}
	
	time_held = current_time - fuse_start;
	power = time_held + HANDGRENADE_MINPOWER;
	if ( power > HANDGRENADE_MAXPOWER ) {
		power = HANDGRENADE_MAXPOWER;
	}

	if ( time_held < HANDGRENADE_QUICKTHROWTIME ) {
		playAnim( ANIMCHANNEL_ALL, "throw_quick" );
		sys.wait( HANDGRENADE_QUICKTHROWLAUNCH );
		exploded = false;
	} else if ( time_held < HANDGRENADE_FUSE ) {
		playAnim( ANIMCHANNEL_ALL, "throw" );
		sys.wait( HANDGRENADE_NORMALTHROWLAUNCH	);
		exploded = false;
	} else {
		// no anim.  grenade just blows up
		ExplodeInHand();
		exploded = true;
	}
	
	if ( !exploded ) {
		GrenadeNoNade();
		current_time = sys.getTime();
		if ( projectile ) {
			projectile.show();
			projectile.unbind();
			launchProjectiles( HANDGRENADE_NUMPROJECTILES, spread, current_time - fuse_start, power, 1.0 );
			projectile = $null_entity;
		}

		waitUntil( animDone( ANIMCHANNEL_ALL, HANDGRENADE_FIRE_TO_IDLE ) );
	}
	
	if ( !ammoAvailable() ) {
		weaponHolstered();
		nextWeapon();
	} else {
		GrenadeNade();
		weaponState( "Idle", HANDGRENADE_FIRE_TO_IDLE );
	}
}

void weapon_handgrenade::EnterCinematic() {
	if ( projectile ) {
		projectile.remove();
		projectile = $null_entity;		
	}
	weaponState( "Idle", 0 );
}

void weapon_handgrenade::ExitCinematic() {
	if ( !ammoAvailable() ) {
		weaponHolstered();
		nextWeapon();
	} else {
		GrenadeNade();
		weaponState( "Idle", 0 );
	}
}

void weapon_handgrenade::GrenadeNade() {
	show_grenade = true;
	UpdateSkin();
}

void weapon_handgrenade::GrenadeNoNade() {
	show_grenade = false;
	UpdateSkin();
}

void weapon_handgrenade::UpdateSkin() {
	if ( !show_grenade ) {
		if ( isInvisible() ) {
			setSkin( skin_nonade_invis );
		} else {
			setSkin( skin_nonade );
		}
	} else {
		if ( isInvisible() ) {
			setSkin( skin_nade_invis );
		} else {
			setSkin( skin_nade );
		}
	}
}

void weapon_handgrenade::WeaponStolen() {
	if ( projectile ) {
		projectile.remove();
		projectile = $null_entity;		
	}
}

void weapon_handgrenade::OwnerDied() {
	float time_held;

	if ( projectile ) {
		time_held = sys.getTime() - fuse_start;
		projectile.show();
		projectile.unbind();

		// allow grenade to drop
		launchProjectiles( HANDGRENADE_NUMPROJECTILES, spread, time_held, 0, 1.0 );

		projectile = $null_entity;
	}
}

void weapon_handgrenade::ExplodeInHand() {
	string	entname;
	entity	explosion;
	vector	forward;
	vector	angles;
	entity	owner;

	if ( projectile ) {
		projectile.remove();
		projectile = $null_entity;
	}

	owner = getOwner();

	GrenadeNoNade();
	startSound( "snd_explode", SND_CHANNEL_ANY, false );

	if ( !sys.isClient() ) {
		useAmmo( HANDGRENADE_NUMPROJECTILES );

		angles = owner.getViewAngles();
		forward = sys.angToForward( angles );

		entname = getKey( "def_explode_inhand" );
		explosion = sys.spawn( entname );
		explosion.setOrigin( getOrigin() + forward * 16 );
		explosion.setShaderParm( SHADERPARM_TIMEOFFSET, -sys.getTime() );
		delayRemove( explosion, 2 );

		// this should kill us
		sys.radiusDamage( getOrigin(), self, owner, $null_entity, getKey( "def_damage_inhand" ), 1.0 );
	}
}
