From a2a554dff7e0b8bcf8102c0d6e74c3ecdc028ba6 Mon Sep 17 00:00:00 2001 From: Kelsi Date: Wed, 6 May 2026 07:16:27 -0700 Subject: [PATCH] feat(editor): add --info-quests CLI for quests.json summary Completes the --info-* family. Reports total/chained quest counts, reward/item counts, total XP awarded, objective-type breakdown (kill/collect/talk), and any quest-chain validation errors. Lets zone authors spot broken chains, missing rewards, and lopsided XP balance from the command line. --- tools/editor/main.cpp | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/tools/editor/main.cpp b/tools/editor/main.cpp index 387f3ffd..04f683f9 100644 --- a/tools/editor/main.cpp +++ b/tools/editor/main.cpp @@ -2,6 +2,7 @@ #include "content_pack.hpp" #include "npc_spawner.hpp" #include "object_placer.hpp" +#include "quest_editor.hpp" #include "pipeline/wowee_model.hpp" #include "pipeline/wowee_building.hpp" #include "pipeline/wowee_collision.hpp" @@ -30,6 +31,7 @@ static void printUsage(const char* argv0) { std::printf(" --info-wot Print WOT/WHM terrain metadata (tile, chunks, height range) and exit\n"); std::printf(" --info-creatures

Print creatures.json summary (counts, behaviors) and exit\n"); std::printf(" --info-objects

Print objects.json summary (counts, types, scale range) and exit\n"); + std::printf(" --info-quests

Print quests.json summary (counts, rewards, chain errors) and exit\n"); std::printf(" --info-wcp Print WCP archive metadata (name, files) and exit\n"); std::printf(" --version Show version and format info\n\n"); std::printf("Wowee World Editor v1.0.0 — by Kelsi Davis\n"); @@ -96,6 +98,46 @@ int main(int argc, char* argv[]) { std::printf(" total tris : %zu\n", totalIdx / 3); std::printf(" total mats : %zu (across all groups)\n", totalMats); return 0; + } else if (std::strcmp(argv[i], "--info-quests") == 0 && i + 1 < argc) { + std::string path = argv[++i]; + wowee::editor::QuestEditor qe; + if (!qe.loadFromFile(path)) { + std::fprintf(stderr, "Failed to load quests.json: %s\n", path.c_str()); + return 1; + } + const auto& quests = qe.getQuests(); + int chained = 0, withReward = 0, withItems = 0; + int objKill = 0, objCollect = 0, objTalk = 0; + uint32_t totalXp = 0; + for (const auto& q : quests) { + if (q.nextQuestId != 0) chained++; + if (q.reward.xp > 0 || q.reward.gold > 0 || + q.reward.silver > 0 || q.reward.copper > 0) withReward++; + if (!q.reward.itemRewards.empty()) withItems++; + totalXp += q.reward.xp; + using OT = wowee::editor::QuestObjectiveType; + for (const auto& obj : q.objectives) { + if (obj.type == OT::KillCreature) objKill++; + else if (obj.type == OT::CollectItem) objCollect++; + else if (obj.type == OT::TalkToNPC) objTalk++; + } + } + std::vector errors; + qe.validateChains(errors); + std::printf("quests.json: %s\n", path.c_str()); + std::printf(" total : %zu\n", quests.size()); + std::printf(" chained : %d (have nextQuestId)\n", chained); + std::printf(" with reward : %d\n", withReward); + std::printf(" with items : %d\n", withItems); + std::printf(" total XP : %u (avg %.0f per quest)\n", totalXp, + quests.empty() ? 0.0 : double(totalXp) / quests.size()); + std::printf(" objectives : %d kill, %d collect, %d talk\n", + objKill, objCollect, objTalk); + if (!errors.empty()) { + std::printf(" chain errors: %zu\n", errors.size()); + for (const auto& e : errors) std::printf(" - %s\n", e.c_str()); + } + return 0; } else if (std::strcmp(argv[i], "--info-objects") == 0 && i + 1 < argc) { std::string path = argv[++i]; wowee::editor::ObjectPlacer placer;