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

#define ID_WAIT			(taskid - TASK_WAIT)
#define ID_ATTACK			(taskid - TASK_ATTACK)
#define ID_USE_SKILL			(taskid - TASK_USE_SKILL)

#define MAXCARRY			5
#define RADIUS				300.0
#define MAXPLAYERS			32
#define pev_nade_type		pev_flTimeStepSound
#define NADE_TYPE_JUMPING	26517
#define AMMOID_SM			13

#define DEATH_1			"zombi_death_1.wav"
#define DEATH_2			"zombi_death_2.wav"

new const light_classname[] = "nst_deimos_skill"
new const sprites_exp[] = "sprites/deimosexp.spr"
new const sprites_trail[] = "sprites/trail.spr"
new const sound_skill_start[] = "deimos_skill_start.wav"
new const sound_skill_hit[] = "deimos_skill_hit.wav"
new const hand_T[] = "models/v_deimos_t.mdl"
new const hand_CT[] = "models/v_deimos_ct.mdl"
new const g_PlayerModel[] = "models/p_zombibomb.mdl"
new const g_ViewModel_CT[] = "models/v_deimos_bomb_ct.mdl"
new const g_ViewModel_T[] = "models/v_deimos_bomb_t.mdl"
new const g_WorldModel[] = "models/w_zombibomb.mdl"
new const g_SoundGrenadeBuy[][] = { "zombi_bomb_deploy.wav" }
new const g_SoundAmmoPurchase[][] = { "zombi_bomb_idle_3.wav" }
new const g_SoundBombExplode[][] = { "zombi_bomb_exp.wav" }

new sprites_exp_index, sprites_trail_index, index_T, index_CT
new g_iExplo
new g_iJumpingNadeCount[MAXPLAYERS + 1]
new cvar_speed
new g_MaxPlayers
new g_wait[33], g_useskill[33]
new Float:g_frozen_gravity[33], Float:g_frozen_maxspeed[33];

enum (+= 100)
{
	TASK_WAIT = 2000,
	TASK_ATTACK,
	TASK_USE_SKILL
}

public plugin_init()
{
	register_plugin("Deimos Arena", "0.1", "WPMG Team")

	register_event("HLTV", "event_round_start", "a", "1=0", "2=0")
	register_event("Money", "EventMoney", "b")
	register_event("ResetHUD", "EventResetHud", "be")
	register_event("TeamInfo", "event_TeamInfo", "a", "2=TERRORIST", "2=CT")
	register_clcmd("drop", "use_skill")
	register_clcmd("say bomb", "clcmd_bomb")
       
	cvar_speed = register_cvar("zp_zombiebomb_knockback", "800")

	register_forward(FM_CmdStart, "fw_CmdStart")
	register_forward(FM_Touch, "fw_Touch")
	register_forward(FM_EmitSound, "EmitSound")
	register_forward(FM_SetModel, "fw_SetModel")

	RegisterHam(Ham_Think, "grenade", "fw_ThinkGrenade")
	RegisterHam(Ham_Spawn, "player", "Player_Spawn", 1)
	RegisterHam(Ham_Killed, "player", "Player_Killed_Pre")
	RegisterHam(Ham_Killed, "player", "Player_Killed", 1)
	RegisterHam(Ham_TakeDamage, "player", "Player_TakeDamage")
	RegisterHam(Ham_Touch, "weaponbox", "Player_Touch")
	RegisterHam(Ham_Touch, "armoury_entity", "Player_Touch")
	RegisterHam(Ham_Touch, "weapon_shield", "Player_Touch")
	RegisterHam(Ham_Item_Deploy, "weapon_knife", "Player_Item_Deploy", 1)
	RegisterHam(Ham_Item_Deploy, "weapon_smokegrenade", "Player_Item_Deploy_Grenade", 1)
	RegisterHam(Ham_Player_PreThink, "player", "Player_PreThink", 1)

	g_MaxPlayers = get_maxplayers()
}

