diff --git a/src/core/execution/TransportShipExecution.ts b/src/core/execution/TransportShipExecution.ts index fd02d3b84..b5ccdf464 100644 --- a/src/core/execution/TransportShipExecution.ts +++ b/src/core/execution/TransportShipExecution.ts @@ -29,6 +29,7 @@ export class TransportShipExecution implements Execution { private dst: TileRef | null; private src: TileRef | null; + private retreatDst: TileRef | false | null = null; private boat: Unit; private originalOwner: Player; @@ -156,27 +157,21 @@ export class TransportShipExecution implements Execution { } if (this.boat.retreating()) { - // Ensure retreat source is still valid for (new) owner - if (this.mg.owner(this.src!) !== this.attacker) { - // Use bestTransportShipSpawn, not canBuild because of its max boats check etc - const newSrc = this.attacker.bestTransportShipSpawn(this.dst); - if (newSrc === false) { - this.src = null; - } else { - this.src = newSrc; - } - } + // Resolve retreat destination once, based on current boat location when retreat begins. + this.retreatDst ??= this.attacker.bestTransportShipSpawn( + this.boat.tile(), + ); - if (this.src === null) { + if (this.retreatDst === false) { console.warn( - `TransportShipExecution: retreating but no src found for new attacker`, + `TransportShipExecution: retreating but no retreat destination found`, ); this.attacker.addTroops(this.boat.troops()); this.boat.delete(false); this.active = false; return; } else { - this.dst = this.src; + this.dst = this.retreatDst; if (this.boat.targetTile() !== this.dst) { this.boat.setTargetTile(this.dst); diff --git a/tests/Disconnected.test.ts b/tests/Disconnected.test.ts index c52f00911..d8ba217e4 100644 --- a/tests/Disconnected.test.ts +++ b/tests/Disconnected.test.ts @@ -373,7 +373,7 @@ describe("Disconnected", () => { expect(game.owner(enemyShoreTile)).toBe(player1); }); - test("Captured transport ship should retreat to owner's shore tile", () => { + test("Captured transport ship should retreat to closest owner shore tile", () => { player1.conquer(game.map().ref(coastX, 4)); player2.conquer(game.map().ref(coastX, 1)); @@ -397,9 +397,15 @@ describe("Disconnected", () => { expect(player2.isAlive()).toBe(false); expect(transportShip.owner()).toBe(player1); + const expectedRetreatTile = player1.bestTransportShipSpawn( + transportShip.tile(), + ); + expect(expectedRetreatTile).not.toBe(false); + transportShip.orderBoatRetreat(); executeTicks(game, 2); + expect(transportShip.targetTile()).toBe(expectedRetreatTile); expect(transportShip.targetTile()).not.toBe(enemyShoreTile); expect(game.owner(transportShip.targetTile()!)).toBe(player1); });