diff --git a/tools/editor/editor_ui.cpp b/tools/editor/editor_ui.cpp index 1c0c0462..e87b24e0 100644 --- a/tools/editor/editor_ui.cpp +++ b/tools/editor/editor_ui.cpp @@ -2402,9 +2402,41 @@ void EditorUI::renderPropertiesPanel(EditorApp& app) { ImGui::SameLine(); ImGui::Text("[%d, %d]", app.getLoadedTileX(), app.getLoadedTileY()); ImGui::Text("Chunks: %d Tris: %d", tr->getChunkCount(), tr->getTriangleCount()); - ImGui::Text("Objects: %zu NPCs: %zu", + ImGui::Text("Objects: %zu NPCs: %zu Q: %zu", app.getObjectPlacer().objectCount(), - app.getNpcSpawner().spawnCount()); + app.getNpcSpawner().spawnCount(), + app.getQuestEditor().questCount()); + + // Zone metadata (mapId, displayName, flags) + if (ImGui::CollapsingHeader("Zone Metadata")) { + auto& m = app.getZoneManifest(); + int mid = static_cast(m.mapId); + if (ImGui::InputInt("Map ID", &mid)) + m.mapId = static_cast(std::clamp(mid, 0, 65535)); + if (ImGui::IsItemHovered()) + ImGui::SetTooltip("Custom zones: 9000-12000. Must be unique per server."); + + char dispBuf[128] = {}; + std::strncpy(dispBuf, m.displayName.c_str(), sizeof(dispBuf) - 1); + if (ImGui::InputText("Display Name", dispBuf, sizeof(dispBuf))) + m.displayName = dispBuf; + if (ImGui::IsItemHovered()) + ImGui::SetTooltip("Name shown in-game on the world map and loading screen"); + + char descBuf[256] = {}; + std::strncpy(descBuf, m.description.c_str(), sizeof(descBuf) - 1); + if (ImGui::InputTextMultiline("Description##zone", descBuf, sizeof(descBuf), ImVec2(-1, 40))) + m.description = descBuf; + + ImGui::Separator(); + ImGui::Text("Zone Flags:"); + ImGui::Checkbox("Allow Flying", &m.allowFlying); + ImGui::SameLine(); + ImGui::Checkbox("PvP", &m.pvpEnabled); + ImGui::Checkbox("Indoor", &m.isIndoor); + ImGui::SameLine(); + ImGui::Checkbox("Sanctuary", &m.isSanctuary); + } } else { ImGui::TextColored(ImVec4(0.6f, 0.6f, 0.6f, 1.0f), "No terrain loaded"); } diff --git a/tools/editor/zone_manifest.cpp b/tools/editor/zone_manifest.cpp index 03a1be9b..2a1bbcea 100644 --- a/tools/editor/zone_manifest.cpp +++ b/tools/editor/zone_manifest.cpp @@ -44,6 +44,14 @@ bool ZoneManifest::save(const std::string& path) const { if (hasCreatures) files["creatures"] = "creatures.json"; j["files"] = files; + // Zone gameplay flags + nlohmann::json flags; + flags["allowFlying"] = allowFlying; + flags["pvpEnabled"] = pvpEnabled; + flags["isIndoor"] = isIndoor; + flags["isSanctuary"] = isSanctuary; + j["flags"] = flags; + // Audio configuration if (!musicTrack.empty() || !ambienceDay.empty()) { nlohmann::json audio; @@ -87,6 +95,15 @@ bool ZoneManifest::load(const std::string& path) { } } + // Zone gameplay flags + if (j.contains("flags")) { + const auto& fl = j["flags"]; + allowFlying = fl.value("allowFlying", false); + pvpEnabled = fl.value("pvpEnabled", false); + isIndoor = fl.value("isIndoor", false); + isSanctuary = fl.value("isSanctuary", false); + } + // Audio configuration if (j.contains("audio")) { const auto& a = j["audio"]; diff --git a/tools/editor/zone_manifest.hpp b/tools/editor/zone_manifest.hpp index 9270b0ca..616c7a21 100644 --- a/tools/editor/zone_manifest.hpp +++ b/tools/editor/zone_manifest.hpp @@ -17,6 +17,12 @@ struct ZoneManifest { bool hasCreatures = false; std::string description; + // Zone gameplay flags + bool allowFlying = false; + bool pvpEnabled = false; + bool isIndoor = false; + bool isSanctuary = false; + // Audio configuration std::string musicTrack; // Background music file path std::string ambienceDay; // Daytime ambient sound