private ScrambleStatus ScrambleTeams(List<PlayerModel> usOrig, List<PlayerModel> ruOrig, bool logOnly)
{
/*
We have to check every move to make sure that we are not overfilling a team
or a squad. We get the live player count for each team. We start with the live
count in case a new player has joined that would overfill the team. Player's leaving
are ignored, since they help make a team less filled. Therefore these counts might
be overestimates, but are never less than the actual live count. We can't wait
for full round-trip updates, so we "dead reckon" the updated team counts for each
move we make.
*/
bool first = true;
PerModeSettings perMode = GetPerModeSettings();
int maxTeam = perMode.MaxPlayers/2;
int usCount = 0;
int ruCount = 0;
Dictionary<int,int> allocated = new Dictionary<int,int>(); // key is combined team + squad
// Get live counts
List<String> allCopy = new List<String>();
lock (fAllPlayers) {
allCopy.AddRange(fAllPlayers);
}
foreach (String name in allCopy) {
PlayerModel m = GetPlayer(name);
if (m == null || m.Role != ROLE_PLAYER)
continue;
if (m.Team == 1) { ++usCount; }
else if (m.Team == 2) { ++ruCount; }
}
// Check for full server
if (usCount >= maxTeam && ruCount >= maxTeam) {
List<PlayerModel> allPlayers = new List<PlayerModel>();
allPlayers.AddRange(usOrig);
allPlayers.AddRange(ruOrig);
RestoreSquads(allPlayers, null, logOnly);
return ScrambleStatus.CompletelyFull; // can't scramble, server is full
}
List<PlayerModel> usClone = new List<PlayerModel>();
List<PlayerModel> ruClone = new List<PlayerModel>();
// Remove players from these lists as they are moved
usClone.AddRange(usOrig);
ruClone.AddRange(ruOrig);
// Move one by one, sending to the smallest team
while (usClone.Count + ruClone.Count > 0) {
if (DebugLevel >= 7) DebugScrambler("Team counts: Max = " + maxTeam + ", " + GetTeamName(1) + "(" + usCount + "), " + GetTeamName(2) + "(" + ruCount + ")");
// Pick next list to pull from, using the one that represents moving to the lowest live count
int nextList = 0;
if (usCount < maxTeam && usClone.Count > 0 && (usCount <= ruCount || ruClone.Count == 0)) {
nextList = 1;
} else if (ruCount < maxTeam && ruClone.Count > 0 && (ruCount <= usCount || usClone.Count == 0)) {
nextList = 2;
} else {
List<PlayerModel> remaining = new List<PlayerModel>();
remaining.AddRange(usClone);
remaining.AddRange(ruClone);
RestoreSquads(remaining, allocated, logOnly);
if (first) return ScrambleStatus.Failure; // can't continue scramble, server is full
return ScrambleStatus.PartialSuccess;
}
// Pull from list and do the move
DebugScrambler("Remaining to be moved: To " + GetTeamName(1) + "(" + usClone.Count + "), To " + GetTeamName(2) + "(" + ruClone.Count + ")");
List<PlayerModel> pullFrom = (nextList == 1) ? usClone : ruClone;
PlayerModel clone = pullFrom[0];
pullFrom.Remove(clone);
PlayerModel actual = GetPlayer(clone.Name);
int actualTeam = (actual != null) ? actual.Team : 0;
first = false;
try {
ScrambleMove(clone, nextList, logOnly);
int num = 0;
int key = (nextList * 1000) + clone.ScrambledSquad;
if (allocated.TryGetValue(key, out num)) {
num = num + 1;
}
if (num > fMaxSquadSize) {
DebugScrambler("WARNING: team " + nextList + ", squad " + clone.ScrambledSquad + " has more than " + fMaxSquadSize + " players!");
} else {
allocated[key] = num;
}
} catch (Exception e) { ConsoleException(e); }
// Moving to a new team?
if (actualTeam != clone.Team) {
if (nextList == 1) {
++usCount;
--ruCount;
} else {
++ruCount;
--usCount;
}
} // otherwise moved to same team, so no change in team counts
}
return ScrambleStatus.Success;
}