mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-05-07 09:33:51 +00:00
feat(editor): add --info-creature and --info-quest single-entity inspectors
The --list-* commands give table views; the --info-* (creatures/objects/
quests) give summary counts. Neither shows every field of a single
entry. These fill that gap:
wowee_editor --info-creature $Z/creatures.json 0
Creature [0] 'Captain'
id : 1
displayId : 11430
position : (100.00, 200.00, 50.00)
orientation : 0.00 deg
scale : 1.00
level : 12
health/mana : 100 / 0
damage : 5-10
armor : 0
faction : 0
behavior : stationary
wander rad : 10.0
aggro rad : 20.0
leash rad : 40.0
respawn ms : 300000
patrol points : 0
flags :
wowee_editor --info-quest $Z/quests.json 0
Quest [0] 'Hunt Wolves'
id : 1
required level : 5
giver NPC id : 100
turn-in NPC id : 100
next quest id : 0 (terminal)
reward : 250 XP, 0g 0s 0c, 1 item(s)
item[0] : Item:Sword
objectives : 1
[0] kill ×5 Wolf — Slay 5 Wolf
Useful for digging into 'why is this NPC not behaving like I expect?'
or reviewing one quest's full design in one screen instead of running
3-4 list-* commands. JSON mode emits every field as a structured
record for programmatic consumption.
Inspector lineup is now complete from aggregate to per-entry:
--info-{creatures,objects,quests} (counts)
--list-{creatures,objects,quests} (table)
--info-{creature,quest} (single entry, all fields)
This commit is contained in:
parent
17b83858c1
commit
b7696d1aa9
1 changed files with 193 additions and 0 deletions
|
|
@ -591,6 +591,10 @@ static void printUsage(const char* argv0) {
|
|||
std::printf(" List every objective on a quest (for --remove-quest-objective)\n");
|
||||
std::printf(" --list-quest-rewards <p> <questIdx> [--json]\n");
|
||||
std::printf(" List XP/coin/item rewards on a quest\n");
|
||||
std::printf(" --info-creature <p> <idx> [--json]\n");
|
||||
std::printf(" Print every field for one creature spawn (stats, behavior, AI, flags)\n");
|
||||
std::printf(" --info-quest <p> <idx> [--json]\n");
|
||||
std::printf(" Print every field for one quest (objectives + reward + chain in one shot)\n");
|
||||
std::printf(" --info-wcp <wcp-path> [--json]\n");
|
||||
std::printf(" Print WCP archive metadata (name, files) and exit\n");
|
||||
std::printf(" --list-wcp <wcp-path> Print every file inside a WCP archive (sorted by path) and exit\n");
|
||||
|
|
@ -631,6 +635,7 @@ int main(int argc, char* argv[]) {
|
|||
"--info-zone", "--info-wcp", "--list-wcp",
|
||||
"--list-creatures", "--list-objects", "--list-quests",
|
||||
"--list-quest-objectives", "--list-quest-rewards",
|
||||
"--info-creature", "--info-quest",
|
||||
"--unpack-wcp", "--pack-wcp",
|
||||
"--validate", "--validate-wom", "--validate-wob", "--validate-woc",
|
||||
"--validate-whm", "--validate-all", "--validate-glb", "--info-glb",
|
||||
|
|
@ -2496,6 +2501,194 @@ int main(int argc, char* argv[]) {
|
|||
std::printf(" [%zu] %s\n", k, r.itemRewards[k].c_str());
|
||||
}
|
||||
return 0;
|
||||
} else if (std::strcmp(argv[i], "--info-creature") == 0 && i + 2 < argc) {
|
||||
// Single-creature deep dive — every CreatureSpawn field for
|
||||
// one entry. Companion to --list-creatures (which is a
|
||||
// table view); useful for digging into 'why is this NPC
|
||||
// not behaving like I expect?'.
|
||||
std::string path = argv[++i];
|
||||
std::string idxStr = argv[++i];
|
||||
bool jsonOut = (i + 1 < argc &&
|
||||
std::strcmp(argv[i + 1], "--json") == 0);
|
||||
if (jsonOut) i++;
|
||||
int idx;
|
||||
try { idx = std::stoi(idxStr); }
|
||||
catch (...) {
|
||||
std::fprintf(stderr, "info-creature: bad idx '%s'\n", idxStr.c_str());
|
||||
return 1;
|
||||
}
|
||||
wowee::editor::NpcSpawner sp;
|
||||
if (!sp.loadFromFile(path)) {
|
||||
std::fprintf(stderr, "info-creature: failed to load %s\n", path.c_str());
|
||||
return 1;
|
||||
}
|
||||
if (idx < 0 || idx >= static_cast<int>(sp.spawnCount())) {
|
||||
std::fprintf(stderr,
|
||||
"info-creature: idx %d out of range [0, %zu)\n",
|
||||
idx, sp.spawnCount());
|
||||
return 1;
|
||||
}
|
||||
const auto& s = sp.getSpawns()[idx];
|
||||
using B = wowee::editor::CreatureBehavior;
|
||||
const char* behavior =
|
||||
s.behavior == B::Patrol ? "patrol" :
|
||||
s.behavior == B::Wander ? "wander" : "stationary";
|
||||
if (jsonOut) {
|
||||
nlohmann::json j;
|
||||
j["index"] = idx;
|
||||
j["id"] = s.id;
|
||||
j["name"] = s.name;
|
||||
j["modelPath"] = s.modelPath;
|
||||
j["displayId"] = s.displayId;
|
||||
j["position"] = {s.position.x, s.position.y, s.position.z};
|
||||
j["orientation"] = s.orientation;
|
||||
j["level"] = s.level;
|
||||
j["health"] = s.health;
|
||||
j["mana"] = s.mana;
|
||||
j["minDamage"] = s.minDamage;
|
||||
j["maxDamage"] = s.maxDamage;
|
||||
j["armor"] = s.armor;
|
||||
j["faction"] = s.faction;
|
||||
j["scale"] = s.scale;
|
||||
j["behavior"] = behavior;
|
||||
j["wanderRadius"] = s.wanderRadius;
|
||||
j["aggroRadius"] = s.aggroRadius;
|
||||
j["leashRadius"] = s.leashRadius;
|
||||
j["respawnTimeMs"] = s.respawnTimeMs;
|
||||
j["patrolPoints"] = s.patrolPath.size();
|
||||
j["hostile"] = s.hostile;
|
||||
j["questgiver"] = s.questgiver;
|
||||
j["vendor"] = s.vendor;
|
||||
j["trainer"] = s.trainer;
|
||||
std::printf("%s\n", j.dump(2).c_str());
|
||||
return 0;
|
||||
}
|
||||
std::printf("Creature [%d] '%s'\n", idx, s.name.c_str());
|
||||
std::printf(" id : %u\n", s.id);
|
||||
std::printf(" displayId : %u\n", s.displayId);
|
||||
std::printf(" modelPath : %s\n",
|
||||
s.modelPath.empty() ? "(uses displayId)" : s.modelPath.c_str());
|
||||
std::printf(" position : (%.2f, %.2f, %.2f)\n",
|
||||
s.position.x, s.position.y, s.position.z);
|
||||
std::printf(" orientation : %.2f deg\n", s.orientation);
|
||||
std::printf(" scale : %.2f\n", s.scale);
|
||||
std::printf(" level : %u\n", s.level);
|
||||
std::printf(" health/mana : %u / %u\n", s.health, s.mana);
|
||||
std::printf(" damage : %u-%u\n", s.minDamage, s.maxDamage);
|
||||
std::printf(" armor : %u\n", s.armor);
|
||||
std::printf(" faction : %u\n", s.faction);
|
||||
std::printf(" behavior : %s\n", behavior);
|
||||
std::printf(" wander rad : %.1f\n", s.wanderRadius);
|
||||
std::printf(" aggro rad : %.1f\n", s.aggroRadius);
|
||||
std::printf(" leash rad : %.1f\n", s.leashRadius);
|
||||
std::printf(" respawn ms : %u\n", s.respawnTimeMs);
|
||||
std::printf(" patrol points : %zu\n", s.patrolPath.size());
|
||||
std::printf(" flags : %s%s%s%s\n",
|
||||
s.hostile ? "hostile " : "",
|
||||
s.questgiver ? "questgiver " : "",
|
||||
s.vendor ? "vendor " : "",
|
||||
s.trainer ? "trainer " : "");
|
||||
return 0;
|
||||
} else if (std::strcmp(argv[i], "--info-quest") == 0 && i + 2 < argc) {
|
||||
// Single-quest deep dive — combines what --list-quest-objectives
|
||||
// and --list-quest-rewards show into one view, plus the chain
|
||||
// pointer + descriptions that neither covers.
|
||||
std::string path = argv[++i];
|
||||
std::string idxStr = argv[++i];
|
||||
bool jsonOut = (i + 1 < argc &&
|
||||
std::strcmp(argv[i + 1], "--json") == 0);
|
||||
if (jsonOut) i++;
|
||||
int idx;
|
||||
try { idx = std::stoi(idxStr); }
|
||||
catch (...) {
|
||||
std::fprintf(stderr, "info-quest: bad idx '%s'\n", idxStr.c_str());
|
||||
return 1;
|
||||
}
|
||||
wowee::editor::QuestEditor qe;
|
||||
if (!qe.loadFromFile(path)) {
|
||||
std::fprintf(stderr, "info-quest: failed to load %s\n", path.c_str());
|
||||
return 1;
|
||||
}
|
||||
if (idx < 0 || idx >= static_cast<int>(qe.questCount())) {
|
||||
std::fprintf(stderr,
|
||||
"info-quest: idx %d out of range [0, %zu)\n",
|
||||
idx, qe.questCount());
|
||||
return 1;
|
||||
}
|
||||
const auto& q = qe.getQuests()[idx];
|
||||
using OT = wowee::editor::QuestObjectiveType;
|
||||
auto typeName = [](OT t) {
|
||||
switch (t) {
|
||||
case OT::KillCreature: return "kill";
|
||||
case OT::CollectItem: return "collect";
|
||||
case OT::TalkToNPC: return "talk";
|
||||
case OT::ExploreArea: return "explore";
|
||||
case OT::EscortNPC: return "escort";
|
||||
case OT::UseObject: return "use";
|
||||
}
|
||||
return "?";
|
||||
};
|
||||
if (jsonOut) {
|
||||
nlohmann::json j;
|
||||
j["index"] = idx;
|
||||
j["id"] = q.id;
|
||||
j["title"] = q.title;
|
||||
j["description"] = q.description;
|
||||
j["completionText"] = q.completionText;
|
||||
j["requiredLevel"] = q.requiredLevel;
|
||||
j["questGiverNpcId"] = q.questGiverNpcId;
|
||||
j["turnInNpcId"] = q.turnInNpcId;
|
||||
j["nextQuestId"] = q.nextQuestId;
|
||||
j["reward"] = {
|
||||
{"xp", q.reward.xp},
|
||||
{"gold", q.reward.gold},
|
||||
{"silver", q.reward.silver},
|
||||
{"copper", q.reward.copper},
|
||||
{"items", q.reward.itemRewards}
|
||||
};
|
||||
nlohmann::json objs = nlohmann::json::array();
|
||||
for (const auto& obj : q.objectives) {
|
||||
objs.push_back({
|
||||
{"type", typeName(obj.type)},
|
||||
{"target", obj.targetName},
|
||||
{"count", obj.targetCount},
|
||||
{"description", obj.description}
|
||||
});
|
||||
}
|
||||
j["objectives"] = objs;
|
||||
std::printf("%s\n", j.dump(2).c_str());
|
||||
return 0;
|
||||
}
|
||||
std::printf("Quest [%d] '%s'\n", idx, q.title.c_str());
|
||||
std::printf(" id : %u\n", q.id);
|
||||
std::printf(" required level : %u\n", q.requiredLevel);
|
||||
std::printf(" giver NPC id : %u\n", q.questGiverNpcId);
|
||||
std::printf(" turn-in NPC id : %u\n", q.turnInNpcId);
|
||||
std::printf(" next quest id : %u%s\n", q.nextQuestId,
|
||||
q.nextQuestId == 0 ? " (terminal)" : "");
|
||||
if (!q.description.empty()) {
|
||||
std::printf(" description : %s\n", q.description.c_str());
|
||||
}
|
||||
if (!q.completionText.empty()) {
|
||||
std::printf(" completion text : %s\n", q.completionText.c_str());
|
||||
}
|
||||
std::printf(" reward : %u XP, %ug %us %uc, %zu item(s)\n",
|
||||
q.reward.xp, q.reward.gold, q.reward.silver,
|
||||
q.reward.copper, q.reward.itemRewards.size());
|
||||
for (size_t k = 0; k < q.reward.itemRewards.size(); ++k) {
|
||||
std::printf(" item[%zu] : %s\n", k,
|
||||
q.reward.itemRewards[k].c_str());
|
||||
}
|
||||
std::printf(" objectives : %zu\n", q.objectives.size());
|
||||
for (size_t k = 0; k < q.objectives.size(); ++k) {
|
||||
const auto& o = q.objectives[k];
|
||||
std::printf(" [%zu] %-7s ×%u %s%s%s\n",
|
||||
k, typeName(o.type), o.targetCount,
|
||||
o.targetName.c_str(),
|
||||
o.description.empty() ? "" : " — ",
|
||||
o.description.c_str());
|
||||
}
|
||||
return 0;
|
||||
} else if (std::strcmp(argv[i], "--diff-wcp") == 0 && i + 2 < argc) {
|
||||
// Print which files differ between two WCP archives. Useful
|
||||
// when verifying that an authoring tweak only changed what
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue