#include <amxmodx>
#include <amxmisc>
#include <fakemeta>

#define PLUGIN "NST Create Points"
#define VERSION "1.0"
#define AUTHOR "NST"


new const SPAWNS_URL[] = "%s/zm_ai/sp_%s.cfg"
new const WAYS_URL[] = "%s/zm_ai/wp_%s.cfg"
new const BOXS_URL[] = "%s/zm_ai/box_%s.cfg"
const MAX_BOXS = 128
const MAX_SPAWNS = 128
const MAX_WAYS = 64
const MAX_POINTS = 32
new g_spawns[MAX_SPAWNS][4], g_total_spawns, g_spawn_edit, g_spawns_r[MAX_SPAWNS][4],
g_boxs[MAX_BOXS][3], g_total_boxs, g_box_edit, g_boxs_r[MAX_SPAWNS][3],
g_ways[MAX_WAYS][MAX_POINTS][4], g_total_ways, g_way_edit, g_total_points, g_point_edit, g_ways_r[MAX_WAYS][MAX_POINTS][4]
new cache_spr_line
new const color_spawn_bot[3] = {255,255,255}
new const color_spawn_boss[3] = {255,0,0}
new const color_way_fpoint[3] = {255,255,0}
new const color_way_point[3] = {0,255,0}
new const color_way_way[3] = {0,0,255}
new const color_way_edit[3] = {0,255,255}
new const color_point_edit[3] = {162,17,237}

// Task offsets
enum (+= 100)
{
	TASK_SHOW_SPAWNS = 2000,
	TASK_SHOW_WAYS,
	TASK_SHOW_BOXS

}
// IDs inside tasks
#define ID_SHOW_SPAWNS (taskid - TASK_SHOW_SPAWNS)
#define ID_SHOW_WAYS (taskid - TASK_SHOW_WAYS)
#define ID_SHOW_BOXS (taskid - TASK_SHOW_BOXS)


//######################################################################
// REG PLUGIN
//######################################################################
public plugin_precache()
{
	cache_spr_line = precache_model("sprites/laserbeam.spr")
}
public plugin_init()
{
	register_plugin(PLUGIN, VERSION, AUTHOR)
	
	// Language files
	//register_dictionary("nst_points.txt")
	
	// Cmd
	register_concmd("sp_maker", "menu_main")
	//register_concmd("ww","ww")
}


//######################################################################
// MENU MAIN
//######################################################################
public menu_main(id)
{
	// check is admin
	if (!check_user_admin(id)) return PLUGIN_HANDLED;
	
	// remove task
	if (task_exists(id+TASK_SHOW_SPAWNS)) remove_task(id+TASK_SHOW_SPAWNS)
	if (task_exists(id+TASK_SHOW_BOXS)) remove_task(id+TASK_SHOW_BOXS)
	
	// create main menu
	new title[64], item_name[3][64]
	format(title, charsmax(title), "[NST Points] %L:", LANG_PLAYER, "MENU_MAIN_TITLE")
	format(item_name[0], 63, "%L", LANG_PLAYER, "MENU_MAIN_ITEM_SPAWNS")
	format(item_name[1], 63, "%L", LANG_PLAYER, "MENU_MAIN_ITEM_WAYS")
	format(item_name[2], 63, "%L", LANG_PLAYER, "MENU_MAIN_ITEM_BOXS")

	new mHandleID = menu_create(title, "menu_main_handler")
	menu_additem(mHandleID, item_name[0], "spawn", 0)
	menu_additem(mHandleID, item_name[1], "way", 0)
	menu_additem(mHandleID, item_name[2], "box", 0)
	menu_display(id, mHandleID, 0)	

	return PLUGIN_HANDLED;
}
public menu_main_handler(id, menu, item)
{
	if (item == MENU_EXIT)
	{
		menu_destroy(menu)
		return;
	}
	
	new itemid[32], itemname[32], access
	menu_item_getinfo(menu, item, access, itemid, charsmax(itemid), itemname, charsmax(itemname), access)

	if (equal(itemid, "spawn"))
	{
		// set task show point
		if (task_exists(id+TASK_SHOW_SPAWNS)) remove_task(id+TASK_SHOW_SPAWNS)
		set_task(1.0, "task_show_spawns", id+TASK_SHOW_SPAWNS, _, _, "b")
	
		spawn_main(id)
	}
	else if (equal(itemid, "way"))
	{
		// set task show point
		if (task_exists(id+TASK_SHOW_SPAWNS)) remove_task(id+TASK_SHOW_SPAWNS)
		set_task(1.0, "task_show_spawns", id+TASK_SHOW_SPAWNS, _, _, "b")

		way_main(id)
	}
	else if (equal(itemid, "box"))
	{
		// set task show point
		if (task_exists(id+TASK_SHOW_BOXS)) remove_task(id+TASK_SHOW_BOXS)
		set_task(1.0, "task_show_boxs", id+TASK_SHOW_BOXS, _, _, "b")
	
		box_main(id)
	}

	
	menu_destroy(menu)
}
public task_show_spawns(taskid)
{
	new id = ID_SHOW_SPAWNS
	spawn_show(id)
	
	if (task_exists(id+TASK_SHOW_WAYS)) remove_task(id+TASK_SHOW_WAYS)
	set_task(0.5, "task_show_ways", id+TASK_SHOW_WAYS)
}
public task_show_ways(taskid)
{
	new id = ID_SHOW_WAYS
	way_show(id)
}
public task_show_boxs(taskid)
{
	new id = ID_SHOW_BOXS
	box_show(id)
}


//######################################################################
// SPAWNS POINTS
//######################################################################
// ===================== SPAWN MAIN MENU =====================
public spawn_main(id)
{
	// remove spawns choose
	g_spawn_edit = -1
	
	// create menu
	new title[64], item_name[5][64]
	format(title, charsmax(title), "[NST Points] %L", LANG_PLAYER, "MENU_SPAWNS_TITLE", g_total_spawns, MAX_SPAWNS)
	format(item_name[0], 63, "%L", LANG_PLAYER, "MENU_SPAWNS_ITEM_ADD")
	format(item_name[1], 63, "%L", LANG_PLAYER, "MENU_SPAWNS_ITEM_EDIT")
	format(item_name[2], 63, "%L", LANG_PLAYER, "MENU_SPAWNS_ITEM_SAVE")
	format(item_name[3], 63, "%L", LANG_PLAYER, "MENU_SPAWNS_ITEM_LOAD")
	format(item_name[4], 63, "%L", LANG_PLAYER, "MENU_SPAWNS_ITEM_DEL")

	new mHandleID = menu_create(title, "spawn_main_handler")
	menu_additem(mHandleID, item_name[0], "add", 0)
	menu_additem(mHandleID, item_name[1], "edit", 0)
	menu_additem(mHandleID, item_name[2], "save", 0)
	menu_additem(mHandleID, item_name[3], "load", 0)
	menu_additem(mHandleID, item_name[4], "del", 0)
	menu_display(id, mHandleID, 0)
}
public spawn_main_handler(id, menu, item)
{
	if (item == MENU_EXIT)
	{
		// destroy menu
		menu_destroy(menu)
		// show menu main
		menu_main(id)
		return;
	}
	
	new itemid[32], itemname[32], access
	menu_item_getinfo(menu, item, access, itemid, charsmax(itemid), itemname, charsmax(itemname), access)
	menu_destroy(menu)
	
	if (equal(itemid, "add"))
	{
		spawn_create(id)
		return;
	}
	else if (equal(itemid, "edit"))
	{
		// set first value for g_spawn_edit
		g_spawn_edit = 0
		spawn_edit(id)
		return;
	}
	else if (equal(itemid, "save")) spawn_save()
	else if (equal(itemid, "load")) spawn_load()
	else if (equal(itemid, "del")) spawn_del(1)
	
	// show main menu
	spawn_main(id)
}

// ===================== spawn create =====================
public spawn_create(id)
{
	// remove spawns choose
	g_spawn_edit = -1
	
	// create menu
	new title[64], item_name[3][64]
	format(title, charsmax(title), "[NST Points] %L", LANG_PLAYER, "MENU_SPAWNS_ADD_TITLE", g_total_spawns, MAX_SPAWNS)
	format(item_name[0], 63, "%L", LANG_PLAYER, "MENU_SPAWNS_ADD_ITEM_ADD")
	format(item_name[1], 63, "%L", LANG_PLAYER, "MENU_SPAWNS_ADD_ITEM_ADD_BOSS")
	format(item_name[2], 63, "%L", LANG_PLAYER, "MENU_SPAWNS_ADD_ITEM_DEL")

	new mHandleID = menu_create(title, "spawn_create_handler")
	menu_additem(mHandleID, item_name[0], "add", 0)
	menu_additem(mHandleID, item_name[1], "add_boss", 0)
	menu_additem(mHandleID, item_name[2], "del", 0)
	menu_display(id, mHandleID, 0)
}
public spawn_create_handler(id, menu, item)
{
	if (item == MENU_EXIT)
	{
		// destroy menu
		menu_destroy(menu)
		// show menu main
		spawn_main(id)
		return;
	}
	
	new itemid[32], itemname[32], access
	menu_item_getinfo(menu, item, access, itemid, charsmax(itemid), itemname, charsmax(itemname), access)
	menu_destroy(menu)

	if (equali(itemid, "add")) spawn_create_add(id)
	else if (equali(itemid, "add_boss")) spawn_create_add(id, 1)
	else if (equali(itemid, "del")) spawn_del()

	// return menu create spawns
	spawn_create(id)
	
	return;
}
spawn_create_add(id, boss=0)
{
	// check max points
	if (g_total_spawns>=MAX_SPAWNS)
	{
		new message[128]
		format(message, charsmax(message), ">x04[NST Points] >x01%L", LANG_PLAYER, "NOTICE_MAX_SPAWNS", MAX_SPAWNS)
		color_saytext(id, message)
		return;
	}
	
	// add current points
	new Float:originF[3], origin[3]
	pev(id, pev_origin, originF)
	origin[0] = floatround(originF[0])
	origin[1] = floatround(originF[1])
	origin[2] = floatround(originF[2])
	
	if (!is_point(origin) || !spawn_check_dist(originF))
	{
		new message[128]
		format(message, charsmax(message), ">x04[NST Points] >x01%L", LANG_PLAYER, "NOTICE_SPAWNS_DIST")
		color_saytext(id, message)
		return;
	}
	
	g_spawns[g_total_spawns][0] = origin[0]
	g_spawns[g_total_spawns][1] = origin[1]
	g_spawns[g_total_spawns][2] = origin[2]
	g_spawns[g_total_spawns][3] = boss
	g_total_spawns ++
}

// ===================== spawn edit =====================
public spawn_edit(id)
{
	// check total
	if (!g_total_spawns)
	{
		new message[128]
		format(message, charsmax(message), ">x04[NST Points] >x01%L", LANG_PLAYER, "NOTICE_SPAWNS_NOTVALUE")
		color_saytext(id, message)
		spawn_main(id)
		return;
	}
	
	// create menu
	new title[64], item_name[4][64]
	format(title, charsmax(title), "[NST Points] %L", LANG_PLAYER, "MENU_SPAWNS_EDIT_TITLE")
	format(item_name[0], 63, "%L", LANG_PLAYER, "MENU_SPAWNS_EDIT_ITEM_BACK")
	format(item_name[1], 63, "%L", LANG_PLAYER, "MENU_SPAWNS_EDIT_ITEM_NEXT")
	format(item_name[2], 63, "%L", LANG_PLAYER, "MENU_SPAWNS_EDIT_ITEM_EDIT")
	format(item_name[3], 63, "%L", LANG_PLAYER, "MENU_SPAWNS_EDIT_ITEM_DEL")

	new mHandleID = menu_create(title, "spawn_edit_handler")
	menu_additem(mHandleID, item_name[0], "back", 0)
	menu_additem(mHandleID, item_name[1], "next", 0)
	menu_additem(mHandleID, item_name[2], "edit", 0)
	menu_additem(mHandleID, item_name[3], "del", 0)
	menu_display(id, mHandleID, 0)
}
public spawn_edit_handler(id, menu, item)
{
	if (item == MENU_EXIT)
	{
		// destroy menu
		menu_destroy(menu)
		// show menu main
		spawn_main(id)
		return;
	}
	
	new itemid[32], itemname[32], access
	menu_item_getinfo(menu, item, access, itemid, charsmax(itemid), itemname, charsmax(itemname), access)
	
	if (equal(itemid, "back")) spawn_edit_back()
	else if (equal(itemid, "next")) spawn_edit_next()
	else if (equal(itemid, "edit")) spawn_edit_edit(id, g_spawn_edit)
	else if (equal(itemid, "del")) spawn_edit_del(g_spawn_edit)
	
	menu_destroy(menu)
	
	// return menu
	spawn_edit(id)
}
spawn_edit_back()
{
	if (g_spawn_edit<=0) g_spawn_edit = g_total_spawns-1
	else g_spawn_edit --
}
spawn_edit_next()
{
	if (g_spawn_edit<0 || g_spawn_edit>=g_total_spawns-1) g_spawn_edit = 0
	else g_spawn_edit ++
}
spawn_edit_edit(id, point)
{
	// check value
	if (point<0 || point>=g_total_spawns) return;

	// get points
	new Float:originF[3], origin[3]
	pev(id, pev_origin, originF)
	origin[0] = floatround(originF[0])
	origin[1] = floatround(originF[1])
	origin[2] = floatround(originF[2])
	
	// check point
	if (!is_point(origin) || !spawn_check_dist(originF, point))
	{
		new message[128]
		format(message, charsmax(message), ">x04[NST Points] >x01%L", LANG_PLAYER, "NOTICE_SPAWNS_DIST")
		color_saytext(0, message)
		return;
	}
	
	// update
	g_spawns[point][0] = origin[0]
	g_spawns[point][1] = origin[1]
	g_spawns[point][2] = origin[2]
}
spawn_edit_del(spawn)
{
	// check value
	if (spawn<0 || spawn>=g_total_spawns) return;
	
	// del spawn point
	new spawn_r[4]
	g_spawns[spawn] = spawn_r
	
	// create g_spawns_r
	reset_spawn(1)
	new total_s, point[3]
	for (new i=0; i<g_total_spawns; i++)
	{
		point[0] = g_spawns[i][0]
		point[1] = g_spawns[i][1]
		point[2] = g_spawns[i][2]
		if (is_point(point))
		{
			g_spawns_r[total_s][0] = point[0]
			g_spawns_r[total_s][1] = point[1]
			g_spawns_r[total_s][2] = point[2]
			g_spawns_r[total_s][3] = g_spawns[i][3]
			total_s ++
		}
	}
	
	// update g_spawns
	spawn_del(1)
	for (new s=0; s<total_s; s++)
	{
		g_spawns[s][0] = g_spawns_r[s][0]
		g_spawns[s][1] = g_spawns_r[s][1]
		g_spawns[s][2] = g_spawns_r[s][2]
		g_spawns[s][3] = g_spawns_r[s][3]
	}
	g_total_spawns = total_s
	if (spawn) g_spawn_edit = spawn-1
}

// ===================== spawn save =====================
spawn_save()
{
	// check total
	if (!g_total_spawns)
	{
		new message[128]
		format(message, charsmax(message), ">x04[NST Points] >x01%L", LANG_PLAYER, "NOTICE_SPAWNS_NOTVALUE")
		color_saytext(0, message)
		return;
	}

	// get url file
	new cfgdir[32], mapname[32], urlfile[64]
	get_configsdir(cfgdir, charsmax(cfgdir))
	get_mapname(mapname, charsmax(mapname))
	formatex(urlfile, charsmax(urlfile), SPAWNS_URL, cfgdir, mapname)

	// save file
	if (file_exists(urlfile)) delete_file(urlfile)
	new lineset[128]
	for (new i=0; i<g_total_spawns; i++)
	{
		if (!g_spawns[i][0] && !g_spawns[i][1] && !g_spawns[i][2]) break;
		
		format(lineset, charsmax(lineset), "%i %i %i %i", g_spawns[i][3], g_spawns[i][0], g_spawns[i][1], g_spawns[i][2])
		write_file(urlfile, lineset, i)
	}
	
	// show notice
	new message[128]
	format(message, charsmax(message), ">x04[NST Points] >x01%L", LANG_PLAYER, "NOTICE_SAVESPAWN_COMPLETE")
	color_saytext(0, message)
}

// ===================== spawn load =====================
spawn_load()
{
	// Check for spawns points of the current map
	new cfgdir[32], mapname[32], filepath[100], linedata[64], point[3]
	get_configsdir(cfgdir, charsmax(cfgdir))
	get_mapname(mapname, charsmax(mapname))
	formatex(filepath, charsmax(filepath), SPAWNS_URL, cfgdir, mapname)
	
	// check file exit
	if (!file_exists(filepath))
	{
		new message[128]
		format(message, charsmax(message), ">x04[NST Points] >x01%L", LANG_PLAYER, "NOTICE_FILE_EXIT", filepath)
		color_saytext(0, message)
		return;
	}
	
	// first reset value
	reset_spawn()
	
	// Load spawns points
	new file = fopen(filepath,"rt"), row[4][6]
	while (file && !feof(file))
	{
		fgets(file, linedata, charsmax(linedata))
		
		// invalid spawn
		if(!linedata[0] || str_count(linedata,' ') < 2) continue;
		
		// get spawn point data
		parse(linedata,row[0],5,row[1],5,row[2],5,row[3],5)
		
		// set spawnst
		point[0] = str_to_num(row[1])
		point[1] = str_to_num(row[2])
		point[2] = str_to_num(row[3])
		if (is_point(point))
		{
			g_spawns[g_total_spawns][0] = point[0]
			g_spawns[g_total_spawns][1] = point[1]
			g_spawns[g_total_spawns][2] = point[2]
			g_spawns[g_total_spawns][3] = str_to_num(row[0])
	
			// increase spawn count
			g_total_spawns ++
			if (g_total_spawns>=MAX_SPAWNS) break;
		}
	}
	if (file) fclose(file)
	
	// notice
	if (g_total_spawns)
	{
		new message[128]
		format(message, charsmax(message), ">x04[NST Points] >x01%L", LANG_PLAYER, "NOTICE_LOADSPAWN_COMPLETE", g_total_spawns)
		color_saytext(0, message)
	}
}

// ===================== spawn del all =====================
spawn_del(all=0)
{
	// check total
	if (!g_total_spawns)
	{
		new message[128]
		format(message, charsmax(message), ">x04[NST Points] >x01%L", LANG_PLAYER, "NOTICE_SPAWNS_NOTVALUE")
		color_saytext(0, message)
		return;
	}
	
	// del all
	if (all)
	{
		reset_spawn()
	}
	// del newest points
	else
	{
		static reset[4]
		g_total_spawns --
		g_spawns[g_total_spawns] = reset
	}
}

// ===================== other function =====================
spawn_show(id)
{
	if (!g_total_spawns) return;
	
	new color[3], start[3], end[3]
	for (new i=0; i<g_total_spawns; i++)
	{
		if (i==g_spawn_edit) color = color_point_edit
		else if (g_spawns[i][3]) color = color_spawn_boss
		else color = color_spawn_bot
		start[0] = g_spawns[i][0]
		start[1] = g_spawns[i][1]
		start[2] = g_spawns[i][2]
		if (!is_point(start)) return;
		end = start
		start[2] -= 36
		end[2] += 36

		create_line_point(id, start, end, color)
	}
}
spawn_check_dist(Float:origin[3], point=-1)
{
	new Float:originE[3], Float:origin1[3], Float:origin2[3]
	
	for (new i=0; i<g_total_spawns; i++)
	{
		if (i==point) continue;
		
		originE[0] = float(g_spawns[i][0])
		originE[1] = float(g_spawns[i][1])
		originE[2] = float(g_spawns[i][2])
		
		// xoy
		origin1 = origin
		origin2 = originE
		origin1[2] = origin2[2] = 0.0
		if (vector_distance(origin1, origin2)<=2*16.0)
		{
			// oz
			origin1 = origin
			origin2 = originE
			origin1[0] = origin2[0] = origin1[1] = origin2[1] = 0.0
			if (vector_distance(origin1, origin2)<=100.0) return 0;
		}
	}

	return 1;
}



//######################################################################
// WAYS POINTS
//######################################################################
// ===================== way main menu =====================
public way_main(id)
{
	// remove way choose
	g_spawn_edit = g_way_edit = g_point_edit = -1
	
	// create menu
	new title[64], item_name[5][64]
	format(title, charsmax(title), "[NST Points] %L", LANG_PLAYER, "MENU_WAYS_TITLE", g_total_ways, MAX_WAYS)
	format(item_name[0], 63, "%L", LANG_PLAYER, "MENU_WAYS_ITEM_ADD")
	format(item_name[1], 63, "%L", LANG_PLAYER, "MENU_WAYS_ITEM_EDIT")
	format(item_name[2], 63, "%L", LANG_PLAYER, "MENU_WAYS_ITEM_SAVE")
	format(item_name[3], 63, "%L", LANG_PLAYER, "MENU_WAYS_ITEM_LOAD")
	format(item_name[4], 63, "%L", LANG_PLAYER, "MENU_WAYS_ITEM_DEL")

	new mHandleID = menu_create(title, "way_main_handler")
	menu_additem(mHandleID, item_name[0], "add", 0)
	menu_additem(mHandleID, item_name[1], "edit", 0)
	menu_additem(mHandleID, item_name[2], "save", 0)
	menu_additem(mHandleID, item_name[3], "load", 0)
	menu_additem(mHandleID, item_name[4], "del", 0)
	menu_display(id, mHandleID, 0)
}
public way_main_handler(id, menu, item)
{
	if (item == MENU_EXIT)
	{
		// destroy menu
		menu_destroy(menu)
		// show menu main
		menu_main(id)
		return;
	}
	
	new itemid[32], itemname[32], access
	menu_item_getinfo(menu, item, access, itemid, charsmax(itemid), itemname, charsmax(itemname), access)
	menu_destroy(menu)
	
	if (equal(itemid, "add"))
	{
		// check max way
		if (g_total_ways>=MAX_WAYS)
		{
			new message[128]
			format(message, charsmax(message), ">x04[NST Points] >x01%L", LANG_PLAYER, "NOTICE_MAX_WAYS", MAX_WAYS)
			color_saytext(id, message)
			return;
		}
		g_total_points = 0
		reset_way(g_total_ways)
		way_create(id)
		return;
	}
	else if (equal(itemid, "edit"))
	{
		// set first value for g_way_edit
		g_way_edit = 0
		way_edit(id)
		return;
	}
	else if (equal(itemid, "save")) way_save()
	else if (equal(itemid, "load")) way_load()
	else if (equal(itemid, "del")) way_del(1)
	
	// show main menu
	way_main(id)
}

// ===================== way create =====================
public way_create(id)
{
	new title[64], item_name[10][64]
	format(title, charsmax(title), "[NST Points] %L", LANG_PLAYER, "MENU_WAYS_ADD_TITLE", g_total_points, MAX_POINTS)
	format(item_name[0], 64, "%L", LANG_PLAYER, "MENU_WAYS_ADD_ITEM_ADD")
	format(item_name[1], 64, "%L", LANG_PLAYER, "MENU_WAYS_ADD_ITEM_DEL")
	format(item_name[2], 64, "%L", LANG_PLAYER, "MENU_WAYS_ADD_ITEM_DEL_ALL")
	format(item_name[3], 64, "%L", LANG_PLAYER, "MENU_WAYS_ADD_ITEM_SAVE")

	new mHandleID = menu_create(title, "way_create_handler")
	menu_additem(mHandleID, item_name[0], "add", 0)
	menu_additem(mHandleID, item_name[1], "del", 0)
	menu_additem(mHandleID, item_name[2], "del_all", 0)
	menu_additem(mHandleID, item_name[3], "save", 0)
	menu_display(id, mHandleID, 0)
}
public way_create_handler(id, menu, item)
{
	if (item == MENU_EXIT)
	{
		// destroy menu
		menu_destroy(menu)
		// show menu main
		way_main(id)
		return;
	}
	
	new itemid[32], itemname[32], access
	menu_item_getinfo(menu, item, access, itemid, charsmax(itemid), itemname, charsmax(itemname), access)
	menu_destroy(menu)
	
	if (equal(itemid, "add")) way_create_add(id)
	else if (equal(itemid, "del")) way_create_del()
	else if (equal(itemid, "del_all")) way_create_del(1)
	else if (equal(itemid, "save"))
	{
		way_create_save(id)
		return;
	}
	
	// show menu way create 
	way_create(id)
}
way_create_add(id)
{
	// check max points
	if (g_total_points>=MAX_POINTS)
	{
		new message[128]
		format(message, charsmax(message), ">x04[NST Points] >x01%L", LANG_PLAYER, "NOTICE_MAX_POINTS", MAX_POINTS)
		color_saytext(id, message)
		return;
	}
	
	// add new points into current way
	new Float:originF[3], origin[3]
	pev(id, pev_origin, originF)
	origin[0] = floatround(originF[0])
	origin[1] = floatround(originF[1])
	origin[2] = floatround(originF[2])
	if (!is_point(origin)) return;
	
	g_ways[g_total_ways][g_total_points][0] = origin[0]
	g_ways[g_total_ways][g_total_points][1] = origin[1]
	g_ways[g_total_ways][g_total_points][2] = origin[2]
	g_ways[g_total_ways][g_total_points][3] = 1
	
	// update total point
	g_total_points ++
}
way_create_del(all=0)
{
	// del all points of current way
	if (all)
	{
		g_total_points = 0
		reset_way(g_total_ways)
	}
	// del newest point
	else if (g_total_points)
	{
		g_total_points --
		reset_point(g_total_ways, g_total_points)
	}
}
way_create_save(id)
{
	if (g_total_points)
	{
		g_total_points = 0
		g_total_ways ++
	}
	way_main(id)
}

// ===================== way edit =====================
public way_edit(id)
{
	// check total
	if (!g_total_ways)
	{
		new message[128]
		format(message, charsmax(message), ">x04[NST Points] >x01%L", LANG_PLAYER, "NOTICE_WAYS_NOTVALUE")
		color_saytext(id, message)
		way_main(id)
		return;
	}
	
	// set first value for g_way_edit
	g_point_edit = -1

	// create menu
	new title[64], item_name[4][64]
	format(title, charsmax(title), "[NST Points] %L", LANG_PLAYER, "MENU_WAYS_EDIT_TITLE", g_total_ways, MAX_WAYS)
	format(item_name[0], 63, "%L", LANG_PLAYER, "MENU_WAYS_EDIT_ITEM_BACK")
	format(item_name[1], 63, "%L", LANG_PLAYER, "MENU_WAYS_EDIT_ITEM_NEXT")
	format(item_name[2], 63, "%L", LANG_PLAYER, "MENU_WAYS_EDIT_ITEM_EDIT")
	format(item_name[3], 63, "%L", LANG_PLAYER, "MENU_WAYS_EDIT_ITEM_DEL")

	new mHandleID = menu_create(title, "way_edit_handler")
	menu_additem(mHandleID, item_name[0], "back", 0)
	menu_additem(mHandleID, item_name[1], "next", 0)
	menu_additem(mHandleID, item_name[2], "edit", 0)
	menu_additem(mHandleID, item_name[3], "del", 0)
	menu_display(id, mHandleID, 0)
}
public way_edit_handler(id, menu, item)
{
	if (item == MENU_EXIT)
	{
		// destroy menu
		menu_destroy(menu)
		// show menu main
		way_main(id)
		return;
	}
	
	new itemid[32], itemname[32], access
	menu_item_getinfo(menu, item, access, itemid, charsmax(itemid), itemname, charsmax(itemname), access)
	menu_destroy(menu)
	
	if (equal(itemid, "back")) way_edit_back()
	else if (equal(itemid, "next")) way_edit_next()
	else if (equal(itemid, "edit"))
	{
		// set first value for g_way_edit
		g_point_edit = 0
		way_edit_edit(id)
		return;
	}
	else if (equal(itemid, "del")) way_edit_del(g_way_edit)
	
	// return menu
	way_edit(id)
}
way_edit_back()
{
	if (g_way_edit<=0) g_way_edit = g_total_ways-1
	else g_way_edit --
}
way_edit_next()
{
	if (g_way_edit<0 || g_way_edit>=g_total_ways-1) g_way_edit = 0
	else g_way_edit ++
}
way_edit_edit(id)
{
	point_edit(id)
}
way_edit_del(way)
{
	// check value
	if (way<0 || way>=g_total_ways) return;
	
	// del current way
	reset_way(way)
	
	// create g_ways_r
	reset_all_way(1)
	new total_w, total_p, point[3]
	for (new w=0; w<g_total_ways; w++)
	{
		if (!g_ways[w][0][3]) continue;
		
		for (new p=0; p<MAX_POINTS; p++)
		{
			point[0] = g_ways[w][p][0]
			point[1] = g_ways[w][p][1]
			point[2] = g_ways[w][p][2]
			if (!g_ways[w][p][3] || !is_point(point)) break;

			g_ways_r[total_w][total_p][0] = point[0]
			g_ways_r[total_w][total_p][1] = point[1]
			g_ways_r[total_w][total_p][2] = point[2]
			g_ways_r[total_w][total_p][3] = 1
			total_p ++
		}
		total_w ++
		total_p = 0
	}

	// update g_ways
	reset_all_way()
	g_ways = g_ways_r
	g_total_ways = total_w
	if (way) g_way_edit = way-1
}

// ===================== point edit =====================
public point_edit(id)
{
	// create menu
	new title[64], item_name[5][64]
	format(title, charsmax(title), "[NST Points] %L", LANG_PLAYER, "MENU_POINTS_EDIT_TITLE", g_total_points, MAX_POINTS)
	format(item_name[0], 63, "%L", LANG_PLAYER, "MENU_POINTS_EDIT_ITEM_BACK")
	format(item_name[1], 63, "%L", LANG_PLAYER, "MENU_POINTS_EDIT_ITEM_NEXT")
	format(item_name[2], 63, "%L", LANG_PLAYER, "MENU_POINTS_EDIT_ITEM_EDIT")
	format(item_name[3], 63, "%L", LANG_PLAYER, "MENU_POINTS_EDIT_ITEM_DEL")
	format(item_name[4], 63, "%L", LANG_PLAYER, "MENU_POINTS_EDIT_ITEM_INSERT")

	new mHandleID = menu_create(title, "point_edit_handler")
	menu_additem(mHandleID, item_name[0], "back", 0)
	menu_additem(mHandleID, item_name[1], "next", 0)
	menu_additem(mHandleID, item_name[2], "edit", 0)
	menu_additem(mHandleID, item_name[3], "del", 0)
	menu_additem(mHandleID, item_name[4], "insert", 0)
	
	menu_display(id, mHandleID, 0)
}
public point_edit_handler(id, menu, item)
{
	if (item == MENU_EXIT)
	{
		// destroy menu
		menu_destroy(menu)
		// show menu main
		way_edit(id)
		return;
	}
	
	new itemid[32], itemname[32], access
	menu_item_getinfo(menu, item, access, itemid, charsmax(itemid), itemname, charsmax(itemname), access)
	menu_destroy(menu)
	
	if (equal(itemid, "back")) point_edit_back()
	else if (equal(itemid, "next")) point_edit_next()
	else if (equal(itemid, "edit")) point_edit_edit(id, g_way_edit, g_point_edit)
	else if (equal(itemid, "del")) point_edit_del(g_way_edit, g_point_edit)
	else if (equal(itemid, "insert")) point_edit_insert(id, g_way_edit, g_point_edit)
	
	// return menu
	point_edit(id)
}
point_edit_back()
{
	if (g_point_edit<=0) g_point_edit = get_total_point_of_way(g_way_edit)-1
	else g_point_edit --
}
point_edit_next()
{
	if (g_point_edit<0 || g_point_edit>=get_total_point_of_way(g_way_edit)-1) g_point_edit = 0
	else g_point_edit ++
}
point_edit_edit(id, way, point)
{
	// check value
	if (point<0 || point>=get_total_point_of_way(way)) return;

	// get points
	new Float:originF[3], origin[3]
	pev(id, pev_origin, originF)
	origin[0] = floatround(originF[0])
	origin[1] = floatround(originF[1])
	origin[2] = floatround(originF[2])
	
	// check point
	if (!is_point(origin)) return;
	
	// update
	g_ways[way][point][0] = origin[0]
	g_ways[way][point][1] = origin[1]
	g_ways[way][point][2] = origin[2]
	g_ways[way][point][3] = 1
}
point_edit_del(way, point)
{
	// check value
	if (point<0 || point>=get_total_point_of_way(way)) return;
	
	// del ways
	reset_point(way, point)
	
	// create g_ways_n
	new g_ways_n[MAX_POINTS][4], points[3], total
	for (new p=0; p<MAX_POINTS; p++)
	{
		points[0] = g_ways[way][p][0]
		points[1] = g_ways[way][p][1]
		points[2] = g_ways[way][p][2]
		if (!g_ways[way][p][3] || !is_point(points)) continue;

		g_ways_n[total][0] = points[0]
		g_ways_n[total][1] = points[1]
		g_ways_n[total][2] = points[2]
		g_ways_n[total][3] = g_ways[way][p][3]
		total++
	}
	
	// update g_ways
	for (new p=0; p<total; p++)
	{
		g_ways[way][p][0] = g_ways_n[p][0]
		g_ways[way][p][1] = g_ways_n[p][1]
		g_ways[way][p][2] = g_ways_n[p][2]
		g_ways[way][p][3] = g_ways_n[p][3]
	}
	if (point) g_point_edit = point-1
}
point_edit_insert(id, way, point)
{
	// check value
	if (point<0 || point>=get_total_point_of_way(way) || point+1>=MAX_POINTS) return;
	
	// create g_ways_n
	new g_ways_n[MAX_POINTS][4], points[3], p_
	for (new p=0; p<MAX_POINTS; p++)
	{
		points[0] = g_ways[way][p][0]
		points[1] = g_ways[way][p][1]
		points[2] = g_ways[way][p][2]
		if (!g_ways[way][p][3] || !is_point(points)) break;
		
		if (p<=point) p_ = p
		else p_ = p+1

		g_ways_n[p_][0] = points[0]
		g_ways_n[p_][1] = points[1]
		g_ways_n[p_][2] = points[2]
		g_ways_n[p_][3] = g_ways[way][p][3]
	}
	
	// insert points
	new Float:originF[3], origin[3]
	pev(id, pev_origin, originF)
	origin[0] = floatround(originF[0])
	origin[1] = floatround(originF[1])
	origin[2] = floatround(originF[2])
	if (!is_point(origin)) return;
	g_ways_n[point+1][0] = origin[0]
	g_ways_n[point+1][1] = origin[1]
	g_ways_n[point+1][2] = origin[2]
	g_ways_n[point+1][3] = 1
	
	// update g_ways
	for (new p=0; p<MAX_POINTS; p++)
	{
		if (!g_ways_n[p][3]) break;
		
		g_ways[way][p][0] = g_ways_n[p][0]
		g_ways[way][p][1] = g_ways_n[p][1]
		g_ways[way][p][2] = g_ways_n[p][2]
		g_ways[way][p][3] = g_ways_n[p][3]
	}
}

// ===================== way save =====================
way_save()
{
	if (!g_total_ways)
	{
		new message[128]
		format(message, charsmax(message), ">x04[NST Points] >x01%L", LANG_PLAYER, "NOTICE_WAYS_NOTVALUE")
		color_saytext(0, message)
		return;
	}
	
	// get url file
	new cfgdir[32], mapname[32], urlfile[64]
	get_configsdir(cfgdir, charsmax(cfgdir))
	get_mapname(mapname, charsmax(mapname))
	formatex(urlfile, charsmax(urlfile), WAYS_URL, cfgdir, mapname)

	// save file
	if (file_exists(urlfile)) delete_file(urlfile)
	new lineset[1024]
	for (new w=0; w<g_total_ways; w++)
	{	
		for (new p=0; p<MAX_POINTS; p++)
		{
			if (!g_ways[w][p][3] || (!g_ways[w][p][0] && !g_ways[w][p][1] && !g_ways[w][p][2])) break;
			
			if (!p) format(lineset, charsmax(lineset), "%i %i %i", g_ways[w][p][0], g_ways[w][p][1], g_ways[w][p][2])
			else format(lineset, charsmax(lineset), "%s,%i %i %i", lineset, g_ways[w][p][0], g_ways[w][p][1], g_ways[w][p][2])
		}
		write_file(urlfile, lineset, w)
	}
	
	// show notice
	new message[128]
	format(message, charsmax(message), ">x04[NST Points] >x01%L", LANG_PLAYER, "NOTICE_SAVEWAY_COMPLETE")
	color_saytext(0, message)
}

