Commit graph

2 commits

Author SHA1 Message Date
Kelsi
c3f7286d4a feat(editor): add WTRN JSON round-trip authoring workflow
Closes the WTRN open-format loop with --export-wtrn-json /
--import-wtrn-json, mirroring the JSON pairs added for
every other novel binary format. All 16 binary formats
added since WOL now have full JSON round-trip authoring.

Each NPC round-trips:
  • npcId, kindMask (dual int + kindList string array),
    greeting
  • spells[]: spellId / cost / requiredSkill+rank / minLevel
  • items[]:  itemId / stockCount / restockSec /
              extendedCost / moneyCostCopper

The stockCount field has special handling — the sentinel
0xFFFFFFFF value emits as the string "unlimited" instead of
the raw integer, since 4294967295 reads as a magic-number
typo in hand-edit JSON. The importer accepts either form.

Verified byte-identical round-trip on the starter preset
(innkeeper 4001 with 1 spell + 3 items, exercising both
unlimited-stock and finite-stock-with-restock cases).

Adds 2 flags (553 documented total now).
2026-05-09 16:14:50 -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