mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-05-07 09:33:51 +00:00
feat(editor): add --mvp-zone for one-command demo zone setup
Quick-start: scaffold a zone AND populate one of each content type
(1 creature, 1 object, 1 quest with objective + XP reward) in a
single command. Goes from empty filesystem to 'something to look at'
without 7 chained --add-* commands:
wowee_editor --mvp-zone 'Demo Land' 30 30
Created demo zone: custom_zones/Demo_Land
tile : (30, 30)
contents : 1 creature, 1 object, 1 quest (with objective + reward)
next : wowee_editor --info-zone-tree custom_zones/Demo_Land
Demo Land/
├─ Manifest ...
├─ Tiles (1) — (30, 30)
├─ Creatures (1) — lvl 5 Demo Wolf
├─ Objects (1) — m2 World/Generic/Tree.m2
├─ Quests (1) — [1] Welcome to Demo Land (lvl 1, 100 XP)
│ └─ kill ×1 Demo Wolf
Demo content is positioned roughly at tile center (533.33-yard
intervals from origin tile 32/32). Quest references the demo
creature's auto-id so --check-zone-refs passes immediately.
Use cases:
- Smoke-testing the bake/validate pipeline
- Screenshot bait for docs / blog posts
- Editor onboarding (open a zone in the GUI to see the format)
- CI sanity check (does our editor still produce a viewable zone?)
Verified end-to-end: --mvp-zone 'Demo Land' → --info-zone-tree
shows all 4 sections populated correctly, file list matches
expected 6 files.
This commit is contained in:
parent
9c7b6aebfc
commit
dbf973e29e
1 changed files with 103 additions and 1 deletions
|
|
@ -524,6 +524,8 @@ static void printUsage(const char* argv0) {
|
|||
std::printf(" --for-each-zone <projectDir> -- <cmd...>\n");
|
||||
std::printf(" Run <cmd...> for every zone in <projectDir>; '{}' in cmd is replaced with the zone path\n");
|
||||
std::printf(" --scaffold-zone <name> [tx ty] Create a blank zone in custom_zones/<name>/ and exit\n");
|
||||
std::printf(" --mvp-zone <name> [tx ty]\n");
|
||||
std::printf(" Scaffold + add a creature + object + quest (with objective+reward) for quick demos\n");
|
||||
std::printf(" --add-tile <zoneDir> <tx> <ty> [baseHeight]\n");
|
||||
std::printf(" Add a new ADT tile to an existing zone (extends the manifest's tiles list)\n");
|
||||
std::printf(" --remove-tile <zoneDir> <tx> <ty>\n");
|
||||
|
|
@ -788,7 +790,7 @@ int main(int argc, char* argv[]) {
|
|||
"--export-zone-summary-md", "--export-quest-graph",
|
||||
"--export-zone-csv", "--export-zone-html", "--export-project-html",
|
||||
"--export-zone-checksum",
|
||||
"--scaffold-zone", "--add-tile", "--remove-tile", "--list-tiles",
|
||||
"--scaffold-zone", "--mvp-zone", "--add-tile", "--remove-tile", "--list-tiles",
|
||||
"--for-each-zone", "--zone-stats", "--info-tilemap",
|
||||
"--list-zone-deps", "--check-zone-refs", "--check-zone-content",
|
||||
"--export-zone-deps-md",
|
||||
|
|
@ -9682,6 +9684,106 @@ int main(int argc, char* argv[]) {
|
|||
slug.c_str(), slug.c_str());
|
||||
std::printf(" next step: run editor without args, then File → Open Zone\n");
|
||||
return 0;
|
||||
} else if (std::strcmp(argv[i], "--mvp-zone") == 0 && i + 1 < argc) {
|
||||
// Quick-start: scaffold + populate one of each content type
|
||||
// (1 creature, 1 object, 1 quest with objective + reward).
|
||||
// Useful for demos, screenshot bait, smoke tests of the
|
||||
// bake/validate pipeline. The zone goes from empty to
|
||||
// 'something to look at' in one command.
|
||||
std::string rawName = argv[++i];
|
||||
int sx = 32, sy = 32;
|
||||
if (i + 2 < argc) {
|
||||
int parsedX = std::atoi(argv[i + 1]);
|
||||
int parsedY = std::atoi(argv[i + 2]);
|
||||
if (parsedX >= 0 && parsedX <= 63 &&
|
||||
parsedY >= 0 && parsedY <= 63) {
|
||||
sx = parsedX; sy = parsedY;
|
||||
i += 2;
|
||||
}
|
||||
}
|
||||
// Reuse scaffold-zone's slug logic.
|
||||
std::string slug;
|
||||
for (char c : rawName) {
|
||||
if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
|
||||
(c >= '0' && c <= '9') || c == '_' || c == '-') slug += c;
|
||||
else if (c == ' ') slug += '_';
|
||||
}
|
||||
if (slug.empty()) {
|
||||
std::fprintf(stderr,
|
||||
"mvp-zone: name '%s' has no valid characters\n",
|
||||
rawName.c_str());
|
||||
return 1;
|
||||
}
|
||||
namespace fs = std::filesystem;
|
||||
std::string dir = "custom_zones/" + slug;
|
||||
if (fs::exists(dir)) {
|
||||
std::fprintf(stderr,
|
||||
"mvp-zone: directory already exists: %s\n", dir.c_str());
|
||||
return 1;
|
||||
}
|
||||
fs::create_directories(dir);
|
||||
// Scaffold terrain.
|
||||
auto terrain = wowee::editor::TerrainEditor::createBlankTerrain(
|
||||
sx, sy, 100.0f, wowee::editor::Biome::Grassland);
|
||||
std::string base = dir + "/" + slug + "_" +
|
||||
std::to_string(sx) + "_" + std::to_string(sy);
|
||||
wowee::editor::WoweeTerrain::exportOpen(terrain, base, sx, sy);
|
||||
// Manifest.
|
||||
wowee::editor::ZoneManifest zm;
|
||||
zm.mapName = slug;
|
||||
zm.displayName = rawName;
|
||||
zm.mapId = 9000;
|
||||
zm.baseHeight = 100.0f;
|
||||
zm.tiles.push_back({sx, sy});
|
||||
zm.hasCreatures = true;
|
||||
zm.save(dir + "/zone.json");
|
||||
// Position the demo content roughly centered in the tile.
|
||||
// Tile (32, 32) is the WoW map origin; tile centers are at
|
||||
// 533.33-yard intervals from there.
|
||||
float centerX = (32.0f - sy) * 533.33333f - 266.667f;
|
||||
float centerY = (32.0f - sx) * 533.33333f - 266.667f;
|
||||
float centerZ = 100.0f;
|
||||
// Demo creature.
|
||||
wowee::editor::NpcSpawner sp;
|
||||
wowee::editor::CreatureSpawn c;
|
||||
c.name = "Demo Wolf";
|
||||
c.position = {centerX, centerY, centerZ};
|
||||
c.level = 5;
|
||||
c.health = 100;
|
||||
c.minDamage = 5; c.maxDamage = 10;
|
||||
c.displayId = 11430; // any valid id; renderer falls back if absent
|
||||
sp.getSpawns().push_back(c);
|
||||
sp.saveToFile(dir + "/creatures.json");
|
||||
// Demo object — a tree placement near the creature.
|
||||
wowee::editor::ObjectPlacer op;
|
||||
wowee::editor::PlacedObject po;
|
||||
po.type = wowee::editor::PlaceableType::M2;
|
||||
po.path = "World/Generic/Tree.m2";
|
||||
po.position = {centerX + 5.0f, centerY, centerZ};
|
||||
po.scale = 1.0f;
|
||||
op.getObjects().push_back(po);
|
||||
op.saveToFile(dir + "/objects.json");
|
||||
// Demo quest with objective + XP reward.
|
||||
wowee::editor::QuestEditor qe;
|
||||
wowee::editor::Quest q;
|
||||
q.title = "Welcome to " + rawName;
|
||||
q.requiredLevel = 1;
|
||||
q.questGiverNpcId = c.id; // self-referential so refs check passes
|
||||
q.turnInNpcId = c.id;
|
||||
q.reward.xp = 100;
|
||||
wowee::editor::QuestObjective obj;
|
||||
obj.type = wowee::editor::QuestObjectiveType::KillCreature;
|
||||
obj.targetName = "Demo Wolf";
|
||||
obj.targetCount = 1;
|
||||
obj.description = "Slay the Demo Wolf";
|
||||
q.objectives.push_back(obj);
|
||||
qe.addQuest(q);
|
||||
qe.saveToFile(dir + "/quests.json");
|
||||
std::printf("Created demo zone: %s\n", dir.c_str());
|
||||
std::printf(" tile : (%d, %d)\n", sx, sy);
|
||||
std::printf(" contents : 1 creature, 1 object, 1 quest (with objective + reward)\n");
|
||||
std::printf(" next : wowee_editor --info-zone-tree %s\n", dir.c_str());
|
||||
return 0;
|
||||
} else if (std::strcmp(argv[i], "--add-tile") == 0 && i + 3 < argc) {
|
||||
// Extend an existing zone with another ADT tile. Zones can
|
||||
// span multiple tiles (e.g. a continent fragment), but
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue