The feet tray learns hazards and the warp step
Two blind spots close. The active body — wizard or ridden mount — standing on a dimensional-warp token gets a "step through the warp" button in the feet tray, dispatching warpStep for the wizard and creatureWarpStep for the mount (the command the RNRX troll report earned). And whatever you stand IN shows as a warning chip: tacks, slime, dust, a pit, the ooze — the near plane's last secrets told. 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
043a8b94a2
commit
728f9fc28a
@@ -1911,7 +1911,10 @@
|
||||
: { type: "pickUpObject", instanceId: w.id })}
|
||||
onCreatureMove={(creatureId, direction) => dispatch({ type: "moveCreature", creatureId, direction })}
|
||||
onCreatureAttack={(creatureId, targetId) => dispatch({ type: "creatureAttack", creatureId, targetId })}
|
||||
onbody={(id) => (fpvBody = id)} />
|
||||
onbody={(id) => (fpvBody = id)}
|
||||
onWarpStep={(creatureId) => dispatch(creatureId
|
||||
? { type: "creatureWarpStep", creatureId }
|
||||
: { type: "warpStep" })} />
|
||||
{/if}
|
||||
<Board
|
||||
{view}
|
||||
|
||||
@@ -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, onbody = null }: {
|
||||
let { view, batch, onhide, onstride = null, canStride = false, ontarget = null, onfacing = null, litCells = null, onpickup = null, onCreatureMove = null, onCreatureAttack = null, onbody = null, onWarpStep = null }: {
|
||||
view: GameView;
|
||||
/** The latest live event batch, numbered so each plays once, with
|
||||
* the view the server sent alongside it. */
|
||||
@@ -43,6 +43,9 @@
|
||||
/** 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;
|
||||
/** A dimensional-warp step for whichever body the pane is: the
|
||||
* wizard (null) or the ridden creature (its id). */
|
||||
onWarpStep?: ((creatureId: string | null) => void) | null;
|
||||
} = $props();
|
||||
|
||||
const povId = $derived(view.you);
|
||||
@@ -113,6 +116,25 @@
|
||||
cam.x = mx; cam.y = my; cam.facing = face;
|
||||
});
|
||||
|
||||
/** What the ACTIVE body stands in or on: hazards it cannot see below
|
||||
* itself, and the dimensional token it could step through. */
|
||||
const underfoot = $derived.by(() => {
|
||||
const body = possessed ?? me;
|
||||
if (!body || !canStride) return { hazard: null as string | null, warpHere: false };
|
||||
const k = `${body.position.x},${body.position.y}`;
|
||||
const HAZARD_NAMES: Record<string, string> = {
|
||||
tacks: "tacks underfoot", slime: "green slime", dust: "a dust cloud",
|
||||
pit: "an open pit", ooze: "the killer ooze",
|
||||
};
|
||||
const kind = view.squareContents[k]?.kind;
|
||||
return {
|
||||
hazard: kind ? HAZARD_NAMES[kind] ?? null : null,
|
||||
warpHere: view.dimWarps.some((w) =>
|
||||
(w.a.x === body.position.x && w.a.y === body.position.y) ||
|
||||
(w.b.x === body.position.x && w.b.y === body.position.y)),
|
||||
};
|
||||
});
|
||||
|
||||
/** Bodies sharing the active eyes' square: inside the near plane, so
|
||||
* the renderer cannot show them — the tray stands in for the sprite,
|
||||
* and clicking routes exactly as clicking the sprite would. */
|
||||
@@ -441,9 +463,10 @@
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
{#if onpickup && canStride && atFeet.length > 0 && !possessed}
|
||||
{#if canStride && ((!possessed && atFeet.length > 0) || underfoot.hazard || underfoot.warpHere)}
|
||||
<div class="feet-tray">
|
||||
<span class="feet-label">at your feet</span>
|
||||
{#if !possessed && onpickup}
|
||||
{#each atFeet as item (item.id)}
|
||||
<button class="feet-item" title={item.label}
|
||||
onclick={() => onpickup?.({ kind: item.kind, id: item.id })}>
|
||||
@@ -454,6 +477,13 @@
|
||||
{/if}
|
||||
</button>
|
||||
{/each}
|
||||
{/if}
|
||||
{#if underfoot.hazard}
|
||||
<span class="feet-hazard">⚠ {underfoot.hazard}</span>
|
||||
{/if}
|
||||
{#if underfoot.warpHere && onWarpStep}
|
||||
<button class="stamp tiny" onclick={() => onWarpStep?.(possessedId)}>⇋ step through the warp</button>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
@@ -577,6 +607,7 @@
|
||||
.feet-item:hover { border-color: #c9a72a; }
|
||||
.feet-item img { width: 30px; height: 30px; object-fit: contain; }
|
||||
.feet-fallback { font-size: 0.65rem; color: #d8d2c0; padding: 0 4px; }
|
||||
.feet-hazard { font-size: 0.7rem; color: #d98a4a; white-space: nowrap; }
|
||||
.drive-fwd { top: 0; left: 20%; right: 20%; height: 16%; }
|
||||
.drive-fwd:hover { background: linear-gradient(to bottom, rgba(0, 0, 0, 0.22), transparent); }
|
||||
.drive-back { bottom: 0; left: 20%; right: 20%; height: 15%; }
|
||||
|
||||
Reference in New Issue
Block a user