import { AllianceRequestReplyExecution } from "src/core/execution/alliance/AllianceRequestReplyExecution"; import { GameUpdateType } from "src/core/game/GameUpdates"; import { NukeExecution } from "../src/core/execution/NukeExecution"; import { Game, Player, PlayerInfo, PlayerType, UnitType, } from "../src/core/game/Game"; import { setup } from "./util/Setup"; import { TestConfig } from "./util/TestConfig"; let game: Game; let player1: Player; let player2: Player; let player3: Player; describe("Alliance acceptance immediately destroys in-flight nukes", () => { beforeEach(async () => { game = await setup( "plains", { infiniteGold: true, instantBuild: true, infiniteTroops: true, }, [ new PlayerInfo("player1", PlayerType.Human, "c1", "p1"), new PlayerInfo("player2", PlayerType.Human, "c2", "p2"), new PlayerInfo("player3", PlayerType.Human, "c3", "p3"), ], ); (game.config() as TestConfig).nukeAllianceBreakThreshold = () => 0; while (game.inSpawnPhase()) { game.executeNextTick(); } player1 = game.player("p1"); player2 = game.player("p2"); player3 = game.player("p3"); player1.conquer(game.ref(0, 0)); player2.conquer(game.ref(5, 5)); player3.conquer(game.ref(10, 10)); player1.buildUnit(UnitType.MissileSilo, game.ref(0, 0), {}); }); test("accepting alliance destroys in-flight nukes between the newly allied players", () => { game.addExecution( new NukeExecution( UnitType.AtomBomb, player1, game.ref(5, 5), game.ref(0, 0), -1, 5, ), ); game.executeNextTick(); // init game.executeNextTick(); // spawn nuke expect(game.units(UnitType.AtomBomb)).toHaveLength(1); expect(player2.isAlliedWith(player1)).toBe(false); expect(player1.isFriendly(player2)).toBe(false); player2.createAllianceRequest(player1); game.addExecution( new AllianceRequestReplyExecution(player2.id(), player1, true), ); game.executeNextTick(); expect(player2.isAlliedWith(player1)).toBe(true); expect(player1.isFriendly(player2)).toBe(true); expect(game.units(UnitType.AtomBomb)).toHaveLength(0); }); test("accepting alliance destroys only nukes between allied players", () => { player1.buildUnit(UnitType.MissileSilo, game.ref(0, 0), {}); game.addExecution( new NukeExecution(UnitType.AtomBomb, player1, game.ref(5, 5), null), ); game.addExecution( new NukeExecution(UnitType.AtomBomb, player1, game.ref(10, 10), null), ); game.executeNextTick(); // init game.executeNextTick(); // spawn nukes expect(game.units(UnitType.AtomBomb)).toHaveLength(2); expect(player2.isAlliedWith(player1)).toBe(false); expect(player1.isFriendly(player2)).toBe(false); player1.createAllianceRequest(player2); game.addExecution( new AllianceRequestReplyExecution(player1.id(), player2, true), ); game.executeNextTick(); expect(player2.isAlliedWith(player1)).toBe(true); expect(player1.isFriendly(player2)).toBe(true); expect(game.units(UnitType.AtomBomb)).toHaveLength(1); // Ensure remaining nuke targets player3 const remainingNuke = game.units(UnitType.AtomBomb)[0]; expect(remainingNuke.targetTile()).toBe(game.ref(10, 10)); }); test("accepting alliance displays a nuke-cancellation display message", () => { game.addExecution( new NukeExecution( UnitType.AtomBomb, player1, game.ref(5, 5), game.ref(0, 0), -1, 5, ), ); game.executeNextTick(); // init game.executeNextTick(); // spawn nuke expect(game.units(UnitType.AtomBomb)).toHaveLength(1); expect(player2.isAlliedWith(player1)).toBe(false); expect(player1.isFriendly(player2)).toBe(false); player2.createAllianceRequest(player1); game.addExecution( new AllianceRequestReplyExecution(player2.id(), player1, true), ); const updates = game.executeNextTick(); expect(player2.isAlliedWith(player1)).toBe(true); expect(player1.isFriendly(player2)).toBe(true); expect(game.units(UnitType.AtomBomb)).toHaveLength(0); const messages = updates[GameUpdateType.DisplayEvent]?.map((e) => e.message) ?? []; expect( messages.some( (m) => m === "events_display.alliance_nukes_destroyed_outgoing" || m === "events_display.alliance_nukes_destroyed_incoming", ), ).toBe(true); }); });