#pragma semicolon 1
#define DEBUG
#define PLUGIN_AUTHOR "jenz, thx to zuff for help"
#define PLUGIN_VERSION "1.00"
#define MAXZONES 64
#define ZONENAMELENGTH 256
#include <sourcemod>
#include <sdktools>
#include <sdkhooks>
#pragma newdecls required
//----------------------------------------------------------------------------------------------------
// Purpose: Global variables
//----------------------------------------------------------------------------------------------------
//forwards
static char g_sConfigzones[PLATFORM_MAX_PATH];
static Handle g_hForwardedZonesEnter;
static Handle g_hForwardedZonesLeaver;
//material
int g_iBeam = -1;
//creating new zones based on shavit/blaacky stuff 
char g_cZones[MAXZONES][ZONENAMELENGTH];
char g_cZoneIndexName[MAXZONES][ZONENAMELENGTH];
float f_startPos[MAXZONES][3];
float f_endpos[MAXZONES][3];
int i_admindrawing[MAXPLAYERS];
int ZONE_INDEX[MAXPLAYERS];
//experimental int?
int i_renameRefference[MAXPLAYERS];
int i_zoneRefference;
//counting zones
int i_zoneCount;
//making zone names
bool b_zonenaming[MAXPLAYERS];
//deleting zones
int i_adminSelectOption[MAXPLAYERS];
//entity refference
int i_zoneEntRef[MAXZONES];
//mapname
char mapname[125];
//----------------------------------------------------------------------------------------------------
// Purpose: description
//----------------------------------------------------------------------------------------------------
public Plugin myinfo = 
{
	name = "Unloze zones",
	author = PLUGIN_AUTHOR,
	description = "Zones to use for zonerewards",
	version = PLUGIN_VERSION,
	url = "www.unloze.com"
};
//----------------------------------------------------------------------------------------------------
// Purpose: pluginstart/end/askpluginload
//----------------------------------------------------------------------------------------------------
public void OnPluginStart()
{
	//hooks
	HookEvent("round_start", Event_roundStart, EventHookMode_Post);
	//commands
	RegConsoleCmd("say", Cmd_Say);
	RegAdminCmd("sm_zones", Cmd_Zones, ADMFLAG_GENERIC);
	RegAdminCmd("sm_zone", Cmd_Zones, ADMFLAG_GENERIC);
	RegAdminCmd("sm_zonetest", Cmd_Zonetest, ADMFLAG_ROOT);
	
	RegAdminCmd("sm_showzones", Cmd_ZoneDisplay, ADMFLAG_CUSTOM1);
	RegAdminCmd("sm_showzone", Cmd_ZoneDisplay, ADMFLAG_CUSTOM1);
}
//----------------------------------------------------------------------------------------------------
// Purpose: 
//----------------------------------------------------------------------------------------------------
public void OnPluginEnd()
{
	CloseHandle(g_hForwardedZonesEnter);
	CloseHandle(g_hForwardedZonesLeaver);
}
//----------------------------------------------------------------------------------------------------
// Purpose: 
//----------------------------------------------------------------------------------------------------
public APLRes AskPluginLoad2(Handle myself, bool late, char [] error, int err_max)
{
	//global forwards
	g_hForwardedZonesEnter = CreateGlobalForward("unloze_zoneEntry", ET_Ignore, Param_Cell, Param_String);
	g_hForwardedZonesLeaver = CreateGlobalForward("unloze_zoneLeave", ET_Ignore, Param_Cell, Param_String);
	CreateNative("unloze_zoneCount", Native_zoneCount);
	CreateNative("ZoneNameBasedOnIndex", Native_ZoneNameBasedOnIndex);
	return APLRes_Success;
}
//----------------------------------------------------------------------------------------------------
// Purpose: 
//----------------------------------------------------------------------------------------------------
public int Native_zoneCount(Handle handler, int numParams)
{
	return i_zoneCount;
}
//----------------------------------------------------------------------------------------------------
// Purpose: 
//----------------------------------------------------------------------------------------------------
public int Native_ZoneNameBasedOnIndex(Handle handler, int numParams)
{
	int i = GetNativeCell(1);
	SetNativeString(2, g_cZones[i][ZONENAMELENGTH -1], sizeof(g_cZones), true);
}
//----------------------------------------------------------------------------------------------------
// Purpose: Displayes zones
//----------------------------------------------------------------------------------------------------
public Action Cmd_ZoneDisplay(int client, int args)
{	
	displayzones(client);
}
//----------------------------------------------------------------------------------------------------
// Purpose: 
//----------------------------------------------------------------------------------------------------
public void displayzones(int client)
{
	if (i_admindrawing[client] == 0)
	{
		i_admindrawing[client] = -1;
		PrintToChat(client, "Activated zone display");
	}
	else if (i_admindrawing[client] <= -1)
	{
		i_admindrawing[client] = 0;
		PrintToChat(client, "De-Activated zone display");
	}
}
//----------------------------------------------------------------------------------------------------
// Purpose: commands && menus
//----------------------------------------------------------------------------------------------------
public Action Cmd_Zonetest(int client, int args)
{
	ReadZoneFile();
	return Plugin_Handled;
}
//----------------------------------------------------------------------------------------------------
// Purpose: 
//----------------------------------------------------------------------------------------------------
public Action Cmd_Zones(int client, int args)
{
	Menu menu = new Menu(MenuHandler1);
	menu.SetTitle("UNLOZE Zones menu!");
	menu.AddItem("Create new Zone", "Create new Zone");
	menu.AddItem("Rename Zones", "Rename Zones");
	menu.AddItem("Show/hide Zones", "Show/hide Zones");
	menu.AddItem("Delete Zone", "Delete Zone");
	menu.AddItem("Goto Zone", "Goto Zone");
	menu.AddItem("Editing Zone", "Editing Zone");
	menu.ExitButton = true;
	menu.Display(client, 0);
	return Plugin_Handled;
}
//----------------------------------------------------------------------------------------------------
// Purpose: 
//----------------------------------------------------------------------------------------------------
public int MenuHandler1(Menu menu, MenuAction action, int param1, int choice)
{
	/* If the menu was cancelled, print a message to the server about it. */
	if (action == MenuAction_Cancel)
	{
		PrintToServer("Client %d's menu was cancelled.  Reason: %d", param1, choice);
	}
	/* If the menu has ended, destroy it */
	else if (action == MenuAction_End)
	{
		delete menu;
	}
	else if (action == MenuAction_Select)
	{
		char info[32];
		menu.GetItem(choice, info, sizeof(info));
		if (StrEqual(info, "Create new Zone", true))
		{
			PrintToChat(param1, "Creating new zone");
			GetClientAbsOrigin(param1, f_startPos[ZONE_INDEX[param1]]);
			i_admindrawing[param1] = 1;
			cmd_menuFinishZone(param1, 0);
		}
		else if (StrEqual(info, "Rename Zones", true))
		{
			//make menu to select zone
			i_adminSelectOption[param1] = 7;
			cmd_menuZoneCounter(param1);
		}
		else if (StrEqual(info, "Show/hide Zones", true))
		{
			i_adminSelectOption[param1] = 6;
			cmd_menuZoneCounter(param1);
		}
		else if (StrEqual(info, "Delete Zone", true))
		{
			i_adminSelectOption[param1] = 1;
			cmd_menuZoneCounter(param1);
		}
		else if (StrEqual(info, "Goto Zone", true))
		{
			i_adminSelectOption[param1] = 2;
			cmd_menuZoneCounter(param1);
		}
		else if (StrEqual(info, "Editing Zone", true))
		{
			i_adminSelectOption[param1] = 5;
			cmd_menuZoneCounter(param1);
		}
		
	}
}

