// SUPER SAIYAN GOHAN! - from Dragon Ball, Z, GT series. Gohan is Goku and Chi-Chi's first son.

/* CVARS - copy and paste to shconfig.cfg

//Super Saiyan Gohan
ssjgohan_level 9
ssjgohan_damage 125		//Damage spread over radius of blast (Default 125)
ssjgohan_radius 300		//Radius of the damage (Default 300)
ssjgohan_cooldown 30		//Seconds til next available use from power explode (Default 30)
ssjgohan_powerspeed 1000	//Speed of Kamehameha, min-500 max-(server's sv_maxvelocity) (Default 1000)
ssjgohan_blast_decals 1		//Show the burn decals from blast (Default 1)

*/

/*
* v1.1 - vittu - 10/4/08
*      - Updated to be SH 1.2.0 compliant, removed amx compatibility.
*      - Burn decals have been corrected for czero.
*
* v1.0 - vittu - 12/2/05
*      - Fixed to ssjgohan_blast_decals cvar named incorrectly in code.
*          Thanks to Om3g[A] for pointing it out.
*
* v1.0 - vittu - 9/17/05
*
*   Entity creation partially based on Bazooka, which is based on Missiles Launcher 3.8.2 by Eric Lidman & jtp10181.
*   Extra sprites and sounds used from Earth's Special Forces a HL mod - http://www.esforces.com/
*/

#include <superheromod>

// GLOBAL VARIBLES
new gHeroID
new bool:gHasSSJGohan[SH_MAXSLOTS+1]
new bool:gUsingPower[SH_MAXSLOTS+1]
new bool:gChargeOver[SH_MAXSLOTS+1]
new bool:gPowerKeyUsed[SH_MAXSLOTS+1]
new gPowerID[SH_MAXSLOTS+1]
new gLastWeapon[SH_MAXSLOTS+1]
new gMsgBarTime, gMaxPlayers
new gSpriteSmoke, gSpriteTrail, gSpriteExplosion

