// ver 1.2.3 added JumpBomb model, fixed other bugs, added screen effect (c) Zombie-rus

#include <amxmodx>
#include <amxmisc>
#include <fakemeta>
#include <engine>
#include <cstrike>
#include <hamsandwich>
#include <zombieplague>

#define PLUGIN "Zombie Class Deimos"
#define VERSION "1.2.3"
#define AUTHOR "NST Team / Zombie-rus"

new spr_skill[] = "g_tentacle"
new const light_classname[] = "nst_deimos_skill"

new sprites_exp_index, sprites_trail_index

new g_wait[33], g_check[33], g_useskill[33], g_msgStatusIcon, g_zclass_deimos, g_msgScreenFade, g_msgScreenShake
new g_CurWeapon[33], g_bombmodelwpn[64]

const WPN_NOT_DROP = ((1<<2)|(1<<CSW_HEGRENADE)|(1<<CSW_SMOKEGRENADE)|(1<<CSW_FLASHBANG)|(1<<CSW_KNIFE)|(1<<CSW_C4))
enum (+= 100)
{
	TASK_WAIT = 2000,
	TASK_ATTACK,
	TASK_BOT_USE_SKILL,
	TASK_USE_SKILL
}
// IDs inside tasks
#define ID_WAIT (taskid - TASK_WAIT)
#define ID_ATTACK (taskid - TASK_ATTACK)
#define ID_BOT_USE_SKILL (taskid - TASK_BOT_USE_SKILL)
#define ID_USE_SKILL (taskid - TASK_USE_SKILL)

const m_flTimeWeaponIdle = 48
const m_flNextAttack = 83

new const sprites_exp[] = "sprites/deimosexp.spr"
new const sprites_trail[] = "sprites/trail.spr"
new const sound_skill_start[] = "zombie_plague/deimos_skill_start.wav"
new const sound_skill_hit[] = "zombie_plague/deimos_skill_hit.wav"
const skill_dmg = 0
const skill_anim = 11
const Float:skill_time_wait = 12.0

new const zclass_name[] = { "Демон" }
new const zclass_info[] = { "\w[\rОтравляет\w]" }
new const zclass_model[] = { "zombie-rus_s0h2" }
new const zclass_clawmodel[] = { "v_zombie-rus_s0h.mdl" }
const zclass_health = 3500
const zclass_speed = 240
const Float:zclass_gravity = 1.0
const Float:zclass_knockback = 1.0

#define OFFSET_MODELINDEX 491
#define OFFSET_LINUX 5 

new index, defaultindex

new const WeaponNames[][] =
{
		"", "weapon_p228", "", "weapon_scout", "weapon_hegrenade", "weapon_xm1014", "weapon_c4", "weapon_mac10",
		"weapon_aug", "weapon_smokegrenade", "weapon_elite", "weapon_fiveseven", "weapon_ump45", "weapon_sg550",
		"weapon_galil", "weapon_famas", "weapon_usp", "weapon_glock18", "weapon_awp", "weapon_mp5navy", "weapon_m249",
		"weapon_m3", "weapon_m4a1", "weapon_tmp", "weapon_g3sg1", "weapon_flashbang", "weapon_deagle", "weapon_sg552",
		"weapon_ak47", "weapon_knife", "weapon_p90"
}

const FFADE_IN = 		0x0000

public plugin_init()
{
	register_plugin(PLUGIN, VERSION, AUTHOR)
	
	// msg
	g_msgStatusIcon = get_user_msgid("StatusIcon")
	
	// Events
	register_logevent("logevent_round_start",2, "1=Round_Start")
	register_event("HLTV", "event_round_start", "a", "1=0", "2=0")
	register_event("DeathMsg", "Death", "a")
	register_event("CurWeapon", "Event_CurrentWeapon", "be", "1=1")

	for (new i = 1; i < sizeof WeaponNames; i++)
	if (WeaponNames[i][0]) RegisterHam(Ham_Item_Deploy, WeaponNames[i], "fw_Weapon_Deploy_Post", 1)
	
	// FM Forwards
	register_forward(FM_CmdStart, "fw_CmdStart")
	register_forward(FM_Touch, "fw_Touch")

	// Cmd
	register_concmd("drop", "use_skill")
}

public plugin_precache()
{
	formatex(g_bombmodelwpn, charsmax(g_bombmodelwpn), "models/zr/v_bomb_deimos2.mdl")
	
	engfunc(EngFunc_PrecacheModel, g_bombmodelwpn)
	
	g_zclass_deimos = zp_register_zombie_class(zclass_name, zclass_info, zclass_model, zclass_clawmodel, zclass_health, zclass_speed, zclass_gravity, zclass_knockback)
	
	sprites_exp_index = precache_model(sprites_exp)
	sprites_trail_index = precache_model(sprites_trail)
	precache_sound(sound_skill_start)
	precache_sound(sound_skill_hit)
	
	index = precache_model("models/player/zombie-rus_s0h2/zombie-rus_s0h2.mdl")
    defaultindex = precache_model("models/player.mdl")
}

