Prerequisite for the World-row bridge, taken verbatim from the vault half of afd5a4a
(feature/p0-gates-and-defects, already merged into integration/all-systems; the rest of that commit
is unrelated RAF work). Neither feature/mythic-plus nor feature/great-vault ever received it, and
each vault slot's level is defined as the Nth-best run of the week, so the row must keep every run's
level rather than a single bestLevel.
The Great Vault World-row bridge needs both halves and neither branch has both:
feature/mythic-plus owns WeeklyRewardChestThreshold.db2 (the DB2 the row ladder is read from) and
ChallengeModeMgr's vault services; feature/great-vault owns WeeklyRewardsMgr (the three-row
Dungeon/Raid/World model) and WeeklyRewardHandler.cpp, which is the handler an assembly actually
binds to CMSG_REQUEST_WEEKLY_REWARDS / CMSG_CLAIM_WEEKLY_REWARD.
Live 68974 purchase list (TESTER_SNIFF2_LINDORMI_MINE, 458 B = 8 + 10x45)
proves the JamBattlePayPurchase wire order is
{ u64 PurchaseID, i32 Status, i32 ResultCode, u32 ProductID, u64 BasePrice,
u64 UserPrice, i64 TimeCreated, u8 walletNameLen } - the walletName length
byte sits at the END of the 45-byte record (purchase unix times align at
record offset 36, byte 44 is the empty-wallet 0), while we wrote it right
after ProductID. Move it in GetPurchaseListResponse::Write and
PurchaseUpdate::Write.
Also: every completed purchase in the capture carries Status=6 (not the
enum-registrar Done=3 we assumed; failed VAS showed 12/63), so bump
STATUS_DONE in BattlePayHandler accordingly.
No behavioral redesign - record layout and status constant only. Empty-list
replies were byte-identical either way, so this only matters once records
are populated.
Capture dump_12.0.7.68974_2026-08-08_02-54-06 ("linformi-shop-key"):
- The Silvermoon-city Lindormi is creature 197711 (not 259053, which stays the
sniffed in-dungeon Algeth'ar Academy entry): map 0 (GUID128 map bits + packet
MapID), spawn 8672.9854 -4517.0728 23.9514 o 5.6468, zone 15969/16079.
- Seed her city spawn (guid 9000201), wire creature_template 197711 to gossip
menu 29898 / npcflag GOSSIP|VENDOR / npc_lindormi, add the two sniffed menu
options (125048 "I seem to have misplaced my Keystone.", 140067 Timelost
Saddle vendor) and her 16-item ExtendedCost-11574 vendor list.
- npc_lindormi: offer the sniffed misplaced-keystone option while the player
holds no key; grant a fresh keystone at the weekly floor on select (retail
pushes item 180653 the same way: SPELL_GO 352816 -> ITEM_PUSH_RESULT).
- world_quest_template: append the 75 quests that rotated in on 2026-08-08
(union 321 vs seeded 314; 68 rotated out but historical rows are kept).
Honor Campaign.RewardQuestID and surface CampaignXCondition.FailureReason.
CampaignsByCompletionQuest reverse index built in QuestMgr::Load() walks
sCampaignStore for rows where Completed>0 && RewardQuestID>0; on quest
turn-in (RewardQuest path in Player.cpp line ~15347) we look up
campaigns whose Completed quest matches and AddQuestAndCheckCompletion
the RewardQuestID if the player has not already received it. Mirrors
the retail "campaign chapter handover -> reward quest" flow.
CampaignXConditionsByCampaign bucket (sorted by OrderIndex asc) drives
GetCampaignStallFailureReason(): walks the campaign's conditions in
order and returns the localized FailureReason of the first row whose
PlayerConditionID is not met. Caller is the campaign-stall UI tooltip
path. Without this, the post-10.0 campaign UI shows generic "stalled"
text instead of "Reach level 70 to continue." etc.
QuestLine.db2 (loaded in 10A.3) supplies Name and Description so the
existing SMSG_UI_MAP_QUEST_LINES_RESPONSE path now renders chapter
titles correctly client-side.