Team Game 2.0

NOT IN THE MANGA™
★ Black Lounger ★
✔️ HL Verified
🚂 Steam Linked
💻 Oldtimer
Joined
Jan 5, 2008
Messages
3,276
Best answers
0
Location
Lithuania
Team Game 2.1

Version 2.1 seems to work flawlessly.

Description:
It's an addon for Earth's Special Forces 1.2.3's Teamplay game mode. Here you are unable to choose your team yourself - it is chosen for you automatically to balance the game. Whenever you kill your opponent, opponent's team is instantly changed to match yours - that means you get one additional teammate. The same happens to you when you die - you're moved into your killer's team. The game ends when there are no players in one of the teams. Then a 10-second cooldown appears to get ready for the teams to be balanced (randomly) and the game to start again.​

Notes:
  • There is a 10-second cooldown between team changes (it's hardcoded into ESF's engine and I can't do anything about it)
  • Server's CVAR mp_gamemode must be set to "1" (Teamplay)
Source:
Code:
#include <amxmodx>
#include <engine>
#include <hamsandwich>

#define TEAM_GOOD 1
#define TEAM_EVIL 2

new g_Countdown, g_MaxPlayers, bool:g_PutInServer[33] = {true, ...};

public plugin_init()
{
	register_plugin("Team Game", "2.0 Fix", "hleV");

	new const TeamCommands[][] =
	{
		"change_team",
		"jointeam"
	};

	new const ClassCommands[][] =
	{
		"change_class",
		"buu",
		"goku",
		"gohan",
		"krillin",
		"frieza",
		"piccolo",
		"trunks",
		"vegeta",
		"cell",
		"randompc"
	};

	new Item;

	for (Item = 0; Item < sizeof(TeamCommands); Item++)
		register_clcmd(TeamCommands[Item], "ChangeTeam");

	for (Item = 0; Item < sizeof(ClassCommands); Item++)
		register_clcmd(ClassCommands[Item], "ChangeClass");

	register_message(get_user_msgid("VGUIMenu"), "VGUIMenu");

	RegisterHam(Ham_Killed, "player", "Killed", 1);

	g_MaxPlayers = get_maxplayers();
}

public plugin_cfg()
{
	server_cmd("allow_spectators 0");
	server_cmd("mp_friendlyfire 0");
	server_cmd("mp_forcerespawn 1");
	server_cmd("mp_spawn_invulnerable_time 0");
}

public client_putinserver(Client)
	TG_ChooseTeam(Client);

public client_disconnect(Client)
{
	g_PutInServer[Client] = true;

	set_task(0.1, "CheckPlayers");
}

public client_kill(Client)
	return PLUGIN_HANDLED;

public ChangeTeam(Client)
{
	client_print(Client, print_chat, "* You can't change youre team in Team Game.");

	return PLUGIN_HANDLED;
}

public ChangeClass(Client)
{
	if (g_PutInServer[Client])
	{
		g_PutInServer[Client] = false;

		set_task(0.1, "CheckPlayers");

		return PLUGIN_CONTINUE;
	}

	if (g_Countdown)
		return PLUGIN_CONTINUE;

	client_print(Client, print_chat, "* Change your class during the countdown.");

	return PLUGIN_HANDLED;
}

public VGUIMenu()
	if (get_msg_arg_int(1) == 2)
		set_msg_arg_int(1, ARG_BYTE, 3);

public Killed(Victim, Killer)
{
	if (!Killer || Killer == Victim)
	{
		if (TG_SetTeam(Victim, TG_GetTeam(Victim) == TEAM_GOOD ? TEAM_EVIL : TEAM_GOOD))
			TG_CountTeamPlayers();

		return;
	}

	if (TG_SetTeam(Victim, TG_GetTeam(Killer)))
		TG_CountTeamPlayers();
}

public Countdown()
{
	if (!g_Countdown)
	{
		TG_BalanceTeams();
		client_print(0, print_center, "Teams have been balanced!");

		return;
	}
		
	client_print(0, print_center, "Balancing teams in %d...", g_Countdown--);
}

public CheckPlayers()
	TG_CountTeamPlayers();

stock TG_GetTeam(Client)
{
	new Team[2];
	get_user_team(Client, Team, 1);

	switch (Team[0])
	{
		case 'G': return TEAM_GOOD;
		case 'E': return TEAM_EVIL;
	}

	return 0;
}

stock bool:TG_SetTeam(Client, const Team)
{
	new const Command[] = "jointeam";

	switch (Team)
	{
		case TEAM_GOOD: engclient_cmd(Client, Command, "1");
		case TEAM_EVIL: engclient_cmd(Client, Command, "2");
	}

	new bool:Changed = bool:(TG_GetTeam(Client) == Team);

	if (!Changed)
		client_print(Client, print_chat, "* Your team was not changed due to team change delay.");

	return Changed;
}

stock TG_GetTeamPlayers(const Team)
{
	new Count;

	for (new Client = 1; Client <= g_MaxPlayers; Client++)
		if (is_user_connected(Client) && TG_GetTeam(Client) == Team)
			Count++;

	return Count;
}

stock TG_CountTeamPlayers()
{
	if (g_Countdown || get_playersnum() < 2)
		return;

	new Good, Evil;

	for (new Client = 1; Client <= g_MaxPlayers; Client++)
	{
		if (!is_user_connected(Client) || g_PutInServer[Client])
			continue;

		switch (TG_GetTeam(Client))
		{
			case TEAM_GOOD: Good++;
			case TEAM_EVIL: Evil++;
		}
	}

	if ((!Good || !Evil) && (Good + Evil) > 1)
	{
		g_Countdown = 10;
		set_task(1.0, "Countdown", 1024, _, _, "a", g_Countdown + 1);
	}
}

stock TG_BalanceTeams()
{
	new Array:Players = ArrayCreate(1, 1), Random, Size, Client;

	for (Client = 1; Client <= g_MaxPlayers; Client++)
	{
		if (!is_user_connected(Client) || g_PutInServer[Client])
			continue;

		ArrayPushCell(Players, Client);
	}

	while ((Size = ArraySize(Players)) && TG_GetTeamPlayers(1) != TG_GetTeamPlayers(2))
	{
		Random = random(Size);
		Client = ArrayGetCell(Players, Random);
		ArrayDeleteItem(Players, Random);

		TG_ChooseTeam(Client);
	}
}

stock TG_ChooseTeam(Client)
{
	new Good = TG_GetTeamPlayers(TEAM_GOOD);
	new Evil = TG_GetTeamPlayers(TEAM_EVIL);

	if (Good > Evil)
		TG_SetTeam(Client, TEAM_EVIL);
	else if (Good < Evil)
		TG_SetTeam(Client, TEAM_GOOD);
	else if (g_PutInServer[Client])
		engclient_cmd(Client, "jointeam", "5");
}
Download teamgame.amxx (mirror link would be appreciated).
 
Last edited:
Active Member
✔️ HL Verified
💻 Oldtimer
Joined
Nov 6, 2004
Messages
3,055
Best answers
0
Location
Round Rock, TX
This is well written. Good job.

Code:
set_task(0.1, "CheckPlayers");
You can just call CheckPlayers since client_disconnect() is called post anyway.

Code:
    new const TeamCommands[][] =
    {
        "change_team",
        "jointeam"
    };

    new const ClassCommands[][] =
    {
        "change_class",
        "buu",
        "goku",
        "gohan",
        "krillin",
        "frieza",
        "piccolo",
        "trunks",
        "vegeta",
        "cell",
        "randompc"
    };
You allocate this memory, but never use it again. It'd be a bit faster if you didn't cache any of that.

Sub said:
10:24 AM - Sub: i tried joining his server yesterday
10:24 AM - Sub: it kept kicking me
10:24 AM - Sub: "Bots aren't allowed!"
10:24 AM - Sub: I'm not a ****ing bot
 
Last edited:
NOT IN THE MANGA™
★ Black Lounger ★
✔️ HL Verified
🚂 Steam Linked
💻 Oldtimer
Joined
Jan 5, 2008
Messages
3,276
Best answers
0
Location
Lithuania
I directly called the function instead of setting task in the first place but noticed that it starts the balance even when player has disconnected and only 1 player left in the server. Task seemed to fix it.

plugin_init() is only called once and every variable created in it is destroyed after the function ended so I don't see a big deal about it. Just didn't want to write "ChangeClass" everytime I register client's command. I could have done new const ChangeClassFunction[] = "ChangeClass" though. But still I don't see a big deal about it.

I wonder why DeathMsg ****ed it up and left me with no other choice but using Ham.

About the "Bots aren't allowed!"... My server is running on Linux OS, so the engine files are outdated. People from "CN" and "AU" are not allowed because Bots (EvolutionX, and a bunch of other random names) come from there with ****ing 47 protocol clients.

Gonna shut down the server since Team Game testing was successful.
 
Last edited:
Active Member
✔️ HL Verified
💻 Oldtimer
Joined
Nov 6, 2004
Messages
3,055
Best answers
0
Location
Round Rock, TX
2D arrays are very slow. That's why it's a problem. When you cache it, then use it, it has to be referenced from memory, which is more work. If you're using it just once, it's extremely inefficient. Cut out the middle man.
 

sub

Active Member
💻 Oldtimer
Joined
Jun 18, 2003
Messages
5,961
Best answers
0
Location
New York
I directly called the function instead of setting task in the first place but noticed that it starts the balance even when player has disconnected and only 1 player left in the server. Task seemed to fix it.

plugin_init() is only called once and every variable created in it is destroyed after the function ended so I don't see a big deal about it. Just didn't want to write "ChangeClass" everytime I register client's command. I could have done new const ChangeClassFunction[] = "ChangeClass" though. But still I don't see a big deal about it.

I wonder why DeathMsg ****ed it up and left me with no other choice but using Ham.

About the "Bots aren't allowed!"... My server is running on Linux OS, so the engine files are outdated. People from "CN" and "AU" are not allowed because Bots (EvolutionX, and a bunch of other random names) come from there with ****ing 47 protocol clients.

Gonna shut down the server since Team Game testing was successful.
I'm from New York though
 
NOT IN THE MANGA™
★ Black Lounger ★
✔️ HL Verified
🚂 Steam Linked
💻 Oldtimer
Joined
Jan 5, 2008
Messages
3,276
Best answers
0
Location
Lithuania
I'm from New York though
It also disconnects player if his country cannot be recognized. Sometimes it just returns "", so it still means kick.
 
Now with Kung-Fu action!
✔️ HL Verified
💻 Oldtimer
Joined
May 13, 2004
Messages
1,761
Best answers
0
Location
England
If it's anything like the version you, me and Grega played, you'll have a winner. I don't know very much about code but it's definitely fun ^^.
 

Users who are viewing this thread

Top Bottom