The facing ribbon rides the mount
While the pane possesses a creature, the keymap's golden ribbon moves to the mount's token — same shallow triangle, sized to the smaller body, turning with the borrowed eyes — and leaves the wizard's brow until the rider returns. 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
714c5bef80
commit
e499df22d7
@@ -56,6 +56,8 @@
|
||||
let fpBatch = $state<{ n: number; events: GameEvent[]; view: GameView } | null>(null);
|
||||
/** The pane camera's compass quadrant, worn by the keymap token. */
|
||||
let fpvFacing = $state<Side | null>(null);
|
||||
/** The creature the pane is riding, if any: the ribbon moves to it. */
|
||||
let fpvBody = $state<string | null>(null);
|
||||
let fxCancels: (() => void)[] = [];
|
||||
/** A trap drawn by YOU earns a modal; buried log lines get missed. */
|
||||
let trapNotice = $state<string | null>(null);
|
||||
@@ -1908,7 +1910,8 @@
|
||||
? { type: "pickUpTreasure", treasureId: w.id }
|
||||
: { type: "pickUpObject", instanceId: w.id })}
|
||||
onCreatureMove={(creatureId, direction) => dispatch({ type: "moveCreature", creatureId, direction })}
|
||||
onCreatureAttack={(creatureId, targetId) => dispatch({ type: "creatureAttack", creatureId, targetId })} />
|
||||
onCreatureAttack={(creatureId, targetId) => dispatch({ type: "creatureAttack", creatureId, targetId })}
|
||||
onbody={(id) => (fpvBody = id)} />
|
||||
{/if}
|
||||
<Board
|
||||
{view}
|
||||
@@ -1931,6 +1934,7 @@
|
||||
{litCells}
|
||||
{sightTrace}
|
||||
povFacing={prefs.liveFp && view.you && !net.spectating ? fpvFacing : null}
|
||||
povCreatureId={prefs.liveFp && !net.spectating ? fpvBody : null}
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
onEdgeClick,
|
||||
onPlayerClick,
|
||||
povFacing = null,
|
||||
povCreatureId = null,
|
||||
onCreatureClick,
|
||||
onWarpClick,
|
||||
onCellPeek,
|
||||
@@ -47,6 +48,8 @@
|
||||
/** Which way YOUR first-person camera faces: a wedge on your token
|
||||
* keeps the keymap and the pane pointing the same way. */
|
||||
povFacing?: "N" | "E" | "S" | "W" | null;
|
||||
/** While the pane rides a creature, the ribbon moves to ITS token. */
|
||||
povCreatureId?: string | null;
|
||||
onCreatureClick?: (creatureId: string) => void;
|
||||
onWarpClick?: (cell: { x: number; y: number }, side: Side) => void;
|
||||
/** Long-press on a square: read the card behind whatever occupies it. */
|
||||
@@ -592,7 +595,7 @@
|
||||
{/if}
|
||||
{/if}
|
||||
</g>
|
||||
{#if povFacing && p.id === view.you}
|
||||
{#if povFacing && !povCreatureId && p.id === view.you}
|
||||
<!-- A short wide ribbon hugging the token's leading edge: base as
|
||||
wide as the token, rising a fifth of that outward. -->
|
||||
{@const fa = povFacing === "E" ? 0 : povFacing === "S" ? Math.PI / 2 : povFacing === "W" ? Math.PI : -Math.PI / 2}
|
||||
@@ -653,6 +656,19 @@
|
||||
<text x="0" y="4" class="creature-label">{c.kind === "fire-imp" ? "I" : c.kind === "democratic-monster" ? "D" : c.kind[0]?.toUpperCase()}</text>
|
||||
{/if}
|
||||
</g>
|
||||
{#if povFacing && povCreatureId === c.id}
|
||||
<!-- The rider's facing ribbon, worn by the mount. -->
|
||||
{@const fa2 = povFacing === "E" ? 0 : povFacing === "S" ? Math.PI / 2 : povFacing === "W" ? Math.PI : -Math.PI / 2}
|
||||
{@const ch = CELL * 0.26}
|
||||
{@const cfx = Math.cos(fa2)}
|
||||
{@const cfy = Math.sin(fa2)}
|
||||
{@const cpx = -cfy}
|
||||
{@const cpy = cfx}
|
||||
<polygon
|
||||
points={`${cfx * ch + cpx * ch},${cfy * ch + cpy * ch} ${cfx * ch - cpx * ch},${cfy * ch - cpy * ch} ${cfx * ch * 1.5},${cfy * ch * 1.5}`}
|
||||
class="pov-wedge"
|
||||
/>
|
||||
{/if}
|
||||
</g>
|
||||
{/each}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
import { untrack } from "svelte";
|
||||
import type { GameEvent, GameView, Side } from "@wizwar/engine";
|
||||
|
||||
let { view, batch, onhide, onstride = null, canStride = false, ontarget = null, onfacing = null, litCells = null, onpickup = null, onCreatureMove = null, onCreatureAttack = null }: {
|
||||
let { view, batch, onhide, onstride = null, canStride = false, ontarget = null, onfacing = null, litCells = null, onpickup = null, onCreatureMove = null, onCreatureAttack = null, onbody = null }: {
|
||||
view: GameView;
|
||||
/** The latest live event batch, numbered so each plays once, with
|
||||
* the view the server sent alongside it. */
|
||||
@@ -40,6 +40,9 @@
|
||||
/** Possession: ride a creature's eyes and drive it from the pane. */
|
||||
onCreatureMove?: ((creatureId: string, side: Side) => void) | null;
|
||||
onCreatureAttack?: ((creatureId: string, targetId: string) => void) | null;
|
||||
/** Reports which creature (if any) the pane is riding, so the keymap
|
||||
* can move the facing ribbon to the mount's token. */
|
||||
onbody?: ((creatureId: string | null) => void) | null;
|
||||
} = $props();
|
||||
|
||||
const povId = $derived(view.you);
|
||||
@@ -363,6 +366,7 @@
|
||||
raf = requestAnimationFrame(tick);
|
||||
return () => cancelAnimationFrame(raf);
|
||||
});
|
||||
$effect(() => { onbody?.(possessedId); });
|
||||
let lastQuad = -99;
|
||||
$effect(() => {
|
||||
const q = ((Math.round(cam.facing / (Math.PI / 2)) % 4) + 4) % 4;
|
||||
|
||||
Reference in New Issue
Block a user