// ===================== way load =====================
way_load()
{
	// Check for way points of the current map
	new cfgdir[32], mapname[32], filepath[100], linedata[1024], key[32], originL[3][6], point[3]
	get_configsdir(cfgdir, charsmax(cfgdir))
	get_mapname(mapname, charsmax(mapname))
	formatex(filepath, charsmax(filepath), WAYS_URL, cfgdir, mapname)
	
	// check file exit
	if (!file_exists(filepath))
	{
		new message[128]
		format(message, charsmax(message), ">x04[NST Points] >x01%L", LANG_PLAYER, "NOTICE_FILE_EXIT", filepath)
		color_saytext(0, message)
		return;
	}

	// first reset value
	reset_all_way()
	g_total_ways = 0
	
	// load way points
	new file = fopen(filepath,"rt")
	while (file && !feof(file))
	{
		fgets(file, linedata, charsmax(linedata))
		
		// invalid way
		if(!linedata[0]) continue;

		// get way points data
		new totalpoints
		while (linedata[0] != 0 && strtok(linedata, key, charsmax(key), linedata, charsmax(linedata), ','))
		{
			// get point data
			parse(key,originL[0],5,originL[1],5,originL[2],5)
			
			point[0] = str_to_num(originL[0])
			point[1] = str_to_num(originL[1])
			point[2] = str_to_num(originL[2])
			if (!is_point(point)) continue;
			
			g_ways[g_total_ways][totalpoints][0] = point[0]
			g_ways[g_total_ways][totalpoints][1] = point[1]
			g_ways[g_total_ways][totalpoints][2] = point[2]
			g_ways[g_total_ways][totalpoints][3] = 1
			
			// increase point count
			totalpoints ++
			if (totalpoints>=MAX_POINTS) break;
		}
		
		// increase way points count
		g_total_ways ++
		if (g_total_ways>=MAX_WAYS) break;
	}
	if (file) fclose(file)
	
	// notice
	if (g_total_ways)
	{
		new message[128]
		format(message, charsmax(message), ">x04[NST Points] >x01%L", LANG_PLAYER, "NOTICE_LOADWAY_COMPLETE", g_total_ways)
		color_saytext(0, message)
	}
}

// ===================== way load =====================
way_del(all=0)
{
	// del all ways
	if (all) reset_all_way()

	// del newest way
	else if (g_total_ways)
	{
		g_total_ways --
		reset_way(g_total_ways)
	}
}

// ===================== way show =====================
way_show(id)
{
	new color_w[3], color_p[3], start[3], end[3], totalway
	
	totalway = g_total_ways
	if (g_ways[g_total_ways][0][3]) totalway++
	totalway = min(totalway, MAX_WAYS)
	if (!totalway) return;

	for (new w=0; w<totalway; w++)
	{	
		if (w==g_way_edit) color_w = color_way_edit
		else color_w = color_way_way
		
		for (new p=0; p<MAX_POINTS; p++)
		{
			// check value of point
			if (!g_ways[w][p][3]) break;
			
			// show current point
			start[0] = g_ways[w][p][0]
			start[1] = g_ways[w][p][1]
			start[2] = g_ways[w][p][2]
			if (!is_point(start)) break;
			
			end = start
			start[2] -= 36
			end[2] += 36
			
			if (w==g_way_edit && p==g_point_edit) color_p = color_point_edit
			else if (!p) color_p = color_way_fpoint
			else color_p = color_way_point
			create_line_point(id, start, end, color_p)

			// show line from current point to next point
			if (p+1<MAX_POINTS)
			{
				start[0] = g_ways[w][p][0]
				start[1] = g_ways[w][p][1]
				start[2] = g_ways[w][p][2]
				end[0] = g_ways[w][p+1][0]
				end[1] = g_ways[w][p+1][1]
				end[2] = g_ways[w][p+1][2]
				if (!g_ways[w][p+1][3] || !is_point(end)) break;
				
				create_line_point(id, start, end, color_w)
			}
		}
	}
}


//######################################################################
// BOX SPAWNS POINTS
//######################################################################
// ===================== BOX MAIN MENU =====================
public box_main(id)
{
	// remove boxs choose
	g_box_edit = -1
	
	// create menu
	new title[64], item_name[5][64]
	format(title, charsmax(title), "[NST Points] %L", LANG_PLAYER, "MENU_BOXS_TITLE", g_total_boxs, MAX_BOXS)
	format(item_name[0], 63, "%L", LANG_PLAYER, "MENU_BOXS_ITEM_ADD")
	format(item_name[1], 63, "%L", LANG_PLAYER, "MENU_BOXS_ITEM_EDIT")
	format(item_name[2], 63, "%L", LANG_PLAYER, "MENU_BOXS_ITEM_SAVE")
	format(item_name[3], 63, "%L", LANG_PLAYER, "MENU_BOXS_ITEM_LOAD")
	format(item_name[4], 63, "%L", LANG_PLAYER, "MENU_BOXS_ITEM_DEL")

	new mHandleID = menu_create(title, "box_main_handler")
	menu_additem(mHandleID, item_name[0], "add", 0)
	menu_additem(mHandleID, item_name[1], "edit", 0)
	menu_additem(mHandleID, item_name[2], "save", 0)
	menu_additem(mHandleID, item_name[3], "load", 0)
	menu_additem(mHandleID, item_name[4], "del", 0)
	menu_display(id, mHandleID, 0)
}
public box_main_handler(id, menu, item)
{
	if (item == MENU_EXIT)
	{
		// destroy menu
		menu_destroy(menu)
		// show menu main
		menu_main(id)
		return;
	}
	
	new itemid[32], itemname[32], access
	menu_item_getinfo(menu, item, access, itemid, charsmax(itemid), itemname, charsmax(itemname), access)
	menu_destroy(menu)
	
	if (equal(itemid, "add"))
	{
		box_create(id)
		return;
	}
	else if (equal(itemid, "edit"))
	{
		// set first value for g_box_edit
		g_box_edit = 0
		box_edit(id)
		return;
	}
	else if (equal(itemid, "save")) box_save()
	else if (equal(itemid, "load")) box_load()
	else if (equal(itemid, "del")) box_del(1)
	
	// show main menu
	box_main(id)
}

