/*================================================================================
	
	-------------------------------------------
	-*- [ZP] Addon: C4 Bomb | by Re.Act!ve -*- 
	-------------------------------------------

	~~~~~~~~~~~~~~~
	- Credits -
	~~~~~~~~~~~~~~~
	Re.Act!ve 			This Build Plugin

	~~~~~~~~~~~~~~~
	- Changelog -
	~~~~~~~~~~~~~~~
	v. 1.0	 - First Plugin Released, version released
================================================================================*/

#include <amxmodx>
#include <engine>
#include <fakemeta_util>
#include <hamsandwich>
#include <zombie_plague_advance>

#define PLUGIN "[ZP] Addon: С4 Bomb"
#define AUTHOR "Re.Act!ve"
#define VERSION "1.0"
#define bomb_name "bomb_c4"

new const g_item_name[] = { "C4 Bomb" };    	// Name
new const g_item_cost = 20 ;   			 	// Cost
new const Float:RADIUS = 2200.0
new const g_time_used = 5; 				// Time planted the bomb
new const c4_model[] = "models/w_c4.mdl"  	// Model C4 models/w_c4.mdl
new const sprite_grenade_ring[] = "sprites/shockwave.spr"
new const give_bomb[] = { "weapons/c4_disarm.wav" }		// Sound Give Bomb
new const glass[2][] = { "debris/bustglass1.wav", "debris/bustglass2.wav" }		// Sound Give Bomb
new const planted_bomb[] = { "radio/bombpl.wav" }			// Sound Planted Bomb
new const explode_bomb[] = { "weapons/explode4.wav" }	// Sound Explode Bomb
new const explosion_bomb[] = { "weapons/c4_explode1.wav" }	// Sound Explosion Bomb
new iconstatus, g_c4_type, g_item_c4, g_c4_time, g_c4_kill_type, g_c4_exp, g_c4_health, g_c4_ammo, g_c4_ammo2, g_c4_ammo3, g_MaxPlayers, g_BombX, g_msgBarTime;
new g_SyncHUD, g_planted, g_time, explosion, boom, m_iTrail, gmsg_screenshake, ent_id
new bool:g_bomb[32], bool:g_used[33], bool:g_going[33], decal

public plugin_init() 
{
	g_c4_type = register_cvar("zp_c4_type", "0")			// 0 - Выдается людям в начале каждого раунда. 1 - Сделать в виде Extra Item
	g_c4_time = register_cvar("zp_c4_time", "20")			// Время, через которое взорвется с4
	g_c4_kill_type= register_cvar("zp_c4_kill_type", "0")	// Бомба взрывается и: 0 - действует на всех в радиусе, 1 - действует только зомби
	g_c4_exp = register_cvar("zp_c4_exp_type", "1")		// 0 - убивает всех в радиусе взырва, 1 - в зависимости от радиуса наносит урон (квар ниже)
	g_c4_health = register_cvar("zp_c4_health", "120.0")	// Сколько хп у бомбы? (0 - не ломается)
	g_c4_ammo = register_cvar("zp_c4_ammo", "15")	// Сколько получит тот, кто установил бомбу, если она взорвалась
	g_c4_ammo2 = register_cvar("zp_c4_ammo2", "15")	// Сколько получат оставшиеся люди за взорванную бомбу (0 - не получат)
	g_c4_ammo3 = register_cvar("zp_c4_ammo3", "15")	// Сколько получит зомби, сломавший бомбу или заразивший подрывника (0 - не получит)

	register_plugin(PLUGIN, VERSION, AUTHOR)
	register_event("CurWeapon", "grenade_icon", "be", "1=1")
	register_event("HLTV", "RoundStart", "a", "1=0", "2=0")
	register_event("DeathMsg", "event_death", "a")
	register_forward(FM_PlayerPreThink, "fw_PlayerPreThink") 

	register_forward(FM_CmdStart, "fw_CmdStart")
	g_msgBarTime = get_user_msgid("BarTime")
	register_dictionary("zp_addon_c4.txt");
	decal = engfunc(EngFunc_DecalIndex,"{scorch3")
	if(get_pcvar_num(g_c4_type) != 0)
    	g_item_c4 = zp_register_extra_item(g_item_name, g_item_cost, ZP_TEAM_HUMAN)

	register_clcmd("say /bomb1", "givebomb")
	//register_clcmd("say /create", "Create_Entityes")
	g_SyncHUD = CreateHudSyncObj( 1 );
	gmsg_screenshake = get_user_msgid("ScreenShake");
	g_MaxPlayers = get_maxplayers()
	iconstatus = get_user_msgid("StatusIcon")
}