//First 3 are mid size burn decals, second 3 are larger grenade size
new gBurnDecal[6] = {28, 29, 30, 46, 47, 48}
new gPcvarMaxDamage, gPcvarRadius, gPcvarCooldown, gPcvarSpeed, gPcvarDecals
new const gPowerClass[] = "ssjgohan_kamehameha"
new const gSoundCharge[] = "shmod/ssjgohan_kamehame.wav"
new const gSoundRelease[] = "shmod/ssjgohan_ha.wav"
new const gSoundBeam[] = "shmod/esf_beamhead.wav"
new const gModelKamehameha[] = "sprites/shmod/esf_kamehameha_blue.spr"
//----------------------------------------------------------------------------------------------
public plugin_init()
{
	// Plugin Info
	register_plugin("SUPERHERO Super Saiyan Gohan", "1.1", "vittu")

	// DO NOT EDIT THIS FILE TO CHANGE CVARS, USE THE SHCONFIG.CFG
	new pcvarLevel = register_cvar("ssjgohan_level", "9")
	gPcvarMaxDamage = register_cvar("ssjgohan_damage", "125")
	gPcvarRadius = register_cvar("ssjgohan_radius", "300")
	gPcvarCooldown = register_cvar("ssjgohan_cooldown", "30")
	gPcvarSpeed = register_cvar("ssjgohan_powerspeed", "1000")
	gPcvarDecals = register_cvar("ssjgohan_blast_decals", "1")

	// FIRE THE EVENT TO CREATE THIS SUPERHERO!
	gHeroID = sh_create_hero("Super Saiyan Gohan", pcvarLevel)
	sh_set_hero_info(gHeroID, "Guided Kamehameha", "Hold +power key down to charge, and release to fire your Kamehameha.")
	sh_set_hero_bind(gHeroID)

	// EVENTS
	register_event("CurWeapon", "curweapon", "be", "1=1")
	register_forward(FM_Think, "fm_Think")
	register_forward(FM_Touch, "fm_Touch")

	gMsgBarTime = get_user_msgid("BarTime")
	gMaxPlayers = get_maxplayers()

	// Set to correct burn decals if mod is CZ
	new mod_name[9]
	get_modname(mod_name, 8)
	if ( equal(mod_name, "czero") ) {
		gBurnDecal = {40, 41, 42, 58, 59, 60}
	}
}
//----------------------------------------------------------------------------------------------
public plugin_precache()
{
	precache_sound(gSoundCharge)
	precache_sound(gSoundRelease)
	precache_sound(gSoundBeam)
	precache_model(gModelKamehameha)
	gSpriteTrail = precache_model("sprites/shmod/esf_trail_blue.spr")
	gSpriteExplosion = precache_model("sprites/shmod/esf_exp_blue.spr")
	gSpriteSmoke = precache_model("sprites/wall_puff4.spr")
}
//----------------------------------------------------------------------------------------------
public sh_hero_init(id, heroID, mode)
{
	if ( gHeroID != heroID ) return

	gHasSSJGohan[id] = mode ? true : false

	if ( gPowerID[id] > 0 ) {
		remove_power(id, gPowerID[id])
	}
}
//----------------------------------------------------------------------------------------------
public sh_client_spawn(id)
{
	gPlayerInCooldown[id] = false
	gUsingPower[id] = false
	gPowerKeyUsed[id] = false
}
//----------------------------------------------------------------------------------------------
public sh_hero_key(id, heroID, key)
{
	if ( gHeroID != heroID || sh_is_freezetime() ) return
	if ( !is_user_alive(id) || !gHasSSJGohan[id] ) return

	if ( key == SH_KEYDOWN ) {
		if ( gPlayerInCooldown[id] ) {
			sh_sound_deny(id)
			sh_chat_message(id, gHeroID, "Not enough KI, you must wait longer")
			return
		}

		// Prevent too many entities, which would cause server problems
		if ( gPowerID[id] ) {
			sh_sound_deny(id)
			sh_chat_message(id, gHeroID, "Already using Kamehameha Attack")
			return
		}

		// Remember this weapon...
		gLastWeapon[id] = get_user_weapon(id)

		// Switch to knife
		engclient_cmd(id, "weapon_knife")

		// Set some variables
		gUsingPower[id] = true
		gPowerKeyUsed[id] = true
		gChargeOver[id] = false

		emit_sound(id, CHAN_STATIC, gSoundCharge, VOL_NORM, ATTN_NORM, 0, PITCH_NORM)

		// Show a progress bar for time til charge is full
		progressBar(id, 4)

		// Must wait for full bar time/sound til power can be used, this task will set it ok
		set_task(4.0, "powerCharged", id)
	}
	if ( key == SH_KEYUP ) {
		if ( !gChargeOver[id] ) {

			remove_task(id)

			// Stop the sound
			emit_sound(id, CHAN_STATIC, gSoundCharge, VOL_NORM, ATTN_NORM, SND_STOP, PITCH_NORM)

			// Remove progress bar
			progressBar(id, 0)

			// Switch back to previous weapon...
			if ( gLastWeapon[id] != CSW_KNIFE ) sh_switch_weapon(id, gLastWeapon[id])

			gUsingPower[id] = false
			gPowerKeyUsed[id] = false

			return
		}

		if ( !is_user_alive(id) || !gHasSSJGohan[id] || !gPowerKeyUsed[id] ) return

		// Stop the sound
		emit_sound(id, CHAN_STATIC, gSoundCharge, VOL_NORM, ATTN_NORM, SND_STOP, PITCH_NORM)

		emit_sound(id, CHAN_STATIC, gSoundRelease, VOL_NORM, ATTN_NORM, 0, PITCH_NORM)

		// Remove progress bar
		progressBar(id, 0)

		set_user_maxspeed(id, 1.0)

		create_power(id)

		gPowerKeyUsed[id] = false
	}
}
//----------------------------------------------------------------------------------------------
public powerCharged(id)
{
	gChargeOver[id] = true
}
//----------------------------------------------------------------------------------------------
progressBar(id, seconds)
{
	message_begin(MSG_ONE_UNRELIABLE, gMsgBarTime, _, id)
	write_byte(seconds)
	write_byte(0)
	message_end()
}
//----------------------------------------------------------------------------------------------
create_power(id)
{
	new newEnt = engfunc(EngFunc_CreateNamedEntity, engfunc(EngFunc_AllocString, "info_target"))
	if ( !newEnt ) {
		sh_chat_message(id, gHeroID, "Power Creation Failure")
		return
	}

	gPowerID[id] = newEnt

	set_pev(newEnt, pev_classname, gPowerClass)
	engfunc(EngFunc_SetModel, newEnt, gModelKamehameha)

	// Vec Mins/Maxes must be below +/- 5.0 to make a burndecal correctly
	engfunc(EngFunc_SetSize, newEnt, {-2.0, -2.0, -2.0}, {2.0, 2.0, 2.0})

	new Float:fl_Origin[3], Float:fl_Angles[3], Float:fl_vAngle[3]
	// Get users postion and angles (angles are probably not needed in this case)
	pev(id, pev_origin, fl_Origin)
	pev(id, pev_angles, fl_Angles)
	pev(id, pev_v_angle, fl_vAngle)

	// Change height of entity origin to hands
	fl_Origin[2] += 6.0

	// Set entity postion and angles
	engfunc(EngFunc_SetOrigin, newEnt, fl_Origin)
	set_pev(newEnt, pev_angles, fl_Angles)
	set_pev(newEnt, pev_v_angle, fl_vAngle)

	// Set properties of the entity
	set_pev(newEnt, pev_solid, SOLID_BBOX)
	set_pev(newEnt, pev_movetype, MOVETYPE_FLY)
	set_pev(newEnt, pev_rendermode, kRenderTransAdd)
	set_pev(newEnt, pev_renderamt, 255.0)
	set_pev(newEnt, pev_scale, 1.20)
	set_pev(newEnt, pev_owner, id)

	new Float:fl_Velocity[3], AimVec[3], Float:fl_EndOrigin[3]

	get_user_origin(id, AimVec, 3)
	IVecFVec(AimVec, fl_EndOrigin)

	// Seting entSpeed higher then 2000.0 will require server to set sv_maxvelocity higher as well
	// sh_get_velocity verifies sv_maxvelocity is set high enough if not it will lower the speed
	sh_get_velocity(fl_Origin, fl_EndOrigin, get_pcvar_float(gPcvarSpeed), fl_Velocity)

	set_pev(newEnt, pev_velocity, fl_Velocity)

	emit_sound(newEnt, CHAN_STATIC, gSoundBeam, VOL_NORM, ATTN_NORM, 0, PITCH_NORM)

	// Trail on enity. It's flawed by not being removable, so make it last long.
	message_begin(MSG_BROADCAST, SVC_TEMPENTITY)
	write_byte(TE_BEAMFOLLOW)
	write_short(newEnt)		// entity:attachment to follow
	write_short(gSpriteTrail)	// sprite index
	write_byte(100)			// life in 0.1's
	write_byte(8)			// line width in 0.1's
	write_byte(255)			// r,g,b
	write_byte(255)
	write_byte(255)
	write_byte(255)			// brightness
	message_end()

	new Float:gametime
	global_get(glb_time, gametime)
	set_pev(newEnt, pev_nextthink, gametime + 0.1)
}
//----------------------------------------------------------------------------------------------
public fm_Think(ent)
{
	if ( !pev_valid(ent) ) return FMRES_IGNORED

	static classname[32]
	classname[0] = '^0'
	pev(ent, pev_classname, classname, 31)

	if ( !equal(classname, gPowerClass) ) return FMRES_IGNORED

	new id = pev(ent, pev_owner)

	if ( !is_user_connected(id) ) {
		fm_Touch(ent, 0)
		return FMRES_IGNORED
	}

	new Float:fl_Origin[3], AimVec[3], Float:fl_EndOrigin[3], Float:fl_Velocity[3], Float:fl_OldVelocity[3]
	new avgFactor
	new Float:speed = get_pcvar_float(gPcvarSpeed)

	get_user_origin(id, AimVec, 3)
	IVecFVec(AimVec, fl_EndOrigin)
	pev(ent, pev_origin, fl_Origin)

	if ( speed < 1000.0 )
		avgFactor = 6
	else if ( speed < 1500.0 )
		avgFactor = 4
	else
		avgFactor = 2

	sh_get_velocity(fl_Origin, fl_EndOrigin, speed, fl_Velocity)

	pev(ent, pev_velocity, fl_OldVelocity)

	// Make it lag a bit, helps keep movement smooth else would be too erratic
	new oneless = avgFactor-1
	fl_Velocity[0] += fl_OldVelocity[0] * oneless
	fl_Velocity[1] += fl_OldVelocity[1] * oneless
	fl_Velocity[2] += fl_OldVelocity[2] * oneless

	fl_Velocity[0] /= avgFactor
	fl_Velocity[1] /= avgFactor
	fl_Velocity[2] /= avgFactor

	set_pev(ent, pev_velocity, fl_Velocity)

	new Float:gametime
	global_get(glb_time, gametime)
	set_pev(ent, pev_nextthink, gametime + 0.1)

	return FMRES_IGNORED
}
//----------------------------------------------------------------------------------------------
public fm_Touch(ptr, ptd)
{
	if ( !sh_is_active() ) return FMRES_IGNORED
	if ( !pev_valid(ptr) ) return FMRES_IGNORED

	static classname[32]
	classname[0] = '^0'
	pev(ptr, pev_classname, classname, 31)

	// Lets block the picking up of a shield
	if ( equal(classname, gPowerClass) ) {
		new id = pev(ptr, pev_owner)

		new Float:dRatio, Float:distanceBetween, damage
		new Float:dmgRadius = get_pcvar_float(gPcvarRadius)
		new maxDamage = get_pcvar_num(gPcvarMaxDamage)
		new CsTeams:idTeam = cs_get_user_team(id)
		new FFOn = sh_friendlyfire_on()
		new Float:vicOrigin[3]
		new Float:fl_vExplodeAt[3]

		pev(ptr, pev_origin, fl_vExplodeAt)

		for ( new victim = 1; victim <= gMaxPlayers; victim++ )
		{
			if ( !is_user_alive(victim) ) continue
			if ( idTeam == cs_get_user_team(victim) && !FFOn && id != victim ) continue

			pev(victim, pev_origin, vicOrigin)
			distanceBetween = vector_distance(fl_vExplodeAt, vicOrigin)

			if ( distanceBetween <= dmgRadius )
			{
				dRatio = distanceBetween / dmgRadius
				damage = maxDamage - floatround(maxDamage * dRatio)

				// Lessen damage taken by self
				if (victim == id) damage = floatround(damage / 2.0)

				if ( !damage ) damage = 1	// Incase damage cvar is really low cause something if within the radius 
				sh_extra_damage(victim, id, damage, "Kamehameha", _, SH_DMG_NORM, true, _, fl_vExplodeAt)

				// Make them feel it
				new Float:fl_vicVelocity[3]
				fl_vicVelocity[0] = ((vicOrigin[0] - fl_vExplodeAt[0]) / distanceBetween) * 300.0
				fl_vicVelocity[1] = ((vicOrigin[1] - fl_vExplodeAt[1]) / distanceBetween) * 300.0
				fl_vicVelocity[2] = 150.0

				set_pev(victim, pev_velocity, fl_vicVelocity)
				sh_screen_shake(victim, 1.2, 1.2, 1.2)
			}
		}


		// Make some Effects
		new blastSize = floatround(dmgRadius / 12.0)

		// Explosion Sprite
		message_begin(MSG_BROADCAST, SVC_TEMPENTITY)
		write_byte(TE_GLOWSPRITE)	//23
		engfunc(EngFunc_WriteCoord, fl_vExplodeAt[0])
		engfunc(EngFunc_WriteCoord, fl_vExplodeAt[1])
		engfunc(EngFunc_WriteCoord, fl_vExplodeAt[2])
		write_short(gSpriteExplosion)	// model
		write_byte(01)			// life 0.x sec
		write_byte(blastSize)		// size
		write_byte(255)			// brightness
		message_end()

		// Explosion (smoke, sound/effects)
		message_begin(MSG_BROADCAST, SVC_TEMPENTITY)
		write_byte(TE_EXPLOSION)	//3
		engfunc(EngFunc_WriteCoord, fl_vExplodeAt[0])
		engfunc(EngFunc_WriteCoord, fl_vExplodeAt[1])
		engfunc(EngFunc_WriteCoord, fl_vExplodeAt[2])
		write_short(gSpriteSmoke)	// model
		write_byte(blastSize+5)		// scale in 0.1's
		write_byte(20)			// framerate
		write_byte(10)			// flags
		message_end()

		// Create Burn Decals, if they are used
		if ( get_pcvar_num(gPcvarDecals) ) {
			// Change burn decal according to blast size
			new decal = random_num(0,2)
			if (blastSize > 18) {
				//If radius >~ 216 use larger decals
				decal += 3
			}

			message_begin(MSG_BROADCAST, SVC_TEMPENTITY)
			write_byte(TE_GUNSHOTDECAL)	//109
			engfunc(EngFunc_WriteCoord, fl_vExplodeAt[0])
			engfunc(EngFunc_WriteCoord, fl_vExplodeAt[1])
			engfunc(EngFunc_WriteCoord, fl_vExplodeAt[2])
			write_short(0)			//?
			write_byte(gBurnDecal[decal])		//decal
			message_end()
		}

		// Stop the sounds
		emit_sound(ptr, CHAN_STATIC, gSoundBeam, VOL_NORM, ATTN_NORM, SND_STOP, PITCH_NORM)
		emit_sound(id, CHAN_STATIC, gSoundRelease, VOL_NORM, ATTN_NORM, SND_STOP, PITCH_NORM)

		engfunc(EngFunc_RemoveEntity, ptr)

		new Float:cooldown = get_pcvar_float(gPcvarCooldown)
		if ( cooldown > 0.0 ) sh_set_cooldown(id, cooldown)

		// Reset the Varible
		gPowerID[id] = 0
		gUsingPower[id] = false

		// Switch back to previous weapon and reset speed...
		if ( gLastWeapon[id] != CSW_KNIFE ) sh_switch_weapon(id, gLastWeapon[id])
		else sh_reset_max_speed(id)
	}

	return FMRES_IGNORED
}
//----------------------------------------------------------------------------------------------
public remove_power(id, powerID)
{
	new Float:fl_vOrigin[3]

	pev(powerID, pev_origin, fl_vOrigin)

	// Create an effect of kamehameha being removed
	message_begin(MSG_BROADCAST, SVC_TEMPENTITY)
	write_byte(TE_IMPLOSION)	//14
	engfunc(EngFunc_WriteCoord, fl_vOrigin[0])
	engfunc(EngFunc_WriteCoord, fl_vOrigin[1])
	engfunc(EngFunc_WriteCoord, fl_vOrigin[2])
	write_byte(120)			// radius
	write_byte(40)			// count
	write_byte(45)			// life in 0.1's
	message_end()

	// Reset Variables
	gPowerID[id] = 0
	gUsingPower[id] = false

	// Stop the sounds
	emit_sound(powerID, CHAN_STATIC, gSoundBeam, VOL_NORM, ATTN_NORM, SND_STOP, PITCH_NORM)
	emit_sound(id, CHAN_STATIC, gSoundRelease, VOL_NORM, ATTN_NORM, SND_STOP, PITCH_NORM)

	engfunc(EngFunc_RemoveEntity, powerID)

	if ( is_user_connected(id) ) {
		// Switch back to previous weapon and reset speed...
		if ( gLastWeapon[id] != CSW_KNIFE ) sh_switch_weapon(id, gLastWeapon[id])
		else sh_reset_max_speed(id)
	}
}
//----------------------------------------------------------------------------------------------
public curweapon(id)
{
	if ( !is_user_alive(id) || !sh_is_inround() ) return
	if ( !gHasSSJGohan[id] || !gUsingPower[id] ) return

	//new wpnid = read_data(2)
	if ( read_data(2) != CSW_KNIFE ) {
		// Knife only when using power
		engclient_cmd(id, "weapon_knife")

		// Make them freeze in place if power created
		if ( gPowerID[id] > 0 ) set_user_maxspeed(id, 1.0)
	}
}
//----------------------------------------------------------------------------------------------
public sh_round_end()
{
	for ( new id = 1; id <= gMaxPlayers; id++ ) {
		if ( gHasSSJGohan[id] && gPowerID[id] > 0 ) {
			remove_power(id, gPowerID[id])
		}
	}
}
//----------------------------------------------------------------------------------------------
public client_disconnect(id)
{
	if( gHasSSJGohan[id] && gPowerID[id] > 0) {
		remove_power(id, gPowerID[id])
	}
}
//----------------------------------------------------------------------------------------------