// ===================== box create =====================
public box_create(id)
{
	// remove boxs choose
	g_box_edit = -1
	
	// create menu
	new title[64], item_name[2][64]
	format(title, charsmax(title), "[NST Points] %L", LANG_PLAYER, "MENU_BOXS_ADD_TITLE", g_total_boxs, MAX_BOXS)
	format(item_name[0], 63, "%L", LANG_PLAYER, "MENU_BOXS_ADD_ITEM_ADD")
	format(item_name[1], 63, "%L", LANG_PLAYER, "MENU_BOXS_ADD_ITEM_DEL")

	new mHandleID = menu_create(title, "box_create_handler")
	menu_additem(mHandleID, item_name[0], "add", 0)
	menu_additem(mHandleID, item_name[1], "del", 0)
	menu_display(id, mHandleID, 0)
}
public box_create_handler(id, menu, item)
{
	if (item == MENU_EXIT)
	{
		// destroy menu
		menu_destroy(menu)
		// show menu main
		box_main(id)
		return;
	}
	
	new itemid[32], itemname[32], access
	menu_item_getinfo(menu, item, access, itemid, charsmax(itemid), itemname, charsmax(itemname), access)
	menu_destroy(menu)

	if (equali(itemid, "add")) box_create_add(id)
	else if (equali(itemid, "del")) box_del()

	// return menu create boxs
	box_create(id)
	
	return;
}
box_create_add(id)
{
	// check max points
	if (g_total_boxs>=MAX_BOXS)
	{
		new message[128]
		format(message, charsmax(message), ">x04[NST Points] >x01%L", LANG_PLAYER, "NOTICE_MAX_BOXS", MAX_BOXS)
		color_saytext(id, message)
		return;
	}
	
	// add current points
	new Float:originF[3], origin[3]
	pev(id, pev_origin, originF)
	origin[0] = floatround(originF[0])
	origin[1] = floatround(originF[1])
	origin[2] = floatround(originF[2])
	
	if (!is_point(origin) || !box_check_dist(originF))
	{
		new message[128]
		format(message, charsmax(message), ">x04[NST Points] >x01%L", LANG_PLAYER, "NOTICE_BOXS_DIST")
		color_saytext(id, message)
		return;
	}
	
	g_boxs[g_total_boxs][0] = origin[0]
	g_boxs[g_total_boxs][1] = origin[1]
	g_boxs[g_total_boxs][2] = origin[2]
	g_total_boxs ++
}

// ===================== box edit =====================
public box_edit(id)
{
	// check total
	if (!g_total_boxs)
	{
		new message[128]
		format(message, charsmax(message), ">x04[NST Points] >x01%L", LANG_PLAYER, "NOTICE_BOXS_NOTVALUE")
		color_saytext(id, message)
		box_main(id)
		return;
	}
	
	// create menu
	new title[64], item_name[4][64]
	format(title, charsmax(title), "[NST Points] %L", LANG_PLAYER, "MENU_BOXS_EDIT_TITLE")
	format(item_name[0], 63, "%L", LANG_PLAYER, "MENU_BOXS_EDIT_ITEM_BACK")
	format(item_name[1], 63, "%L", LANG_PLAYER, "MENU_BOXS_EDIT_ITEM_NEXT")
	format(item_name[2], 63, "%L", LANG_PLAYER, "MENU_BOXS_EDIT_ITEM_EDIT")
	format(item_name[3], 63, "%L", LANG_PLAYER, "MENU_BOXS_EDIT_ITEM_DEL")

	new mHandleID = menu_create(title, "box_edit_handler")
	menu_additem(mHandleID, item_name[0], "back", 0)
	menu_additem(mHandleID, item_name[1], "next", 0)
	menu_additem(mHandleID, item_name[2], "edit", 0)
	menu_additem(mHandleID, item_name[3], "del", 0)
	menu_display(id, mHandleID, 0)
}
public box_edit_handler(id, menu, item)
{
	if (item == MENU_EXIT)
	{
		// destroy menu
		menu_destroy(menu)
		// show menu main
		box_main(id)
		return;
	}
	
	new itemid[32], itemname[32], access
	menu_item_getinfo(menu, item, access, itemid, charsmax(itemid), itemname, charsmax(itemname), access)
	
	if (equal(itemid, "back")) box_edit_back()
	else if (equal(itemid, "next")) box_edit_next()
	else if (equal(itemid, "edit")) box_edit_edit(id, g_box_edit)
	else if (equal(itemid, "del")) box_edit_del(g_box_edit)
	
	menu_destroy(menu)
	
	// return menu
	box_edit(id)
}
box_edit_back()
{
	if (g_box_edit<=0) g_box_edit = g_total_boxs-1
	else g_box_edit --
}
box_edit_next()
{
	if (g_box_edit<0 || g_box_edit>=g_total_boxs-1) g_box_edit = 0
	else g_box_edit ++
}
box_edit_edit(id, point)
{
	// check value
	if (point<0 || point>=g_total_boxs) return;

	// get points
	new Float:originF[3], origin[3]
	pev(id, pev_origin, originF)
	origin[0] = floatround(originF[0])
	origin[1] = floatround(originF[1])
	origin[2] = floatround(originF[2])
	
	// check point
	if (!is_point(origin) || !box_check_dist(originF, point))
	{
		new message[128]
		format(message, charsmax(message), ">x04[NST Points] >x01%L", LANG_PLAYER, "NOTICE_BOXS_DIST")
		color_saytext(0, message)
		return;
	}
	
	// update
	g_boxs[point][0] = origin[0]
	g_boxs[point][1] = origin[1]
	g_boxs[point][2] = origin[2]
}
box_edit_del(box)
{
	// check value
	if (box<0 || box>=g_total_boxs) return;
	
	// del box point
	new box_r[3]
	g_boxs[box] = box_r
	
	// create g_boxs_r
	reset_box(1)
	new total_s, point[3]
	for (new i=0; i<g_total_boxs; i++)
	{
		point[0] = g_boxs[i][0]
		point[1] = g_boxs[i][1]
		point[2] = g_boxs[i][2]
		if (is_point(point))
		{
			g_boxs_r[total_s][0] = point[0]
			g_boxs_r[total_s][1] = point[1]
			g_boxs_r[total_s][2] = point[2]
			total_s ++
		}
	}
	
	// update g_boxs
	box_del(1)
	for (new s=0; s<total_s; s++)
	{
		g_boxs[s][0] = g_boxs_r[s][0]
		g_boxs[s][1] = g_boxs_r[s][1]
		g_boxs[s][2] = g_boxs_r[s][2]
	}
	g_total_boxs = total_s
	if (box) g_box_edit = box-1
}

// ===================== box save =====================
box_save()
{
	// check total
	if (!g_total_boxs)
	{
		new message[128]
		format(message, charsmax(message), ">x04[NST Points] >x01%L", LANG_PLAYER, "NOTICE_BOXS_NOTVALUE")
		color_saytext(0, message)
		return;
	}

	// get url file
	new cfgdir[32], mapname[32], urlfile[64]
	get_configsdir(cfgdir, charsmax(cfgdir))
	get_mapname(mapname, charsmax(mapname))
	formatex(urlfile, charsmax(urlfile), BOXS_URL, cfgdir, mapname)

	// save file
	if (file_exists(urlfile)) delete_file(urlfile)
	new lineset[128]
	for (new i=0; i<g_total_boxs; i++)
	{
		if (!g_boxs[i][0] && !g_boxs[i][1] && !g_boxs[i][2]) break;
		
		format(lineset, charsmax(lineset), "%i %i %i", g_boxs[i][0], g_boxs[i][1], g_boxs[i][2])
		write_file(urlfile, lineset, i)
	}
	
	// show notice
	new message[128]
	format(message, charsmax(message), ">x04[NST Points] >x01%L", LANG_PLAYER, "NOTICE_SAVEBOX_COMPLETE")
	color_saytext(0, message)
}

