feat(editor): add WACT (Action Bar Layout) open catalog format

Open replacement for the hardcoded per-class default action bar
bindings. Defines which abilities auto-populate which action
button slots when a new character is created or a class is
reset. A Warrior's button 1 binds Heroic Strike, button 2
Charge, button 3 Rend, etc. — new characters of that class get
those buttons pre-populated so the action bar isn't empty on
first login.

Distinct from WKBD (Keybindings) which maps physical keys to
action button slots — WACT maps action button slots to
abilities. The two together complete the default-control
configuration: Key 1 -> Action Slot 1 (WKBD) -> Heroic Strike
(WACT).

Seven barMode values cover the major action bar contexts:
  - Main (slots 0-11, standard 12-button bar)
  - Pet (hunter/warlock pet action bar)
  - Vehicle (mounted/vehicle action bar)
  - Stance1/2/3 (warrior battle/defensive/berserker; druid
    bear/cat/tree)
  - Custom (server-custom bar overlay)

Cross-references back to WCHC (classMask layout), WSPL (spellId
for the bound ability), and WIT (itemId for item-macro bindings
like Hearthstone in slot 12). findByClass(classBit, barMode)
returns the bindings sorted by buttonSlot — used directly by
character creation to populate action bars.

Three preset emitters: --gen-act (10 Warrior starter bindings on
Main bar with canonical 3.3.5a abilities), --gen-act-mage (10
Mage starter bindings including Counterspell + Polymorph),
--gen-act-pet (10 Hunter pet-bar bindings using barMode=Pet for
Attack/Stance/Bite/Claw/Dismiss).

Validation enforces id+name+classMask presence, barMode 0..6,
no duplicate ids; warns on:
  - buttonSlot > 143 (max is 12 bars × 12 slots = 144)
  - both spellId and itemId set (engine prefers spellId, item
    is silently ignored)
  - both spellId=0 AND itemId=0 (button will render empty)
  - (classMask + barMode + buttonSlot) collisions for
    overlapping classes — multiple bindings fighting for the
    same physical slot

Wired through the cross-format table; WACT appears in all 18
cross-format utilities. Format count 94 -> 95; CLI flag count
1083 -> 1088.
This commit is contained in:
Kelsi 2026-05-10 00:11:53 -07:00
parent 48ca202716
commit 48dbf72f11
10 changed files with 692 additions and 0 deletions

View file

@ -0,0 +1,117 @@
#pragma once
#include <cstdint>
#include <string>
#include <vector>
namespace wowee {
namespace pipeline {
// Wowee Open Action Bar Layout catalog (.wact) — novel
// replacement for the hardcoded per-class default action
// bar bindings in the WoW client. Defines which abilities
// auto-populate which action button slots when a new
// character is created or a class is reset.
//
// Each entry binds one (classMask, buttonSlot) pair to a
// spell or item. A Warrior's button 1 might bind Heroic
// Strike, button 2 Charge, button 3 Battle Shout, etc.
// New characters of that class get those buttons pre-
// populated so the action bar isn't empty on first login.
//
// Distinct from WKBD (Keybindings) which maps physical
// keys to action button slots — WACT maps action button
// slots to abilities. The two together complete the
// default-control configuration: Key 1 -> Action Slot 1
// (WKBD) -> Heroic Strike (WACT).
//
// Cross-references with previously-added formats:
// WCHC: classMask uses the same bit layout as WCHC
// class IDs (Warrior=0x01, Paladin=0x02, ...).
// WSPL: spellId references the WSPL spell entry that
// the button casts when triggered.
// WIT: itemId references a WIT item entry for item
// macro bindings (Hearthstone in slot 12, etc.).
//
// Binary layout (little-endian):
// magic[4] = "WACT"
// version (uint32) = current 1
// nameLen + name (catalog label)
// entryCount (uint32)
// entries (each):
// bindingId (uint32)
// nameLen + name
// descLen + description
// classMask (uint32)
// spellId (uint32)
// itemId (uint32)
// buttonSlot (uint8) / barMode (uint8) / pad[2]
// iconColorRGBA (uint32)
struct WoweeActionBar {
enum BarMode : uint8_t {
Main = 0, // standard 12-button main bar (slots 0-11)
Pet = 1, // hunter/warlock pet action bar
Vehicle = 2, // mounted/vehicle action bar
Stance1 = 3, // warrior battle / druid bear stance
Stance2 = 4, // warrior defensive / druid cat
Stance3 = 5, // warrior berserker / druid tree
Custom = 6, // server-custom bar overlay
};
struct Entry {
uint32_t bindingId = 0;
std::string name;
std::string description;
uint32_t classMask = 0;
uint32_t spellId = 0;
uint32_t itemId = 0; // 0 if spell-only
uint8_t buttonSlot = 0; // 0..143 (12 bars × 12 slots)
uint8_t barMode = Main;
uint8_t pad0 = 0;
uint8_t pad1 = 0;
uint32_t iconColorRGBA = 0xFFFFFFFFu;
};
std::string name;
std::vector<Entry> entries;
bool isValid() const { return !entries.empty(); }
const Entry* findById(uint32_t bindingId) const;
// Return all entries for a given class on a specific
// bar mode, in buttonSlot order. Used by character
// creation to populate the action bar with defaults.
std::vector<const Entry*> findByClass(uint32_t classBit,
uint8_t barMode) const;
static const char* barModeName(uint8_t m);
};
class WoweeActionBarLoader {
public:
static bool save(const WoweeActionBar& cat,
const std::string& basePath);
static WoweeActionBar load(const std::string& basePath);
static bool exists(const std::string& basePath);
// Preset emitters used by --gen-act* variants.
//
// makeWarrior — 10 Warrior starter bindings on the
// Main bar (Heroic Strike, Charge,
// Rend, Thunder Clap, Battle Shout,
// Sunder Armor, Mocking Blow, etc).
// makeMage — 10 Mage starter bindings on the Main
// bar (Fireball, Frostbolt, Frost
// Nova, Polymorph, Mage Armor, etc).
// makeHunterPet — 10 Hunter Pet-bar bindings using
// barMode=Pet (Attack, Follow, Stay,
// Aggressive/Defensive/Passive
// stances, Bite, Claw, etc).
static WoweeActionBar makeWarrior(const std::string& catalogName);
static WoweeActionBar makeMage(const std::string& catalogName);
static WoweeActionBar makeHunterPet(const std::string& catalogName);
};
} // namespace pipeline
} // namespace wowee