mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-05-10 02:53:51 +00:00
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.
120 lines
4 KiB
C++
120 lines
4 KiB
C++
#pragma once
|
||
|
||
#include <cstdint>
|
||
#include <string>
|
||
#include <vector>
|
||
|
||
namespace wowee {
|
||
namespace pipeline {
|
||
|
||
// Wowee Open Trainer / Vendor catalog (.wtrn) — novel
|
||
// 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 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.
|
||
//
|
||
// Cross-references with previously-added formats:
|
||
// WTRN.entry.npcId → WCRT.entry.creatureId
|
||
// WTRN.spell.spellId → WSPL.entry.spellId
|
||
// WTRN.spell.requiredSkillId → WSKL.entry.skillId
|
||
// WTRN.item.itemId → WIT.entry.itemId
|
||
//
|
||
// Binary layout (little-endian):
|
||
// magic[4] = "WTRN"
|
||
// version (uint32) = current 1
|
||
// nameLen + name (catalog label)
|
||
// entryCount (uint32)
|
||
// entries (each):
|
||
// npcId (uint32)
|
||
// kindMask (uint8) + pad[3]
|
||
// greetingLen + greeting
|
||
// spellCount (uint16) + itemCount (uint16)
|
||
// spells (spellCount × {
|
||
// spellId (uint32)
|
||
// moneyCostCopper (uint32)
|
||
// requiredSkillId (uint32)
|
||
// requiredSkillRank (uint16)
|
||
// requiredLevel (uint16)
|
||
// })
|
||
// items (itemCount × {
|
||
// itemId (uint32)
|
||
// stockCount (uint32) -- 0xFFFFFFFF = unlimited
|
||
// restockSec (uint32)
|
||
// extendedCost (uint32)
|
||
// moneyCostCopper (uint32) -- 0 = use WIT.buyPrice
|
||
// })
|
||
struct WoweeTrainer {
|
||
enum KindMask : uint8_t {
|
||
Trainer = 0x01,
|
||
Vendor = 0x02,
|
||
};
|
||
|
||
static constexpr uint32_t kUnlimitedStock = 0xFFFFFFFFu;
|
||
|
||
struct SpellOffer {
|
||
uint32_t spellId = 0;
|
||
uint32_t moneyCostCopper = 0;
|
||
uint32_t requiredSkillId = 0; // 0 = no skill prerequisite
|
||
uint16_t requiredSkillRank = 0;
|
||
uint16_t requiredLevel = 1;
|
||
};
|
||
|
||
struct ItemOffer {
|
||
uint32_t itemId = 0;
|
||
uint32_t stockCount = kUnlimitedStock;
|
||
uint32_t restockSec = 0;
|
||
uint32_t extendedCost = 0; // 0 = copper-only
|
||
uint32_t moneyCostCopper = 0; // 0 = inherit from WIT
|
||
};
|
||
|
||
struct Entry {
|
||
uint32_t npcId = 0;
|
||
uint8_t kindMask = 0;
|
||
std::string greeting;
|
||
std::vector<SpellOffer> spells;
|
||
std::vector<ItemOffer> items;
|
||
};
|
||
|
||
std::string name;
|
||
std::vector<Entry> entries;
|
||
|
||
bool isValid() const { return !entries.empty(); }
|
||
|
||
// Lookup by npcId — nullptr if not present.
|
||
const Entry* findByNpc(uint32_t npcId) const;
|
||
|
||
// Decode the kindMask into a short string (e.g.
|
||
// "trainer+vendor" or just "vendor").
|
||
static std::string kindMaskName(uint8_t k);
|
||
};
|
||
|
||
class WoweeTrainerLoader {
|
||
public:
|
||
static bool save(const WoweeTrainer& cat,
|
||
const std::string& basePath);
|
||
static WoweeTrainer load(const std::string& basePath);
|
||
static bool exists(const std::string& basePath);
|
||
|
||
// Preset emitters used by --gen-trainers* variants.
|
||
//
|
||
// makeStarter — 1 NPC (Bartleby innkeeper, npcId=4001)
|
||
// acting as both vendor + trainer: sells
|
||
// 3 starter items + teaches First Aid.
|
||
// makeMageTrainer — npcId=4003 (alchemist) becomes a
|
||
// mage trainer offering Frostbolt /
|
||
// Fireball / Arcane Intellect / Blink
|
||
// at appropriate ranks.
|
||
// makeWeaponVendor — npcId=4002 (smith) sells 5 weapons
|
||
// across the WIT weapon catalog.
|
||
static WoweeTrainer makeStarter(const std::string& catalogName);
|
||
static WoweeTrainer makeMageTrainer(const std::string& catalogName);
|
||
static WoweeTrainer makeWeaponVendor(const std::string& catalogName);
|
||
};
|
||
|
||
} // namespace pipeline
|
||
} // namespace wowee
|