Sight travels through the wraparound openings
"If casting a spell, or checking line of sight through the AUTO WARP, treat it as a straight line, and the two connected boards as though they were adjacent" — and the lettered openings reconnect edges the same way. hasWarpLineOfSight models it: the line must run straight down the corridor, out one mouth, and in through the paired mouth, with both corridor legs clear and neither mouth filled solid. The new sightBetween (direct or through-a-warp) is now the game's LOS check everywhere — spells, ambush triggers, Around The Corner, the visionstone sweep, and the targeting dim on the client. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
fce3adc340
commit
64454ffc3e
@@ -3,6 +3,7 @@ import {
|
||||
assembleBoard,
|
||||
edgeState,
|
||||
hasLineOfSight,
|
||||
sightBetween,
|
||||
layoutIds,
|
||||
stepTarget,
|
||||
type SectorPlacement,
|
||||
@@ -136,3 +137,39 @@ describe("player counts 2-6", () => {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("line of sight through wraparound openings", () => {
|
||||
const twoSector: SectorPlacement[] = [
|
||||
{ boardId: "board-a", origin: { x: 0, y: 0 }, rotation: 0 },
|
||||
{ boardId: "board-b", origin: { x: 0, y: 5 }, rotation: 0 },
|
||||
];
|
||||
|
||||
it("sees straight down the corridor, out one mouth and in the other", () => {
|
||||
const board = assembleBoard(twoSector);
|
||||
// (2,0) N wraps to (2,9): the mouths see each other through the join.
|
||||
expect(hasLineOfSight(board, { x: 2, y: 0 }, { x: 2, y: 9 })).toBe(false);
|
||||
expect(sightBetween(board, { x: 2, y: 0 }, { x: 2, y: 9 })).toBe(true);
|
||||
expect(sightBetween(board, { x: 2, y: 9 }, { x: 2, y: 0 })).toBe(true);
|
||||
});
|
||||
|
||||
it("demands a straight corridor: off-axis viewers see nothing", () => {
|
||||
const board = assembleBoard(twoSector);
|
||||
expect(sightBetween(board, { x: 1, y: 0 }, { x: 2, y: 9 })).toBe(false);
|
||||
expect(sightBetween(board, { x: 3, y: 1 }, { x: 2, y: 9 })).toBe(false);
|
||||
});
|
||||
|
||||
it("walls inside either corridor still block the warp sight", () => {
|
||||
const board = assembleBoard(twoSector);
|
||||
// Layout A: the wall between (2,0) and (2,1)'s row (home column sight is
|
||||
// cut above row 2 — pinned earlier) blocks a deeper viewer's warp sight.
|
||||
const deepViewer = { x: 2, y: 2 };
|
||||
expect(hasLineOfSight(board, deepViewer, { x: 2, y: 0 })).toBe(false);
|
||||
expect(sightBetween(board, deepViewer, { x: 2, y: 9 })).toBe(false);
|
||||
});
|
||||
|
||||
it("a filled mouth chokes the tunnel", () => {
|
||||
const board = assembleBoard(twoSector);
|
||||
const stone = { "2,9": true as const };
|
||||
expect(sightBetween(board, { x: 2, y: 0 }, { x: 2, y: 8 }, stone)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user