Commit Graph
9 Commits
Author SHA1 Message Date
jwinterm be34bd2b2d feat(tavern): a real cat (Pet Cats Pack, CC-0)
The old 'cat' used a char-goblin sprite (green monster). Replaced with actual
pixel cats from the Pet Cats Pack (CC-0, commercial-ok):
- html/assets/cats/cat1..6-idle.png — 6 cats, 10-frame 50x50 idle strips.
- catSprites.js: loads + animates a cat sprite (RK.drawCatCanvas), flips to face left.
- tileRenderer: draws entities with kind 'cat' via the cat sprite path (shadow + frame).
- tavernLife: spawns a RANDOM cat that wanders the customer floor (not behind the
  bar), injected as kind 'cat' with its catSprite id. Degrades to a villager if
  catSprites.js isn't loaded.
- tavern.html loads catSprites.js.

Client-only (no server change). Suite 57 suites / 413 tests green.
2026-07-11 07:02:01 -04:00
jwinterm 4b78fec853 feat(chat): per-player nostr identity (Phase 2) + premium subscription unlocks cosmetic tiers
Phase 2 — a signed-in player can post global chat under their OWN Smirk npub
instead of the shared bridge account:

- src/utils/verifyChatEvent.js: verify a client-signed chat event with the same
  defenses as verifyNip98Event (rebuild clean event, recompute id, verify schnorr,
  freshness) PLUS the impersonation guard — the event's pubkey MUST equal the
  session's authenticated npub (users.smirk_public_key from NIP-98 login).
- ChatProvider.relaySignedEvent (base: local delivery only) + NostrChatProvider
  override (local delivery + publish the PRE-SIGNED event to the relays, no
  re-signing, echo-deduped) so it carries the player's npub.
- chatHandler.handleSignedChatMessage: rate-limit + resolve the session npub +
  verify + escape + relay. socketHandlers wires the  event. Serves
  lobby + tavern (both render the global broadcast).
- html/js/smirkChatSign.js + tavern send wire: feature-detected client helper —
  signs via window.smirk.signNostrEvent, falls back to the unsigned send when
  Smirk isn't connected, so it's inert (and safe) until a page has a wallet.

Premium -> cosmetics (the P1 catalog already had the hook):
- entitlements.levelForUser now takes the HIGHER of premium_level and an
  active-subscription tier, so a wowne.ro premium sub sets the entitlement tier
  and unlocks tile/customization packs at/below it — one sub, chat perks +
  cosmetics. Buying credits still never joins the premium ladder.

Behavior-preserving: no subscription_tier => unchanged; chat_signed only fires
when a client opts in. The client signing path needs browser verification against
a connected Smirk wallet (like the NIP-98 login). Tests: +13 (verify incl.
impersonation/tamper/channel/freshness, relay+echo-dedupe, sub-tier unlock).
Suite 56 suites / 407 tests green.
2026-07-10 22:20:10 -04:00
jwinterm ebf14560dd feat(tavern): unified global chat with persistent history in the tavern
The tavern used ephemeral, room-scoped chat with no backlog, so entering it
showed a blank log. Wire it to the shared global chat provider instead:

- TavernManager takes a globalChatProvider (the lobby's chat provider) and
  publishes tavern messages to the 'global' scope, so tavern + lobby share ONE
  conversation that persists to Postgres and (when NOSTR_CHAT_ENABLED) fans out
  over relay.smirk.cash. Falls back to the old tavern-scoped ephemeral provider
  when none is injected.
- On join, the tavern sends the recent global backlog (chat_history) to the
  joiner so history shows immediately.
- tavern.html: render chat_history on join and accept global-scope broadcasts
  (not just this room's), so lobby<->tavern messages flow both ways.

Tests: +3 (join sends backlog, chat routes to global scope, legacy fallback
stays tavern-scoped). Suite 55 suites / 394 tests green.
2026-07-10 19:54:38 -04:00
jwinterm 0f68eec26b feat: real-time multiplayer race mode (free, prestige, crypto)
Adds a complete block-cadence multiplayer race mode alongside solo and tavern.
  Disabled by default; enable with MATCH_ENABLED=true.

  Highlights:
  - New shared engine: MatchRoom, MatchEngine, MatchState (transport-agnostic, unit-tested).
  - Per-economy queues: free, credits_prestige, crypto_race with atomic escrow/refund.
  - MatchScheduler drains queues on every new block and starts 2–32 player races.
  - MatchManager handles Socket.IO lifecycle, server-authoritative movement, reconnect grace,
    forfeit/AFK handling, and end-of-match persistence.
  - Crypto races use race-entry tickets (grants.race_entries) to avoid on-chain refunds; winner
    payout is queued through the existing batch payout/retry service.
  - Leaderboard integration: free → Pleb, prestige → /api/leaderboard?board=prestige,
    crypto → Hall of Champions.
  - Tavern integration: Queue for Race panel, active race list, and live spectator rendering.
  - Dedicated /match.html client with economy selector, race HUD, and post-match scoreboard.
  - Migration 022 adds matches, match_entrants, match_events, match_queue_entries,
    race_entry_transactions, users.race_entries, and payouts.match_id.

  Docs:
  - New docs/MATCH_MODE.md with full architecture, config, events, and operational notes.
  - Updated README.md, docs/TAVERN_AND_MULTIPLAYER.md, docs/TODO.md, src/.env.example,
    and src/.env.

  Tests: 40 new unit tests across 7 suites, all passing.

  Known follow-ups for real-world validation:
  - Full integration test with Postgres + Socket.IO.
  - Server boot check with MATCH_ENABLED=false (default) to ensure solo/tavern remain unaffected.
  - Browser render-kit verification in /match.html and tavern spectator.
  - Crypto-race payout end-to-end with real wallet-rpc.
2026-07-09 13:26:52 -04:00
jwinterm 8fa8b06b20 feat: lively tavern (NPCs + speech bubbles), spectator camera, dungeon render adapter
- tavernLife.js: client-side NPCs (bartender, patrons, cat) with autonomous
    movement, random speech bubbles, and real-player chat bubbles
  - T2b: spectator camera — watch live dungeon runs from inside the tavern
    (game list, spectate_start/update, ESC to leave)
  - R1: sceneFromGameState adapter — converts dungeon game state to render-kit
    Scene with lighting grid and entity mapping
  - R2: pre-populated Kenney roguelikeSheet tile defaults for the tiled renderer
  - Dungeon renderer support: TileRenderer + AsciiRenderer handle lightGrid,
    dungeon features/items/monster entities
  - 3 new tests (242 total, 36 suites, all passing)
2026-07-09 06:31:35 -04:00
jwinterm 49ea01606e fix designed-room iso character rendering 2026-07-06 07:04:26 -04:00
jwinterm 83020f6c08 polish character customizer render choices 2026-07-06 04:26:00 -04:00
jwinterm 3195386ba1 refactor: resolve avatar visuals through render kit 2026-07-06 03:41:11 -04:00
jwinterm 454e6ab69a feat: add tavern render kit and character entitlements 2026-07-05 20:57:46 -04:00