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]",