/*
[ZP] Laser Gun 
Created by anggara_nothing
Fix Darkden
www.Dark-games.ru

Description :
Give you lasergun after you buy it. Can burn the zombie.

Credit :
MeRcyLeZZ -- for Napalm Nade plugin(for get the burning code.)^_^
Toster v2.1 -- for laser sight plugin.( for create a laser beam.)
*/

#include <amxmodx>
#include <zombieplague>
#include <hamsandwich>
#include <fakemeta>
#include <xs>

#define PLUGIN "[ZP] Laser Gun"
#define VERSION "1.5"
#define AUTHOR "anggara_nothing"

// Flame task
#define FLAME_DURATION args[0]
#define FLAME_ATTACKER args[1]

// Laser sprites
new const sprite_laser_fire[] = "sprites/flame.spr"
new const sprite_laser_smoke[] = "sprites/black_smoke3.spr"
new const sprite_laser_beam[] = "sprites/white.spr"
new g_flameSpr, g_smokeSpr
new  g_laserspr

// Weapon model.
new const model_laser_view[] = "models/zombie_plague/v_laser_gun2.mdl"

// Player burning sounds.
new const grenade_fire_player[][] = { "zombie_plague/zombie_burn3.wav","zombie_plague/zombie_burn4.wav","zombie_plague/zombie_burn5.wav","zombie_plague/zombie_burn6.wav","zombie_plague/zombie_burn7.wav" }

new lgid
new has_LG[33]
new cvar_duration, cvar_slowdown, cvar_damage
new maxplyr

public plugin_init()
{
	
	register_plugin(PLUGIN, VERSION, AUTHOR)
	
	register_event("HLTV", "event_new_round", "a", "1=0", "2=0")
	
	RegisterHam(Ham_TakeDamage, "player", "fw_TakeDamage")
	
	register_event("CurWeapon", "event_curweapon", "be", "1=1")
	
	cvar_duration = get_cvar_pointer("zp_fire_duration")
	cvar_slowdown = get_cvar_pointer("zp_fire_slowdown")
	cvar_damage = get_cvar_pointer("zp_fire_damage")
	
	maxplyr = get_maxplayers()
}

public plugin_precache()
{
	new i
	
	lgid = zp_register_extra_item("Плазменная пушка", 30, ZP_TEAM_HUMAN)
	
	engfunc(EngFunc_PrecacheModel, model_laser_view)
	
	for (i = 0; i < sizeof grenade_fire_player; i++)
		engfunc(EngFunc_PrecacheSound, grenade_fire_player[i])
	
	g_flameSpr = engfunc(EngFunc_PrecacheModel, sprite_laser_fire)
	g_smokeSpr = engfunc(EngFunc_PrecacheModel, sprite_laser_smoke)
	g_laserspr = engfunc(EngFunc_PrecacheModel, sprite_laser_beam)
}

public event_new_round()
{
	for(new id = 0; id < maxplyr; id++)
	{
		has_LG[id] = 0
	}
}

public zp_extra_item_selected(player, itemid)
{
	if(itemid == lgid)
	{
		// If player have AWP, strip the AWP.
		fm_strip_user_gun(player,18)
		
		has_LG[player] = 1
		fm_give_item(player, "weapon_awp")
	}
}

// Ham Take Damage Forward (inflictor = weapon)
public fw_TakeDamage(victim, inflictor, attacker, Float:damage, damage_type)
{
	// Not alive or disconnected.
	if (!is_user_alive(attacker)  || !is_user_connected(attacker))
		return HAM_IGNORED;
	
	// Not zombie
	if (!zp_get_user_zombie(victim))
		return PLUGIN_CONTINUE;
	
	if (!has_LG[attacker])
		return PLUGIN_CONTINUE;
	
	static params[1]
	if (zp_get_user_nemesis(victim)) // fire duration (nemesis takes less)
		params[0] = get_pcvar_num(cvar_duration)
	else
		params[0] = get_pcvar_num(cvar_duration)*5
		
	if (get_user_weapon(attacker) == CSW_AWP )
	{
		// Set burning task on victim
		set_task(0.1, "burning_flame", victim, params, sizeof params)
	}
	
	return PLUGIN_CONTINUE;
}

public event_curweapon(id)
{
	new button = pev(id, pev_button)
	
	if (get_user_weapon(id) != CSW_AWP )
		return ;
	
	if (!is_user_alive(id))
		return ;
	
	if (!has_LG[id])
		return ;
	
	set_pev(id, pev_viewmodel2, model_laser_view)
	
	if (button&IN_ATTACK) show_laser(id)
}

// Burning Flames
public burning_flame(args[1], taskid)
{
	// Get player origin and flags
	static Float:originF[3], flags
	pev(taskid, pev_origin, originF)
	flags = pev(taskid, pev_flags)
	
	// in water - victim death - burning stopped
	if ((flags & FL_INWATER) || FLAME_DURATION < 1 || !is_user_alive(taskid))
	{
		// Smoke sprite
		engfunc(EngFunc_MessageBegin, MSG_PVS, SVC_TEMPENTITY, originF, 0)
		write_byte(TE_SMOKE) // TE id
		engfunc(EngFunc_WriteCoord, originF[0]) // x
		engfunc(EngFunc_WriteCoord, originF[1]) // y
		engfunc(EngFunc_WriteCoord, originF[2]-50.0) // z
		write_short(g_smokeSpr) // sprite
		write_byte(random_num(15, 20)) // scale
		write_byte(random_num(10, 20)) // framerate
		message_end()
		
		return;
	}
	
	// Get fire slow down setting
	static Float:slowdown
	slowdown = get_pcvar_float(cvar_slowdown)
	
	// Fire slow down, unless nemesis
	if (slowdown > 0.0 && !zp_get_user_nemesis(taskid) && (flags & FL_ONGROUND))
	{
		static Float:velocity[3]
		pev(taskid, pev_velocity, velocity)
		xs_vec_mul_scalar(velocity, slowdown, velocity)
		set_pev(taskid, pev_velocity, velocity)
	}
	
	// Get health and fire damage setting
	static health, firedamage
	health = pev(taskid, pev_health)
	firedamage = get_pcvar_num(cvar_damage)
	
	// Take damage from the fire
	if (health > firedamage)
		fm_set_user_health(taskid, health - firedamage)
	
	// Flame sprite
	engfunc(EngFunc_MessageBegin, MSG_PVS, SVC_TEMPENTITY, originF, 0)
	write_byte(TE_SPRITE) // TE id
	engfunc(EngFunc_WriteCoord, originF[0]+random_float(-5.0, 5.0)) // x
	engfunc(EngFunc_WriteCoord, originF[1]+random_float(-5.0, 5.0)) // y
	engfunc(EngFunc_WriteCoord, originF[2]+random_float(-10.0, 10.0)) // z
	write_short(g_flameSpr) // sprite
	write_byte(random_num(5, 10)) // scale
	write_byte(200) // brightness
	message_end()
	
	// Randomly play burning zombie scream sounds (not for nemesis)
	if (!random_num(0, 20) && !zp_get_user_nemesis(taskid))
		engfunc(EngFunc_EmitSound, taskid, CHAN_VOICE, grenade_fire_player[random_num(0, sizeof grenade_fire_player - 1)], 1.0, ATTN_NORM, 0, PITCH_NORM)
	
	// Decrease task cycle counter
	FLAME_DURATION -= 1;
	
	// Keep sending flame messaegs
	set_task(0.2, "burning_flame", taskid, args, sizeof args)
}

