From cd172b24fb10fb3927792ae0f95b24514a961592 Mon Sep 17 00:00:00 2001
From: ariclone <>
Date: Thu, 23 May 2002 20:42:33 +0000
Subject: [PATCH] Fixed race selection and slot exclusion ("closed") in
 gui-started network game. Don't think this was easy..

---
 src/network/netconnect.cpp | 160 +++++++++++++++++++++++--------------
 src/network/network.cpp    |   3 +-
 src/ui/menus.cpp           |  88 ++++++++++++++++----
 3 files changed, 176 insertions(+), 75 deletions(-)

diff --git a/src/network/netconnect.cpp b/src/network/netconnect.cpp
index 7c2a19071..2552bc8f5 100644
--- a/src/network/netconnect.cpp
+++ b/src/network/netconnect.cpp
@@ -842,30 +842,85 @@ global void NetworkServerResyncClients(void)
 global void NetworkServerStartGame(void)
 {
     int h, i, j, n;
-    unsigned long u;
-    int num[PlayerMax];
+    int num[PlayerMax], org[PlayerMax], rev[PlayerMax];
     char buf[1024];
     InitMessage *msg;
     InitMessage message, statemsg;
 
     DebugCheck(ServerSetupState.CompOpt[0] != 0);
 
+    // save it first..
+    LocalSetupState = ServerSetupState;
+
     // Make a list of the available player slots.
     for (h = i = 0; i < PlayerMax; i++) {
 	if (ScenSelectPudInfo->PlayerType[i] == PlayerPerson) {
+	    rev[i] = h;
 	    num[h++] = i;
-	    DebugLevel3Fn("Slot %d is available for an interactive player\n", i);
+	    DebugLevel0Fn("Slot %d is available for an interactive player (%d)\n", i, rev[i]);
+	}
+    }
+    // Make a list of the available computer slots.
+    n = h;
+    for (i = 0; i < PlayerMax; i++) {
+	if (ScenSelectPudInfo->PlayerType[i] == PlayerComputer) {
+	    rev[i] = n++;
+	    DebugLevel0Fn("Slot %d is available for an ai computer player (%d)\n", i, rev[i]);
+	}
+    }
+    // Make a list of the remaining slots.
+    for (i = 0; i < PlayerMax; i++) {
+	if (ScenSelectPudInfo->PlayerType[i] != PlayerPerson &&
+				ScenSelectPudInfo->PlayerType[i] != PlayerComputer) {
+	    rev[i] = n++;
+	    // PlayerNobody - not available to anything..
 	}
     }
 
+#if 0
+    printf("INITIAL ServerSetupState:\n");
+    for (i = 0; i < PlayerMax-1; i++) {
+	printf("%02d: CO: %d   Race: %d   Host: ", i, ServerSetupState.CompOpt[i], ServerSetupState.Race[i]);
+	if (ServerSetupState.CompOpt[i] == 0) {
+	    printf(" %d.%d.%d.%d:%d %s", NIPQUAD(ntohl(Hosts[i].Host)),
+			 ntohs(Hosts[i].Port), Hosts[i].PlyName);
+	}
+	printf("\n");
+    }
+#endif
+
+    // Reverse to assign slots to menu setup state positions.
+    for (i = 0; i < PlayerMax; i++) {
+	org[i] = -1;
+	for (j = 0; j < PlayerMax; j++) {
+	    if (rev[j] == i) {
+		org[i] = j;
+		break;
+	    }
+	}
+    }
+
+#if 0
+    printf("\n"); for (i=0;i<PlayerMax;i++) printf("% 2d: %d\n", i, org[i]); printf("\n");
+#endif
+
     // Compact host list.. (account for computer/closed slots in the middle..)
-    for (i = 1; i < PlayerMax; i++) {
+    for (i = 1; i < h; i++) {
 	if (Hosts[i].PlyNr == 0) {
 	    for (j = i + 1; j < PlayerMax - 1; j++) {
 		if (Hosts[j].PlyNr) {
+		    DebugLevel0Fn("Compact: Hosts %d -> Hosts %d\n", j, i);
 		    Hosts[i] = Hosts[j];
-		    DebugLevel3Fn("Compact: Hosts %d -> Hosts %d\n", j, i);
-		    Hosts[j].PlyNr = 0;
+		    Hosts[j].PlyNr = Hosts[j].Host = Hosts[j].Port = 0;
+		    n = LocalSetupState.CompOpt[i];
+		    LocalSetupState.CompOpt[i] = LocalSetupState.CompOpt[j];
+		    LocalSetupState.CompOpt[j] = n;
+		    n = LocalSetupState.Race[i];
+		    LocalSetupState.Race[i] = LocalSetupState.Race[j];
+		    LocalSetupState.Race[j] = n;
+		    n = LocalSetupState.LastFrame[i];
+		    LocalSetupState.LastFrame[i] = LocalSetupState.LastFrame[j];
+		    LocalSetupState.LastFrame[j] = n;
 		    break;
 		}
 	    }
@@ -874,67 +929,51 @@ global void NetworkServerStartGame(void)
 	    }
 	}
     }
-    // Randomize the position.
-    for (i = 0; i < NetPlayers; i++) {
-	if (h > 0) {
-	    int chosen = MyRand() % h;
 
-	    DebugLevel3Fn("Assigning player %d to slot %i\n", i, num[chosen]);
-	    Hosts[i].PlyNr = num[chosen];
-	    num[chosen] = num[--h];
+    // Randomize the position.
+    j = h;
+    for (i = 0; i < NetPlayers; i++) {
+	if (j > 0) {
+	    int k, o, chosen = MyRand() % j;
+
+	    n = num[chosen];
+	    Hosts[i].PlyNr = n;
+	    k = org[i];
+	    if (k != n) {
+		for (o = 0; o < PlayerMax; o++) {
+		    if (org[o] == n) {
+			org[o] = k;
+			break;
+		    }
+		}
+		org[i] = n;
+	    }
+	    DebugLevel0Fn("Assigning player %d to slot %d (%d)\n", i, n, org[i]);
+
+	    num[chosen] = num[--j];
 	} else {
 	    DebugCheck(1 == 1);
 #if 0
-	    // ARI: is this code path realy executed? (initially h >= NetPlayers..)
+	    // ARI: is this code path really executed? (initially h >= NetPlayers..)
 	    Hosts[i].PlyNr = num[0];
 	    DebugLevel0Fn("Hosts[%d].PlyNr = %i\n", i, num[0]);
 #endif
 	}
     }
 
-    // Shuffle setup states to match the assigned Host slots.
-    for (i = 0; i < PlayerMax; i++) {
-	num[i] = 0;
-    }
-    for (i = 0; i < NetPlayers; i++) {
-	num[Hosts[i].PlyNr] = 1;
-    }
-    for (i = 0; i < NetPlayers; i++) {
-	h = Hosts[i].PlyNr;
-	if (ServerSetupState.CompOpt[h]) {
-	    for (j = 0; j < PlayerMax; j++) {
-		if (num[j] == 0 && ServerSetupState.CompOpt[j] == 0) {
-		    u = ServerSetupState.CompOpt[h];
-		    ServerSetupState.CompOpt[h] = ServerSetupState.CompOpt[j];
-		    ServerSetupState.CompOpt[j] = u;
-		    u = ServerSetupState.Race[h];
-		    ServerSetupState.Race[h] = ServerSetupState.Race[j];
-		    ServerSetupState.Race[j] = u;
-		    u = ServerSetupState.LastFrame[h];
-		    ServerSetupState.LastFrame[h] = ServerSetupState.LastFrame[j];
-		    ServerSetupState.LastFrame[j] = u;
-		    break;
-		}
-	    }
-	}
-    }
-
-#ifdef DEBUG
-    for (i = 0; i < PlayerMax-1; i++) {
-	printf("%02d: CO: %d   Race: %d   Host: ", i, ServerSetupState.CompOpt[i], ServerSetupState.Race[i]);
-	if (ServerSetupState.CompOpt[i] == 0) {
-	    for (j = 0; j < NetPlayers; j++) {
-		if (Hosts[j].PlyNr == i) {
-		    printf(" %d.%d.%d.%d:%d %s", NIPQUAD(ntohl(Hosts[j].Host)),
-				 ntohs(Hosts[j].Port), Hosts[j].PlyName);
-		    
-		}
-	    }
-	}
-	printf("\n");
-    }
+#if 0
+    printf("\n"); for (i=0;i<PlayerMax;i++) printf("% 2d: %d\n", i, org[i]); printf("\n");
 #endif
 
+    // Complete all setup states for the assigned slots.
+    for (i = 0; i < PlayerMax; i++) {
+	num[i] = 1;
+	n = org[i];
+	ServerSetupState.CompOpt[n] = LocalSetupState.CompOpt[i];
+	ServerSetupState.Race[n] = LocalSetupState.Race[i];
+	ServerSetupState.LastFrame[n] = LocalSetupState.LastFrame[i];
+    }
+
     /* NOW we have NetPlayers in Hosts array, with ServerSetupState shuffled up to match it.. */
 
     //
@@ -962,7 +1001,6 @@ global void NetworkServerStartGame(void)
 	message.u.Hosts[i].Port = Hosts[i].Port;
 	memcpy(message.u.Hosts[i].PlyName, Hosts[i].PlyName, 16);
 	message.u.Hosts[i].PlyNr = htons(Hosts[i].PlyNr);
-// 	PlayerSetName(&Players[Hosts[i].PlyNr], Hosts[i].PlyName);
     }
 
     // Prepare the final state message:
@@ -1207,7 +1245,7 @@ changed:
 		message.SubType = ICMGo;
 		NetworkSendRateLimitedClientMessage(&message, 250);
 	    } else {
-		DebugLevel3Fn("ccs_started: Final State Enough ICMGo sent - starting\n");
+		DebugLevel3Fn("ccs_started: Final state enough ICMGo sent - starting\n");
 		NetConnectRunning = 0;	// End the menu..
 	    }
 	    break;
@@ -1409,7 +1447,6 @@ local void NetworkParseMenuPacket(const InitMessage *msg, int size)
 				    Hosts[HostsCount].Port = msg->u.Hosts[i].Port;
 				    Hosts[HostsCount].PlyNr = ntohs(msg->u.Hosts[i].PlyNr);
 				    memcpy(Hosts[HostsCount].PlyName, msg->u.Hosts[i].PlyName, 16);
-				    // PlayerSetName(&Players[Hosts[HostsCount].PlyNr], Hosts[HostsCount].PlyName);
 				    HostsCount++;
 				    DebugLevel0Fn("Client %d = %d.%d.%d.%d:%d [%s]\n",
 					    ntohs(ntohs(msg->u.Hosts[i].PlyNr)), NIPQUAD(ntohl(msg->u.Hosts[i].Host)),
@@ -1425,13 +1462,18 @@ local void NetworkParseMenuPacket(const InitMessage *msg, int size)
 			    Hosts[HostsCount].Port = NetLastPort;
 			    Hosts[HostsCount].PlyNr = ntohs(msg->u.Hosts[i].PlyNr);
 			    memcpy(Hosts[HostsCount].PlyName, msg->u.Hosts[i].PlyName, 16);
-			    // PlayerSetName(&Players[Hosts[HostsCount].PlyNr], Hosts[HostsCount].PlyName);
 			    HostsCount++;
 			    NetPlayers = HostsCount + 1;
 			    DebugLevel0Fn("Server %d = %d.%d.%d.%d:%d [%s]\n",
 				    ntohs(msg->u.Hosts[i].PlyNr), NIPQUAD(ntohl(NetLastHost)),
 				    ntohs(NetLastPort), msg->u.Hosts[i].PlyName);
 
+			    // put ourselves to the end, like on the server..
+			    Hosts[HostsCount].Host = 0;
+			    Hosts[HostsCount].Port = 0;
+			    Hosts[HostsCount].PlyNr = NetLocalPlayerNumber;
+			    memcpy(Hosts[HostsCount].PlyName, NetworkName, 16);
+
 			    NetLocalState = ccs_goahead;
 			    NetStateMsgCnt = 0;
 			    break;
diff --git a/src/network/network.cpp b/src/network/network.cpp
index 497c32519..9c3b1ceb5 100644
--- a/src/network/network.cpp
+++ b/src/network/network.cpp
@@ -645,7 +645,8 @@ global void NetworkEvent(void)
 	}
     }
     if (i == HostsCount) {
-	DebugLevel0Fn("Not a host in play\n");
+	DebugLevel0Fn("Not a host in play: %d.%d.%d.%d:%d\n",
+		 NIPQUAD(ntohl(NetLastHost)), ntohs(NetLastPort));
 	return;
     }
     player = Hosts[i].PlyNr;
diff --git a/src/ui/menus.cpp b/src/ui/menus.cpp
index 532a4ecc1..22568827d 100644
--- a/src/ui/menus.cpp
+++ b/src/ui/menus.cpp
@@ -173,6 +173,7 @@ local void MultiClientRCSAction(Menuitem *mi, int i);
 
 local void MultiGameStart(void);
 local void MultiGameCancel(void);
+local void NetworkGamePrepareGameSettings(void);
 local void MultiGameSetupInit(Menuitem *mi);	// master init
 local void MultiGameSetupExit(Menuitem *mi);	// master exit
 local void MultiGameDrawFunc(Menuitem *mi);
@@ -3038,6 +3039,7 @@ local void TerminateNetConnect(void)
 	    return;
 
 	case ccs_started:
+	    NetworkGamePrepareGameSettings();
 	    CustomGameStart();
 	    return;
 
@@ -3081,6 +3083,7 @@ local void MultiGameStart(void)
     Invalidate();
 
     NetworkServerStartGame();
+    NetworkGamePrepareGameSettings();
 
     CustomGameStart();
 }
@@ -4010,7 +4013,7 @@ local void GameRCSAction(Menuitem *mi, int i)
 
     if (mi->d.pulldown.curopt == i) {
 	GameSettings.Presets[0].Race = v[i];
-	ServerSetupState.Race[0] = i;
+	ServerSetupState.Race[0] = 2 - i;
 	NetworkServerResyncClients();
     }
 }
@@ -4107,6 +4110,74 @@ local void MultiGameClientDrawFunc(Menuitem *mi)
     GameDrawFunc(mi);
 }
 
+/**
+**	Multiplayer network game final race an player type setup.
+*/
+local void NetworkGamePrepareGameSettings(void)
+{
+    int h, i;
+    int num[PlayerMax];
+
+    DebugCheck(!ScenSelectPudInfo);
+
+    DebugLevel0Fn("NetPlayers = %d\n", NetPlayers);
+
+#ifdef DEBUG
+    for (i = 0; i < PlayerMax-1; i++) {
+	printf("%02d: CO: %d   Race: %d   Host: ", i, ServerSetupState.CompOpt[i], ServerSetupState.Race[i]);
+	if (ServerSetupState.CompOpt[i] == 0) {
+	    for (h = 0; h < NetPlayers; h++) {
+		if (Hosts[h].PlyNr == i) {
+		    printf("%s", Hosts[h].PlyName);
+		}
+	    }
+	}
+	printf("\n");
+    }
+#endif
+
+    // Make a list of the available player slots.
+    for (h = i = 0; i < PlayerMax-1; i++) {
+	if (ScenSelectPudInfo->PlayerType[i] == PlayerPerson) {
+	    DebugLevel3Fn("Player slot %i is available for a person\n", i);
+	    num[h++] = i;
+	}
+    }
+    for (i = 0; i < h; i++) {
+	switch(ServerSetupState.CompOpt[num[i]]) {
+	    case 0:
+		GameSettings.Presets[num[i]].Type = PlayerPerson;
+		DebugLevel3Fn("Settings[%d].Type == Person\n", num[i]);
+		switch (ServerSetupState.Race[num[i]]) {
+		    case 1:
+			GameSettings.Presets[num[i]].Race = PlayerRaceOrc;
+			break;
+		    case 2:
+			GameSettings.Presets[num[i]].Race = PlayerRaceHuman;
+		    default:
+			break;
+		}
+		break;
+	    case 1:
+		GameSettings.Presets[num[i]].Type = PlayerComputer;
+		DebugLevel3Fn("Settings[%d].Type == Computer\n", num[i]);
+		break;
+	    case 2:
+		GameSettings.Presets[num[i]].Type = PlayerNobody;
+		DebugLevel3Fn("Settings[%d].Type == Closed\n", num[i]);
+	    default:
+		break;
+	}
+    }
+
+#ifdef DEBUG
+    for (i = 0; i < NetPlayers; i++) {
+	DebugCheck(GameSettings.Presets[Hosts[i].PlyNr].Type != PlayerPerson);
+	;
+    }
+#endif
+}
+
 /**
 **	Player selectors have changed.
 **	Caution: Called by map change (inital = 1)!
@@ -4421,16 +4492,8 @@ local void MultiClientGemAction(Menuitem *mi __attribute__((unused)))
 
 local void MultiClientRCSAction(Menuitem *mi, int i)
 {
-#if 0
-    int v[] = { PlayerRaceHuman, PlayerRaceOrc, SettingsPresetMapDefault };
-#endif
-
     if (mi->d.pulldown.curopt == i) {
-	LocalSetupState.Race[NetLocalHostsSlot] = i;
-#if 0
-	// FIXME: Handle RACES -> Not visible! Delayed to final InitConfig msg...
-	GameSettings.Presets[NetLocalHostsSlot].Race = v[i];
-#endif
+	LocalSetupState.Race[NetLocalHostsSlot] = 2 - i;
 	MultiClientUpdate(0);
     }
 }
@@ -4506,11 +4569,6 @@ global void NetConnectForceDisplayUpdate(void)
 */
 global void NetClientUpdateState(void)
 {
-#if 0
-    // FIXME: Handle RACES -> Not visible! Delayed to final InitConfig msg...
-    GameSettings.Presets[0].Race = ServerSetupState.Race[0];
-#endif
-
     GameRESAction(NULL, ServerSetupState.ResOpt);
     NetMultiClientMenuItems[CLIENT_RESOURCE].d.pulldown.curopt =
 	ServerSetupState.ResOpt;