Raised This Month: $51 Target: $400
 12% 

[Incomplete Plugin] Simple Team Balancer


Post New Thread Reply   
 
Thread Tools Display Modes
Author Message
FlyingMongoose
Veteran Member
Join Date: Mar 2004
Old 02-03-2009 , 06:24   [Incomplete Plugin] Simple Team Balancer
Reply With Quote #1

This was a simple team balancer that I'm most likely never going to complete as well. The idea behind the balancing algorithm is averages in score differences.

It also tries to truly enforce randomization of teams, if force auto-assign is enabled it allows the player to select any team, but ultimately forces them to a team based on what team would result in them being number balanced.

This also enforces players REMAIN on their assigned teams

This can also enforce a map change to next map in mapcycle if the win difference is too high

Planned features:
Admin immunity
a "buddy feature" (similar to antithysis' simple team balancer)
Upgrade to win difference so as to include "rounds in a row won" as well.

Note: This is currently fairly bugged and is not perfect, but certain features do work.

Code:
#pragma semicolon 1
#pragma dynamic 65536

#include <sourcemod>
#include <cstrike>
#include <sdktools>

#define DEFAULTCOLOR 0x01
#define GREEN 0x04
#define FMTB_VERSION "1.0.0"

public Plugin:myinfo = 
{
	name = "FlyingMongoose's Team Balancer",
	author = "FlyingMongoose",
	description = "Team Balancer for Counter-Strike: Source",
	version = FMTB_VERSION,
	url = "http://www.interwavestuiods.com/"
}

new Handle:cvarForceAutoAssign;
new Handle:cvarRoundDifferenceBalance;
new Handle:cvarEnforceTeam;
new Handle:cvarWinDiffMapChange;

new iPlayersTeam[MAXPLAYERS + 1];
new iLastBalanced[4];
new iMaxClients;

new RoundStartTime;

public OnPluginStart()
{
	CreateConVar("fmtb_version",FMTB_VERSION, _,FCVAR_PLUGIN|FCVAR_NOTIFY|FCVAR_REPLICATED|FCVAR_SPONLY);
	cvarForceAutoAssign = CreateConVar("fmtb_forceautoassign","1","Turns force auto assign on or off",FCVAR_PLUGIN,true,0.0,true,1.0);
	cvarRoundDifferenceBalance = CreateConVar("fmtb_rounddifference","3","The difference in score between teams for a balance to occur. Setting to 0 disables the balancer.",FCVAR_PLUGIN,true,0.0,false);
	cvarEnforceTeam = CreateConVar("fmtb_enforceteam","1","Enforces player stay on the team they were either balanced to or auto-assigned to",FCVAR_PLUGIN,true,0.0,true,1.0);
	cvarWinDiffMapChange = CreateConVar("fmtb_windifferencemapchange","8","Number of wins difference before a map will change.",FCVAR_PLUGIN,true,0.0,false);
	HookEvent("player_team",ev_PlayerTeam,EventHookMode_Post);
	HookEvent("round_end",ev_RoundEnd,EventHookMode_Post);
	HookEvent("round_start",ev_RoundStart,EventHookMode_Pre);
}

public OnMapStart()
{
	iMaxClients = GetMaxClients();
}

public OnMapEnd()
{
	for(new i = 0; i <= iMaxClients; i++) {
		iPlayersTeam[i] = 0;
	}
}

public OnClientDisconnect_Post(client)
{
	if (iLastBalanced[iPlayersTeam[client]] == client)
		iLastBalanced[iPlayersTeam[client]] = 0;
	iPlayersTeam[client] = 0;
	
}

public OnConfigsExecuted()
{
	AutoExecConfig(true,"fmtb","sourcemod");
}
public Action:Timer_DelayMapChange(Handle:timer, Handle:NextMapPack)
{
	decl String:NextMap[255];
	ResetPack(NextMapPack,false);
	ReadPackString(NextMapPack,NextMap,sizeof(NextMap));
	ServerCommand("changelevel %s",NextMap);
}

public Action:ev_RoundEnd(Handle:event, const String:name[], bool:dontBroadcast)
{
	new CTScore = GetTeamScore(CS_TEAM_CT);
	new TScore = GetTeamScore(CS_TEAM_T);
	new scoreDiff = RoundFloat(FloatAbs(float(CTScore - TScore)));
	new winDiffMapChange = GetConVarInt(cvarWinDiffMapChange);
	if(winDiffMapChange > 0)
	{
		if(scoreDiff >= winDiffMapChange)
		{
			decl String:NextMap[255];
			GetNextMap(NextMap,sizeof(NextMap));
			PrintToChatAll("%c[FMTB]%c The score difference is too high, the map is changing in 5 seconds.",GREEN,DEFAULTCOLOR);
			new Handle:NextMapPack = CreateDataPack();
			WritePackString(NextMapPack,NextMap);
			CreateTimer(5.0,Timer_DelayMapChange,NextMapPack);
		}
	}
	new scoreDiffBal = GetConVarInt(cvarRoundDifferenceBalance);
	if(scoreDiffBal > 0)
	{	
		if (CTScore + TScore != 0)
		{
			if (scoreDiff >= scoreDiffBal) {
				new winningteam, losingteam;
				if (CTScore > TScore) {
					winningteam = CS_TEAM_CT;
					losingteam = CS_TEAM_T;
				} else {
					winningteam = CS_TEAM_T;
					losingteam = CS_TEAM_CT;
				}
				new balanceWPlayer = FindScoreDifference(winningteam, true);
				new balanceLPlayer = FindScoreDifference(losingteam, false);
				if (balanceWPlayer != 0 && balanceLPlayer !=0) {
					iPlayersTeam[balanceLPlayer] = winningteam;
					iPlayersTeam[balanceWPlayer] = losingteam;
					iLastBalanced[losingteam] = balanceWPlayer;
					iLastBalanced[winningteam] = balanceLPlayer;
					if(iPlayersTeam[balanceWPlayer] == CS_TEAM_CT)
					{
						GetPlayerWeaponSlot(balanceWPlayer,5);
						ClientCommand(balanceWPlayer,"slot5; wait; slot5; wait; slot5; wait; drop");
					}
					CS_SwitchTeam(balanceWPlayer, iPlayersTeam[balanceWPlayer]);
					if(iPlayersTeam[balanceLPlayer] == CS_TEAM_CT)
					{
						GetPlayerWeaponSlot(balanceLPlayer,5);
						ClientCommand(balanceLPlayer,"slot5; wait; slot5; wait; slot5; wait; drop");
					}
					CS_SwitchTeam(balanceLPlayer, iPlayersTeam[balanceLPlayer]);
					PrintToChat(balanceWPlayer,"%c[FMTB]%c You have been balanced to the other team.",GREEN,DEFAULTCOLOR);
					PrintToChat(balanceLPlayer,"%c[FMTB]%c You have been balanced to the other team.",GREEN,DEFAULTCOLOR);
				}
			}
		}
	}
	new CTCount = GetTeamClientCount(CS_TEAM_CT);
	new TCount = GetTeamClientCount(CS_TEAM_T);
	new playerDifferences = RoundFloat(FloatAbs(float(CTCount - TCount)));
	if(playerDifferences >= 2)
	{
		if(CTCount < TCount)
		{
			for(new i = 1; i <= iMaxClients; i++)
			{
				if(CTCount == TCount || CTCount == TCount + 1 || CTCount == TCount - 1)
				{
					break;
				}
				if(i != 0 && IsClientConnected(i) && IsClientInGame(i) && CS_TEAM_T == GetClientTeam(i))
				{
					iPlayersTeam[i] = CS_TEAM_T;
					PrintToChat(i,"%c[FMTB]%c You have been balanced to the other team.",GREEN,DEFAULTCOLOR);
					CS_SwitchTeam(i,CS_TEAM_T);
				}
			}
		}
		if(CTCount > TCount)
		{
			for(new i = 1; i <= iMaxClients; i++)
			{
				if(CTCount > TCount)
				{
					if(CTCount == TCount || CTCount == TCount + 1 || CTCount == TCount - 1)
					{
						break;
					}
					if(i != 0 && IsClientConnected(i) && IsClientInGame(i) && CS_TEAM_CT == GetClientTeam(i)){
						GetPlayerWeaponSlot(i,5);
						ClientCommand(i,"slot5; wait; slot5; wait; slot5; wait; drop");
						PrintToChat(i,"%c[FMTB]%c You have been balanced to the other team.",GREEN,DEFAULTCOLOR);
						CS_SwitchTeam(i,CS_TEAM_CT);	
					}
				}
			}
		}
	}
}

public Action:ev_PlayerTeam(Handle:event,const String:name[],bool:dontBroadcast)
{
	new client = GetClientOfUserId(GetEventInt(event,"userid"));
	if (client != 0 && !IsClientConnected(client) && !IsClientInGame(client))
		return Plugin_Handled;
	new team = GetEventInt(event,"team");
	if (team <= 1)
		return Plugin_Continue;
	if (iPlayersTeam[client] == 0 && GetConVarInt(cvarForceAutoAssign) == 1 && iLastBalanced[CS_TEAM_CT] != client && iLastBalanced[CS_TEAM_T] != client) {
		CreateTimer(0.5, Timer_DelaySelectTeam, client, TIMER_FLAG_NO_MAPCHANGE);
		PrintToChat(client,"%c[FMTB]%c You have been force auto-assigned.",GREEN,DEFAULTCOLOR);
		return Plugin_Continue;
	}
	if (iPlayersTeam[client] != team && GetConVarInt(cvarEnforceTeam) == 1 &&  iLastBalanced[CS_TEAM_CT] != client && iLastBalanced[CS_TEAM_T] != client) {
		CreateTimer(0.5, Timer_DelaySwitchTeam, client, TIMER_FLAG_NO_MAPCHANGE);
		PrintToChat(client,"%c[FMTB]%c You are not allowed to change teams.",GREEN,DEFAULTCOLOR);
		return Plugin_Continue;
	}
	return Plugin_Continue;
}

public Action:ev_RoundStart(Handle:event, const String:name[], bool:dontBroadcast)
{
	RoundStartTime = GetTime();
}

public Action:Timer_DelaySelectTeam(Handle:timer, any:client)
{
	iPlayersTeam[client] = SelectTeam();
	if(iPlayersTeam[client] < 0){
		if(RoundFloat(float(GetTime() - RoundStartTime)) > 45)
		{
			CreateTimer(0.5,Timer_DelayRespawn,client);
		}
		if(iPlayersTeam[client] == CS_TEAM_CT)
		{
			GetPlayerWeaponSlot(client,5);
			ClientCommand(client,"slot5; wait; slot5; wait; slot5; wait; drop");
		}
		CS_SwitchTeam(client, iPlayersTeam[client]);
	}
	return Plugin_Handled;
}


public Action:Timer_DelayRespawn(Handle:timer, any:client)
{
	CS_RespawnPlayer(client);
}

public Action:Timer_DelaySwitchTeam(Handle:timer, any:client)
{
	if(iPlayersTeam[client] == CS_TEAM_CT)
	{
		new bombIndex = GetPlayerWeaponSlot(client,5);
		if(bombIndex > -1)
		{
			EquipPlayerWeapon(client,bombIndex);
			ClientCommand(client,"slot5; wait; slot5; wait; slot5; wait; drop");
		}
	}
	CS_SwitchTeam(client, iPlayersTeam[client]);
	iLastBalanced[iPlayersTeam[client]] = 0;
	return Plugin_Handled;
}

stock SelectTeam()
{
	new CTCount = GetTeamClientCount(CS_TEAM_CT);
	new TCount = GetTeamClientCount(CS_TEAM_T);
	new Team = 0;
	if(CTCount == TCount){
		Team = -1;
	} else if (CTCount > TCount){
		Team = CS_TEAM_T;
	} else if (CTCount < TCount){
		Team = CS_TEAM_CT;
	} else {
		Team = GetRandomInt(CS_TEAM_T, CS_TEAM_CT);
	}
	return Team;
}

stock FindScoreDifference(teamIndex,bool:isLowest)
{
	new currClientDiff;
	new lastClientDiff = 0;
	new client = 0;
	new teamavg = GetTeamAverage(teamIndex);
	if(teamavg != 0){
		if(isLowest) {
			for(new i = 1; i <= iMaxClients; i++) {
				if(IsClientInGame(i) 
				&& GetClientTeam(i) == teamIndex) {
					currClientDiff = GetClientFrags(i) - GetClientDeaths(i);
					if(currClientDiff <= teamavg
					&& currClientDiff <= lastClientDiff 
					&& iLastBalanced[CS_TEAM_CT] != i 
					&& iLastBalanced[CS_TEAM_T] != i) {
						lastClientDiff = GetClientFrags(i) - GetClientDeaths(i);
						client = i;
					}
				}
			}
		} else if(!isLowest){
			for(new i = 1; i <= iMaxClients; i++){
				if(IsClientInGame(i) 
				&& GetClientTeam(i) == teamIndex) {
					currClientDiff = GetClientFrags(i) - GetClientDeaths(i);
					if(currClientDiff >= teamavg 
					&& currClientDiff >= lastClientDiff 
					&& iLastBalanced[CS_TEAM_CT] != i 
					&& iLastBalanced[CS_TEAM_T] != i) {
						lastClientDiff = GetClientFrags(i) - GetClientDeaths(i);
						client = i;
					}
				}
			}
		}
		iLastBalanced[teamIndex] = client;
		return client;
	}else{
		return 0;
	}
	
}

stock GetTeamAverage(teamIndex)
{
	new ScoreCount;
	for(new i = 1; i <= iMaxClients; i++) {
		if(IsClientInGame(i) && GetClientTeam(i) == teamIndex) {
			ScoreCount = (GetClientFrags(i) - GetClientDeaths(i)) + ScoreCount;
		}
	}
	new teamCount = GetTeamClientCount(teamIndex);
	if(teamCount > 0){
		new AverageScore = ScoreCount/GetTeamClientCount(teamIndex);
		return AverageScore;
	}else{
		return 0;
	}
}
I will not provide tech support for this, however I will provide support in the form of answers to questions provided by whomever wishes to pick up where I left off.
__________________
Please do NOT PM for support.

Only ask for support in plugin threads.

TunedChaos.com - Precision Tuned Game Servers
FlyingMongoose is offline
FlyingMongoose
Veteran Member
Join Date: Mar 2004
Old 02-04-2009 , 00:04   Re: [Incomplete Plugin] Simple Team Balancer
Reply With Quote #2

On a note, please credit myself and Antithysis if you use this code base.
__________________
Please do NOT PM for support.

Only ask for support in plugin threads.

TunedChaos.com - Precision Tuned Game Servers
FlyingMongoose is offline
Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -4. The time now is 09:01.


Powered by vBulletin®
Copyright ©2000 - 2024, vBulletin Solutions, Inc.
Theme made by Freecode