From fa82d32a9f44e04b8114dbd3760385ab6a382c10 Mon Sep 17 00:00:00 2001 From: Kelsi Date: Fri, 20 Mar 2026 06:29:33 -0700 Subject: [PATCH] feat: add [indoors]/[outdoors] macro conditionals via WMO detection Add indoor/outdoor state macro conditionals using the renderer's WMO interior detection. Essential for mount macros that need to select ground mounts indoors vs flying mounts outdoors. The Renderer now caches the insideWmo state in playerIndoors_ and exposes it via isPlayerIndoors(). Updated /macrohelp to list the new conditionals. --- include/rendering/renderer.hpp | 2 ++ src/rendering/renderer.cpp | 1 + src/ui/game_screen.cpp | 13 ++++++++++++- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/include/rendering/renderer.hpp b/include/rendering/renderer.hpp index 92c1de59..b53e87d1 100644 --- a/include/rendering/renderer.hpp +++ b/include/rendering/renderer.hpp @@ -139,6 +139,7 @@ public: QuestMarkerRenderer* getQuestMarkerRenderer() const { return questMarkerRenderer.get(); } SkySystem* getSkySystem() const { return skySystem.get(); } const std::string& getCurrentZoneName() const { return currentZoneName; } + bool isPlayerIndoors() const { return playerIndoors_; } VkContext* getVkContext() const { return vkCtx; } VkDescriptorSetLayout getPerFrameSetLayout() const { return perFrameSetLayout; } VkRenderPass getShadowRenderPass() const { return shadowRenderPass; } @@ -356,6 +357,7 @@ private: std::string currentZoneName; bool inTavern_ = false; bool inBlacksmith_ = false; + bool playerIndoors_ = false; // Cached WMO inside state for macro conditionals float musicSwitchCooldown_ = 0.0f; bool deferredWorldInitEnabled_ = true; bool deferredWorldInitPending_ = false; diff --git a/src/rendering/renderer.cpp b/src/rendering/renderer.cpp index 4dad508d..6583f4bf 100644 --- a/src/rendering/renderer.cpp +++ b/src/rendering/renderer.cpp @@ -3476,6 +3476,7 @@ void Renderer::update(float deltaTime) { uint32_t insideWmoId = 0; const bool insideWmo = canQueryWmo && wmoRenderer->isInsideWMO(camPos.x, camPos.y, camPos.z, &insideWmoId); + playerIndoors_ = insideWmo; // Ambient environmental sounds: fireplaces, water, birds, etc. if (ambientSoundManager && camera && wmoRenderer && cameraController) { diff --git a/src/ui/game_screen.cpp b/src/ui/game_screen.cpp index fed9a119..35cda2a0 100644 --- a/src/ui/game_screen.cpp +++ b/src/ui/game_screen.cpp @@ -5772,6 +5772,16 @@ static std::string evaluateMacroConditionals(const std::string& rawArg, if (c == "pet") return gameHandler.hasPet(); if (c == "nopet") return !gameHandler.hasPet(); + // indoors / outdoors — WMO interior detection (affects mount type selection) + if (c == "indoors" || c == "nooutdoors") { + auto* r = core::Application::getInstance().getRenderer(); + return r && r->isPlayerIndoors(); + } + if (c == "outdoors" || c == "noindoors") { + auto* r = core::Application::getInstance().getRenderer(); + return !r || !r->isPlayerIndoors(); + } + // group / nogroup — player is in a party or raid if (c == "group" || c == "party") return gameHandler.isInGroup(); if (c == "nogroup") return !gameHandler.isInGroup(); @@ -6131,7 +6141,8 @@ void GameScreen::sendChatMessage(game::GameHandler& gameHandler) { "--- Macro Conditionals ---", "Usage: /cast [cond1,cond2] Spell1; [cond3] Spell2; Default", "State: [combat] [mounted] [swimming] [flying] [stealthed]", - " [channeling] [pet] [group] (prefix no- to negate)", + " [channeling] [pet] [group] [indoors] [outdoors]", + " (prefix no- to negate any condition)", "Target: [harm] [help] [exists] [noexists] [dead] [nodead]", " [target=focus] [target=pet] [target=player]", "Form: [noform] [nostance] [form:0]",