feat(editor): add WHRD (Heroic Loot Scaling) — 108th open format

Novel replacement for the implicit Heroic-mode loot rules
vanilla WoW encoded in dungeon/raid script systems: a
Normal-mode boss drops items from one loot table, the
Heroic-mode version drops the same items at +N item
levels with M× drop chance plus an optional Heroic-only
currency token. Each WHRD entry binds one (mapId,
difficultyId) combination to its scaling rules so the
loot-roll engine can layer the modifiers over the base
WLOT loot table at encounter death.

Six tunable fields per scaling: itemLevelDelta (signed
int16, typically +13 for 5-man Heroic, +13 to +26 for
raid Heroic), bonusQualityChance (basis points 0..10000
for the probability of a +1-quality-tier bonus drop),
dropChanceMultiplier (float, 1.0 = same rate, 1.5 =
+50%), heroicTokenItemId (per-tier currency reward like
Emblem of Frost), bonusEmblemCount (extra emblems on
top of base 1× per boss).

mapId=0 is a wildcard that applies the scaling to ANY
map at the given difficultyId — used by the
ChallengeMode preset to define generic Bronze/Silver/
Gold tier scalings without naming each instance.

Three preset emitters: makeWotLK5manHeroic (5 WotLK
5-man Heroics: Utgarde Keep, Nexus, Azjol-Nerub,
Ahn'kahet, Drak'Tharon — all +13/2× Emblem of Heroism),
makeRaid25Heroic (4 25H raids: Naxx +13, EoE +13,
Ulduar +26, ICC +26 with corresponding Conquest/Triumph/
Frost emblems), makeChallengeMode (3 anachronistic
challenge-mode tiers as a template for custom servers
backporting MoP-era systems).

Validator's most novel checks are bounds-aware:
bonusQualityChance capped at 10000 basis points (above
that would guarantee multiple bonus drops), no negative
itemLevelDelta (Heroic shouldn't be worse than Normal —
warning, not error), no >50 ilvl delta (beyond canonical
range — warning), no zero or excessive dropChance-
Multiplier, AND (mapId, difficultyId) tuple uniqueness
unless mapId=0 wildcard (multiple scalings binding the
same instance+difficulty would make loot-roll lookup
ambiguous).

Format count 107 -> 108. CLI flag count 1175 -> 1180.
This commit is contained in:
Kelsi 2026-05-10 01:52:58 -07:00
parent 81070c470c
commit ede6fb9c3a
10 changed files with 729 additions and 0 deletions

View file

@ -0,0 +1,126 @@
#pragma once
#include <cstdint>
#include <string>
#include <vector>
namespace wowee {
namespace pipeline {
// Wowee Open Heroic Loot Scaling catalog (.whrd) —
// novel replacement for the implicit Heroic-mode loot
// rules vanilla WoW encoded in the dungeon/raid script
// system: a Normal-mode boss drops items from one loot
// table, the Heroic-mode version drops the same items
// at +N item levels with M× drop chance, plus an
// optional Heroic-only currency token (Emblem of Frost,
// etc.). Each WHRD entry binds one (mapId, difficultyId)
// combination to its scaling rules.
//
// Cross-references with previously-added formats:
// WMS: mapId references the WMS map catalog.
// WCDF: difficultyId references the WCDF creature/
// instance difficulty variant catalog.
// WIT: heroicTokenItemId references the WIT item
// catalog (the per-Heroic currency token, 0 if
// no token reward).
// WLOT: rules are layered over the base WLOT loot
// table the encounter normally drops.
//
// Binary layout (little-endian):
// magic[4] = "WHRD"
// version (uint32) = current 1
// nameLen + name (catalog label)
// entryCount (uint32)
// entries (each):
// scalingId (uint32)
// nameLen + name
// descLen + description
// mapId (uint32) / difficultyId (uint32)
// itemLevelDelta (int16) — bonus ilvl over
// Normal (often
// +13 for 5-man
// Heroic, +13 to +26
// for raid Heroic)
// bonusQualityChance (uint16) — 0..10000 (basis
// points, 100 = 1%);
// probability of a
// bonus +1-tier
// quality drop
// dropChanceMultiplier (float) — 1.0 = same drop
// rate, 1.5 = +50%,
// etc.
// heroicTokenItemId (uint32) — 0 if no token
// bonusEmblemCount (uint8) — extra emblem-token
// rewards on top of
// base 1× per boss
// pad0 / pad1 / pad2 (uint8)
// iconColorRGBA (uint32)
struct WoweeHeroicScaling {
struct Entry {
uint32_t scalingId = 0;
std::string name;
std::string description;
uint32_t mapId = 0;
uint32_t difficultyId = 0;
int16_t itemLevelDelta = 13;
uint16_t bonusQualityChance = 0;
float dropChanceMultiplier = 1.0f;
uint32_t heroicTokenItemId = 0;
uint8_t bonusEmblemCount = 0;
uint8_t pad0 = 0;
uint8_t pad1 = 0;
uint8_t pad2 = 0;
uint32_t iconColorRGBA = 0xFFFFFFFFu;
};
std::string name;
std::vector<Entry> entries;
bool isValid() const { return !entries.empty(); }
const Entry* findById(uint32_t scalingId) const;
// Returns the scaling rules for a given (map,
// difficulty) combo, or nullptr if no Heroic
// scaling is defined (defaults to no scaling).
// Used by the loot-roll engine when an encounter
// dies on Heroic-difficulty content.
const Entry* findForInstance(uint32_t mapId,
uint32_t difficultyId) const;
};
class WoweeHeroicScalingLoader {
public:
static bool save(const WoweeHeroicScaling& cat,
const std::string& basePath);
static WoweeHeroicScaling load(const std::string& basePath);
static bool exists(const std::string& basePath);
// Preset emitters used by --gen-hrd* variants.
//
// makeWotLK5manHeroic — 5 WotLK 5-man Heroic
// scalings (Utgarde Keep /
// Nexus / Azjol-Nerub /
// Ahn'kahet / Drak'Tharon).
// +13 ilvl, 1.0× drop
// chance, 2× Emblem of
// Heroism.
// makeRaid25Heroic — 4 25H raid scalings (Naxx
// / EoE / Ulduar / ICC).
// +26 ilvl, 1.5× drop chance
// on rare items, 1× Emblem
// of Frost per boss.
// makeChallengeMode — 3 challenge-mode tier
// scalings (Bronze / Silver
// / Gold). Anachronistic
// for WotLK but useful
// template for custom-server
// content.
static WoweeHeroicScaling makeWotLK5manHeroic(const std::string& catalogName);
static WoweeHeroicScaling makeRaid25Heroic(const std::string& catalogName);
static WoweeHeroicScaling makeChallengeMode(const std::string& catalogName);
};
} // namespace pipeline
} // namespace wowee