public Event_CurrentWeapon(id) g_CurWeapon[id] = read_data(2)

public event_round_start()
{
	for (new id=1; id<33; id++)
	{
		if (!is_user_connected(id)) continue;
		
		reset_value_player(id)
		StatusIcon(id, spr_skill, 0)
	}
}

public zp_user_infected_post(id, infector)
{
    set_wpnmodel(id)
	fm_set_user_model_index(id, index)
}

public zp_user_humanized_post(id, survivor)
{
	fm_set_user_model_index(id, defaultindex)
}

public logevent_round_start()
{
	for (new id=1; id<33; id++)
	{
		if (!is_user_connected(id)) continue;
		if (is_user_bot(id))
		{
			if (task_exists(id+TASK_BOT_USE_SKILL)) remove_task(id+TASK_BOT_USE_SKILL)
			set_task(float(random_num(5,15)), "bot_use_skill", id+TASK_BOT_USE_SKILL)
		}
	}
}

public Death()
{
	new victim = read_data(2) 
	StatusIcon(victim, spr_skill, 0)
	reset_value_player(victim)
}

public fw_Weapon_Deploy_Post(weapon_ent)
{
	static id; id = get_pdata_cbase(weapon_ent, 41, 4)

	static weaponid ; weaponid = cs_get_weapon_id(weapon_ent)

	g_CurWeapon[id] = weaponid
	
	replace_weapon_models(id, weaponid)
}

public client_connect(id)
{
	reset_value_player(id)
}

public client_disconnect(id)
{
	reset_value_player(id)
}

reset_value_player(id)
{
	if (task_exists(id+TASK_WAIT)) remove_task(id+TASK_WAIT)
	if (task_exists(id+TASK_BOT_USE_SKILL)) remove_task(id+TASK_BOT_USE_SKILL)

	g_wait[id] = 0
	g_check[id] = 0
	g_useskill[id] = 0
}

// bot use skill

public bot_use_skill(taskid)
{
	new id = ID_BOT_USE_SKILL
	if (!is_user_bot(id)) return;

	use_skill(id)
	if (task_exists(taskid)) remove_task(taskid)
	set_task(float(random_num(5,15)), "bot_use_skill", id+TASK_BOT_USE_SKILL)
}

public use_skill(id)
{
	if (!is_user_alive(id)) return PLUGIN_CONTINUE
	
	new health = get_user_health(id) - skill_dmg
	if ((zp_get_user_zombie_class(id) == g_zclass_deimos) && (zp_get_user_zombie(id)) && (!g_wait[id]) && (health>0) && (get_user_weapon(id)==CSW_KNIFE))
	{
		g_useskill[id] = 1
		
		// set health
		fm_set_user_health(id, health)
		
		// set time wait
		new Float:timewait = skill_time_wait
		
		g_wait[id] = 1
		if (task_exists(id+TASK_WAIT)) remove_task(id+TASK_WAIT)
		set_task(timewait, "RemoveWait", id+TASK_WAIT)
		return PLUGIN_HANDLED
	}
	
	return PLUGIN_CONTINUE
}

public task_use_skill(taskid)
{
	new id = ID_USE_SKILL
	
	// play anim & sound
	play_weapon_anim(id, 8)
	set_weapons_timeidle(id, skill_time_wait)
	set_player_nextattack(id, 0.5)
	PlayEmitSound(id, sound_skill_start)
	entity_set_int(id, EV_INT_sequence, skill_anim)
	
	// attack
	if (task_exists(id+TASK_ATTACK)) remove_task(id+TASK_ATTACK)
	set_task(0.5, "launch_light", id+TASK_ATTACK)
}

