From 6e3e9983075883acfa09344df9728c708f969101 Mon Sep 17 00:00:00 2001 From: Eric Wagoner Date: Thu, 3 Sep 2026 14:47:24 -0400 Subject: [PATCH] Three slips for a stranger's first game MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two newcomers on announcement day left within minutes at the same moment: they picked up a treasure, the turn's actions ended as the rules say, every walk after that was refused, and the status line's "turn spent" told them nothing about why or what the treasure was for. Both had stalled over a minute before their first move as well. Now: on a first turn, a coaching slip says what a turn is — walk this many squares, a NUMBER card walks farther, tap a card to cast, End turn — dismissed once with "got it" and remembered in prefs. After a pickup, the status line says the pickup ended the actions and the treasure comes along, and to end the turn and carry it home. While carrying on later turns, a slip names whose treasure it is, how far home is, and that two scored wins; your own treasure scores nothing in your arms. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01Jm2auWk6RP71CjaAb4FMoG --- packages/web/src/App.svelte | 31 ++++++++++++++++++++++++++++++- packages/web/src/prefs.svelte.ts | 4 ++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/packages/web/src/App.svelte b/packages/web/src/App.svelte index 9ddd71f..f95edb3 100644 --- a/packages/web/src/App.svelte +++ b/packages/web/src/App.svelte @@ -2478,11 +2478,38 @@
Your turn — round {view.turn.round}. {#if view.turn.actionsEnded} - turn spent — end it when ready + {#if me?.carriedTreasureId} + picking up ended your actions for this turn, and the treasure comes with you — + End turn now, then carry it home to score. + {:else} + picking up ended your actions for this turn — End turn when ready. + {/if} {:else} {view.turn.movementAllowance - view.turn.movementUsed} moves left{view.turn.attackUsed ? " · attack spent" : ""} {/if}
+ {#if !prefs.coached && !view.turn.actionsEnded} + +
+ How a turn works. Walk up to {view.turn.movementAllowance} squares by tapping + squares beside your wizard (or with the arrow keys); play a NUMBER card first to walk farther. + Tap a card to cast it. When you're done, End turn. Stuck? Ask the automatons for hints. + +
+ {/if} + {#if me?.carriedTreasureId && !view.turn.actionsEnded} + {@const chest = view.treasures.find((t) => t.id === me!.carriedTreasureId)} + {@const away = dreadDistance(view.board, me!.position, me!.home)} +
+ 💰 Carrying {chest && chest.owner !== view.you ? `${chest.owner}'s treasure` : "your own treasure"} — + {#if chest && chest.owner !== view.you} + your home is {away} square{away === 1 ? "" : "s"} away; drop it there to score. Two scored wins the game. + {:else} + it scores nothing in your arms; drop it on your home to keep it safe. + {/if} +
+ {/if} {:else}
{view.activePlayerId} is taking their turn…
{/if} @@ -3507,6 +3534,8 @@ transform: rotate(-0.4deg); } .slip.yours { border-left: 4px solid #2e7d32; } + .slip.coach { border-left: 4px solid #c9a72a; } + .slip.coach .stamp { margin-left: 0.5rem; } .slip.urgent { border-left: 4px solid #b3372b; transform: rotate(0.4deg); } .slip.ambush-note { border-left: 4px solid #43331f; font-size: 0.85rem; } .slip.catchup { border-left: 4px solid #5b3f9e; display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; } diff --git a/packages/web/src/prefs.svelte.ts b/packages/web/src/prefs.svelte.ts index 555e30c..38491cc 100644 --- a/packages/web/src/prefs.svelte.ts +++ b/packages/web/src/prefs.svelte.ts @@ -25,6 +25,8 @@ export interface Prefs { /** The hand of cards stands in a column at the board's left instead of * lying along the bottom (wide screens only). */ handLeft: boolean; + /** The first-turn coaching slip has been read and dismissed. */ + coached: boolean; } const KEY = "wizwar-prefs"; @@ -33,6 +35,7 @@ function load(): Prefs { const fallback: Prefs = { art: "photo", autoGrab: false, flourishes: true, wizardName: "", color: null, cautions: true, botTier: "adept", instantReplay: true, liveFp: false, handLeft: false, + coached: false, }; try { const raw = localStorage.getItem(KEY); @@ -49,6 +52,7 @@ function load(): Prefs { instantReplay: p.instantReplay !== false, liveFp: p.liveFp === true, handLeft: p.handLeft === true, + coached: p.coached === true, }; } catch { return fallback;