public plugin_precache()
{
	precache_sound(DEATH_1)
	precache_sound(DEATH_2)
	precache_model(hand_T)
	precache_model(hand_CT)
	precache_sound(sound_skill_start)
	precache_sound(sound_skill_hit)
	precache_sound("zombi_swing_1.wav")
	precache_sound("zombi_swing_2.wav")
	precache_sound("zombi_wall_1.wav")
	precache_sound("zombi_attack_3.wav")
	precache_sound("zombi_attack_1.wav")
	precache_model(g_PlayerModel)
	precache_model(g_ViewModel_CT)
	precache_model(g_ViewModel_T)
	precache_model(g_WorldModel)

	g_iExplo = precache_model("sprites/zombiebomb_exp.spr")
	index_T = precache_model("models/player/deimos_T/deimos_T.mdl")
	index_CT = precache_model("models/player/deimos_CT/deimos_CT.mdl")
	sprites_exp_index = precache_model(sprites_exp)
	sprites_trail_index = precache_model(sprites_trail)

	new i

	for(i = 0; i < sizeof g_SoundGrenadeBuy; i++)
		precache_sound(g_SoundGrenadeBuy[i])

	for(i = 0; i < sizeof g_SoundAmmoPurchase; i++)
		precache_sound(g_SoundAmmoPurchase[i])

	for(i = 0; i < sizeof g_SoundBombExplode; i++)
		precache_sound(g_SoundBombExplode[i])
}

public client_connect(id)
{
	reset_value_player(id)
}

public client_disconnect(id)
{
	if(task_exists(id))
		remove_task(id)

	reset_value_player(id)
}

public Player_Spawn(id)
{
	if(!is_user_alive(id))
		return;

	strip_user_weapons(id)
	give_item(id, "weapon_knife")
	set_pev(id, pev_health, 200.0)

	if(get_user_team(id) == 1)
	{
		cs_set_user_model(id, "deimos_T")
		fm_cs_set_user_model_index(id, index_T)
	}
	else if(get_user_team(id) == 2)
	{
		cs_set_user_model(id, "deimos_CT")
		fm_cs_set_user_model_index(id, index_CT)
	}
}

public Player_Killed_Pre(victim, attacker, shouldgib)
{
	SetHamParamInteger(3, 2)
}

public Player_Killed(victim, attacker, shouldgib)
{
	reset_value_player(victim)
	client_print(victim, print_center, "You will be respawn through 3 seconds")
	message_begin(MSG_ONE, 108, { 0, 0, 0 }, victim)
	write_byte(3)
	write_byte(0)
	message_end()

	switch(random_num(0, 1))
	{
		case 0: emit_sound(victim, CHAN_WEAPON, DEATH_1, 1.0, ATTN_NORM, 0, PITCH_NORM)
		case 1: emit_sound(victim, CHAN_WEAPON, DEATH_2, 1.0, ATTN_NORM, 0, PITCH_NORM)
	}

	set_task(3.0, "respawn", victim)
}

public Player_Item_Deploy(weapon) 
{
	new id = get_pdata_cbase(weapon, 41, 4)

	switch(get_user_team(id))
	{
		case 1:
		{ 
			set_pev(id, pev_viewmodel2, hand_T) 
			set_pev(id, pev_weaponmodel2, "") 
		}
		case 2:
		{ 
			set_pev(id, pev_viewmodel2, hand_CT) 
			set_pev(id, pev_weaponmodel2, "") 
		}
	}
}

public Player_Item_Deploy_Grenade(weapon)
{
	new id = get_pdata_cbase(weapon, 41, 4)

        if(g_iJumpingNadeCount[id] > 0)
        {
		switch(get_user_team(id))
		{
			case 1: set_pev(id, pev_viewmodel2, g_ViewModel_T)
			case 2: set_pev(id, pev_viewmodel2, g_ViewModel_CT)
		}
		set_pev(id, pev_weaponmodel2, g_WorldModel)
        }
}

public	 Player_TakeDamage(victim, inflicator, attacker, Float:damage)
{
	if(!is_user_connected(attacker))
		return;

	if(victim == attacker)
		return;

	if(get_user_weapon(attacker) == CSW_KNIFE)
	{
		if(pev(attacker, pev_button) & IN_ATTACK)
			SetHamParamFloat(4, damage = 50.0)
		else if(pev(attacker, pev_button) & IN_ATTACK2)
			SetHamParamFloat(4, damage = 200.0)
	}
	set_pdata_float(victim, 108, 1.0, 5)
}

