Browse Source

Proper initial commit

nosoop 2 years ago
parent
commit
f9581d5c07
1 changed files with 169 additions and 0 deletions
  1. 169 0
      scripting/csrd_bot_swap.sp

+ 169 - 0
scripting/csrd_bot_swap.sp

@@ -0,0 +1,169 @@
+/**
+ * [CSRD] Bot Team Trading
+ * 
+ * Allows players to switch between balanced teams if a bot is able to switch in their place.
+ * Removes the need to switch to Spectators before switching to the desired team.
+ * 
+ * Works with the built-in manager and Doctor McKay's Bot Manager.
+ * Intended for use with "fill" quota mode.
+ */
+#pragma semicolon 1
+#include <sourcemod>
+
+#include <tf2_stocks>
+#include <printvalvetranslation>
+
+#pragma newdecls required
+
+#define PLUGIN_VERSION "0.0.1"
+public Plugin myinfo = {
+	name = "[CSRD] Cross-Team Bot Swap",
+	author = "nosoop",
+	description = "Allow switching on balanced teams if a bot can be swapped too.",
+	version = PLUGIN_VERSION,
+	url = "https://git.csrd.science/"
+}
+
+/**
+ * TODO: make it so only replicate disabled balance check if other team has bots?
+ */
+
+public void OnPluginStart() {
+	// TODO maybe call on post-round team switch??
+	HookEvent("player_team", OnTeamStateChange, EventHookMode_PostNoCopy);
+	
+	AddCommandListener(OnTeamChangeRequested, "jointeam");
+}
+
+public void OnPluginEnd() {
+	ConVar unbalanceLimit = FindConVar("mp_teams_unbalance_limit");
+	
+	for (int i = 1; i <= MaxClients; i++) {
+		if (IsClientConnected(i) && IsClientInGame(i) && !IsFakeClient(i)) {
+			unbalanceLimit.ReplicateToClient(i, "1");
+		}
+	}
+}
+
+public void OnConfigsExecuted() {
+	OnTeamStateChangePost(true);
+}
+
+public void OnTeamStateChange(Event event, const char[] name, bool dontBroadcast) {
+	// frame delay to ensure players are in correct team
+	RequestFrame(OnTeamStateChangePost);
+}
+
+/**
+ * Called when the number of players on a team change.
+ */
+public void OnTeamStateChangePost(any data) {
+	ConVar unbalanceLimit = FindConVar("mp_teams_unbalance_limit");
+	
+	// if no unbalance limit, don't bother
+	if (!unbalanceLimit.BoolValue) {
+		return;
+	}
+	
+	// First pass:  set unbalance limit to 1 on all human clients, count bots on teams.
+	int nRedBots, nBlueBots;
+	for (int i = 1; i <= MaxClients; i++) {
+		if (IsClientConnected(i) && IsClientInGame(i)) {
+			if (IsFakeClient(i)) {
+				switch (TF2_GetClientTeam(i)) {
+					case TFTeam_Red: {
+						nRedBots++;
+					}
+					case TFTeam_Blue: {
+						nBlueBots++;
+					}
+				}
+			} else {
+				unbalanceLimit.ReplicateToClient(i, "1");
+			}
+		}
+	}
+	
+	// Second pass:  If teams are even, allow players to switch if opposite team has bots.
+	if (TF2_GetTeamClientCount(TFTeam_Red) == TF2_GetTeamClientCount(TFTeam_Blue)) {
+		for (int i = 1; i <= MaxClients; i++) {
+			if (IsClientConnected(i) && IsClientInGame(i) && !IsFakeClient(i)) {
+				TFTeam team = TF2_GetClientTeam(i);
+				
+				if (team == TFTeam_Red && nBlueBots) {
+					unbalanceLimit.ReplicateToClient(i, "2");
+				} else if (team == TFTeam_Blue && nRedBots) {
+					unbalanceLimit.ReplicateToClient(i, "2");
+				}
+			}
+		}
+	}
+}
+
+public Action OnTeamChangeRequested(int client, const char[] name, int argc) {
+	if (TF2_GetTeamClientCount(TFTeam_Red) == TF2_GetTeamClientCount(TFTeam_Blue)) {
+		TFTeam team = TF2_GetClientTeam(client);
+		if (team != TFTeam_Red && team != TFTeam_Blue) {
+			return Plugin_Continue;
+		}
+		
+		char argstring[64];
+		GetCmdArgString(argstring, sizeof(argstring));
+		
+		if (StrEqual(argstring, "red")) {
+			SwapFakeClient(TFTeam_Red);
+		} else if (StrEqual(argstring, "blue")) {
+			SwapFakeClient(TFTeam_Blue);
+		}
+		// if switching to spec, let bot manager deal with filling in a player
+	}
+	// team change command will succeed now that a bot was swapped
+	return Plugin_Continue;
+}
+
+/**
+ * Moves a bot from one playing team to the other.
+ */
+void SwapFakeClient(TFTeam sourceTeam) {
+	if (sourceTeam != TFTeam_Red && sourceTeam != TFTeam_Blue) {
+		ThrowError("Attempting to swap fake client off of a non-playing team.");
+	}
+	
+	int[] bots = new int[TF2_GetTeamClientCount(sourceTeam)];
+	
+	int nBots;
+	for (int i = 1; i <= MaxClients; i++) {
+		if (IsClientInGame(i) && IsFakeClient(i) && TF2_GetClientTeam(i) == sourceTeam) {
+			bots[nBots++] = i;
+		}
+	}
+	
+	if (nBots) {
+		int bot = bots[GetRandomInt(0, nBots - 1)];
+		TFTeam newTeam = sourceTeam == TFTeam_Red? TFTeam_Blue : TFTeam_Red;
+		TF2_ChangeClientTeam(bot, newTeam);
+		TF2_RespawnPlayer(bot);
+		
+		// delay message so it gets displayed after the player switches
+		RequestFrame(BotSwapMessage, GetClientUserId(bot));
+	}
+}
+
+/**
+ * Displays a "<player> was moved to the other team for game balance" message.
+ */
+public void BotSwapMessage(int userid) {
+	int client = GetClientOfUserId(userid);
+	
+	if (client) {
+		char name[MAX_NAME_LENGTH];
+		GetClientName(client, name, sizeof(name));
+		
+		PrintValveTranslationToAll(Destination_Chat, "#game_player_was_team_balanced", name);
+	}
+}
+
+// 
+stock int TF2_GetTeamClientCount(TFTeam team) {
+	return GetTeamClientCount(view_as<int>(team));
+}