public plugin_precache()  
{
	explosion = precache_model("sprites/mushroom.spr");
	boom = precache_model("sprites/zerogxplode.spr");
	m_iTrail = engfunc(EngFunc_PrecacheModel, sprite_grenade_ring)
	precache_model(c4_model)
	precache_sound(give_bomb)
	precache_sound(glass[0])
	precache_sound(glass[1])
	precache_sound(explode_bomb)
	precache_sound(explosion_bomb)
	precache_sound(planted_bomb)
}

public RoundStart()
{
	for (new id = 0; id <= g_MaxPlayers; id++)
	g_bomb[id] = false;

	new entity; entity = ent_id
	if(is_valid_ent(entity))
	{
		client_print(0, print_chat, "ZP Valid")
		remove_entity(entity)
	}

	g_planted = 0;
}

public zp_user_infected_post(id, infector, nemesis)
{
	remove_grenade_icon(id)
	g_bomb[id] = false;
}

public givebomb(id)
{
	if(!zp_get_user_zombie(id))
	{
		g_used[id] = false;
		client_print(id, print_chat, "[ZP] Bomb Give!")
		emit_sound(id, CHAN_STREAM, give_bomb, 1.0, ATTN_NORM, 0, PITCH_NORM)
		g_bomb[id] = true;
	}
}

public zp_round_started(gamemode, id)
{
	if( (gamemode == MODE_INFECTION) && (get_pcvar_num(g_c4_type) != 1) )
	{
		new id;
		g_BombX = 0;
		for (new i=1; i <=3; i++)
		{
			id = random_num(1, g_MaxPlayers)
			if( !zp_get_user_zombie(id) && is_user_alive(id) && !is_user_bot(id) && (g_BombX != 1) )
			{
				g_BombX = 1;
				fm_strip_user_gun(id,9)
				g_used[id] = false;
				g_bomb[id] = true;
				g_planted = 0;
				emit_sound(id, CHAN_STREAM, give_bomb, 1.0, ATTN_NORM, 0, PITCH_NORM)
				set_task(1.0, "Hud_MSG", id, "", 0, "b")
			}
		}
	}
}

public zp_extra_item_selected(player, itemid)
{
	if( (itemid == g_item_c4) && (get_pcvar_num(g_c4_type) != 0) )
	{
		g_used[player] = false;
		g_bomb[player] = true;
		g_planted = 0;
	}
	else
	{
		if(itemid == g_item_c4)
		{
			client_print(player, print_chat, "[ZP] %L", LANG_PLAYER, "C4_BOMB_NO_BUY")
			zp_set_user_ammo_packs(player, zp_get_user_ammo_packs(player) + g_item_cost)
		}
	}
}

public Hud_MSG(id)
{
	if(g_bomb[id] && (g_planted != 1))
	{	
		set_hudmessage(255, 255, 0, 0.02, 0.18, _, _, 2.5)
		ShowSyncHudMsg(id, g_SyncHUD,"%L", LANG_PLAYER, "C4_BOMB_HAVE")
	}
	else remove_task(id)
}

public Hud_MSG2()
{
	if(g_planted != 0)
	{	
		set_hudmessage(255, 255, 0, 0.02, 0.18, _, _, 2.5)
		ShowSyncHudMsg(0, g_SyncHUD,"%L", LANG_PLAYER, "C4_BOMB_TIME", g_time)
	}
	else remove_task()
}

public fw_PlayerPreThink(id)
{
   	if (!is_user_alive(id) || zp_get_user_zombie(id) )
        return;

	if( !g_going[id] && g_bomb[id])
	{
		set_pev( id, pev_maxspeed, 1.0 )
	}
}

public fw_CmdStart(id, handle, random_seed)
{
	// Not alive
	if(!is_user_alive(id))
		return FMRES_IGNORED;
	
	// Isn't a zombie?
	if(zp_get_user_zombie(id) || zp_get_user_nemesis(id))
		return FMRES_IGNORED;

	if ( !g_bomb[id] )
        return FMRES_IGNORED;

	// Ent origin	
	new  aim[3] , Origin[3]
	get_user_origin(id, aim, 3)
	get_user_origin(id, Origin)

	// Get user old and actual buttons
	static iInUseButton, iInUseOldButton
	iInUseButton = (get_uc(handle, UC_Buttons) & IN_USE)
	iInUseOldButton = (get_user_oldbutton(id) & IN_USE)

	// Pressing +use button
	if(iInUseButton && (get_distance(aim, Origin) <= 100) && ((aim[2]+25) < Origin[2]) )
	{
		// Last used button isn't +use, i need to
		// do this, because i call this "only" 1 time
		if(!iInUseOldButton && is_user_alive(id) )
		{
			client_print(id, print_center, "%L", LANG_PLAYER, "C4_BOMB_PLANTE")
			// A bar appears in his screen
			message_begin(MSG_ONE, g_msgBarTime, _, id)
			write_byte(g_time_used) // time
			write_byte(0) // unknown
			message_end()
			g_going[id] = false;
			set_task(5.0, "Create_Entity", id)			
			return FMRES_HANDLED
		}
	}
	else
	{
		// Last used button it's +use
		if(iInUseOldButton || (get_distance(aim, Origin) > 100) )
		{
			
			stop_bartime(id)
			//remove_task(id)
			return FMRES_HANDLED
		}
	}

	return FMRES_IGNORED
}