public Player_Touch(weapon, id)
{
	if(is_user_alive(id))
		return HAM_SUPERCEDE;
	
	return HAM_IGNORED;
}

public Player_PreThink(id)
{
	if((pev(id, pev_button) & IN_DUCK) && (pev(id, pev_oldbuttons) & IN_DUCK))
		set_pev(id, pev_view_ofs, Float:{0.0, 0.0, 15.0})
	else
		set_pev(id, pev_view_ofs, Float:{0.0, 0.0, 25.0})
}

public EmitSound(id, channel, const sample[], Float:volume, Float:attn, flags, pitch)
{
	if(!is_user_alive(id) || !is_user_connected(id) || get_user_weapon(id) != CSW_KNIFE)
		return FMRES_IGNORED

	if(equal(sample, "weapons/knife_slash1.wav"))
	{
		emit_sound(id, channel, "zombi_swing_1.wav", 1.0, ATTN_NORM, 0, PITCH_NORM)
		return FMRES_SUPERCEDE
	}
	if(equal(sample, "weapons/knife_slash2.wav"))
	{
		emit_sound(id, channel, "zombi_swing_2.wav", 1.0, ATTN_NORM, 0, PITCH_NORM)
		return FMRES_SUPERCEDE
	}
	if(equal(sample, "weapons/knife_hitwall1.wav"))
	{
		emit_sound(id, channel, "zombi_wall_1.wav", 1.0, ATTN_NORM, 0, PITCH_NORM)
		return FMRES_SUPERCEDE
	}
	if(equal(sample, "weapons/knife_stab.wav"))
	{
		emit_sound(id, channel, "zombi_attack_3.wav", 1.0, ATTN_NORM, 0, PITCH_NORM)
		return FMRES_SUPERCEDE
	}
	if(equal(sample, "weapons/knife_hit1.wav") || equal(sample, "weapons/knife_hit2.wav") || equal(sample, "weapons/knife_hit3.wav") || equal(sample, "weapons/knife_hit4.wav"))
	{
		emit_sound(id, channel, "zombi_attack_1.wav", 1.0, ATTN_NORM, 0, PITCH_NORM)
		return FMRES_SUPERCEDE
	}
	return FMRES_IGNORED
}

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

	set_rendering(id)
	g_wait[id] = 0
	g_useskill[id] = 0
	g_iJumpingNadeCount[id] = 0
}

public use_skill(id)
{
	if (!is_user_alive(id)) return PLUGIN_CONTINUE

	if ((!g_wait[id]) && (get_user_weapon(id)==CSW_KNIFE))
	{
		g_useskill[id] = 1

		new Float:timewait = 7.0
		
		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_weapon_anim(id, 2)
	set_weapons_timeidle(id, 7.0)
	set_pdata_float(id, 83, 0.5, 4)
	emit_sound(id, CHAN_WEAPON, sound_skill_start, 1.0, ATTN_NORM, 0, PITCH_NORM)
	entity_set_int(id, EV_INT_sequence, 2)

	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;

	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

	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)

	set_rendering(ent, kRenderFxGlowShell, 0, 0, 0, kRenderTransAlpha, 0)

	message_begin( MSG_BROADCAST, SVC_TEMPENTITY )
	write_byte(TE_BEAMFOLLOW)
	write_short(ent)
	write_short(sprites_trail_index)
	write_byte(5)
	write_byte(3)

	write_byte(209)
	write_byte(120)
	write_byte(9)

	write_byte(200)
	message_end()

	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
}

