mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 13:50:43 +00:00
b2ba37e0ab
Resolves #2484 ## Description: - When an alliance is created between two players, any incoming nukes between them are destroyed mid-air. This prevents the traitor debuff from being applied on impact, even if the nukes were launched before the alliance was formed. - If a player has launched nukes at multiple nations, only the nukes targeting the newly allied nation are destroyed. This is what the players will see after the alliance is created (in case they have launched nukes at each other): <img width="423" height="125" alt="Screenshot 2026-01-04 092907" src="https://github.com/user-attachments/assets/6544fb7a-7623-4fc3-b799-89ef8fe897d6" /> ## 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: assessin.
164 lines
4.5 KiB
TypeScript
164 lines
4.5 KiB
TypeScript
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);
|
|
});
|
|
});
|