#include <clientprefs>
#include <multicolors>
#include <sdkhooks>
#include <sourcemod>
#include <zombiereloaded>
#include <leader>


/* BOOLS */
bool g_bHidePlayers[MAXPLAYERS+1][MAXPLAYERS+1];

/* INTEGERS */
int g_iHideRange[MAXPLAYERS+1];

/* CONVARS */
ConVar g_hCVar_HideEnabled;

/* COOKIES */
Handle g_hCookie_HideRange;

#define DISABLED -1
#define SHORT_RANGE 120
#define MEDIUM_RANGE 250
#define LONG_RANGE 500

int SHORT = SHORT_RANGE * SHORT_RANGE;
int MEDIUM = MEDIUM_RANGE * MEDIUM_RANGE;
int LONG = LONG_RANGE * LONG_RANGE;

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public Plugin myinfo =
{
	name         = "Hide Teammates",
	author       = "Neon",
	description  = "A plugin that can !hide teammates with individual distances",
	version      = "2.0.1",
	url 		= "https://steamcommunity.com/id/n3ontm"
};

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public void OnPluginStart()
{

	g_hCVar_HideEnabled = CreateConVar("sm_hide_enabled", "1", "", FCVAR_NONE, true, 0.0, true, 1.0);
	g_hCVar_HideEnabled.AddChangeHook(OnConVarChanged);
	AutoExecConfig(true);

	g_hCookie_HideRange = RegClientCookie("hide_range", "", CookieAccess_Private);

	RegConsoleCmd("sm_hide", OnHideSettings, "Hiding near humans");

	for(int client = 1; client <= MaxClients; client++)
	{
		if(IsClientInGame(client))
		{
			OnClientPutInServer(client);

			if(AreClientCookiesCached(client))
				OnClientCookiesCached(client);
		}

	}
	SetCookieMenuItem(MenuHandler_CookieMenu, 0, "Hide");
}

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public void OnMapStart()
{
	CreateTimer(0.3, UpdateHide, INVALID_HANDLE, TIMER_REPEAT|TIMER_FLAG_NO_MAPCHANGE);
}

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public void OnConVarChanged(ConVar convar, const char[] oldValue, const char[] newValue)
{
	for(int client = 1; client <= MaxClients; client++)
	{
		for(int target = 1; target <= MaxClients; target++)
			g_bHidePlayers[client][target] = false;

		if(IsClientInGame(client))
		{
			if(g_hCVar_HideEnabled.BoolValue)
				SDKHook(client, SDKHook_SetTransmit, Hook_SetTransmit);
			else
				SDKUnhook(client, SDKHook_SetTransmit, Hook_SetTransmit);
		}
	}

	if(g_hCVar_HideEnabled.BoolValue)
		CPrintToChatAll("{cyan}[Hide] {white}has been allowed.");
	else
		CPrintToChatAll("{cyan}[Hide] {white}has been disabled.");
}

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public void OnClientPutInServer(int client)
{
	if(!g_hCVar_HideEnabled.BoolValue)
		return;

	SDKHook(client, SDKHook_SetTransmit, Hook_SetTransmit);
}

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public void OnClientDisconnect(int client)
{
	g_iHideRange[client] = 0;
	for(int target = 1; target <= MaxClients; target++)
	{
		g_bHidePlayers[client][target] = false;
	}
}

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public void OnClientCookiesCached(int client)
{
	char sBuffer[16];
	GetClientCookie(client, g_hCookie_HideRange, sBuffer, sizeof(sBuffer));

	if (sBuffer[0])
	{
		g_iHideRange[client] = StringToInt(sBuffer);
		if (g_iHideRange[client] != SHORT && g_iHideRange[client] != MEDIUM && g_iHideRange[client] != LONG)
			g_iHideRange[client] = DISABLED;
	}
	else
		g_iHideRange[client] = DISABLED;
}

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public Action UpdateHide(Handle timer)
{
	if(!g_hCVar_HideEnabled.BoolValue)
		return Plugin_Continue;

	for(int client = 1; client <= MaxClients; client++)
	{
		if(g_iHideRange[client] == DISABLED)
		{
			for(int target = 1; target <= MaxClients; target++)
			{
				g_bHidePlayers[client][target] = false;
			}
			continue;
		}

		if(!IsClientInGame(client) || !IsPlayerAlive(client) || !ZR_IsClientHuman(client) || IsFakeClient(client) || IsFakeClient(client))
		{
			for(int target = 1; target <= MaxClients; target++)
			{
				g_bHidePlayers[client][target] = false;
			}
			continue;
		}

		float fOriginClient[3];
		float fOriginTarget[3];
		int iLeader = Leader_CurrentLeader()

		for(int target = 1; target <= MaxClients; target++)
		{
			if(IsClientInGame(target) && IsPlayerAlive(target) && ZR_IsClientHuman(target) && target != client)
			{
				GetClientAbsOrigin(target, fOriginTarget);
				GetClientAbsOrigin(client, fOriginClient);
				//PrintToChatAll("%N--%N::::::%f", client, target, GetVectorDistance(fOriginTarget, fOriginClient, false));
				if((GetVectorDistance(fOriginTarget, fOriginClient, true) <= float(g_iHideRange[client])) && (iLeader != target))
					g_bHidePlayers[client][target] = true;
				else
					g_bHidePlayers[client][target] = false;
			}
			else
				g_bHidePlayers[client][target] = false;
		}
	}
	return Plugin_Continue;
}

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public Action Hook_SetTransmit(int target, int client)
{
	if(g_bHidePlayers[client][target])
		return Plugin_Handled;

	return Plugin_Continue;
}

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public Action OnHideSettings(int client, int args)
{
	ShowSettingsMenu(client);
	return Plugin_Handled;
}

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public void ShowSettingsMenu(int client)
{
	Menu menu = new Menu(MenuHandler_MainMenu);

	menu.SetTitle("Hide", client);

	char sBuffer[128];

	Format(sBuffer, sizeof(sBuffer), "Disabled%s", (g_iHideRange[client] == DISABLED) ? " [Selected]" : "");
	menu.AddItem("", sBuffer, (g_iHideRange[client] == DISABLED));

	Format(sBuffer, sizeof(sBuffer), "Short Range%s", (g_iHideRange[client] == SHORT) ? " [Selected]" : "");
	menu.AddItem("", sBuffer, (g_iHideRange[client] == SHORT));

	Format(sBuffer, sizeof(sBuffer), "Medium Range%s", (g_iHideRange[client] == MEDIUM) ? " [Selected]" : "");
	menu.AddItem("", sBuffer, (g_iHideRange[client] == MEDIUM));

	Format(sBuffer, sizeof(sBuffer), "Long Range%s", (g_iHideRange[client] == LONG) ? " [Selected]" : "");
	menu.AddItem("", sBuffer, (g_iHideRange[client] == LONG));

	if(!g_hCVar_HideEnabled.BoolValue)
		menu.AddItem("", "Warning: Hide is currently disabled on the server", ITEMDRAW_DISABLED);

	menu.ExitBackButton = true;

	menu.Display(client, MENU_TIME_FOREVER);
}

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public int MenuHandler_MainMenu(Menu menu, MenuAction action, int client, int selection)
{
	switch(action)
	{
		case(MenuAction_Select):
		{
			switch(selection)
			{
				case(0):
				{
					g_iHideRange[client] = DISABLED
				}
				case(1):
				{
					g_iHideRange[client] = SHORT
				}
				case(2):
				{
					g_iHideRange[client] = MEDIUM
				}
				case(3):
				{
					g_iHideRange[client] = LONG
				}
			}
			char sBuffer[16];
			Format(sBuffer, sizeof(sBuffer), "%d", g_iHideRange[client]);
			SetClientCookie(client, g_hCookie_HideRange, sBuffer);
			ShowSettingsMenu(client);
		}
		case(MenuAction_Cancel):
		{
			ShowCookieMenu(client);
		}
		case(MenuAction_End):
		{
			delete menu;
		}
	}
}

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public void MenuHandler_CookieMenu(int client, CookieMenuAction action, any info, char[] buffer, int maxlen)
{
	switch(action)
	{
		case(CookieMenuAction_DisplayOption):
		{
			Format(buffer, maxlen, "Hide", client);
		}
		case(CookieMenuAction_SelectOption):
		{
			ShowSettingsMenu(client);
		}
	}
}