mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 09:20:47 +00:00
Fix nuke preview showing teammate SAMs as threats (#4342)
## Problem In the nuke trajectory preview, the SAM-intercept **"X"** marker was drawn over **teammates'** SAMs — implying their SAM would shoot down your missile. It shouldn't: like allies, a teammate's SAM never engages your nuke. The bug only affected teammates; allies already worked. ## Cause The preview built its threat set from `myPlayer.allies()` only — formal alliances — and never considered teammates. That diverged from the sim ([`SAMLauncherExecution.ts`](src/core/execution/SAMLauncherExecution.ts#L118-L134)), which skips any nuke whose owner it's `isFriendly()` with (**same team OR allied**). ## Fix `samThreatensNukePreview` now takes a teammate set and excludes teammates **unconditionally**. The subtlety: allies keep the existing *betrayal* exception — a strike close enough to break the alliance makes that ally's SAM engage at launch (`listNukeBreakAlliance`, the same function the sim uses). Teammates get **no** such exception, because a strike can break an alliance but never a team relationship. So even a player who is both a teammate *and* a betrayed ally is correctly left off the threat set. ## Notes - The sim has an "aftergame fun" exception where teammate SAMs *do* target teammate nukes once there's a winner. The preview only appears while aiming a buildable mid-game (no winner yet), so that case doesn't apply here. ## Tests Updated `samThreatensNukePreview` unit tests for the new signature and added coverage for: teammate excluded, and teammate stays excluded even when listed as betrayed. All 11 tests pass. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -35,21 +35,40 @@ describe("BuildPreviewController ghost preservation (locked nuke / Enter confirm
|
||||
});
|
||||
|
||||
describe("samThreatensNukePreview (nuke trajectory threat set, #4226)", () => {
|
||||
const teammates = new Set([7, 8]);
|
||||
const allies = new Set([2, 3]);
|
||||
|
||||
test("non-allied SAM threatens the trajectory", () => {
|
||||
expect(samThreatensNukePreview(5, allies, new Set())).toBe(true);
|
||||
test("non-friendly SAM threatens the trajectory", () => {
|
||||
expect(samThreatensNukePreview(5, teammates, allies, new Set())).toBe(true);
|
||||
});
|
||||
|
||||
test("allied SAM does not threaten when the strike breaks no alliance", () => {
|
||||
expect(samThreatensNukePreview(2, allies, new Set())).toBe(false);
|
||||
expect(samThreatensNukePreview(2, teammates, allies, new Set())).toBe(
|
||||
false,
|
||||
);
|
||||
});
|
||||
|
||||
test("would-be-betrayed ally's SAM threatens (alliance breaks at launch)", () => {
|
||||
expect(samThreatensNukePreview(2, allies, new Set([2]))).toBe(true);
|
||||
expect(samThreatensNukePreview(2, teammates, allies, new Set([2]))).toBe(
|
||||
true,
|
||||
);
|
||||
});
|
||||
|
||||
test("other allies' SAMs still excluded when a different ally is betrayed", () => {
|
||||
expect(samThreatensNukePreview(3, allies, new Set([2]))).toBe(false);
|
||||
expect(samThreatensNukePreview(3, teammates, allies, new Set([2]))).toBe(
|
||||
false,
|
||||
);
|
||||
});
|
||||
|
||||
test("teammate SAM does not threaten the trajectory", () => {
|
||||
expect(samThreatensNukePreview(7, teammates, new Set(), new Set())).toBe(
|
||||
false,
|
||||
);
|
||||
});
|
||||
|
||||
test("teammate SAM stays excluded even if listed as betrayed (a strike never breaks a team)", () => {
|
||||
expect(
|
||||
samThreatensNukePreview(7, teammates, new Set([7]), new Set([7])),
|
||||
).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user