v0.30.0
What's new
Darkmoon Party Shuffle
v0.30.0 (2026-09-09)
Full Changelog Previous Releases
- feat(roster): declare the spec you play for an event, without respeccing
A player who signs up hours ahead is rarely in the specialization they intend
to play. The roster entry read the active in-game spec at join time and never
looked again, so signing up as the healer meant respeccing right then — or
silently misrepresenting yourself for the whole event.
The local player can now declare, for the duration of one event, which of their
own class specializations their roster entry reports. It is a display and
shuffle input only: the in-game specialization is never read back into, nor
changed by, the declaration.- Roster gains SetDeclaredSpec / GetDeclaredSpec / SeedDeclaredSpecFromGame,
held module-local so spec resolution stays testable with no comm state.
GetSelfEntry resolves the declared specId over the active one and re-derives
spec and role from it; the class-derived Bloodlust / Battle-Rez fallbacks are
untouched because a declaration can never cross classes. - The declaration is seeded from the active spec on create and join, so a player
who never opens the control behaves exactly as before. - It is scoped to the event: persisted on the active-event record so it survives
a /reload, reinstated by RestoreSession before the self entry is built, and
discarded with the record on leave or a forced exit. - Comm:SetDeclaredSpec refuses once the hands are visible and re-announces
through the existing JOIN path; RefreshSelfEntry's change signature now covers
specId, so a redundant selection sends nothing. No wire or envelope change. - The Deck row spec text becomes a click target on the player's own row only: a
MENU-mode dropdown listing that class's specializations, framed so it reads as
editable, greyed with an explanatory tooltip while the hands are dealt. - The solo demo seeds on StartDemo and clears on EndDemo, and the declaration
path has a _demo branch that mutates only the local roster: no JOIN, no
MPPSDB write.
Adds scripts/lua-tests/declared-spec.test.lua covering seeding, the class guard,
entry re-derivation, the persistence round-trip through restore, the deal-time
gate, the redundant-selection no-op and the demo's zero-traffic invariant.
npm run test:lua is green at 413 tests.
Co-Authored-By: Claude Opus 5 noreply@anthropic.com
- Roster gains SetDeclaredSpec / GetDeclaredSpec / SeedDeclaredSpecFromGame,
- docs(openspec): archive add-mythic-plus-rating
Syncs the delta spec into openspec/specs/mythic-plus-rating (a new capability:
6 requirements, 23 scenarios) and moves the change under changes/archive.
Co-Authored-By: Claude Opus 5 noreply@anthropic.com - feat(rating): show each member's Mythic+ rating next to their item level
An organizer deciding who goes in which group could only see item level, a weak
proxy in Mythic+. An addon cannot read another character's rating remotely --
GetPlayerMythicPlusRatingSummary needs a unit token and event registrants are
cross-realm and out of range -- so the rating travels the way item level already
does: each client reads its own score and it rides the roster.
Detection reads C_ChallengeMode.GetOverallDungeonScore dynamically and is guarded
at every step, so a client without the API degrades to no rating instead of
erroring. No score means no field, never a zero that would render as one.
On the wire it is a single optional lean key (mr), emitted only when the member
has a score, so a ratingless entry adds no bytes. No new message type, route or
envelope version -- an older client simply ignores the key.
Comm:RefreshSelfEntry now covers the rating in its change signature alongside the
owned keystone (_lastOwnedKeySig becomes _lastSelfSig) and Roster listens for
CHALLENGE_MODE_COMPLETED. One signature rather than one per field, because a
completed key commonly moves both at once and two would announce it twice.
Displayed beneath the item level in the Deck and all-groups views, and in the
top-right corner of the poker hand card -- the one free corner, facing the item
level across the card's diagonal, with a hard shadow so the violet stays legible
over the class-tinted art band. The bottom row of the cell and slot now reserve
the same right inset as the row above, so a long spec name cannot run under the
number at the narrowest reflow width.
The add-ghost dialog gains an optional rating field. Unlike item level a blank
rating is never synthesized: nothing consumes it, so there is no gap to fill and
inventing a score for a player the organizer knows nothing about would be worse
than showing nothing.
The dev fixture fabricates ratings under the seeded PRNG, leaving every seventh
fake ratingless so /mpps demo shows both cases, and the demo self entry gets a
stand-in score for a player who has none.
Adds 24 harness tests (387 total, green).
Co-Authored-By: Claude Opus 5 noreply@anthropic.com - chore(dev): add a local deploy script for in-game testing
Mirrors the checkout into the live AddOns folder so a change can be tried in
game without waiting for a CurseForge build. Copies only the directories the
.toc references plus the .toc and LICENSE, so node_modules, scripts, openspec
and docs never reach the game folder.
The deployed .toc keeps the literal @project-version@ token, so the addon
reports its DEV_TARGET / DEV_BUILD string in game and a /reload can be
confirmed. SavedVariables live under WTF, so redeploying never touches saved
event data.
Exposed asnpm run deploy.
Co-Authored-By: Claude Opus 5 noreply@anthropic.com
This mod has no additional files

