Kelsidavis-WoWee/include/pipeline/wowee_gossip.hpp
Kelsi 2de08a3fd0 feat(pipeline): add WGSP (Wowee Gossip Menu) format
Novel open replacement for AzerothCore-style gossip_menu +
gossip_menu_option + npc_text SQL tables PLUS the Blizzard
NpcText.dbc family. The 23rd open format added to the
editor.

An NPC's dialogue tree: a menu of options the player can
pick from when right-clicking the NPC. Each option may
bridge to another menu, trigger a vendor / trainer
interaction, offer a quest, etc. The simplified per-option
model (kind + actionTarget + flags + moneyCost) covers the
common cases without needing separate npc_text condition
tables.

Closes a major cross-format gap: WCRT.entry.gossipId has
existed since batch 116 (when WCRT was added) but pointed
to a format that didn't exist yet. The innkeeper preset's
menuId=4001 deliberately matches WCRT's Bartleby NPC so
the demo content stack can wire WCRT.gossipId = 4001 once
that field is plumbed through the runtime.

Cross-references:
  WCRT.entry.gossipId        -> WGSP.entry.menuId
  WGSP.option.actionTarget (Submenu) -> WGSP.entry.menuId
  WGSP.option.actionTarget (Vendor / Trainer)
                              -> WTRN.entry.npcId
  WGSP.option.actionTarget (Quest)  -> WQT.entry.questId

Format:
  • magic "WGSP", version 1, little-endian
  • per menu: menuId / titleText + options[]
  • per option: optionId / text / kind / actionTarget /
    requiredFlags / moneyCostCopper

Enums:
  • OptionKind (13): Close / Submenu / Vendor / Trainer /
                     Quest / Tabard / Banker / Innkeeper /
                     FlightMaster / TextOnly / Script /
                     Battlemaster / Auctioneer
  • OptionFlags:    AllianceOnly / HordeOnly / Coinpouch /
                     QuestGated / Closes

API: WoweeGossipLoader::save / load / exists / findById;
presets makeStarter (1 menu with vendor + trainer + close),
makeInnkeeper (2-menu tree: main menu 4001 with hearth /
vendor / flight / submenu options + lore submenu 4002 that
links back), makeQuestGiver (1 menu with 2 quest options
referencing WQT 1 and 100, plus a paid respec script
exercising the Coinpouch flag with a 10g cost).

CLI added (5 flags, 558 documented total now):
  --gen-gossip / --gen-gossip-innkeeper / --gen-gossip-questgiver
  --info-wgsp / --validate-wgsp

Validator catches: menuId=0 + duplicates, empty title /
options, unknown option kind, empty option text, Submenu
options pointing at non-existent menuIds (intra-format
cross-reference resolution), Coinpouch flag without
moneyCost (misleading UI), AllianceOnly+HordeOnly conflict.
2026-05-09 16:20:07 -07:00

123 lines
4.3 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#pragma once
#include <cstdint>
#include <string>
#include <vector>
namespace wowee {
namespace pipeline {
// Wowee Open Gossip Menu catalog (.wgsp) — novel replacement
// for AzerothCore-style gossip_menu + gossip_menu_option +
// npc_text SQL tables PLUS the Blizzard NpcText.dbc family.
// The 23rd open format added to the editor.
//
// An NPC's dialogue tree: a menu of options the player can
// pick from when right-clicking the NPC. Each option may
// bridge to another menu, trigger a vendor / trainer
// interaction, offer a quest, etc.
//
// This format closes the WCRT.gossipId cross-reference gap
// from batch 116 — until now WCRT had a gossipId field that
// pointed to a format that didn't exist yet.
//
// Cross-references with previously-added formats:
// WCRT.entry.gossipId → WGSP.entry.menuId
// WGSP.option.actionTarget (kind=Submenu) → WGSP.entry.menuId
// (intra-format chain)
// WGSP.option.actionTarget (kind=Vendor / Trainer)
// → WTRN.entry.npcId
// WGSP.option.actionTarget (kind=Quest) → WQT.entry.questId
//
// Binary layout (little-endian):
// magic[4] = "WGSP"
// version (uint32) = current 1
// nameLen + name (catalog label)
// entryCount (uint32)
// entries (each):
// menuId (uint32)
// titleLen + titleText
// optionCount (uint8) + pad[3]
// options (optionCount × {
// optionId (uint32)
// textLen + text
// kind (uint8) + pad[3]
// actionTarget (uint32)
// requiredFlags (uint32)
// moneyCostCopper (uint32)
// })
struct WoweeGossip {
enum OptionKind : uint8_t {
Close = 0, // closes the menu, no action
Submenu = 1, // jumps to another menuId
Vendor = 2, // opens vendor inventory window
Trainer = 3, // opens trainer spell window
Quest = 4, // opens quest dialog
Tabard = 5, // opens tabard customization
Banker = 6, // opens bank
Innkeeper = 7, // sets hearth + opens vendor
FlightMaster = 8, // opens taxi node
TextOnly = 9, // dialogue only, no action
Script = 10, // triggers a server-side script
Battlemaster = 11,
Auctioneer = 12,
};
enum OptionFlags : uint32_t {
AllianceOnly = 0x01,
HordeOnly = 0x02,
Coinpouch = 0x04, // shows the coin icon when paid
QuestGated = 0x08, // visible only with matching quest
Closes = 0x10, // closes the menu after the action
};
struct Option {
uint32_t optionId = 0;
std::string text;
uint8_t kind = TextOnly;
uint32_t actionTarget = 0; // submenu / NPC / quest id
uint32_t requiredFlags = 0;
uint32_t moneyCostCopper = 0;
};
struct Entry {
uint32_t menuId = 0;
std::string titleText;
std::vector<Option> options;
};
std::string name;
std::vector<Entry> entries;
bool isValid() const { return !entries.empty(); }
// Lookup by menuId — nullptr if not present.
const Entry* findById(uint32_t menuId) const;
static const char* optionKindName(uint8_t k);
};
class WoweeGossipLoader {
public:
static bool save(const WoweeGossip& cat,
const std::string& basePath);
static WoweeGossip load(const std::string& basePath);
static bool exists(const std::string& basePath);
// Preset emitters used by --gen-gossip* variants.
//
// makeStarter — single menu with greeting + 3 options
// (vendor / trainer / close).
// makeInnkeeper — menu 4001 (matches WCRT.gossipId on
// Bartleby): set hearth + browse goods
// + bind to flight + close.
// makeQuestGiver — branching menu: greeting + 2 quests +
// submenu "tell me about the area"
// leading to lore text + close.
static WoweeGossip makeStarter(const std::string& catalogName);
static WoweeGossip makeInnkeeper(const std::string& catalogName);
static WoweeGossip makeQuestGiver(const std::string& catalogName);
};
} // namespace pipeline
} // namespace wowee