The eyes watch through a warp mouth; a cutaway is for what no sight reaches
The Warp Sniper cut to another angle the moment the fireball landed, though the caster could see the whole thing: the director counted a warp mouth before the target as blocked sight. Sight threads warps as the rules say, and now the camera does too. director.sightline finds the heading that actually sees a point — straight, or through a mouth by aiming at the target's position in the far room and asking whether the bent ray reaches it — and both the aim and the turn-toward-the- actor rules use it. Only a point no ray reaches earns the cutaway. Warp Sniper's second beat re-blessed: Wanderer's eyes now find Rival through the mouth as the turn passes to him. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jm2auWk6RP71CjaAb4FMoG
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
7c0a761c59
commit
86856781df
@@ -7,7 +7,7 @@
|
||||
import { scheduleFx, type BoardFx } from "./fx";
|
||||
import { fpFxForEvents, type FpFx } from "./fpv/fx3d";
|
||||
import { castRay, edgeMid } from "./fpv/raycast";
|
||||
import { cutawayStand, deepestFacing, aimOfEvents, gatherGlides, hurledIn, shortestArc } from "./fpv/director";
|
||||
import { cutawayStand, deepestFacing, aimOfEvents, gatherGlides, hurledIn, shortestArc, sightline } from "./fpv/director";
|
||||
import { prefs } from "./prefs.svelte";
|
||||
import { cardDef, isPermanentDuration, stackSightTrace } from "@wizwar/engine";
|
||||
import type { GameEvent, GameView } from "@wizwar/engine";
|
||||
@@ -387,26 +387,20 @@
|
||||
}
|
||||
else if (aim) {
|
||||
const ax = aim.x + 0.5, ay = aim.y + 0.5;
|
||||
const toAim = Math.hypot(ax - tx, ay - ty);
|
||||
const sight = castRay(v, tx, ty, Math.atan2(ay - ty, ax - tx));
|
||||
// Blocked: a wall before the target, or a warp mouth before it —
|
||||
// a warp BEYOND the target bends nothing the eyes need.
|
||||
const warpBefore = sight.warped && (sight.warpDist ?? Infinity) < toAim - 0.4;
|
||||
if (warpBefore || sight.dist < toAim - 0.4) {
|
||||
return takeCutaway(ax, ay);
|
||||
}
|
||||
targetFacing = Math.atan2(ay - ty, ax - tx);
|
||||
// The eyes watch their own magic land wherever they can see it —
|
||||
// straight down a corridor or through a warp mouth. Only a target
|
||||
// out of all sight earns the cutaway.
|
||||
const heading = sightline(v, tx, ty, ax, ay);
|
||||
if (heading === null) return takeCutaway(ax, ay);
|
||||
targetFacing = heading;
|
||||
aimed = true;
|
||||
} else if (actor && actor.id !== povId &&
|
||||
(actor.position.x !== me.position.x || actor.position.y !== me.position.y)) {
|
||||
// Turn toward the actor — but only if these eyes could actually see
|
||||
// them: an unbroken straight sight line, no warps bending it.
|
||||
const ax = actor.position.x + 0.5, ay = actor.position.y + 0.5;
|
||||
const toActor = Math.hypot(ax - tx, ay - ty);
|
||||
const ray = castRay(v, tx, ty, Math.atan2(ay - ty, ax - tx));
|
||||
const warpBefore = ray.warped && (ray.warpDist ?? Infinity) < toActor - 0.2;
|
||||
if (!warpBefore && ray.dist > toActor - 0.2) {
|
||||
targetFacing = Math.atan2(ay - ty, ax - tx);
|
||||
// them, straight or through a mouth.
|
||||
const heading = sightline(v, tx, ty, actor.position.x + 0.5, actor.position.y + 0.5, 0.2);
|
||||
if (heading !== null) {
|
||||
targetFacing = heading;
|
||||
aimed = true;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user