public Create_Entity(id)
{
	new g_entity = create_entity("info_target")
	entity_set_string(g_entity, EV_SZ_classname, bomb_name)
	ent_id = g_entity
	emit_sound(0, CHAN_STREAM, planted_bomb, 1.0, ATTN_NORM, 0, PITCH_NORM)
	g_bomb[id] = false;
	g_used[id] = true;
	// Ent origin	
	new  aim[3] , Float: Entorigin[3]
	get_user_origin(id, aim, 3)
	g_planted = 1;
	g_time = get_pcvar_num(g_c4_time);

	IVecFVec(aim , Entorigin)
	// Integer to float
	entity_set_vector(g_entity, EV_VEC_origin, Entorigin)
	RegisterHamFromEntity(Ham_Killed, g_entity, "fw_killed")	
	RegisterHamFromEntity(Ham_TakeDamage, g_entity, "fw_takedmg")
	entity_set_model(g_entity, c4_model)
	entity_set_int(g_entity, EV_INT_solid, SOLID_BBOX)
	entity_set_size(g_entity, Float: {-10.0, -10.0, -10.0}, Float:{10.0, 10.0, 10.0})
	entity_set_float(g_entity, EV_FL_takedamage, 1.0)
	entity_set_float(g_entity, EV_FL_health, get_pcvar_float(g_c4_health))
	set_task(1.0, "Hud_MSG2", 0, "", 0, "b")
	set_task(1.0, "CountDown", g_entity)
	set_task(1.0, "AmmoPack", id, _, _, "a",get_pcvar_num(g_c4_time))
	drop_to_floor(g_entity)		

}

public fw_takedmg(victim, inflictor, attacker, Float:damage, damagebits)
{
	new entity;
	entity = ent_id

	if( victim != entity )
	return

	emit_sound(victim, CHAN_STREAM, glass[random_num(0,1)], 1.0, ATTN_NORM, 0, PITCH_NORM)
}

public AmmoPack(id)
{
	if( (g_planted != 0) && (g_time < 1))
	{
		for(new i=1;i<=g_MaxPlayers;i++)
		{
			if(!zp_get_user_zombie(i) && g_bomb[i])
			{
				zp_set_user_ammo_packs(i, zp_get_user_ammo_packs(i) + get_pcvar_num(g_c4_ammo))
			}
			else
			{
				if(!zp_get_user_zombie(i) && (get_pcvar_num(g_c4_ammo2) != 0))
				zp_set_user_ammo_packs(i, zp_get_user_ammo_packs(i) + get_pcvar_num(g_c4_ammo2))
			}
		}
	}
}

public CountDown(entity)
{
	if(g_planted != 0)
	{
		if(g_time > 1)
		{
			g_time = g_time - 1;
			set_task(1.0, "CountDown", entity)
		}
		else
		{
			set_task(1.0, "Explosion_Bomb", entity)
		}
		
	}
	else remove_task()
}

public Explosion_Bomb(entity)
{
	static Float:Dist[32], Float:originF[3], Float:origin[3]
	pev(entity, pev_origin, originF)

	new Float:Dmg_zm[32], Float:Dmg_hum[32];
	for (new victim = 0; victim <= g_MaxPlayers; victim++)
	{
		Dist[victim] = vector_distance(origin,originF)
		pev(victim,pev_origin,origin)
		if ( (vector_distance(origin,originF) <= RADIUS) && is_user_alive(victim) && !is_user_bot(victim) )
		{
			message_begin(MSG_ONE_UNRELIABLE, gmsg_screenshake, _, victim)
			write_short((1<<12)*75) // amplitude
			write_short((1<<12)*7) // duration
			write_short((1<<12)*75) // frequency
			message_end()
			do_screen_fade(victim, 1.2, 0.5, 255, 255, 255, 200);

			if(get_pcvar_num(g_c4_exp) == 0)
			{
				if( (get_pcvar_num(g_c4_kill_type) == 1) && zp_get_user_zombie(victim) )
				{
					user_kill(victim, 0)
				}
				else
				{
					if(get_pcvar_num(g_c4_kill_type) != 1)
					user_kill(victim, 0)
				}
			}
			else
			{
	
				if(zp_get_user_zombie(victim))
				{
					Dmg_zm[victim] = (RADIUS * 1400.0) / Dist[victim] ;
					ExecuteHamB(Ham_TakeDamage, victim, 0, entity, Dmg_zm[victim], DMG_BLAST)
				}
				else		
				{	
					Dmg_hum[victim] = (RADIUS * 120.0) / Dist[victim];
					ExecuteHamB(Ham_TakeDamage, victim, 0, entity, Dmg_hum[victim], DMG_BLAST)
				}
			}
		}
	}
	Explosion(entity)
}

