Warps preserve your heading, not your bearing
Stepping through a rim warp spun the live camera 180: the director aimed along the displacement vector, and a top-to-bottom wrap's vector points exactly opposite the walk. The exit facing now comes from the warp's own geometry — the far mouth's inward direction — so travel carries straight through plain wraps and rotates correctly where boards were laid rotated; a dimensional token step keeps the facing it entered with. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
This commit is contained in:
co-authored by
Claude Fable 5
parent
770e79d063
commit
5f91e30eb4
@@ -12,7 +12,7 @@
|
|||||||
import { tokenArt } from "./art";
|
import { tokenArt } from "./art";
|
||||||
import { objectArt } from "./art";
|
import { objectArt } from "./art";
|
||||||
import { fpFxForEvents, type FpFx } from "./fpv/fx3d";
|
import { fpFxForEvents, type FpFx } from "./fpv/fx3d";
|
||||||
import { castRay } from "./fpv/raycast";
|
import { castRay, SIDE_ANGLE, OPPOSITE } from "./fpv/raycast";
|
||||||
import { aimOfEvents, gatherGlides, hurledIn, shortestArc } from "./fpv/director";
|
import { aimOfEvents, gatherGlides, hurledIn, shortestArc } from "./fpv/director";
|
||||||
import { untrack } from "svelte";
|
import { untrack } from "svelte";
|
||||||
import type { GameEvent, GameView, Side } from "@wizwar/engine";
|
import type { GameEvent, GameView, Side } from "@wizwar/engine";
|
||||||
@@ -175,6 +175,22 @@
|
|||||||
const events = b && b.n !== directedBatch ? b.events : [];
|
const events = b && b.n !== directedBatch ? b.events : [];
|
||||||
if (b) directedBatch = b.n;
|
if (b) directedBatch = b.n;
|
||||||
const hurled = hurledIn(events, povId);
|
const hurled = hurledIn(events, povId);
|
||||||
|
// Stepping through a warp keeps your HEADING, not your bearing to a
|
||||||
|
// point: you emerge walking out of the far mouth, so the exit facing
|
||||||
|
// is the far mouth's inward direction — travel preserved through a
|
||||||
|
// plain wrap, properly rotated where the boards were laid rotated.
|
||||||
|
// (A dimensional token has no mouths: facing simply carries over.)
|
||||||
|
let warpFacing: number | null = null;
|
||||||
|
for (const e of events) {
|
||||||
|
if (e.type === "moved" && e.player === povId && e.via === "warp") {
|
||||||
|
const w = v.board.warps.find((wp) =>
|
||||||
|
wp.from.cell.x === e.from.x && wp.from.cell.y === e.from.y &&
|
||||||
|
wp.to.cell.x === e.to.x && wp.to.cell.y === e.to.y);
|
||||||
|
if (w) warpFacing = SIDE_ANGLE[OPPOSITE[w.to.side]];
|
||||||
|
} else if (e.type === "warpStepped" && e.player === povId) {
|
||||||
|
warpFacing = camF;
|
||||||
|
}
|
||||||
|
}
|
||||||
const willCut = !camReady || (dist > 1.6 && !hurled);
|
const willCut = !camReady || (dist > 1.6 && !hurled);
|
||||||
cutawayShot = false;
|
cutawayShot = false;
|
||||||
const takeCutaway = (ax: number, ay: number) => {
|
const takeCutaway = (ax: number, ay: number) => {
|
||||||
@@ -194,7 +210,10 @@
|
|||||||
const aim = aimOfEvents(events, v, povId, m.position, actor);
|
const aim = aimOfEvents(events, v, povId, m.position, actor);
|
||||||
let targetFacing = camF;
|
let targetFacing = camF;
|
||||||
let aimed = false;
|
let aimed = false;
|
||||||
if (camReady && !willCut && dist > 0.05 && !hurled) {
|
if (warpFacing !== null) {
|
||||||
|
targetFacing = warpFacing;
|
||||||
|
aimed = true;
|
||||||
|
} else if (camReady && !willCut && dist > 0.05 && !hurled) {
|
||||||
targetFacing = Math.atan2(dy, dx);
|
targetFacing = Math.atan2(dy, dx);
|
||||||
aimed = true;
|
aimed = true;
|
||||||
} else if (aim?.self) {
|
} else if (aim?.self) {
|
||||||
|
|||||||
Reference in New Issue
Block a user