feat(lobby): surface Doomsday Clock preset + anonymous names as lobby settings (#4616)

## Description:

Public rotation lobbies can run the **Doomsday Clock** at one of four
presets (slow/normal/fast/veryfast), and lobbies can **anonymize player
names**, but the lobby UI surfaced neither: the Doomsday Clock badge was
generic and there were no settings cards for either. Players couldn't
tell what a lobby was actually set to.

This surfaces both as regular lobby settings, matching how the other
modifiers already display:

- **Settings cards** (join/waiting view): adds a "Doomsday Clock" card
showing the active preset name, and an "Anonymous Players" card,
alongside the existing modifier cards.
- **Lobby badge** (home lobby list): the Doomsday Clock badge now reads
"Doomsday Clock: Fast" instead of the generic label. Falls back to the
plain label when no speed is present (older payloads / non-rotation
lobbies).

Client-only. Both `doomsdayClock.speed` and `anonymizeNames` already
ship in the public `GameConfig`, so no server or schema changes are
needed.


## Please complete the following:

- [] I have added screenshots for all UI updates
- [x] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [x] I have added relevant tests to the test directory

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

zixer._
This commit is contained in:
Zixer1
2026-07-15 17:20:53 -07:00
committed by GitHub
parent f6e1b8fbae
commit 4621084500
5 changed files with 44 additions and 3 deletions
+1
View File
@@ -1255,6 +1255,7 @@
"disable_alliances_label": "Alliances",
"doomsday_clock": "Doomsday Clock",
"doomsday_clock_label": "Doomsday Clock",
"doomsday_clock_with_speed": "Doomsday Clock: {speed}",
"gold_multiplier": "x{amount} Gold Multiplier",
"hard_nations": "Hard Nations",
"nukes_disabled": "Nukes Disabled",
+1
View File
@@ -329,6 +329,7 @@ export class GameModeSelector extends LitElement {
const modifierLabels = getModifierLabels(
lobby.gameConfig?.publicGameModifiers,
lobby.gameConfig?.doomsdayClock?.speed,
);
// Sort by length for visual consistency (shorter labels first)
if (modifierLabels.length > 1) {
+16
View File
@@ -640,6 +640,22 @@ export class JoinLobbyModal extends BaseModal {
.value=${translateText("common.enabled")}
></lobby-config-item>`,
);
if (c.doomsdayClock?.enabled)
cards.push(
html`<lobby-config-item
.label=${translateText("public_game_modifier.doomsday_clock_label")}
.value=${translateText(
`doomsday_clock_speed.${c.doomsdayClock.speed ?? "normal"}`,
)}
></lobby-config-item>`,
);
if (c.anonymizeNames)
cards.push(
html`<lobby-config-item
.label=${translateText("host_modal.anonymous_players")}
.value=${translateText("common.enabled")}
></lobby-config-item>`,
);
if ((isTeam && !c.donateGold) || (!isTeam && c.donateGold))
cards.push(
html`<lobby-config-item
+15 -3
View File
@@ -1,4 +1,5 @@
import IntlMessageFormat from "intl-messageformat";
import { DoomsdayClockSpeed } from "../core/game/DoomsdayClock";
import {
Duos,
GameMode,
@@ -131,6 +132,7 @@ export interface ModifierInfo {
*/
export function getActiveModifiers(
modifiers: PublicGameModifiers | undefined,
doomsdayClockSpeed?: DoomsdayClockSpeed,
): ModifierInfo[] {
if (!modifiers) return [];
const result: ModifierInfo[] = [];
@@ -221,10 +223,19 @@ export function getActiveModifiers(
});
}
if (modifiers.isDoomsdayClock) {
result.push({
const info: ModifierInfo = {
labelKey: "public_game_modifier.doomsday_clock_label",
badgeKey: "public_game_modifier.doomsday_clock",
});
};
// Name the preset when we know it; older payloads / non-rotation lobbies
// may not carry a speed, so keep the plain badge as a fallback.
if (doomsdayClockSpeed !== undefined) {
info.badgeKey = "public_game_modifier.doomsday_clock_with_speed";
info.badgeParams = {
speed: translateText(`doomsday_clock_speed.${doomsdayClockSpeed}`),
};
}
result.push(info);
}
return result;
}
@@ -234,8 +245,9 @@ export function getActiveModifiers(
*/
export function getModifierLabels(
modifiers: PublicGameModifiers | undefined,
doomsdayClockSpeed?: DoomsdayClockSpeed,
): string[] {
return getActiveModifiers(modifiers).map((m) =>
return getActiveModifiers(modifiers, doomsdayClockSpeed).map((m) =>
translateText(m.badgeKey, m.badgeParams),
);
}
@@ -12,6 +12,17 @@ describe("doomsday clock public modifier", () => {
expect(mods[0].labelKey).toBe("public_game_modifier.doomsday_clock_label");
});
it("names the preset when a speed is provided", () => {
const mods = getActiveModifiers({ isDoomsdayClock: true }, "fast");
expect(mods).toHaveLength(1);
expect(mods[0].badgeKey).toBe(
"public_game_modifier.doomsday_clock_with_speed",
);
expect(mods[0].labelKey).toBe("public_game_modifier.doomsday_clock_label");
// The speed is resolved to its translated label and passed as a badge param.
expect(mods[0].badgeParams?.speed).toBeDefined();
});
it("omits the badge when the modifier is absent", () => {
expect(getActiveModifiers({})).toHaveLength(0);
expect(getActiveModifiers(undefined)).toHaveLength(0);