From 1d53c35ed719f3e181d2bfec4e8e1918a51d7693 Mon Sep 17 00:00:00 2001 From: Kelsi Date: Fri, 20 Mar 2026 08:27:10 -0700 Subject: [PATCH] feat: show out-of-range red tint on macro action bar buttons The out-of-range indicator (red tint) only applied to SPELL-type action bar slots. Macro buttons like /cast Frostbolt never turned red even when the target was out of range. Now resolves the macro's primary spell via the cached lookup and checks its max range against the target distance, giving the same visual feedback as regular spell buttons. --- src/ui/game_screen.cpp | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/src/ui/game_screen.cpp b/src/ui/game_screen.cpp index a386dc9e..7ead77a6 100644 --- a/src/ui/game_screen.cpp +++ b/src/ui/game_screen.cpp @@ -8746,23 +8746,28 @@ void GameScreen::renderActionBar(game::GameHandler& gameHandler) { const bool onGCD = gameHandler.isGCDActive() && !onCooldown && !slot.isEmpty(); // Out-of-range check: red tint when a targeted spell cannot reach the current target. - // Only applies to SPELL slots with a known max range (>5 yd) and an active target. + // Applies to SPELL and MACRO slots with a known max range (>5 yd) and an active target. // Item range is checked below after barItemDef is populated. bool outOfRange = false; - if (!slot.isEmpty() && slot.type == game::ActionBarSlot::SPELL && slot.id != 0 - && !onCooldown && gameHandler.hasTarget()) { - uint32_t maxRange = spellbookScreen.getSpellMaxRange(slot.id, assetMgr); - if (maxRange > 5) { // >5 yd = not melee/self - auto& em = gameHandler.getEntityManager(); - auto playerEnt = em.getEntity(gameHandler.getPlayerGuid()); - auto targetEnt = em.getEntity(gameHandler.getTargetGuid()); - if (playerEnt && targetEnt) { - float dx = playerEnt->getX() - targetEnt->getX(); - float dy = playerEnt->getY() - targetEnt->getY(); - float dz = playerEnt->getZ() - targetEnt->getZ(); - float dist = std::sqrt(dx * dx + dy * dy + dz * dz); - if (dist > static_cast(maxRange)) - outOfRange = true; + { + uint32_t rangeCheckSpellId = 0; + if (slot.type == game::ActionBarSlot::SPELL && slot.id != 0) + rangeCheckSpellId = slot.id; + else if (slot.type == game::ActionBarSlot::MACRO && slot.id != 0) + rangeCheckSpellId = resolveMacroPrimarySpellId(slot.id, gameHandler); + if (rangeCheckSpellId != 0 && !onCooldown && gameHandler.hasTarget()) { + uint32_t maxRange = spellbookScreen.getSpellMaxRange(rangeCheckSpellId, assetMgr); + if (maxRange > 5) { + auto& em = gameHandler.getEntityManager(); + auto playerEnt = em.getEntity(gameHandler.getPlayerGuid()); + auto targetEnt = em.getEntity(gameHandler.getTargetGuid()); + if (playerEnt && targetEnt) { + float dx = playerEnt->getX() - targetEnt->getX(); + float dy = playerEnt->getY() - targetEnt->getY(); + float dz = playerEnt->getZ() - targetEnt->getZ(); + if (std::sqrt(dx*dx + dy*dy + dz*dz) > static_cast(maxRange)) + outOfRange = true; + } } } }