public clcmd_bomb(id)
{
	if(!is_user_alive(id))
		return;

	if(get_user_frags(id) < 2)
	{
		client_print(id, print_chat, "Not enough frags!")
		return;
	}

	if(g_iJumpingNadeCount[id] >= MAXCARRY)
	{
		client_print(id, print_chat, "Cannot hold mode grenades!")
		return;
	}

	new iBpAmmo = cs_get_user_bpammo(id, CSW_SMOKEGRENADE)

	if(g_iJumpingNadeCount[id] >= 1)
	{
		set_user_frags(id, get_user_frags(id) - 2)
		cs_set_user_bpammo(id, CSW_SMOKEGRENADE, iBpAmmo + 1)
		emit_sound(id, CHAN_ITEM, g_SoundAmmoPurchase[random_num(0, sizeof g_SoundAmmoPurchase-1)], VOL_NORM, ATTN_NORM, 0, PITCH_NORM)
		g_iJumpingNadeCount[id]++
		ExecuteHamB(Ham_Item_Deploy, find_ent_by_owner(-1, "weapon_smokegrenade", id))
	}
	else
	{
		set_user_frags(id, get_user_frags(id) - 2)
		give_item(id, "weapon_smokegrenade")
		emit_sound(id, CHAN_ITEM, g_SoundGrenadeBuy[random_num(0, sizeof g_SoundGrenadeBuy-1)], VOL_NORM, ATTN_NORM, 0, PITCH_NORM)
		g_iJumpingNadeCount[id] = 1
		ExecuteHamB(Ham_Item_Deploy, find_ent_by_owner(-1, "weapon_smokegrenade", id))
	}
}

light_exp(ent, victim)
{
	if(!pev_valid(ent)) return;

	new attacker = pev(ent, pev_owner)
	if (is_user_alive(victim) && (get_user_team(attacker) != get_user_team(victim)))
	{
		set_pev(victim, pev_health, max(pev(victim, pev_health) - random_num(20, 100), 0))
		set_pdata_float(victim, 83, 5.0, 4)

		set_rendering(victim, kRenderFxGlowShell, 209, 120, 9, kRenderNormal, 30)

		pev(victim, pev_gravity, g_frozen_gravity[victim])
		pev(victim, pev_maxspeed, g_frozen_maxspeed[victim])

		if(pev(victim, pev_flags) & FL_ONGROUND)
			set_pev(victim, pev_gravity, 999999.9)
		else
			set_pev(victim, pev_gravity, 0.000001)

		set_pev(victim, pev_maxspeed, 1.0)

		set_task(5.0, "off_rendering", victim)
	}

	static Float:origin[3]
	pev(ent, pev_origin, origin)
	message_begin(MSG_BROADCAST,SVC_TEMPENTITY)
	write_byte(TE_EXPLOSION)
	write_coord(floatround(origin[0]))
	write_coord(floatround(origin[1]))
	write_coord(floatround(origin[2]))
	write_short(sprites_exp_index)
	write_byte(40)
	write_byte(30)
	write_byte(14)
	message_end()

	emit_sound(ent, CHAN_WEAPON, sound_skill_hit, 1.0, ATTN_NORM, 0, PITCH_NORM)
}

public off_rendering(victim)
{
	set_pev(victim, pev_gravity, g_frozen_gravity[victim])
	set_pev(victim, pev_maxspeed, g_frozen_maxspeed[victim])
	set_rendering(victim)
}

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(g_useskill[id])
	{
		set_uc(uc_handle, UC_Buttons, IN_ATTACK2)
		g_useskill[id] = 0
		entity_set_int(id, EV_INT_sequence, 2)
		
		if (task_exists(id+TASK_USE_SKILL)) remove_task(id+TASK_USE_SKILL)
		set_task(0.0, "task_use_skill", id+TASK_USE_SKILL)
	}
	return FMRES_IGNORED
}

public respawn(id)
{
	if(is_user_alive(id))
		return;

	ExecuteHamB(Ham_CS_RoundRespawn, id)
}

public EventResetHud(id) 
{	
	message_begin(MSG_ONE_UNRELIABLE, get_user_msgid("HideWeapon"), _, id)
	write_byte((1<<5))
	message_end()
}

public EventMoney(id) 
{
	message_begin(MSG_ONE_UNRELIABLE, get_user_msgid("Money"), _, id)
	write_long(0)
	write_byte(1)
	message_end()
}

public event_round_start()
{
	for (new id=1; id <= g_MaxPlayers; id++)
	{
		if(!is_user_connected(id))
		continue;

		reset_value_player(id)
	}
}

public event_TeamInfo()
{
	new id = read_data(1)

	if(is_user_alive(id))
		return;

	set_task(3.0, "respawn", id)
}


