The sector ghost slides where the sector actually went

The relocation flourish corrected its coordinates against the view —
but effects are mapped when the events arrive, one message before
the new state, so the correction read the PRE-move board and the
ghost slid between unrelated squares. The sectorRelocated event now
carries its origins in final coordinates, computed after the maze
renormalizes, and the flourish trusts the event alone.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Eric Wagoner
2026-08-17 16:48:20 -04:00
co-authored by Claude Fable 5
parent e57307efbe
commit d89d995daf
2 changed files with 11 additions and 8 deletions
+8 -1
View File
@@ -528,7 +528,10 @@ export type GameEvent =
| { type: "illusionWallCreated"; caster: PlayerId; edge: { cell: Cell; side: Side } }
| { type: "illusionTested"; player: PlayerId; edge: string; result: "believes" | "seesThrough" }
| { type: "sectorRotated"; caster: PlayerId; sectorIndex: number; clockwise: boolean }
| { type: "sectorRelocated"; caster: PlayerId; sectorIndex: number; from: Cell; to: Cell }
| { type: "sectorRelocated"; caster: PlayerId; sectorIndex: number; from: Cell; to: Cell;
/** Origins in FINAL coordinates (the maze may renormalize after the
* landing); from/to record the pre-shift request. */
finalFrom: Cell; finalTo: Cell }
| { type: "creatureCreated"; creatureId: string; kind: CreatureState["kind"]; controller: PlayerId; at: Cell }
| { type: "creatureMoved"; creatureId: string; from: Cell; to: Cell; direction: Side; by: PlayerId }
| { type: "creatureAttacked"; creatureId: string; kind: CreatureState["kind"]; target: PlayerId | string; dieRoll: number | null }
@@ -1459,9 +1462,13 @@ const CARD_EFFECTS: Record<string, AttackEffect | NeutralEffect | CounterEffect>
const fromOrigin = { ...state.board.placements[idx]!.origin };
const problem = relocateSector(state, idx, dest);
if (problem) return problem;
const finalTo = { ...state.board.placements[idx]!.origin };
const shift = { x: finalTo.x - dest.x, y: finalTo.y - dest.y };
events.push({
type: "sectorRelocated", caster: caster.id, sectorIndex: idx,
from: fromOrigin, to: dest,
finalFrom: { x: fromOrigin.x + shift.x, y: fromOrigin.y + shift.y },
finalTo,
});
return null;
},
+3 -7
View File
@@ -296,13 +296,9 @@ export function fxForEvents(
return out;
}
case "sectorRelocated": {
// The event records pre-normalization origins; the view holds the
// truth. Shift the recorded start by the same correction.
const trueTo = view.board.placements[e.sectorIndex]?.origin;
if (trueTo) {
const dx = trueTo.x - e.to.x, dy = trueTo.y - e.to.y;
push({ kind: "sector-slide", from: { x: e.from.x + dx, y: e.from.y + dy }, to: { ...trueTo } });
}
// The event carries origins in final coordinates — the view at fx
// time is still the PRE-move board and cannot be trusted for this.
push({ kind: "sector-slide", from: { ...e.finalFrom }, to: { ...e.finalTo } });
return out;
}
default: