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).
This commit is contained in:
Kelsi 2026-05-09 15:50:25 -07:00
parent dda7933df9
commit 95e593e59c
8 changed files with 581 additions and 0 deletions

View file

@ -0,0 +1,95 @@
#pragma once
#include <cstdint>
#include <string>
#include <vector>
namespace wowee {
namespace pipeline {
// Wowee Open Skill Catalog (.wskl) — novel replacement for
// Blizzard's SkillLine.dbc + SkillLineCategory.dbc + the
// AzerothCore-style player_classlevelstats / 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
//
// Binary layout (little-endian):
// magic[4] = "WSKL"
// version (uint32) = current 1
// nameLen + name (catalog label)
// entryCount (uint32)
// entries (each):
// skillId (uint32)
// nameLen + name
// descLen + description
// categoryId (uint8) / canTrain (uint8) / pad[2]
// maxRank (uint16) / rankPerLevel (uint16)
// iconLen + iconPath
struct WoweeSkill {
enum CategoryId : uint8_t {
Weapon = 0,
Class = 1, // class spec trees (Fire, Holy, ...)
Profession = 2, // primary: Mining, Alchemy
SecondaryProfession = 3, // First Aid, Cooking, Fishing
Language = 4,
ArmorProficiency = 5, // Mail, Plate, Shields
Riding = 6,
WeaponSpec = 7, // class weapon-specialization talents
};
struct Entry {
uint32_t skillId = 0;
std::string name;
std::string description;
uint8_t categoryId = Profession;
uint8_t canTrain = 1; // 1 = requires trainer
uint16_t maxRank = 300; // typical classic profession cap
uint16_t rankPerLevel = 0; // weapon skills auto-grow
std::string iconPath;
};
std::string name;
std::vector<Entry> entries;
bool isValid() const { return !entries.empty(); }
// Lookup by skillId — nullptr if not present.
const Entry* findById(uint32_t skillId) const;
static const char* categoryName(uint8_t c);
};
class WoweeSkillLoader {
public:
static bool save(const WoweeSkill& cat,
const std::string& basePath);
static WoweeSkill load(const std::string& basePath);
static bool exists(const std::string& basePath);
// Preset emitters used by --gen-skills* variants.
//
// makeStarter — minimal: Swords + Lockpicking + Mining +
// First Aid + Common (one per category that
// the runtime uses immediately).
// makeProfessions — full primary + secondary profession
// set (the 12 classic gathering /
// crafting professions).
// makeWeapons — every weapon-skill slot with WoW's
// canonical max-rank scaling (rankPerLevel=5).
static WoweeSkill makeStarter(const std::string& catalogName);
static WoweeSkill makeProfessions(const std::string& catalogName);
static WoweeSkill makeWeapons(const std::string& catalogName);
};
} // namespace pipeline
} // namespace wowee