Files
OpenFrontIO/tests/AllianceDonation.test.ts
Aotumuri f1d162825e feat: remove spawn timer on singleplayer (#3199)
Resolves #1041 

## Description:

Remove the singleplayer spawn countdown so the game starts when the
player spawns, spawn nations immediately after player spawn, and align
game timer/max-timer timing with the new start point.

Added a singleplayer regression test for spawn-immunity timing
(GameImpl.test.ts) and updated spawn-phase loop tests to use gameType:
GameType.Public where singleplayer behavior is not under test (e.g.
MIRV/AI/Spawn/WinCheck-related suites), eliminating inSpawnPhase()
timeout hangs after the new singleplayer start logic.


https://github.com/user-attachments/assets/c07a585f-1153-490e-88ca-a91fc7ae5756

## 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:
aotumuri
2026-05-11 12:44:44 -07:00

129 lines
4.3 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);
});
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);
});
});