diff --git a/src/core/execution/NukeExecution.ts b/src/core/execution/NukeExecution.ts index 284724e75..d4eaefcdb 100644 --- a/src/core/execution/NukeExecution.ts +++ b/src/core/execution/NukeExecution.ts @@ -375,6 +375,10 @@ export class NukeExecution implements Execution { for (const [player, numImpactedTiles] of tilesPerPlayers) { const tilesBeforeNuke = player.numTilesOwned() + numImpactedTiles; const transportShips = player.units(UnitType.TransportShip); + const transportShipTroops = new Map(); + for (const unit of transportShips) { + transportShipTroops.set(unit, unit.troops()); + } const outgoingAttacks = player.outgoingAttacks(); const maxTroops = config.maxTroops(player); // nukeDeathFactor could compute the complete fallout in a single call instead @@ -400,16 +404,19 @@ export class NukeExecution implements Execution { attack.setTroops(attackTroops - deaths); } for (const unit of transportShips) { - const unitTroops = unit.troops(); + const unitTroops = transportShipTroops.get(unit) ?? unit.troops(); const deaths = config.nukeDeathFactor( this.nukeType, unitTroops, numTilesLeft, maxTroops, ); - unit.setTroops(unitTroops - deaths); + transportShipTroops.set(unit, Math.max(0, unitTroops - deaths)); } } + for (const [unit, troops] of transportShipTroops) { + unit.setTroops(troops); + } } const outer2 = magnitude.outer * magnitude.outer; diff --git a/src/core/game/UnitImpl.ts b/src/core/game/UnitImpl.ts index 46b38c7a3..5071d51f0 100644 --- a/src/core/game/UnitImpl.ts +++ b/src/core/game/UnitImpl.ts @@ -172,7 +172,12 @@ export class UnitImpl implements Unit { } setTroops(troops: number): void { - this._troops = Math.max(0, troops); + const nextTroops = Math.max(0, troops); + if (this._troops === nextTroops) { + return; + } + this._troops = nextTroops; + this.mg.addUpdate(this.toUpdate()); } troops(): number { return this._troops; diff --git a/tests/Attack.test.ts b/tests/Attack.test.ts index da7ec9a2a..781f04704 100644 --- a/tests/Attack.test.ts +++ b/tests/Attack.test.ts @@ -9,6 +9,7 @@ import { UnitType, } from "../src/core/game/Game"; import { TileRef } from "../src/core/game/GameMap"; +import { GameUpdateType, UnitUpdate } from "../src/core/game/GameUpdates"; import { GameID } from "../src/core/Schemas"; import { setup } from "./util/Setup"; import { TestConfig } from "./util/TestConfig"; @@ -119,10 +120,24 @@ describe("Attack", () => { const ship = defender.units(UnitType.TransportShip)[0]; expect(ship.troops()).toBe(100); - game.executeNextTick(); + const updates = game.executeNextTick(); + const updatedShip = defender.units(UnitType.TransportShip)[0]; + const shipUpdates = (updates[GameUpdateType.Unit] as UnitUpdate[]).filter( + (u) => u.id === ship.id(), + ); expect(nuke.isActive()).toBe(false); - expect(defender.units(UnitType.TransportShip)[0].troops()).toBeLessThan(90); + expect(updatedShip.troops()).toBeLessThan(90); + expect(shipUpdates).toContainEqual( + expect.objectContaining({ + id: ship.id(), + unitType: UnitType.TransportShip, + troops: updatedShip.troops(), + transportShipState: expect.objectContaining({ + troops: updatedShip.troops(), + }), + }), + ); }); test("Boat penalty on retreat Transport Ship arrival", async () => {