Allow up to seven teams for players (#445)

## Description:

- Allow up to seven teams for players, and one for bots.
- Add team count selection to the single player dialog.
- Select random number of teams in server rotation.

Fixes #456

## Please complete the following:

- [x] I have added screenshots for all UI updates
- [x] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
- [x] I understand that submitting code with bugs that could have been
caught through manual testing blocks releases and new features for all
contributors


![image](https://github.com/user-attachments/assets/cbc1ba82-9d06-4763-896c-abdce067a161)


![image](https://github.com/user-attachments/assets/9f82a0a5-c0bb-49b6-a714-2b13286a64ca)

## Please put your Discord username so you can be contacted if a bug or
regression is found:

fake.neo

---------

Co-authored-by: Scott Anderson <662325+scottanderson@users.noreply.github.com>
This commit is contained in:
Scott Anderson
2025-04-15 19:02:58 -07:00
committed by GitHub
co-authored by Scott Anderson
parent 1ed3d50eb1
commit 5167f67b96
16 changed files with 290 additions and 83 deletions
+28 -28
View File
@@ -2,10 +2,10 @@ import { PlayerInfo, Team } from "./Game";
export function assignTeams(
players: PlayerInfo[],
teams: Team[],
): Map<PlayerInfo, Team | "kicked"> {
const result = new Map<PlayerInfo, Team | "kicked">();
let redTeamCount = 0;
let blueTeamCount = 0;
const teamPlayerCount = new Map<Team, number>();
// Group players by clan
const clanGroups = new Map<string, PlayerInfo[]>();
@@ -23,7 +23,7 @@ export function assignTeams(
}
}
const maxTeamSize = Math.ceil(players.length / 2);
const maxTeamSize = Math.ceil(players.length / teams.length);
// Sort clans by size (largest first)
const sortedClans = Array.from(clanGroups.entries()).sort(
@@ -33,38 +33,38 @@ export function assignTeams(
// First, assign clan players
for (const [_, clanPlayers] of sortedClans) {
// Try to keep the clan together on the team with fewer players
if (redTeamCount <= blueTeamCount) {
// Assign to red team
for (const player of clanPlayers) {
if (redTeamCount < maxTeamSize) {
redTeamCount++;
result.set(player, Team.Red);
} else {
result.set(player, "kicked");
}
}
} else {
// Assign to blue team
for (const player of clanPlayers) {
if (blueTeamCount < maxTeamSize) {
blueTeamCount++;
result.set(player, Team.Blue);
} else {
result.set(player, "kicked");
}
let team: Team | null = null;
let teamSize = 0;
for (const t of teams) {
const p = teamPlayerCount.get(t) ?? 0;
if (team !== null && teamSize <= p) continue;
teamSize = p;
team = t;
}
for (const player of clanPlayers) {
if (teamSize < maxTeamSize) {
teamSize++;
result.set(player, team);
} else {
result.set(player, "kicked");
}
}
teamPlayerCount.set(team, teamSize);
}
// Then, assign non-clan players to balance teams
for (const player of noClanPlayers) {
if (redTeamCount <= blueTeamCount) {
redTeamCount++;
result.set(player, Team.Red);
} else {
blueTeamCount++;
result.set(player, Team.Blue);
let team: Team | null = null;
let teamSize = 0;
for (const t of teams) {
const p = teamPlayerCount.get(t) ?? 0;
if (team !== null && teamSize <= p) continue;
teamSize = p;
team = t;
}
teamPlayerCount.set(team, teamSize + 1);
result.set(player, team);
}
return result;