public fw_SetModel(Entity, const Model[])
{
	if(Entity < 0)
		return FMRES_IGNORED
       
        if(pev(Entity, pev_dmgtime) == 0.0)
            return FMRES_IGNORED
       
        new iOwner = entity_get_edict(Entity, EV_ENT_owner)   
       
        if(g_iJumpingNadeCount[iOwner] >= 1 && equal(Model [7], "w_sm", 4))
        {
		set_pev(Entity, pev_nade_type, 0)
           
		set_pev(Entity, pev_nade_type, NADE_TYPE_JUMPING)
           
		g_iJumpingNadeCount[iOwner]--
           
		entity_set_model(Entity, g_WorldModel)
		return FMRES_SUPERCEDE
	}
	return FMRES_IGNORED
}

public fw_ThinkGrenade(Entity)
{
        if(!pev_valid(Entity))
            return HAM_IGNORED
       
        static Float:dmg_time
        pev(Entity, pev_dmgtime, dmg_time)
       
        if(dmg_time > get_gametime())
            return HAM_IGNORED
       
	if(pev(Entity, pev_nade_type) == NADE_TYPE_JUMPING)
	{
		jumping_explode(Entity)
		return HAM_SUPERCEDE
	}
	return HAM_IGNORED
}

public jumping_explode(Entity)
{
	if(Entity < 0)
	return;
       
	static Float:flOrigin[3]
	pev(Entity, pev_origin, flOrigin)
       
	engfunc(EngFunc_MessageBegin, MSG_PVS, SVC_TEMPENTITY, flOrigin, 0)
	write_byte(TE_SPRITE)
	engfunc(EngFunc_WriteCoord, flOrigin[0])
	engfunc(EngFunc_WriteCoord, flOrigin[1])
	engfunc(EngFunc_WriteCoord, flOrigin[2] + 45.0)
	write_short(g_iExplo)
	write_byte(35)
	write_byte(186)
	message_end()
       
	emit_sound(Entity, CHAN_WEAPON, g_SoundBombExplode[random_num(0, sizeof g_SoundBombExplode-1)], VOL_NORM, ATTN_NORM, 0, PITCH_NORM)
       
	for(new i = 1; i < g_MaxPlayers; i++)
        {
		if(!is_user_alive(i))
                continue;
           
		new Float:flVictimOrigin[3]
		pev(i, pev_origin, flVictimOrigin)
           
		new Float:flDistance = get_distance_f(flOrigin, flVictimOrigin)   
           
		if(flDistance <= RADIUS)
		{
			new Float:flSpeed = get_pcvar_float(cvar_speed)
			new Float:flNewSpeed = flSpeed * (1.0 - (flDistance / RADIUS))
			new Float:flVelocity[3]

			get_speed_vector(flOrigin, flVictimOrigin, flNewSpeed, flVelocity)   
			set_pev(i, pev_velocity, flVelocity)
		}
	}
	engfunc(EngFunc_RemoveEntity, Entity)
}       

stock get_speed_vector(const Float:origin1[3],const Float:origin2[3],Float:speed, Float:new_velocity[3])
{
        new_velocity[0] = origin2[0] - origin1[0]
        new_velocity[1] = origin2[1] - origin1[1]
        new_velocity[2] = origin2[2] - origin1[2]
        new Float:num = floatsqroot(speed*speed / (new_velocity[0]*new_velocity[0] + new_velocity[1]*new_velocity[1] + new_velocity[2]*new_velocity[2]))
        new_velocity[0] *= num
        new_velocity[1] *= num
        new_velocity[2] *= num
       
        return 1;
}

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])
{
	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
}

set_weapons_timeidle(id, Float:timeidle)
{
	new entwpn = get_weapon_ent(id, get_user_weapon(id))
	if (pev_valid(entwpn)) set_pdata_float(entwpn, 48, timeidle+3.0, 4)
}

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
}

stock fm_find_ent_by_owner(entity, const classname[], owner)
{
	while ((entity = engfunc(EngFunc_FindEntityByString, entity, "classname", classname)) && pev(entity, pev_owner) != owner){}
	return entity;
}

stock fm_cs_set_user_model_index(id, value)
{
	set_pdata_int(id, 491, value, 5)
}