Skip to content

Feature: Name teams after clans#3301

Open
deshack wants to merge 6 commits intomainfrom
team-names
Open

Feature: Name teams after clans#3301
deshack wants to merge 6 commits intomainfrom
team-names

Conversation

@deshack
Copy link
Contributor

@deshack deshack commented Feb 26, 2026

Resolves #3300

Description:

In games with 8+ teams (where teams are not named after territory colors), name teams after the clan tags majority when possible, fallback to numbered team names otherwise.

Screenshot taken from a duo in solo mode (I'm the only human in the team):

Screenshot_20260226-204026

Please complete the following:

  • I have added screenshots for all UI updates
  • I process any text displayed to the user through translateText() and I've added it to the en.json file
  • I have added relevant tests to the test directory
  • I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced

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

deshack_82603

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 26, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b82ada2 and e62a461.

📒 Files selected for processing (1)
  • src/core/game/GameImpl.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/core/game/GameImpl.ts

Walkthrough

Adds a clan-based team naming heuristic and integrates it into team assignment: computeClanTeamName determines a clan or coalition name per team; GameImpl uses it when adding players in numbered-team modes, resolves rename collisions, and applies safe renames to playerTeams and player→team mappings; tests added.

Changes

Cohort / File(s) Summary
Team naming helper
src/core/game/TeamAssignment.ts
New exported `computeClanTeamName(players: PlayerInfo[]): string
Team assignment integration
src/core/game/GameImpl.ts
Imports computeClanTeamName; when adding players in numbered-team modes builds a team→players reverse map, computes candidate clan names, constructs a rename map, iteratively resolves collisions against existing names and other renames, and applies renames to playerTeams and playerToTeam.
Tests
tests/TeamAssignment.test.ts
New unit tests for computeClanTeamName covering unanimous clan, strict majority, top-two coalition, no-clan/fallback, bots/untagged, and mixed human/bot scenarios.

Sequence Diagram

sequenceDiagram
    participant Game as GameImpl
    participant Assign as TeamAssignment
    participant Map as PlayerMappings

    Game->>Game: Detect numbered-team mode
    Game->>Map: Build team -> players reverse map
    loop per team
        Game->>Assign: computeClanTeamName(players)
        Assign->>Assign: Filter humans, count clan tags
        Assign->>Assign: Choose unanimous / majority / coalition / null
        Assign-->>Game: Return candidate name or null
    end
    Game->>Game: Build rename map (exclude nulls & identical names)
    Game->>Game: Iterative collision resolution vs existing names and other renames
    Game->>Map: Apply renames to playerTeams and playerToTeam mappings
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

Teams numbered once, now wear clan crest,
Votes of players name who’s best,
One or two clans rule the day,
Collisions checked, mappings sway,
Match titles sing where fights are blessed. ⚔️

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Feature: Name teams after clans' accurately and concisely summarizes the main change in the PR—implementing clan-based team naming logic.
Description check ✅ Passed The description is directly related to the changeset, referencing issue #3300, explaining the feature purpose, and detailing implementation approach with clan-based naming logic.
Linked Issues check ✅ Passed The code implements all proposed heuristics [#3300]: unanimous clan matching, majority clan matching, coalition/hybrid naming, and fallback to numbered teams when appropriate.
Out of Scope Changes check ✅ Passed All changes are directly scoped to implementing clan-based team naming: GameImpl.ts applies renames, TeamAssignment.ts computes clan names, and tests validate the new functionality.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
src/core/game/GameImpl.ts (1)

216-218: Minor: Avoid as any cast

The cast works but is a bit loose. Since Team = string and Object.values(ColoredTeams) returns string[], you can avoid it:

-    const isNumberedTeams = !this.playerTeams.some((t) =>
-      Object.values(ColoredTeams).includes(t as any),
-    );
+    const coloredTeamValues = Object.values(ColoredTeams);
+    const isNumberedTeams = !this.playerTeams.some((t) =>
+      coloredTeamValues.includes(t),
+    );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/core/game/GameImpl.ts` around lines 216 - 218, The includes cast is too
loose: in GameImpl.ts update the isNumberedTeams expression to remove the
unnecessary "as any" by comparing the team value directly against the
ColoredTeams values (e.g. const isNumberedTeams = !this.playerTeams.some(t =>
Object.values(ColoredTeams).includes(t));), or if needed explicitly type t as
string/Team to satisfy TypeScript; reference symbols: isNumberedTeams,
playerTeams, ColoredTeams.
src/core/game/TeamAssignment.ts (1)

127-132: Consider limiting coalition name length

The PR objectives mention limiting hybrid names' character length to avoid UI/leaderboard overflow. Currently, long clan tags could produce names like VERYLONGTAG1 / VERYLONGTAG2 which might not fit well in the UI.

Consider adding a max-length check, falling back to null when the coalition string is too long.

💡 Possible length check
   // Coalition: top two clans cover the majority of humans
   if (sorted.length >= 2) {
     const [secondTag, secondCount] = sorted[1];
     if ((topCount + secondCount) / total > 0.5) {
-      return `${topTag} / ${secondTag}`;
+      const coalition = `${topTag} / ${secondTag}`;
+      const MAX_TEAM_NAME_LENGTH = 20; // adjust as needed
+      if (coalition.length <= MAX_TEAM_NAME_LENGTH) {
+        return coalition;
+      }
     }
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/core/game/TeamAssignment.ts` around lines 127 - 132, The coalition name
can become too long (e.g., "VERYLONGTAG1 / VERYLONGTAG2"); update the logic in
TeamAssignment where the coalition is formed (the block that computes `${topTag}
/ ${secondTag}` using sorted, topCount and secondCount) to enforce a maximum
character length: define a COALITION_NAME_MAX_LENGTH constant and before
returning the concatenated string check its length and return null if it exceeds
the limit. Ensure you apply the check to the exact return site that currently
returns `${topTag} / ${secondTag}` so long hybrid names are rejected
consistently.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/core/game/GameImpl.ts`:
- Around line 237-254: The collision check in GameImpl.ts only compares
renameMap.values() against themselves and misses conflicts where a newName
equals an existing team name that isn't being renamed; update the logic around
renameMap to also consider current team names in this.playerTeams (excluding the
team being renamed) by building a Set of existingNames from this.playerTeams
and, when iterating renameMap.entries(), drop the rename
(renameMap.delete(oldTeam)) if newName exists in existingNames or if it collides
with another rename as currently checked; keep the subsequent application to
this.playerTeams and playerToTeam unchanged.

---

Nitpick comments:
In `@src/core/game/GameImpl.ts`:
- Around line 216-218: The includes cast is too loose: in GameImpl.ts update the
isNumberedTeams expression to remove the unnecessary "as any" by comparing the
team value directly against the ColoredTeams values (e.g. const isNumberedTeams
= !this.playerTeams.some(t => Object.values(ColoredTeams).includes(t));), or if
needed explicitly type t as string/Team to satisfy TypeScript; reference
symbols: isNumberedTeams, playerTeams, ColoredTeams.

In `@src/core/game/TeamAssignment.ts`:
- Around line 127-132: The coalition name can become too long (e.g.,
"VERYLONGTAG1 / VERYLONGTAG2"); update the logic in TeamAssignment where the
coalition is formed (the block that computes `${topTag} / ${secondTag}` using
sorted, topCount and secondCount) to enforce a maximum character length: define
a COALITION_NAME_MAX_LENGTH constant and before returning the concatenated
string check its length and return null if it exceeds the limit. Ensure you
apply the check to the exact return site that currently returns `${topTag} /
${secondTag}` so long hybrid names are rejected consistently.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a7b137b and 395c51d.

📒 Files selected for processing (3)
  • src/core/game/GameImpl.ts
  • src/core/game/TeamAssignment.ts
  • tests/TeamAssignment.test.ts

@github-project-automation github-project-automation bot moved this from Triage to Development in OpenFront Release Management Feb 26, 2026
@bijx
Copy link
Contributor

bijx commented Feb 27, 2026

love this feature, reminds me of rocket league lol

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/core/game/GameImpl.ts`:
- Around line 241-251: The collision check for renames is flawed because
existingNames and newNames are computed once while renameMap is mutated; update
the logic to perform a fixed-point collision pass: repeatedly recompute
existingNames (teams not in renameMap) and newNames
(Array.from(renameMap.values())), iterate renameMap entries and remove any entry
whose newName collides with existingNames or appears more than once in newNames,
and repeat until a full pass makes no deletions, then apply the remaining
renames; reference renameMap, existingNames, newNames, and this.playerTeams when
locating the code to change.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 395c51d and 1ddccba.

📒 Files selected for processing (1)
  • src/core/game/GameImpl.ts

@iiamlewis iiamlewis added this to the Backlog milestone Mar 2, 2026
@iiamlewis iiamlewis added the needs-grooming This feature has not been approved. label Mar 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-grooming This feature has not been approved.

Projects

Status: Development

Development

Successfully merging this pull request may close these issues.

Feature: Team naming based on player clan tags

4 participants