Commit graph

33 commits

Author SHA1 Message Date
Kelsi
af214d8b34 feat(pipeline): add WCHN (Wowee Chat Channel) catalog
Novel open replacement for Blizzard's ChatChannels.dbc +
the AzerothCore-style chat_channel SQL tables. The 40th
open format added to the editor.

Defines the world chat channel system: General, Trade,
LookingForGroup, GuildRecruitment, LocalDefense, plus
per-zone area channels and custom user-created channels.
Each channel has access rules (faction / level), join
behavior (auto vs opt-in), broadcast policy (announce /
moderated), and optional area / map gating that auto-joins
or auto-leaves the channel as the player moves.

Cross-references with previously-added formats:
  WCHN.entry.areaIdGate -> WMS.area.areaId
                           (channel auto-attaches in this area)
  WCHN.entry.mapIdGate  -> WMS.map.mapId
                           (channel auto-attaches on this map)

Format:
  • magic "WCHN", version 1, little-endian
  • per channel: channelId / name / description /
    channelType / factionAccess / autoJoin / announce /
    moderated / minLevel / areaIdGate / mapIdGate

Enums:
  • ChannelType (10): AreaLocal / Zone / Continent / World /
                      Trade / LookingForGroup / GuildRecruit /
                      LocalDefense / Custom / Pvp
  • FactionAccess (3): Alliance / Horde / Both

API: WoweeChannelLoader::save / load / exists / findById.

Three preset emitters:
  • makeStarter   — 4 stock channels (General Zone +
                     Trade + LFG + GuildRecruit) with
                     default autoJoin policies
  • makeCity      — 5 city-specific channels (3 Stormwind +
                     2 Orgrimmar) with mapId / areaId gates
                     so they auto-attach on entry
  • makeModerated — 3 moderated / restricted channels
                     (LocalDefense level 10+, WorldDefense
                     moderated, RaidCoordination level 60+)

CLI added (5 flags, 677 documented total now):
  --gen-channels / --gen-channels-city / --gen-channels-moderated
  --info-wchn / --validate-wchn

Validator catches: channelId=0 + duplicates, empty name,
unknown channelType / factionAccess, world / continent
channel with area or map gate (gate is silently ignored at
runtime — usually a typo), minLevel=0 (no level gate at all).
2026-05-09 18:43:26 -07:00
Kelsi
ab72380ee0 feat(pipeline): add WAUC (Wowee Auction House) catalog
Novel open replacement for Blizzard's AuctionHouse.dbc +
the AzerothCore-style auctionhouse / auctionhousebot SQL
tables. The 39th open format added to the editor.

Defines per-house rules for the auction system: faction
access, deposit rate (basis points of buyout price), house
cut on successful sale, three listing duration tiers with
per-tier deposit multipliers, disallowed item-class bitmask,
and the auctioneer NPC.

Cross-references with previously-added formats:
  WAUC.entry.auctioneerNpcId   -> WCRT.entry.creatureId
                                   (Auctioneer-flagged NPC)
  WAUC.entry.disallowedClassMask
                                  bitmask of WIT.Class values
                                  that may not be auctioned at
                                  this house

The faction-pair preset captures the canonical asymmetry:
faction houses charge 5% on a successful sale while neutral
houses charge 15% — the cross-faction tax that makes
neutral AHs profitable for goblins.

Format:
  • magic "WAUC", version 1, little-endian
  • per house: houseId / auctioneerNpcId / name /
    factionAccess / baseDepositRateBp / houseCutRateBp /
    maxBidCopper / 3 duration hours + 3 deposit multipliers /
    disallowedClassMask

Enums:
  • FactionAccess (4): Alliance / Horde / Neutral / Both
  • Rates use basis points: 10000 = 100%

API: WoweeAuctionLoader::save / load / exists / findById.

Three preset emitters showcase typical auction setups:
  • makeStarter        — 1 neutral house with default 12h /
                          24h / 48h tiers
  • makeFactionPair    — 3 houses (Stormwind / Orgrimmar /
                          Booty Bay) with auctioneer NPC IDs
                          + canonical faction-vs-neutral cut
                          rates
  • makeRestricted     — 1 house disallowing Containers (1) +
                          Quest items (12) + Keys (13) with
                          tighter durations + 1000g bid cap

CLI added (5 flags, 670 documented total now):
  --gen-auction / --gen-auction-pair / --gen-auction-restricted
  --info-wauc / --validate-wauc

Validator catches: houseId=0 + duplicates, empty name,
factionAccess out of range, duration tier=0, durations not
in short<=medium<=long order, houseCutRateBp >= 100% (seller
loses money on a sale), warns on >50% cut.
2026-05-09 18:34:54 -07:00
Kelsi
62e793800c feat(pipeline): add WPET (Wowee Pet System) catalog
Novel open replacement for AzerothCore-style pet_template +
pet_levelstats SQL + the pet-related subsets of
CreatureFamily.dbc + SpellFamilyName.dbc. The 38th open
format added to the editor.

Defines two related kinds of player-controlled NPCs in
one catalog:
  • Pet families  — hunter pet families (Wolf / Cat / Bear /
                     Boar / Raptor / Spider / etc.) with
                     per-family ability sets, base stat
                     multipliers, and diet preferences
  • Warlock minions — Imp / Voidwalker / Succubus /
                       Felhunter / Felguard, each with
                       their own summon spell, creature
                       template, and ability list

Cross-references with previously-added formats:
  WPET.family.familyId          -> WCRT.entry.familyId
                                    (matches creature family)
  WPET.family.abilities.spellId -> WSPL.entry.spellId
  WPET.minion.summonSpellId     -> WSPL.entry.spellId
  WPET.minion.creatureId        -> WCRT.entry.creatureId
                                    (used for stat scaling)
  WPET.minion.abilities.spellId -> WSPL.entry.spellId

The starter preset's familyIds (1=Wolf, 2=Cat) match
WCRT::FamilyId enum values, so a hunter taming a wolf via
WCRT links straight through to WPET ability sets.

Format:
  • magic "WPET", version 1, little-endian
  • families[]: familyId / name / description / icon /
    petType / baseAttackSpeed / damageMultiplier /
    armorMultiplier / dietMask / abilities[]
  • minions[]: minionId / name / summonSpellId / creatureId /
    abilities[] (each: spellId / rank / autocastDefault)

Enums:
  • PetType (3): Cunning / Ferocity / Tenacity
                  (WotLK+ talent tree categorization)
  • DietFlags:   Meat / Fish / Bread / Cheese / Fruit / Fungus

API: WoweePetLoader::save / load / exists +
WoweePet::findFamily / findMinion + dietMaskName helper
that decodes a dietMask into a "meat+fish" string.

Three preset emitters showcase typical pet catalogs:
  • makeStarter — 2 hunter families (Wolf + Cat) with full
                   3-ability sets + 1 warlock Imp
  • makeHunter  — 8 classic hunter families covering all
                   3 petType categories with appropriate
                   diet masks
  • makeWarlock — 5 warlock minions each with summon spell
                   ID and creatureId pointing into WCRT

CLI added (5 flags, 663 documented total now):
  --gen-pets / --gen-pets-hunter / --gen-pets-warlock
  --info-wpet / --validate-wpet

Validator catches: ids=0 + duplicates, empty name, petType
out of range, baseAttackSpeed<=0 (would divide by zero in
DPS calc), dietMask=0 (pet cannot be fed for happiness),
minion missing summonSpellId / creatureId.
2026-05-09 18:27:02 -07:00
Kelsi
f290a0d4a9 feat(pipeline): add WPCD (Wowee Player Condition) format
Novel open replacement for Blizzard's PlayerCondition.dbc +
the AzerothCore-style condition_template SQL tables. The
37th open format added to the editor.

Defines reusable boolean conditions that other formats can
reference for gating: "player has quest X completed",
"player level >= N", "player class is mage", "player has
item Y in inventory", "WSEA event Z is active".

Conditions can be grouped and combined with AND/OR
aggregators on a per-group basis: a quest-giver gossip
option that says "show only to level 60 alliance mages
who completed quest 1234" composes 4 conditions sharing
the same groupId with AND aggregation. The runtime walks
each group, applies the group's aggregator, and returns
the boolean result to the caller.

Cross-references with previously-added formats — the
targetId field has a polymorphic interpretation by kind:
  WPCD.targetId (kind=QuestCompleted/Active) -> WQT.questId
  WPCD.targetId (kind=HasItem)               -> WIT.itemId
  WPCD.targetId (kind=HasSpell)              -> WSPL.spellId
  WPCD.targetId (kind=HasAchievement)        -> WACH.achievementId
  WPCD.targetId (kind=AreaId)                -> WMS.areaId
  WPCD.targetId (kind=EventActive)           -> WSEA.eventId
  WPCD.targetId (kind=HasTitle)              -> WTIT.titleId
  WPCD.targetId (kind=FactionRep)            -> WFAC.factionId
  WPCD.targetId (kind=Class/Race)            -> WCHC class/race id

Future format extensions can reference WPCD.conditionId in
their own gating fields — WTRG triggers gated by player
state, WGSP options visible only when conditions are met,
WMOU summon spells condition-gated by quest progress, etc.

Format:
  • magic "WPCD", version 1, little-endian
  • per condition: conditionId / groupId (0 = standalone) /
    name / description / kind / aggregator / negated /
    targetId / minValue / maxValue

Enums:
  • Kind (17): AlwaysTrue / AlwaysFalse / QuestCompleted /
                QuestActive / HasItem / HasSpell / MinLevel /
                MaxLevel / ClassMatch / RaceMatch /
                FactionRep / HasAchievement / TeamSize /
                GuildLevel / EventActive / AreaId / HasTitle
  • Aggregator (2): And / Or

API: WoweeConditionLoader::save / load / exists / findById.