// ===================== box load =====================
box_load()
{
	// Check for boxs points of the current map
	new cfgdir[32], mapname[32], filepath[100], linedata[64], point[3]
	get_configsdir(cfgdir, charsmax(cfgdir))
	get_mapname(mapname, charsmax(mapname))
	formatex(filepath, charsmax(filepath), BOXS_URL, cfgdir, mapname)
	
	// check file exit
	if (!file_exists(filepath))
	{
		new message[128]
		format(message, charsmax(message), ">x04[NST Points] >x01%L", LANG_PLAYER, "NOTICE_FILE_EXIT", filepath)
		color_saytext(0, message)
		return;
	}
	
	// first reset value
	reset_box()
	
	// Load boxs points
	new file = fopen(filepath,"rt"), row[3][6]
	while (file && !feof(file))
	{
		fgets(file, linedata, charsmax(linedata))
		
		// invalid box
		if(!linedata[0] || str_count(linedata,' ') < 2) continue;
		
		// get box point data
		parse(linedata,row[0],5,row[1],5,row[2],5)
		
		// set boxst
		point[0] = str_to_num(row[0])
		point[1] = str_to_num(row[1])
		point[2] = str_to_num(row[2])
		if (is_point(point))
		{
			g_boxs[g_total_boxs][0] = point[0]
			g_boxs[g_total_boxs][1] = point[1]
			g_boxs[g_total_boxs][2] = point[2]
	
			// increase box count
			g_total_boxs ++
			if (g_total_boxs>=MAX_BOXS) break;
		}
	}
	if (file) fclose(file)
	
	// notice
	if (g_total_boxs)
	{
		new message[128]
		format(message, charsmax(message), ">x04[NST Points] >x01%L", LANG_PLAYER, "NOTICE_LOADBOX_COMPLETE", g_total_boxs)
		color_saytext(0, message)
	}
}

// ===================== box del all =====================
box_del(all=0)
{
	// check total
	if (!g_total_boxs)
	{
		new message[128]
		format(message, charsmax(message), ">x04[NST Points] >x01%L", LANG_PLAYER, "NOTICE_BOXS_NOTVALUE")
		color_saytext(0, message)
		return;
	}
	
	// del all
	if (all)
	{
		reset_box()
	}
	// del newest points
	else
	{
		static reset[3]
		g_total_boxs --
		g_boxs[g_total_boxs] = reset
	}
}

// ===================== other function =====================
box_show(id)
{
	if (!g_total_boxs) return;
	
	new color[3], start[3], end[3]
	for (new i=0; i<g_total_boxs; i++)
	{
		if (i==g_box_edit) color = color_point_edit
		else color = color_way_point
		start[0] = g_boxs[i][0]
		start[1] = g_boxs[i][1]
		start[2] = g_boxs[i][2]
		if (!is_point(start)) return;
		end = start
		start[2] -= 36
		end[2] += 36

		create_line_point(id, start, end, color)
	}
}
box_check_dist(Float:origin[3], point=-1)
{
	new Float:originE[3], Float:origin1[3], Float:origin2[3]
	
	for (new i=0; i<g_total_boxs; i++)
	{
		if (i==point) continue;
		
		originE[0] = float(g_boxs[i][0])
		originE[1] = float(g_boxs[i][1])
		originE[2] = float(g_boxs[i][2])
		
		// xoy
		origin1 = origin
		origin2 = originE
		origin1[2] = origin2[2] = 0.0
		if (vector_distance(origin1, origin2)<=2*16.0) return 0;
	}

	return 1;
}



//######################################################################
// FUNCTION MAIN
//######################################################################
reset_box(t=0)
{
	for (new s=0; s<MAX_BOXS; s++)
	{
		for (new i=0; i<3; i++)
		{
			if (t) g_spawns_r[s][i] = 0
			else g_spawns[s][i] = 0
		}
	}
	if (!t) g_total_spawns = 0
}
reset_spawn(t=0)
{
	for (new s=0; s<MAX_SPAWNS; s++)
	{
		for (new i=0; i<4; i++)
		{
			if (t) g_spawns_r[s][i] = 0
			else g_spawns[s][i] = 0
		}
	}
	if (!t) g_total_spawns = 0
}
reset_point(way, point, t=0)
{
	for (new i=0; i<4; i++)
	{
		if (t) g_ways_r[way][point][i] = 0
		else g_ways[way][point][i] = 0
	}
}
reset_way(way, t=0)
{
	for (new p=0; p<MAX_POINTS; p++)
	{
		reset_point(way, p, t)
	}	
}
reset_all_way(t=0)
{
	for (new w=0; w<MAX_WAYS; w++)
	{
		reset_way(w, t)
	}
	if (!t) g_total_ways = 0
}
get_total_point_of_way(w)
{
	if (!g_ways[w][0][3]) return 0;
	
	new total, point[3]
	for (new p=0; p<MAX_POINTS; p++)
	{
		point[0] = g_ways[w][p][0]
		point[1] = g_ways[w][p][1]
		point[2] = g_ways[w][p][2]
		if (!g_ways[w][p][3] || !is_point(point)) break;
		
		total ++
	}
	
	return total
}
is_point(point[3])
{
	if (!point[0] && !point[1] && !point[2]) return 0
	return 1
}
create_line_point(id, const start[3], const end[3], const color[3])
{
	if (!is_user_connected(id)) return;
	
	message_begin(MSG_ONE, SVC_TEMPENTITY, {0,0,0}, id)
	write_byte(TE_BEAMPOINTS)	// temp entity event
	write_coord(start[0])		// startposition: x
	write_coord(start[1])		// startposition: y
	write_coord(start[2])		// startposition: z
	write_coord(end[0])		// endposition: x
	write_coord(end[1])		// endposition: y
	write_coord(end[2])		// endposition: z
	write_short(cache_spr_line)	// sprite index
	write_byte(0)			// start frame
	write_byte(0)			// framerate
	write_byte(10)			// life in 0.1's
	write_byte(15)			// line width in 0.1's
	write_byte(0)			// noise amplitude in 0.01's
	write_byte(color[0])		// color: red
	write_byte(color[1])		// color: green
	write_byte(color[2])		// color: blue
	write_byte(200)			// brightness
	write_byte(0)			// scroll speed in 0.1's
	message_end()
}
color_saytext(player, const message[], any:...)
{
	new text[256]
	format(text, charsmax(text), "%s",message)
	format(text, charsmax(text), "%s",check_text(text))
	
	new dest
	if (player) dest = MSG_ONE
	else dest = MSG_ALL
	
	message_begin(dest, get_user_msgid("SayText"), {0,0,0}, player)
	write_byte(1)
	write_string(text)
	message_end()
}
check_text(text1[])
{
	new text[256]
	format(text, charsmax(text), "%s", text1)
	
	replace_all(text, charsmax(text), ">x04", "^x04")
	replace_all(text, charsmax(text), ">x03", "^x03")
	replace_all(text, charsmax(text), ">x01", "^x01")

	return text
}
check_user_admin(id)
{
	if (get_user_flags(id) & ADMIN_KICK) return 1
	return 0;
}
str_count(const str[], searchchar)
{
	new count, i, len = strlen(str)
	
	for (i = 0; i <= len; i++)
	{
		if(str[i] == searchchar)
			count++
	}
	
	return count;
}
