Kelsidavis-WoWee/include/pipeline/wowee_quest_graph.hpp
Kelsi 76cda20297 feat(pipeline): WQGR quest graph catalog (132nd open format)
Novel representation of quest-chain dependencies that vanilla
WoW carried implicitly in QuestRelations.dbc (the prequest
column) + per-quest server scripts. Each WQGR entry binds one
quest to its display name, level/class/race gating,
prerequisite quest list (must be completed first), follow-up
quest hints (next-quest suggestions for the journal UI), and
quest type flags (Normal / Daily / Repeatable / Group / Raid).

Three presets:
  --gen-qgr-starter   5-quest linear chain (Northshire human-
                      starter Q100..Q104, levels 1..8) with
                      chainHeadHint=1 on Q100
  --gen-qgr-branched  4-quest converging DAG (Q200 unlocks
                      both Q201 + Q202, both required for Q203)
                      — demonstrates true DAG semantics, not
                      just linear lists
  --gen-qgr-dailies   3 standalone daily quests (Daily type,
                      no prereqs, no followups)

Validator catches: id+name required, questType 0..4,
factionAccess 0..3, maxLevel >= minLevel, no self-prereq
(catch-22), no missing prereq questId, full DFS cycle detection
on prevQuestIds (progression deadlock — quests would be
unreachable). Reuses the proven cycle-extraction pattern from
WMOD addon manifest (extracts back-edge path so the editor sees
the loop). Warns on followup hint to self/missing-id (advisory
only — followups are hints not contracts) and on
chainHeadHint=1 with non-empty prereqs (contradicts chain-head
semantics).

Format count 131 -> 132. CLI flag count 1382 -> 1389.
2026-05-10 04:22:13 -07:00

152 lines
5.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 Quest Graph catalog (.wqgr) — novel
// representation of quest-chain dependencies that
// vanilla WoW carried implicitly in
// QuestRelations.dbc (the prequest column) +
// per-quest server scripts. Each WQGR entry binds
// one quest to its display name, level/class/race
// gating, prerequisite quest list (must be
// completed first), follow-up quest hints (next-
// quest suggestions for the journal UI), and quest
// type flags (Normal / Daily / Repeatable / Group /
// Raid).
//
// The variable-length prereq array gives the
// validator something interesting to check: a DFS
// cycle detector flags player-unreachable quests
// (Q1 prereq=Q2, Q2 prereq=Q3, Q3 prereq=Q1 is a
// progression deadlock — no player could ever
// satisfy the cycle).
//
// Cross-references with previously-added formats:
// WQTM: questId references the WQTM quest catalog
// (the actual quest objectives + rewards
// live in WQTM; WQGR only describes the
// dependency graph between them).
// WMS: zoneId references the WMS map catalog.
//
// Binary layout (little-endian):
// magic[4] = "WQGR"
// version (uint32) = current 1
// nameLen + name (catalog label)
// entryCount (uint32)
// entries (each):
// questId (uint32)
// nameLen + name
// minLevel (uint8)
// maxLevel (uint8) — 0 = no upper gate
// questType (uint8) — 0=Normal /
// 1=Daily /
// 2=Repeatable /
// 3=Group /
// 4=Raid
// factionAccess (uint8) — 0=Both /
// 1=Alliance /
// 2=Horde /
// 3=Neutral
// classRestriction (uint16) — bitmask of allowed
// classIds (0 =
// no restriction)
// raceRestriction (uint16) — bitmask of allowed
// raceIds (0 =
// no restriction)
// zoneId (uint32)
// chainHeadHint (uint8) — 0/1 bool — first
// quest in a chain
// (UI sort hint)
// pad0 (uint8)
// pad1 (uint16)
// prevCount (uint32) — prereq array
// prevQuestIds (uint32 × count)
// followupCount (uint32) — hint array
// followupQuestIds (uint32 × count)
struct WoweeQuestGraph {
enum QuestType : uint8_t {
Normal = 0,
Daily = 1,
Repeatable = 2,
Group = 3,
Raid = 4,
};
enum FactionAccess : uint8_t {
Both = 0,
Alliance = 1,
Horde = 2,
Neutral = 3,
};
struct Entry {
uint32_t questId = 0;
std::string name;
uint8_t minLevel = 0;
uint8_t maxLevel = 0;
uint8_t questType = Normal;
uint8_t factionAccess = Both;
uint16_t classRestriction = 0;
uint16_t raceRestriction = 0;
uint32_t zoneId = 0;
uint8_t chainHeadHint = 0;
uint8_t pad0 = 0;
uint16_t pad1 = 0;
std::vector<uint32_t> prevQuestIds;
std::vector<uint32_t> followupQuestIds;
};
std::string name;
std::vector<Entry> entries;
bool isValid() const { return !entries.empty(); }
const Entry* findById(uint32_t questId) const;
// Returns all quests that have the given questId
// as a prereq (the "what unlocks once I finish
// this" lookup — used by the journal UI's
// "completing this opens" panel).
std::vector<const Entry*> findUnlocksFrom(uint32_t questId) const;
// Returns all quests in a zone — used by the
// zone-detail UI to populate the per-zone quest
// list.
std::vector<const Entry*> findByZone(uint32_t zoneId) const;
};
class WoweeQuestGraphLoader {
public:
static bool save(const WoweeQuestGraph& cat,
const std::string& basePath);
static WoweeQuestGraph load(const std::string& basePath);
static bool exists(const std::string& basePath);
// Preset emitters used by --gen-qgr* variants.
//
// makeStarterChain — 5-quest linear chain
// (Northshire human starter
// Q1->Q2->Q3->Q4->Q5).
// Q1 has chainHeadHint=1.
// Levels 1..5.
// makeBranchedChain — 4-quest converging chain
// (Q1 -> Q2a, Q1 -> Q2b,
// both -> Q3). Demonstrates
// DAG semantics not just
// a linear list.
// makeDailies — 3 standalone daily quests
// (Daily type, no prereqs,
// no follow-ups). Baseline
// empty-deps path.
static WoweeQuestGraph makeStarterChain(const std::string& catalogName);
static WoweeQuestGraph makeBranchedChain(const std::string& catalogName);
static WoweeQuestGraph makeDailies(const std::string& catalogName);
};
} // namespace pipeline
} // namespace wowee