mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-05-10 02:53:51 +00:00
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.
This commit is contained in:
parent
929693405e
commit
5ea1f7ee2a
8 changed files with 843 additions and 0 deletions
150
include/pipeline/wowee_spells.hpp
Normal file
150
include/pipeline/wowee_spells.hpp
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace wowee {
|
||||
namespace pipeline {
|
||||
|
||||
// Wowee Open Spell Catalog (.wspl) — novel replacement for
|
||||
// Blizzard's Spell.dbc + SpellEffect.dbc + the AzerothCore-
|
||||
// style spell_dbc / spell_proc tables. The 20th open format
|
||||
// added to the editor.
|
||||
//
|
||||
// Each entry holds the metadata side of a spell: name,
|
||||
// description, school, range, mana cost, 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.entry.equippedMain (item with on-use) → WIT → WSPL
|
||||
//
|
||||
// Binary layout (little-endian):
|
||||
// magic[4] = "WSPL"
|
||||
// version (uint32) = current 1
|
||||
// nameLen + name (catalog label)
|
||||
// entryCount (uint32)
|
||||
// entries (each):
|
||||
// spellId (uint32)
|
||||
// nameLen + name
|
||||
// descLen + description
|
||||
// iconLen + iconPath
|
||||
// school (uint8) / targetType (uint8) / effectKind (uint8) / pad
|
||||
// castTimeMs (uint32)
|
||||
// cooldownMs (uint32)
|
||||
// gcdMs (uint32)
|
||||
// manaCost (uint32)
|
||||
// rangeMin (float)
|
||||
// rangeMax (float)
|
||||
// minLevel (uint16) / maxStacks (uint16)
|
||||
// durationMs (int32) -- -1 = permanent, 0 = instant
|
||||
// effectValueMin (int32)
|
||||
// effectValueMax (int32)
|
||||
// effectMisc (int32)
|
||||
// flags (uint32)
|
||||
struct WoweeSpell {
|
||||
enum School : uint8_t {
|
||||
SchoolPhysical = 0,
|
||||
SchoolHoly = 1,
|
||||
SchoolFire = 2,
|
||||
SchoolNature = 3,
|
||||
SchoolFrost = 4,
|
||||
SchoolShadow = 5,
|
||||
SchoolArcane = 6,
|
||||
};
|
||||
|
||||
enum TargetType : uint8_t {
|
||||
TargetSelf = 0,
|
||||
TargetSingle = 1,
|
||||
TargetCone = 2,
|
||||
TargetAoeFromSelf = 3,
|
||||
TargetLine = 4,
|
||||
TargetGround = 5,
|
||||
};
|
||||
|
||||
enum EffectKind : uint8_t {
|
||||
EffectDamage = 0,
|
||||
EffectHeal = 1,
|
||||
EffectBuff = 2,
|
||||
EffectDebuff = 3,
|
||||
EffectTeleport = 4,
|
||||
EffectSummon = 5,
|
||||
EffectDispel = 6,
|
||||
};
|
||||
|
||||
enum Flags : uint32_t {
|
||||
Passive = 0x01,
|
||||
Hidden = 0x02, // not shown in spellbook
|
||||
Channeled = 0x04,
|
||||
Ranged = 0x08,
|
||||
AreaOfEffect = 0x10,
|
||||
Triggered = 0x20, // no mana cost, no GCD
|
||||
UnitTargetOnly = 0x40,
|
||||
FriendlyOnly = 0x80,
|
||||
HostileOnly = 0x100,
|
||||
};
|
||||
|
||||
struct Entry {
|
||||
uint32_t spellId = 0;
|
||||
std::string name;
|
||||
std::string description;
|
||||
std::string iconPath;
|
||||
uint8_t school = SchoolPhysical;
|
||||
uint8_t targetType = TargetSelf;
|
||||
uint8_t effectKind = EffectDamage;
|
||||
uint32_t castTimeMs = 0;
|
||||
uint32_t cooldownMs = 0;
|
||||
uint32_t gcdMs = 1500; // canonical 1.5s GCD default
|
||||
uint32_t manaCost = 0;
|
||||
float rangeMin = 0.0f;
|
||||
float rangeMax = 5.0f; // melee range default
|
||||
uint16_t minLevel = 1;
|
||||
uint16_t maxStacks = 1;
|
||||
int32_t durationMs = 0; // 0 = instant, -1 = permanent
|
||||
int32_t effectValueMin = 0;
|
||||
int32_t effectValueMax = 0;
|
||||
int32_t effectMisc = 0;
|
||||
uint32_t flags = 0;
|
||||
};
|
||||
|
||||
std::string name;
|
||||
std::vector<Entry> entries;
|
||||
|
||||
bool isValid() const { return !entries.empty(); }
|
||||
|
||||
// Lookup by spellId — nullptr if not present.
|
||||
const Entry* findById(uint32_t spellId) const;
|
||||
|
||||
static const char* schoolName(uint8_t s);
|
||||
static const char* targetTypeName(uint8_t t);
|
||||
static const char* effectKindName(uint8_t e);
|
||||
};
|
||||
|
||||
class WoweeSpellLoader {
|
||||
public:
|
||||
static bool save(const WoweeSpell& cat,
|
||||
const std::string& basePath);
|
||||
static WoweeSpell load(const std::string& basePath);
|
||||
static bool exists(const std::string& basePath);
|
||||
|
||||
// Preset emitters used by --gen-spells* variants.
|
||||
//
|
||||
// makeStarter — 4 demo spells covering damage / heal /
|
||||
// buff / teleport effect kinds.
|
||||
// makeMage — frost bolt + fireball + arcane intellect
|
||||
// + blink — classic mage starter rotation.
|
||||
// makeWarrior — mortal strike + shield bash + battle shout
|
||||
// + heroic strike — classic warrior toolkit.
|
||||
static WoweeSpell makeStarter(const std::string& catalogName);
|
||||
static WoweeSpell makeMage(const std::string& catalogName);
|
||||
static WoweeSpell makeWarrior(const std::string& catalogName);
|
||||
};
|
||||
|
||||
} // namespace pipeline
|
||||
} // namespace wowee
|
||||
Loading…
Add table
Add a link
Reference in a new issue