From 8f8de97d9bfa35cf8f384309b759747f3d1ff653 Mon Sep 17 00:00:00 2001 From: Evan Date: Sun, 17 Nov 2024 10:33:13 -0800 Subject: [PATCH] remove BuildValidator --- TODO.txt | 2 ++ src/client/graphics/GameRenderer.ts | 2 -- .../graphics/layers/radial/BuildMenu.ts | 4 +-- src/core/execution/MissileSiloExecution.ts | 9 ++--- src/core/execution/NukeExecution.ts | 3 +- src/core/execution/PortExecution.ts | 3 +- src/core/execution/TradeShipExecution.ts | 1 - src/core/game/BuildValidator.ts | 34 ------------------- src/core/game/Game.ts | 2 ++ src/core/game/PlayerImpl.ts | 28 ++++++++++++++- 10 files changed, 36 insertions(+), 52 deletions(-) delete mode 100644 src/core/game/BuildValidator.ts diff --git a/TODO.txt b/TODO.txt index 37549b742..9ecdd6013 100644 --- a/TODO.txt +++ b/TODO.txt @@ -184,12 +184,14 @@ * trade ship gives gold when completes route DONE 11/15/2024 * add missile silo DONE 11/15/2024 * nuke spawns from missile silo DONE 11/16/2024 +* REFACTOR: move canbuild to player * BUG: can build destroyer on land * make two nukes: atom & hydrogen * destroyer can capture trade ships * add battleship * add defense post * add radiation from nuke +* only show units you can build in the build menu * REFACTOR: make TransportShip follow build unit flow * NPC has relations * use twitter emojis diff --git a/src/client/graphics/GameRenderer.ts b/src/client/graphics/GameRenderer.ts index 7a248fd5c..e3de4a53e 100644 --- a/src/client/graphics/GameRenderer.ts +++ b/src/client/graphics/GameRenderer.ts @@ -15,7 +15,6 @@ import { ControlPanel } from "./layers/ControlPanel"; import { UIState } from "./UIState"; import { BuildMenu } from "./layers/radial/BuildMenu"; import { UnitLayer } from "./layers/UnitLayer"; -import { BuildValidator } from "../../core/game/BuildValidator"; import { StructureLayer } from "./layers/StructureLayer"; @@ -35,7 +34,6 @@ export function createRenderer(canvas: HTMLCanvasElement, game: Game, eventBus: } buildMenu.game = game buildMenu.eventBus = eventBus - buildMenu.buildValidator = new BuildValidator(game) const leaderboard = document.querySelector('leader-board') as Leaderboard; if (!emojiTable || !(leaderboard instanceof Leaderboard)) { diff --git a/src/client/graphics/layers/radial/BuildMenu.ts b/src/client/graphics/layers/radial/BuildMenu.ts index 2d0e3357a..69d293094 100644 --- a/src/client/graphics/layers/radial/BuildMenu.ts +++ b/src/client/graphics/layers/radial/BuildMenu.ts @@ -9,7 +9,6 @@ import missileSiloIcon from '../../../../../resources/images/MissileSiloIconWhit import goldCoinIcon from '../../../../../resources/images/GoldCoinIcon.svg'; import portIcon from '../../../../../resources/images/PortIcon.svg'; import { renderNumber } from '../../Utils'; -import { BuildValidator } from '../../../../core/game/BuildValidator'; import { ContextMenuEvent } from '../../../InputHandler'; interface BuildItemDisplay { @@ -30,7 +29,6 @@ const buildTable: BuildItemDisplay[][] = [ export class BuildMenu extends LitElement { public game: Game; public eventBus: EventBus; - public buildValidator: BuildValidator; private myPlayer: Player; private clickedCell: Cell; @@ -152,7 +150,7 @@ export class BuildMenu extends LitElement { if (this.myPlayer == null) { return false } - return this.buildValidator.canBuild(this.myPlayer, this.game.tile(this.clickedCell), item.unitType) + return this.myPlayer.canBuild(item.unitType, this.game.tile(this.clickedCell)) } public onBuildSelected = (item: BuildItemDisplay) => { diff --git a/src/core/execution/MissileSiloExecution.ts b/src/core/execution/MissileSiloExecution.ts index 365371a40..6b580bcd7 100644 --- a/src/core/execution/MissileSiloExecution.ts +++ b/src/core/execution/MissileSiloExecution.ts @@ -1,9 +1,4 @@ -import { BuildValidator } from "../game/BuildValidator"; -import { AllPlayers, Cell, Execution, MutableGame, MutablePlayer, MutableUnit, Player, PlayerID, Tile, Unit, UnitType } from "../game/Game"; -import { AStar, PathFinder } from "../PathFinding"; -import { PseudoRandom } from "../PseudoRandom"; -import { bfs, dist, manhattanDist } from "../Util"; -import { TradeShipExecution } from "./TradeShipExecution"; +import { Cell, Execution, MutableGame, MutablePlayer, MutableUnit, Player, PlayerID, Tile, Unit, UnitType } from "../game/Game"; export class MissileSiloExecution implements Execution { @@ -26,7 +21,7 @@ export class MissileSiloExecution implements Execution { tick(ticks: number): void { if (this.silo == null) { const tile = this.mg.tile(this.cell) - if (!new BuildValidator(this.mg).canBuild(this.player, tile, UnitType.MissileSilo)) { + if (!this.player.canBuild(UnitType.MissileSilo, tile)) { console.warn(`player ${this.player} cannot build port at ${this.cell}`) this.active = false return diff --git a/src/core/execution/NukeExecution.ts b/src/core/execution/NukeExecution.ts index 7d402ab74..abd21d1ad 100644 --- a/src/core/execution/NukeExecution.ts +++ b/src/core/execution/NukeExecution.ts @@ -1,4 +1,3 @@ -import { BuildValidator } from "../game/BuildValidator"; import { Cell, Execution, MutableGame, MutablePlayer, PlayerID, Tile, MutableUnit, UnitType } from "../game/Game"; import { PathFinder } from "../PathFinding"; import { PseudoRandom } from "../PseudoRandom"; @@ -35,7 +34,7 @@ export class NukeExecution implements Execution { tick(ticks: number): void { if (this.nuke == null) { - if (new BuildValidator(this.mg).canBuild(this.player, this.dst, UnitType.Nuke)) { + if (this.player.canBuild(UnitType.Nuke, this.dst)) { const spawn = this.player.units(UnitType.MissileSilo) .sort((a, b) => manhattanDist(a.tile().cell(), this.cell) - manhattanDist(b.tile().cell(), this.cell))[0] this.nuke = this.player.buildUnit(UnitType.Nuke, 0, spawn.tile()) diff --git a/src/core/execution/PortExecution.ts b/src/core/execution/PortExecution.ts index 05964344b..e889556e7 100644 --- a/src/core/execution/PortExecution.ts +++ b/src/core/execution/PortExecution.ts @@ -1,4 +1,3 @@ -import { BuildValidator } from "../game/BuildValidator"; import { AllPlayers, Cell, Execution, MutableGame, MutablePlayer, MutableUnit, Player, PlayerID, Tile, Unit, UnitType } from "../game/Game"; import { AStar, PathFinder } from "../PathFinding"; import { PseudoRandom } from "../PseudoRandom"; @@ -30,7 +29,7 @@ export class PortExecution implements Execution { tick(ticks: number): void { if (this.port == null) { const tile = this.mg.tile(this.cell) - if (!new BuildValidator(this.mg).canBuild(this.player, tile, UnitType.Port)) { + if (!this.player.canBuild(UnitType.Port, tile)) { console.warn(`player ${this.player} cannot build port at ${this.cell}`) this.active = false return diff --git a/src/core/execution/TradeShipExecution.ts b/src/core/execution/TradeShipExecution.ts index 2578f22ef..a173622ff 100644 --- a/src/core/execution/TradeShipExecution.ts +++ b/src/core/execution/TradeShipExecution.ts @@ -1,4 +1,3 @@ -import { BuildValidator } from "../game/BuildValidator"; import { AllPlayers, Cell, Execution, MutableGame, MutablePlayer, MutableUnit, Player, PlayerID, Tile, Unit, UnitType } from "../game/Game"; import { AStar, PathFinder } from "../PathFinding"; import { PseudoRandom } from "../PseudoRandom"; diff --git a/src/core/game/BuildValidator.ts b/src/core/game/BuildValidator.ts deleted file mode 100644 index 725af9a32..000000000 --- a/src/core/game/BuildValidator.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { bfs, dist, manhattanDist } from "../Util"; -import { Game, Player, Tile, UnitType } from "./Game"; - -export class BuildValidator { - constructor(private game: Game) { } - - canBuild(player: Player, tile: Tile, unitType: UnitType): boolean { - const cost = this.game.unitInfo(unitType).cost - if (!player.isAlive() || player.gold() < cost) { - return false - } - switch (unitType) { - case UnitType.Nuke: - return player.units(UnitType.MissileSilo).length > 0 - case UnitType.Port: - return this.canBuildPort(player, tile) - case UnitType.Destroyer: - return this.canBuildDestroyer(player, tile) - case UnitType.MissileSilo: - return tile.owner() == player - } - } - - canBuildPort(player: Player, tile: Tile): boolean { - return Array.from(bfs(tile, dist(tile, 20))) - .filter(t => t.owner() == player && t.isOceanShore()).length > 0 - - } - - canBuildDestroyer(player: Player, tile: Tile): boolean { - return player.units(UnitType.Port) - .filter(u => manhattanDist(u.tile().cell(), tile.cell()) < this.game.config().boatMaxDistance()).length > 0 - } -} \ No newline at end of file diff --git a/src/core/game/Game.ts b/src/core/game/Game.ts index d8c62feaa..cca4e10b4 100644 --- a/src/core/game/Game.ts +++ b/src/core/game/Game.ts @@ -213,6 +213,8 @@ export interface Player { // Number between 0, 1 targetTroopRatio(): number troops(): number + + canBuild(type: UnitType, tile: Tile): boolean } export interface MutablePlayer extends Player { diff --git a/src/core/game/PlayerImpl.ts b/src/core/game/PlayerImpl.ts index 4f51a0257..6803cb0d0 100644 --- a/src/core/game/PlayerImpl.ts +++ b/src/core/game/PlayerImpl.ts @@ -1,6 +1,6 @@ import { MutablePlayer, Tile, PlayerInfo, PlayerID, PlayerType, Player, TerraNullius, Cell, Execution, AllianceRequest, MutableAllianceRequest, MutableAlliance, Alliance, Tick, TargetPlayerEvent, EmojiMessage, EmojiMessageEvent, AllPlayers, Gold, UnitType } from "./Game"; import { ClientID } from "../Schemas"; -import { processName, simpleHash } from "../Util"; +import { bfs, dist, manhattanDist, processName, simpleHash } from "../Util"; import { CellString, GameImpl } from "./GameImpl"; import { UnitImpl } from "./UnitImpl"; import { TileImpl } from "./TileImpl"; @@ -324,6 +324,32 @@ export class PlayerImpl implements MutablePlayer { return toRemove } + canBuild(unitType: UnitType, tile: Tile): boolean { + const cost = this.gs.unitInfo(unitType).cost + if (!this.isAlive() || this.gold() < cost) { + return false + } + switch (unitType) { + case UnitType.Nuke: + return this.units(UnitType.MissileSilo).length > 0 + case UnitType.Port: + return this.canBuildPort(tile) + case UnitType.Destroyer: + return this.canBuildDestroyer(tile) + case UnitType.MissileSilo: + return tile.owner() == this + } + } + + canBuildPort(tile: Tile): boolean { + return Array.from(bfs(tile, dist(tile, 20))) + .filter(t => t.owner() == this && t.isOceanShore()).length > 0 + } + + canBuildDestroyer(tile: Tile): boolean { + return this.units(UnitType.Port) + .filter(u => manhattanDist(u.tile().cell(), tile.cell()) < this.gs.config().boatMaxDistance()).length > 0 + } hash(): number { return simpleHash(this.id()) * (this.population() + this.numTilesOwned());