// Show laser.
public show_laser(id)
{	
	if(zp_get_user_zombie(id) || zp_get_user_first_zombie(id) || zp_get_user_last_zombie(id) || zp_get_user_nemesis(id))
		return PLUGIN_CONTINUE;
	
	new e[3]
	get_user_origin(id, e, 3)
	
	// Laser beam.
	message_begin( MSG_BROADCAST,SVC_TEMPENTITY)
	write_byte (1)
	write_short(id ) //(id | 0x1000)
	write_coord (e[0]) // x = horizontal /\ write_coord = position
	write_coord (e[1]) // y = vertical
	write_coord (e[2]) // z = ???
	write_short(g_laserspr) // The sprite
	write_byte (0)// framestart
	write_byte (0)// framerate
	write_byte (1) // Life
	write_byte (7) // Width 
	write_byte (0) // Noise ?
	write_byte (0) 		// Red   | R,G,B
	write_byte (0)		// Green | R,G,B
	write_byte (255)		// BLUE  | R,G,B
	write_byte (200) // Brightness.
	write_byte (200) // Speed.
	message_end()
	
	// Laser hit.
	message_begin(MSG_BROADCAST, SVC_TEMPENTITY) 
	write_byte( TE_SPRITE ) 
	write_coord(e[0])
	write_coord(e[1])
	write_coord(e[2])
	write_short( g_flameSpr )
	write_byte(random_num(5, 10)) // scale
	write_byte(200) // brightness
	message_end() 
	
	return PLUGIN_CONTINUE;
}

// Give an item to a player (from fakemeta_util)
stock fm_give_item(id, const item[])
{
	static ent
	ent = engfunc(EngFunc_CreateNamedEntity, engfunc(EngFunc_AllocString, item))
	if (!pev_valid(ent)) return;
	
	static Float:originF[3]
	pev(id, pev_origin, originF)
	set_pev(ent, pev_origin, originF)
	set_pev(ent, pev_spawnflags, pev(ent, pev_spawnflags) | SF_NORESPAWN)
	dllfunc(DLLFunc_Spawn, ent)
	
	static save
	save = pev(ent, pev_solid)
	dllfunc(DLLFunc_Touch, ent, id)
	if (pev(ent, pev_solid) != save)
		return;
	
	engfunc(EngFunc_RemoveEntity, ent)
}

// Set player's health (from fakemeta_util)
stock fm_set_user_health(id, health)
{
	(health > 0) ? set_pev(id, pev_health, float(health)) : dllfunc(DLLFunc_ClientKill, id);
}

// only weapon index or its name can be passed, if neither is passed then the current gun will be stripped
stock bool:fm_strip_user_gun(index, wid = 0, const wname[] = "") {
	new ent_class[32];
	if (!wid && wname[0])
		copy(ent_class, sizeof ent_class - 1, wname);
	else {
		new weapon = wid, clip, ammo;
		if (!weapon && !(weapon = get_user_weapon(index, clip, ammo)))
			return false;
		
		get_weaponname(weapon, ent_class, sizeof ent_class - 1);
	}

	new ent_weap = fm_find_ent_by_owner(-1, ent_class, index);
	if (!ent_weap)
		return false;

	engclient_cmd(index, "drop", ent_class);

	new ent_box = pev(ent_weap, pev_owner);
	if (!ent_box || ent_box == index)
		return false;

	dllfunc(DLLFunc_Think, ent_box);

	return true;
}

// From fakemeta_util
stock fm_find_ent_by_owner(index, const classname[], owner, jghgtype = 0) {
	new strtype[11] = "classname", ent = index;
	switch (jghgtype) {
		case 1: strtype = "target";
		case 2: strtype = "targetname";
	}

	while ((ent = engfunc(EngFunc_FindEntityByString, ent, strtype, classname)) && pev(ent, pev_owner) != owner) {}

	return ent;
}


/* AMXX-Studio Notes - DO NOT MODIFY BELOW HERE
*{\\ rtf1\\ ansi\\ deff0{\\ fonttbl{\\ f0\\ fnil Tahoma;}}\n\\ viewkind4\\ uc1\\ pard\\ lang1033\\ f0\\ fs16 \n\\ par }
*/
