mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-05-08 10:03:51 +00:00
feat(editor): in-editor "Random Populate" menu mirrors CLI
Adds EditorApp::randomPopulateZone(creatureCount, objectCount, seed) and a Generate-menu submenu with sliders for both counts plus a seed input. Same logic and bestiary as the --random-populate-zone CLI: 12 creature templates with level jitter, 5 placeholder WMO prop types with randomized rotation/scale. Spawns are placed within the loaded tile's world bbox, marked dirty + auto-save pending so the populated content persists across restarts. The CLI command remains for CI / scripting / batch workflows; the menu serves designers who want to populate from the GUI without context-switching to a terminal. Same-seed reproducibility: a hover hint reminds the user that the seed determines the output deterministically.
This commit is contained in:
parent
bdf2497f46
commit
89dacba666
3 changed files with 98 additions and 0 deletions
|
|
@ -1702,6 +1702,84 @@ void EditorApp::generateCompleteZone() {
|
|||
showToast("Zone generated!");
|
||||
}
|
||||
|
||||
void EditorApp::randomPopulateZone(int creatureCount, int objectCount,
|
||||
uint32_t seed) {
|
||||
if (!terrain_.isLoaded() || loadedTileX_ < 0 || loadedTileY_ < 0) {
|
||||
showToast("Load a tile first");
|
||||
return;
|
||||
}
|
||||
// Loaded tile world bbox. Each tile is 533.33y; WoW grid centers
|
||||
// tile (32, 32) at origin (+X = -wowY tile, +Y = -wowX tile).
|
||||
constexpr float kTileSize = 533.33333f;
|
||||
float wMinX = (32.0f - loadedTileY_ - 1) * kTileSize;
|
||||
float wMaxX = (32.0f - loadedTileY_) * kTileSize;
|
||||
float wMinY = (32.0f - loadedTileX_ - 1) * kTileSize;
|
||||
float wMaxY = (32.0f - loadedTileX_) * kTileSize;
|
||||
float baseZ = terrain_.chunks[0].position[2];
|
||||
|
||||
uint32_t rng = seed ? seed : 1u;
|
||||
auto next01 = [&]() {
|
||||
rng = rng * 1664525u + 1013904223u;
|
||||
return (rng >> 8) / float(1 << 24);
|
||||
};
|
||||
auto rangeF = [&](float a, float b) { return a + next01() * (b - a); };
|
||||
auto rangeI = [&](int a, int b) {
|
||||
return a + static_cast<int>(next01() * (b - a + 1));
|
||||
};
|
||||
static const std::vector<std::pair<const char*, uint32_t>> kRandomCreatures = {
|
||||
{"Wolf", 5}, {"Boar", 4}, {"Bear", 7}, {"Spider", 3},
|
||||
{"Bandit", 6}, {"Kobold", 4}, {"Murloc", 5}, {"Skeleton", 5},
|
||||
{"Wisp", 3}, {"Goblin", 5}, {"Stag", 4}, {"Crab", 3},
|
||||
};
|
||||
static const std::vector<const char*> kRandomObjects = {
|
||||
"World/Generic/Tree01.wmo",
|
||||
"World/Generic/Boulder.wmo",
|
||||
"World/Generic/Bush.wmo",
|
||||
"World/Generic/Stump.wmo",
|
||||
"World/Generic/Mushroom.wmo",
|
||||
};
|
||||
int placedCreatures = 0, placedObjects = 0;
|
||||
for (int n = 0; n < creatureCount; ++n) {
|
||||
const auto& [name, baseLvl] = kRandomCreatures[
|
||||
rangeI(0, static_cast<int>(kRandomCreatures.size()) - 1)];
|
||||
CreatureSpawn s;
|
||||
s.name = name;
|
||||
s.position.x = rangeF(wMinX, wMaxX);
|
||||
s.position.y = rangeF(wMinY, wMaxY);
|
||||
s.position.z = baseZ;
|
||||
int lvl = std::max(1, static_cast<int>(baseLvl) + rangeI(-1, 2));
|
||||
s.level = static_cast<uint32_t>(lvl);
|
||||
s.health = 50 + s.level * 10;
|
||||
s.orientation = rangeF(0.0f, 360.0f);
|
||||
npcSpawner_.placeCreature(s);
|
||||
placedCreatures++;
|
||||
}
|
||||
auto& objs = objectPlacer_.getObjects();
|
||||
uint32_t maxUid = 0;
|
||||
for (const auto& o : objs) maxUid = std::max(maxUid, o.uniqueId);
|
||||
for (int n = 0; n < objectCount; ++n) {
|
||||
PlacedObject o;
|
||||
o.path = kRandomObjects[
|
||||
rangeI(0, static_cast<int>(kRandomObjects.size()) - 1)];
|
||||
o.type = PlaceableType::WMO;
|
||||
o.position.x = rangeF(wMinX, wMaxX);
|
||||
o.position.y = rangeF(wMinY, wMaxY);
|
||||
o.position.z = baseZ;
|
||||
o.rotation = glm::vec3(0.0f, rangeF(0.0f, 6.28f), 0.0f);
|
||||
o.scale = rangeF(0.8f, 1.4f);
|
||||
o.uniqueId = ++maxUid;
|
||||
o.nameId = 0;
|
||||
o.selected = false;
|
||||
objs.push_back(o);
|
||||
placedObjects++;
|
||||
}
|
||||
objectsDirty_ = true;
|
||||
autoSavePendingChanges_ = true;
|
||||
viewport_.updateNpcMarkers(npcSpawner_.getSpawns());
|
||||
showToast("Populated: " + std::to_string(placedCreatures) +
|
||||
" creatures + " + std::to_string(placedObjects) + " objects");
|
||||
}
|
||||
|
||||
void EditorApp::clearAllObjects() {
|
||||
vkDeviceWaitIdle(window_->getVkContext()->getDevice());
|
||||
objectPlacer_.clearAll();
|
||||
|
|
|
|||
|
|
@ -98,6 +98,10 @@ public:
|
|||
int batchConvertAssets(const std::string& dataDir);
|
||||
void clearAllObjects();
|
||||
void generateCompleteZone();
|
||||
// Drop N random creatures + M random objects within the loaded
|
||||
// tile's world bbox. Mirrors the --random-populate-zone CLI
|
||||
// command so users can do bulk population from inside the editor.
|
||||
void randomPopulateZone(int creatureCount, int objectCount, uint32_t seed);
|
||||
void centerOnTerrain();
|
||||
|
||||
// Multi-tile support
|
||||
|
|
|
|||
|
|
@ -379,6 +379,22 @@ void EditorUI::renderMenuBar(EditorApp& app) {
|
|||
}
|
||||
if (ImGui::MenuItem("Generate Complete Zone", nullptr, false, app.hasTerrainLoaded()))
|
||||
app.generateCompleteZone();
|
||||
if (ImGui::BeginMenu("Random Populate", app.hasTerrainLoaded())) {
|
||||
static int rpCreatures = 20;
|
||||
static int rpObjects = 10;
|
||||
static int rpSeed = 42;
|
||||
ImGui::SliderInt("Creatures##rp", &rpCreatures, 0, 200);
|
||||
ImGui::SliderInt("Objects##rp", &rpObjects, 0, 200);
|
||||
ImGui::InputInt("Seed##rp", &rpSeed);
|
||||
if (rpSeed < 0) rpSeed = 0;
|
||||
if (ImGui::Button("Populate##rp", ImVec2(-1, 0))) {
|
||||
app.randomPopulateZone(rpCreatures, rpObjects,
|
||||
static_cast<uint32_t>(rpSeed));
|
||||
}
|
||||
ImGui::TextColored(ImVec4(0.6f, 0.6f, 0.6f, 1),
|
||||
"Same seed → same population (reproducible)");
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
if (ImGui::MenuItem("Clear All Objects/NPCs", nullptr, false, app.hasTerrainLoaded())) {
|
||||
if (app.getObjectPlacer().objectCount() > 0 || app.getNpcSpawner().spawnCount() > 0)
|
||||
app.clearAllObjects();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue