import { PortExecution } from "../src/core/execution/PortExecution"; import { Game, Player, PlayerInfo, PlayerType, UnitType, } from "../src/core/game/Game"; import { setup } from "./util/Setup"; let game: Game; let player: Player; let other: Player; describe("PortExecution", () => { beforeEach(async () => { game = await setup( "half_land_half_ocean", { instantBuild: true, }, [ new PlayerInfo("player", PlayerType.Human, null, "player_id"), new PlayerInfo("other", PlayerType.Human, null, "other_id"), ], ); while (game.inSpawnPhase()) { game.executeNextTick(); } player = game.player("player_id"); player.addGold(BigInt(1000000)); other = game.player("other_id"); game.config().structureMinDist = () => 10; }); test("Destination ports chances scale with level", () => { game.config().proximityBonusPortsNb = () => 0; game.config().tradeShipShortRangeDebuff = () => 0; player.conquer(game.ref(7, 10)); const spawn = player.canBuild(UnitType.Port, game.ref(7, 10)); if (spawn === false) { throw new Error("Unable to build port for test"); } const port = player.buildUnit(UnitType.Port, spawn, {}); const execution = new PortExecution(port); execution.init(game, 0); execution.tick(0); other.conquer(game.ref(0, 0)); const otherPort = other.buildUnit(UnitType.Port, game.ref(0, 0), {}); otherPort.increaseLevel(); otherPort.increaseLevel(); const ports = execution.tradingPorts(); expect(ports.length).toBe(3); }); test("Trade ship proximity bonus", () => { game.config().proximityBonusPortsNb = () => 10; game.config().tradeShipShortRangeDebuff = () => 0; player.conquer(game.ref(7, 10)); const spawn = player.canBuild(UnitType.Port, game.ref(7, 10)); if (spawn === false) { throw new Error("Unable to build port for test"); } const port = player.buildUnit(UnitType.Port, spawn, {}); const execution = new PortExecution(port); execution.init(game, 0); execution.tick(0); other.conquer(game.ref(0, 0)); other.buildUnit(UnitType.Port, game.ref(0, 0), {}); const ports = execution.tradingPorts(); expect(ports.length).toBe(2); }); test("Trade ship short range debuff", () => { game.config().proximityBonusPortsNb = () => 10; // Short range debuff cancels out the proximity bonus. game.config().tradeShipShortRangeDebuff = () => 100; player.conquer(game.ref(7, 10)); const spawn = player.canBuild(UnitType.Port, game.ref(7, 10)); if (spawn === false) { throw new Error("Unable to build port for test"); } const port = player.buildUnit(UnitType.Port, spawn, {}); const execution = new PortExecution(port); execution.init(game, 0); execution.tick(0); other.conquer(game.ref(0, 0)); other.buildUnit(UnitType.Port, game.ref(0, 0), {}); const ports = execution.tradingPorts(); expect(ports.length).toBe(1); }); test("Blocked trade route is omitted from trading ports", () => { game.config().proximityBonusPortsNb = () => 0; game.config().tradeShipShortRangeDebuff = () => 0; player.conquer(game.ref(7, 10)); const spawn = player.canBuild(UnitType.Port, game.ref(7, 10)); if (spawn === false) { throw new Error("Unable to build port for test"); } const port = player.buildUnit(UnitType.Port, spawn, {}); const execution = new PortExecution(port); execution.init(game, 0); other.conquer(game.ref(0, 0)); const blockedPort = other.buildUnit(UnitType.Port, game.ref(0, 0), {}); other.conquer(game.ref(0, 1)); const openPort = other.buildUnit(UnitType.Port, game.ref(0, 1), {}); game.blockTradeRouteUntil(port.id(), blockedPort.id(), game.ticks() + 100); const ports = execution.tradingPorts(); expect(ports).toContain(openPort); expect(ports).not.toContain(blockedPort); }); test("Blocked trade route becomes eligible again after expiry", () => { game.config().proximityBonusPortsNb = () => 0; game.config().tradeShipShortRangeDebuff = () => 0; player.conquer(game.ref(7, 10)); const spawn = player.canBuild(UnitType.Port, game.ref(7, 10)); if (spawn === false) { throw new Error("Unable to build port for test"); } const port = player.buildUnit(UnitType.Port, spawn, {}); const execution = new PortExecution(port); execution.init(game, 0); other.conquer(game.ref(0, 0)); const blockedPort = other.buildUnit(UnitType.Port, game.ref(0, 0), {}); game.blockTradeRouteUntil(port.id(), blockedPort.id(), game.ticks() + 1); expect(execution.tradingPorts()).not.toContain(blockedPort); expect( game.isTradeRouteBlocked(port.id(), blockedPort.id(), game.ticks()), ).toBe(true); expect( game.isTradeRouteBlocked(port.id(), blockedPort.id(), game.ticks() + 1), ).toBe(false); expect(execution.tradingPorts()).toContain(blockedPort); }); test("Trade route blacklist affects hash and expires cleanly", () => { player.conquer(game.ref(7, 10)); const spawn = player.canBuild(UnitType.Port, game.ref(7, 10)); if (spawn === false) { throw new Error("Unable to build port for test"); } const port = player.buildUnit(UnitType.Port, spawn, {}); other.conquer(game.ref(0, 0)); const otherPort = other.buildUnit(UnitType.Port, game.ref(0, 0), {}); const baseHash = (game as any).hash(); game.blockTradeRouteUntil(port.id(), otherPort.id(), game.ticks() + 100); const blockedHash = (game as any).hash(); (game as any)._ticks += 100; const expiredHash = (game as any).hash(); expect(blockedHash).not.toBe(baseHash); expect(expiredHash).toBe(baseHash); }); });