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

#define	MAX_ITEMS_MAP 64
#define MAX_SPAWN_ROUND 3

#define write_coord_f(%1)	engfunc(EngFunc_WriteCoord, %1)

new g_total_supplyboxes
new Float:g_spawns[MAX_ITEMS_MAP][3]
new g_total_spawned
new g_spawned[MAX_ITEMS_MAP]
new sprite
new Float:g_delay[33]
new g_entity_box[1025]

new g_mapfile[64]

new const g_model_box[] = "models/zombie_plague/supplybox_zbs.mdl"
new const g_sound_spawn[] = "zombie_plague/supplybox_resp.wav"
new const g_sound_get[] = "zombie_plague/supplybox_dro.wav"

new cvar_time, cvar_max_boxes_round, cvar_updatedelay, cvar_maxdistance, cvar_scale, cvar_z

const KEYSMENU = MENU_KEY_1|MENU_KEY_2|MENU_KEY_3|MENU_KEY_4|MENU_KEY_5|MENU_KEY_6|MENU_KEY_7|MENU_KEY_8|MENU_KEY_9|MENU_KEY_0

public plugin_precache()
{
	register_plugin("[ZP] Podarki", "1.0", "iPhone and 6OTpapa")
	precache_model(g_model_box)
	precache_sound(g_sound_spawn)
	precache_sound(g_sound_get)
	sprite = precache_model("sprites/supl.spr")
}

public plugin_init()
{
	register_event("HLTV", "event_round_start", "a", "1=0", "2=0")
	
	register_forward(FM_Touch, "fw_TouchSupplybox")
	register_forward(FM_PlayerPreThink, "fw_PlayerPreThink")
	
	register_clcmd("say /supplybox_menu", "show_menu_supplybox", ADMIN_CFG, " - display item's menu")
	
	register_menu("Menu Place Supplybox", KEYSMENU, "menu_supplybox")
	
	cvar_time = register_cvar("zp_sb_time", "60.0")
	cvar_max_boxes_round = register_cvar("zp_sb_max_round", "4")
	cvar_updatedelay = register_cvar("zp_sb_update_delay", "0.2")
	cvar_maxdistance = register_cvar("zp_sb_max_distance", "5000")
	cvar_scale = register_cvar("zp_sb_scale", "0.001")
	cvar_z = register_cvar("zp_sb_z", "30.0")
	
}

public plugin_cfg()
{
	new g_map[32]
	get_mapname(g_map, charsmax(g_map))
	formatex(g_mapfile, charsmax(g_mapfile), "addons/amxmodx/configs/supplyboxes/%s.ini", g_map)
	load_spawns()
}

public event_round_start()
{
	g_total_spawned = 0
	static entity; entity = -1
	while ((entity = engfunc(EngFunc_FindEntityByString, entity, "classname", "supplybox")))
	{
		engfunc(EngFunc_RemoveEntity, entity)
		g_spawned[g_entity_box[entity]] = false
	}
}

public spawn_supplybox()
{
        if (!g_total_supplyboxes)
                return
        
        new i[MAX_SPAWN_ROUND + 1]
        static j, q, b
        b = 0
        j = random_num(1, MAX_SPAWN_ROUND)
        for(q = 1; q <= j; q++)
        {
                i[q] = random_num(0, g_total_supplyboxes)
                
                while(g_spawned[i[q]])
                {
                        
                        b++
                        if (b >= 100)
                                return
                                
                        i[q] = random_num(0, g_total_supplyboxes)
                        
                        
                }
                
                static s
                s = 0
                
                if(g_total_spawned == get_pcvar_num(cvar_max_boxes_round))
                {
                        static entity; entity = -1
                        while ((entity = engfunc(EngFunc_FindEntityByString, entity, "classname", "supplybox")) && !s)
                        {
                                engfunc(EngFunc_RemoveEntity, entity)
                                g_spawned[g_entity_box[entity]] = false
                                s = 1
                                g_total_spawned--
                        }
                }
                
                place_box(i[q])
                g_total_spawned++
        }
        for(q = 1; q <= 32; q++)
        {
                if(is_user_connected(q))
                {
                        client_cmd(q, "spk sound/%s", g_sound_spawn)
                        client_print(q, print_center, "Подари Доставлены!!", q)
                }
        }
}

public place_box(supplybox)
{
	static entity; entity = engfunc(EngFunc_CreateNamedEntity, engfunc(EngFunc_AllocString, "info_target"))
	set_pev(entity, pev_classname, "supplybox")
	set_pev(entity, pev_origin, g_spawns[supplybox])

	engfunc(EngFunc_SetModel, entity, g_model_box)

	set_pev(entity, pev_mins, Float:{-10.0,-10.0,0.0})
	set_pev(entity, pev_maxs, Float:{10.0,10.0,25.0})
	set_pev(entity, pev_size, Float:{-10.0,-10.0,0.0,10.0,10.0,25.0})
	engfunc(EngFunc_SetSize, entity, Float:{-10.0,-10.0,0.0}, Float:{10.0,10.0,25.0})

	set_pev(entity, pev_solid, SOLID_TRIGGER)
	set_pev(entity, pev_movetype, MOVETYPE_TOSS)
	g_entity_box[entity] = supplybox
	g_spawned[supplybox] = true
}

