#include <sourcemod>
#include <sdktools>
#include <BossHP>
#include <zombiereloaded>
#include <clientprefs>
#include <multicolors>

#define SPECMODE_NONE           0
#define SPECMODE_FIRSTPERSON    4
#define SPECMODE_THIRDPERSON    5
#define SPECMODE_FREELOOK       6

#pragma newdecls required
#pragma	semicolon 1

bool g_bShowBossHitmarker[MAXPLAYERS+1];
bool g_bShowZombieHitmarker[MAXPLAYERS+1];
bool g_bHitmarkerSound[MAXPLAYERS+1];

int g_iHitmarkerSoundVolume[MAXPLAYERS+1] = {100,...};

Handle g_hTimer[MAXPLAYERS+1] = {null,...};

Handle g_hCookie_ShowBossHitmarker;
Handle g_hCookie_ShowZombieHitmarker;
Handle g_hCookie_HitmarkerSound;
Handle g_hCookie_HitmarkerSoundVolume;

//Handle g_hHudText;

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public Plugin myinfo =
{
	name         = "Htimarker",
	author       = "Neon & Nano",
	description  = "Players can enable or disable their hitmarkers while shooting zombies or bosses",
	version      = "1.0.0",
};

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public void OnPluginStart()
{
	g_hCookie_ShowBossHitmarker = RegClientCookie("hitmarker_boss", "", CookieAccess_Private);
	g_hCookie_ShowZombieHitmarker = RegClientCookie("hitmarker_zombie", "", CookieAccess_Private);
	g_hCookie_HitmarkerSound = RegClientCookie("hitmarker_sound", "", CookieAccess_Private);
	g_hCookie_HitmarkerSoundVolume = RegClientCookie("hitmarker_sound_volume", "", CookieAccess_Private);

	//g_hHudText = CreateHudSynchronizer();

	RegConsoleCmd("sm_hm", OnHitmarkerSettings);
	RegConsoleCmd("sm_hitmarker", OnHitmarkerSettings);
	RegConsoleCmd("sm_bhm", OnToggleBossHitmarker);
	RegConsoleCmd("sm_zhm", OnToggleZombieHitmarker);
	RegConsoleCmd("sm_hmsound", OnToggleHitmarkerSound);

	SetCookieMenuItem(MenuHandler_CookieMenu, 0, "Hitmarker");

	HookEvent("player_hurt",  OnClientHurt);
}

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public void OnMapStart()
{
	PrecacheGeneric("overlays/nano/hitmarker.vtf", true);
	PrecacheGeneric("overlays/nano/hitmarker.vmt", true);
	AddFileToDownloadsTable("materials/overlays/nano/hitmarker.vtf");
	AddFileToDownloadsTable("materials/overlays/nano/hitmarker.vmt");

	PrecacheSound("unloze/hm_v2.mp3");
	AddFileToDownloadsTable("sound/unloze/hm_v2.mp3");
}

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

	if (sBuffer[0])
		g_bShowBossHitmarker[client] = true;
	else
		g_bShowBossHitmarker[client] = false;

	GetClientCookie(client, g_hCookie_ShowZombieHitmarker, sBuffer, sizeof(sBuffer));

	if (sBuffer[0])
		g_bShowZombieHitmarker[client] = true;
	else
		g_bShowZombieHitmarker[client] = false;

	GetClientCookie(client, g_hCookie_HitmarkerSound, sBuffer, sizeof(sBuffer));

	if (sBuffer[0])
		g_bHitmarkerSound[client] = true;
	else
		g_bHitmarkerSound[client] = false;

	GetClientCookie(client, g_hCookie_HitmarkerSoundVolume, sBuffer, sizeof(sBuffer));

	if (sBuffer[0])
		g_iHitmarkerSoundVolume[client] = 100;
	else
		g_iHitmarkerSoundVolume[client] = StringToInt(sBuffer);
}

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public void OnClientDisconnect(int client)
{
	g_bShowBossHitmarker[client] = false;
	g_bShowZombieHitmarker[client] = false;
	g_bHitmarkerSound[client] = false;
	g_iHitmarkerSoundVolume[client] = 100;
}

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

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

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public void ToggleBossHitmarker(int client)
{
	g_bShowBossHitmarker[client] = !g_bShowBossHitmarker[client];
	SetClientCookie(client, g_hCookie_ShowBossHitmarker, g_bShowBossHitmarker[client] ? "1" : "");

	CPrintToChat(client, "{cyan}[Hitmarker] {white}%s.", g_bShowBossHitmarker[client] ? "Boss Hitmarker Enabled" : "Boss Hitmarker Disabled");
}

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

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public void ToggleZombieHitmarker(int client)
{
	g_bShowZombieHitmarker[client] = !g_bShowZombieHitmarker[client];
	SetClientCookie(client, g_hCookie_ShowZombieHitmarker, g_bShowZombieHitmarker[client] ? "1" : "");

	CPrintToChat(client, "{cyan}[Hitmarker] {white}%s.", g_bShowZombieHitmarker[client] ? "Zombie Hitmarker Enabled" : "Zombie Hitmarker Disabled");
}

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

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public void ToggleHitmarkerSound(int client)
{
	g_bHitmarkerSound[client] = !g_bHitmarkerSound[client];
	SetClientCookie(client, g_hCookie_HitmarkerSound, g_bHitmarkerSound[client] ? "1" : "");

	CPrintToChat(client, "{cyan}[Hitmarker] {white}%s.", g_bHitmarkerSound[client] ? "Hitmarker Sound Enabled" : "Hitmarker Sound Disabled");
}

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public void ToggleHitmarkerSoundVolume(int client)
{
	g_iHitmarkerSoundVolume[client] += 25;

	if(g_iHitmarkerSoundVolume[client] > 100)
		g_iHitmarkerSoundVolume[client] = 25;

	char sBuffer[16];
	IntToString(g_iHitmarkerSoundVolume[client], sBuffer, sizeof(sBuffer));

	SetClientCookie(client, g_hCookie_HitmarkerSoundVolume, sBuffer);

	//CPrintToChat(client, "{cyan}[Hitmarker] {white}Hitmarker Sound Volume: %d\%", g_iHitmarkerSoundVolume[client]);
}

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

	menu.SetTitle("Hitmarker Settings", client);

	char sBuffer[128];

	Format(sBuffer, sizeof(sBuffer), "Boss Hitmarker: %s", g_bShowBossHitmarker[client] ? "Enabled" : "Disabled");
	menu.AddItem("0", sBuffer);

	Format(sBuffer, sizeof(sBuffer), "Zombie Hitmarker: %s", g_bShowZombieHitmarker[client] ? "Enabled" : "Disabled");
	menu.AddItem("1", sBuffer);

	Format(sBuffer, sizeof(sBuffer), "Hitmarker Sound: %s", g_bHitmarkerSound[client] ? "Enabled" : "Disabled");
	menu.AddItem("2", sBuffer);

	Format(sBuffer, sizeof(sBuffer), "Hitmarker Sound Volume: %d\%", g_iHitmarkerSoundVolume[client]);
	menu.AddItem("3", sBuffer);

	menu.ExitBackButton = true;

	menu.Display(client, MENU_TIME_FOREVER);
}

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

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public int MenuHandler_MainMenu(Menu menu, MenuAction action, int client, int selection)
{
	switch(action)
	{
		case(MenuAction_Select):
		{
			switch(selection)
			{
				case(0): ToggleBossHitmarker(client);
				case(1): ToggleZombieHitmarker(client);
				case(2): ToggleHitmarkerSound(client);
				case(3): ToggleHitmarkerSoundVolume(client);
			}

			ShowSettingsMenu(client);
		}
		case(MenuAction_Cancel):
		{
			ShowCookieMenu(client);
		}
		case(MenuAction_End):
		{
			delete menu;
		}
	}
}

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public void OnBossDamaged(CBoss Boss, CConfig Config, int client, float damage)
{
	if (!IsValidClient(client))
		return;

	if (g_bShowBossHitmarker[client])
	{
		//SetHudTextParams(-1.0, -1.0, 0.3, 255, 0, 0, 255, 0, 0.0, 0.0, 0.0);
		//ShowSyncHudText(client, g_hHudText, "∷");
		ShowOverlay(client);
	}

	for (int spec = 1; spec <= MaxClients; spec++)
	{
		if (!IsClientInGame(spec) || !IsClientObserver(spec) || !g_bShowBossHitmarker[spec])
			continue;

		int specMode   = GetClientSpectatorMode(spec);
		int specTarget = GetClientSpectatorTarget(spec);

		if ((specMode == SPECMODE_FIRSTPERSON) && specTarget == client)
		{
			//SetHudTextParams(-1.0, -1.0, 0.3, 255, 0, 0, 255, 0, 0.0, 0.0, 0.0);
			//ShowSyncHudText(spec, g_hHudText, "∷");
			ShowOverlay(spec);
		}
	}
}

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public void OnClientHurt(Event hEvent, const char[] sEvent, bool bDontBroadcast)
{
	int client = GetClientOfUserId(hEvent.GetInt("attacker"));
	int victim = GetClientOfUserId(hEvent.GetInt("userid"));

	if (client < 1 || client > MaxClients || victim < 1 || victim > MaxClients)
		return;

	if (client == victim || (IsPlayerAlive(client) && ZR_IsClientZombie(client)))
		return;

	if (g_bShowZombieHitmarker[client])
	{
		//SetHudTextParams(-1.0, -1.0, 0.3, 255, 0, 0, 255, 0, 0.0, 0.0, 0.0);
		//ShowSyncHudText(client, g_hHudText, "∷");
		ShowOverlay(client);
	}

	for (int spec = 1; spec <= MaxClients; spec++)
	{
		if (!IsClientInGame(spec) || !IsClientObserver(spec) || !g_bShowZombieHitmarker[spec])
			continue;

		int specMode   = GetClientSpectatorMode(spec);
		int specTarget = GetClientSpectatorTarget(spec);

		if (specMode == SPECMODE_FIRSTPERSON && specTarget == client)
		{
			//SetHudTextParams(-1.0, -1.0, 0.3, 255, 0, 0, 255, 0, 0.0, 0.0, 0.0);
			//ShowSyncHudText(spec, g_hHudText, "∷");
			ShowOverlay(spec);
		}
	}

}

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public void ShowOverlay(int client)
{
	if (g_bHitmarkerSound[client])
	{
		float fVolume = g_iHitmarkerSoundVolume[client] / 100.0;
		EmitSoundToClient(client, "unloze/hm_v2.mp3", .volume=fVolume);
	}

	if (g_hTimer[client] != null)
	{
		delete g_hTimer[client];
		g_hTimer[client] = null;
	}
	ClientCommand(client, "r_screenoverlay \"%s\"", "overlays/nano/hitmarker");
	g_hTimer[client] = CreateTimer(0.3, ClearOverlay, client, TIMER_FLAG_NO_MAPCHANGE);
}

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public Action ClearOverlay(Handle timer, int client)
{
	g_hTimer[client] = null;
	ClientCommand(client, "r_screenoverlay \"\"");
}

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
stock int IsValidClient(int client, bool nobots = true)
{
	if (client <= 0 || client > MaxClients || !IsClientConnected(client) || (nobots && IsFakeClient(client)))
		return false;

	return IsClientInGame(client);
}

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
int GetClientSpectatorMode(int client)
{
	return GetEntProp(client, Prop_Send, "m_iObserverMode");
}

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
int GetClientSpectatorTarget(int client)
{
	return GetEntPropEnt(client, Prop_Send, "m_hObserverTarget");
}