mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-05-09 18:43:51 +00:00
feat(editor): add --clone-quest for templating quests with shared shape
Common designer workflow: build a base quest with objectives + rewards
once, then make N variants ('Slay Wolves' / 'Slay Bears' / 'Slay
Tigers') with the same shape. Doing this through individual --add-*
commands means re-typing all objectives + items each time. --clone-quest
deep-copies an existing quest in one shot:
wowee_editor --clone-quest $Z 0 # 'Foo' -> 'Foo (copy)'
wowee_editor --clone-quest $Z 0 'Slay Bears' # custom title
Carries:
- All objectives (deep copy via vector value-copy)
- All item rewards
- XP / coin reward fields
- requiredLevel, giver, turnIn
Resets:
- id (set to 0; addQuest auto-assigns a fresh one)
- nextQuestId (cleared — chaining the clone to the same next quest
would corrupt chain semantics; user can re-set it explicitly)
Verified: scaffolded zone, added quest with 2 objectives + 1 item +
xp=250. Cloned twice (default name, custom name). Result: 3 quests
in list, both clones have full objective list and reward intact.
This commit is contained in:
parent
b6ce6b4fe9
commit
2c41f7804b
1 changed files with 66 additions and 1 deletions
|
|
@ -429,6 +429,8 @@ static void printUsage(const char* argv0) {
|
||||||
std::printf(" Append one objective to a quest by index\n");
|
std::printf(" Append one objective to a quest by index\n");
|
||||||
std::printf(" --remove-quest-objective <zoneDir> <questIdx> <objIdx>\n");
|
std::printf(" --remove-quest-objective <zoneDir> <questIdx> <objIdx>\n");
|
||||||
std::printf(" Remove the objective at given 0-based index from a quest\n");
|
std::printf(" Remove the objective at given 0-based index from a quest\n");
|
||||||
|
std::printf(" --clone-quest <zoneDir> <questIdx> [newTitle]\n");
|
||||||
|
std::printf(" Duplicate a quest (with all objectives + rewards) and append it\n");
|
||||||
std::printf(" --add-quest-reward-item <zoneDir> <questIdx> <itemPath> [more...]\n");
|
std::printf(" --add-quest-reward-item <zoneDir> <questIdx> <itemPath> [more...]\n");
|
||||||
std::printf(" Append item reward(s) to a quest's reward.itemRewards list\n");
|
std::printf(" Append item reward(s) to a quest's reward.itemRewards list\n");
|
||||||
std::printf(" --set-quest-reward <zoneDir> <questIdx> [--xp N] [--gold N] [--silver N] [--copper N]\n");
|
std::printf(" --set-quest-reward <zoneDir> <questIdx> [--xp N] [--gold N] [--silver N] [--copper N]\n");
|
||||||
|
|
@ -549,7 +551,7 @@ int main(int argc, char* argv[]) {
|
||||||
"--scaffold-zone", "--add-tile", "--remove-tile", "--list-tiles",
|
"--scaffold-zone", "--add-tile", "--remove-tile", "--list-tiles",
|
||||||
"--add-creature", "--add-object", "--add-quest",
|
"--add-creature", "--add-object", "--add-quest",
|
||||||
"--add-quest-objective", "--add-quest-reward-item", "--set-quest-reward",
|
"--add-quest-objective", "--add-quest-reward-item", "--set-quest-reward",
|
||||||
"--remove-quest-objective",
|
"--remove-quest-objective", "--clone-quest",
|
||||||
"--remove-creature", "--remove-object", "--remove-quest",
|
"--remove-creature", "--remove-object", "--remove-quest",
|
||||||
"--copy-zone", "--rename-zone",
|
"--copy-zone", "--rename-zone",
|
||||||
"--build-woc", "--regen-collision", "--fix-zone",
|
"--build-woc", "--regen-collision", "--fix-zone",
|
||||||
|
|
@ -604,6 +606,11 @@ int main(int argc, char* argv[]) {
|
||||||
"--remove-quest-objective requires <zoneDir> <questIdx> <objIdx>\n");
|
"--remove-quest-objective requires <zoneDir> <questIdx> <objIdx>\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
if (std::strcmp(argv[i], "--clone-quest") == 0 && i + 2 >= argc) {
|
||||||
|
std::fprintf(stderr,
|
||||||
|
"--clone-quest requires <zoneDir> <questIdx>\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
if (std::strcmp(argv[i], "--add-quest-reward-item") == 0 && i + 3 >= argc) {
|
if (std::strcmp(argv[i], "--add-quest-reward-item") == 0 && i + 3 >= argc) {
|
||||||
std::fprintf(stderr,
|
std::fprintf(stderr,
|
||||||
"--add-quest-reward-item requires <zoneDir> <questIdx> <itemPath>\n");
|
"--add-quest-reward-item requires <zoneDir> <questIdx> <itemPath>\n");
|
||||||
|
|
@ -3692,6 +3699,64 @@ int main(int argc, char* argv[]) {
|
||||||
removedDesc.c_str(), oIdx, qIdx, q->title.c_str(),
|
removedDesc.c_str(), oIdx, qIdx, q->title.c_str(),
|
||||||
q->objectives.size());
|
q->objectives.size());
|
||||||
return 0;
|
return 0;
|
||||||
|
} else if (std::strcmp(argv[i], "--clone-quest") == 0 && i + 2 < argc) {
|
||||||
|
// Duplicate a quest. Useful for templating: create a base
|
||||||
|
// quest with objectives + rewards once, then clone N times
|
||||||
|
// for variants ('Slay Wolves', 'Slay Bears' with the same
|
||||||
|
// shape). Optional newTitle replaces the cloned copy's title;
|
||||||
|
// omit to get '<original> (copy)'.
|
||||||
|
std::string zoneDir = argv[++i];
|
||||||
|
std::string idxStr = argv[++i];
|
||||||
|
std::string newTitle;
|
||||||
|
if (i + 1 < argc && argv[i + 1][0] != '-') {
|
||||||
|
newTitle = argv[++i];
|
||||||
|
}
|
||||||
|
std::string path = zoneDir + "/quests.json";
|
||||||
|
if (!std::filesystem::exists(path)) {
|
||||||
|
std::fprintf(stderr, "clone-quest: %s not found\n", path.c_str());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
int qIdx;
|
||||||
|
try { qIdx = std::stoi(idxStr); }
|
||||||
|
catch (...) {
|
||||||
|
std::fprintf(stderr, "clone-quest: bad questIdx '%s'\n", idxStr.c_str());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
wowee::editor::QuestEditor qe;
|
||||||
|
if (!qe.loadFromFile(path)) {
|
||||||
|
std::fprintf(stderr, "clone-quest: failed to load %s\n", path.c_str());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (qIdx < 0 || qIdx >= static_cast<int>(qe.questCount())) {
|
||||||
|
std::fprintf(stderr,
|
||||||
|
"clone-quest: questIdx %d out of range [0, %zu)\n",
|
||||||
|
qIdx, qe.questCount());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
// Deep-copy by value via vector iteration; .objectives and
|
||||||
|
// .reward are STL containers so the copy is automatic.
|
||||||
|
wowee::editor::Quest clone = qe.getQuests()[qIdx];
|
||||||
|
// Reset id so the editor's auto-id sequence assigns a fresh
|
||||||
|
// one — addQuest does this internally if id==0.
|
||||||
|
clone.id = 0;
|
||||||
|
// Reset chain link too — copying a chained quest with the
|
||||||
|
// same nextQuestId would corrupt the chain semantics.
|
||||||
|
clone.nextQuestId = 0;
|
||||||
|
clone.title = newTitle.empty()
|
||||||
|
? (clone.title + " (copy)")
|
||||||
|
: newTitle;
|
||||||
|
qe.addQuest(clone);
|
||||||
|
if (!qe.saveToFile(path)) {
|
||||||
|
std::fprintf(stderr, "clone-quest: failed to write %s\n", path.c_str());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
std::printf("Cloned quest %d -> '%s' (now %zu total)\n",
|
||||||
|
qIdx, clone.title.c_str(), qe.questCount());
|
||||||
|
std::printf(" carried %zu objective(s), %zu item reward(s), xp=%u\n",
|
||||||
|
clone.objectives.size(),
|
||||||
|
clone.reward.itemRewards.size(),
|
||||||
|
clone.reward.xp);
|
||||||
|
return 0;
|
||||||
} else if (std::strcmp(argv[i], "--add-quest-reward-item") == 0 && i + 3 < argc) {
|
} else if (std::strcmp(argv[i], "--add-quest-reward-item") == 0 && i + 3 < argc) {
|
||||||
// Append one or more item rewards to a quest. Multiple paths
|
// Append one or more item rewards to a quest. Multiple paths
|
||||||
// can be passed in a single invocation:
|
// can be passed in a single invocation:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue