Skip to content

ai-battle: support team assignment (--teams) and establish team start-pacts#1957

Open
FlexApex wants to merge 10 commits into
Return-To-The-Roots:masterfrom
FlexApex:ai-battle-teams
Open

ai-battle: support team assignment (--teams) and establish team start-pacts#1957
FlexApex wants to merge 10 commits into
Return-To-The-Roots:masterfrom
FlexApex:ai-battle-teams

Conversation

@FlexApex

Copy link
Copy Markdown

ai-battle: support team assignment (--teams) and establish team start-pacts

Builds on #1949 (uses its HeadlessGame). Two commits:

1. --teams option for team assignment

Adds a --teams option to the headless ai-battle harness so the AI can be
verified under real team rules instead of a free-for-all:

ai-battle -m Map.swd --ai aijh --ai aijh --ai aijh --ai aijh --teams "0,1;2,3"

Groups are separated by ;, player indices by ,. The first group becomes
Team1, the second Team2, and so on; unlisted players stay teamless. The
assignment is threaded through HeadlessGame into GeneratePlayerInfo, which
sets PlayerInfo::team.

2. Establish team start-pacts in HeadlessGame to match GameClient (avoid desyncs in replays)

GameClient::StartGame calls GamePlayer::MakeStartPacts() for every player on
a fresh map, creating the ally + non-aggression pacts that bind a team together.
HeadlessGame never did this, so a recorded ai-battle with teams had no pacts:
GamePlayer::IsAttackable() returned true for teammates and the AIs attacked
their own team. On replay GameClient does set up the pacts, so the recorded
inter-team attack commands hit allied players and were resolved differently —
producing an object-count divergence (replay desync) without any RANDOM
divergence.

MakeStartPacts() early-returns for Team::None, so the call is a no-op until
players are actually assigned to teams via --teams. Together with the
MapLoader::SetupResources() call already in HeadlessGame, this makes the
headless world setup match the GameClient replay path.

Note

MichalLabuda and others added 10 commits June 18, 2026 02:52
Adds a --teams option (e.g. "0,1;2,3" for a 2v2) that assigns players to
teams in the headless harness, so the AI can be verified under real team
rules instead of a free-for-all. Player indices map to Team1, Team2, ...
in the order the groups are given; unlisted players stay teamless.

The assignment is threaded through HeadlessGame into GeneratePlayerInfo,
which sets PlayerInfo::team. Establishing the actual alliances follows in
the next commit.
…ient

GameClient::StartGame calls GamePlayer::MakeStartPacts() for every player
on a fresh map, creating the ally + non-aggression pacts that bind a team
together. HeadlessGame never did this, so in a recorded ai-battle with
teams the teammates had no pacts and GamePlayer::IsAttackable() returned
true for them: the AIs attacked their own team. On replay GameClient
*does* set up the pacts, so the recorded inter-team attack commands hit
allied players and were resolved differently, producing an object-count
divergence (and replay desync) without any RANDOM divergence.

MakeStartPacts() early-returns for Team::None, so this is a no-op until
players are actually assigned to teams via --teams.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants