Files
OpenFrontIO/tests/AllianceDonation.test.ts
Mattia Migliorini f362e47413 Cancel nukes when accepting alliance via radial menu (#3155)
Resolves #3154

## Description:

#2716 introduced nuke cancellation logic on alliance acceptance via
`AllianceRequestReplyExecution`. The radial menu action, though, calls
`AllianceRequestExecution` instead, which accepts the alliance if a
request has already been made by the other player.

This PR moves the nuke cancellation logic to `GameImpl`, hooking into
the `acceptAllianceRequest` method, therefore accounting for every
alliance acceptance, regardless of the specific action that brought to
that.

## 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:

deshack_82603
2026-02-16 11:10:26 -08:00

133 lines
4.4 KiB
TypeScript

import { AllianceRequestExecution } from "../src/core/execution/alliance/AllianceRequestExecution";
import { DonateGoldExecution } from "../src/core/execution/DonateGoldExecution";
import { Game, Player, PlayerType } from "../src/core/game/Game";
import { playerInfo, setup } from "./util/Setup";
let game: Game;
let player1: Player;
let player2: Player;
describe("Alliance Donation", () => {
beforeEach(async () => {
game = await setup(
"plains",
{
infiniteGold: false,
instantBuild: true,
infiniteTroops: false,
donateGold: true,
donateTroops: true,
},
[
playerInfo("player1", PlayerType.Human),
playerInfo("player2", PlayerType.Human),
],
);
player1 = game.player("player1");
player1.conquer(game.ref(0, 0));
player1.addGold(1000n);
player1.addTroops(1000);
player2 = game.player("player2");
player2.conquer(game.ref(0, 1));
player2.addGold(100n);
player2.addTroops(100);
while (game.inSpawnPhase()) {
game.executeNextTick();
}
});
test("Can donate gold after alliance formed by reply", () => {
game.addExecution(new AllianceRequestExecution(player1, player2.id()));
game.executeNextTick();
game.addExecution(new AllianceRequestExecution(player2, player1.id()));
game.executeNextTick();
expect(player1.isAlliedWith(player2)).toBeTruthy();
expect(player2.isAlliedWith(player1)).toBeTruthy();
expect(player1.isFriendly(player2)).toBeTruthy();
expect(player2.isFriendly(player1)).toBeTruthy();
expect(player1.canDonateGold(player2)).toBeTruthy();
const goldBefore = player2.gold();
const success = player1.donateGold(player2, 100n);
expect(success).toBeTruthy();
expect(player2.gold()).toBe(goldBefore + 100n);
});
test("Can donate troops after alliance formed by reply", () => {
game.addExecution(new AllianceRequestExecution(player1, player2.id()));
game.executeNextTick();
game.addExecution(new AllianceRequestExecution(player2, player1.id()));
game.executeNextTick();
expect(player1.isAlliedWith(player2)).toBeTruthy();
expect(player2.isAlliedWith(player1)).toBeTruthy();
expect(player1.canDonateTroops(player2)).toBeTruthy();
const troopsBefore = player2.troops();
const success = player1.donateTroops(player2, 100);
expect(success).toBeTruthy();
expect(player2.troops()).toBe(troopsBefore + 100);
});
test("Can donate gold after alliance formed by mutual request", () => {
game.addExecution(new AllianceRequestExecution(player1, player2.id()));
game.executeNextTick();
game.addExecution(new AllianceRequestExecution(player2, player1.id()));
game.executeNextTick();
expect(player1.isAlliedWith(player2)).toBeTruthy();
expect(player2.isAlliedWith(player1)).toBeTruthy();
expect(player1.isFriendly(player2)).toBeTruthy();
expect(player2.isFriendly(player1)).toBeTruthy();
expect(player1.canDonateGold(player2)).toBeTruthy();
const goldBefore = player2.gold();
const success = player1.donateGold(player2, 100n);
expect(success).toBeTruthy();
expect(player2.gold()).toBe(goldBefore + 100n);
});
test("Can donate troops after alliance formed by mutual request", () => {
game.addExecution(new AllianceRequestExecution(player1, player2.id()));
game.executeNextTick();
game.addExecution(new AllianceRequestExecution(player2, player1.id()));
game.executeNextTick();
expect(player1.isAlliedWith(player2)).toBeTruthy();
expect(player2.isAlliedWith(player1)).toBeTruthy();
expect(player1.canDonateTroops(player2)).toBeTruthy();
const troopsBefore = player2.troops();
const success = player1.donateTroops(player2, 100);
expect(success).toBeTruthy();
expect(player2.troops()).toBe(troopsBefore + 100);
});
test("Can donate immediately after accepting alliance (race condition)", () => {
game.addExecution(new AllianceRequestExecution(player1, player2.id()));
game.executeNextTick();
const goldBefore = player2.gold();
game.addExecution(new AllianceRequestExecution(player2, player1.id()));
game.addExecution(new DonateGoldExecution(player1, player2.id(), 100));
game.executeNextTick();
expect(player1.isAlliedWith(player2)).toBeTruthy();
expect(player2.isAlliedWith(player1)).toBeTruthy();
game.executeNextTick();
// Donation should have succeeded
expect(player2.gold()).toBe(goldBefore + 100n);
});
});