The reel through your own eyes: first-person replay (stage two)
Sight now runs THROUGH the warps as the rules say: a ray reaching a mouth re-enters at its pair and marches on, the far side swimming in violet haze. The floor's furniture joins the scene — bushes stand tall, safes squat, slime and tacks and pits lie low, dropped daggers glint. And the replay reel gains a 👁 toggle: relive the catch-up or the whole tale through your wizard's eyes, the camera turning before it strides, easing between cells, cutting on teleports, and turning toward whoever acted while you stood still. The /?fpv workshop grows &demo=1 — two automatons play a stretch and the real Replay component reruns it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
dae01969b0
commit
65092f50af
@@ -3,12 +3,17 @@
|
||||
// eyes, free-fly controls. No rules run here — the camera walks where
|
||||
// walls allow and the maze is exactly what viewFor would send that
|
||||
// player at the table, beliefs and all.
|
||||
import { createGame, viewFor, cellKey } from "@wizwar/engine";
|
||||
import FirstPerson from "./FirstPerson.svelte";
|
||||
import { createGame, viewFor, cellKey, applyCommand, automatonCommand, automatonFallback, redactEvent } from "@wizwar/engine";
|
||||
import type { GameEvent, GameState, GameView } from "@wizwar/engine";
|
||||
import FirstPerson from "./FirstPerson.svelte";
|
||||
import Replay from "../Replay.svelte";
|
||||
import { canWalk } from "./raycast";
|
||||
|
||||
const q = new URLSearchParams(location.search);
|
||||
const seed = Number(q.get("seed") ?? 42);
|
||||
/** ?demo=1: two automatons play a stretch, then the reel replays it —
|
||||
* the real Replay component, toggleable into first person. */
|
||||
const demoReel = q.has("demo");
|
||||
const { state: dealt } = createGame({
|
||||
playerIds: ["Wanderer", "Rival", "Stranger"],
|
||||
seed,
|
||||
@@ -64,6 +69,34 @@
|
||||
return () => cancelAnimationFrame(raf);
|
||||
});
|
||||
|
||||
// The demo reel: drive the clockwork for a while, keeping a step per
|
||||
// command exactly as the server's catch-up would build it.
|
||||
type Step = { seq: number; actor: string; events: GameEvent[]; view: GameView };
|
||||
function buildDemoSteps(): Step[] {
|
||||
let s: GameState = dealt;
|
||||
const actingSeat = (g: GameState) =>
|
||||
g.stack?.waitingOn ?? g.pendingDiscard ?? g.chaosPending?.queue[0] ??
|
||||
g.outOfTurnWindow?.playerId ?? g.players[g.turn.activeIndex]!.id;
|
||||
const steps: Step[] = [];
|
||||
for (let i = 0; i < 80 && s.phase === "playing"; i++) {
|
||||
const seat = actingSeat(s);
|
||||
const cmd = automatonCommand(viewFor(s, seat), "hunter", "adept")
|
||||
?? automatonFallback(viewFor(s, seat), "adept");
|
||||
let r = applyCommand(s, seat, cmd);
|
||||
if (!r.ok) r = applyCommand(s, seat, automatonFallback(viewFor(s, seat), "adept"));
|
||||
if (!r.ok) r = applyCommand(s, seat, { type: "endTurn", draw: 0 });
|
||||
if (!r.ok) break;
|
||||
s = r.state;
|
||||
steps.push({
|
||||
seq: i, actor: seat,
|
||||
events: r.events.map((e) => redactEvent(e, povId)).filter((e): e is GameEvent => e !== null),
|
||||
view: viewFor(s, povId),
|
||||
});
|
||||
}
|
||||
return steps;
|
||||
}
|
||||
const demoSteps = demoReel ? buildDemoSteps() : [];
|
||||
|
||||
// Minimap geometry (top-down, one small square per cell).
|
||||
const MM = 9;
|
||||
const cells = Object.keys(view.board.cells).map((k) => {
|
||||
@@ -81,12 +114,17 @@
|
||||
|
||||
<svelte:window onkeydown={(e) => onKey(e, true)} onkeyup={(e) => onKey(e, false)} />
|
||||
|
||||
{#if demoReel}
|
||||
<Replay steps={demoSteps} onclose={() => (location.search = "?fpv")} />
|
||||
{/if}
|
||||
|
||||
<div class="fpv-shop">
|
||||
<h1>The maze, through {povId}'s eyes</h1>
|
||||
<p class="hint">
|
||||
Arrows / WASD walk and turn. Walls and shut doors refuse you; fire and
|
||||
stranger things do not — this workshop has eyes, not rules. Seed with
|
||||
<code>?fpv&seed=N</code>, stand anywhere with <code>&x=&y=&dir=</code>.
|
||||
<code>?fpv&seed=N</code>, stand anywhere with <code>&x=&y=&dir=</code>,
|
||||
or watch the clockwork's reel with <code>&demo=1</code> (toggle 👁).
|
||||
</p>
|
||||
<div class="stage">
|
||||
<FirstPerson {view} {povId} {x} {y} {facing} />
|
||||
|
||||
Reference in New Issue
Block a user