Skip to content

Instantly share code, notes, and snippets.

@kimoto
Created August 23, 2010 19:05
Show Gist options
  • Save kimoto/546095 to your computer and use it in GitHub Desktop.
Save kimoto/546095 to your computer and use it in GitHub Desktop.
//
// Name: auto team balance plugin
// History:
// ver0.3:
// refactoring:
// cleanup source code
// ver0.2:
// make base routines
// ver0.1:
// first edit
//
#include <sourcemod>
#include <adt_array>
#define PLUGIN_VERSION "0.1"
#define TEAM_SPECTATE 1
#define TEAM_SURVIVOR 2
#define TEAM_INFECTED 3
#define MIN_PLAYER_SIZE 0
#define MAX_PLAYER_SIZE 32
#define PLUGIN_FILENAME "autoteambalance"
#define ARRAY_SIZE 50
#define ESCAPE_LOOP_COUNT 20
new Handle:g_hEnable = INVALID_HANDLE;
new Handle:g_hDebug = INVALID_HANDLE;
new Handle:g_hSelectKey = INVALID_HANDLE;
new bool:g_bEnable = true;
new bool:g_bDebug = true;
new g_iSelectKey = 0;
public Plugin:myinfo =
{
name = "auto team balance",
author = "kimoto",
description = "auto team balance plugin",
version = PLUGIN_VERSION,
url = ""
}
public OnPluginStart()
{
RegConsoleCmd("autobalance", Command_AutoBalance)
RegConsoleCmd("debug_autobalance", Command_DebugAutoBalance)
}
public OnMapStart()
{
AutoBalance(0);
}
public AutoBalance(client)
{
PrintToConsole(client, "******* do autobalance!!");
new Handle:players = INVALID_HANDLE; // dynamic array
new Handle:survivors = INVALID_HANDLE;
new Handle:infected = INVALID_HANDLE;
new Handle:spectators = INVALID_HANDLE;
players = CreateArray(ARRAY_SIZE);
survivors = CreateArray(ARRAY_SIZE);
infected = CreateArray(ARRAY_SIZE);
spectators = CreateArray(ARRAY_SIZE);
// calc all players
for(new i=1; i<=GetMaxClients(); i++)
{
// ingame and not bot player
if(IsClientInGame(i) && !IsClientBot(i))
{
PushArrayCell(players, i);
if(GetClientTeam(i) == TEAM_INFECTED)
{
// infected player
PushArrayCell(infected, i);
}else if(GetClientTeam(i) == TEAM_SURVIVOR)
{
// survivor player
PushArrayCell(survivors, i);
}else if(GetClientTeam(i) == TEAM_SPECTATE)
{
// spectate player
PushArrayCell(spectators, i);
}else{
DebugPrint("-------- not implemented code: %d", GetClientTeam(i));
}
}
}
DebugPrint("players: %d", GetArraySize(players));
DebugPrint("survivors: %d", GetArraySize(survivors));
DebugPrint("infected: %d", GetArraySize(infected));
DebugPrint("spectators: %d", GetArraySize(spectators));
// validate min players
//if(GetArraySize(players) <= MIN_PLAYER_SIZE)
// return false;
// execute autobalance core
AutoBalanceCore(client, players, survivors, infected, spectators);
return true; // success;
}
public AutoBalanceCore(client, players, survivors, infected, spectators)
{
// min check
if( GetArraySize(players) <= MIN_PLAYER_SIZE )
{
DebugPrint("not auto-balanced: players(%d) <= MIN_PLAYER_SIZE(%d)", GetArraySize(players), MIN_PLAYER_SIZE);
return false;
}
new Handle:active_players = CreateArray(ARRAY_SIZE);
new Handle:purpose_survivors = CreateArray(ARRAY_SIZE);
new Handle:purpose_infected = CreateArray(ARRAY_SIZE);
// make active players list
for(new i=0; i<GetArraySize(survivors); i++)
{
PushArrayCell(active_players, GetArrayCell(survivors, i));
}
for(new i=0; i<GetArraySize(infected); i++)
{
PushArrayCell(active_players, GetArrayCell(infected, i));
}
DebugPrint("shuffle array");
inspect( ShuffleArray(active_players) );
DebugPrint("######### active players");
inspect(active_players);
new total_size = GetArraySize(active_players)
new half_size = total_size / 2;
for(new i=0; i<total_size; i++)
{
if(0 <= i && i< half_size)
{
PushArrayCell(purpose_survivors, GetArrayCell(active_players, i));
}
else
{
PushArrayCell(purpose_infected, GetArrayCell(active_players, i));
}
}
DebugPrint("************* purpose");
inspect(purpose_survivors);
inspect(purpose_infected);
// stay survivor players
new Handle:need_players = ArraySubtraction(purpose_survivors, survivors);
// go away survivor players
new Handle:not_need_players = ArraySubtraction(survivors, purpose_survivors);
DebugPrint("*************** array sub");
inspect( need_players );
inspect( not_need_players );
new n = 0;
// auto balance core loop
while(true)
{
// end condition
if(GetArraySize(need_players) == 0 && GetArraySize(not_need_players) == 0)
{
break;
}
if(n > ESCAPE_LOOP_COUNT){
DebugPrint("******** emergency escape routine");
break;
}
// pickup not need player one
new not_need_player = ArrayShift(not_need_players);
if(not_need_player != -1)
{
DebugPrint("# not need player going spectator");
FindRemoveValueInArray(survivors, not_need_player);
// TODO: change team to spectator
ChangeClientTeamWrapper(not_need_player, TEAM_SPECTATE);
PushArrayCell(spectators, not_need_player);
//inspect(survivors);
}
// pickup need player one, please come here survivor from infected
new need_player = ArrayShift(need_players);
if(need_player != -1)
{
DebugPrint("# need player going survivor");
PushArrayCell(survivors, need_player);
FindRemoveValueInArray(infected, need_player);
// TODO: change team to survivor
ChangeClientTeamWrapper(need_player, TEAM_SURVIVOR);
}
// not need player(tmp spectator -> to -> infected)
if(not_need_player != -1)
{
DebugPrint("# go tmp spectator to infected");
PushArrayCell(infected, not_need_player);
FindRemoveValueInArray(spectators, not_need_player);
// TODO: change team to infected
ChangeClientTeamWrapper(not_need_player, TEAM_INFECTED);
}
n++;
}
// result debug print
DebugPrint("***survivors");
inspect(survivors);
DebugPrint("***infected");
inspect(infected);
DebugPrint("***spectators");
inspect(spectators);
}
public Action:Command_AutoBalance(client, args)
{
AutoBalance(client);
}
#define INSPECT_BUFFER_SIZE 512
#define INSPECT_VALUE_BUFFER_SIZE 256
public inspect(array)
{
decl String:buffer[INSPECT_BUFFER_SIZE] = "";
for(new i=0; i<GetArraySize(array); i++)
{
decl String:value[INSPECT_VALUE_BUFFER_SIZE] = "";
IntToString(GetArrayCell(array, i), value, sizeof(value));
StrCat(buffer, INSPECT_BUFFER_SIZE, value);
StrCat(buffer, INSPECT_BUFFER_SIZE, ",");
}
DebugPrint(buffer);
}
public ShuffleArray(array)
{
new N = GetArraySize(array);
for(new i=1; i<N; i++)
{
//new a = GetRandomInt(0, i + 1);
new a = GetRandomInt(0, i);
// swap
new iValue = GetArrayCell(array, i);
new aValue = GetArrayCell(array, a);
SetArrayCell(array, i, aValue);
SetArrayCell(array, a, iValue);
}
return array;
}
// array subtraction
// return is a - b
public ArraySubtraction(a, b)
{
new Handle:subArray = CreateArray(ARRAY_SIZE);
for(new i=0; i<GetArraySize(a); i++)
{
new bool:bExist = false;
// ikko mo itti sinakattara subtraction array ni ireru
for(new j=0; j<GetArraySize(b); j++)
{
if(GetArrayCell(a, i) == GetArrayCell(b, j)) bExist = true;
}
// ikko demo itti sita toiu koto!
if(bExist == false)
{
PushArrayCell(subArray, GetArrayCell(a, i));
}
}
return subArray;
}
public ArrayShift(a)
{
if(GetArraySize(a) == 0)
return -1;
new value = GetArrayCell(a, 0);
RemoveFromArray(a, 0);
return value;
}
public FindRemoveValueInArray(array, value)
{
// find and remove value
new target = FindValueInArray(array, value);
new removed_value = GetArrayCell(array, target);
RemoveFromArray(array, target);
return removed_value;
}
public ChangeClientTeamWrapper(client, team)
{
DebugPrint("change client team ->: %d", team);
if(IsClientInGame(client))
ChangeClientTeam(client, team);
}
public Action:Command_DebugAutoBalance(client, args)
{
// nise no steam id jyouhou tokawo kisai sita test data
new Handle:players = INVALID_HANDLE; // dynamic array
new Handle:survivors = INVALID_HANDLE;
new Handle:infected = INVALID_HANDLE;
new Handle:spectators = INVALID_HANDLE;
players = CreateArray(ARRAY_SIZE);
survivors = CreateArray(ARRAY_SIZE);
infected = CreateArray(ARRAY_SIZE);
spectators = CreateArray(ARRAY_SIZE);
PushArrayCell(players, 1);
PushArrayCell(players, 2);
PushArrayCell(players, 3);
PushArrayCell(players, 4);
PushArrayCell(players, 5);
PushArrayCell(players, 6);
PushArrayCell(players, 7);
PushArrayCell(players, 8);
PushArrayCell(players, 9);
PushArrayCell(players, 10);
PushArrayCell(players, 11);
PushArrayCell(players, 12);
PushArrayCell(survivors, 1);
PushArrayCell(survivors, 2);
PushArrayCell(survivors, 3);
PushArrayCell(survivors, 4);
PushArrayCell(infected, 5);
PushArrayCell(infected, 6);
PushArrayCell(infected, 7);
PushArrayCell(infected, 8);
PushArrayCell(spectators, 9);
PushArrayCell(spectators, 10);
PushArrayCell(spectators, 11);
PushArrayCell(spectators, 12);
/*
DebugPrint("====== array test");
DebugPrint("return: %d", ArrayShift(survivors));
DebugPrint("return: %d", ArrayShift(survivors));
DebugPrint("return: %d", ArrayShift(survivors));
DebugPrint("return: %d", ArrayShift(survivors));
DebugPrint("return: %d", ArrayShift(survivors));
*/
inspect(survivors);
// execute autobalance core
AutoBalanceCore(client, players, survivors, infected, spectators);
}
#define MAX_LINE_WIDTH 64
public IsClientBot(client)
{
decl String:SteamID[MAX_LINE_WIDTH];
GetClientAuthString(client, SteamID, sizeof(SteamID));
if (StrEqual(SteamID, "BOT"))
return true;
return false;
}
#define DEBUG_PRINT_BUFFER_SIZE 128
public DebugPrint(const String:Message[], any:...)
{
if (g_bDebug)
{
decl String:DebugBuff[DEBUG_PRINT_BUFFER_SIZE];
VFormat(DebugBuff, sizeof(DebugBuff), Message, 2);
LogMessage(DebugBuff);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment