From d4b71058a4f5c7e5847eefa737fb1d03a53b3671 Mon Sep 17 00:00:00 2001
From: Tim Felgentreff <timfelgentreff@gmail.com>
Date: Tue, 15 Mar 2022 23:21:47 +0100
Subject: [PATCH] fix and document player team assignement via presets

---
 src/game/game.cpp       | 10 +++++++---
 src/game/replay.cpp     |  7 +++++++
 src/network/network.cpp |  6 ++++++
 3 files changed, 20 insertions(+), 3 deletions(-)

diff --git a/src/game/game.cpp b/src/game/game.cpp
index d8dd1695a..97b0d21ed 100644
--- a/src/game/game.cpp
+++ b/src/game/game.cpp
@@ -865,10 +865,14 @@ void CreateGame(const std::string &filename, CMap *map)
 		}
 		CreatePlayer(playertype);
 		if (GameSettings.Presets[i].Team != SettingsPresetMapDefault) {
-			int presetTeam = GameSettings.Presets[i].Team;
+			// why this calculation? Well. The CreatePlayer function assigns some
+			// default team values, starting from up to PlayerMax + some constant (2 at the time
+			// of this writing). So to not accidentally interfere with those teams, we assign the team
+			// offset by 2 * PlayerMax.
+			Players[i].Team = GameSettings.Presets[i].Team + 2 * PlayerMax;
 			for (int j = 0; j < i; j++) {
-				if (Players[j].Team != SettingsPresetMapDefault) {
-					if (Players[j].Team != presetTeam) {
+				if (GameSettings.Presets[j].Team != SettingsPresetMapDefault) {
+					if (GameSettings.Presets[j].Team != GameSettings.Presets[i].Team) {
 						Players[i].SetDiplomacyEnemyWith(Players[j]);
 						Players[j].SetDiplomacyEnemyWith(Players[i]);
 					} else {
diff --git a/src/game/replay.cpp b/src/game/replay.cpp
index 7c52ccde5..29c093df6 100644
--- a/src/game/replay.cpp
+++ b/src/game/replay.cpp
@@ -172,6 +172,13 @@ static FullReplay *StartReplay()
 		// Players array. For replay, we want to store these,
 		// generally. However, this is not true for teams, since there is
 		// automatic handling of alliance flags for rescueable players.
+		// Additionally, teams are automatically created in CPlayer::Init.
+		// The presets team is actually not used verbatim, but instead used
+		// as the basis of further calculation for the actual player's team
+		// (see game.cpp CreateGame right after the CreatePlayer call where
+		// we check GameSettings.Presets[i].Team != SettingsPresetMapDefault)
+		// So in order for the replay to work, we must not save the actual player
+		// teams, but instead the preset teams.
 		replay->ReplaySettings.Presets[i].AIScript = Players[i].AiName; // GameSettings.Presets[i].AIScript;
 		replay->ReplaySettings.Presets[i].Race = Players[i].Race; // GameSettings.Presets[i].Race;
 		replay->ReplaySettings.Presets[i].Team = GameSettings.Presets[i].Team; // Players[i].Team;
diff --git a/src/network/network.cpp b/src/network/network.cpp
index 5afe278ca..c8f253d77 100644
--- a/src/network/network.cpp
+++ b/src/network/network.cpp
@@ -614,6 +614,9 @@ void NetworkSendSelection(CUnit **units, int count)
 	// Check if we have any teammates to send to
 	bool hasteammates = false;
 	for (int i = 0; i < NetPlayers; ++i) {
+		if (ThisPlayer->Index == Hosts[i].PlyNr) {
+			continue; // skip self
+		}
 		if (Hosts[i].IsValid() && Players[Hosts[i].PlyNr].Team == ThisPlayer->Team) {
 			hasteammates = true;
 			break;
@@ -1211,6 +1214,9 @@ void NetworkRecover()
 		return;
 	}
 	for (int i = 0; i < NetPlayers; ++i) {
+		if (ThisPlayer->Index == Hosts[i].PlyNr) {
+			continue; // skip self
+		}
 		CheckPlayerThatTimeOut(i);
 	}
 	NetworkResendCommands();