// 1 spec
// 2 Ts
// 3 Cts

#include <sourcemod>
#include <sdktools>
#include <cstrike>
//#include <tf2>

#define FADE_IN 0x0001
#define SPEC 1
#define TS 2
#define CTS 3 

new Handle:g_Cvar_round_restart_delay;
new Handle:g_adtClientlist;
new Handle:g_adtPlayers;
new Handle:g_cvar_tbenabled;
new Handle:g_cvar_checkinterval;
//new Handle:g_cvar_balancemethod;
new Handle:g_cvar_adminimmunity;
new Handle:g_cvar_deathmatch;
new Handle:g_cvar_teamdifference;
new g_roundend_counter = 0;
new g_teamT;
new g_teamCT;
new g_diff;

public Plugin:myinfo =
{
	name = "GTS-Team-Balancer",
	author = "FreeZ",
	version = "1.2.2",
	description = "Simple Team-Balancer",
	url = "http://gts-fun.de"
};

public OnPluginStart()
{
	g_cvar_tbenabled = CreateConVar("sm_tbenabled", "1", "Enables the Team-Balancer plugin", 0, true, 0.0, true, 1.0);
	g_cvar_checkinterval = CreateConVar("sm_checkinterval", "1", "team balance after x rounds", 0, true, 1.0, false, 0.0);
	//g_cvar_balancemethod = CreateConVar("sm_balancemethod", "1", "Choose the balance method: 1=Player count 2=Kills per death", 0, true, 1.0, true, 2.0);
	g_cvar_teamdifference = CreateConVar("sm_teamdifference", "2", "Switch when team difference is bigger than or equal x ", 0, true, 2.0, false, 0.0);
	g_cvar_adminimmunity = CreateConVar("sm_adminimmunity", "-1", "Admin immunity Level -1=Disabled", 0, true, -1.0, true, 99.0);
	g_cvar_deathmatch = CreateConVar("sm_deathmatch", "0", "Run Deathmatch on the server? (sm_checkinterval will disabled) 0=Disabled 1=Enabled", 0, true, 0.0, true, 1.0);
	
	HookEvent("round_end", Event_RoundEnd);
	HookEvent("player_death", Event_PlayerDeath);
	g_Cvar_round_restart_delay = FindConVar("mp_round_restart_delay");
	PrintToChatAll("[TB] Team-Balancer is loaded");
	
	AutoExecConfig(true, "plugin.gts_teambalancer");
}

public Event_RoundEnd(Handle:event, const String:name[], bool:dontBroadcast)
{
	// plugin enable check
	if(!GetConVarBool(g_cvar_tbenabled) || GetConVarBool(g_cvar_deathmatch))
	{
		return;
	}
	
	new Float:restart_delay = GetConVarFloat(g_Cvar_round_restart_delay);	
	g_roundend_counter++;
	
	if(GetConVarInt(g_cvar_checkinterval) == g_roundend_counter)
	{
		CreateTimer((restart_delay-0.1), BalanceRound, INVALID_HANDLE);
		g_roundend_counter = 0;
	}
}

public Event_PlayerDeath(Handle:event, const String:name[], bool:dontBroadcast)
{
	if(GetConVarBool(g_cvar_tbenabled) && GetConVarBool(g_cvar_deathmatch))
	{
		new client = GetClientOfUserId(GetEventInt(event, "userid"));
	
		BalanceDeath(client);
	}
}

public bool:TeamDifference()
{
	g_teamT = GetTeamClientCount(TS);
	g_teamCT = GetTeamClientCount(CTS);
	g_diff = g_teamT - g_teamCT;
	
	if (g_diff < 0)
	{
		g_diff = -g_diff;
	}
	
	
	if(g_diff >= GetConVarInt(g_cvar_teamdifference))
	{
		if(GetConVarBool(g_cvar_deathmatch))
		{
		g_diff = 2;
		return true;
		}
		g_diff = RoundToFloor(Float:(g_diff/2.0)+1);
		return true;
	}
	return false;
}

