Closes the editing loop on the spell-aura-type catalog: dump a
.waur to JSON, hand-edit auraKind / targetingHint / tick interval
/ stack rules (e.g. retune PeriodicDamage from 3000ms to 2500ms
ticks for a faster server, mark a custom aura as
HostileOnly+stackable up to 10, switch a server-custom DoT from
StatMod to Periodic kind), re-import to a byte-identical binary.
Three dual-encoded fields:
- auraKind: int 0..8 OR "periodic" / "stat-mod" / "damage-mod"
/ "movement" / "visual" / "trigger" / "resource" / "control"
/ "misc"
- targetingHint: int 0..3 OR "any" / "self" / "hostile" /
"beneficial"
- isStackable: bool OR int (machine-generated sidecars work
too)
Verified byte-identical round-trip on all three presets
(periodic / stats / movement). CLI flag count 1001 -> 1003.
Open replacement for the SpellEffect.EffectAuraType field
meanings used when SpellEffect.Effect=APPLY_AURA. Defines what
each aura-type integer value actually does once an aura is
attached to a unit — PERIODIC_DAMAGE ticks damage every N
seconds, MOD_STAT adds a stat bonus, MOD_INCREASE_SPEED scales
movement, MOD_DAMAGE_PERCENT_DONE scales spell power, etc.
Companion to WSEF — together they cover the full spell-effect
classification space:
WSEF: outer effect ID — what does the effect DO?
(APPLY_AURA, SCHOOL_DAMAGE, HEAL, etc)
WAUR: inner aura type — when WSEF=APPLY_AURA, what KIND
of aura is applied? (PERIODIC_DAMAGE, MOD_STAT,
STUN, ROOT, etc)
Nine auraKind values (Periodic / StatMod / DamageMod /
Movement / Visual / Trigger / Resource / Control / Misc)
classify the major behavior families. Periodic auras carry an
updateFrequencyMs (canonical 3s for DoT/HoT, 2s for energize,
1s for fast triggers). Stackable auras carry a maxStackCount.
Cross-references back to WSEF (this catalog is the secondary
classification that WSEF entry id 6 (APPLY_AURA) dispatches
into) and forward to WSPL (spell entries with effect=APPLY_AURA
reference an auraTypeId here).
Three preset emitters: --gen-aur (5 periodic auras with
canonical tick intervals), --gen-aur-stats (5 stat-modifier
auras instantly applied on attach), --gen-aur-movement (4
movement-impairing CC auras typical of crowd-control spells).
Validation enforces name presence, auraKind 0..8, targetingHint
0..3, no duplicate ids; errors on Periodic kind without
updateFrequencyMs (would never tick); warns on:
- non-Periodic/Trigger kinds with updateFrequencyMs > 0
(engine ignores tick interval)
- maxStackCount > 0 with isStackable=false (cap unreachable)
Wired through the cross-format table; WAUR appears automatically
in all 15 cross-format utilities. Format count 82 -> 83;
CLI flag count 996 -> 1001 — broke the 1000-flag mark.
Closes the editing loop on the spell-effect-type catalog: dump a
.wsef to JSON, hand-edit effectKind / behaviorFlags / baseAmount
(e.g. tag a server-custom effect ID as Damage kind, add
IgnoresImmunities to a custom dispel, retune ScriptedHeal's
default baseAmount), re-import to a byte-identical binary.
Two dual-encoded fields:
- effectKind: int 0..9 OR "damage" / "heal" / "aura" /
"energize" / "trigger" / "movement" / "summon" / "dispel"
/ "dummy" / "misc"
- behaviorFlags: int bitfield OR pipe-separated label string
("RequiresTarget|IsHostileEffect|TriggersGCD"). Importer
prefers int form when both present so unknown bits round-
trip losslessly.
Verified byte-identical round-trip on all three presets
(damage / healing / aura). CLI flag count 994 -> 996.
Open replacement for the SpellEffect.Effect field meanings in
Spell.dbc plus the engine's hard-coded effect dispatch table.
Defines what each spell-effect integer value actually does —
SCHOOL_DAMAGE=2 deals magical damage, DUMMY=3 is a script hook,
HEAL=10 restores health, ENERGIZE=30 restores power,
APPLY_AURA=6 attaches a buff/debuff, etc.
WotLK's Spell.dbc has 192+ effect type integers, each with its
own resolver in the spell engine. This catalog lets the engine
look up "given effect=10, what resolution behavior do I run?"
via a single table lookup instead of a hard-coded switch
statement, and lets server-custom spells reference new effect
IDs without touching engine code.
Ten effectKind values capture the major behavior families
(Damage / Heal / Aura / Energize / Trigger / Movement / Summon /
Dispel / Dummy / Misc), and a 6-bit behaviorFlags field
captures targeting/gating semantics:
- RequiresTarget — must have a target
- RequiresLineOfSight — LoS check on target
- IsHostileEffect — hostile only (PvP gating)
- IsBeneficialEffect — friendly only
- IgnoresImmunities — bypasses Bubble / IBF / etc
- TriggersGCD — counts toward GCD
Distinct from WAUR (Spell Aura Type, future format) which is the
secondary classification used when effectType is APPLY_AURA. The
two together cover the full spell-effect classification space.
Three preset emitters: --gen-sef (5 damage effects covering
typical Spell.dbc damage IDs), --gen-sef-healing (4 heal
effects all flagged IsBeneficialEffect), --gen-sef-aura (5
aura-application effects covering single-target / pet /
party-wide / area variants).
Validation enforces name presence, effectKind 0..9, no duplicate
ids; warns on:
- both Hostile and Beneficial flags set (engine picks Hostile,
contradiction suggests config bug)
- Damage kind without TriggersGCD (most damage should be on GCD
— env damage is the canonical exception)
- Heal kind without IsBeneficialEffect (engine treats heal as
ungated, may damage enemies)
Wired through the cross-format table; WSEF appears automatically
in all 15 cross-format utilities. Format count 81 -> 82; CLI flag
count 989 -> 994.
Walks both trees in parallel, classifies each file by its 4-byte
magic, and bucks differences into five categories:
- only-in-A file present in A, missing from B (removed)
- only-in-B file present in B, missing from A (added)
- magic-changed same path but the format swapped
(e.g. somebody renamed a .wsrg to .wmat)
- size-changed same magic, different byte size
(content was edited)
- identical same magic, same size
Exit 1 if any category but identical is non-zero, so it composes
into shell pipelines and CI. JSON sidecar via --json.
Useful for project-version comparison: did anything actually
change between two snapshots? --diff-tree answers in one pass.
Pairs naturally with the existing --diff-headers (which goes
deeper on a single file pair) and the --bulk-* / --audit-tree
family of cross-tree utilities.
Files whose magic isn't recognized by the format table are
silently skipped so unrelated junk in the tree (build artifacts,
temp files) doesn't pollute the diff. Identity check is
magic+size only — true byte-equality would need a hash and the
heuristic is good enough for the typical use case.
This is the 15th cross-format utility:
--list-formats / --info-magic / --summary-dir / --rename-by-magic
--bulk-rename-by-magic / --touch-tree / --tree-summary-md
--catalog-grep / --diff-headers / --audit-tree / --magic-fix
--bulk-validate / --bulk-export-json / --bulk-import-json
--diff-tree
CLI flag count 988 -> 989.
Closes the editing loop on the achievement-criteria catalog: dump
a .wacr to JSON, hand-edit criteriaType / targetId / requiredCount
/ timeLimitMs / progressOrder (e.g. retune a kill-count from 50
boars to 25, swap a quest progression target, add a time limit to
turn a normal achievement into a speedrun, reorder progressOrder
so the easiest sub-objective shows first in the UI), re-import to
a byte-identical binary.
The exporter emits both criteriaType (int 0..12) and the human-
readable criteriaTypeName ("kill-creature" / "reach-level" /
"complete-quest" / "earn-gold" / "gain-honor" / "earn-reputation"
/ "explore-zone" / "loot-item" / "use-item" / "cast-spell" /
"pvp-kill" / "dungeon-run" / "misc"); the importer accepts either
form. The 13-way enum is the largest single-field dual-encoding
implemented so far in any catalog round-trip.
Verified byte-identical round-trip on all three presets
(kill / quest / mixed). CLI flag count 986 -> 988.
Open replacement for Blizzard's Achievement_Criteria.dbc. Defines
the individual progression criteria that a character must
complete to earn an achievement.
Each WACH achievement has a tree of WACR criteria — "Kill 100
boars" is one criteria entry with criteriaType=KillCreature,
targetId=boarCreatureId, requiredCount=100. Multi-criteria
achievements (e.g. "Visit all 3 capital cities") have one entry
per sub-objective, all referencing the same achievementId, with
progressOrder determining their display sequence in the
achievement UI.
Thirteen criteriaType values cover the full progression variety:
KillCreature / ReachLevel / CompleteQuest / EarnGold /
GainHonor / EarnReputation / ExploreZone / LootItem /
UseItem / CastSpell / PvPKill / DungeonRun / Misc
The targetId field is type-polymorphic — for KillCreature it
references WCRT.creatureId, for CompleteQuest it references
WQT.questId, for ExploreZone it's a WMS.zoneId, etc. The engine
interprets it based on criteriaType.
Cross-references back to WACH (achievementId), WCRT
(KillCreature.targetId), WQT (CompleteQuest.targetId), WIT
(LootItem/UseItem.targetId), WMS (ExploreZone.targetId), WSPL
(CastSpell.targetId). findByAchievement(achId) returns all
criteria for an achievement sorted by progressOrder — used
directly by the achievement UI to render the progress checklist.
Three preset emitters: --gen-acr (5 kill criteria under one
composite achievement showing different creature targets),
--gen-acr-quest (4-step quest progression), --gen-acr-mixed
(5 cross-type criteria demonstrating the full CriteriaType
variety).
Validation enforces id+name+achievementId presence,
criteriaType 0..12, no duplicate ids; warns on:
- missing targetId for type-specific kinds (KillCreature,
CompleteQuest, etc. — engine cannot track without it)
- ReachLevel with requiredCount > 80 (above WotLK cap)
- timeLimitMs set on non-time-sensitive types (engine
ignores it for ReachLevel / EarnGold)
- requiredCount=0 (criteria completes instantly on first
progress event — usually a misconfig)
Wired through the cross-format table; WACR appears automatically
in all 14 cross-format utilities. Format count 80 -> 81; CLI flag
count 981 -> 986.
Closes the editing loop on the spell-reagent catalog: dump a
.wspr to JSON, hand-edit reagentKind / spellId / per-slot
itemId+count pairs (e.g. swap a Mage Portal's reagent from Rune
of Portals to a server-custom item, change a Warlock summon to
need 2 Soul Shards instead of 1, add Tier-3 Catalyst entries
for upgraded spell variants), re-import to a byte-identical
binary.
Reagent slot arrays (8 itemIds, 8 counts) are exported as JSON
arrays — easier to read and edit than 16 individual numbered
fields. Importer pads arrays shorter than 8 with zeros and
silently truncates longer arrays, so hand-edited sidecars don't
need to spell out every empty slot.
The exporter emits both reagentKind (int 0..4) and the human-
readable reagentKindName ("standard" / "soul-shard" /
"focused-item" / "catalyst" / "tradeable"); the importer accepts
either form.
Verified byte-identical round-trip on all three presets
(mage / warlock / rez). CLI flag count 979 -> 981.
Open replacement for the per-spell reagent fields in Spell.dbc
(Reagent[8] + ReagentCount[8]). Defines the item reagents that a
spell consumes from the caster's inventory each time it's cast —
Mage Portal needs a Rune of Portals, Resurrection needs a Holy
Candle (focused, not consumed), Warlock summons consume Soul
Shards.
One entry per reagent-using spell — most spells have no reagents
and are absent from this catalog. Each entry can list up to 8
(itemId, count) pairs which all must be present for the spell
to cast. Five reagentKind values capture the variety of reagent
semantics:
- Standard — ordinary consumed reagent
- SoulShard — warlock-specific shard tracking
- FocusedItem — required to cast but NOT consumed
(Symbol of Divinity for Resurrection)
- Catalyst — enables a stronger version of the spell
- Tradeable — crafting reagent for trade-skill recipes
Cross-references back to WSPL (every entry references a spellId)
and WIT (every reagent itemId references an item entry).
findBySpell(spellId) is the primary engine lookup.
Three preset emitters: --gen-spr (4 mage portal/teleport
reagents using Rune of Teleportation 17031), --gen-spr-warlock
(4 demon summons each consuming 1 Soul Shard 6265),
--gen-spr-rez (3 resurrection variants demonstrating each
ReagentKind including a no-reagent Druid Rebirth and a
focused-item Priest Resurrection).
Validation enforces id+name+spellId presence, reagentKind 0..4,
no duplicate ids; warns on:
- slot itemId/count mismatch (id without count or vice versa)
- SoulShard kind with non-canonical reagent (not item 6265)
- FocusedItem kind with no reagent slots set (focused-item
gating has nothing to gate)
- duplicate spellId across entries (engine honors only first)
This is the 80th open format milestone. Wired through the
cross-format table; WSPR appears automatically in all 14
cross-format utilities. Format count 79 -> 80; CLI flag count
974 -> 979.
Two new cross-format utilities for git-friendly catalog editing:
--bulk-export-json <dir> recursively walks the tree, peeks
each file's magic, and dispatches the
per-format --export-X-json flag for
every .w* it finds. Writes one .json
sidecar per binary.
--bulk-import-json <dir> inverse direction — recursively walks
*.wXXX.json sidecars and dispatches
the per-format --import-X-json flag
to write back the byte-identical
binary.
Both report total / processed / failed / skipped counts and exit
1 on any failure. Asset-style formats with no per-format JSON
exporter are counted in the "skipped" bucket.
Use case — git-friendly diffs of binary catalogs:
--bulk-export-json mydir # convert binaries to JSON
git add mydir/*.json && git commit # version control as text
git diff # see exact catalog changes
--bulk-import-json mydir # restore binaries
Verified end-to-end: 5 different format presets (WSRG, WCDF,
WMAT, WTLE, WCTR) round-trip byte-identical through export -> JSON
-> import. Reuses the same shellQuote / WEXITSTATUS scaffolding
as --bulk-validate. CLI flag count 972 -> 974.
This brings the cross-format utility count to 14:
--list-formats / --info-magic / --summary-dir / --rename-by-magic
--bulk-rename-by-magic / --touch-tree / --tree-summary-md
--catalog-grep / --diff-headers / --audit-tree / --magic-fix
--bulk-validate / --bulk-export-json / --bulk-import-json
Closes the editing loop on the currency-type catalog: dump a
.wctr to JSON, hand-edit currencyKind / cap values / categoryId
/ isAccountWide / iconPath (e.g. raise Conquest Points weekly
cap from 1650 to 2200, retag a server-custom currency from
Misc to FactionToken kind, mark Honor Points as account-wide
for a casual server), re-import to a byte-identical binary.
The exporter emits both currencyKind (int 0..5) and the human-
readable currencyKindName ("pvp-honor" / "pve-raid" /
"faction-token" / "event-token" / "crafting" / "misc"); the
importer accepts either form. isAccountWide round-trips as a
JSON bool but accepts int as well so machine-generated sidecars
work too.
Verified byte-identical round-trip on all three presets
(pvp / pve / faction). CLI flag count 970 -> 972.
Open replacement for Blizzard's CurrencyTypes.dbc plus the
per-currency cap tables in CurrencyCategory.dbc. Defines the
in-game currencies that are NOT regular item stacks: Honor
Points, Arena Points, Justice Points, Valor Points, Conquest
Points, plus the various faction tokens (Champion's Seal,
Wintergrasp Mark of Honor, Emblem of Frost).
Distinct from regular items in WIT — currencies are tracked
per-character as scalar quantities with weekly + absolute caps,
not as stackable inventory slots. Some currencies are still
backed by a WIT item entry for the icon and tooltip text
(itemId field), while others (Honor, Arena) live entirely in
the currency system.
The cap model captures both shapes:
- maxQuantity = absolute lifetime cap (Honor Points 75k)
- maxQuantityWeekly = weekly earn cap, no absolute cap
(Conquest Points 1650/wk)
- both 0 = uncapped (faction tokens, Emblem of Frost)
earnableNow(id, current, weekly) is the engine helper that
returns the smaller of (remaining absolute, remaining weekly).
Cross-references back to WIT (itemId for tooltip art) and
WFAC (categoryId references factionId for FactionToken kind —
the rep gate that lets you spend the token).
Three preset emitters: --gen-ctr (4 PvP currencies covering
absolute, weekly-only, and uncapped tiers), --gen-ctr-pve (4
PvE raid currencies with same cap variety), --gen-ctr-faction
(4 faction tokens with their categoryId pointing at WFAC
faction ids).
Validation enforces id+name presence, currencyKind 0..5, no
duplicate ids; warns on:
- maxQuantityWeekly > maxQuantity (weekly cap will never be
reached, absolute cap blocks first)
- FactionToken kind with categoryId=0 (rep gate breaks)
- no caps + no itemId + no iconPath (currency has no display
data and unbounded earn rate)
Wired through the cross-format table; WCTR appears automatically
in all 12 cross-format utilities. Format count 78 -> 79; CLI flag
count 965 -> 970.
Closes the editing loop on the talent-tab catalog: dump a .wtle
to JSON, hand-edit roleHint / classMask / displayOrder /
iconPath / backgroundFile (e.g. swap a Mage Frost tab from DPS
to Hybrid, point Holy Paladin's tab to a custom background art
file, reorder displayOrder to put Protection first), re-import
to a byte-identical binary.
The exporter emits both roleHint (int 0..4) and the human-
readable roleHintName ("dps" / "tank" / "healer" / "hybrid" /
"pet"); the importer accepts either form.
Verified byte-identical round-trip on all three presets
(warrior / mage / paladin). CLI flag count 963 -> 965.
Open replacement for Blizzard's TalentTab.dbc plus the per-tab
fields in Spell.dbc / Talent.dbc. Defines the three talent trees
that each class has — Warrior: Arms / Fury / Protection;
Mage: Arcane / Fire / Frost; Paladin: Holy / Protection /
Retribution; etc.
Each tab carries its own name, role hint (DPS / Tank / Healer /
Hybrid / PetClass), display order in the talent UI, background
artwork path (e.g. "WarriorArms" for the parchment background),
icon path, and the class bitmask it belongs to.
Distinct from WTAL (which defines individual talent points) —
WTLE says "the Arms tree exists for Warriors, displays in tab 1,
is a DPS spec"; WTAL says "Mortal Strike is a 1-point talent in
the Arms tree, row 7, requires Improved Charge as a prerequisite".
Cross-references back to WCHC (classMask uses the same bit
layout) and forward to WTAL (talent entries reference tabId
here). findByClass(classBit) returns all tabs for a class
sorted by displayOrder — the talent UI uses this directly to
populate its tab buttons.
Three preset emitters: --gen-tle (Warrior 3 tabs with two DPS +
one Tank), --gen-tle-mage (Mage 3 DPS tabs), --gen-tle-paladin
(Paladin 3 tabs covering all three roles in one preset).
Validation enforces id+name+classMask presence (classMask=0
means no class can use the tab — usually a config bug),
roleHint 0..4, no duplicate ids; warns on empty iconPath
(missing-texture render), empty backgroundFile (no panel art),
displayOrder>3 (UI shows at most 4 tabs), and (classMask +
displayOrder) collisions for overlapping classes (two tabs
claiming the same UI slot for the same class).
Wired through the cross-format table; WTLE appears automatically
in all 12 cross-format utilities. Format count 77 -> 78; CLI flag
count 958 -> 963.
Closes the editing loop on the player-spawn-profile catalog: dump
a .wpsp to JSON, hand-edit raceMask / classMask / spawn coords /
bind point / starting items + counts / starting spell ids
(e.g. move Northshire's spawn coords, swap a Hunter's starter
weapon, give every Warrior a Hearthstone, retune a DK's spell
loadout to include Frost Strike), re-import to a byte-identical
binary.
Verified byte-identical round-trip on all three presets
(alliance / horde / dk). CLI flag count 956 -> 958.
Open replacement for AzerothCore's playercreateinfo SQL table
plus the per-class/race starting fields in CharStartOutfit.dbc.
Defines the initial state for a newly created character: starting
map / zone / position / facing, bind point (Hearthstone
destination), up to 4 starting items with counts, and up to 4
starting spells.
One entry per (race, class) combination — a Human Warrior spawns
at Northshire Abbey with a Worn Shortsword and Heroic Strike
already learned, while an Orc Hunter spawns in Valley of Trials
with Aimed Shot and a starter rifle. Death Knights have their
own preset spawning at lvl 55 in Acherus, the Ebon Hold.
The race+class fields are bitmasks (mirroring WCHC layout) so
one profile entry can cover multiple class/race combinations
that share starting state. findByRaceClass(raceBit, classBit)
is the engine helper used by character creation.
Cross-references back to WCHC (race/class bit layouts), WMS (map
ids), WIT (starting item ids), and WSPL (starting spell ids).
Three preset emitters: --gen-psp (5 Alliance combos covering
each starting zone from Northshire to Ammen Vale), --gen-psp-horde
(5 Horde combos from Valley of Trials to Sunstrider Isle),
--gen-psp-dk (2 DK combos at lvl 55 in Acherus with Death Coil /
Plague Strike / Death Grip starter loadout).
Validation enforces id+name+race+class+startingLevel presence,
no duplicate ids; warns on (0,0,0) spawn (uninitialized entry),
item id/count mismatch (granted item without count or vice versa),
startingLevel > 80 (above WotLK cap), and Death Knight class
with startingLevel < 55 (DKs canonically start at 55).
Wired through the cross-format table; WPSP appears automatically
in all 12 cross-format utilities. Format count 76 -> 77; CLI flag
count 951 -> 956.
Recursively walks a directory, peeks each file's 4-byte magic to
identify the format, derives the per-format --validate-X flag
from the format table's --info-X entry, and invokes that
validator as a subprocess for each file. Reports total / passed
/ failed / skipped counts and lists the failure paths with their
exit codes; returns exit 1 if any failure is found.
For each failure it prints the exact follow-up command needed to
reproduce the detailed error message, so the user doesn't have
to remember which validator goes with which extension. Asset-
style formats with no validator (.wom / .wob / .whm world
geometry) are counted in the "skipped" bucket but don't fail
the run.
Composes with the existing audit/fix tooling:
--audit-tree dir # find header-level breakage
--magic-fix dir --apply # auto-fix ext/magic mismatches
--bulk-validate dir # run every per-format validator
# then re-run --validate-X on individual failures for detail
This is the 12th cross-format utility — depth-checking that
catches per-format semantic errors (duplicate ids, invalid
enums, contradictory flag combos, dangling cross-refs) that
--audit-tree's header-only scan can't see. CLI flag count
950 -> 951.
Closes the editing loop on the item-material catalog: dump a
.wmat to JSON, hand-edit materialKind / weightCategory / foley /
impact sound bindings / material flags (e.g. swap a Hide entry
from Light to Medium weight, add IsBreakable to a wooden bow,
re-bind Plate's foley to a different WSND entry, mark a new
HolyForged variant), re-import to a byte-identical binary.
Three different field types each take dual int+name forms:
- materialKind: int 0..11 OR "cloth"/"leather"/"mail"/"plate"/
"wood"/"stone"/"metal"/"liquid"/"organic"/"crystal"/
"ethereal"/"hide"
- weightCategory: int 0..2 OR "light"/"medium"/"heavy"
- materialFlags: int bitfield OR pipe-separated label string
("IsMagical|IsBreakable|IsHolyCharged"). Importer prefers
int form when both present so unknown bits round-trip
losslessly.
Verified byte-identical round-trip on all three presets
(armor / weapon / magical). CLI flag count 948 -> 950.
Open replacement for Blizzard's Material.dbc plus the Material
and SheatheType fields in ItemDisplayInfo.dbc. Defines the
material categorization that items reference (Cloth / Leather /
Mail / Plate / Wood / Steel / Crystal / Ethereal / etc), each
with its own foley sound (played on item use), impact sound
(played on drop / hit), weight category, and material-property
flags (IsBreakable / IsMagical / IsFlammable / IsConductive /
IsHolyCharged / IsCursed).
The engine plays a sword's metallic clang from impactSoundId
when it hits a stone wall, but a cloth tabard makes no such
sound — the difference is exactly the material assigned by this
catalog. Every armor and weapon item in WIT references a
materialId here.
Twelve materialKind values cover the standard armor classes
(Cloth/Leather/Mail/Plate/Hide), structural materials (Wood /
Stone / Metal), and special categories (Liquid / Organic /
Crystal / Ethereal). Three weight tiers (Light / Medium / Heavy)
control encumbrance UI hints.
Cross-references back to WSND (foleySoundId / impactSoundId
reference WSND sound entries) and forward to WIT (item entries
reference materialId here).
Three preset emitters: --gen-mat (5 armor materials matching
WoW's armor classes), --gen-mat-weapon (5 weapon materials from
breakable+flammable Wood through enchanted endgame steel),
--gen-mat-magical (4 magical materials with special flags
including the IsHolyCharged anti-undead property).
Validation enforces id+name presence, materialKind 0..11,
weightCategory 0..2, no duplicate ids; warns on:
- IsHolyCharged + IsCursed both set (engine picks one,
typically IsCursed wins)
- Plate kind that's not Heavy weight (canonical violation)
- Cloth kind that's not Light weight (canonical violation)
Wired through the cross-format table; WMAT appears automatically
in all 11 cross-format utilities. Format count 75 -> 76; CLI flag
count 943 -> 948.
Closes the editing loop on the creature-difficulty routing
catalog: dump a .wcdf to JSON, hand-edit baseCreatureId / 4
variant ids / spawnGroupKind (e.g. swap a Lich King variant from
heroic25Id 39168 to a custom encore template, change a 5-man
boss from Boss to MiniBoss kind, route a new world boss through
the WorldBoss kind), re-import to a byte-identical binary.
The exporter emits both spawnGroupKind (int 0..5) and the human-
readable spawnGroupKindName ("boss" / "mini-boss" / "rare-elite"
/ "trash" / "add" / "world-boss"); the importer accepts either
form.
Verified byte-identical round-trip on all three presets
(starter / wotlk / fiveman). CLI flag count 941 -> 943.
Open replacement for Blizzard's CreatureDifficulty.dbc. Maps a
base creature entry to its difficulty variants:
Normal-10 / Normal-25 / Heroic-10 / Heroic-25 in WotLK raid
format. Each variant is itself a separate WCRT creature entry
with its own stats, abilities, and loot.
When a 25-man party engages an instance, the engine looks up the
encounter base creature's difficultyId, reads the normal25Id
field, and spawns that variant instead. This is how Lord
Marrowgar in 25-Heroic ICC has 30M HP and hits for 80k while the
same encounter in 10-Normal has 5M HP and hits for 25k — same
spawn point, different WCRT entries.
5-man dungeons typically use only normal10Id + heroic10Id (the
25-man fields stay 0 — engine falls through to the 10-man
variant when 25-man is queried). World bosses don't scale at
all (all 4 variant fields stay 0, engine falls back to the base
entry).
Cross-references back to WCRT — every non-zero variant id field
points at a WCRT.creatureId entry; the base creature itself
lives in WCRT too.
Three preset emitters: --gen-cdf (4 example bosses with full
4-variant routing), --gen-cdf-wotlk-raid (4 ICC-style raid
bosses Marrowgar/Deathwhisper/Saurfang/LK with all 4 difficulty
variants), --gen-cdf-fiveman (4 5-man dungeon bosses with only
Normal+Heroic 10-man set). resolveVariant(id, mode) is the
engine helper.
Validation enforces id+name+baseCreatureId presence,
spawnGroupKind 0..5, no duplicate ids; warns on:
- WorldBoss kind with non-zero variant ids (world bosses don't scale)
- duplicate baseCreatureId across routes (only first honored)
- all-self-reference non-WorldBoss (creature doesn't actually scale)
- Boss with n25 but not n10 (raid sequencing typo — n10 always
comes with n25)
Wired through the cross-format table; WCDF appears automatically
in all 11 cross-format utilities. Format count 74 -> 75; CLI flag
count 936 -> 941.
Closes the editing loop on the glyph-slot catalog: dump a .wgfs
to JSON, hand-edit slotKind / displayOrder / minLevelToUnlock /
requiredClassMask (e.g. add a fourth Major slot, lower a Minor
slot's unlock from 75 to 70, restrict a Prime slot to Mages
only), re-import to a byte-identical binary.
The exporter emits both slotKind (int 0..2) and the human-
readable slotKindName ("major", "minor", "prime"); the importer
accepts either form.
Verified byte-identical round-trip on all three presets
(starter / wotlk / cata). CLI flag count 934 -> 936.
Open replacement for Blizzard's GlyphSlot.dbc. Defines the
per-class glyph slot layout: which slots a class has (Major /
Minor / Prime), in which display order they appear in the
spellbook UI, and at which character level each slot becomes
available for use.
Distinct from WGLY (GlyphProperties) which defines the individual
glyphs themselves. WGLY says "Glyph of Polymorph exists, costs 1
inscription dust, modifies Polymorph"; WGFS says "the slot that
holds Glyph of Polymorph is the second Major Glyph Slot, unlocks
at level 25, and only Mages have it".
Layout grew across expansions, captured by the three presets:
- --gen-gfs — 6 slots: 3 Major + 3 Minor all-class
baseline (25/50/75 each)
- --gen-gfs-wotlk — 6 slots: 3 Major (15/30/50) + 3 Minor
(15/50/70) matching WotLK 3.3.5a
- --gen-gfs-cata — 9 slots: 3 Prime + 3 Major + 3 Minor
matching Cataclysm
Cross-references back to WGLY (glyphs reference slotKind to
constrain which glyph fits which slot) and WCHC (requiredClassMask
uses the same bit layout as WCHC class IDs).
Validation enforces id+name+classMask presence (classMask=0 means
no class can use the slot — usually a config bug), slotKind 0..2,
no duplicate ids; warns on minLevelToUnlock>80 (would never
unlock at WotLK cap), displayOrder>4 (UI typically shows 3-4),
and (kind+order) collisions for overlapping classMask (two slots
claiming the same UI position would render on top of each other).
isUnlockedFor(id, classBit, level) is the engine helper.
Wired through the cross-format table; WGFS appears automatically
in all 11 cross-format utilities. Format count 73 -> 74; CLI flag
count 929 -> 934.
Closes the editing loop on the spell-power-cost bucket catalog:
dump a .wspc to JSON, hand-edit baseCost / perLevelCost /
percentOfBase / powerType / costFlags (e.g. retune LowMana from
5% to 4%, add ScalesWithMastery to a class bucket, switch a
Whirlwind cost from 25 rage to 20), re-import to a byte-identical
binary.
The exporter emits both powerType (int 0..11) and the human-
readable powerTypeName ("mana" / "rage" / "focus" / "energy" /
"happiness" / "runic-power" / "runes" / "soul-shards" /
"holy-power" / "eclipse" / "health" / "no-cost"). costFlags is
emitted as both int bitfield AND pipe-separated label string.
The importer prefers the int form for costFlags when both are
present so unknown flag bits round-trip losslessly.
Verified byte-identical round-trip on all three presets
(starter / rage / mixed). CLI flag count 927 -> 929.
Open replacement for the per-spell power-cost fields in Spell.dbc
plus SpellPowerCost-related side tables. Defines categorical
power-cost buckets that spells reference (LowMana 5% / MediumMana
15% / HighMana 30% of caster max mana; fixed Rage-30 /
Energy-40 / Runic-30 / etc), so spells share cost metadata across
ranks instead of embedding per-rank cost numbers.
Completes the small lookup-bucket five-pack:
WSRG — range bucket
WSCT — cast time bucket
WSDR — duration bucket
WSCD — cooldown bucket
WSPC — power cost bucket (this catalog)
Five small integer ids per spell (range / cast / dur / cd / cost)
replace the dozens of duplicate per-rank fields that Blizzard's
Spell.dbc carries. Editing one bucket here retunes every spell
that references it — change LowMana from 5% to 4% and every
rank-1 bolt across every caster class becomes cheaper.
Cost can be flat (baseCost), per-level scaled (perLevelCost), or
percentage-of-max-power (percentOfBase) — the engine sums
whichever fields are non-zero. resolveCost(id, level, maxPower)
does the math. Twelve power types covering every WoW resource
(Mana / Rage / Focus / Energy / Happiness / Runic Power / Runes /
Soul Shards / Holy Power / Eclipse / Health / NoCost).
Three preset emitters: --gen-spc (4 baseline mana tiers),
--gen-spc-rage (4 fixed warrior rage costs including stance-locked
Whirlwind), --gen-spc-mixed (5 cross-class costs covering every
non-mana power type with refund-on-miss flag for energy).
Validation enforces id+name presence, powerType 0..11, no
duplicate ids; warns on percentOfBase outside [0,1] (would
overflow), NoCost type with non-zero cost fields, and non-NoCost
types with no cost set (would cast for free — easy bug to ship).
Wired through the cross-format table; WSPC appears automatically
in all 11 cross-format utilities. Format count 72 -> 73; CLI flag
count 922 -> 927.
Natural follow-up to --audit-tree: when that utility flags
ext-mismatch or magic-no-ext issues, --magic-fix proposes (and
optionally applies) the renames that resolve them. Walks a
directory recursively, reads each file's 4-byte magic, looks it
up in the format table, and renames to the canonical extension
when the current extension doesn't match (or is absent).
Defaults to dry-run for safety — prints the proposed renames so
they can be reviewed first; pass --apply to commit them. Refuses
to clobber existing files: when the target path already exists
(e.g. foo.wsct + foo.wsrg both with WSRG magic), the rename is
flagged as a collision and skipped, leaving both files in place
for manual resolution. Returns exit 1 if any proposals exist (in
dry-run) or any collisions are skipped (in apply), so it composes
into shell pipelines.
JSON sidecar via --json. Suggested workflow:
--audit-tree dir # find what's broken
--magic-fix dir # preview the auto-fixes
--magic-fix dir --apply # commit them
--audit-tree dir # confirm clean
CLI flag count 921 -> 922.
Closes the editing loop on the creature-family catalog: dump a
.wcef to JSON, hand-edit familyKind / petTalentTree /
minLevelForTame / petFoodTypes (e.g. add Bread to Bear's diet,
move Boar from Tenacity to Cunning, drop the tame requirement on
exotic Worm from 50 to 45), re-import to a byte-identical binary.
Three different field types each take dual int+name forms:
- familyKind: int 0..5 OR "beast"/"demon"/"undead"/"elemental"/
"not-pet"/"exotic"
- petTalentTree: int 0..3 OR "none"/"ferocity"/"tenacity"/
"cunning"
- petFoodTypes: int bitfield OR pipe-separated label string
("Meat|Fish|Raw"). Importer prefers the int form when both
are present so unknown bits round-trip losslessly.
Verified byte-identical round-trip on all three presets
(starter / ferocity / exotic). CLI flag count 919 -> 921.
Open replacement for CreatureFamily.dbc plus the per-creature
family fields in Creature.dbc. Defines the family categorization
that pet-able beasts share (Bear / Cat / Wolf / Boar / Crab /
Raptor / Devilsaur / etc), each with its own pet talent tree
(Ferocity / Tenacity / Cunning), food preferences as a bitmask
(Meat / Fish / Bread / Cheese / Fruit / Fungus / Raw), the skill
line that family-specific abilities reference, and the minimum
hunter level required to tame it.
Used by the hunter pet system to decide which talent tree a tamed
pet uses, validate that a hunter can tame a creature, match
feeding-table food items to pet preferences, and gate exotic-beast
families behind the Beast Master 51-point talent.
Cross-references back to WCRT (creature.familyId points here) and
WSPL (family-specific abilities reference WSPL spellId via the
skillLine field).
Three preset emitters: --gen-cef (5 baseline families covering
both major talent trees), --gen-cef-ferocity (4 DPS-tree pets
with bleed/howl/armor-shred mechanics), --gen-cef-exotic (4
exotic Beast Master families requiring 51-point talent).
Validation enforces id+name presence, familyKind 0..5, talent
tree 0..3, no duplicate ids, and warns on:
- NotPet families with a non-None talent tree (irrelevant)
- Exotic families with minLevelForTame > 80 (level-cap unreachable)
- Beast/Exotic families with no food types set (pet would starve)
Wired through the cross-format table; WCEF appears automatically
in all 10 cross-format utilities. Format count 71 -> 72; CLI flag
count 914 -> 919.
Closes the editing loop on the spell-cooldown bucket catalog: dump
a .wscd to JSON, hand-edit cooldownMs / bucketKind / category
flags (e.g. retune the global cooldown from 1.5s to 1.0s, mark a
bucket as IgnoresCooldownReduction, add Polymorph variants to the
class family bucket), re-import to a byte-identical binary.
The exporter emits both bucketKind (int 0..4) and the human-
readable bucketKindName ("spell", "item", "class", "global",
"misc"); same dual form for categoryFlags (int bitfield AND
"AffectedByHaste|OnGCDStart" pipe-separated label string). The
importer prefers the int form for categoryFlags when both are
present so unknown flag bits round-trip losslessly, falling back
to the label form for hand-edited sidecars.
Verified byte-identical round-trip on all three presets
(starter / class / items). CLI flag count 912 -> 914.
Open replacement for SpellCooldown.dbc plus the per-spell
category-cooldown fields in Spell.dbc. Defines the shared-cooldown
buckets that related spells reference: casting one spell triggers
a cooldown on every other spell in the same bucket. Mage Polymorph
variants (Sheep / Pig / Turtle / Cat) all share one bucket so
morphing a target locks all variants at once. Healing potions and
mana potions share the SharedWithItems bucket so consuming one
locks the other.
Distinct from WSDR (which times how long an aura stays on a
target) — WSCD times how long before a spell can be cast again.
The global cooldown (GCD) is itself just one bucket of this kind,
flagged with OnGCDStart so the engine triggers it at cast start
rather than cast finish.
Three preset emitters: --gen-cdb (4 baseline buckets including
GCD), --gen-cdb-class (5 mage-specific class cooldowns including
the Polymorph family), --gen-cdb-items (5 item cooldowns
including the heal/mana potion shared bucket and the 60min
Hearthstone family). Validation enforces id+name presence,
bucketKind 0..4, no duplicate ids, and warns on Global without
OnGCDStart (engine wouldn't trigger on cast start) and Spell
kind with SharedWithItems (contradictory).
categoryFlags is a bitfield (AffectedByHaste / SharedWithItems /
OnGCDStart / IgnoresCooldownReduction); --info-wscd decodes the
bits to label list. Wired through the cross-format table; WSCD
appears automatically in all 9 cross-format utilities. Format
count 70 -> 71; CLI flag count 907 -> 912.
Walks a directory recursively and groups problems by category:
too-small (file under 16 bytes — can't hold a header),
unknown-magic (.w* file whose magic is not in the format table),
ext-mismatch (extension says one format but the magic says
another — usually from a renamed file), magic-no-ext (file with
recognized Wowee magic but no .w* extension), and header-trunc
(magic matches but the rest of the header is truncated). Returns
exit 1 if any issue is found, so it composes into shell pipelines
and CI checks. JSON sidecar via --json.
Catches the kinds of breakage that --summary-dir silently rolls
into the "unrecognized" bucket — a renamed .wsrg file masquerading
as .wsct shows up cleanly here but would otherwise be invisible.
Like every cross-format utility this reuses cli_format_table.cpp,
so new formats are audited automatically. CLI flag count
906 -> 907.
Closes the editing loop on the spell-duration bucket catalog: dump
a .wsdr to JSON, hand-edit baseDurationMs / perLevelMs / clamp /
durationKind (e.g. retune Renew from 9s to 10s base across every
spell that references the HoT5Tick bucket), re-import to a
byte-identical binary. The exporter emits both durationKind (int
0..4) and the human-readable durationKindName ("instant", "timed",
"tick", "until-cancelled", "until-death"); the importer accepts
either, so JSON sidecars stay readable without losing the
canonical binary encoding.
Verified byte-identical round-trip on all three presets
(starter / buffs / dot). CLI flag count 904 -> 906.
Open replacement for SpellDuration.dbc plus per-spell duration
fields in Spell.dbc. Defines the categorical duration buckets
that auras / DoTs / HoTs / buffs reference (5s / 30s / 5min / 1hr
/ UntilCancelled / UntilDeath).
Together with WSRG (range) and WSCT (cast time), this completes a
small triplet of spell-metadata catalogs: instead of every
Frostbolt rank embedding its own range, cast time, and
chill-debuff duration as duplicate fields, each spell holds three
small integer ids that resolve through these three tables. The
engine retunes thousands of spells at once by editing one bucket.
Duration scales with caster level via perLevelMs (a rank-1 Renew
at 9s grows to 12s at lvl 60), then is clamped to maxDurationMs.
Negative baseDurationMs is the canonical sentinel for "no timer"
(UntilCancelled / UntilDeath); resolveAtLevel returns -1 for
those so HUD code can render the indefinite-duration glyph.
Three preset emitters: --gen-sdr (5 baseline tiers from instant
to one-hour), --gen-sdr-buffs (4 long-duration buffs including
UntilDeath), --gen-sdr-dot (4 tick-based DoT/HoT buckets at 3s
ticks). Validation enforces base>0 for Timed/TickBased, base<0
for permanent kinds, max>=base, durationKind 0..4, no duplicate
ids, and warns on Instant+nonzero base.
Wired through the cross-format table; WSDR appears automatically
in all 9 cross-format utilities. Format count 69 -> 70; CLI flag
count 899 -> 904.
Closes the editing loop on the spell-cast-time bucket catalog:
dump a .wsct to JSON, hand-edit baseCastMs / perLevelMs / clamp
bounds (retune a Pyroblast bucket from 3000ms to 2800ms across
every spell that references it), re-import to a byte-identical
binary. The exporter emits both castKind (int 0..4) and the
human-readable castKindName ("instant", "cast", "channel",
"delayed", "charge"); the importer accepts either.
Verified byte-identical round-trip on all three presets
(starter / channel / ramp). CLI flag count 897 -> 899.
Companion to WSRG: open replacement for SpellCastTimes.dbc plus
the per-spell castTime fields in Spell.dbc. Defines categorical
cast-time buckets (Instant 0ms / FastCast 1s / MediumCast 1.5s /
LongCast 3s) that thousands of spells reference instead of each
embedding their own ms count. Together WSRG and WSCT let the
spell engine resolve "Frostbolt's range bucket = id 3" and
"Frostbolt's cast time bucket = id 5" with two table reads
instead of duplicating per-rank data.
Cast time can scale with character level via perLevelMs (a rank-1
spell at 1000ms can grow to 2200ms at lvl 60), then the bucket
result is clamped to [minCastMs, maxCastMs] before haste is
applied. resolveAtLevel() does the math for engine consumers.
Three preset emitters: --gen-sct (4 baseline buckets),
--gen-sct-channel (3 channeled-spell durations), --gen-sct-ramp
(4 level-scaled buckets with non-zero perLevelMs). Validation
catches negative baseCastMs, min>max, duplicate ids, warns on
Instant kind with non-zero base (cast bar would still show), and
errors on Channel kind with zero base (would tick once and end).
Wired through the cross-format table; WSCT appears automatically
in all 9 cross-format utilities. Format count 68 -> 69; CLI flag
count 892 -> 897.
Closes the editing loop on the spell-range bucket catalog: dump a
.wsrg to a JSON sidecar, hand-edit the buckets (rename, retune
yards, recolor HUD indicator), re-import to a byte-identical
binary. The exporter emits both the int rangeKind (0..6) and the
human-readable rangeKindName ("self", "melee", "short", "ranged",
"long", "very-long", "unlimited"); the importer accepts either,
so JSON sidecars stay readable without losing the canonical binary
encoding.
Verified byte-identical round-trip on all three presets (starter,
ranged, friendly). CLI flag count 890 -> 892.
Open replacement for Blizzard's SpellRange.dbc plus the per-spell
range-bucket fields in Spell.dbc. Defines the categorical range
buckets that spells reference instead of carrying their own min/max
yards (every Frostbolt shares one 30y bucket; every Heal shares
one 40y friendly bucket). Each entry carries separate min/max for
hostile vs friendly targets so heals can reach further on allies
than nukes do on enemies, plus an icon color for HUD range
indicators.
Three preset emitters: --gen-srg (3 baseline buckets:
Self/Melee/Spell), --gen-srg-ranged (5 ranged spell buckets:
Short/Medium/Long/VeryLong/Unlimited), --gen-srg-friendly (3
friendly-only buckets where hostile range is 0). --info-wsrg and
--validate-wsrg round out the per-format surface; validation
catches negative ranges, min>max, duplicate ids, out-of-range
rangeKind, and warns on Self+nonzero range or Melee>8y.
Wired through the cross-format table so WSRG appears automatically
in --list-formats, --info-magic, --diff-headers, --summary-dir,
--rename-by-magic, --catalog-grep, --tree-summary-md, and
--touch-tree. Format count 67 -> 68; CLI flag count 885 -> 890.
Compares two .w* files at the standard catalog header level:
4-byte magic, version, catalog name, entry count, total file
bytes. Useful for confirming a JSON round-trip didn't drift,
checking whether two preset emissions produced equivalent
output, or quickly diagnosing when a content snapshot has
silently shifted (entry count up means content was added,
file bytes up but everything else same means entry payloads
got fatter).
Output uses = / ≠ markers per field so visual scanning is
fast. Three diagnostic summary cases: identical headers (and
same bytes — possibly byte-equal, run cmp(1) to confirm),
same shape but bytes differ (entry payloads diverged), and
different formats entirely (files are unrelated).
Returns exit 1 if any field differs, so the flag composes
into shell pipelines (`if diff-headers a.wcms b.wcms; then ...`).
World/asset formats stop after magic since their layouts
diverge from the standard catalog header.
Supports --json variant for tooling integration.
Closes the JSON round-trip gap on the quest sort catalog
format shipped last batch. --export-wqso-json emits all 9
scalar fields plus a dual int + name form for sortKind (12
values) so hand-edits can use either representation.
--import-wqso-json accepts either form. Verified byte-
identical round-trip on all three preset emitters (starter
3-sort generic / 10-class with WCHC bit masks / 8-profession
with WTSK enum cross-refs). 884 documented CLI flags.
67th open format — replaces QuestSort.dbc plus the quest-log
categorization fields in QuestInfo.dbc. Defines the
categories that quests fall into for the quest-log UI:
class quests (Warrior trial, etc), profession quests, daily
quests, holiday events, reputation grinds, dungeon /
heroic / raid quests, repeatables, PvP, tournament.
12 sort kinds (General / ClassQuest / Profession / Daily /
Holiday / Reputation / Dungeon / Raid / Heroic / Repeatable
/ PvP / Tournament). Each WQT (quest) entry can reference
a sortId here to be grouped under the right header in the
quest log. Sorts can be class-restricted (Warrior quests
only show for warriors), profession-restricted, or
faction-reputation-gated.
Cross-references with prior formats — targetClassMask uses
WCHC.classId bit positions (matches WGLY/WSET/WGTP
convention), targetProfessionId points at WTSK.profession
enum, targetFactionId points at WFAC.factionId.
CLI: --gen-qso (3 generic sorts — General catch-all, Daily
reset, Repeatable non-daily), --gen-qso-class (10 class-
specific sorts with proper bit masks for Warrior 0x02
through Druid 0x800), --gen-qso-profession (8 profession
sorts with WTSK profession enum cross-refs), --info-wqso,
--validate-wqso with --json variants. Validator catches
id+name+displayName required, kind 0..11, ClassQuest with
classMask=0 (not actually class-restricted), Profession
with profId=0 + non-Blacksmithing-name (likely typo since
0=Blacksmithing in WTSK), and Reputation with factionId=0
(no faction to grind).
Format graph: 66 → 67 binary formats. CLI flag count: 877
→ 882.
Closes the JSON round-trip gap on the unit movement catalog
format shipped this batch. --export-wumv-json emits all 11
scalar fields plus a dual int + name form for
movementCategory (12 values) so hand-edits can use either
representation. --import-wumv-json defaults baseMultiplier
to 1.0 and maxMultiplier to 1.4 (canonical Sprint cap)
when omitted. Verified byte-identical round-trip on all
three preset emitters (starter / flight / buffs). 877
documented CLI flags.
66th open format — replaces UnitMovement.dbc plus the
movement-modifier portions of CreatureModelData.dbc. Defines
movement speed types (walk / run / swim / flight / fly /
pitch) with their canonical baseline speeds in yards-per-
second, plus the temp speed buffs that stack on top
(Sprint, Aspect of the Cheetah, Travel Form).
12 movement categories cover the canonical surface (Walk /
Run / Backward / Swim / SwimBack / Turn / Flight /
FlightBack / Pitch / Fly / FlyBack / TempBuff). baseSpeed
is yards/second for baseline categories and ignored for
TempBuff entries (which use baseMultiplier instead).
maxMultiplier caps stacking — Sprint capped at 1.4 means
Sprint + Aspect of Cheetah doesn't exceed 1.4× run speed.
stackingPriority resolves conflicts when multiple buffs
of equal multiplier compete (higher wins).
CLI: --gen-umv (4 baseline at canonical WoW vanilla speeds:
Walk 2.5y/s, Run 7.0y/s, Swim 4.7y/s, Turn π rad/s),
--gen-umv-flight (5 flight entries — ground-rail Flight
7y/s, free Fly 14y/s, Pitch 1.5 rad/s, backward variants
at slower 4.5y/s), --gen-umv-buffs (5 temp speed buffs
matching real WoW spell auras with proper durations and
stacking priorities), --info-wumv, --validate-wumv with
--json variants. Validator catches id+name required,
category 0..11, baseMultiplier > 0 (otherwise unit freezes
in place), maxMultiplier >= baseMultiplier (cap below
floor would clamp the base down), baseline categories
need baseSpeed > 0, and Run < 3.0y/s warning (canonical
is 7.0y/s).
Format graph: 65 → 66 binary formats. CLI flag count: 870
→ 875.
Closes the JSON round-trip gap on the combat rating
conversion catalog format shipped last batch.
--export-wcrr-json emits all 10 scalar fields plus a dual
int + name form for ratingKind so hand-edits can use
either representation. --import-wcrr-json defaults
pointsAtL1/L60/L70/L80 to canonical WoW WotLK starter
values when omitted (1 / 14 / 22 / 45) — matches typical
combat rating curves so a sparse sidecar still produces a
working catalog. Verified byte-identical round-trip on all
three preset emitters (starter Hit/Crit/Haste / defensive
Defense+Dodge+Parry+Block / spell SpellPower+Pen+MP5).
870 documented CLI flags.
65th open format — replaces gtCombatRatings.dbc plus the
per-level rating-to-percentage tables in gtRegenHPPerSpt.dbc
and related stat-curve DBCs. Defines per-rating-type
conversion factors at canonical level breakpoints (1 / 60
/ 70 / 80) — the runtime linearly interpolates between
breakpoints for intermediate levels.
pointsAtLevelN is "how many rating points equal 1% of the
benefit at that level." Higher level = more rating needed
for the same %. Standard WoW WotLK example: 14 crit rating
= 1% crit at L60, but 45.91 = 1% at L80.
5 rating kinds (Combat / Defense / Spell / Resilience /
Other) classify what stat resolver category each rating
belongs to.
CLI: --gen-crr (3 essential combat ratings — Hit/Crit/Haste
at canonical WoW WotLK conversion values), --gen-crr-defensive
(4 defensive — Defense/Dodge/Parry/Block with diminishing-
returns soft-cap percentages), --gen-crr-spell (3 spell —
SpellPower direct 1:1, SpellPenetration flat, MP5 mana
regen), --info-wcrr, --validate-wcrr with --json variants.
Validator catches id+name required, kind 0..4, all
pointsAtLN > 0 (otherwise stat resolver would div-by-zero),
maxBenefitPercent > 0 (rating would never grant any
benefit), and non-monotonic conversion curve warning
(rating cost typically ascends with level for non-flat
ratings like SpellPower).
Format graph: 64 → 65 binary formats. CLI flag count: 861
→ 868.
Closes the JSON round-trip gap on the item-suffix catalog
format shipped this batch. --export-wsuf-json emits all 5
scalar fields plus a dual int + name form for suffixCategory
and a nested stats[] array — only populated stat slots are
emitted to keep hand-edits compact. --import-wsuf-json
clears the trailing stat slots before parsing (so a 2-stat
sidecar correctly leaves slots 2-4 zero) and accepts
suffixCategory by either int or name. Verified byte-
identical round-trip on all three preset emitters (starter
2-stat / magical 1-stat / PvP 3-stat). 863 documented CLI
flags.
64th open format — replaces ItemRandomProperties.dbc +
ItemRandomSuffix.dbc plus the AzerothCore-style suffix-roll
tables. Defines random "of the X" suffixes that roll on
green and blue items at world drop ("Sturdy Cloth Cap of
the Bear" = base item + STR + STA suffix).
5 suffix categories (Generic / Elemental / Defensive /
PvPSuffix / Crafted), per-suffix item-quality bracket gating
(only blue+ items can roll PvPSuffix), restricted-slot mask
that limits which equipment slots a suffix can apply to (15
slot bits matching WCEQ slot enum), and up to 5 stat bonus
slots per suffix matching WoW canonical max.
statValuePoints isn't an absolute number — it's a scaling
base that the runtime multiplies by an item-level
coefficient to compute the final per-item bonus, so "of the
Bear" gives proportionally more strength on a level-60 item
than on a level-20 item.
Cross-references with prior formats — statKind values match
WIT.statType enum (STR=4, AGI=3, INT=5, SPI=6, STA=7) so
item generators roll consistent stats with base items.
CLI: --gen-suf (3 generic stat triads — Bear STR+STA, Eagle
INT+SPI, Tiger STR+AGI), --gen-suf-magical (4 elemental
spell-power suffixes restricted to caster-eligible slots),
--gen-suf-pvp (3 PvPSuffix entries with resilience + offensive
stats, blue+ quality only), --info-wsuf, --validate-wsuf with
--json variants. Validator catches id+name required, category
0..4, quality range valid (0..7 covers heirloom), itemQuality
floor<=ceiling, stat-kind/value pairing (kind=0 with value!=0
is a typo, vice versa), and no-stats warning (suffix renames
item without changing it).
Format graph: 63 → 64 binary formats. CLI flag count: 854
→ 861.
Closes the JSON round-trip gap on the loading screen catalog
format shipped last batch. --export-wlds-json emits all 11
scalar fields plus a dual int + name form for
expansionRequired so hand-edits can use either representation.
--import-wlds-json accepts either form, defaulting minLevel
to 1 and maxLevel to 80 when omitted (full level range).
Verified byte-identical round-trip on all three preset
emitters (starter / WotLK instances / raid intros with
isWideAspect=1). 856 documented CLI flags.
63rd open format — replaces LoadingScreens.dbc plus the
per-zone background-image tables. Defines the loading-screen
images shown when the client crosses into a new map /
instance, with optional level-bracket gating and expansion
gating (TBC art only shown if expansion installed).
When multiple screens match the player's current map + level
+ expansion, displayWeight selects randomly between them — a
zone with 3 weighted variants gets a different image roughly
proportional to weight.
4 expansion gates (Classic / TBC / WotLK / TurtleWoW),
isAnimated flag for screens with subtle animation,
isWideAspect flag for 16:9 raid intro art (vs 4:3 standard).
Cross-references with prior formats — mapId points at
WMS.map.mapId (which map triggers this loading screen);
mapId=0 is the catch-all sentinel for screens shown when
no map-specific screen matches.
CLI: --gen-lds (3 base screens — Elwynn level 1-30, Orgrimmar,
GenericFallback level 31-80 catch-all), --gen-lds-instances
(5 WotLK dungeon screens with mapId+expansion cross-refs:
Halls of Lightning/Stone, Utgarde Pinnacle, Violet Hold,
Old Kingdom), --gen-lds-raid (3 raid intro screens —
Naxxramas/Ulduar/ToC at isWideAspect=1 with weight=3),
--info-wlds, --validate-wlds with --json variants. Validator
catches id+name+texture required, expansion 0..3, level range
valid, weight=0 (in pool but never picked), and the practical
catch-all overlap warning when multiple mapId=0 screens share
overlapping level brackets (random pick becomes
non-deterministic).
Format graph: 62 → 63 binary formats. CLI flag count: 847
→ 854.
Closes the JSON round-trip gap on the DK rune cost catalog
format shipped this batch. --export-wrun-json emits all 9
scalar fields plus a dual int + name form for spellTreeBranch
(4 values) so hand-edits can use either representation.
--import-wrun-json accepts either form. Verified byte-
identical round-trip on all three preset emitters (starter
3-cost / blood-tree 4-cost / frost-tree 4-cost).
849 documented CLI flags.
62nd open format — replaces RuneCost.dbc plus the DK-specific
portions of ChrPowerType. Defines per-spell rune costs (Blood
/ Frost / Unholy) and runic-power generation / consumption
for the Death Knight class.
4 spell tree branches (BloodTree / FrostTree / UnholyTree /
Generic) classify which spec uses each rune cost. Each entry
binds a spell to its rune cost (how many of each rune kind
the spell consumes), an optional anyDeathConvertCost (extra
Death-rune-acceptable cost for procced abilities), and a
runicPowerCost (negative = generator, positive = spender).
Cross-references with prior formats — spellId points at
WSPL.spellId (the spell that uses this rune cost).
CLI: --gen-rune (3 baseline DK abilities — Death Strike
1F+1U + 20RP gen, Frost Strike pure 40 RP spender, Heart
Strike 1B + 10RP gen), --gen-rune-blood (4 blood-tree DK
abilities — Heart Strike, Death and Decay AoE, Vampiric
Blood tank cooldown, Rune Tap self-heal), --gen-rune-frost
(4 frost-tree — Frost Strike, Howling Blast AoE, Obliterate
finisher, Icy Touch ranged opener applying Frost Fever),
--info-wrun, --validate-wrun with --json variants. Validator
catches id+name+spellId required, branch 0..3, no rune cost
> 2 (DK only has 2 of each rune type so a higher cost can
never be paid), runicPowerCost > 100 (DK RP cap), no-cost
warning (spell consumes nothing — verify it's a
passive/stance/form), and high-RP-generator warning (> 25
RP per cast is unusual).
Format graph: 61 → 62 binary formats. CLI flag count: 840
→ 847.