Skip to content
3 changes: 2 additions & 1 deletion resources/lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,8 @@
"teams_Duos": "of 2 (Duos)",
"teams_Trios": "of 3 (Trios)",
"teams_Quads": "of 4 (Quads)",
"teams_hvn": "Humans Vs Nations",
"teams_hvn": "Humans vs Nations",
"teams_hvn_detailed": "{num} Humans vs {num} Nations",
"teams": "{num} teams",
"players_per_team": "of {num}"
},
Expand Down
21 changes: 18 additions & 3 deletions src/client/HostLobbyModal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -551,9 +551,9 @@ export class HostLobbyModal extends LitElement {
: translateText("host_modal.players")
}
<span style="margin: 0 8px;">•</span>
${this.disableNations ? 0 : this.nationCount}
${this.getEffectiveNationCount()}
${
this.nationCount === 1
this.getEffectiveNationCount() === 1
? translateText("host_modal.nation_player")
: translateText("host_modal.nation_players")
}
Expand All @@ -564,7 +564,7 @@ export class HostLobbyModal extends LitElement {
.clients=${this.clients}
.lobbyCreatorClientID=${this.lobbyCreatorClientID}
.teamCount=${this.teamCount}
.nationCount=${this.disableNations ? 0 : this.nationCount}
.nationCount=${this.getEffectiveNationCount()}
.onKickPlayer=${(clientID: string) => this.kickPlayer(clientID)}
></lobby-team-view>
</div>
Expand Down Expand Up @@ -876,6 +876,21 @@ export class HostLobbyModal extends LitElement {
this.nationCount = 0;
}
}

/**
* Returns the effective nation count for display purposes.
* In HumansVsNations mode, this equals the number of human players.
* Otherwise, it uses the manifest nation count (or 0 if nations are disabled).
*/
private getEffectiveNationCount(): number {
if (this.disableNations) {
return 0;
}
if (this.gameMode === GameMode.Team && this.teamCount === HumansVsNations) {
return this.clients.length;
}
return this.nationCount;
}
}

async function createLobby(creatorClientID: string): Promise<GameInfo> {
Expand Down
16 changes: 12 additions & 4 deletions src/client/PublicLobby.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ export class PublicLobby extends LitElement {
lobby.gameConfig.gameMode,
teamCount,
teamTotal,
teamSize,
);
const teamDetailLabel = this.getTeamDetailLabel(
lobby.gameConfig.gameMode,
Expand Down Expand Up @@ -241,7 +242,7 @@ export class PublicLobby extends LitElement {
if (teamCount === Duos) return 2;
if (teamCount === Trios) return 3;
if (teamCount === Quads) return 4;
if (teamCount === HumansVsNations) return Math.floor(maxPlayers / 2);
if (teamCount === HumansVsNations) return maxPlayers;
return undefined;
}
if (typeof teamCount === "number" && teamCount > 0) {
Expand All @@ -265,10 +266,13 @@ export class PublicLobby extends LitElement {
gameMode: GameMode,
teamCount: number | string | null,
teamTotal: number | undefined,
teamSize: number | undefined,
): string {
if (gameMode !== GameMode.Team) return translateText("game_mode.ffa");
if (teamCount === HumansVsNations)
return translateText("public_lobby.teams_hvn");
if (teamCount === HumansVsNations && teamSize !== undefined)
return translateText("public_lobby.teams_hvn_detailed", {
num: teamSize,
});
const totalTeams =
teamTotal ?? (typeof teamCount === "number" ? teamCount : 0);
return translateText("public_lobby.teams", { num: totalTeams });
Expand All @@ -282,7 +286,11 @@ export class PublicLobby extends LitElement {
): string | null {
if (gameMode !== GameMode.Team) return null;

if (typeof teamCount === "string" && teamCount !== HumansVsNations) {
if (typeof teamCount === "string" && teamCount === HumansVsNations) {
return null;
}

if (typeof teamCount === "string") {
const teamKey = `public_lobby.teams_${teamCount}`;
const maybeTranslated = translateText(teamKey);
if (maybeTranslated !== teamKey) return maybeTranslated;
Expand Down
17 changes: 7 additions & 10 deletions src/core/GameRunner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import {
Game,
GameUpdates,
NameViewData,
Nation,
Player,
PlayerActions,
PlayerBorderTiles,
Expand All @@ -26,6 +25,7 @@ import {
GameUpdateType,
GameUpdateViewData,
} from "./game/GameUpdates";
import { createNationsForGame } from "./game/NationUtils";
import { loadTerrainMap as loadGameMap } from "./game/TerrainMapLoader";
import { PseudoRandom } from "./PseudoRandom";
import { ClientID, GameStartInfo, Turn } from "./Schemas";
Expand Down Expand Up @@ -56,15 +56,12 @@ export async function createGameRunner(
);
});

const nations = gameStart.config.disableNations
? []
: gameMap.nations.map(
(n) =>
new Nation(
new Cell(n.coordinates[0], n.coordinates[1]),
new PlayerInfo(n.name, PlayerType.Nation, null, random.nextID()),
),
);
const nations = createNationsForGame(
gameStart,
gameMap.nations,
humans.length,
random,
);

const game: Game = createGame(
humans,
Expand Down
3 changes: 2 additions & 1 deletion src/core/configuration/DefaultConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,8 @@ export abstract class DefaultServerConfig implements ServerConfig {
p -= p % 4;
break;
case HumansVsNations:
// For HumansVsNations, return the base team player count
// Half the slots are for humans, the other half will get filled with nations
p = Math.floor(p / 2);
break;
default:
p -= p % numPlayerTeams;
Expand Down
12 changes: 11 additions & 1 deletion src/core/execution/NationExecution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,15 @@ export class NationExecution implements Execution {
}

if (this.mg.inSpawnPhase()) {
// select a tile near the position defined in the map manifest for the current nation
// Place nations without a spawn cell (Dynamically created for HumansVsNations) randomly by SpawnExecution
if (this.nation.spawnCell === undefined) {
this.mg.addExecution(
new SpawnExecution(this.gameID, this.nation.playerInfo),
);
return;
}

// Select a tile near the position defined in the map manifest
const rl = this.randomSpawnLand();

if (rl === null) {
Expand Down Expand Up @@ -194,6 +202,8 @@ export class NationExecution implements Execution {
}

private randomSpawnLand(): TileRef | null {
if (this.nation.spawnCell === undefined) throw new Error("not initialized");

const delta = 25;
let tries = 0;
while (tries < 50) {
Expand Down
2 changes: 1 addition & 1 deletion src/core/game/Game.ts
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ export enum Relation {

export class Nation {
constructor(
public readonly spawnCell: Cell,
public readonly spawnCell: Cell | undefined,
public readonly playerInfo: PlayerInfo,
) {}
}
Expand Down
Loading
Loading