diff --git a/.claude/skills/wizwar-duel/SKILL.md b/.claude/skills/wizwar-duel/SKILL.md index b461127..0201a17 100644 --- a/.claude/skills/wizwar-duel/SKILL.md +++ b/.claude/skills/wizwar-duel/SKILL.md @@ -255,6 +255,29 @@ probing legality is free, so when unsure, try it and read the error. on WARP LANDING squares hit players who never see the token coming. That placement doctrine is proven; repeat it. +## Game-fifteen scars (six seats, lost to a two-life walk home) + +- **Same victim twice, again — and the kill feeds the carrier.** + Kestrel banked Automaton IV's first chest, his troll killed IV, and + IV's cards passed to him — the hand that kept him alive on two life + long enough to walk IV's second chest home (the game-nine lesson, + taught a second time). A wizard's death is a card windfall for its + killer: when a weak player falls to someone carrying, price the loot + into his survival. When a human has one banked, find the victim whose + LAST floor chest sits nearest him and guard THAT square. +- **The interception window is the turn BEFORE the grab.** Once he held + the chest four steps from home, nothing I could reach could see his + road. Run the sight-and-block scan against his likely grab squares + every turn he has one banked, not after he picks up. +- **CHAOS scrambles your own tools.** I cast it to strip his numbers and + lost both pick-locks my door route needed; my whole plan was a hand + I no longer held. Cast it only when your plan does not depend on the + hand you are giving away. +- Stone and thornbush as blockers worked twice against a bot carrier + (8 -> 11, then 8 -> 22 steps): a bot BFS reroutes rather than wades, + and buys real turns. The block scan (my reach x visible empty squares + x carrier's new distance) is the tool; keep it in the scratchpad. + ## The passivity audit (Eric, after game thirteen) - "You did nothing but draw for several turns" — true, and fatal. A diff --git a/packages/web/src/App.svelte b/packages/web/src/App.svelte index c528e3c..8e9e513 100644 --- a/packages/web/src/App.svelte +++ b/packages/web/src/App.svelte @@ -1890,12 +1890,17 @@ return bent ? bentSightedCellsFor(view, castingDouble?.position) : sightedCellsFor(view, castingDouble?.position); }); + /** The creatures that strike on command; the rest (a fire imp, a wraith) + * pick their own victims, as the engine's creatureAttack holds. */ + const ORDERED_ATTACKERS = new Set(["troll", "skeleton", "shadow"]); + const attackReady = (c: { kind: string; attackUsed: boolean; justCreated?: boolean }) => + ORDERED_ATTACKERS.has(c.kind) && !c.attackUsed && !c.justCreated; /** Creatures awaiting your orders this turn (yours + any democratic monster). */ const idleCreatures = $derived( view != null && isYourTurn ? view.creatures.filter((c) => (c.controllerId === view!.you || c.kind === "democratic-monster") && - (c.movementUsed < c.movesPerTurn || (!c.attackUsed && !c.justCreated))) + (c.movementUsed < c.movesPerTurn || attackReady(c))) : [], ); @@ -3440,7 +3445,11 @@ {#if youMustShield}
- Chaos comes for your hand. Tap your Full Shield to sit out, or + {#if view.yourHand.some((c) => c.cardId === "full-shield")} + Chaos comes for your hand. Tap your Full Shield to sit out, or + {:else} + Chaos comes for your hand, and you hold no Full Shield to sit it out. + {/if}
{:else if view.chaosPending} @@ -3450,7 +3459,7 @@ {@const moves = c.movesPerTurn - c.movementUsed}
🜲 {c.controllerId === view.you ? "Your" : "The"} {cardDef(c.kind).name} awaits orders: - {#if moves > 0}{moves} move{moves === 1 ? "" : "s"}{/if}{#if moves > 0 && !c.attackUsed && !c.justCreated} · {/if}{#if !c.attackUsed && !c.justCreated}attack ready{/if}. + {#if moves > 0}{moves} move{moves === 1 ? "" : "s"}{/if}{#if moves > 0 && attackReady(c)} · {/if}{#if attackReady(c)}attack ready{/if}. Tap its token to command it.
{/each}