Bodies sharing your square get a tray of their own

A wizard or creature standing IN your square lives inside the
renderer's near plane — no sprite, nothing to click, though
same-square is exactly where punches, thieves, and a mount's claws
operate. A "sharing your square" tray now joins the cockpit above the
feet tray: co-located bodies as clickable portraits, routed through
the same target handler a sprite click uses — so a possessed skeleton
claws its square-mate and a wizard punches theirs, all from inside
the pane.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
This commit is contained in:
Eric Wagoner
2026-08-27 15:13:46 -04:00
co-authored by Claude Fable 5
parent e499df22d7
commit 043a8b94a2
+46
View File
@@ -113,6 +113,27 @@
cam.x = mx; cam.y = my; cam.facing = face;
});
/** 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. */
const withYou = $derived.by(() => {
const body = possessed ?? me;
if (!body || !canStride) return [];
const bx = body.position.x, by = body.position.y;
const items: { kind: "player" | "creature"; id: string; art: string; label: string }[] = [];
for (const p of view.players) {
if (!p.alive || p.id === view.you) continue;
if (p.position.x !== bx || p.position.y !== by) continue;
items.push({ kind: "player", id: p.id, art: tokenArt(`wizard-${p.colorIndex}`, "players"), label: p.id });
}
for (const c of view.creatures) {
if (c.id === possessedId) continue;
if (c.position.x !== bx || c.position.y !== by) continue;
items.push({ kind: "creature", id: c.id, art: tokenArt(c.kind, "creatures"), label: c.kind.replace(/-/g, " ") });
}
return items;
});
const cam = $state({ x: 0, y: 0, facing: 0 });
let camReady = false;
/** While the player steers, the director keeps its hands off the
@@ -409,6 +430,17 @@
{/each}
</div>
{/if}
{#if withYou.length > 0}
<div class="with-tray">
<span class="feet-label">sharing your square</span>
{#each withYou as body (body.id)}
<button class="feet-item" title={body.label}
onclick={() => handleTarget(body.kind === "player" ? { kind: "player", id: body.id } : { kind: "creature", id: body.id })}>
<img src={body.art} alt={body.label} />
</button>
{/each}
</div>
{/if}
{#if onpickup && canStride && atFeet.length > 0 && !possessed}
<div class="feet-tray">
<span class="feet-label">at your feet</span>
@@ -499,6 +531,20 @@
color: #c9a72a;
}
.ride-stats { font-size: 0.7rem; color: #8d8672; }
.with-tray {
position: absolute;
bottom: 54px;
left: 50%;
transform: translateX(-50%);
display: flex;
align-items: center;
gap: 6px;
background: rgba(13, 12, 18, 0.78);
border: 1px solid #3a3428;
border-radius: 6px;
padding: 4px 10px;
z-index: 3;
}
.feet-tray {
position: absolute;
bottom: 8px;