//----------------------------------------------------------------------------------------------------
// Purpose: simple say hook
//----------------------------------------------------------------------------------------------------
public Action Cmd_Say(int client, int args)
{
	if (b_zonenaming[client])
	{
		GetCmdArgString(g_cZones[ZONE_INDEX[client]], sizeof(g_cZones));
		chattrim(g_cZones[ZONE_INDEX[client]]);
		PrintToChat(client, "Updated zone name to: %s", g_cZones[ZONE_INDEX[client]]);
		//renaming zones
		i_adminSelectOption[client] = 3;
		
		//PrintToChatAll("i_renameRefference value: %i", i_renameRefference[client]);
		KillMultiple(i_renameRefference[client]);
		
		CreateZones(f_startPos[i_renameRefference[client]], f_endpos[i_renameRefference[client]], g_cZones[ZONE_INDEX[client]], i_renameRefference[client]);
		writetofile(f_startPos[i_renameRefference[client]], f_endpos[i_renameRefference[client]], g_cZones[ZONE_INDEX[client]], i_renameRefference[client], client);
		i_renameRefference[client] = 0;
		b_zonenaming[client] = false;
	}
}

public void chattrim(char[] message)
{
	for (int i = 0; i < strlen(message); i++)
	{
		if (StrContains(message[i], "}", false) >= 0)
		{
			strcopy(message, strlen(message), message[i]);
		}
	}
	ReplaceString(message, strlen(message), "\"", "", true);
}

//----------------------------------------------------------------------------------------------------
// Purpose: Creatingzonepoints and displaying them
//----------------------------------------------------------------------------------------------------

// https://forums.alliedmods.net/showthread.php?p=2030793
/*
* Generates all 8 points of a zone given just 2 of its points
*/
public void CreateZonePoints(float point[8][3])
{
    for (int i = 1; i < 7; i++)
    {
        for (int j = 0; j < 3; j++)
        {
            point[i][j] = point[((i >> (2 - j)) & 1) * 7][j];
        }
    }
}

/*
* Graphically draws a zone
*    if client == 0, it draws it for all players in the game
*   if client index is between 0 and MaxClients+1, it draws for the specified client
*/
public Action DrawZone(int client, float array[8][3], int beamsprite, int halosprite, color[4], float life)
{
	//shavit idea
	static int pairs[][] =
	{
		{ 0, 2 },
		{ 2, 6 },
		{ 6, 4 },
		{ 4, 0 },
		{ 0, 1 },
		{ 3, 1 },
		{ 3, 2 },
		{ 3, 7 },
		{ 5, 1 },
		{ 5, 4 },
		{ 6, 7 },
		{ 7, 5 }
	};	
	for (int i = 0; i < 12; i++)
	{
		TE_SetupBeamPoints(array[pairs[i][0]], array[pairs[i][1]], beamsprite, halosprite, 0, 0, life, 5.0, 5.0, 1, 1.1, color, 1);
		TE_SendToClient(client, 0.0);
	}
	return Plugin_Handled;
}

