NukeWars: only block MIRV; prevent ships crossing midpoint; bias spawn selection toward midpoint for balance

This commit is contained in:
Restart2008
2025-10-24 20:08:58 -07:00
parent 0e90699c10
commit 4d528548c7
5 changed files with 82 additions and 31 deletions
+3 -11
View File
@@ -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;
}
+26 -1
View File
@@ -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);
}
+13 -7
View File
@@ -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;
}
}
+15 -11
View File
@@ -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;
}
}
+25 -1
View File
@@ -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);
}
}