Reflected Swap Meet: the reflector chooses the trade (rev 27)

'FULL REFLECTION lets the other player decide which objects, if any,
will be swapped' — the reflector's choice now rides their counteract
(params.cardId, reflector's item first), resolved with the roles
swapped when the reflection settles; 'none' or no choice trades
nothing. The client walks the reflector through the same give-and-take
picker, with a 'swap nothing' refusal.

Also from room XRT7: the trade picker now honors each room's own rules
revision (older rooms trade only object-typed cards), so it can no
longer offer a wizardblade a rev-25 engine will quietly refuse — and a
fizzled swap finally says so in the log instead of vanishing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
This commit is contained in:
Eric Wagoner
2026-08-17 22:36:00 -04:00
co-authored by Claude Fable 5
parent 3aef6694f3
commit 2bb2ca62d8
6 changed files with 161 additions and 12 deletions
+1
View File
@@ -137,6 +137,7 @@ export function humanize(e: GameEvent): string | null {
case "illusionBelieved": return e.believed ? `${e.player} flinches — the illusion feels real!` : `${e.player} laughs off the illusion.`;
case "itemStolen": return `${e.to} picks ${e.from}'s pocket.`;
case "itemsSwapped": return `${e.a} and ${e.b} swap items.`;
case "swapFizzled": return `${e.player}'s trade comes to nothing — the named items were not there to swap.`;
case "wardSprung": return `${e.owner}'s treasure was WARDED — it bites ${e.victim}!`;
case "curseRemoved": return `${e.caster} lifts a curse from ${e.target}.`;
case "objectEnchanted": return `An object gleams with Swarthmore's enchantment.`;