Three preset emitters showcase typical usage:
  • makeStarter — 4 standalone conditions covering the most
                   common kinds (quest-done / has-item /
                   min-level / class)
  • makeGated   — 5 conditions in 2 groups demonstrating
                   AND-aggregation (alliance + mage + lvl 60)
                   and OR-aggregation (did quest 1 OR quest 100)
  • makeEvent   — 3 event-gated conditions cross-referencing
                   WSEA event IDs (Hallow's End / Brewfest /
                   Winter's Veil)

CLI added (5 flags, 656 documented total now):
  --gen-conditions / --gen-conditions-gated / --gen-conditions-event
  --info-wpcd / --validate-wpcd

Validator catches: conditionId=0 + duplicates, kind /
aggregator out of range, kinds requiring targetId having
target=0 (skips AlwaysTrue/False, MinLevel/MaxLevel,
TeamSize, GuildLevel which use min/max instead), TeamSize
with min > max.
2026-05-09 18:18:27 -07:00
Kelsi
80ebf1dba5 feat(pipeline): add WGLD (Wowee Guild) catalog format
Novel open replacement for AzerothCore-style guild +
guild_member + guild_rank + guild_bank_tab + guild_perk
SQL tables. The 36th open format added to the editor.

Each guild entry holds the complete social-organization
state: header (name, leader, faction, MOTD, info,
creation date, level + experience, bank money, packed
emblem), rank ladder with permissions bitmask + daily
withdraw caps, member roster with rank + join date +
public/officer notes, bank tabs with per-tab and per-rank
deposit / withdraw / view permission masks, and purchased
guild perks referencing WSPL spell IDs.

Cross-references with previously-added formats:
  WGLD.entry.factionId       ~  WCHC.race.factionId
                                 (guilds are faction-locked)
  WGLD.entry.perks.spellId  -> WSPL.entry.spellId

Format:
  • magic "WGLD", version 1, little-endian
  • per guild: header (12 scalar fields + 4 strings) +
    ranks[] + members[] + bankTabs[] + perks[]
  • per rank: rankIndex / name / permissionsMask /
    moneyPerDayCopper
  • per member: characterName / rankIndex / joinedDate /
    publicNote / officerNote
  • per bankTab: tabIndex / name / iconPath /
    deposit+withdraw+view permission masks
  • per perk: perkId / name / spellId / requiredGuildLevel

Enums:
  • Faction (2): Alliance / Horde
  • RankPermissionFlags (14): GuildChat / OfficerChat /
                               Invite / Remove / Promote /
                               Demote / SetMotd /
                               EditPublicNote /
                               EditOfficerNote / ViewBank /
                               Deposit / Withdraw / Disband /
                               RepairFromBank

API: WoweeGuildLoader::save / load / exists / findById +
shared addDefaultRanks helper used by both starter and
faction-pair presets.

Three preset emitters:
  • makeStarter     — 1 small guild, default 5-rank ladder
                       (GM/Officer/Veteran/Member/Initiate),
                       3 members borrowing names from WCRT
                       merchants for cross-format consistency
  • makeFull        — 1 fleshed-out guild: 6 ranks (with
                       Recruit added) + 8 members + 4 bank
                       tabs (officer-only withdraw on tabs
                       3+4) + 3 perks referencing WSPL
                       spell IDs (Heroic Strike / Battle
                       Shout / Thunder Clap as placeholder
                       perk procs)
  • makeFactionPair — 2 parallel guilds, one Alliance + one
                       Horde, with identical rank structures

CLI added (5 flags, 649 documented total now):
  --gen-guilds / --gen-guilds-full / --gen-guilds-pair
  --info-wgld / --validate-wgld

Validator catches: guildId=0 + duplicates, empty name /
leaderName, factionId out of range, no ranks (members can't
exist without a rank ladder), member.rankIndex exceeding
the highest defined rank (intra-format cross-reference
resolution), duplicate bank tabIndices, perks with
spellId=0 (perk does nothing).
2026-05-09 18:10:45 -07:00
Kelsi
a50d83f6c9 feat(pipeline): add WGEM (Wowee Gem / Enchantment) format
Novel open replacement for Blizzard's ItemEnchantment.dbc +
GemProperties.dbc + SpellItemEnchantment.dbc. The 35th
open format added to the editor.

Defines two related kinds of item enhancement in one
catalog:
  • Gems         — socketable jewelry pieces with color
                    (red / blue / yellow / meta) that fit
                    into gear sockets, granting stats or
                    triggering passive spells when socketed
  • Enchantments — persistent buffs applied to weapon /
                    armor pieces, either by an enchanter
                    spell or by an item proc (Mongoose,
                    Crusader, Berserking)

Cross-references with previously-added formats:
  WGEM.gem.itemIdToInsert  -> WIT.entry.itemId
  WGEM.gem.spellId         -> WSPL.entry.spellId
  WGEM.enchantment.spellId -> WSPL.entry.spellId

Format:
  • magic "WGEM", version 1, little-endian
  • gems[]: gemId / itemIdToInsert / name / color /
    statType + statValue / requiredItemQuality / spellId
  • enchantments[]: enchantId / name / description /
    iconPath / enchantSlot / statType + statValue /
    spellId / durationSeconds / chargeCount

Enums:
  • Color (8):       Meta / Red / Yellow / Blue / Purple /
                      Green / Orange / Prismatic
  • EnchantSlot (5): Permanent / Temporary / SocketColor /
                      Ring / Cloak

API: WoweeGemLoader::save / load / exists +
WoweeGem::findGem / findEnchant.

Three preset emitters showcase common shapes:
  • makeStarter  — 3 gems (one per primary color) +
                    2 enchantments (proc + stat)
  • makeGemSet   — 6-gem full color palette covering
                    primary + secondary combinations
  • makeEnchants — 5 enchant variants spanning slots
                    (Mongoose / Deadly Poison / stats ring /
                    cloak / Berserking)

CLI added (5 flags, 642 documented total now):
  --gen-gems / --gen-gems-set / --gen-gems-enchants
  --info-wgem / --validate-wgem

Validator catches: ids=0 + duplicates, empty name, color /
slot out of range, stat-only entries with statValue=0 (gem
provides nothing), chargeCount > 0 on non-Temporary
enchant slots (charges silently ignored at runtime).

The validator caught a real preset issue on first run —
the proc enchants (Mongoose / Deadly Poison / Berserking)
had spellId=0 and statValue=0, providing nothing. Fixed by
adding placeholder spellIds in the 28000-29000 range, with
a comment noting they resolve to real WSPL proc spells
when the spell catalog is extended.
2026-05-09 18:01:48 -07:00
Kelsi
492d626c3b feat(pipeline): add WMAL (Wowee Mail Template) format
Novel open replacement for AzerothCore-style
mail_loot_template SQL + the in-game mail subset of the
inventory + currency systems. The 34th open format added
to the editor.

Defines templated mail messages with currency + item
attachments. Triggered by quest reward delivery (overflow
when bag is full), auction house bid wins / sales,
achievement reward attachments, GM correspondence, holiday
event mailings (Brewfest samples, Hallow's End candy), and
returned-mail-on-rejection.

Cross-references with previously-added formats:
  WMAL.entry.senderNpcId        -> WCRT.entry.creatureId
  WMAL.entry.attachments.itemId -> WIT.entry.itemId

Format:
  • magic "WMAL", version 1, little-endian
  • per template: templateId / senderNpcId / subject / body /
    senderName / moneyCopperAttached / categoryId / cod /
    returnable / expiryDays / attachments[] (each: itemId +
    quantity)

Enums:
  • Category (8): QuestReward / Auction / GmCorrespondence /
                   AchievementReward / EventMailing / Raffle /
                   ScriptDelivery / ReturnedMail

API: WoweeMailLoader::save / load / exists / findById.

Three preset emitters showcase typical mail templates:
  • makeStarter — 3 templates (quest overflow / auction won /
                   GM gift) covering the 3 most common
                   categories
  • makeHoliday — 4 holiday samples that cross-reference the
                   WTKN seasonal token IDs (200=Tricky Treats,
                   201=Brewfest, 202=Coin of Ancestry,
                   203=Stranger's Gift) so the demo content
                   stack ships a full holiday onboarding
                   experience
  • makeAuction — 5-template auction-house family (outbid /
                   won / sold / expired / cancelled) — runtime
                   fills in actual bid amounts / sold items
                   at send time

CLI added (5 flags, 635 documented total now):
  --gen-mail / --gen-mail-holiday / --gen-mail-auction
  --info-wmal / --validate-wmal

Validator catches: templateId=0 + duplicates, empty subject,
neither senderNpcId nor senderName set (no displayable
sender), unknown category, expiryDays=0 (mail expires
immediately), cod=1 with no money attached (free COD),
empty mail in categories where the runtime doesn't fill in
content (skips Auction / GmCorrespondence / ReturnedMail
where empty templates are intentional).

Two bugs caught + fixed during smoke-test on the auction
preset:
  • print formatting glued the `0` from senderNpcId after
    the senderName when no NPC was set (rendered as
    "Postmaster0" instead of "Postmaster") — fixed with an
    explicit if/else split
  • validator's "no money + no items" warning was too
    aggressive for the Auction category, where templates
    are intentionally informational and the runtime fills
    in the real values — added Auction + ReturnedMail to
    the skip list
2026-05-09 17:41:03 -07:00
Kelsi
1b385fb39c feat(pipeline): add WBGD (Wowee Battleground Definition) format
Novel open replacement for Blizzard's BattlemasterList.dbc +
PvpDifficulty.dbc + the AzerothCore-style
battleground_template SQL tables. The 33rd open format
added to the editor.

Defines per-BG gameplay rules: player count brackets,
score-to-win, time limit, objective type (annihilation /
capture flag / control nodes / king of hill / resource race
/ carry object), per-team start positions, respawn timer,
and the WTKN currency token awarded on win.

Cross-references with previously-added formats:
  WBGD.entry.mapId       -> WMS.map.mapId
                            (where mapType=Battleground)
  WBGD.entry.markTokenId -> WTKN.entry.tokenId
                            (Mark of Honor for that BG)

The classic preset's markTokenId fields (102/103/104)
deliberately match WTKN.makePvp's "Mark of Honor: Warsong
Gulch / Arathi Basin / Alterac Valley" token ids — so the
demo content stack already wires together: WBGD.scoreToWin
reached → grant WTKN mark → which a vendor in WTRN can
charge in via item.extendedCost.

Format:
  • magic "WBGD", version 1, little-endian
  • per BG: battlegroundId / mapId / name / description /
    objectiveKind / min+maxPlayersPerSide /
    minLevel..maxLevel / scoreToWin / timeLimitSeconds /
    bracketSize / allianceStart vec3 + facing /
    hordeStart vec3 + facing / respawnTimeSeconds /
    markTokenId

Enums:
  • ObjectiveKind (6): Annihilation / CaptureFlag /
                       ControlNodes / KingOfHill /
                       ResourceRace / CarryObject

API: WoweeBattlegroundLoader::save / load / exists /
findById.

Three preset emitters showcase typical BG shapes:
  • makeStarter — 1 king-of-hill BG (10v10, 3-cap to win)
  • makeClassic — 3 classic BGs with authentic player
                   counts, level brackets, scoring, and
                   WTKN cross-refs (Warsong Gulch CTF /
                   Arathi Basin nodes / Alterac Valley
                   resource race)
  • makeArena   — 3 arena formats (Nagrand 2v2 / Blade's
                   Edge 3v3 / Lordaeron 5v5) — annihilation
                   objective + no respawn + 25 min cap

CLI added (5 flags, 628 documented total now):
  --gen-bg / --gen-bg-classic / --gen-bg-arena
  --info-wbgd / --validate-wbgd

Validator catches: bgId=0 + duplicates, empty name, unknown
objectiveKind, player count=0, min>max counts/levels,
scoreToWin=0 (no win condition), non-annihilation BG with
respawnTimeSeconds=0 (losing side cannot recover).
2026-05-09 17:30:59 -07:00
Kelsi
8ab049ff9d feat(pipeline): add WMOU (Wowee Mount catalog) format
Novel open replacement for Blizzard's Mount.dbc +
MountCapability.dbc + MountType.dbc + the mount-related
subsets of Spell.dbc / Item.dbc. The 32nd open format added
to the editor.

Defines all summonable steeds: ground mounts, flying mounts,
swimming mounts, racial mounts (Tauren Plainsrunner for
druids), and class mounts (Warlock dreadsteed, Paladin
charger). Each mount has a summon spell, optional teach
item, riding skill prerequisite, speed bonus, and faction
/ race availability mask.

Cross-references with previously-added formats:
  WMOU.entry.summonSpellId   -> WSPL.entry.spellId
  WMOU.entry.itemIdToLearn   -> WIT.entry.itemId
  WMOU.entry.requiredSkillId -> WSKL.entry.skillId
                                 (Riding skill ID 762)
  WCHC.race.mountSpellId     ~= WMOU.entry.summonSpellId
                                 (loose match by spellId)

Format:
  • magic "WMOU", version 1, little-endian
  • per mount: mountId / name / description / icon /
    displayId / summonSpellId / itemIdToLearn /
    requiredSkillId+Rank / speedPercent / mountKind /
    factionId / categoryId / raceMask

Enums:
  • Kind (5):     Ground / Flying / Swimming / Hybrid /
                   Aquatic
  • Faction (3):  Both / Alliance / Horde
  • Category (8): Common / Epic / Racial / Event /
                   Achievement / Pvp / Quest / ClassMount

API: WoweeMountLoader::save / load / exists / findById.

Three preset emitters showcase typical mount catalogs:
  • makeStarter — 3 mounts (ground horse + epic flying
                   gryphon + aquatic riding turtle)
  • makeRacial  — 6 racial mounts (4 Alliance: Pinto / Ram /
                   Frostsaber / Mechanostrider; 2 Horde:
                   Dire Wolf / Skeletal Horse) with raceMask
                   gating per WCHC race bit positions
  • makeFlying  — 4 flying mounts spanning Common (60%) ->
                   Epic (100%) -> Achievement (280%) -> Pvp
                   (310%) speed tiers

CLI added (5 flags, 621 documented total now):
  --gen-mounts / --gen-mounts-racial / --gen-mounts-flying
  --info-wmou / --validate-wmou

Validator catches: mountId=0 + duplicates, empty name,
summonSpellId=0 (mount cannot be cast), unknown enum values,
speedPercent=0 (no speed bonus), flying mount with
requiredSkillRank<150 (player can't fly), Racial category
without raceMask (any race could use — usually a typo).
2026-05-09 17:23:00 -07:00
Kelsi
ff4159c369 feat(pipeline): add WSEA (Wowee Seasonal Event) format
Novel open replacement for Blizzard's GameEvents.dbc + the
AzerothCore-style game_event / game_event_creature /
game_event_gameobject SQL tables. The 31st open format
added to the editor.

Calendar-based content: holidays (Hallow's End, Winter's
Veil), recurring promotional events (Children's Week,
Lunar Festival, Brewfest), one-time anniversaries, and
XP-bonus weekends. Each event has a start date, duration,
optional recurrence (yearly / monthly / weekly), faction
restriction, optional XP bonus, and a reward currency
cross-reference into WTKN.

Cross-references with previously-added formats:
  WSEA.entry.tokenIdReward -> WTKN.entry.tokenId
                              (the seasonal currency the
                               event hands out — Tricky
                               Treats during Hallow's End,
                               Brewfest Tokens during
                               Brewfest, etc.)

The yearly preset's tokenIdReward values (200/201/202/203)
deliberately match WTKN.makeSeasonal's seasonal token ids
so the demo content stack already wires together: WSEA
yearly events grant WTKN tokens that vendors can charge in
via WTRN.item.extendedCost.

Format:
  • magic "WSEA", version 1, little-endian
  • per event: eventId / name / description / iconPath /
    announceMessage / startDate (Unix epoch seconds) /
    duration_seconds / recurrenceDays (0=one-shot, 365=yearly) /
    holidayKind / factionGroup / bonusXpPercent / tokenIdReward

Enums:
  • HolidayKind (7): Combat / Collection / Racial /
                     Anniversary / Fishing / Cosmetic /
                     WorldEvent
  • FactionGroup (3): Both / Alliance / Horde

API: WoweeEventLoader::save / load / exists / findById.

Three preset emitters showcase typical event shapes:
  • makeStarter       — 3 events covering Combat /
                         Fishing / Anniversary kinds
  • makeYearly        — 4 yearly holidays with full WTKN
                         cross-refs (Hallow's End / Brewfest /
                         Lunar Festival / Winter's Veil)
  • makeBonusWeekends — 3 monthly Fri-Sun bonus tiers
                         (50% / 100% / 200% RAF-style)

CLI added (5 flags, 614 documented total now):
  --gen-events / --gen-events-yearly / --gen-events-weekends
  --info-wsea / --validate-wsea

Validator catches: eventId=0 + duplicates, empty name,
unknown holidayKind / factionGroup, duration_seconds=0
(event never runs), duration > recurrence period (events
would overlap themselves on next iteration), bonusXpPercent
> 200 (very high — verify intentional).
2026-05-09 17:14:46 -07:00
Kelsi
eefaa5653b feat(pipeline): add WTIT (Wowee Title catalog) format
Novel open replacement for Blizzard's CharTitles.dbc + the
AzerothCore-style character_title SQL table. The 30th open
format added to the editor.

Defines the player-display titles awarded for completing
achievements ("the Versatile"), reaching PvP ranks
("Sergeant Major" / "Stone Guard"), participating in raids
("Champion of the Naaru"), levelling a profession ("Master
Locksmith"), or seasonal events ("Brewmaster", "the
Hallowed").

Closes a long-standing gap: WACH.entry.titleReward has been
a free-form string since batch 116 with no formal catalog
to resolve against. WTIT systematizes those strings into a
real catalog — the runtime resolves WACH.titleReward to a
WTIT entry by name, then displays the titleId in the player
title selector.

Cross-references:
  WACH.entry.titleReward (string) ~= WTIT.entry.name
                                     (string match — runtime
                                      resolves achievement-
                                      granted titles by
                                      looking up matching WTIT
                                      entry by name)

Format:
  • magic "WTIT", version 1, little-endian
  • per title: titleId / name / nameMale / nameFemale /
    iconPath / prefix (suffix vs prefix display) /
    category / sortOrder

Enums:
  • Category (8): Achievement / Pvp / Raid / ClassTitle /
                   Event / Profession / Lore / Custom

API: WoweeTitleLoader::save / load / exists +
WoweeTitle::findById / findByName.

Three preset emitters showcase typical title catalogs:
  • makeStarter     — 4 titles (Versatile / Sergeant /
                       Champion / Hallowed) covering 4
                       categories
  • makePvp         — 28-title classic Honor System ladder
                       (14 Alliance ranks Private->Grand
                       Marshal + 14 Horde ranks Scout->High
                       Warlord)
  • makeAchievement — 8 achievement titles including "the
                       Versatile" matching WACH.makeMeta's
                       achievement 250 titleReward + capstone
                       profession titles

CLI added (5 flags, 608 documented total now):
  --gen-titles / --gen-titles-pvp / --gen-titles-achievement
  --info-wtit / --validate-wtit

Validator catches: titleId=0 + duplicates, empty name,
unknown category, gender variants set on only one side
(causes mixed-gender display when the runtime falls back to
canonical for the unset side).
2026-05-09 17:07:56 -07:00
Kelsi
8c78f8aeb2 feat(pipeline): add WTRG (Wowee Area Trigger) format
Novel open replacement for Blizzard's AreaTrigger.dbc +
AreaTriggerTeleport.dbc + the AzerothCore-style
areatrigger_template / areatrigger_teleport SQL tables.
The 29th open format added to the editor.

Defines proximity-based event zones — when a player enters
a defined region (box or sphere), the runtime fires the
trigger's action: teleport to another map, award
exploration XP for a quest, run a server script, gate an
instance entrance behind a key item, mark a PvP boundary,
or simply display a "Discovered: {area name}" banner.

Cross-references with previously-added formats — every
trigger field has a real format target:
  WTRG.entry.mapId / areaId  -> WMS.map.mapId / WMS.area.areaId
  WTRG.actionTarget (Teleport)        -> WMS.mapId
  WTRG.actionTarget (QuestExploration) -> WQT.questId
  WTRG.requiredQuestId       -> WQT.entry.questId
  WTRG.requiredItemId        -> WIT.entry.itemId (key)

Format:
  • magic "WTRG", version 1, little-endian
  • per trigger: triggerId / mapId / areaId / name /
    center vec3 / shape / kind / boxDims vec3 / radius /
    actionTarget / dest vec3 / destOrientation /
    requiredQuestId / requiredItemId / minLevel

Enums:
  • Shape (2): Box / Sphere
  • Kind (7): Teleport / QuestExploration / Script /
              InstanceEntrance / AreaName / CombatStartZone /
              Waypoint

API: WoweeTriggerLoader::save / load / exists / findById.

Three preset emitters showcase common trigger shapes:
  • makeStarter    — area-name + quest-exploration with
                      cross-ref to WQT 100 ("Investigate the
                      Camp")
  • makeDungeon    — outdoor area-name + portal-style
                      InstanceEntrance with Deadmines key
                      gate (WIT itemId 5200, matches
                      WLCK.makeDungeon's Boss Vault Seal) +
                      interior exit teleport back outdoors
  • makeFlightPath — 2 sphere waypoints near flight masters
                      so the runtime can auto-open the
                      flight UI on proximity (matches WTAX
                      starter node positions)

CLI added (5 flags, 601 documented total now):
  --gen-triggers / --gen-triggers-dungeon / --gen-triggers-flightpath
  --info-wtrg / --validate-wtrg

Validator catches: triggerId=0 + duplicates, unknown shape /
kind, non-finite center, sphere with radius<=0, box with
all-zero half-extents, teleport / instance with dest=(0,0,0)
(silently does nothing — usually a typo), QuestExploration
without an actionTarget questId.
2026-05-09 17:01:43 -07:00
Kelsi
b632554b5b feat(pipeline): add WTKN (Wowee Token catalog) format
Novel open replacement for Blizzard's Currency.dbc +
CurrencyCategory.dbc + CurrencyTypes.dbc + the AzerothCore-
style player_currency SQL tables. The 28th open format
added to the editor.

Defines secondary currency tokens beyond gold: Honor Points
(PvP), Arena Points (rated PvP), Marks of Honor (per
battleground), faction reputation tokens, holiday-event
currencies. Each token has a balance cap, optional weekly
cap (regenerating earnings limit), and a category for
grouping in the player's currency tab.

Cross-references:
  WTRN.item.extendedCost -> WTKN.entry.tokenId
                             (vendors can charge in tokens
                              instead of copper — when
                              extendedCost > 0 the runtime
                              looks up the matching token)

Format:
  • magic "WTKN", version 1, little-endian
  • per token: tokenId / name / description / iconPath /
    category / maxBalance / weeklyCap / flags

Enums:
  • Category (6): Misc / Pvp / Reputation / Crafting /
                   Seasonal / Holiday
  • Flags:        AccountWide / Tradeable / HiddenUntilEarned /
                   ResetsOnLogout / ConvertsToGold

API: WoweeTokenLoader::save / load / exists / findById.

Three preset emitters showcase typical token shapes:
  • makeStarter  — 3 tokens (Honor / Marks / Stormwind Guard
                    rep) covering Pvp + Reputation categories
  • makePvp      — full PvP set: Honor (75k) + Arena (5k +
                    weekly 1500) + 6 BG marks of honor for
                    classic + TBC + WotLK battlegrounds
  • makeSeasonal — 4 holiday tokens (Tricky Treats /
                    Brewfest / Coin of Ancestry / Stranger's
                    Gift) all flagged ResetsOnLogout to make
                    them event-bound

CLI added (5 flags, 592 documented total now):
  --gen-tokens / --gen-tokens-pvp / --gen-tokens-seasonal
  --info-wtkn / --validate-wtkn

Validator catches: tokenId=0 + duplicates, empty name,
unknown category, weeklyCap > maxBalance (cap unreachable),
ResetsOnLogout + AccountWide combo (incoherent — account
state survives logout by definition).
2026-05-09 16:53:11 -07:00
Kelsi
e66601c208 feat(pipeline): add WCHC (Wowee Character Classes/Races) format
Novel open replacement for Blizzard's CharClasses.dbc +
CharRaces.dbc + CharStartOutfit.dbc trio. The 27th open
format added to the editor — completes the foundational
character-creation surface.

One file holds three flat arrays:
  • classes — playable classes (Warrior / Mage / etc.) with
              power type (mana/rage/focus/energy/runic),
              base HP+power scaling, faction availability
  • races   — playable races with faction (Alliance/Horde/
              Neutral), starting map+zone, default language
              spell, base stats, racial mount spell
  • outfits — starting gear loadout per (class, race, gender)
              triple, listing item IDs and display slots

Cross-references with previously-added formats:
  WCHC.race.startingMapId        -> WMS.map.mapId
  WCHC.race.startingZoneAreaId   -> WMS.area.areaId
  WCHC.race.defaultLanguageSpellId -> WSPL.entry.spellId
  WCHC.race.mountSpellId         -> WSPL.entry.spellId
  WCHC.outfit.items.itemId       -> WIT.entry.itemId

The starter preset's outfits use real WIT itemIds (1=Worn
Shortsword, 2=Linen Vest, 3=Healing Potion) so the demo
content stack is consistent: a freshly created Human Warrior
in WCHC starts with WIT items 1/2/3, drops them on death
into a WLOT-tracked corpse loot, and can be respawned via
WSPN, etc.

Format:
  • magic "WCHC", version 1, little-endian
  • classes[]: classId / name / icon / powerType / display /
    baseHP+perLevel / basePower+perLevel / factionAvailability
  • races[]: raceId / name / icon / factionId / male+female
    displayId / 5 base stats / startingMap+zone /
    defaultLanguage+mount spell IDs
  • outfits[]: classId+raceId+gender + items[]
    (each: itemId + displaySlot)

Enums:
  • PowerType (6): Mana / Rage / Focus / Energy / RunicPower / Runes
  • RaceFaction (3): Alliance / Horde / Neutral
  • Gender: Male / Female
  • FactionAvailability bitmask: AvailableAlliance, AvailableHorde

API: WoweeCharsLoader::save / load / exists +
WoweeChars::findClass / findRace / findOutfit (by class+race+gender).

CLI added (5 flags, 585 documented total now):
  --gen-chars / --gen-chars-alliance / --gen-chars-allraces
  --info-wchc / --validate-wchc

Validator catches: ids unique, baseHealth=0 (instant-death
character), factionAvailability=0 (no faction can pick),
empty names, factionId out of range, outfit references to
non-existent class/race ids (cross-format resolution),
gender > 1, outfit items with itemId=0, outfit with no
items (warning — naked character).
2026-05-09 16:47:04 -07:00
Kelsi
82a8c3559e feat(pipeline): add WMS (Wowee Map / Area) catalog format
Novel open replacement for Blizzard's Map.dbc + AreaTable.dbc
+ the AzerothCore-style world_zone SQL tables. The 26th open
format added to the editor.

Defines two related kinds of locator in one catalog:
  • Maps  — top-level worlds (continents / instances / raids /
            battlegrounds / arenas) with a friendly name,
            type, expansion tag, and player-count cap.
  • Areas — sub-zones within maps with friendly names, parent-
            area chain, recommended level range, faction-
            territory marker (alliance / horde / contested /
            both), exploration XP, and an ambient-sound
            cross-reference into WSND.

The runtime uses Areas for minimap labels, location strings
under the player frame, "Discover Sub-zone" XP gains, and
ambient-music selection on zone entry.

Cross-references with previously-added formats:
  WMS.area.ambienceSoundId    -> WSND.entry.soundId
  WMS.area.parentAreaId       -> WMS.area.areaId (intra-format
                                   sub-zone hierarchy)
  WSPN entries are tied to WMS.area boundaries by
  world position (no direct ID — the runtime resolves
  position -> area at lookup time)

Format:
  • magic "WMSX", version 1, little-endian
  • maps[] (each): mapId / name / shortName / mapType /
    expansionId / maxPlayers
  • areas[] (each): areaId / mapId / parentAreaId / name /
    minLevel..maxLevel / factionGroup / explorationXP /
    ambienceSoundId

Enums:
  • MapType (5):     Continent / Instance / Raid / Battleground / Arena
  • ExpansionId (5): Classic / Tbc / Wotlk / Cata / Mop
  • FactionGroup:    Both / Alliance / Horde / Contested
                      (PvP-flagging zone)

API: WoweeMapsLoader::save / load / exists +
WoweeMaps::findMap / findArea.

Three preset emitters showcase the catalog shape:
  • makeStarter — 1 continent + 3 areas with parent chain
                   (Goldshire is a sub-zone of Elwynn Forest)
  • makeClassic — 2 continents + Deadmines instance + 6
                   areas (Stormwind/Elwynn/Goldshire/Westfall/
                   Duskwood/Teldrassil/Deadmines) with WSND
                   ambient-sound refs
  • makeBgArena — Alterac Valley (40-player BG) + Nagrand
                   Arena (5v5 with maxPlayers=10)

CLI added (5 flags, 578 documented total now):
  --gen-maps / --gen-maps-classic / --gen-maps-bgarena
  --info-wms / --validate-wms

Validator catches: empty map name, unknown mapType / expansion,
BG/Arena with maxPlayers=0 (no participant cap), area ids=0
+ duplicates, empty area name, maxLevel < minLevel, areas
referencing non-existent maps, parentAreaId chains crossing
maps (sub-zones must be on the same world), self-parent.
2026-05-09 16:40:00 -07:00
Kelsi
99baf2d0c4 feat(pipeline): add WTAL (Wowee Talent catalog) format
Novel open replacement for Blizzard's TalentTab.dbc +
Talent.dbc + the AzerothCore-style talent_progression SQL
tables. The 25th open format added to the editor.

Defines class talent specialization trees: per-class set
of named tabs (Arms / Fury / Protection for warrior, Fire
/ Frost / Arcane for mage), each with talents arranged in
a row/column grid, each talent having up to 5 ranks and
an optional prerequisite chain.

Cross-references with previously-added formats:
  WTAL.talent.prereqTalentId -> WTAL.talent.talentId
                                 (intra-format chain)
  WTAL.talent.rankSpellIds[] -> WSPL.entry.spellId
                                 (spell granted at each rank)

Format:
  • magic "WTAL", version 1, little-endian
  • per tree: treeId / name / iconPath / requiredClassMask /
    talents[] (row, col, maxRank, prereqTalentId+rank,
    rankSpellIds[5] zero-padded for unused ranks)

Enums:
  • ClassMask: bit positions match canonical CharClasses.dbc
    classIds — Warrior / Paladin / Hunter / Rogue / Priest /
    DK / Shaman / Mage / Warlock / Druid

API: WoweeTalentLoader::save / load / exists +
WoweeTalent::findTree / findTalent (global lookup across
all trees in the catalog).

Three preset emitters showcase tree shapes:
  • makeStarter — 1 small tree (3-talent vertical chain)
  • makeWarrior — 3 trees (Arms 4 / Fury 4 / Protection 3)
                   with WSPL cross-refs at capstones
                   (Mortal Strike -> WSPL 12294, Battle Shout
                   -> WSPL 6673, Thunder Clap -> WSPL 6343)
  • makeMage    — 3 trees (Arcane / Fire / Frost) with
                   capstones referencing Frostbolt 116 /
                   Fireball 133 / Blink 1953 from WSPL

CLI added (5 flags, 571 documented total now):
  --gen-talents / --gen-talents-warrior / --gen-talents-mage
  --info-wtal / --validate-wtal

Validator catches: tree+talent ids=0 or duplicates, empty
tree name, requiredClassMask=0 (every class would see this
tree — usually a typo), maxRank not in 1..5, talent listing
itself as prerequisite, prereqTalentId pointing at a
talent that doesn't exist in this catalog (intra-format
cross-reference resolution), prereqRank=0 or > the prereq
talent's maxRank (catches off-by-one references), gaps in
rankSpellIds progression (rank N has spell but rank N-1
doesn't — usually a typo).

The validator caught a real authoring bug in the makeMage /
makeWarrior presets during smoke testing — initial check
was comparing prereqRank against the WRONG talent's maxRank
(this talent's rather than the prereq's). Fixed in the same
commit by hoisting the check into the cross-reference
resolution pass where the prereq talent is in hand.
2026-05-09 16:33:45 -07:00
Kelsi
3b107459b2 feat(pipeline): add WTAX (Wowee Taxi catalog) format
Novel open replacement for Blizzard's TaxiNodes.dbc +
TaxiPath.dbc + TaxiPathNode.dbc. The 24th open format
added to the editor.

Defines the flight-master network: a set of named nodes
(positions on the world map) plus the paths between them
(sequences of waypoints with per-segment delay and a
per-path gold cost). The same file holds both node and
path lists — flat arrays keyed by id, with intra-format
references from path.fromNodeId / toNodeId to node.nodeId.

Cross-references:
  WCRT.entry (with FlightMaster npcFlag) ~= WTAX.nodeId
                                            (matched by world
                                             position; flight
                                             master NPCs stand
                                             at their nodes)
  WTAX.path.fromNodeId / toNodeId -> WTAX.entry.nodeId
                                     (intra-format graph)

Format:
  • magic "WTAX", version 1, little-endian
  • nodes (each): nodeId / mapId / name / iconPath /
    position / faction restrictions
  • paths (each): pathId / from+toNodeId / moneyCostCopper /
    waypoints[] each with position + per-waypoint delaySec

API: WoweeTaxiLoader::save / load / exists +
WoweeTaxi::findNode / findPath / findPathBetween.

Three preset emitters showcase different graph shapes:
  • makeStarter  — 2 nodes + 2 paths (round-trip)
  • makeRegion   — 4 nodes at a 500m square + 4-path
                    directed ring (NW->NE->SE->SW->NW)
  • makeContinent — 6 nodes hub-spoke + 3 perimeter
                     shortcuts; intermediate waypoints
                     climb to altitude 120m for visual
                     arc effect

CLI added (5 flags, 564 documented total now):
  --gen-taxi / --gen-taxi-region / --gen-taxi-continent
  --info-wtax / --validate-wtax

Validator catches: nodeId/pathId=0 + duplicates, empty node
name, non-finite positions, fromNodeId == toNodeId
(self-loop path), path references to non-existent nodes
(intra-format cross-reference resolution), negative
waypoint delays.
2026-05-09 16:26:27 -07:00
Kelsi
2de08a3fd0 feat(pipeline): add WGSP (Wowee Gossip Menu) format
Novel open replacement for AzerothCore-style gossip_menu +
gossip_menu_option + npc_text SQL tables PLUS the Blizzard
NpcText.dbc family. The 23rd open format added to the
editor.

An NPC's dialogue tree: a menu of options the player can
pick from when right-clicking the NPC. Each option may
bridge to another menu, trigger a vendor / trainer
interaction, offer a quest, etc. The simplified per-option
model (kind + actionTarget + flags + moneyCost) covers the
common cases without needing separate npc_text condition
tables.

Closes a major cross-format gap: WCRT.entry.gossipId has
existed since batch 116 (when WCRT was added) but pointed
to a format that didn't exist yet. The innkeeper preset's
menuId=4001 deliberately matches WCRT's Bartleby NPC so
the demo content stack can wire WCRT.gossipId = 4001 once
that field is plumbed through the runtime.

Cross-references:
  WCRT.entry.gossipId        -> WGSP.entry.menuId
  WGSP.option.actionTarget (Submenu) -> WGSP.entry.menuId
  WGSP.option.actionTarget (Vendor / Trainer)
                              -> WTRN.entry.npcId
  WGSP.option.actionTarget (Quest)  -> WQT.entry.questId

Format:
  • magic "WGSP", version 1, little-endian
  • per menu: menuId / titleText + options[]
  • per option: optionId / text / kind / actionTarget /
    requiredFlags / moneyCostCopper

Enums:
  • OptionKind (13): Close / Submenu / Vendor / Trainer /
                     Quest / Tabard / Banker / Innkeeper /
                     FlightMaster / TextOnly / Script /
                     Battlemaster / Auctioneer
  • OptionFlags:    AllianceOnly / HordeOnly / Coinpouch /
                     QuestGated / Closes

API: WoweeGossipLoader::save / load / exists / findById;
presets makeStarter (1 menu with vendor + trainer + close),
makeInnkeeper (2-menu tree: main menu 4001 with hearth /
vendor / flight / submenu options + lore submenu 4002 that
links back), makeQuestGiver (1 menu with 2 quest options
referencing WQT 1 and 100, plus a paid respec script
exercising the Coinpouch flag with a 10g cost).

CLI added (5 flags, 558 documented total now):
  --gen-gossip / --gen-gossip-innkeeper / --gen-gossip-questgiver
  --info-wgsp / --validate-wgsp

Validator catches: menuId=0 + duplicates, empty title /
options, unknown option kind, empty option text, Submenu
options pointing at non-existent menuIds (intra-format
cross-reference resolution), Coinpouch flag without
moneyCost (misleading UI), AllianceOnly+HordeOnly conflict.
2026-05-09 16:20:07 -07:00
Kelsi
d2ca3ea22b feat(pipeline): add WTRN (Wowee Trainer / Vendor catalog) format
Novel open replacement for AzerothCore-style npc_trainer +
npc_vendor SQL tables PLUS the Blizzard TrainerSpells.dbc
family. The 22nd open format added to the editor.

Unifies trainer spell lists and vendor item inventories
into one per-NPC entry. A creature flagged Trainer or
Vendor in WCRT references a WTRN entry that lists what they
teach / sell. The same NPC can be both — kindMask is a
bitmask covering the Trainer (0x01) and Vendor (0x02) kinds.

This format closes a major cross-format gap: WCRT.npcFlags
already had Vendor / Trainer bits, but until now there was
no format defining what a vendor sells or what a trainer
teaches. Now an NPC marked Vendor in WCRT has a real
inventory, and an NPC marked Trainer has a real spell list.

Cross-references — every WTRN field has a real format target:
  WTRN.entry.npcId           -> WCRT.entry.creatureId
  WTRN.spell.spellId         -> WSPL.entry.spellId
  WTRN.spell.requiredSkillId -> WSKL.entry.skillId
  WTRN.item.itemId           -> WIT.entry.itemId

Format:
  • magic "WTRN", version 1, little-endian
  • per NPC: npcId / kindMask / greeting + spells[] + items[]
  • per spell offer: spellId / moneyCostCopper /
    requiredSkillId / requiredSkillRank / requiredLevel
  • per item offer: itemId / stockCount (0xFFFFFFFF =
    unlimited) / restockSec / extendedCost / moneyCostCopper
    (0 = inherit from WIT.buyPrice)

API: WoweeTrainerLoader::save / load / exists / findByNpc;
presets makeStarter (innkeeper 4001 as both trainer +
vendor: teaches First Aid + sells starter items),
makeMageTrainer (NPC 4003 teaches the WSPL mage spells
at scaling cost), makeWeaponVendor (NPC 4002 sells WIT
weapons with mixed unlimited/finite stock + restock timers).

CLI added (5 flags, 551 documented total now):
  --gen-trainers / --gen-trainers-mage / --gen-trainers-weapons
  --info-wtrn / --validate-wtrn

Validator catches: npcId=0 + duplicates, kindMask=0 (NPC
offers nothing), Trainer flag without spells, Vendor flag
without items, spells/items present without the matching
kind bit (silently ignored at runtime), spellId=0 / itemId=0
in offers, finite stock with restockSec=0 (single-fill —
usually intentional but worth surfacing).

The 3 presets deliberately use npcIds matching WCRT village
merchants (4001/4002/4003) so the demo content stack is
self-consistent: WCRT 4001 has the Vendor + Trainer flag,
and WTRN 4001 actually defines what they sell and teach.
2026-05-09 16:12:58 -07:00
Kelsi
e5eaf13866 feat(pipeline): add WACH (Wowee Achievement Catalog) format
Novel open replacement for Blizzard's Achievement.dbc +
AchievementCriteria.dbc + AchievementCategory.dbc + the
AzerothCore-style character_achievement /
character_achievement_progress SQL tables. The 21st open
format added to the editor.

Each achievement carries display metadata (name, description,
icon, points, faction restriction) plus a list of criteria
the player must satisfy. Criteria mirror the WQT objective
model (kind + targetId + quantity), so the runtime can
reuse the same progress-tracking machinery for both quests
and achievements.

Cross-references with previously-added formats — every
criterion kind has a real format target:
  WACH.criteria.targetId (kind=KillCreature)    -> WCRT.creatureId
  WACH.criteria.targetId (kind=CompleteQuest)   -> WQT.questId
  WACH.criteria.targetId (kind=LootItem)        -> WIT.itemId
  WACH.criteria.targetId (kind=CastSpell)       -> WSPL.spellId
  WACH.criteria.targetId (kind=ReachSkillLevel) -> WSKL.skillId
  WACH.criteria.targetId (kind=EarnReputation)  -> WFAC.factionId
  WACH.criteria.targetId (kind=CompleteAchievement) -> WACH.achievementId
                                                       (meta-achievements)

Format:
  • magic "WACH", version 1, little-endian
  • per achievement: id / categoryId / name / description /
    iconPath / titleReward / points / minLevel / faction /
    flags / criteria[]
  • per criterion: criteriaId / kind / targetId / quantity /
    description

Enums:
  • CriteriaKind (9): KillCreature / CompleteQuest / LootItem /
                      ReachLevel / EarnReputation / CastSpell /
                      ReachSkillLevel / VisitArea /
                      CompleteAchievement
  • Faction:    Both / Alliance / Horde
  • Flags:      HiddenUntilEarned / ServerFirst / RealmFirst /
                 Tracking / Counter / Account

API: WoweeAchievementLoader::save / load / exists /
findById; presets makeStarter (3 simple kill/quest/level
demos), makeBandit (3 with WCRT/WGOT/WQT cross-refs),
makeMeta (3 base + 1 meta-achievement granting "the
Versatile" title, exercising CompleteAchievement criterion
kind that lets achievements depend on other achievements).

CLI added (5 flags, 542 documented total now):
  --gen-achievements / --gen-achievements-bandit / --gen-achievements-meta
  --info-wach / --validate-wach

Validator catches: achievementId=0 + duplicates, empty name,
faction out of range, no criteria (achievement can never
be earned), criterion quantity=0, unknown criterion kind,
targetId=0 on criterion kinds that need a real resource
reference (everything except ReachLevel which uses the
quantity field for the level number).

The bandit preset's cross-references close the gameplay
graph end-to-end: kill 50 creatureId=1000 (matches WCRT/
WSPN/WLOT bandit), loot objectId=2000 (matches WGOT bandit
strongbox), complete questId=1 (matches WQT Bandit Trouble).
The meta preset closes a separate loop: 3 sub-achievements
covering Mining (skillId=186), Lockpicking (skillId=633),
and Frostbolt cast count (spellId=116) — each pointing at
a real WSKL/WSPL entry that already exists in the demo
content stack.
2026-05-09 16:04:30 -07:00
Kelsi
5ea1f7ee2a feat(pipeline): add WSPL (Wowee Spell Catalog) format
Novel open replacement for Blizzard's Spell.dbc +
SpellEffect.dbc + the AzerothCore-style spell_dbc /
spell_proc tables. The 20th open format added to the
editor — completes the canonical-data side of the gameplay
graph.

Each entry holds the metadata side of a spell: name,
description, school, range, mana / cast / cooldown times,
plus a single primary effect. The simplified effect model
(one effectKind + min/max value + misc field) covers the
common cases (damage / heal / buff / debuff / teleport /
summon / dispel) without needing to reproduce the full
multi-effect graph that classic Spell.dbc carries.

Cross-references with previously-added formats:
  WLCK.channel.targetId (kind=Spell)       -> WSPL.entry.spellId
  WQT.objective.targetId (kind=SpellCast)  -> WSPL.entry.spellId
  WCRT.equippedMain (item with on-use)     -> WIT -> WSPL

Format:
  • magic "WSPL", version 1, little-endian
  • per spell: spellId / name / description / iconPath /
    school / targetType / effectKind / cast & cooldown &
    GCD ms / manaCost / range min..max / minLevel /
    maxStacks / durationMs / effectValueMin..Max /
    effectMisc / flags

Enums:
  • School (7):     Physical / Holy / Fire / Nature / Frost /
                     Shadow / Arcane
  • TargetType (6): Self / Single / Cone / AoeFromSelf /
                     Line / Ground
  • EffectKind (7): Damage / Heal / Buff / Debuff / Teleport /
                     Summon / Dispel
  • Flags:          Passive / Hidden / Channeled / Ranged /
                     AreaOfEffect / Triggered / UnitTargetOnly /
                     FriendlyOnly / HostileOnly

API: WoweeSpellLoader::save / load / exists / findById;
presets makeStarter (Strike + Lesser Heal + Power Word:
Fortitude + Hearthstone, one per major effect kind),
makeMage (Frostbolt 116 + Fireball 133 + Arcane Intellect
1459 + Blink 1953, canonical Classic spellIds), makeWarrior
(Heroic Strike 78 + Thunder Clap 6343 + Battle Shout 6673 +
Mortal Strike 12294).

CLI added (5 flags, 535 documented total now):
  --gen-spells / --gen-spells-mage / --gen-spells-warrior
  --info-wspl / --validate-wspl

Validator catches: spellId=0 + duplicates, empty name,
school out of range, effectKind out of range, NaN range,
range/value min>max, FriendlyOnly+HostileOnly conflict
(incoherent), friendly-only with damage/debuff effect
(incoherent), hostile-only with heal/buff effect, buff/debuff
effect with durationMs=0 (instant fade — almost certainly
authoring oversight).

The validator caught a real preset-emitter authoring error
during initial smoke testing — buff spells were setting
effectValueMin without effectValueMax (validator's range
check immediately flagged it), prompting an in-batch fix
to set both fields. This is exactly the catch-the-typo
purpose validators serve.
2026-05-09 15:58:09 -07:00
Kelsi
95e593e59c feat(pipeline): add WSKL (Wowee Skill Catalog) format
Novel open replacement for Blizzard's SkillLine.dbc +
SkillLineCategory.dbc + the AzerothCore-style player skill
base tables. The 19th open format added to the editor.

Defines every player-trackable skill: weapon proficiencies
(Swords, Axes, Bows), professions (Mining, Alchemy,
Cooking), languages (Common, Dwarvish), class
specializations (Fire, Frost, Holy, Protection), armor
proficiencies (Mail, Plate), and secondary skills (First
Aid, Lockpicking, Riding).

Cross-references with previously-added formats:
  WLCK.channel.targetId (kind=Lockpick) -> WSKL.entry.skillId
  WGOT.entry.requiredSkill              -> WSKL.entry.skillId

The starter preset's skillIds 186 (Mining) and 633
(Lockpicking) deliberately match the canonical IDs already
referenced by WGOT.makeGather and WLCK.makeDungeon —
so the demo content stack now wires together end-to-end:
WGOT herb-node requires skill 186 -> WSKL Mining at rank 1+;
WLCK bandit-strongbox channel requires skill 633 -> WSKL
Lockpicking at rank 1+.

Format:
  • magic "WSKL", version 1, little-endian
  • per skill: skillId / name / description / categoryId /
    canTrain / maxRank / rankPerLevel / iconPath

Enums:
  • CategoryId (8): Weapon / Class / Profession /
    SecondaryProfession / Language / ArmorProficiency /
    Riding / WeaponSpec

API: WoweeSkillLoader::save / load / exists / findById;
presets makeStarter (5-skill demo with cross-referenced
canonical IDs), makeProfessions (12 classic professions:
9 primary + 3 secondary), makeWeapons (16 weapon skills
with canonical SkillLine IDs and rankPerLevel=5 auto-grow).

CLI added (5 flags, 528 documented total now):
  --gen-skills / --gen-skills-professions / --gen-skills-weapons
  --info-wskl / --validate-wskl

Validator catches: skillId=0 + duplicates, empty name,
maxRank=0, unknown categoryId, suspicious maxRank=1 on
non-Language skill (only languages cap at 1), weapon skill
with rankPerLevel=0 (won't auto-grow on use).
2026-05-09 15:50:25 -07:00
Kelsi
81b1897a24 feat(pipeline): add WLCK (Wowee Lock Template) format
Novel open replacement for Blizzard's Lock.dbc. The 18th
open format added to the editor. Closes the cross-reference
gap from WGOT.entry.lockId — until now that field pointed
to a format that didn't exist yet.

A lock is a multi-channel security check. Each lock has up
to 5 independent channels; a player can open the lock by
satisfying ANY ONE channel:
  • Item     — requires a specific key item (WIT cross-ref)
  • Lockpick — requires the lockpicking skill at minimum rank
                (rogue / engineering profession)
  • Spell    — requires casting a specific spell
  • Damage   — can be forced open with attack damage

Cross-references with previously-added formats:
  WGOT.entry.lockId               -> WLCK.entry.lockId
  WLCK.channel.targetId (Item)    -> WIT.entry.itemId
  WLCK.channel.targetId (Lockpick) -> future WSKL skillId
  WLCK.channel.targetId (Spell)   -> future WSPL spellId

The starter and dungeon presets' lockIds (1 and 2)
deliberately match WGOT.makeDungeon's iron-door lockId=1
and bandit-strongbox lockId=2, so the demo content stack
already wires together: WSPN spawn -> WGOT object template
-> WLCK lock template -> WIT key items.

Format:
  • magic "WLCK", version 1, little-endian
  • per lock: lockId / name / flags / 5 fixed channel slots
  • per channel: kind / skillRequired / targetId
  • all 5 slots written even when unused (kind=None +
    zeroed fields), keeping the per-entry size constant for
    fast random access

Enums:
  • ChannelKind: None / Item / Lockpick / Spell / Damage
  • Flags:       DestructOnOpen / RespawnOnKey / TrapOnFail

API: WoweeLockLoader::save / load / exists / findById;
presets makeStarter (Iron Door + Wooden Chest), makeDungeon
(matches WGOT cross-references; light/heavy lockpicks +
boss-key-only seal), makeProfessions (4-tier rogue lockpick
progression at ranks 1/100/175/250).

CLI added (5 flags, 521 documented total now):
  --gen-locks / --gen-locks-dungeon / --gen-locks-professions
  --info-wlck / --validate-wlck

Validator catches: lockId=0 + duplicates, all-None channels
(lock can never open), Item/Spell/Lockpick channels with
targetId=0 (no resource referenced), unknown channel kind,
skillRequired set on non-Lockpick channel (silently ignored
at runtime — flag as warning).
2026-05-09 15:44:26 -07:00
Kelsi
4868f780cc feat(pipeline): add WFAC (Wowee Faction Catalog) format
Novel open replacement for Blizzard's Faction.dbc +
FactionTemplate.dbc + the AzerothCore-style
reputation_reward / reputation_spillover SQL tables. The
17th open format added to the editor.

Combines the "displayable Faction" (player-facing name +
reputation thresholds for friendly/honored/revered/exalted)
with the "FactionTemplate matrix" (which factions are
hostile to which) into one entry. The runtime walks the
catalog to answer two questions:
  • "Will faction A attack faction B on sight?" -> enemy list
  • "What rep tier is the player with X?"      -> thresholds

Cross-references with previously-added formats:
  WCRT.entry.factionId       -> WFAC.entry.factionId
  WFAC.entry.parentFactionId -> WFAC.entry.factionId
  WFAC.entry.enemies[]       -> WFAC.entry.factionId
  WFAC.entry.friends[]       -> WFAC.entry.factionId

The starter preset's factionId 35 (Friendly) and 14
(Hostile) deliberately match the WCRT preset defaults, so
the demo content stack is consistent: WCRT.makeBandit's
factionId=14 has a real entry in WFAC.makeStarter that
declares it hostile to friendly NPCs (35) and players (1).

Format:
  • magic "WFAC", version 1, little-endian
  • per faction: factionId / parentFactionId / name /
    description / reputationFlags / baseReputation /
    7 ascending tier thresholds (hostile..exalted) /
    enemies[] / friends[]

Enums:
  • ReputationFlags: VisibleOnTab / AtWarDefault / Hidden /
                      NoReputation / IsHeader (group label)
  • Tier (canonical): Hated / Hostile / Unfriendly /
                       Neutral / Friendly / Honored /
                       Revered / Exalted

API: WoweeFactionLoader::save / load / exists / findById +
WoweeFaction::isHostile(a, b); presets makeStarter (3-faction
demo matching WCRT defaults), makeAlliance (header +
Stormwind / Darnassus / Ironforge with reciprocal friend
lists + Defias enemy), makeWildlife (4 beast factions, each
hostile to player but ignoring other beasts).

CLI added (5 flags, 514 documented total now):
  --gen-factions / --gen-factions-alliance / --gen-factions-wildlife
  --info-wfac / --validate-wfac

Validator catches: factionId=0 + duplicates, empty name,
threshold ordering violations (hostile must be < unfriendly
< neutral < ... < exalted), self-listed as enemy or friend,
faction in both enemies and friends (incoherent).
2026-05-09 15:37:59 -07:00
Kelsi
f8d7b6b6bd feat(pipeline): add WGOT (Wowee Game Object Template) format
Novel open replacement for AzerothCore-style
gameobject_template SQL tables PLUS the Blizzard
GameObjectDisplayInfo.dbc / GameObject types metadata. The
16th open format added to the editor.

Game objects are the non-creature interactable scenery:
chests (with loot), doors, buttons, mailboxes, herb / ore
gathering nodes, fishing pools, signposts, mounts. Each
has a displayId for the model, a typeId driving its
interaction logic, and optional cross-references to a lock
(future WLCK) and loot table (existing WLOT).

Cross-references with previously-added formats:
  WSPN.entry.entryId (kind=GameObject) -> WGOT.entry.objectId
  WGOT.entry.lootTableId               -> WLOT.entry.creatureId
                                          (loot tables are
                                           universal — chests
                                           and creatures both
                                           key by ID)

The dungeon preset's Bandit Strongbox uses lootTableId=2000
to match WLOT's bandit chest table id, so the demo content
stack already wires together: spawn (WSPN object kind 2000)
-> object template (WGOT 2000) -> loot table (WLOT 2000).

Format:
  • magic "WGOT", version 1, little-endian
  • per object: objectId / displayId / name / typeId /
    size / castBarCaption / requiredSkill +
    requiredSkillValue / lockId / lootTableId /
    minOpenTimeMs..maxOpenTimeMs / flags

Enums:
  • TypeId (16): Door / Button / Chest / Container /
    QuestGiver / Text / Trap / Goober / Transport /
    Mailbox / MineralNode / HerbNode / FishingNode /
    Mount / Sign / Bonfire
  • Flags: Disabled / ScriptOnly / UsableFromMount /
    Despawn / Frozen / QuestGated

API: WoweeGameObjectLoader::save / load / exists /
findById; presets makeStarter (chest + mailbox + sign),
makeDungeon (door + button + 2 chests + trap with proper
WLOT cross-references), makeGather (Peacebloom herb +
Tin Vein ore + fishing pool with skill requirements).

CLI added (5 flags, 507 documented total now):
  --gen-objects / --gen-objects-dungeon / --gen-objects-gather
  --info-wgot / --validate-wgot

Validator catches: objectId=0 + duplicates, size<=0,
minOpenTime>maxOpenTime, gathering node without skill
requirement (anyone can harvest — usually a typo), chest
without loot table (script must populate), requiredSkillValue
set without requiredSkill (incoherent).
2026-05-09 15:31:49 -07:00
Kelsi
02ae17740e feat(pipeline): add WQT (Wowee Quest Template) format
Novel open replacement for AzerothCore-style quest_template
SQL tables PLUS the Blizzard Quest.dbc / QuestObjective.dbc
trio. The 15th open format added to the editor — and the
last gameplay-graph piece the catalog needed.

Cross-references with previously-added formats:
  WQT.giverCreatureId    -> WCRT.entry.creatureId
  WQT.turninCreatureId   -> WCRT.entry.creatureId
  WQT.objective.targetId -> WCRT (kill) / WIT (collect) /
                             WOB (interact)
  WQT.rewardItem.itemId  -> WIT.entry.itemId
  WQT.prevQuestId        -> WQT.entry.questId (intra-format)
  WQT.nextQuestId        -> WQT.entry.questId

Together with WIT / WCRT / WLOT / WSPN / WOMX / WOL / WOW /
WSND, a content pack can now ship a complete RPG zone
(terrain + props + atmosphere + sounds + creatures + items
+ loot + spawns + quests) entirely in open formats with no
SQL or .dbc dependencies. 15 of 15 expected slots filled.

Format:
  • magic "WQTM", version 1, little-endian
  • per quest: questId / title / objective / description /
    minLevel..maxLevel + questLevel / requiredClass+RaceMask /
    prev+nextQuestId / giver+turninCreatureId /
    objectives[] / xpReward + moneyCopperReward /
    rewardItems[] / flags

Per-objective:
  kind (kill/collect/interact/visit/escort/cast),
  targetId, quantity

Per-reward:
  itemId, qty, pickFlags (AutoGiven / PlayerChoice)

Quest flags: Daily / Weekly / Raid / Group / AutoComplete /
              AutoAccept / Repeatable / ClassQuest / Pvp

API: WoweeQuestLoader::save / load / exists / findById;
presets makeStarter (1 simple kill quest, references the
bandit creatureId=1000), makeChain (3-quest chain with
prev/next links + AutoComplete bridge + player-choice
rewards), makeDaily (Daily+Repeatable+AutoAccept combo).

CLI added (5 flags, 500 documented total — round milestone):
  --gen-quests / --gen-quests-chain / --gen-quests-daily
  --info-wqt / --validate-wqt

Validator catches: questId=0+duplicates, level=0,
maxLevel<minLevel, empty title, no objectives without
AutoComplete (player can't finish), no rewards at all,
Daily without Repeatable (incoherent), targetId=0,
quantity=0, unknown objective kind, reward itemId=0 or qty=0.

The 3-quest chain demo exercises every major feature:
  • multiple objective kinds (visit / collect / kill)
  • prev/next chain links
  • AutoComplete dialogue-bridge quest
  • PlayerChoice reward (1 of 2 weapons)
2026-05-09 15:25:02 -07:00
Kelsi
b2b84139aa feat(pipeline): add WCRT (Wowee Creature Template) format
Novel open replacement for the AzerothCore-style
creature_template SQL table PLUS the Blizzard
CreatureTemplate / CreatureFamily / CreatureType.dbc trio.
The 14th open format added to the editor.

This is the canonical metadata side of creatures shared
across every spawn instance: HP, level range, faction,
behavior flags, NPC role bits (vendor / trainer /
quest-giver / innkeeper), base damage, equipped gear
references.

Cross-references with the previously-added formats:
  WSPN.entry.entryId    -> WCRT.entry.creatureId
  WLOT.entry.creatureId -> WCRT.entry.creatureId
  WCRT.entry.equipped*  -> WIT.entry.itemId

The 4-format set (WIT + WLOT + WSPN + WCRT) now lets a
content pack define a complete RPG zone's creature
ecosystem: what creatures are, where they spawn, what they
drop, and what gear they carry — entirely in open formats
with no SQL dependencies.

Format:
  • magic "WCRT", version 1, little-endian
  • per entry: creatureId / displayId / name / subname /
    minLevel..maxLevel / baseHealth + healthPerLevel /
    baseMana + manaPerLevel / factionId / npcFlags /
    typeId / familyId / damageMin..Max / attackSpeedMs /
    baseArmor / walkSpeed + runSpeed / gossipId /
    equippedMain + equippedOffhand + equippedRanged /
    aiFlags

Enums:
  • TypeId:   Beast / Dragon / Demon / Elemental / Giant /
              Undead / Humanoid / Critter / Mechanical
  • FamilyId: Wolf / Cat / Bear / Boar / Raptor / Hyena /
              Spider / Gorilla / Crab (for Beast types)
  • NpcFlags: Vendor / QuestGiver / Trainer / Banker /
              Innkeeper / FlightMaster / Auctioneer /
              Repair / Stable
  • Behavior: Passive / Aggressive / FleeLowHp / CallHelp /
              NoLeash

API: WoweeCreatureLoader::save / load / exists /
findById; presets makeStarter (1 innkeeper),
makeBandit (creatureId=1000 matches WSPN/WLOT bandit
references, equips WIT itemId=1001 sword), makeMerchants
(creatureIds 4001/4002/4003 match WSPN village labels).

CLI added (5 flags, 493 documented total):
  --gen-creatures / --gen-creatures-bandit / --gen-creatures-merchants
  --info-wcrt / --validate-wcrt

Validator catches: creatureId=0, duplicates, level=0,
minLevel>maxLevel, baseHealth=0, damageMin>damageMax,
attackSpeed=0, non-positive walk/runSpeed, behavior flag
contradictions (passive+aggressive), vendor with
aggressive behavior (player can't trade).
2026-05-09 15:18:44 -07:00
Kelsi
ff0aa1a3c8 feat(pipeline): add WLOT (Wowee Loot Table) format
Novel open replacement for AzerothCore-style
creature_loot_template / gameobject_loot_template SQL
tables. The 13th open format added to the editor.

Pairs naturally with the WIT item catalog from the
preceding commit: each loot drop's itemId references an
entry in a WIT file, so a content pack ships both the
item definitions and the loot tables that reference them.
The runtime composes WIT + WLOT + WSPN to drive the full
"creature dies, drops items" flow without any SQL.

Format:
  • magic "WLOT", version 1, little-endian
  • per table: creatureId / flags / dropCount /
    moneyMin..Max / itemDropCount + drops[]
  • per drop: itemId / chancePercent (float, 0..100) /
    minQty / maxQty / drop_flags

Table flags: QuestOnly, GroupOnly, Pickpocket
Drop flags:  QuestRequired, GroupRollOnly, AlwaysDrop

dropCount is the slot budget — how many distinct drops
to roll per kill. Each item drop is rolled independently
against its chancePercent (so dropCount=2 with 4 candidate
drops at varying chances gives the classic "up to 2 distinct
items per kill" behavior). Drops with the AlwaysDrop flag
bypass the slot budget — used for guaranteed quest items.

API: WoweeLootLoader::save / load / exists /
findByCreatureId; presets makeStarter (1 table, 1 drop),
makeBandit (4 candidates, dropCount=2, matches the camp
spawns from WSPN at creatureId=1000), makeBoss (6 candidates
including guaranteed quest item via AlwaysDrop and a
group-only epic at 5%).

CLI added (5 flags, 486 documented total now):
  --gen-loot / --gen-loot-bandit / --gen-loot-boss
  --info-wlot / --validate-wlot

Validator catches: creatureId=0, duplicates, chance not in
0..100, NaN chance, money min > max, minQty > maxQty,
dropCount=0 with non-empty drops list (silent dead config).

All 3 presets save / load / re-validate clean. The bandit
table's creatureId=1000 deliberately matches WSPN's
makeCamp creatureId so the open-format demo content pack
already has working cross-references.
2026-05-09 15:11:08 -07:00
Kelsi
9093975bdd feat(pipeline): add WIT (Wowee Item Template) format
Novel open replacement for Blizzard's Item.dbc +
ItemDisplayInfo.dbc + the SQL item_template tables that
AzerothCore-style servers store item definitions in. The
12th open format added to the editor.

A WIT file holds the catalog of all items in a content
pack: weapons, armor, consumables, quest items, trade
goods. Each entry pairs gameplay metadata (stats, level
reqs, flags, weapon damage / speed) with display metadata
(displayId for icon / model, quality color), so the
runtime can render inventory tooltips and equip slots
from a single load.

Format:
  • magic "WITM", version 1, little-endian
  • per item: itemId / displayId / quality / itemClass /
    itemSubClass / inventoryType / flags / requiredLevel /
    itemLevel / sellPrice / buyPrice / maxStack / durability
    / damageMin / damageMax / attackSpeedMs /
    statCount + stats[] / name / description

Enums:
  • Quality:       Poor..Heirloom (8 levels)
  • Class:         Consumable, Weapon, Armor, Quest, ... (13)
  • InventoryType: Head..Cloak..Weapon2H (18 slots)
  • Flags:        Unique, BoP, BoE, QuestItem, Conjured, ...
  • StatType:     Stamina, Strength, Intellect, Defense, ...

API: WoweeItemLoader::save / load / exists / findById;
presets makeStarter (4-item demo), makeWeapons (5 items
common -> legendary), makeArmor (6-piece mail set with
BoE flag).

CLI added (5 flags, 480 documented total now):
  --gen-items / --gen-items-weapons / --gen-items-armor
  --info-wit / --validate-wit

Validator catches: itemId=0, duplicate itemIds, weapons
with 0 damage or attackSpeed, weapons with non-weapon
slot, equippables with durability=0 or maxStack>1, sell
price >= buy price (vendor would lose money), out-of-range
quality.

All 3 presets save / load / re-validate clean. Info-table
output includes a gold/silver/copper price formatter for
hand-readability.
2026-05-09 15:04:48 -07:00
Kelsi
88d1e6229f feat(pipeline): add WSPN (Wowee Spawn Point catalog) format
Novel open replacement for AzerothCore-style scattered
creature_template / gameobject SQL spawn tables PLUS the
ADT MDDF / MODF doodad-placement chunks. The 11th open
format, and the first that covers the live world-content
side (atmosphere + sounds + spawns now form the runtime
"what fills this zone" picture).

A WSPN file holds all spawn points for a zone in a single
table, with kind discriminating creature vs game object
vs static doodad. The same format powers:
  • server runtime  — knows what NPCs / objects to spawn
  • editor          — draws spawn markers
  • renderer        — reads the doodad subset directly to
                       draw static props without going
                       through a server roundtrip

Format:
  • magic "WSPN", version 1, little-endian
  • per entry: kind / entryId / position(3f) / rotation(3f)
    / scale / flags / respawnSec / factionId /
    questIdRequired / wanderRadius / label

Flags packed: disabled (0x01), event-only (0x02),
quest-phased (0x04). Reserved bits for future per-entry
encoding extensions.

API: WoweeSpawnsLoader::save / load / exists; presets
makeStarter (1 each kind), makeCamp (4-bandit ring +
chest + 2 tents), makeVillage (6 NPCs + 2 signs + 4
corner trees).

CLI added (5 flags, 473 documented total now):
  --gen-spawns / --gen-spawns-camp / --gen-spawns-village
  --info-wspn / --validate-wspn

Validator catches: out-of-range kind, NaN/inf coords,
non-positive scale, doodad with non-zero respawn (static
prop misuse), creature with respawn=0 (won't respawn after
kill), entryId=0 (orphan reference).

All 3 presets save / load / re-validate clean. Doodad and
game-object entries explicitly set wanderRadius=0 so the
generated catalogs are noise-free.
2026-05-09 14:57:53 -07:00
Kelsi
36d63d8dd0 feat(pipeline): add WSND (Wowee Sound Catalog) format
Novel open replacement for Blizzard's SoundEntries.dbc +
SoundEntriesAdvanced.dbc. The 10th open format added to the
editor — covers the audio-metadata gap (the previous 9 cover
geometry, terrain, atmosphere, and world manifests, but no
sound metadata).

Format:
  • magic "WSND", version 1, little-endian
  • catalogName + entry count
  • per entry: soundId / kind / flags / volume /
    minDistance / maxDistance / filePath / label

Kind enum (7 categories):
  sfx, music, ambient, ui, voice, spell, combat

Flags packed (3 bits used, rest reserved):
  loop (0x01), 3d (0x02), stream (0x04)

API: WoweeSoundLoader::save / load / exists; presets
makeStarter (one entry per kind), makeAmbient (wilderness
loops + footsteps), makeTavern (fire + crowd + drink + door
+ lute).

CLI added (5 flags, 465 documented total now):
  --gen-sound-catalog <base> [name]
  --gen-sound-catalog-ambient <base> [name]
  --gen-sound-catalog-tavern <base> [name]
  --info-wsnd <base> [--json]
  --validate-wsnd <base> [--json]

Validator catches: out-of-range kind, NaN/inf volume or
distances, 3D sounds with bad min/max, duplicate sound IDs,
empty filePaths.

All 3 presets verified: save / load / validate clean
on first run. Variable-length string fields use length-
prefixed encoding with a 1 MiB sanity cap on read to
prevent corrupted-file allocation blowups.
2026-05-09 14:47:16 -07:00
Kelsi
db47f00657 feat(pipeline): add WOMX (Wowee World Map index) format
Novel open replacement for Blizzard's WDT (top-level world
definition table). The 9th open format added to the editor.

A WOMX file holds the manifest of which terrain tiles exist
within a world plus a tiny bit of map-level metadata. The
runtime consults it before attempting to load any individual
tile (so missing tiles produce a clean "no data" result
instead of a file-not-found error).

Format:
  • magic "WMPX", version 1, little-endian
  • mapName + worldType (continent/instance/battleground/arena)
  • gridSize 1..128 (typically 64 for continents)
  • defaultLightId / defaultWeatherId (atmosphere preset
    refs, 0 if none — wires into the WOL/WOW pair)
  • packed bitmap, 1 bit per tile, row-major
  • A 64x64 manifest is exactly 512 bytes of bitmap

API: WoweeWorldMapLoader::save / load / exists; presets
makeContinent (64x64 full), makeInstance (4x4 full),
makeArena (1x1 full).

CLI added (5 flags, 456 total now):
  --gen-world-map <base> [name]            (continent)
  --gen-world-map-instance <base> [name]   (4x4)
  --gen-world-map-arena <base> [name]      (1x1)
  --info-womx <base> [--json]
  --validate-womx <base> [--json]

Round-trip verified: continent + instance + arena presets
all save / load / re-validate to byte-identical state with
correct tile counts.
2026-05-09 14:38:05 -07:00
Kelsi
0ff13ccd67 refactor(editor): replace 60-handler chain with table-driven dispatch
Adds cli_dispatch.{hpp,cpp} containing a static table of every
extracted handler family's dispatch function. The table-walker
tryDispatchAll() iterates the table once per argv token, calling
each handler in turn. handleConvertSingle stays as a special-
case call in main.cpp because it threads dataPath through.

main.cpp shrinks from 486 to 236 lines (-250). Adding a new
handler module now requires touching only cli_dispatch.cpp's
include list + table — no main.cpp edits, no growing
if-else chain. The 60+ #include lines for individual cli_*
modules collapse to one #include for cli_dispatch.hpp.
2026-05-09 10:15:51 -07:00