Allow mappers to define additionalNations 🗺️ (#3902)

## Description:

Adds an optional `additionalNations` array to map manifests (info.json /
manifest.json), used as a name pool when a game requests more nations
than the map defines (HvN, private lobbies, solo games).

Suggested by mapmaker PatrickPlaysBadly.

When the requested nation count exceeds `nations.length`:
1. The deficit is filled by random picks from `additionalNations`
(collisions with manifest names are skipped).
2. If `additionalNations` still does not cover the deficit, the
remainder is generated procedurally as before.

Each entry supports `name`, optional `flag` and optional `coordinates`.
If `coordinates` are provided, the picked nation gets a spawn cell
(otherwise it spawns like the procedurally generated ones, with no fixed
location).

`Nation.flag` is also relaxed to optional, since many existing manifest
entries already omit it.

## Please complete the following:

- [X] 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
- [X] 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:

FloPinguin
This commit is contained in:
FloPinguin
2026-05-11 12:58:34 -07:00
committed by GitHub
parent f1d162825e
commit 19280c0b37
5 changed files with 332 additions and 7 deletions
+21 -1
View File
@@ -4,6 +4,7 @@ import { GameMapLoader } from "./GameMapLoader";
export type TerrainMapData = {
nations: Nation[];
additionalNations: AdditionalNation[];
gameMap: GameMap;
miniGameMap: GameMap;
teamGameSpawnAreas?: TeamGameSpawnAreas;
@@ -23,12 +24,22 @@ export interface MapManifest {
map4x: MapMetadata;
map16x: MapMetadata;
nations: Nation[];
// Optional pool of fallback nation names used when a game requests more
// nations than the manifest defines. Picked at random; if still not enough,
// the remainder is generated procedurally.
additionalNations?: AdditionalNation[];
teamGameSpawnAreas?: TeamGameSpawnAreas;
}
export interface Nation {
coordinates: [number, number];
flag: string;
flag?: string;
name: string;
}
export interface AdditionalNation {
coordinates?: [number, number];
flag?: string;
name: string;
}
@@ -63,6 +74,14 @@ export async function loadTerrainMap(
Math.floor(nation.coordinates[1] / 2),
];
});
manifest.additionalNations?.forEach((nation) => {
if (nation.coordinates !== undefined) {
nation.coordinates = [
Math.floor(nation.coordinates[0] / 2),
Math.floor(nation.coordinates[1] / 2),
];
}
});
}
// Scale spawn areas for compact maps
@@ -82,6 +101,7 @@ export async function loadTerrainMap(
const result = {
nations: manifest.nations,
additionalNations: manifest.additionalNations ?? [],
gameMap: gameMap,
miniGameMap: miniMap,
teamGameSpawnAreas,