public bool:BalanceDeath(client)
{
	g_adtPlayers = CreateArray(3);
	
	if (!TeamDifference())
	{
		return;
	}
	
	if(g_teamT > (g_teamCT + 1))
	{
		if (IsClientInGame(client) && IsClientConnected(client) && (GetClientTeam(client) == TS) && !isimmune(client))
		{
			PushArrayCell(g_adtPlayers, client);
			switcher(0, 0, 255, 255, FADE_IN, CTS);
		}
	}
	
	if (g_teamCT > (g_teamT + 1))
	{
		if (IsClientInGame(client) && IsClientConnected(client) && (GetClientTeam(client) == CTS) && !isimmune(client))
		{
			PushArrayCell(g_adtPlayers, client);
			switcher(255, 0, 0, 255, FADE_IN, TS);
		}
	}
}

public Action:BalanceRound(Handle:timer)
{
	if (!TeamDifference())
	{
		return;
	}
	
	g_adtClientlist = CreateArray(3);
	g_adtPlayers = CreateArray(3);
	
	if (g_teamT > (g_teamCT + 1))
	{
		if (GetTeamClientCount(TS) > 0)
		{
			//Clientliste erstellen
			for (new i = 1; i <= MaxClients; i++)
			{
				if (IsClientInGame(i) && IsClientConnected(i) && (GetClientTeam(i) == TS) && !isimmune(i))
				{
					PushArrayCell(g_adtClientlist, i);
				}
			}
			clientuebergeber();
		}
		switcher(0, 0, 255, 255, FADE_IN, CTS);
	}
	
	if (g_teamCT > (g_teamT + 1))
	{
		if (GetTeamClientCount(CTS) > 0)
		{
			//Clientliste erstellen
			for (new i = 1; i <= MaxClients; i++)
			{
				if (IsClientInGame(i) && IsClientConnected(i) && (GetClientTeam(i) == CTS) && !isimmune(i))
				{
					PushArrayCell(g_adtClientlist, i);
				}
			}
			clientuebergeber();
		}
		switcher(255, 0, 0, 255, FADE_IN, TS);
	}
}

public Action:clientuebergeber()
{
	new randomnumber;
	
	if (GetArraySize(g_adtClientlist)+1 < g_diff)
	{
		g_diff = GetArraySize(g_adtClientlist)+1;
	}

	//Switch-Clientliste erstellen
	for (new j=1; j<g_diff; j++)
	{
		randomnumber = GetRandomInt(0, GetArraySize(g_adtClientlist)-1);
		PushArrayCell(g_adtPlayers, GetArrayCell(g_adtClientlist, randomnumber));
		RemoveFromArray(g_adtClientlist, randomnumber);
	}

}

public Action:switcher(red, green, blue, alpha, type, newteam)
{
	new Handle:msg;
	new duration = 0;
	decl String:gameName[80];
	GetGameFolderName(gameName, 80);
		
	for (new i=1; i<g_diff; i++)
	{
		CS_SwitchTeam(GetArrayCell(g_adtPlayers, i-1), newteam);
		//ChangeClientTeam(GetArrayCell(g_adtPlayers, i-1), newteam);
		
		PrintCenterText(GetArrayCell(g_adtPlayers, i-1), "ACHTUNG: Du bist nun im anderen Team!")
		
		msg = StartMessageOne("Fade", GetArrayCell(g_adtPlayers, i-1));
		BfWriteShort(msg, 500);
		BfWriteShort(msg, duration);
		BfWriteShort(msg, type);
		BfWriteByte(msg, red);
		BfWriteByte(msg, green);
		BfWriteByte(msg, blue);
		BfWriteByte(msg, alpha);
		EndMessage();
	}
	
	if(!GetConVarBool(g_cvar_deathmatch))
	{
		ClearArray(g_adtClientlist);
	}
	ClearArray(g_adtPlayers);
}

bool:isimmune (target)
{
	new immunity = GetConVarInt(g_cvar_adminimmunity);

	if (immunity > -1)
	{
		new AdminId:admin = GetUserAdmin(target);

		if (admin != INVALID_ADMIN_ID)
		{
			return GetAdminImmunityLevel(admin) >= immunity;
		}
	}
	return false;
}