From 4d528548c7f3f189f4b7f29e7dcf31d6272b70a5 Mon Sep 17 00:00:00 2001 From: Restart2008 Date: Fri, 24 Oct 2025 20:08:58 -0700 Subject: [PATCH] NukeWars: only block MIRV; prevent ships crossing midpoint; bias spawn selection toward midpoint for balance --- src/core/configuration/DefaultConfig.ts | 14 +++-------- src/core/execution/MoveWarshipExecution.ts | 27 +++++++++++++++++++++- src/core/execution/SpawnExecution.ts | 20 ++++++++++------ src/core/game/PlayerImpl.ts | 26 ++++++++++++--------- src/core/game/TransportShipUtils.ts | 26 ++++++++++++++++++++- 5 files changed, 82 insertions(+), 31 deletions(-) diff --git a/src/core/configuration/DefaultConfig.ts b/src/core/configuration/DefaultConfig.ts index aaea7ec8d..0e197bd25 100644 --- a/src/core/configuration/DefaultConfig.ts +++ b/src/core/configuration/DefaultConfig.ts @@ -319,20 +319,12 @@ export class DefaultConfig implements Config { } isUnitDisabled(unitType: UnitType): boolean { - // First check game mode specific restrictions + // Nuke Wars: only MIRV is blocked explicitly. Keep any server-configured + // disabledUnits in the check as well. if (this._gameConfig.gameMode === GameMode.NukeWars) { - const allowedUnits = [ - UnitType.MissileSilo, - UnitType.SAMLauncher, - UnitType.AtomBomb, - UnitType.HydrogenBomb, - ]; - if (!allowedUnits.includes(unitType)) { - return true; - } + if (unitType === UnitType.MIRV) return true; } - // Then check manually disabled units return this._gameConfig.disabledUnits?.includes(unitType) ?? false; } diff --git a/src/core/execution/MoveWarshipExecution.ts b/src/core/execution/MoveWarshipExecution.ts index 0a0aad166..8327b0ad5 100644 --- a/src/core/execution/MoveWarshipExecution.ts +++ b/src/core/execution/MoveWarshipExecution.ts @@ -1,4 +1,11 @@ -import { Execution, Game, Player, UnitType } from "../game/Game"; +import { + Execution, + Game, + GameMapType, + GameMode, + Player, + UnitType, +} from "../game/Game"; import { TileRef } from "../game/GameMap"; export class MoveWarshipExecution implements Execution { @@ -24,6 +31,24 @@ export class MoveWarshipExecution implements Execution { console.warn("MoveWarshipExecution: warship is not active"); return; } + // In Nuke Wars on Baikal, prevent assigning patrols that cross the midpoint. + const gc = mg.config().gameConfig(); + if ( + gc.gameMode === GameMode.NukeWars && + gc.gameMap === GameMapType.Baikal + ) { + const mapWidth = mg.width(); + const wantLeft = this.owner.smallID() % 2 === 1; + const posLeft = mg.x(this.position) < Math.floor(mapWidth / 2); + if (wantLeft !== posLeft) { + // reject the move + console.warn( + "MoveWarshipExecution: cannot assign warship patrol across midpoint in Nuke Wars", + ); + return; + } + } + warship.setPatrolTile(this.position); warship.setTargetTile(undefined); } diff --git a/src/core/execution/SpawnExecution.ts b/src/core/execution/SpawnExecution.ts index 89365cbf6..2f24052f8 100644 --- a/src/core/execution/SpawnExecution.ts +++ b/src/core/execution/SpawnExecution.ts @@ -59,18 +59,24 @@ export class SpawnExecution implements Execution { const wantLeft = player.smallID() % 2 === 1; const isLeft = tx < Math.floor(mapWidth / 2); if (wantLeft !== isLeft) { - // Find nearest valid tile on the correct half + // Find nearest valid tile on the correct half. Bias selection toward + // tiles closer to the midpoint so both sides get spawn tiles that + // produce more balanced territory when map land distribution is uneven. let best: TileRef | null = null; - let bestDist = Infinity; + let bestScore = Infinity; + const midpoint = Math.floor(mapWidth / 2); this.mg.forEachTile((t) => { const xt = this.mg.x(t); - const onCorrectHalf = wantLeft - ? xt < Math.floor(mapWidth / 2) - : xt >= Math.floor(mapWidth / 2); + const onCorrectHalf = wantLeft ? xt < midpoint : xt >= midpoint; if (onCorrectHalf && !this.mg.hasOwner(t) && this.mg.isLand(t)) { const d = this.mg.manhattanDist(this.tile, t); - if (d < bestDist) { - bestDist = d; + // score combines distance from original tile and distance from midpoint + // biasFactor controls how strongly we prefer midline tiles (0.0-1.0) + const biasFactor = 0.5; + const centerDistance = Math.abs(xt - midpoint); + const score = d + centerDistance * biasFactor; + if (score < bestScore) { + bestScore = score; best = t; } } diff --git a/src/core/game/PlayerImpl.ts b/src/core/game/PlayerImpl.ts index 5acde80b6..7972439ab 100644 --- a/src/core/game/PlayerImpl.ts +++ b/src/core/game/PlayerImpl.ts @@ -930,19 +930,23 @@ export class PlayerImpl implements Player { return false; } - // Check spawn zone restrictions in Nuke Wars mode - if (this.mg.config().gameConfig().gameMode === GameMode.NukeWars) { - // During spawn phase, enforce strict spawn zones - if (this.mg.inSpawnPhase() && !this.isInTeamSpawnZone(targetTile)) { - return false; + // Prevent crossing midpoint with ships/boats at any time in Nuke Wars. + const gc = this.mg.config().gameConfig(); + if ( + gc.gameMode === GameMode.NukeWars && + gc.gameMap === GameMapType.Baikal + ) { + if ( + unitType === UnitType.TransportShip || + unitType === UnitType.Warship || + unitType === UnitType.TradeShip + ) { + if (!this.isInTeamSpawnZone(targetTile)) return false; } - // After spawn phase, only allow missiles to cross the midpoint - if (!this.mg.inSpawnPhase() && !this.isInTeamSpawnZone(targetTile)) { - const allowedTypes = [UnitType.AtomBomb, UnitType.HydrogenBomb]; - if (!allowedTypes.includes(unitType)) { - return false; - } + // During spawn phase we enforce that regular land spawns happen on-team. + if (this.mg.inSpawnPhase() && !this.isInTeamSpawnZone(targetTile)) { + return false; } } diff --git a/src/core/game/TransportShipUtils.ts b/src/core/game/TransportShipUtils.ts index b457ad94a..f0bc25b8e 100644 --- a/src/core/game/TransportShipUtils.ts +++ b/src/core/game/TransportShipUtils.ts @@ -1,6 +1,6 @@ import { PathFindResultType } from "../pathfinding/AStar"; import { MiniAStar } from "../pathfinding/MiniAStar"; -import { Game, Player, UnitType } from "./Game"; +import { Game, GameMapType, GameMode, Player, UnitType } from "./Game"; import { andFN, GameMap, manhattanDistFN, TileRef } from "./GameMap"; export function canBuildTransportShip( @@ -49,6 +49,18 @@ export function canBuildTransportShip( } if (myPlayerBordersOcean && otherPlayerBordersOcean) { + // In Nuke Wars on Baikal, ensure transport source/destination are on same half. + const gc = game.config().gameConfig(); + if ( + gc.gameMode === GameMode.NukeWars && + gc.gameMap === GameMapType.Baikal + ) { + const mapWidth = game.width(); + const wantLeft = player.smallID() % 2 === 1; + const dstX = game.x(dst); + const dstLeft = dstX < Math.floor(mapWidth / 2); + if (wantLeft !== dstLeft) return false; + } return transportShipSpawn(game, player, dst); } else { return false; @@ -72,6 +84,18 @@ export function canBuildTransportShip( for (const t of sorted) { if (game.owner(t) === player) { + // Block cross-midpoint lake deployments in Nuke Wars on Baikal + const gc = game.config().gameConfig(); + if ( + gc.gameMode === GameMode.NukeWars && + gc.gameMap === GameMapType.Baikal + ) { + const mapWidth = game.width(); + const wantLeft = player.smallID() % 2 === 1; + const tX = game.x(t); + const tLeft = tX < Math.floor(mapWidth / 2); + if (wantLeft !== tLeft) return false; + } return transportShipSpawn(game, player, t); } }