mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-05-10 02:53:51 +00:00
feat(pipeline): add WQT (Wowee Quest Template) format
Novel open replacement for AzerothCore-style quest_template
SQL tables PLUS the Blizzard Quest.dbc / QuestObjective.dbc
trio. The 15th open format added to the editor — and the
last gameplay-graph piece the catalog needed.
Cross-references with previously-added formats:
WQT.giverCreatureId -> WCRT.entry.creatureId
WQT.turninCreatureId -> WCRT.entry.creatureId
WQT.objective.targetId -> WCRT (kill) / WIT (collect) /
WOB (interact)
WQT.rewardItem.itemId -> WIT.entry.itemId
WQT.prevQuestId -> WQT.entry.questId (intra-format)
WQT.nextQuestId -> WQT.entry.questId
Together with WIT / WCRT / WLOT / WSPN / WOMX / WOL / WOW /
WSND, a content pack can now ship a complete RPG zone
(terrain + props + atmosphere + sounds + creatures + items
+ loot + spawns + quests) entirely in open formats with no
SQL or .dbc dependencies. 15 of 15 expected slots filled.
Format:
• magic "WQTM", version 1, little-endian
• per quest: questId / title / objective / description /
minLevel..maxLevel + questLevel / requiredClass+RaceMask /
prev+nextQuestId / giver+turninCreatureId /
objectives[] / xpReward + moneyCopperReward /
rewardItems[] / flags
Per-objective:
kind (kill/collect/interact/visit/escort/cast),
targetId, quantity
Per-reward:
itemId, qty, pickFlags (AutoGiven / PlayerChoice)
Quest flags: Daily / Weekly / Raid / Group / AutoComplete /
AutoAccept / Repeatable / ClassQuest / Pvp
API: WoweeQuestLoader::save / load / exists / findById;
presets makeStarter (1 simple kill quest, references the
bandit creatureId=1000), makeChain (3-quest chain with
prev/next links + AutoComplete bridge + player-choice
rewards), makeDaily (Daily+Repeatable+AutoAccept combo).
CLI added (5 flags, 500 documented total — round milestone):
--gen-quests / --gen-quests-chain / --gen-quests-daily
--info-wqt / --validate-wqt
Validator catches: questId=0+duplicates, level=0,
maxLevel<minLevel, empty title, no objectives without
AutoComplete (player can't finish), no rewards at all,
Daily without Repeatable (incoherent), targetId=0,
quantity=0, unknown objective kind, reward itemId=0 or qty=0.
The 3-quest chain demo exercises every major feature:
• multiple objective kinds (visit / collect / kill)
• prev/next chain links
• AutoComplete dialogue-bridge quest
• PlayerChoice reward (1 of 2 weapons)
This commit is contained in:
parent
24bc52ab11
commit
02ae17740e
8 changed files with 842 additions and 1 deletions
153
include/pipeline/wowee_quests.hpp
Normal file
153
include/pipeline/wowee_quests.hpp
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace wowee {
|
||||
namespace pipeline {
|
||||
|
||||
// Wowee Open Quest Template (.wqt) — novel replacement for
|
||||
// AzerothCore-style quest_template SQL tables PLUS the
|
||||
// Blizzard Quest.dbc / QuestObjective.dbc trio. The 15th
|
||||
// open format added to the editor.
|
||||
//
|
||||
// Cross-references with previously-added formats:
|
||||
// WQT.giverCreatureId → WCRT.entry.creatureId
|
||||
// WQT.turninCreatureId → WCRT.entry.creatureId
|
||||
// WQT.objective.targetId → WCRT (kill) / WIT (collect) / WOB (interact)
|
||||
// WQT.rewardItem.itemId → WIT.entry.itemId
|
||||
// WQT.prevQuestId → WQT.entry.questId (intra-format chain)
|
||||
// WQT.nextQuestId → WQT.entry.questId
|
||||
//
|
||||
// Together with WIT / WCRT / WLOT / WSPN this completes the
|
||||
// gameplay graph: a content pack can ship items + creatures
|
||||
// + spawns + loot tables + quests with no SQL or .dbc files.
|
||||
//
|
||||
// Binary layout (little-endian):
|
||||
// magic[4] = "WQTM"
|
||||
// version (uint32) = current 1
|
||||
// nameLen + name (catalog label)
|
||||
// entryCount (uint32)
|
||||
// entries (each):
|
||||
// questId (uint32)
|
||||
// titleLen + title
|
||||
// objectiveLen + objective -- 1-line "Kill 10 wolves"
|
||||
// descriptionLen + description -- flavor text
|
||||
// minLevel (uint16) / questLevel (uint16) / maxLevel (uint16) / pad
|
||||
// requiredClassMask (uint32) -- bitmask of class IDs; 0 = any
|
||||
// requiredRaceMask (uint32)
|
||||
// prevQuestId (uint32) -- 0 = chain start
|
||||
// nextQuestId (uint32)
|
||||
// giverCreatureId (uint32)
|
||||
// turninCreatureId (uint32)
|
||||
// objectiveCount (uint8) + pad[3]
|
||||
// objectives (objectiveCount × {
|
||||
// kind (uint8) + pad[3]
|
||||
// targetId (uint32)
|
||||
// quantity (uint16) + pad[2]
|
||||
// })
|
||||
// xpReward (uint32)
|
||||
// moneyCopperReward (uint32)
|
||||
// rewardItemCount (uint8) + pad[3]
|
||||
// rewardItems (rewardItemCount × {
|
||||
// itemId (uint32)
|
||||
// qty (uint8) + pickFlags (uint8) + pad[2]
|
||||
// })
|
||||
// flags (uint32)
|
||||
struct WoweeQuest {
|
||||
enum ObjectiveKind : uint8_t {
|
||||
KillCreature = 0,
|
||||
CollectItem = 1,
|
||||
InteractObject = 2,
|
||||
VisitArea = 3,
|
||||
EscortNpc = 4,
|
||||
SpellCast = 5,
|
||||
};
|
||||
|
||||
enum Flags : uint32_t {
|
||||
Daily = 0x01,
|
||||
Weekly = 0x02,
|
||||
Raid = 0x04,
|
||||
Group = 0x08, // requires party / not solo-completable
|
||||
AutoComplete = 0x10, // turns in immediately on objective met
|
||||
AutoAccept = 0x20, // accepts on giver-NPC interaction
|
||||
Repeatable = 0x40,
|
||||
ClassQuest = 0x80,
|
||||
Pvp = 0x100,
|
||||
};
|
||||
|
||||
enum RewardPickFlags : uint8_t {
|
||||
AutoGiven = 0x01, // always handed out on turn-in
|
||||
PlayerChoice = 0x02, // player picks from a list at turn-in
|
||||
};
|
||||
|
||||
struct Objective {
|
||||
uint8_t kind = KillCreature;
|
||||
uint32_t targetId = 0;
|
||||
uint16_t quantity = 1;
|
||||
};
|
||||
|
||||
struct RewardItem {
|
||||
uint32_t itemId = 0;
|
||||
uint8_t qty = 1;
|
||||
uint8_t pickFlags = AutoGiven;
|
||||
};
|
||||
|
||||
struct Entry {
|
||||
uint32_t questId = 0;
|
||||
std::string title;
|
||||
std::string objective;
|
||||
std::string description;
|
||||
uint16_t minLevel = 1;
|
||||
uint16_t questLevel = 1;
|
||||
uint16_t maxLevel = 0; // 0 = no upper cap
|
||||
uint32_t requiredClassMask = 0;
|
||||
uint32_t requiredRaceMask = 0;
|
||||
uint32_t prevQuestId = 0;
|
||||
uint32_t nextQuestId = 0;
|
||||
uint32_t giverCreatureId = 0;
|
||||
uint32_t turninCreatureId = 0;
|
||||
std::vector<Objective> objectives;
|
||||
uint32_t xpReward = 0;
|
||||
uint32_t moneyCopperReward = 0;
|
||||
std::vector<RewardItem> rewardItems;
|
||||
uint32_t flags = 0;
|
||||
};
|
||||
|
||||
std::string name;
|
||||
std::vector<Entry> entries;
|
||||
|
||||
bool isValid() const { return !entries.empty(); }
|
||||
|
||||
// Lookup by questId — nullptr if not present.
|
||||
const Entry* findById(uint32_t questId) const;
|
||||
|
||||
static const char* objectiveKindName(uint8_t k);
|
||||
};
|
||||
|
||||
class WoweeQuestLoader {
|
||||
public:
|
||||
static bool save(const WoweeQuest& cat,
|
||||
const std::string& basePath);
|
||||
static WoweeQuest load(const std::string& basePath);
|
||||
static bool exists(const std::string& basePath);
|
||||
|
||||
// Preset emitters used by --gen-quests* variants.
|
||||
//
|
||||
// makeStarter — 1 short kill quest: "Kill 10 bandits" with
|
||||
// XP + small money reward. Cross-references
|
||||
// WCRT bandit (creatureId=1000) + WCRT
|
||||
// village innkeeper (giver/turnin=4001).
|
||||
// makeChain — 3-quest chain: "Investigate" -> "Recover"
|
||||
// -> "Report Back". Each quest's nextQuestId
|
||||
// points to the next; the third closes the loop.
|
||||
// makeDaily — 1 daily repeatable quest with the Daily +
|
||||
// Repeatable + AutoAccept flag combo.
|
||||
static WoweeQuest makeStarter(const std::string& catalogName);
|
||||
static WoweeQuest makeChain(const std::string& catalogName);
|
||||
static WoweeQuest makeDaily(const std::string& catalogName);
|
||||
};
|
||||
|
||||
} // namespace pipeline
|
||||
} // namespace wowee
|
||||
Loading…
Add table
Add a link
Reference in a new issue