//----------------------------------------------------------------------------------------------------
// Purpose: menus
//----------------------------------------------------------------------------------------------------
public Action cmd_menuZoneCounter(int client)
{
	if (i_zoneCount < 1)
	{
		PrintToChat(client, "No active zones!");
		return Plugin_Handled;
	}
	char c_nameCompare[MAXZONES][256];
	Menu menu = new Menu(MenuHandler2);
	menu.SetTitle("Select which zone to Rename, Display, Delete, Edit or Goto ");
	//PrintToChatAll("i_zoneCount: %i", i_zoneCount);
	for (int i = 0; i < i_zoneCount; i++)
	{
		if (MenuZoneindex(i))
		{
			//PrintToChat(client, "MenuZoneindex true");
			Format(c_nameCompare[i], sizeof(c_nameCompare), g_cZoneIndexName[ZONE_INDEX[i]]);
			char toChar[64];
			IntToString(i, toChar, sizeof(toChar));
			Format(toChar, sizeof(toChar), "_%s", toChar);
			StrCat(g_cZoneIndexName[ZONE_INDEX[i]], sizeof(c_nameCompare), toChar);
			//PrintToChatAll("MenuZoneindex true %s", g_cZoneIndexName[ZONE_INDEX[i]]);
			menu.AddItem(g_cZoneIndexName[ZONE_INDEX[i]], g_cZoneIndexName[ZONE_INDEX[i]]);
		}
	}
	menu.ExitButton = true;
	menu.Display(client, 0);
	return Plugin_Handled;
}
//----------------------------------------------------------------------------------------------------
// Purpose: 
//----------------------------------------------------------------------------------------------------
public int CheckEntryKeys()
{
	//openfile here and find it mannualy in a really autistic way 
	int i_counter[MAXPLAYERS];
	int i_zoneTempCount;
	Handle zonefile = INVALID_HANDLE;
	char line[128];
	zonefile = OpenFile(g_sConfigzones, "r");
	while (!IsEndOfFile(zonefile) && ReadFileLine(zonefile, line, sizeof(line)))
	{
		int temp;
		temp = strlen(line);
		if (temp == 5)
		{	
			TrimString(line);
			ReplaceString(line, sizeof(line), "\"", "", false);
			i_counter[i_zoneTempCount] = StringToInt(line);
			//PrintToChatAll("i_counter[i_zoneTempCount]: %i", i_counter[i_zoneTempCount]);
			++i_zoneTempCount;
			//PrintToChatAll("i_zoneTempCount: %i", i_zoneTempCount);
		}
	}
	
	int i_Upper;
	for (int i = 0; i < i_zoneTempCount; i++)
	{
		if (i_counter[i] > i_Upper)
		{
			i_Upper = i_counter[i];
		}
	}
	i_Upper++;
	CloseHandle(zonefile);
	return i_Upper;
}


public int Keychecker(int i_zoneKeylocal)
{
	//openfile here and find it mannualy in a really autistic way 
	int i_zoneTempCount;
	Handle zonefile = INVALID_HANDLE;
	char line[128];
	zonefile = OpenFile(g_sConfigzones, "r");
	while (!IsEndOfFile(zonefile) && ReadFileLine(zonefile, line, sizeof(line)))
	{
		int temp;
		temp = strlen(line);
		if (temp == 5)
		{	
			if (i_zoneTempCount == i_zoneKeylocal)
			{
				//PrintToChatAll("Success %s", line);
				//PrintToChatAll("temp: %i", temp);
				TrimString(line);
				ReplaceString(line, sizeof(line), "\"", "", false);
				i_zoneTempCount = StringToInt(line);
				//PrintToChatAll("i_zoneTempCount: %i", i_zoneTempCount);
				CloseHandle(zonefile);
				return i_zoneTempCount;
			}
			i_zoneTempCount++;
		}
	}
	CloseHandle(zonefile);
	//PrintToChatAll("Failed finding zone entry key");
	return 0;
}

public bool MenuZoneindex(int ZoneKey)
{
	int i_zoneKeylocal;
	i_zoneKeylocal = Keychecker(ZoneKey);
	char c_entry[64];
	IntToString(i_zoneKeylocal, c_entry, sizeof(c_entry));
	//PrintToChatAll("c_entry: %s", c_entry);
	KeyValues kv_zoneentries = new KeyValues("Zones");
	if (kv_zoneentries.ImportFromFile(g_sConfigzones))
	{
		//PrintToChatAll("Success import from: %s", g_sConfigzones);
	}
	else
	{
		//PrintToChatAll("Failed import from: %s", g_sConfigzones);
		delete kv_zoneentries;
		return false;
	}
	
	if (kv_zoneentries.GotoFirstSubKey())
	{
		//kinda super important
		kv_zoneentries.Rewind();
		if (kv_zoneentries.JumpToKey(c_entry, false))
		{
			//alternatively ZoneKey here
			KvGetString(kv_zoneentries, "name", g_cZoneIndexName[ZONE_INDEX[i_zoneKeylocal]], ZONENAMELENGTH);
			//PrintToChatAll("SUCCESS JumpToKey GotoFirstSubKey: zoneIndexName %s", g_cZoneIndexName[ZONE_INDEX[i_zoneKeylocal]]);
			//PrintToChatAll("c_entry: %s", c_entry);
			delete kv_zoneentries;
			return true;
		}
	}
	//PrintToChatAll("Finished GotoNextKey");
	delete kv_zoneentries;
	return false;
}

public Action cmd_menuFinishZone1(int client, int args)
{
	Menu menu = new Menu(MenuHandler3);
	menu.SetTitle("UNLOZE Editing zone: %s", g_cZoneIndexName[ZONE_INDEX[i_zoneRefference]]);
	menu.AddItem("Finish Zone", "Finish Zone");
	menu.AddItem("Restart Zone", "Restart Zone");
	menu.ExitButton = true;
	menu.Display(client, 0);
	return Plugin_Handled;
}

public Action cmd_menuFinishZone(int client, int args)
{
	Menu menu = new Menu(MenuHandler2);
	menu.SetTitle("UNLOZE Zones menu!");
	menu.AddItem("Finish new Zone", "Finish new Zone");
	menu.AddItem("Restart Zone", "Restart Zone");
	menu.ExitButton = true;
	menu.Display(client, 0);
	return Plugin_Handled;
}
//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public int MenuHandler2(Menu menu, MenuAction action, int param1, int choice)
{
	//PrintToChat(param1, "Disabled Admin drawing");
	/* If the menu was cancelled, print a message to the server about it. */
	if (action == MenuAction_Cancel)
	{
		i_admindrawing[param1] = 0;
		i_adminSelectOption[param1] = 0;
		//PrintToServer("Client %d's menu was cancelled.  Reason: %d", param1, choice);
		return 0;
	}
	else if (action == MenuAction_Select)
	{
		char info[32];
		menu.GetItem(choice, info, sizeof(info));
		if (StrEqual(info, "Finish new Zone", true))
		{
			PrintToChat(param1, "Finished creating zone!");
			i_admindrawing[param1] = 0;
			Format(g_cZones[ZONE_INDEX[i_zoneCount]], sizeof(g_cZones), "UNASSIGNED NAME");
			i_adminSelectOption[param1] = 4;		
			i_zoneCount++;
			CreateZones(f_startPos[ZONE_INDEX[param1]], f_endpos[ZONE_INDEX[param1]], g_cZones[ZONE_INDEX[i_zoneCount]], i_zoneCount);
			writetofile(f_startPos[ZONE_INDEX[param1]], f_endpos[ZONE_INDEX[param1]], g_cZones[ZONE_INDEX[i_zoneCount]], i_zoneCount, param1);
			//Updating file
			ReadZoneFile();
			return 0;
		}
		else if (StrEqual(info, "Restart Zone", true))
		{
			i_admindrawing[param1] = 0;
			Cmd_Zones(param1, 0);
			return 0;
		}
		else 
		{
			DisplayMenuAtItem(menu, param1, GetMenuSelectionPosition(), 0);
			//Deleting Entries
			if (i_zoneCount >= 1)
			{
				//PrintToChatAll("i_zoneCount: %i", i_zoneCount);
				if (i_adminSelectOption[param1] == 1)
				{
					//i_adminSelectOption[param1] = 0;
					for (int i = 0; i < i_zoneCount; i++)
					{
						if (choice == i)
						{
							if (deleteFromFile(i, param1))
							{
								//ZONE_INDEX[param1] = i;
								PrintToChat(param1, "Deleting %s ", g_cZoneIndexName[ZONE_INDEX[i]]);
								i_zoneCount -= 1;
								//potential crashes?
								KillMultiple(i);
							}
							//only one zone to delete
							break;
						}
					}
				}
				//teleporting to zones
				else if (i_adminSelectOption[param1] == 2)
				{
					//PrintToChatAll("i_adminSelectOption == 2");
					//i_adminSelectOption[param1] = 0;
					float f_middle[MAXZONES][3];
					float f_min1[MAXZONES][3], f_max1[MAXZONES][3];
					for (int i = 0; i < i_zoneCount; i++)
					{
						if (choice == i)
						{
							PrintToChat(param1, "Teleported to: %s", g_cZones[i]);
							//PrintToChat(param1, "Teleported to: %s", g_cZoneIndexName[i]);
							f_min1[i][0] = f_startPos[i][0];
							f_min1[i][1] = f_startPos[i][1];
							f_min1[i][2] = f_startPos[i][2];
							f_max1[i][0] = f_endpos[i][0];
							f_max1[i][1] = f_endpos[i][1];
							f_max1[i][2] = f_endpos[i][2];
							//update local variable instead of global
							GetMiddleOfABox(f_min1[i], f_max1[i], f_middle[i]);
							TeleportEntity(param1, f_middle[i], NULL_VECTOR, NULL_VECTOR);
							//only one zone to teleport to
							break;
						}
					}
				}
				//Editing zones
				else if (i_adminSelectOption[param1] == 5)
				{
					//i_adminSelectOption[param1] = 0;
					for (int i = 0; i < i_zoneCount; i++)
					{
						if (choice == i)
						{
							//alternatively g_cZoneIndexName[i]
							i_zoneRefference = i;
							Menu menu1 = new Menu(MenuHandler3);
							menu1.SetTitle("UNLOZE Editing zone: %s", g_cZoneIndexName[ZONE_INDEX[i]]);
							menu1.AddItem("Redo Zone", "Redo Zone");
							menu1.AddItem("move Zone up", "move Zone up");
							menu1.AddItem("move Zone down", "move Zone down");
							menu1.AddItem("move Zone left", "move Zone left");
							menu1.AddItem("move Zone right", "move Zone right");
							menu1.AddItem("move Zone forwards", "move Zone forwards");
							menu1.AddItem("move Zone backwards", "move Zone backwards");
							menu1.ExitButton = true;
							menu1.Display(param1, 0);
							break;
						}
					}
				}
				//displaying zone
				if (i_adminSelectOption[param1] == 6)
				{
					displayzones(param1);
				}
				//renaming zones
				else if (i_adminSelectOption[param1] == 7)
				{
					for (int i = 0; i < i_zoneCount; i++)
					{
						if (choice == i)
						{
							i_renameRefference[param1] = i;
							b_zonenaming[param1] = true;
							PrintToChat(param1, "Enter the name of the zone into the chat");
							//only one zone to update
							break;
						}
					}
				}
			}
			else
			{
				PrintToChat(param1, "No zones available");
			}
		}
	}
	return 0;
}

//----------------------------------------------------------------------------------------------------
// Purpose: MenuHandler3
//----------------------------------------------------------------------------------------------------