public fw_TouchSupplybox(entity, id)
{
	if(!pev_valid(entity))
		return HAM_IGNORED
	
	if(!is_user_alive(id) || zp_get_user_zombie(id) || zp_get_user_survivor(id))
		return HAM_IGNORED
	
	static classname[64]
	pev(entity, pev_classname, classname, charsmax(classname))
	
	if(!equal(classname, "supplybox"))
		return HAM_IGNORED
	
	give_present(id)
	engfunc(EngFunc_RemoveEntity, entity)
	g_spawned[g_entity_box[entity]] = false
	g_total_spawned--
	engfunc(EngFunc_EmitSound, id, CHAN_ITEM, g_sound_get, 1.0, ATTN_NORM, 0, PITCH_NORM)
	static g_name[64]
	get_user_name(id, g_name, charsmax(g_name))
	static i
	for(i = 1; i <= 32; i++)
	{
		if(is_user_connected(i))
		{
			client_print(i, print_center, "%s Подобрал Подарок", g_name, i)
		}
	}

	return HAM_IGNORED
}

public give_present(id) 
{ 
       switch (random_num(0, 3)) 
       { 
       case 0: 
       {
       zp_force_buy_extra_item(id, zp_get_extra_item_id("Бронежилет \r[100 AP]"), 1)
       }
       case 1:
       {	
       zp_force_buy_extra_item(id, zp_get_extra_item_id("[Автомат] \rAk+Knife"), 2)
       }
       case 2:
       {
       zp_force_buy_extra_item(id, zp_get_extra_item_id("[Автомат] \rAklong"), 3)
       }
       case 3:
       {
       zp_force_buy_extra_item(id, zp_get_extra_item_id("[Автомат] \rXm8"), 4)
       }
       case 4:
       {
       zp_force_buy_extra_item(id, zp_get_extra_item_id("[Автомат] \rF2000"), 5)
       }
       case 5:
       {
       zp_force_buy_extra_item(id, zp_get_extra_item_id("[Автомат] \rGuitar"), 6)
       }
       case 6:
       {
       zp_force_buy_extra_item(id, zp_get_extra_item_id("[Автомат] \rWatergun"), 7)
       }
       case 7:
       {
       zp_force_buy_extra_item(id, zp_get_extra_item_id("[Автомат] \rDmp7a1"), 8)
       }
       case 8:
       {
       zp_force_buy_extra_item(id, zp_get_extra_item_id("[Автомат] \rm14"), 9)
       }
       case 9:
       {
       zp_force_buy_extra_item(id, zp_get_extra_item_id("[Автомат] \rCart REd"), 10)
       }
       case 10:
       {
       zp_force_buy_extra_item(id, zp_get_extra_item_id("[Автомат] \rCart Blue"), 11)
       }
       case 11:
       {
       zp_force_buy_extra_item(id, zp_get_extra_item_id("[Винтовка] \rSvd"), 12)
       }
       case 12:
       {
       zp_force_buy_extra_item(id, zp_get_extra_item_id("[Винтовка] \rVsk-94"), 13)
       }
       case 13:
       {
       zp_force_buy_extra_item(id, zp_get_extra_item_id("[Пулемёт] \rMg3"), 14)
       }
    }
}

public fw_PlayerPreThink(id)
{
	if(!is_user_alive(id) || zp_get_user_zombie(id) || zp_get_user_survivor(id)) return
		
	if((g_delay[id] + get_pcvar_float(cvar_updatedelay)) > get_gametime())
		return
	
	g_delay[id] = get_gametime()
	
	static Float:user_origin[3]
	pev(id, pev_origin, user_origin)
	
	static entity; entity = -1
	while ((entity = engfunc(EngFunc_FindEntityByString, entity, "classname", "supplybox")))
	{
		static Float:entity_origin[3]
		pev(entity, pev_origin, entity_origin)
		
		entity_origin[2] += get_pcvar_float(cvar_z)
		
		if((get_distance_f(user_origin, entity_origin) > get_pcvar_num(cvar_maxdistance)) 
		|| !fm_is_in_viewcone(id, entity_origin))
			continue

		static Float:fMiddle[3], Float:fHitPoint[3]
		xs_vec_sub(entity_origin, user_origin, fMiddle)
		fm_trace_line(-1, user_origin, entity_origin, fHitPoint)
								
		static Float:fWallOffset[3], Float:fDistanceToWall
		fDistanceToWall = vector_distance(user_origin, fHitPoint) - 10.0
		normalize(fMiddle, fWallOffset, fDistanceToWall)
		
		static Float:fSpriteOffset[3]
		xs_vec_add(fWallOffset, user_origin, fSpriteOffset)
		
		message_begin(MSG_ONE, SVC_TEMPENTITY, _, id)
		write_byte(TE_SPRITE)
		write_coord_f(fSpriteOffset[0])
		write_coord_f(fSpriteOffset[1])
		write_coord_f(fSpriteOffset[2])
		write_short(sprite)
		write_byte(floatround(fDistanceToWall * get_pcvar_float(cvar_scale)))
		write_byte(125)
		message_end()
	}
}

