promotional bannermobile promotional banner

Loot & Baloot

Loot & Baloot — Play Saudi Baloot (بلوت) inside World of Warcraft. A four-player trick-taking card game over the party addon channel. Host with friends or play solo against bots, with full Hokm / Sun rules, melds, escalations, and SWA claims.

File Details

v3.2.13

  • R
  • May 16, 2026
  • 5.16 MB
  • 10
  • 12.0.5
  • Retail

File Name

WHEREDNGN-v3.2.13.zip

Supported Versions

  • 12.0.5

Loot & Baloot

v3.2.13 (2026-05-16)

Full Changelog Previous Releases

  • docs(CHANGELOG): include bid-card visibility fix in v3.2.13 notes
    Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
  • fix(State/Net): bid-card round identity stops late MSG_START wipe (v3.2.13)
    Reported: Seat 2 cannot see the bid card while the host can. Root
    cause (NOT v3.2.12): S.ApplyStart cleared s.bidCard unconditionally
    while MSG_BIDCARD carried no round identity, so a late or duplicate
    MSG_START reprocessed on a non-host client wiped a bid card that had
    already arrived correctly for the new round. The host is immune
    because it applies the bid card locally after its own ApplyStart and
    never reprocesses a wire MSG_START. s.hand was already protected by
    the analogous s.handRound guard; s.bidCard never got the same
    treatment.
    • State.ApplyBidCard(card, forRound): stamps s.bidCardRound
      (= forRound or s.roundNumber). reset() clears s.bidCardRound.
    • State.ApplyStart: replaces the unconditional s.bidCard = nil with
      a handRound-style guard — only clear (and reset the stamp) when
      s.bidCardRound ~= newRoundNum.
    • Net.SendBidCard: wire is now b;<card>;<roundNumber>; old
      two-field receivers ignore field 3 (backward compatible).
    • Net dispatcher passes fields[3]; _OnBidCard(sender, card, forRound)
      → S.ApplyBidCard(card, tonumber(forRound)). Old two-field
      b;<card> → forRound nil → defaults to current round.
    • Tests: BS.1–BS.4 (15 checks). Pre-fix proof: with the code change
      stashed, BS.1c (+9 others) fail because late _OnStart wipes
      s.bidCard; post-fix all pass.
      Full harness 1405 / 0 (1390 + 15 BS). H1 11/0, H7 9/0. No CHANGELOG/
      tag/release. No protocol bump (optional trailing field only).
      Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
  • docs(CHANGELOG): add v3.2.13 release notes
    Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
  • docs: add v3.2.11 private raid-lobby design
    Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
  • fix(Net.lua): gate non-PARTY MSG_LOBBY behind explicit trust (v3.2.11 blocker)
    Codex review blocker on the v3.2.11 private raid-lobby feature:
    MSG_LOBBY deliberately carries no allowCSV (Q2 keeps suppression
    MSG_HOST-only), so on RAID/INSTANCE_CHAT an uninvited raid listener
    could fall through _OnLobby to S.ApplyLobby and adopt hostName from
    seat 1 — defeating the private-lobby boundary.
    • N.HandleMessage now threads channel into N._OnLobby; signature
      gains a trailing channel param (nil-safe → legacy when absent).
    • _OnLobby: on RAID/INSTANCE_CHAT only, require an explicit trust
      anchor (fromHost / matching pendingHost / WHEREDNGNDB.lastGameID
      reload-recovery) before adopting any lobby state. PARTY stays
      legacy/unrestricted. Placed AFTER the all-empty host-gone reset so
      that trusted-host teardown still works. No allowCSV added to
      MSG_LOBBY (Q2 unchanged).
    • State.HostRemoveInvitee returns nil when the normalized name was
      not on the list, so /baloot uninvite X no longer falsely reports
      success for a never-invited name.
    • tests: CA.11 (12 checks — uninvited/invited raid receiver, PARTY
      legacy, reload recovery) + CA.12 (3 checks — HostRemoveInvitee).
      CA.10g/h channel-literal pins updated: now 2 sanctioned sites
      (groupChannel selector + _OnLobby trust gate).
      Full harness 1390 / 0. H1 11/0, H7 9/0. v3.2.12 duplicate-play fix
      (cb27204) carried via cherry-pick and intact.
      Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
  • feat(Net/State): v3.2.11 private raid-lobby support
    Allow exactly 4 invited players to play while in a raid/instance
    group without exposing the lobby/invite/join flow to the rest of the
    raid. Implements .swarm_findings/v3_2_11_private_raid_lobby_design.md
    (Codex round-1 amended; Q1 implicit-on-first-invitee, Q2 MSG_HOST-only
    allowCSV, Q3 plaintext names accepted).
    • Net.broadcast: opt-in channel selector (groupChannel: PARTY/RAID/
      INSTANCE_CHAT/nil). RAID/INSTANCE_CHAT suppressed unless the session
      is in a private raid-lobby (S.s.raidLobby). PARTY byte-identical to
      v3.2.10. groupChannel is defensive when WoW group APIs are absent
      (headless) — reproduces the old not-in-group early-out as no-send.
    • MSG_HOST gains optional field 4 = comma-joined normalized allowlist
      (raid/instance only; absent in party). SendHostAnnounce/SendLobby
      withhold advertisement until the host is "ready" (>=1 invitee) and
      surface a one-shot host-facing message otherwise.
    • _OnHost: cosmetic receiver-side suppression — uninvited raiders get
      no pendingHost/chat/sound; invited non-hosts opt into raid transport.
    • State: inviteAllow tri-state (nil=legacy PARTY / =engaged-not-ready
      / populated=allowlist) + raidLobby marker; authoritative join gate in
      HostHandleJoin (s.inviteAllow ~= nil); HostAddInvitee/RemoveInvitee/
      Invitees/HostRaidLobbyReady; reset() clears the new fields.
    • UI/Slash: host-only, raid-only invitee editor + /baloot invite/
      uninvite/invites mirror; hidden/refused in a normal party.
    • Tests: CA.1-CA.10 (48 checks) in the AZ Net-harness; AZ default
      stubs made category-aware. Harness 1320 -> 1368, 0 failed.
      H1 11/0, H7 9/0.
      No CHANGELOG/tag/release. No packaging/.toc/.pkgmeta/.github edits.
      Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
      (cherry picked from commit 358f5d43310661e83185e6bc6aefa5e0b3fbd5ea)