public int MenuHandler3(Menu menu, MenuAction action, int param1, int choice)
{
	//i_admindrawing[param1] = 0;
	/* If the menu was cancelled, print a message to the server about it. */
	if (action == MenuAction_Cancel)
	{
		PrintToServer("Client %d's menu was cancelled.  Reason: %d", param1, choice);
	}
	
	/* If the menu has ended, destroy it */
	/*
	else if (action == MenuAction_End)
	{
		delete menu;
	}
	*/
	else if (action == MenuAction_Select)
	{
		DisplayMenuAtItem(menu, param1, GetMenuSelectionPosition(), 0);
		char info[32];
		float f_moveStartPos[MAXZONES][3], f_moveEndPos[MAXZONES][3];
		f_moveStartPos[i_zoneRefference] = f_startPos[i_zoneRefference];
		f_moveEndPos[i_zoneRefference] = f_endpos[i_zoneRefference];
		menu.GetItem(choice, info, sizeof(info));
		if (StrEqual(info, "Redo Zone", true))
		{
			GetClientAbsOrigin(param1, f_startPos[ZONE_INDEX[param1]]);
			i_admindrawing[param1] = 1;
			cmd_menuFinishZone1(param1, 0);
		}
		else if (StrEqual(info, "move Zone up", true))
		{
			f_moveStartPos[i_zoneRefference][2] += 15.0;
		}
		else if (StrEqual(info, "move Zone down", true))
		{
			f_moveEndPos[i_zoneRefference][2] -= 15.0;
		}
		else if (StrEqual(info, "move Zone left", true))
		{
			f_moveStartPos[i_zoneRefference][1] += 15.0;
		}
		else if (StrEqual(info, "move Zone right", true))
		{
			f_moveEndPos[i_zoneRefference][1] -= 15.0;
		}
		else if (StrEqual(info, "move Zone forwards", true))
		{
			f_moveStartPos[i_zoneRefference][0] -= 15.0;
		}
		else if (StrEqual(info, "move Zone backwards", true))
		{
			f_moveEndPos[i_zoneRefference][0] += 15.0;
		}
		//redoing coordinates but keep same name somehow
		else if (StrEqual(info, "Finish Zone", true))
		{
			i_admindrawing[param1] = 0;
			i_adminSelectOption[param1] = 4;
			TrimString(g_cZones[ZONE_INDEX[i_zoneRefference]]);
			CreateZones(f_startPos[ZONE_INDEX[param1]], f_endpos[ZONE_INDEX[param1]], g_cZones[ZONE_INDEX[i_zoneRefference]], i_zoneRefference);
			writetofile(f_startPos[ZONE_INDEX[param1]], f_endpos[ZONE_INDEX[param1]], g_cZones[ZONE_INDEX[i_zoneRefference]], i_zoneRefference, param1);
			//experimental
			ReadZoneFile();
		}
		else if (StrEqual(info, "Restart Zone", true))
		{
			GetClientAbsOrigin(param1, f_startPos[ZONE_INDEX[param1]]);
			i_admindrawing[param1] = 1;
			cmd_menuFinishZone1(param1, 0);
		}
		if (!StrEqual(info, "Restart Zone", true) && !StrEqual(info, "Redo Zone", true) && !StrEqual(info, "Finish Zone", true))
		{
			i_adminSelectOption[param1] = 3;
			TrimString(g_cZones[ZONE_INDEX[i_zoneRefference]]);
			//PrintToChatAll("writetofile after moving zone somewhere");
			CreateZones(f_moveStartPos[i_zoneRefference], f_moveEndPos[i_zoneRefference], g_cZones[ZONE_INDEX[i_zoneRefference]], i_zoneRefference);
			writetofile(f_moveStartPos[i_zoneRefference], f_moveEndPos[i_zoneRefference], g_cZones[ZONE_INDEX[i_zoneRefference]], i_zoneRefference, param1);		
			//experimental for updating in real time
			ReadZoneFile();
		}
		
	}
}

//----------------------------------------------------------------------------------------------------
// Purpose: Writing to File
//----------------------------------------------------------------------------------------------------

public void writetofile(float[3] startpos, float[3] endpos, char[] zones, int EntryValue, int client)
{
	char c_entryCount[64];
	KeyValues kv_zoneentries = CreateKeyValues("Zones");
	int i_zoneKeylocal;
	//PrintToChatAll("EntryValue: %i", EntryValue);
	if (i_adminSelectOption[client] == 3)
	{
		i_zoneKeylocal = Keychecker(EntryValue);
		//PrintToChatAll("i_zoneKeylocal: %i", i_zoneKeylocal);
		IntToString(i_zoneKeylocal, c_entryCount, sizeof(c_entryCount));
	}
	else if (i_adminSelectOption[client] == 4|| i_adminSelectOption[client] == 5)
	{
		i_zoneKeylocal = CheckEntryKeys();
		IntToString(i_zoneKeylocal, c_entryCount, sizeof(c_entryCount));
	}
	float f_min1[3], f_max1[3];
	f_min1[0] = startpos[0];
	f_min1[1] = startpos[1];
	f_min1[2] = startpos[2];
	f_max1[0] = endpos[0];
	f_max1[1] = endpos[1];
	f_max1[2] = endpos[2];
	if (kv_zoneentries.ImportFromFile(g_sConfigzones))
	{
		//PrintToChatAll("Success import from: %s", g_sConfigzones);
	}
	else
	{
		//PrintToChatAll("Failed import from: %s", g_sConfigzones);
		delete kv_zoneentries;
		i_adminSelectOption[client] = 0;
		return;
	}
	kv_zoneentries.Rewind();
	
	if (i_adminSelectOption[client] == 4)
	{
		if (kv_zoneentries.JumpToKey(c_entryCount, true))
		{
			KvSetString(kv_zoneentries, "name", zones);
			KvSetVector(kv_zoneentries, "cordinate_a", f_min1);
			KvSetVector(kv_zoneentries, "cordinate_b", f_max1);
			PrintToChat(client, "Added zone: %s", c_entryCount);
		}
	}
	
	//renaming zone parts
	else if (i_adminSelectOption[client] == 3)
	{
		//c_entryCount starts as 0 and goes to i_zounecount
		if (kv_zoneentries.JumpToKey(c_entryCount, false))
		{
			KvSetString(kv_zoneentries, "name", zones);
			KvSetVector(kv_zoneentries, "cordinate_a", f_min1);
			KvSetVector(kv_zoneentries, "cordinate_b", f_max1);
			/*
			PrintToChat(client, "f_min1 %f", f_min1);
			PrintToChat(client, "f_max1 %f", f_max1);
			PrintToChat(client, "Success zonekeys %s!", c_entryCount);
			*/
			PrintToChat(client, "Coordinate_a: %f", f_min1);
			PrintToChat(client, "Coordinate_b: %f", f_max1);
		}
		/*
		else
		{
			PrintToChat(client, "Failed %s", c_entryCount);
		}
		*/
	}
	
	i_adminSelectOption[client] = 0;
	kv_zoneentries.Rewind();
	kv_zoneentries.ExportToFile(g_sConfigzones);
	delete kv_zoneentries;
}

