#pragma semicolon 1

#define PLUGIN_AUTHOR "null138"
#define PLUGIN_VERSION "3.00"

#include <sourcemod>
#include <sdktools>
#include <clientprefs>

#pragma newdecls required

int iTracerTableID = -1, icvRandom;
Handle hCookieDisabled;
bool bDisabled[MAXPLAYERS + 1] = {false, ...};

public Plugin myinfo = 
{
	name = "Bullet Tracers like on CS:GO/HL2",
	author = PLUGIN_AUTHOR,
	description = "Unlocks game effect",
	version = PLUGIN_VERSION,
	url = "https://steamcommunity.com/id/null138/"
};

public void OnPluginStart()
{
	ConVar cvar;
	cvar = CreateConVar("bullet_tracer_random", "0", "1 = Enable random appearance. 0 = Tracer appears for every shoot");
	icvRandom = cvar.IntValue;
	cvar.AddChangeHook(CVAR_RANDOM_ENABLED);
	AutoExecConfig(true);
	
	RegConsoleCmd("sm_tracers", cmdTracers);
	
	// weapon_fire event is poor choice to use here
	HookEvent("bullet_impact", OnBulletImpact);
	
	hCookieDisabled = RegClientCookie("hl2tracer_disabled", "Tracers Disabled", CookieAccess_Protected);
}

public void CVAR_RANDOM_ENABLED(ConVar cvar, const char[] oldValue, const char[] newValue)
{
	icvRandom = cvar.IntValue;
}

public void OnMapStart()
{
	// Unlock the effect
	int tableId = FindStringTable("EffectDispatch");
	LockStringTables(false);
	AddToStringTable(tableId, "Tracer");
	LockStringTables(true);
	
	// Simply can be used as index 1, but this is in case if any other effects also unlocked in StringTable.
	iTracerTableID = FindStringIndex(FindStringTable("EffectDispatch"), "Tracer");
}

public void OnClientCookiesCached(int client)
{
	char buffer[2];
	GetClientCookie(client, hCookieDisabled, buffer, 2);
	bDisabled[client] = view_as<bool>(StringToInt(buffer));
}

public Action cmdTracers(int client, int args)
{
	if(IsClientInGame(client))
	{
		bDisabled[client] = !bDisabled[client];
		PrintToChat(client, "\x03 Tracers %sabled", bDisabled[client] ? "dis" : "en");
		SetClientCookie(client, hCookieDisabled, bDisabled[client] ? "1" : "0");
	}
	return Plugin_Handled;
}

public void OnBulletImpact(Event event, const char[] name, bool broadCast)
{
	if(icvRandom && GetRandomInt(0, 1) != 0) return;
	
	int client = GetClientOfUserId(event.GetInt("userid"));

	float startPos[3], endPos[3];
	GetWeaponShootPosition(client, startPos);

	endPos[0] = event.GetFloat("x");
	endPos[1] = event.GetFloat("y");
	endPos[2] = event.GetFloat("z");

	TE_Start("EffectDispatch");
	
	TE_WriteNum("m_iEffectName", iTracerTableID);	
	TE_WriteFloat("m_vStart[0]", startPos[0]);
	TE_WriteFloat("m_vStart[1]", startPos[1]);
	TE_WriteFloat("m_vStart[2]", startPos[2]);
	TE_WriteFloat("m_vOrigin[0]", endPos[0]);
	TE_WriteFloat("m_vOrigin[1]", endPos[1]);
	TE_WriteFloat("m_vOrigin[2]", endPos[2]);
	TE_WriteFloat("m_flScale", 5000.0);
	TE_WriteNum("m_fFlags", 8);
	
	int[] clients = new int[MAXPLAYERS];
	int numClients;
	for(int i = 1; i <= MaxClients; i++)
	{
		if(IsClientInGame(i) && !IsFakeClient(i) && !bDisabled[i]) clients[numClients++] = i;
	}
	
	TE_Send(clients, numClients);
}

void GetWeaponShootPosition(int client, float shootPos[3])
{
	float eyePos[3], eyeAng[3], tempPos[3];
	
	GetClientEyePosition(client, eyePos);
	GetClientEyeAngles(client, eyeAng);
	
	GetAngleVectors(eyeAng, tempPos, NULL_VECTOR, NULL_VECTOR);
	ScaleVector(tempPos, 50.0);
	AddVectors(eyePos, tempPos, shootPos);
	GetAngleVectors(eyeAng, NULL_VECTOR, tempPos, NULL_VECTOR);
	NegateVector(tempPos);
	ScaleVector(tempPos, -11.0);
	
	shootPos[2] -= 7.0;
	
	AddVectors(shootPos, tempPos, shootPos);
} 