mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-25 10:04:36 +00:00
Nation build order improvements 🤖 (#2833)
## Description: My first PR about the nation build order. This one is a bit important for HumansVsNations. - Nations build more SAMs in team games - Nations build less factories if they have access to the ocean (instead of focusing ports and factories with the same priority) - Nations no longer place defense posts "without reason" - only when they share a border with someone they haven't allied I'm planning to make the build order a bit different based on difficulty. ## 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:
@@ -2,6 +2,7 @@ import {
|
||||
Difficulty,
|
||||
Execution,
|
||||
Game,
|
||||
GameMode,
|
||||
Gold,
|
||||
Nation,
|
||||
Player,
|
||||
@@ -250,17 +251,31 @@ export class NationExecution implements Execution {
|
||||
|
||||
private handleUnits() {
|
||||
if (this.warshipBehavior === null) throw new Error("not initialized");
|
||||
const hasCoastalTiles = this.hasCoastalTiles();
|
||||
const isTeamGame = this.mg.config().gameConfig().gameMode === GameMode.Team;
|
||||
return (
|
||||
this.maybeSpawnStructure(UnitType.City, (num) => num) ||
|
||||
this.maybeSpawnStructure(UnitType.Port, (num) => num) ||
|
||||
this.warshipBehavior.maybeSpawnWarship() ||
|
||||
this.maybeSpawnStructure(UnitType.Factory, (num) => num) ||
|
||||
this.maybeSpawnStructure(UnitType.Factory, (num) =>
|
||||
hasCoastalTiles ? num * 3 : num,
|
||||
) ||
|
||||
this.maybeSpawnStructure(UnitType.DefensePost, (num) => (num + 2) ** 2) ||
|
||||
this.maybeSpawnStructure(UnitType.SAMLauncher, (num) => num ** 2) ||
|
||||
this.maybeSpawnStructure(UnitType.SAMLauncher, (num) =>
|
||||
isTeamGame ? num : num ** 2,
|
||||
) ||
|
||||
this.maybeSpawnStructure(UnitType.MissileSilo, (num) => num ** 2)
|
||||
);
|
||||
}
|
||||
|
||||
private hasCoastalTiles(): boolean {
|
||||
if (this.player === null) throw new Error("not initialized");
|
||||
for (const tile of this.player.borderTiles()) {
|
||||
if (this.mg.isOceanShore(tile)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private maybeSpawnStructure(
|
||||
type: UnitType,
|
||||
multiplier: (num: number) => number,
|
||||
@@ -294,6 +309,7 @@ export class NationExecution implements Execution {
|
||||
: randTerritoryTileArray(this.random, this.mg, this.player, 25);
|
||||
if (tiles.length === 0) return null;
|
||||
const valueFunction = structureSpawnTileValue(this.mg, this.player, type);
|
||||
if (valueFunction === null) return null;
|
||||
let bestTile: TileRef | null = null;
|
||||
let bestValue = 0;
|
||||
for (const t of tiles) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Game, Player, Relation, UnitType } from "../../game/Game";
|
||||
import { Game, Player, PlayerType, Relation, UnitType } from "../../game/Game";
|
||||
import { TileRef } from "../../game/GameMap";
|
||||
import { closestTile, closestTwoTiles } from "../Util";
|
||||
|
||||
@@ -6,7 +6,7 @@ export function structureSpawnTileValue(
|
||||
mg: Game,
|
||||
player: Player,
|
||||
type: UnitType,
|
||||
): (tile: TileRef) => number {
|
||||
): ((tile: TileRef) => number) | null {
|
||||
const borderTiles = player.borderTiles();
|
||||
const otherUnits = player.units(type);
|
||||
// Prefer spacing structures out of atom bomb range
|
||||
@@ -57,6 +57,22 @@ export function structureSpawnTileValue(
|
||||
};
|
||||
}
|
||||
case UnitType.DefensePost: {
|
||||
// Check if we have any non-friendly non-bot neighbors
|
||||
const hasHostileNeighbor =
|
||||
player
|
||||
.neighbors()
|
||||
.filter(
|
||||
(n): n is Player =>
|
||||
n.isPlayer() &&
|
||||
player.isFriendly(n) === false &&
|
||||
n.type() !== PlayerType.Bot,
|
||||
).length > 0;
|
||||
|
||||
// Don't build defense posts if there is no danger
|
||||
if (!hasHostileNeighbor) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (tile) => {
|
||||
let w = 0;
|
||||
|
||||
@@ -79,6 +95,7 @@ export function structureSpawnTileValue(
|
||||
if (id === player.smallID()) continue;
|
||||
const neighbor = mg.playerBySmallID(id);
|
||||
if (!neighbor.isPlayer()) continue;
|
||||
if (neighbor.type() === PlayerType.Bot) continue;
|
||||
neighbors.add(neighbor);
|
||||
}
|
||||
for (const neighbor of neighbors) {
|
||||
|
||||
Reference in New Issue
Block a user