From f0f9318852dd901890c8a3d4de1c9947f7c6d6a8 Mon Sep 17 00:00:00 2001
From: Scott Anderson <662325+scottanderson@users.noreply.github.com>
Date: Mon, 25 Aug 2025 19:26:02 -0400
Subject: [PATCH] Nations build defense posts (#1935)
## Description:
Nations build defense posts. Fixes #1854.
## 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
---
src/core/execution/FakeHumanExecution.ts | 1 +
.../nation/structureSpawnTileValue.ts | 48 +++++++++++++++++--
2 files changed, 45 insertions(+), 4 deletions(-)
diff --git a/src/core/execution/FakeHumanExecution.ts b/src/core/execution/FakeHumanExecution.ts
index 10eac66ea..bae5b3690 100644
--- a/src/core/execution/FakeHumanExecution.ts
+++ b/src/core/execution/FakeHumanExecution.ts
@@ -461,6 +461,7 @@ export class FakeHumanExecution implements Execution {
this.maybeSpawnStructure(UnitType.Port) ||
this.maybeSpawnWarship() ||
this.maybeSpawnStructure(UnitType.Factory) ||
+ this.maybeSpawnStructure(UnitType.DefensePost) ||
this.maybeSpawnStructure(UnitType.SAMLauncher) ||
this.maybeSpawnStructure(UnitType.MissileSilo)
);
diff --git a/src/core/execution/nation/structureSpawnTileValue.ts b/src/core/execution/nation/structureSpawnTileValue.ts
index 55e1cfa90..e1a716e7c 100644
--- a/src/core/execution/nation/structureSpawnTileValue.ts
+++ b/src/core/execution/nation/structureSpawnTileValue.ts
@@ -1,4 +1,4 @@
-import { Game, Player, UnitType } from "../../game/Game";
+import { Game, Player, Relation, UnitType } from "../../game/Game";
import { TileRef } from "../../game/GameMap";
import { closestTwoTiles } from "../Util";
@@ -46,7 +46,47 @@ export function structureSpawnTileValue(
return (tile) => {
let w = 0;
- // Prefer to be far away from other structures of the same type
+ // Prefer to be away from other structures of the same type
+ const otherTiles: Set = new Set(otherUnits.map((u) => u.tile()));
+ otherTiles.delete(tile);
+ const closestOther = closestTwoTiles(mg, otherTiles, [tile]);
+ if (closestOther !== null) {
+ const d = mg.manhattanDist(closestOther.x, tile);
+ w += Math.min(d, structureSpacing);
+ }
+
+ return w;
+ };
+ }
+ case UnitType.DefensePost: {
+ return (tile) => {
+ let w = 0;
+
+ // Prefer higher elevations
+ w += mg.magnitude(tile);
+
+ const closestBorder = closestTwoTiles(mg, borderTiles, [tile]);
+ if (closestBorder !== null) {
+ // Prefer to be borderSpacing tiles from the border
+ const d = mg.manhattanDist(closestBorder.x, tile);
+ w += Math.max(0, borderSpacing - Math.abs(borderSpacing - d));
+
+ // Prefer adjacent players who are hostile
+ const neighbors: Set = new Set();
+ for (const tile of mg.neighbors(closestBorder.x)) {
+ if (!mg.isLand(tile)) continue;
+ const id = mg.ownerID(tile);
+ if (id === player.smallID()) continue;
+ const neighbor = mg.playerBySmallID(id);
+ if (!neighbor.isPlayer()) continue;
+ neighbors.add(neighbor);
+ }
+ for (const neighbor of neighbors) {
+ w += borderSpacing * (Relation.Friendly - player.relation(neighbor));
+ }
+ }
+
+ // Prefer to be away from other structures of the same type
const otherTiles: Set = new Set(otherUnits.map((u) => u.tile()));
otherTiles.delete(tile);
const closestOther = closestTwoTiles(mg, otherTiles, [tile]);
@@ -61,7 +101,7 @@ export function structureSpawnTileValue(
case UnitType.SAMLauncher: {
const protectTiles: Set = new Set();
for (const unit of player.units()) {
- switch(unit.type()) {
+ switch (unit.type()) {
case UnitType.City:
case UnitType.Factory:
case UnitType.MissileSilo:
@@ -84,7 +124,7 @@ export function structureSpawnTileValue(
w += Math.min(d, borderSpacing);
}
- // Prefer to be far away from other structures of the same type
+ // Prefer to be away from other structures of the same type
const otherTiles: Set = new Set(otherUnits.map((u) => u.tile()));
otherTiles.delete(tile);
const closestOther = closestTwoTiles(mg, otherTiles, [tile]);