mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-07-17 00:10:54 +00:00
fix(doomsday): keep doomed warships on patrol instead of idling at ports (#4597)
Follow-up to #4587 (the 5% drain floor). ## Description: A side below the Doomsday Clock bar cannot repair its navy: warship healing is suppressed in `WarshipExecution.healWarship` so the decay actually lands. Since #4587 floors the drain at 5% of max instead of sinking ships to zero, warships now survive at 5% health, which is below the 75% `warshipRetreatHealthPercent` retreat threshold. The result was that every doomed warship peeled off to the nearest port, docked, and then never healed, sitting idle and out of combat, instead of the intended crippled-but-still-fighting state. This gates the repair-retreat on the Doomsday Clock, mirroring the existing heal gate: a doomed warship no longer starts a retreat, and any in-flight retreat or dock is cancelled so it returns to patrol. It keeps fighting at the floor until its side climbs back above the bar (healing resumes) or it is destroyed in combat. No config, schema, or UI change. Deterministic (a boolean check over existing player/warship state). Covered by three new tests in `tests/Warship.test.ts` (doomed stays on patrol, non-doomed still retreats, doomed undocks). ## Please complete the following: - [x] I have added screenshots for all UI updates (no UI changes) - [x] I process any text displayed to the user through translateText() and I've added it to the en.json file (no user-facing text) - [x] I have added relevant tests to the test directory ## Please put your Discord username so you can be contacted if a bug or regression is found: zixer._
This commit is contained in:
@@ -5,6 +5,7 @@ import {
|
||||
Player,
|
||||
PlayerInfo,
|
||||
PlayerType,
|
||||
Unit,
|
||||
UnitType,
|
||||
} from "../src/core/game/Game";
|
||||
import { TileRef } from "../src/core/game/GameMap";
|
||||
@@ -107,6 +108,53 @@ describe("Warship", () => {
|
||||
expect(warship.health()).toBe(maxHealth - 8);
|
||||
});
|
||||
|
||||
// A crippled warship normally retreats to a port to heal (threshold 75%).
|
||||
function crippledWarshipWithPort(): Unit {
|
||||
const maxHealth = game.config().unitInfo(UnitType.Warship).maxHealth;
|
||||
if (typeof maxHealth !== "number") {
|
||||
throw new Error("warship has no maxHealth");
|
||||
}
|
||||
player1.buildUnit(UnitType.Port, game.ref(coastX, 10), {});
|
||||
const warship = player1.buildUnit(
|
||||
UnitType.Warship,
|
||||
game.ref(coastX + 1, 10),
|
||||
{ patrolTile: game.ref(coastX + 1, 10) },
|
||||
);
|
||||
game.addExecution(new WarshipExecution(warship));
|
||||
player1.conquer(game.ref(coastX, 10)); // owns a tile -> isAlive() for the clock
|
||||
game.executeNextTick();
|
||||
// Drop to ~5%, well below the 75% retreat threshold.
|
||||
const low = Math.max(1, Math.floor(maxHealth * 0.05));
|
||||
warship.modifyHealth(low - warship.health());
|
||||
expect(warship.warshipState().state).toBe("patrolling");
|
||||
return warship;
|
||||
}
|
||||
|
||||
test("Crippled warship retreats to a port when not doomed", async () => {
|
||||
const warship = crippledWarshipWithPort();
|
||||
executeTicks(game, 10);
|
||||
// Baseline: it leaves patrol to retreat/dock at the port.
|
||||
expect(warship.warshipState().state).not.toBe("patrolling");
|
||||
});
|
||||
|
||||
test("Doomed warship stays on patrol instead of retreating", async () => {
|
||||
const warship = crippledWarshipWithPort();
|
||||
player1.enterDoomsdayClock();
|
||||
executeTicks(game, 10);
|
||||
// A doomed side cannot heal, so the warship must not peel off to a port.
|
||||
expect(warship.warshipState().state).toBe("patrolling");
|
||||
});
|
||||
|
||||
test("Doomed warship undocks and returns to patrol", async () => {
|
||||
const warship = crippledWarshipWithPort();
|
||||
executeTicks(game, 10);
|
||||
expect(warship.warshipState().state).not.toBe("patrolling");
|
||||
// Falling under the bar mid-repair sends it back to patrol, not idling.
|
||||
player1.enterDoomsdayClock();
|
||||
game.executeNextTick();
|
||||
expect(warship.warshipState().state).toBe("patrolling");
|
||||
});
|
||||
|
||||
test("Warship captures trade if player has port", async () => {
|
||||
const portTile = game.ref(coastX, 10);
|
||||
player1.buildUnit(UnitType.Port, portTile, {});
|
||||
|
||||
Reference in New Issue
Block a user