mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-07-10 10:14:38 +00:00
43d07ca85f
Tighten the package model around the determinism invariant: everything the
engine imports must itself be deterministic.
- Rename core-public -> engine-public (package, dir, `engine-public/*` alias,
all 118 import sites). It is the deterministic public surface the engine
depends on and that client/server also use.
- Move the pure formatting helpers (renderNumber/renderTroops) from shared
into engine-public/format — the engine uses them and they're deterministic.
- Drop the now-empty shared package (and its alias). `shared` was intended for
client/server-shared, engine-forbidden code; there is none yet, so it is
removed and can be re-added when such code appears.
Final graph: engine-public (leaf) <- engine <- {client, server};
client/server also -> engine-public.
Verified: tsc clean; 1364 + 65 tests pass; prod build succeeds; engine-public
is a leaf; engine has no client/server imports. Lockfile regenerated.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
108 lines
3.1 KiB
TypeScript
108 lines
3.1 KiB
TypeScript
import { NukeExecution } from "engine/execution/NukeExecution";
|
|
import { SpawnExecution } from "engine/execution/SpawnExecution";
|
|
import { UpgradeStructureExecution } from "engine/execution/UpgradeStructureExecution";
|
|
import {
|
|
Game,
|
|
Player,
|
|
PlayerInfo,
|
|
PlayerType,
|
|
UnitType,
|
|
} from "engine/game/Game";
|
|
import { TileRef } from "engine/game/GameMap";
|
|
import { GameID } from "engine-public/Schemas";
|
|
import { setup } from "./util/Setup";
|
|
import { constructionExecution, executeTicks } from "./util/utils";
|
|
|
|
const gameID: GameID = "game_id";
|
|
let game: Game;
|
|
let attacker: Player;
|
|
|
|
function attackerBuildsNuke(
|
|
source: TileRef | null,
|
|
target: TileRef,
|
|
initialize = true,
|
|
) {
|
|
game.addExecution(
|
|
new NukeExecution(UnitType.AtomBomb, attacker, target, source),
|
|
);
|
|
if (initialize) {
|
|
game.executeNextTick();
|
|
game.executeNextTick();
|
|
}
|
|
}
|
|
|
|
describe("MissileSilo", () => {
|
|
beforeEach(async () => {
|
|
game = await setup("plains", { infiniteGold: true, instantBuild: true });
|
|
const attacker_info = new PlayerInfo(
|
|
"attacker_id",
|
|
PlayerType.Human,
|
|
null,
|
|
"attacker_id",
|
|
);
|
|
game.addPlayer(attacker_info);
|
|
|
|
game.addExecution(
|
|
new SpawnExecution(
|
|
gameID,
|
|
game.player(attacker_info.id).info(),
|
|
game.ref(1, 1),
|
|
),
|
|
);
|
|
|
|
attacker = game.player("attacker_id");
|
|
|
|
constructionExecution(game, attacker, 1, 1, UnitType.MissileSilo);
|
|
});
|
|
|
|
test("missilesilo should launch nuke", async () => {
|
|
attackerBuildsNuke(null, game.ref(7, 7));
|
|
expect(attacker.units(UnitType.AtomBomb)).toHaveLength(1);
|
|
expect(attacker.units(UnitType.AtomBomb)[0].tile()).not.toBe(
|
|
game.map().ref(7, 7),
|
|
);
|
|
|
|
for (let i = 0; i < 5; i++) {
|
|
game.executeNextTick();
|
|
}
|
|
expect(attacker.units(UnitType.AtomBomb)).toHaveLength(0);
|
|
});
|
|
|
|
test("missilesilo should only launch one nuke at a time", async () => {
|
|
attackerBuildsNuke(null, game.ref(7, 7));
|
|
attackerBuildsNuke(null, game.ref(7, 7));
|
|
expect(attacker.units(UnitType.AtomBomb)).toHaveLength(1);
|
|
});
|
|
|
|
test("missilesilo should cooldown as long as configured", async () => {
|
|
expect(attacker.units(UnitType.MissileSilo)[0].isInCooldown()).toBeFalsy();
|
|
// send the nuke far enough away so it doesn't destroy the silo
|
|
attackerBuildsNuke(null, game.ref(50, 50));
|
|
expect(attacker.units(UnitType.AtomBomb)).toHaveLength(1);
|
|
|
|
for (let i = 0; i < game.config().SiloCooldown() - 2; i++) {
|
|
game.executeNextTick();
|
|
expect(
|
|
attacker.units(UnitType.MissileSilo)[0].isInCooldown(),
|
|
).toBeTruthy();
|
|
}
|
|
|
|
executeTicks(game, 2);
|
|
|
|
expect(attacker.units(UnitType.MissileSilo)[0].isInCooldown()).toBeFalsy();
|
|
});
|
|
|
|
test("missilesilo should have increased level after upgrade", async () => {
|
|
expect(attacker.units(UnitType.MissileSilo)[0].level()).toEqual(1);
|
|
|
|
const upgradeStructureExecution = new UpgradeStructureExecution(
|
|
attacker,
|
|
attacker.units(UnitType.MissileSilo)[0].id(),
|
|
);
|
|
game.addExecution(upgradeStructureExecution);
|
|
executeTicks(game, 2);
|
|
|
|
expect(attacker.units(UnitType.MissileSilo)[0].level()).toEqual(2);
|
|
});
|
|
});
|