//----------------------------------------------------------------------------------------------------
// Purpose: Deleting entries
//----------------------------------------------------------------------------------------------------
public bool deleteFromFile(int EntryValue, int client)
{	
	int i_zoneKeylocal;
	i_zoneKeylocal = Keychecker(EntryValue);
	//big question here
	//PrintToChatAll("deleteFromFile EntryValue: %i", EntryValue);
	char c_entryCount[128];
	KeyValues kv_zoneentries = CreateKeyValues("Zones");
	IntToString(i_zoneKeylocal, c_entryCount, sizeof(c_entryCount));
	if (kv_zoneentries.ImportFromFile(g_sConfigzones))
	{
		//PrintToChatAll("Success import from: %s", g_sConfigzones);
	}
	else
	{
		//PrintToChatAll("Failed import from: %s", g_sConfigzones);
		delete kv_zoneentries;
		return false;
	}
	kv_zoneentries.Rewind();
	if (kv_zoneentries.JumpToKey(c_entryCount, false))
	{
		//PrintToChat(client, "Success JumpToKey Deleting: %s", c_entryCount);
		kv_zoneentries.DeleteThis();
		kv_zoneentries.Rewind();
		kv_zoneentries.ExportToFile(g_sConfigzones);
		delete kv_zoneentries;
		return true;
	}
	delete kv_zoneentries;
	return false;
}

//----------------------------------------------------------------------------------------------------
// Purpose: PlayerRun
//----------------------------------------------------------------------------------------------------

public void OnPlayerRunCmdPost(int client, int& buttons, int& impulse, float vel[3], float angles[3], int& weapon, int& subtype, int& cmdnum, int& tickcount, int& seed, int mouse[2])
{
	//admin is drawing a new zone
	if (i_admindrawing[client] >= 1)
	{
		i_admindrawing[client]++;
		
		//add delay to prevent client- crash from te_setupbeampoints
		if (i_admindrawing[client] >= 15)
		{
			//PrintToChatAll(">= 15");
			i_admindrawing[client] = 1;
			
			f_endpos[ZONE_INDEX[client]] = GetAimPosition(client);
			float points[8][3];
			points[0] = f_startPos[ZONE_INDEX[client]];
			points[7] = f_endpos[ZONE_INDEX[client]];
			
			CreateZonePoints(points);
			DrawZone(client, points, g_iBeam, 0, { 255, 255, 255, 255 }, 0.5);
		}
	}
	//people with custom flag 1 that want to see zones
	else if (i_admindrawing[client] <= -1)
	{
		i_admindrawing[client] -= 1;
		//add delay to prevent client- crash from te_setupbeampoints
		if (i_admindrawing[client] <= -15)
		{
			i_admindrawing[client] = -1;
			
			//PrintToChatAll("i_zoneCount: %i", i_zoneCount);
			float points[8][3];
			for (int i = 0; i < i_zoneCount; i++)
			{
				points[0] = f_startPos[i];
				points[7] = f_endpos[i];
				//fills all other points than [0] and [7]
				CreateZonePoints(points);
				DrawZone(client, points, g_iBeam, 0, { 255, 255, 255, 255 }, 1.0);
			}
		}
	}
}

//----------------------------------------------------------------------------------------------------
// Purpose: GetAimPosition for zone end drawing
//----------------------------------------------------------------------------------------------------

float[] GetAimPosition(int client)
{
	float pos[3];
	GetClientEyePosition(client, pos);

	float angles[3];
	GetClientEyeAngles(client, angles);

	TR_TraceRayFilter(pos, angles, MASK_SHOT, RayType_Infinite, TraceFilter_NoClients, client);

	if (TR_DidHit())
	{
		float end[3];
		TR_GetEndPosition(end);

		return end;
	}

	return pos;
}

public bool TraceFilter_NoClients(int entity, int contentsMask, any data)
{
	return (entity != data && 1 <= data <= MaxClients || !IsClientInGame(data));
}


//----------------------------------------------------------------------------------------------------
// Purpose: Mapstart
//----------------------------------------------------------------------------------------------------
public void OnMapStart()
{
	GetCurrentMap(mapname, sizeof(mapname));
	PrecacheModel("models/props/cs_office/vending_machine.mdl");
	g_iBeam = PrecacheModel("materials/unloze_tracers/xbeam.vmt");
	AddFileToDownloadsTable("materials/unloze_tracers/xbeam.vmt");
	AddFileToDownloadsTable("materials/unloze_tracers/xbeam.vtf");
	ReadZoneFile();
}


