Add time limit modifier for public games ⏱️

Adds a "time limit" modifier (10/20/30 min) to the public special-game
modifier pool, alongside existing modifiers like starting gold and water
nukes. Reuses the existing maxTimerValue config field, which WinCheckExecution
already enforces (territory leader wins when the timer expires).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Evan Pelle
2026-06-15 16:13:09 +00:00
parent 5be72db060
commit aeb6f9cf66
5 changed files with 38 additions and 3 deletions
+2
View File
@@ -1128,6 +1128,8 @@
"sams_disabled_label": "SAMs",
"starting_gold": "{amount}M Starting Gold",
"starting_gold_label": "Starting Gold",
"time_limit": "{amount}min Time Limit",
"time_limit_label": "Time Limit",
"water_nukes": "Water Nukes",
"water_nukes_label": "Water Nukes"
},
+11
View File
@@ -220,6 +220,17 @@ export function getActiveModifiers(
badgeKey: "public_game_modifier.water_nukes",
});
}
if (modifiers.maxTimerValue) {
result.push({
labelKey: "public_game_modifier.time_limit_label",
badgeKey: "public_game_modifier.time_limit",
badgeParams: {
amount: modifiers.maxTimerValue,
},
value: modifiers.maxTimerValue,
formattedValue: `${modifiers.maxTimerValue} min`,
});
}
return result;
}
+1
View File
@@ -264,6 +264,7 @@ export const GameConfigSchema = z.object({
isSAMsDisabled: z.boolean().optional(),
isPeaceTime: z.boolean().optional(),
isWaterNukes: z.boolean().optional(),
maxTimerValue: z.number().int().min(1).optional(),
})
.optional(),
nations: z
+1
View File
@@ -143,6 +143,7 @@ export interface PublicGameModifiers {
isSAMsDisabled?: boolean;
isPeaceTime?: boolean;
isWaterNukes?: boolean;
maxTimerValue?: number;
}
export interface UnitInfo {
+23 -3
View File
@@ -75,7 +75,10 @@ type ModifierKey =
| "isNukesDisabled"
| "isSAMsDisabled"
| "isPeaceTime"
| "isWaterNukes";
| "isWaterNukes"
| "timeLimit10M"
| "timeLimit20M"
| "timeLimit30M";
// Each entry represents one "ticket" in the pool. More tickets = higher chance of selection.
// Weights are roughly informed by the community "favorite modifier" poll.
@@ -94,6 +97,9 @@ const SPECIAL_MODIFIER_POOL: ModifierKey[] = [
...Array<ModifierKey>(1).fill("isSAMsDisabled"),
...Array<ModifierKey>(1).fill("isPeaceTime"),
...Array<ModifierKey>(4).fill("isWaterNukes"),
...Array<ModifierKey>(2).fill("timeLimit10M"),
...Array<ModifierKey>(2).fill("timeLimit20M"),
...Array<ModifierKey>(1).fill("timeLimit30M"),
];
// Maps where water nukes have a higher chance on top of the normal pool
@@ -122,6 +128,9 @@ const MUTUALLY_EXCLUSIVE_MODIFIERS: [ModifierKey, ModifierKey][] = [
["isHardNations", "startingGold25M"],
["isNukesDisabled", "isSAMsDisabled"],
["isNukesDisabled", "isWaterNukes"],
["timeLimit10M", "timeLimit20M"],
["timeLimit10M", "timeLimit30M"],
["timeLimit20M", "timeLimit30M"],
];
export class MapPlaylist {
@@ -263,6 +272,7 @@ export class MapPlaylist {
isSAMsDisabled,
isPeaceTime,
isWaterNukes,
maxTimerValue,
} = poolResult;
if (boostWaterNukes) {
isWaterNukes = true;
@@ -290,7 +300,8 @@ export class MapPlaylist {
!isNukesDisabled &&
!isSAMsDisabled &&
!isPeaceTime &&
!isWaterNukes
!isWaterNukes &&
maxTimerValue === undefined
) {
excludedModifiers.push("isCrowded");
const fallback = this.getRandomSpecialGameModifiers(
@@ -308,6 +319,7 @@ export class MapPlaylist {
isSAMsDisabled,
isPeaceTime,
isWaterNukes,
maxTimerValue,
} = fallback);
({ isHardNations } = fallback);
}
@@ -368,6 +380,7 @@ export class MapPlaylist {
isSAMsDisabled,
isPeaceTime,
isWaterNukes,
maxTimerValue,
},
startingGold,
goldMultiplier,
@@ -378,7 +391,7 @@ export class MapPlaylist {
: Difficulty.Medium,
infiniteGold: false,
infiniteTroops: false,
maxTimerValue: undefined,
maxTimerValue,
instantBuild: false,
randomSpawn: isRandomSpawn ? true : false,
nations,
@@ -573,6 +586,13 @@ export class MapPlaylist {
isSAMsDisabled: selected.has("isSAMsDisabled") || undefined,
isPeaceTime: selected.has("isPeaceTime") || undefined,
isWaterNukes: selected.has("isWaterNukes") || undefined,
maxTimerValue: selected.has("timeLimit10M")
? 10
: selected.has("timeLimit20M")
? 20
: selected.has("timeLimit30M")
? 30
: undefined,
};
}