public launch_light(taskid)
{
	new id = ID_ATTACK
	if (task_exists(id+TASK_ATTACK)) remove_task(id+TASK_ATTACK)
	
	if (!is_user_alive(id)) return;
	
	// check
	new Float: fOrigin[3], Float:fAngle[3],Float: fVelocity[3]
	pev(id, pev_origin, fOrigin)
	pev(id, pev_view_ofs, fAngle)
	fm_velocity_by_aim(id, 2.0, fVelocity, fAngle)
	fAngle[0] *= -1.0
	
	// create ent
	new ent = engfunc(EngFunc_CreateNamedEntity, engfunc(EngFunc_AllocString, "info_target"))
	set_pev(ent, pev_classname, light_classname)
	engfunc(EngFunc_SetModel, ent, "models/w_hegrenade.mdl")
	set_pev(ent, pev_mins, Float:{-1.0, -1.0, -1.0})
	set_pev(ent, pev_maxs, Float:{1.0, 1.0, 1.0})
	set_pev(ent, pev_origin, fOrigin)
	fOrigin[0] += fVelocity[0]
	fOrigin[1] += fVelocity[1]
	fOrigin[2] += fVelocity[2]
	set_pev(ent, pev_movetype, MOVETYPE_BOUNCE)
	set_pev(ent, pev_gravity, 0.01)
	fVelocity[0] *= 1000
	fVelocity[1] *= 1000
	fVelocity[2] *= 1000
	set_pev(ent, pev_velocity, fVelocity)
	set_pev(ent, pev_owner, id)
	set_pev(ent, pev_angles, fAngle)
	set_pev(ent, pev_solid, SOLID_BBOX)						//store the enitty id
	
	// invisible ent
	fm_set_rendering(ent, kRenderFxGlowShell, 0, 0, 0, kRenderTransAlpha, 0)
	
	// show trail	
	message_begin( MSG_BROADCAST, SVC_TEMPENTITY )
	write_byte(TE_BEAMFOLLOW)
	write_short(ent)				//entity
	write_short(sprites_trail_index)		//model
	write_byte(5)		//10)//life
	write_byte(3)		//5)//width
	write_byte(102)					//r, hegrenade
	write_byte(45)					//g, gas-grenade
	write_byte(145)					//b
	write_byte(200)		//brightness
	message_end()					//move PHS/PVS data sending into here (SEND_ALL, SEND_PVS, SEND_PHS)
	
	//client_print(0, print_chat, "phong")
	return;
}

public fw_Touch(ent, victim)
{
	if (!pev_valid(ent)) return FMRES_IGNORED
	
	new EntClassName[32]
	entity_get_string(ent, EV_SZ_classname, EntClassName, charsmax(EntClassName))
	
	if (equal(EntClassName, light_classname)) 
	{
		light_exp(ent, victim)
		remove_entity(ent)
		return FMRES_IGNORED
	}
	
	return FMRES_IGNORED
}

light_exp(ent, victim)
{
	if (!pev_valid(ent)) return;
	
	// drop current wpn of victim
	new attacker = pev(ent, pev_owner)
	if (is_user_alive(victim) && !zp_get_user_survivor(victim) && (zp_get_user_zombie(attacker) != zp_get_user_zombie(victim)))
	{
		new wpn, wpnname[32]
		wpn = get_user_weapon(victim)
		if( !(WPN_NOT_DROP & (1<<wpn)) && get_weaponname(wpn, wpnname, charsmax(wpnname)) )
		{
			engclient_cmd(victim, "drop", wpnname)
		    
			screen_effects(victim)
		}
	}
	
	// create effect
	static Float:origin[3];
	pev(ent, pev_origin, origin);
	message_begin(MSG_BROADCAST,SVC_TEMPENTITY); 
	write_byte(TE_EXPLOSION); // TE_EXPLOSION
	write_coord(floatround(origin[0])); // origin x
	write_coord(floatround(origin[1])); // origin y
	write_coord(floatround(origin[2])); // origin z
	write_short(sprites_exp_index); // sprites
	write_byte(40); // scale in 0.1's
	write_byte(30); // framerate
	write_byte(14); // flags 
	message_end(); // message end
	
	// play sound exp
	PlayEmitSound(ent, sound_skill_hit)
}

public RemoveWait(taskid)
{
	new id = ID_WAIT
	g_wait[id] = 0
	if (task_exists(taskid)) remove_task(taskid)
}

public fw_CmdStart(id, uc_handle, seed)
{
	if (!is_user_alive(id)) return FMRES_IGNORED
	
	if (zp_get_user_zombie_class(id) == g_zclass_deimos && zp_get_user_zombie(id))
	{
		// show status icon help
		if (g_wait[id] && g_check[id] != 2)
		{
			g_check[id] = 2
			StatusIcon(id, spr_skill, 2)
		}
		else if (!g_wait[id] && g_check[id] != 1)
		{
			g_check[id] = 1
			StatusIcon(id, spr_skill, 1)
		}
		
		// use skill
		if (g_useskill[id])
		{
			set_uc(uc_handle, UC_Buttons, IN_ATTACK2)
			g_useskill[id] = 0
			entity_set_int(id, EV_INT_sequence, skill_anim)
			
			if (task_exists(id+TASK_USE_SKILL)) remove_task(id+TASK_USE_SKILL)
			set_task(0.0, "task_use_skill", id+TASK_USE_SKILL)
		}
	}
	else if (g_check[id])
	{
		// hide status icon
		g_check[id] = 0
		StatusIcon(id, spr_skill, 0)
	}
	
	//client_print(id, print_chat, "[%i]", set_animation(id))
	return FMRES_IGNORED
}

set_wpnmodel(id)
{
	if (!is_user_alive(id)) return;

	new wpn = get_user_weapon(id)

	if (wpn == CSW_HEGRENADE || wpn == CSW_FLASHBANG || wpn == CSW_SMOKEGRENADE)
	{
    set_pev(id, pev_viewmodel2, g_bombmodelwpn)
	}
	
}

PlayEmitSound(id, const sound[])
{
	emit_sound(id, CHAN_WEAPON, sound, 1.0, ATTN_NORM, 0, PITCH_NORM)
}

StatusIcon(id, sprname[], run)
{	
	if (!is_user_connected(id)) return;
	
	message_begin(MSG_ONE, g_msgStatusIcon, {0,0,0}, id);
	write_byte(run); // status (0=hide, 1=show, 2=flash)
	write_string(sprname); // sprite name
	message_end();
}

play_weapon_anim(player, anim)
{
	set_pev(player, pev_weaponanim, anim)
	message_begin(MSG_ONE, SVC_WEAPONANIM, {0, 0, 0}, player)
	write_byte(anim)
	write_byte(pev(player, pev_body))
	message_end()
}

fm_velocity_by_aim(iIndex, Float:fDistance, Float:fVelocity[3], Float:fViewAngle[3])
{
	//new Float:fViewAngle[3]
	pev(iIndex, pev_v_angle, fViewAngle)
	fVelocity[0] = floatcos(fViewAngle[1], degrees) * fDistance
	fVelocity[1] = floatsin(fViewAngle[1], degrees) * fDistance
	fVelocity[2] = floatcos(fViewAngle[0]+90.0, degrees) * fDistance
	return 1
}

get_weapon_ent(id, weaponid)
{
	static wname[32], weapon_ent
	get_weaponname(weaponid, wname, charsmax(wname))
	weapon_ent = fm_find_ent_by_owner(-1, wname, id)
	return weapon_ent
}
set_weapons_timeidle(id, Float:timeidle)
{
	new entwpn = get_weapon_ent(id, get_user_weapon(id))
	if (pev_valid(entwpn)) set_pdata_float(entwpn, m_flTimeWeaponIdle, timeidle+3.0, 4)
}
set_player_nextattack(id, Float:nexttime)
{
	set_pdata_float(id, m_flNextAttack, nexttime, 4)
}
// 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);
}
// Set entity's rendering type (from fakemeta_util)
stock fm_set_rendering(entity, fx = kRenderFxNone, r = 255, g = 255, b = 255, render = kRenderNormal, amount = 16)
{
	static Float:color[3]
	color[0] = float(r)
	color[1] = float(g)
	color[2] = float(b)
	
	set_pev(entity, pev_renderfx, fx)
	set_pev(entity, pev_rendercolor, color)
	set_pev(entity, pev_rendermode, render)
	set_pev(entity, pev_renderamt, float(amount))
}
// Find entity by its owner (from fakemeta_util)
stock fm_find_ent_by_owner(entity, const classname[], owner)
{
	while ((entity = engfunc(EngFunc_FindEntityByString, entity, "classname", classname)) && pev(entity, pev_owner) != owner) { /* keep looping */ }
	return entity;
}

replace_weapon_models(id, weaponid)
{
	if (zp_get_user_zombie_class(id) == g_zclass_deimos && zp_get_user_zombie(id))
	{
		switch(weaponid)
		{
			case CSW_HEGRENADE:
			{
				set_pev(id, pev_viewmodel2, g_bombmodelwpn)
			}
			case CSW_SMOKEGRENADE:
			{
				set_pev(id, pev_viewmodel2, g_bombmodelwpn)
			}
			case CSW_FLASHBANG:
			{
				set_pev(id, pev_viewmodel2, g_bombmodelwpn)
			}
		}
	}
}

screen_effects(victim)
{
	// Screen Fade
	message_begin(MSG_ONE_UNRELIABLE, g_msgScreenFade, _, victim)
	write_short ( 1<<13 ) // Duration
	write_short ( 1<<14 ) // Hold Time
	write_short ( FFADE_IN ) // Fade type
	write_byte ( random_num ( 50, 200 ) ) // Red amount
	write_byte ( random_num ( 50, 200 ) ) // Green amount
	write_byte ( random_num ( 50, 200 ) ) // Blue amount
	write_byte ( random_num ( 50, 200 ) ) // Alpha
	message_end ( )
	// Screen Shake
	message_begin(MSG_ONE_UNRELIABLE, g_msgScreenShake, _, victim)
	write_short ( 0xFFFF ) // Amplitude
	write_short ( 1<<13 ) // Duration
	write_short ( 0xFFFF ) // Frequency
	message_end ( )
}

stock fm_set_user_model_index(id, value)
{
    set_pdata_int(id, OFFSET_MODELINDEX, value, OFFSET_LINUX)
}  