Credibility pass: comments say what the code can't, and the seams are gone
Engine: pit-rim exits live in one helper (pitRimExits) shared by the resolver and the automaton; chargeReach names the six-stride cap; dust sight is inDust + dustAtEnd; PushPending is exported once; the force-field counter builds its events in one list; drawUnderSlowDeath says what it draws under. Test groups are named for the rule they pin, not the revision that introduced it. Client: one smoothstep; one edgeScar per battle-scarred edge; one board-zone rule (which also seats the caption strip on phones); the compass names live in SIDE_NAMES; net.flash() is the one toast; MediaQuery replaces two hand-rolled matchMedia listeners; sprites carry their sizes as plain numbers and their CSS in one rule each; canvas helpers are formatted like the rest of the tree. Comments that told how a cel or a fallback used to look now say what it draws. The actions-over notice no longer blames a pickup when slime ended the turn. Server and ops: dataRoot() is the one data directory; headlineOf builds its deeds without a cast; the rollup and skills read the same way the code behaves. 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
85690f0e23
commit
6e49fc9020
@@ -1,6 +1,6 @@
|
||||
// Websocket client + reactive session state (Svelte 5 runes).
|
||||
|
||||
import type { Command, GameEvent, GameView } from "@wizwar/engine";
|
||||
import type { Command, GameEvent, GameView, Side } from "@wizwar/engine";
|
||||
import { cardDef } from "@wizwar/engine";
|
||||
|
||||
const SERVER_URL =
|
||||
@@ -23,6 +23,9 @@ export function spellName(cardId: string): string {
|
||||
}
|
||||
}
|
||||
|
||||
/** The compass, for captions and buttons. */
|
||||
export const SIDE_NAMES: Record<Side, string> = { N: "North", E: "East", S: "South", W: "West" };
|
||||
|
||||
export function humanize(e: GameEvent): string | null {
|
||||
switch (e.type) {
|
||||
case "gameStarted": {
|
||||
@@ -66,7 +69,7 @@ export function humanize(e: GameEvent): string | null {
|
||||
case "extraTurnGranted": return `${e.player} speeds up — extra turn banked.`;
|
||||
case "wardWindow": return `The grab hangs in the air — ${e.owner} clutches something…`;
|
||||
case "pushWindow": return `${e.giant} bears down on ${e.pushee} at a fork — which way will they go?`;
|
||||
case "pushChosen": return `${e.pushee} breaks ${e.direction === "N" ? "north" : e.direction === "S" ? "south" : e.direction === "E" ? "east" : "west"}.`;
|
||||
case "pushChosen": return `${e.pushee} breaks ${SIDE_NAMES[e.direction].toLowerCase()}.`;
|
||||
case "treasureTorn": return e.toFloor
|
||||
? `${e.attacker} TEARS the treasure from ${e.defender}'s arms — it tumbles to the floor!`
|
||||
: `${e.attacker} TEARS the treasure from ${e.defender}'s arms!`;
|
||||
@@ -246,9 +249,11 @@ const ACTING = new Set([
|
||||
"climbedFromPit", "spellTrapped",
|
||||
]);
|
||||
function actorOf(e: GameEvent, turnOwner: string | null): string | undefined {
|
||||
const any = e as unknown as Record<string, unknown>;
|
||||
for (const k of ["caster", "attacker", "by", "owner"]) if (typeof any[k] === "string") return any[k] as string;
|
||||
if (ACTING.has(e.type) && typeof any.player === "string") return any.player as string;
|
||||
if ("caster" in e && typeof e.caster === "string") return e.caster;
|
||||
if ("attacker" in e && typeof e.attacker === "string") return e.attacker;
|
||||
if ("by" in e && typeof e.by === "string") return e.by;
|
||||
if ("owner" in e && typeof e.owner === "string") return e.owner;
|
||||
if (ACTING.has(e.type) && "player" in e && typeof e.player === "string") return e.player;
|
||||
return turnOwner ?? undefined;
|
||||
}
|
||||
|
||||
@@ -620,12 +625,18 @@ class Net {
|
||||
setTimeout(() => { if (this.error === msg.message) this.error = null; }, 5000);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private send(message: unknown): void {
|
||||
if (this.ws?.readyState === WebSocket.OPEN) this.ws.send(JSON.stringify(message));
|
||||
}
|
||||
|
||||
/** A toast the table shows for a moment, as it shows the server's refusals. */
|
||||
flash(message: string): void {
|
||||
this.error = message;
|
||||
setTimeout(() => { if (this.error === message) this.error = null; }, 5000);
|
||||
}
|
||||
|
||||
create(name: string): void {
|
||||
this.you = name;
|
||||
this.spectating = false;
|
||||
|
||||
Reference in New Issue
Block a user