//----------------------------------------------------------------------------------------------------
// Purpose: Reads from file
//----------------------------------------------------------------------------------------------------
public Action ReadZoneFile()
{
	//loading zone file
	int i_zoneTemp;
	Handle zonefile = INVALID_HANDLE;
	char line[128];
	BuildPath(Path_SM, g_sConfigzones, sizeof(g_sConfigzones), "configs/unloze_zones/%s.zones.txt", mapname);
	zonefile = OpenFile(g_sConfigzones, "r");
	if (zonefile == INVALID_HANDLE)
	{
		Handle kv = CreateKeyValues("Zones");
		KeyValuesToFile(kv, g_sConfigzones);
		CloseHandle(kv);
		//PrintToChatAll("Cannot read file %s ! Creating...", g_sConfigzones);
		delete zonefile;
		return Plugin_Handled;
	}
	while (!IsEndOfFile(zonefile) && ReadFileLine(zonefile, line, sizeof(line)))
	{
		if (StrContains(line, "name", false) >= 0)
		{
			ReplaceString(line, sizeof(line), "\"", "", true);
			ReplaceString(line, sizeof(line), "name", "", true);
			Format(g_cZones[i_zoneTemp], sizeof(g_cZones), line);
		}
		
		//are cordinate_a and cordinate_b 3 vectors or only one to assign?
		if (StrContains(line, "cordinate_a", false) >= 0)
		{
			ReplaceString(line, sizeof(line), "\"", "", true);
			ReplaceString(line, sizeof(line), "cordinate_a", "", true);
			//PrintToChatAll("line CoordA: %s", line);
			
			char sPart[4][32];
			ExplodeString(line, " ", sPart, 4, 32);
			
			f_startPos[i_zoneTemp][0] = StringToFloat(sPart[0]);
			//PrintToChatAll("f_startPos[i_zoneTemp][0]  value: %f", f_startPos[i_zoneTemp][0]);
			
			f_startPos[i_zoneTemp][1]  = StringToFloat(sPart[1]);//reading second vector
			//PrintToChatAll("f_startPos[i_zoneTemp][1]  value: %f", f_startPos[i_zoneTemp][1]);
			
			f_startPos[i_zoneTemp][2]  = StringToFloat(sPart[2]);//reading third vector
			//PrintToChatAll("f_startPos[i_zoneTemp][2]  value: %f", f_startPos[i_zoneTemp][2]);
		}
		if (StrContains(line, "cordinate_b", false) >= 0)
		{
			ReplaceString(line, sizeof(line), "\"", "", true);
			ReplaceString(line, sizeof(line), "cordinate_b", "", true);
			//PrintToChatAll("line CoordB: %s", line);
			
			char sPart[4][32];
			ExplodeString(line, " ", sPart, 4, 32);
			
			f_endpos[i_zoneTemp][0] = StringToFloat(sPart[0]);
			//PrintToChatAll("f_endpos[i_zoneTemp][0] value: %f", f_endpos[i_zoneTemp][0]);
			
			f_endpos[i_zoneTemp][1] = StringToFloat(sPart[1]);//reading second vector
			//PrintToChatAll("f_endpos[i_zoneTemp][1] value: %f", f_endpos[i_zoneTemp][1]);
			
			f_endpos[i_zoneTemp][2] = StringToFloat(sPart[2]);//reading third vector
			//PrintToChatAll("f_endpos[i_zoneTemp][2] value: %f", f_endpos[i_zoneTemp][2]);
			i_zoneTemp++;
		}
	}
	i_zoneCount = i_zoneTemp;
	delete zonefile;
	return Plugin_Handled;
}

//----------------------------------------------------------------------------------------------------
// Purpose: OnClientPostAdminCheck && disconnect
//----------------------------------------------------------------------------------------------------
public void OnClientPostAdminCheck(int client)
{
	ZONE_INDEX[client] = 0;
	i_renameRefference[client] = 0;
	i_adminSelectOption[client] = 0;
	i_admindrawing[client] = 0;
	b_zonenaming[client] = false;
}

public void OnClientDisconnect(int client)
{
	ZONE_INDEX[client] = 0;
	i_renameRefference[client] = 0;
	i_adminSelectOption[client] = 0;
	i_admindrawing[client] = 0;
	b_zonenaming[client] = false;
}

//----------------------------------------------------------------------------------------------------
// Purpose: Hook roundstart
//----------------------------------------------------------------------------------------------------
public void Event_roundStart(Handle event, const char[] name, bool dontBroadcast)
{
	ReadZoneFile();
	for (int i = 0; i < i_zoneCount; i++)
	{
		CreateZones(f_startPos[i], f_endpos[i], g_cZones[i], i);
	}
}

//----------------------------------------------------------------------------------------------------
// Purpose: Destroys trigger_multiple in current round
//----------------------------------------------------------------------------------------------------
public void KillMultiple(int zone)
{
	int zoneEntity[MAXZONES];
	//entref here
	zoneEntity[zone] = EntRefToEntIndex(i_zoneEntRef[zone]);
	if (IsValidEntRef(zoneEntity[zone]))
	{
		SDKUnhook(zoneEntity[zone], SDKHook_StartTouchPost, OnStartTouch);
		SDKUnhook(zoneEntity[zone], SDKHook_EndTouchPost, OnEndTouch);
		AcceptEntityInput(zoneEntity[zone], "Kill");
		//PrintToChatAll("Destroyed trigger multiple");
	}
}
 
//----------------------------------------------------------------------------------------------------
// Purpose: Zone loading https://forums.alliedmods.net/showthread.php?p=2585082
//----------------------------------------------------------------------------------------------------
public void CreateZones(float f_min[3], float f_max[3], char[] sZoneName, int zoneCount)
{
	char c_nameZoneName[128];
	Format(c_nameZoneName, sizeof(c_nameZoneName), sZoneName);
	int entindex = CreateEntityByName("trigger_multiple");
	if (entindex != -1)
	{	
		// According to a mysterious source:
		// Spawnflags:	1 - only a player can trigger this by touch, makes it so a NPC cannot fire a trigger_multiple
		// 2 - Won't fire unless triggering ent's view angles are within 45 degrees of trigger's angles (in addition to any other conditions), so if you want the player to only be able to fire the entity at a 90 degree angle you would do ",angles,0 90 0," into your spawnstring.
		// 4 - Won't fire unless player is in it and pressing use button (in addition to any other conditions), you must make a bounding box,(max\mins) for this to work.
		// 8 - Won't fire unless player/NPC is in it and pressing fire button, you must make a bounding box,(max\mins) for this to work.
		// 16 - only non-player NPCs can trigger this by touch
		// 128 - Start off, has to be activated by a target_activate to be touchable/usable
		// 256 - multiple players can trigger the entity at the same time
		
		//targetname seems not to update in real time when using sdkhooks
		//maybe make a local char here to take parameter instead?
		DispatchKeyValue(entindex, "targetname", c_nameZoneName); 
		DispatchKeyValue(entindex, "spawnflags", "257");
		SetEntityModel(entindex, "models/props/cs_office/vending_machine.mdl");
	}
	DispatchSpawn(entindex);
	ActivateEntity(entindex);
	
	//we need to copy it over to local floats or else parameter gets updated and the origin is fucked
	float f_middle[3];
	float f_min1[3], f_max1[3];
	f_min1[0] = f_min[0];
	f_min1[1] = f_min[1];
	f_min1[2] = f_min[2];
	f_max1[0] = f_max[0];
	f_max1[1] = f_max[1];
	f_max1[2] = f_max[2];
	GetMiddleOfABox(f_min1, f_max1, f_middle);
	//PrintToChatAll("f_middle: %f", f_middle);
	TeleportEntity(entindex, f_middle, NULL_VECTOR, NULL_VECTOR);
	
	
	// Have the mins always be negative
	for (int i = 0; i < 3; i++)
	{
        f_min1[i] = f_min1[i] - f_middle[i];
        if (f_min1[i] > 0.0)
        {
            f_min1[i] *= -1.0;
        }
    }
	// And the maxs always be positive
	for (int i = 0; i < 3; i++)
	{
        f_max1[i] = f_max1[i] - f_middle[i];
        if (f_max1[i] < 0.0)
        {
            f_max1[i] *= -1.0;
        }
	}
	SetEntPropVector(entindex, Prop_Send, "m_vecMins", f_min1);
	SetEntPropVector(entindex, Prop_Send, "m_vecMaxs", f_max1);
	SetEntProp(entindex, Prop_Send, "m_nSolidType", 2);
	
	int enteffects = GetEntProp(entindex, Prop_Send, "m_fEffects");
	enteffects |= 32;
	SetEntProp(entindex, Prop_Send, "m_fEffects", enteffects);
	SDKHook(entindex, SDKHook_StartTouchPost, OnStartTouch);
	SDKHook(entindex, SDKHook_EndTouchPost, OnEndTouch);
	i_zoneEntRef[zoneCount] = EntIndexToEntRef(entindex);
}



//----------------------------------------------------------------------------------------------------
// Purpose: Entity Output Handlers
//----------------------------------------------------------------------------------------------------
public void OnStartTouch(int entindex, int other)
{
	if (IsValidClient(other))
	{
		char zoneName[64];
		GetEntPropString(entindex, Prop_Data, "m_iName", zoneName, sizeof(zoneName));
		//PrintToChatAll("zoneName: %s", zoneName);
		
		//forward
		Call_StartForward(g_hForwardedZonesEnter);
		Call_PushCell(other);
		Call_PushString(zoneName);
		Call_Finish();
	}
}

public void OnEndTouch(int entindex, int other)
{
	if (IsValidClient(other))
	{
		char zoneName[64];
		GetEntPropString(entindex, Prop_Data, "m_iName", zoneName, sizeof(zoneName)); 
		//PrintToChatAll("zoneName: %s", zoneName);
		
		//forward
		Call_StartForward(g_hForwardedZonesLeaver);
		Call_PushCell(other);
		Call_PushString(zoneName);
		Call_Finish();
	}
}

//----------------------------------------------------------------------------------------------------
// Purpose: stocks
//----------------------------------------------------------------------------------------------------
stock bool IsValidClient(int client)
{
	if (client > 0 && client <= MaxClients && IsClientInGame(client) && !IsFakeClient(client) && IsPlayerAlive(client))
	{
		return true;
	}
	return false;
}

stock void GetMiddleOfABox(const float vec1[3], const float vec2[3], float buffer[3])
{
    float mid[3];
    MakeVectorFromPoints(vec1, vec2, mid);
    mid[0] = mid[0] / 2.0;
    mid[1] = mid[1] / 2.0;
    mid[2] = mid[2] / 2.0;
    AddVectors(vec1, mid, buffer);
} 

stock bool IsValidEntRef(int entity)
{
	if (entity && EntRefToEntIndex(entity) != INVALID_ENT_REFERENCE)
	{
		return true;
	}
	return false;
}

//----------------------------------------------------------------------------------------------------
// Purpose: 
//----------------------------------------------------------------------------------------------------