public show_menu_supplybox(id)
{
	static menu[250]
	formatex(menu, charsmax(menu), "\yМеню Подарков^n^n\y1.\w Добавить Подарок^n\y2.\r Удалить Подарок^n^n\y0.\w Выход")
	show_menu(id, KEYSMENU, menu, -1, "Menu Place Supplybox")
}

public menu_supplybox(id, key)
{
	switch (key)
	{
		case 0:
		{
			if (g_total_supplyboxes >= MAX_ITEMS_MAP)
				client_print(id, print_chat, "Max Item's for Map!")
			else
				add_box(id)
		}
		case 1:
			delete_all_boxes()
	}
	if (key == 0 || key == 1)
		show_menu_supplybox(id)
	return PLUGIN_HANDLED
}

public add_box(id)
{
	static origin[3], Float:g_origin[3]
	get_user_origin(id, origin, 3)
	IVecFVec(origin, g_origin)

	static file, buffer[128]; file = fopen(g_mapfile, "at")
	
	formatex(buffer, charsmax(buffer), "%f %f %f^n", g_origin[0], g_origin[1], g_origin[2])
	fputs(file, buffer)
	
	g_spawns[g_total_supplyboxes][0] = g_origin[0]
	g_spawns[g_total_supplyboxes][1] = g_origin[1]
	g_spawns[g_total_supplyboxes][2] = g_origin[2]
	
	fclose(file)
	
	g_total_supplyboxes++
}

public delete_all_boxes()
{
	g_total_supplyboxes = 0
	static ent;ent = -1
	while ((ent = engfunc(EngFunc_FindEntityByString, ent, "classname", "supplybox")))
	{
		engfunc(EngFunc_RemoveEntity, ent)
		g_spawned[g_entity_box[ent]] = false
		g_total_spawned--
	}
	
	delete_file(g_mapfile)
}

public zp_round_started()
{
	set_task(get_pcvar_float(cvar_time), "spawn_supplybox", _, _, _, "b")
}

public zp_round_ended()
{
	remove_task()
}

stock load_spawns()
{
	g_total_supplyboxes = 0
	if (file_exists(g_mapfile))
	{
		static supdata[3][6], file, linedata[128];file = fopen(g_mapfile,"rt")
		
		while (file && !feof(file))
		{
			fgets(file, linedata, charsmax(linedata))
			
			if(!linedata[0] || str_count(linedata,' ') < 2) continue
			
			parse(linedata,supdata[0],5,supdata[1],5,supdata[2],5)
			
			// origin
			g_spawns[g_total_supplyboxes][0] = floatstr(supdata[0])
			g_spawns[g_total_supplyboxes][1] = floatstr(supdata[1])
			g_spawns[g_total_supplyboxes][2] = floatstr(supdata[2])
			
			place_box(g_total_supplyboxes)
			
			g_total_supplyboxes++
		}
		if (file) fclose(file)
	}
}

stock normalize(Float:fIn[3], Float:fOut[3], Float:fMul)
{
	static Float:fLen;fLen = xs_vec_len(fIn)
	xs_vec_copy(fIn, fOut)
	
	fOut[0] /= fLen, fOut[1] /= fLen, fOut[2] /= fLen
	fOut[0] *= fMul, fOut[1] *= fMul, fOut[2] *= fMul
}

stock str_count(const str[], searchchar)
{
	new count, i, len = strlen(str)
	
	for (i = 0; i <= len; i++)
	{
		if(str[i] == searchchar)
			count++
	}
	
	return count;
}

stock bool:fm_is_in_viewcone(index, const Float:point[3]) {
	new Float:angles[3];
	pev(index, pev_angles, angles);
	engfunc(EngFunc_MakeVectors, angles);
	global_get(glb_v_forward, angles);
	angles[2] = 0.0;

	new Float:origin[3], Float:diff[3], Float:norm[3];
	pev(index, pev_origin, origin);
	xs_vec_sub(point, origin, diff);
	diff[2] = 0.0;
	xs_vec_normalize(diff, norm);

	new Float:dot, Float:fov;
	dot = xs_vec_dot(norm, angles);
	pev(index, pev_fov, fov);
	if (dot >= floatcos(fov * M_PI / 360))
		return true;

	return false;
}

stock fm_trace_line(ignoreent, const Float:start[3], const Float:end[3], Float:ret[3]) {
	engfunc(EngFunc_TraceLine, start, end, ignoreent == -1 ? 1 : 0, ignoreent, 0);

	new ent = get_tr2(0, TR_pHit);
	get_tr2(0, TR_vecEndPos, ret);

	return pev_valid(ent) ? ent : 0;
}
/* AMXX-Studio Notes - DO NOT MODIFY BELOW HERE
*{\\ rtf1\\ ansi\\ deff0{\\ fonttbl{\\ f0\\ fnil Tahoma;}}\n\\ viewkind4\\ uc1\\ pard\\ lang1049\\ f0\\ fs16 \n\\ par }
*/