public Explosion(ent)
{
	new entity; entity = ent_id
	static Float:originF[3]
	pev(entity, pev_origin, originF)
	create_blast(originF)
	emit_sound ( 0, CHAN_WEAPON, explosion_bomb, VOL_NORM, ATTN_NORM, 0, PITCH_NORM )
	new NonFloatEndOrigin[3];
	NonFloatEndOrigin[0] = floatround(originF[0]);
	NonFloatEndOrigin[1] = floatround(originF[1]);
	NonFloatEndOrigin[2] = floatround(originF[2]);
	message_begin(MSG_BROADCAST, SVC_TEMPENTITY);
	write_byte(17);
	write_coord(NonFloatEndOrigin[0]);
	write_coord(NonFloatEndOrigin[1]);
	write_coord(NonFloatEndOrigin[2] + 128);
	write_short(explosion);
	write_byte(40);
	write_byte(255);
	message_end();	

	engfunc(EngFunc_MessageBegin, MSG_PAS, SVC_TEMPENTITY, originF, 0)
	write_byte(TE_WORLDDECAL)
	engfunc(EngFunc_WriteCoord, originF[0])
	engfunc(EngFunc_WriteCoord, originF[1])
	engfunc(EngFunc_WriteCoord, originF[2])
	write_byte(decal)
	message_end()
	g_planted = 0;
	remove_entity(entity)
}

public create_blast(const Float:originF[3])
{
	engfunc(EngFunc_MessageBegin, MSG_PVS, SVC_TEMPENTITY, originF, 0)
	write_byte(TE_BEAMCYLINDER) // TE id
	engfunc(EngFunc_WriteCoord, originF[0]) // x
	engfunc(EngFunc_WriteCoord, originF[1]) // y
	engfunc(EngFunc_WriteCoord, originF[2]) // z
	engfunc(EngFunc_WriteCoord, originF[0]) // x axis
	engfunc(EngFunc_WriteCoord, originF[1]) // y axis
	engfunc(EngFunc_WriteCoord, originF[2]+700.0) // z axis
	write_short(m_iTrail) // sprite
	write_byte(0) // startframe
	write_byte(0) // framerate
	write_byte(4) // life
	write_byte(60) // width
	write_byte(0) // noise
	write_byte(255) // red
	write_byte(100) // green
	write_byte(0) // blue
	write_byte(200) // brightness
	write_byte(0) // speed
	message_end()
	
	engfunc(EngFunc_MessageBegin, MSG_PVS, SVC_TEMPENTITY, originF, 0)
	write_byte(TE_BEAMCYLINDER) // TE id
	engfunc(EngFunc_WriteCoord, originF[0]) // x
	engfunc(EngFunc_WriteCoord, originF[1]) // y
	engfunc(EngFunc_WriteCoord, originF[2]) // z
	engfunc(EngFunc_WriteCoord, originF[0]) // x axis
	engfunc(EngFunc_WriteCoord, originF[1]) // y axis
	engfunc(EngFunc_WriteCoord, originF[2]+1200.0) // z axis
	write_short(m_iTrail) // sprite
	write_byte(0) // startframe
	write_byte(0) // framerate
	write_byte(4) // life
	write_byte(60) // width
	write_byte(0) // noise
	write_byte(255) // red
	write_byte(70) // green
	write_byte(0) // blue
	write_byte(200) // brightness
	write_byte(0) // speed
	message_end()
	
	engfunc(EngFunc_MessageBegin, MSG_PVS, SVC_TEMPENTITY, originF, 0)
	write_byte(TE_BEAMCYLINDER) // TE id
	engfunc(EngFunc_WriteCoord, originF[0]) // x
	engfunc(EngFunc_WriteCoord, originF[1]) // y
	engfunc(EngFunc_WriteCoord, originF[2]) // z
	engfunc(EngFunc_WriteCoord, originF[0]) // x axis
	engfunc(EngFunc_WriteCoord, originF[1]) // y axis
	engfunc(EngFunc_WriteCoord, originF[2]+1700.0) // z axis
	write_short(m_iTrail) // sprite
	write_byte(0) // startframe
	write_byte(0) // framerate
	write_byte(6) // life
	write_byte(60) // width
	write_byte(0) // noise
	write_byte(255) // red
	write_byte(0) // green
	write_byte(0) // blue
	write_byte(200) // brightness
	write_byte(0) // speed
	message_end()
}

public client_disconnect(id)
{
	g_bomb[id] = false;
}

public grenade_icon(id) 
{
	remove_grenade_icon(id)
		
	if(is_user_bot(id))
		return
		
	static grenade_color[3]

	if(!g_bomb[id]) // || g_used[id]
	return;

	grenade_color = {255, 149, 0} // Frost	
	// show grenade icons
	message_begin(MSG_ONE,iconstatus,{0,0,0},id)
	write_byte(1) // status (0=hide, 1=show, 2=flash)
	write_string("c4") // sprite name
	write_byte(grenade_color[0]) // red
	write_byte(grenade_color[1]) // green
	write_byte(grenade_color[2]) // blue
	message_end()
	
	return
}

public fw_killed(target, attacker)
{
	new entity;	entity = ent_id

	if( target != entity )
	return

	if( (get_pcvar_num(g_c4_ammo3) != 0) && zp_get_user_zombie(attacker) )
	zp_set_user_ammo_packs(attacker, zp_get_user_ammo_packs(attacker) + get_pcvar_num(g_c4_ammo3))

	Explo_killed(entity)	
	g_planted = 0;
}

Explo_killed(entity)
{
	//new entity; entity = ent_id
	new Float:vOrigin[3];
	pev(entity,pev_origin,vOrigin);
	emit_sound(entity, CHAN_STREAM, explode_bomb, 1.0, ATTN_NORM, 0, PITCH_NORM)
	engfunc(EngFunc_MessageBegin, MSG_PVS, SVC_TEMPENTITY, vOrigin, 0);
	write_byte(TE_EXPLOSION);
	engfunc(EngFunc_WriteCoord,vOrigin[0]);
	engfunc(EngFunc_WriteCoord,vOrigin[1]);
	engfunc(EngFunc_WriteCoord,vOrigin[2]);
	write_short(boom);
	write_byte(30);
	write_byte(15);
	write_byte(0);
	message_end();

	engfunc(EngFunc_MessageBegin, MSG_PAS, SVC_TEMPENTITY, vOrigin, 0)
	write_byte(TE_WORLDDECAL)
	engfunc(EngFunc_WriteCoord, vOrigin[0])
	engfunc(EngFunc_WriteCoord, vOrigin[1])
	engfunc(EngFunc_WriteCoord, vOrigin[2])
	write_byte(decal)
	message_end()
	remove_entity(entity)
}

public remove_grenade_icon(id) 
{
	// remove grenade icons
	message_begin(MSG_ONE,iconstatus,{0,0,0},id)
	write_byte(0) // status (0=hide, 1=show, 2=flash)
	write_string("c4") // sprite name
	message_end()
}

public event_death() 
{
	new id = read_data(2)
	
	if( !is_user_bot(id) )
	{
		remove_grenade_icon(id)
		g_bomb[id] = false
	}
}

stop_bartime(id)
{
	// Remove the task
	if(task_exists(id)) 
	remove_task(id)
	
	// Remove screen's bar
	message_begin(MSG_ONE, g_msgBarTime, _, id)
	write_byte(0) // time
	write_byte(0) // unknown
	message_end()
	g_going[id] = true;
}

stock do_screen_fade(       id, Float:fadeTime, Float:holdTime, red, green, blue, alpha, type = 0x0000       )
{
   static msgScreenFade;
   if (      !msgScreenFade    ) { msgScreenFade = get_user_msgid(    "ScreenFade"           ); }
   new fade, hold;
   fade = clamp(    floatround(     fadeTime * float(1<<12)), 0, 0xFFFF    );
   hold = clamp(     floatround(         holdTime * float(1<<12)), 0, 0xFFFF      );
   message_begin(    MSG_ONE_UNRELIABLE, msgScreenFade, _, id          );
   write_short(          fade    );
   write_short(    hold    );
   write_short(    type   );
   write_byte(      red    );
   write_byte(  green    );
   write_byte(    blue    );
   write_byte(     alpha    );
   message_end(    );
}