From 38674064d67a0c2c641e4f41b041a44d586b490e Mon Sep 17 00:00:00 2001 From: Dusk-92 Date: Sun, 30 Aug 2026 09:11:44 +0200 Subject: [PATCH] Harden macros, world map and actionbar panels --- mods/macro-icons.lua | 133 +++++++++++++++------------ mods/macro-tweaks.lua | 82 ++++++++++------- mods/reduced-actionbar-bags.lua | 19 +++- mods/reduced-actionbar-micromenu.lua | 20 +++- mods/worldmap-reveal.lua | 25 +++-- 5 files changed, 167 insertions(+), 112 deletions(-) diff --git a/mods/macro-icons.lua b/mods/macro-icons.lua index 509e47d..1b22f7d 100644 --- a/mods/macro-icons.lua +++ b/mods/macro-icons.lua @@ -1,5 +1,6 @@ local _G = ShaguTweaks.GetGlobalEnv() local T = ShaguTweaks.T +local API = ShaguTweaks.API or {} local libspell = ShaguTweaks.libspell local module = ShaguTweaks:register({ @@ -14,75 +15,86 @@ local module = ShaguTweaks:register({ module.enable = function(self) local gfind = string.gmatch or string.gfind - local function ButtonMacroScan(bar) - if not bar:IsVisible() then return end + local function BuildMacroCache() + local cache = {} + for macroSlot = 1, 36 do + local name, _, body = GetMacroInfo(macroSlot) + if name and body then + cache[name] = { id = macroSlot, body = body } + end + end + return cache + end - local button, icon + local function GetMacroBody(actionSlot, cache) + if API.GetActionInfo then + local actionType, id = API.GetActionInfo(actionSlot) + if actionType == "macro" and id then + local _, _, body = GetMacroInfo(id) + if body then return body end + end + end + + local macroName = GetActionText(actionSlot) + local entry = macroName and cache[macroName] + return entry and entry.body or nil + end + + local function ResolveSpell(body) + if not body then return end + + local fallback + for line in gfind(body, "[^%\n]+") do + local _, _, match = string.find(line, "^#showtooltip%s+(.+)") + if match then return match end + + if not fallback then + _, _, fallback = string.find(line, "%-%-showtooltip%s+(.+)") + end + if not fallback then + _, _, fallback = string.find(line, "^/cast%s+(.+)") + end + if not fallback then + _, _, fallback = string.find(line, "^/pfcast%s+(.+)") + end + if not fallback then + _, _, fallback = string.find(line, "CastSpellByName%(%\"(.+)%\"%)") + end + end + + return fallback + end + + local function ButtonMacroScan(bar, macroCache) + if not bar:IsVisible() then return end local prefix = bar:GetName() prefix = bar == MainMenuBar and "Action" or prefix prefix = bar == BonusActionBarFrame and "BonusAction" or prefix - -- scan all 12 slots in bar - for slot = 1, 12 do - button = _G[prefix.."Button"..slot] - icon = _G[prefix.."Button"..slot.."Icon"] - + for index = 1, 12 do + local button = _G[prefix.."Button"..index] + local icon = _G[prefix.."Button"..index.."Icon"] if not button then break end - local macro = GetActionText(ActionButton_GetPagedID(_G[prefix.."Button"..slot])) - local spellslot = nil - local booktype = nil + local actionSlot = ActionButton_GetPagedID(button) + local texture = GetActionTexture(actionSlot) + button.spellslot, button.booktype = nil, nil - if macro then - local name, body, _ - for slot = 1, 36 do -- 36 macro slots - name, _, body = GetMacroInfo(slot) - if name == macro then break end + local body = GetMacroBody(actionSlot, macroCache) + local match = ResolveSpell(body) + if match then + local _, _, spell, rank = string.find(match, "(.+)%((.+)%)") + spell = spell or match + button.spellslot, button.booktype = libspell.GetSpellIndex(spell, rank) + + if button.spellslot and button.booktype then + texture = GetSpellTexture(button.spellslot, button.booktype) or texture end + end - if name and body then - local match - - for line in gfind(body, "[^%\n]+") do - _, _, match = string.find(line, '^#showtooltip (.+)') - - if not match then - -- add support to specify custom tooltips via: - -- /run --showtooltip SPELLNAME - _, _, match = string.find(line, '%-%-showtooltip (.+)') - end - - if not match then - _, _, match = string.find(line, '^/cast (.+)') - end - - if not match then - _, _, match = string.find(line, '^/pfcast (.+)') - end - - if not match then - _, _, match = string.find(line, 'CastSpellByName%(%"(.+)%"%)') - end - - if match then - local _, _, spell, rank = string.find(match, '(.+)%((.+)%)') - spell = spell or match - button.spellslot, button.booktype = libspell.GetSpellIndex(spell, rank) - - -- overwrite with spell macro texture where possible - local texture = GetActionTexture(slot) - if button.spellslot and button.booktype then - texture = GetSpellTexture(button.spellslot, button.booktype) - end - - -- update button texture - if texture and texture ~= icon:GetTexture() then - icon:SetTexture(texture) - end - end - end - end + if icon and texture and texture ~= icon:GetTexture() then + icon:SetTexture(texture) end end end @@ -99,6 +111,9 @@ module.enable = function(self) macroicons:RegisterEvent("UPDATE_BONUS_ACTIONBAR") macroicons:RegisterEvent("ACTIONBAR_SHOWGRID") macroicons:SetScript("OnEvent", function() - for _, bar in pairs(bars) do ButtonMacroScan(bar) end + local macroCache = BuildMacroCache() + for _, bar in pairs(bars) do + ButtonMacroScan(bar, macroCache) + end end) end diff --git a/mods/macro-tweaks.lua b/mods/macro-tweaks.lua index 1fa3b49..59af314 100644 --- a/mods/macro-tweaks.lua +++ b/mods/macro-tweaks.lua @@ -1,5 +1,6 @@ local _G = ShaguTweaks.GetGlobalEnv() local T = ShaguTweaks.T +local API = ShaguTweaks.API or {} local module = ShaguTweaks:register({ title = T["Macro Tweaks"], @@ -11,72 +12,85 @@ local module = ShaguTweaks:register({ }) module.enable = function(self) - -- make sure #showtooltip inside macros won't be sent - local hookSendChatMessage = SendChatMessage - function _G.SendChatMessage(msg, ...) - if msg and string.find(msg, "^#showtooltip ") then return end - hookSendChatMessage(msg, unpack(arg)) + -- This interception is intentional: #showtooltip is macro metadata and must + -- not be sent as chat text by the Vanilla macro parser. + local hookSendChatMessage = _G.SendChatMessage + function _G.SendChatMessage(msg, a1, a2, a3, a4, a5, a6, a7, a8) + if msg and string.find(msg, "^#showtooltip%s") then return end + return hookSendChatMessage(msg, a1, a2, a3, a4, a5, a6, a7, a8) end - -- do not write macro calls into chat input history + -- do not write executed macro commands into chat input history if not ChatFrameEditBox._AddHistoryLine then local userinput ChatFrameEditBox._AddHistoryLine = ChatFrameEditBox.AddHistoryLine ChatFrameEditBox.AddHistoryLine = function(self, text) - if not userinput and text and string.find(text, "^/run(.+)") then return end - if not userinput and string.find(text, "^/script(.+)") then return end - if not userinput and string.find(text, "^/cast(.+)") then return end + if not userinput and text then + if string.find(text, "^/run%s*") then return end + if string.find(text, "^/script%s*") then return end + if string.find(text, "^/cast%s*") then return end + end ChatFrameEditBox._AddHistoryLine(self, text) end local OnEnter = ChatFrameEditBox:GetScript("OnEnterPressed") ChatFrameEditBox:SetScript("OnEnterPressed", function(a1,a2,a3,a4) userinput = true - OnEnter(a1,a2,a3,a4) - userinput = nil + if OnEnter then OnEnter(a1,a2,a3,a4) end + userinput = nil end) end + local function GetBagItemName(bag, slot) + if API.GetContainerItemID and API.GetItemNameByID then + local itemID = API.GetContainerItemID(bag, slot) + local name = itemID and API.GetItemNameByID(itemID) + if name then return name end + end + + local itemLink = GetContainerItemLink(bag, slot) + if not itemLink then return end + local _, _, itemID = string.find(itemLink, "item:(%d+)") + return itemID and GetItemInfo(itemID) or nil + end + local function FindItem(item) + local wanted = string.lower(item or "") for bag = 4, 0, -1 do for slot = 1, GetContainerNumSlots(bag) do - local itemLink = GetContainerItemLink(bag,slot) - if itemLink then - local _, _, parse = strfind(itemLink, "(%d+):") - local query = GetItemInfo(parse) - if query and query ~= "" and string.lower(query) == string.lower(item) then - return bag, slot - end + local query = GetBagItemName(bag, slot) + if query and string.lower(query) == wanted then + return bag, slot end end end - - return nil end - -- add /use and /equip to the macro api: - -- https://wowwiki.fandom.com/wiki/Making_a_macro - -- supported arguments: - -- /use - -- /use - -- /use _G.SLASH_EQUIP1 = "/equip" _G.SLASH_EQUIP2 = "/use" - _G.SlashCmdList.EQUIP = function (msg) + _G.SlashCmdList.EQUIP = function(msg) if not msg or msg == "" then return end - local bag, slot, _ - if string.find(msg, "%d+%s+%d+") then - _, _, bag, slot = string.find(msg, "(%d+)%s+(%d+)") - elseif string.find(msg, "%d+") then - _, _, slot = string.find(msg, "(%d+)") + + local bag, slot + local _, _, parsedBag, parsedSlot = string.find(msg, "^(%d+)%s+(%d+)$") + if parsedBag and parsedSlot then + bag, slot = parsedBag, parsedSlot else - bag, slot = FindItem(msg) + local _, _, inventorySlot = string.find(msg, "^(%d+)$") + if inventorySlot then + slot = inventorySlot + else + bag, slot = FindItem(msg) + end end + bag = bag and tonumber(bag) or nil + slot = slot and tonumber(slot) or nil + if bag and slot then UseContainerItem(bag, slot) - elseif not bag and slot then + elseif slot then UseInventoryItem(slot) end end diff --git a/mods/reduced-actionbar-bags.lua b/mods/reduced-actionbar-bags.lua index 3b0a613..b1ca08b 100644 --- a/mods/reduced-actionbar-bags.lua +++ b/mods/reduced-actionbar-bags.lua @@ -1,5 +1,6 @@ local _G = ShaguTweaks.GetGlobalEnv() local T = ShaguTweaks.T +local API = ShaguTweaks.API or {} local module = ShaguTweaks:register({ title = T["Show Bags"], @@ -49,7 +50,9 @@ module.enable = function(self) bagframe:RegisterEvent("PLAYER_ENTERING_WORLD") bagframe:SetScript("OnDragStart", function() - if not IsShiftKeyDown() or not IsControlKeyDown() then return end + local shift = API.IsShiftKeyDown and API.IsShiftKeyDown() or IsShiftKeyDown() + local control = API.IsControlKeyDown and API.IsControlKeyDown() or IsControlKeyDown() + if not shift or not control then return end this:StartMoving() end) @@ -58,7 +61,13 @@ module.enable = function(self) end) bagframe:SetScript("OnUpdate", function() - if MouseIsOver(this) and IsShiftKeyDown() and IsControlKeyDown() then + this.modifierTimer = (this.modifierTimer or 0) + arg1 + if this.modifierTimer < .05 then return end + this.modifierTimer = 0 + + local shift = API.IsShiftKeyDown and API.IsShiftKeyDown() or IsShiftKeyDown() + local control = API.IsControlKeyDown and API.IsControlKeyDown() or IsControlKeyDown() + if MouseIsOver(this) and shift and control then if not this.mousedisabled then -- disable mouse events on all frames this.mousedisabled = true @@ -78,14 +87,18 @@ module.enable = function(self) end) bagframe:SetScript("OnEvent", function() + if this.initialized then return end + this.initialized = true + ShaguTweaks.DarkenFrame(bagframe) for id, frame in pairs(frames) do local anchor = frames[id-1] or bagframe + frame:ClearAllPoints() frame:SetPoint("LEFT", anchor, id == 1 and "LEFT" or "RIGHT", id == 1 and 5 or 2, 0) frame:SetParent(bagframe) frame:SetScale(.8) - frame.Show = frame:Show() + frame.Show = nil frame:Show() end end) diff --git a/mods/reduced-actionbar-micromenu.lua b/mods/reduced-actionbar-micromenu.lua index d4e60f5..84da3bf 100644 --- a/mods/reduced-actionbar-micromenu.lua +++ b/mods/reduced-actionbar-micromenu.lua @@ -1,5 +1,6 @@ local _G = ShaguTweaks.GetGlobalEnv() local T = ShaguTweaks.T +local API = ShaguTweaks.API or {} local module = ShaguTweaks:register({ title = T["Show Micro Menu"], @@ -27,6 +28,7 @@ module.enable = function(self) microframe:SetPoint("BOTTOMRIGHT", UIParent, "BOTTOMRIGHT", -8, 8) microframe:SetWidth(225) microframe:SetHeight(44) + microframe:SetScale(module.config["panelmicro.scale"]) microframe:SetFrameStrata("MEDIUM") microframe:SetBackdrop({ @@ -49,7 +51,9 @@ module.enable = function(self) microframe:RegisterEvent("PLAYER_ENTERING_WORLD") microframe:SetScript("OnDragStart", function() - if not IsShiftKeyDown() or not IsControlKeyDown() then return end + local shift = API.IsShiftKeyDown and API.IsShiftKeyDown() or IsShiftKeyDown() + local control = API.IsControlKeyDown and API.IsControlKeyDown() or IsControlKeyDown() + if not shift or not control then return end this:StartMoving() end) @@ -58,7 +62,13 @@ module.enable = function(self) end) microframe:SetScript("OnUpdate", function() - if MouseIsOver(this) and IsShiftKeyDown() and IsControlKeyDown() then + this.modifierTimer = (this.modifierTimer or 0) + arg1 + if this.modifierTimer < .05 then return end + this.modifierTimer = 0 + + local shift = API.IsShiftKeyDown and API.IsShiftKeyDown() or IsShiftKeyDown() + local control = API.IsControlKeyDown and API.IsControlKeyDown() or IsControlKeyDown() + if MouseIsOver(this) and shift and control then if not this.mousedisabled then -- disable mouse events on all frames this.mousedisabled = true @@ -78,13 +88,17 @@ module.enable = function(self) end) microframe:SetScript("OnEvent", function() + if this.initialized then return end + this.initialized = true + ShaguTweaks.DarkenFrame(microframe) for id, frame in pairs(frames) do local anchor = frames[id-1] or microframe + frame:ClearAllPoints() frame:SetPoint("LEFT", anchor, id == 1 and "LEFT" or "RIGHT", id == 1 and 3.5 or -2, id==1 and 10 or 0) frame:SetParent(microframe) - frame.Show = frame:Show() + frame.Show = nil frame:Show() end end) diff --git a/mods/worldmap-reveal.lua b/mods/worldmap-reveal.lua index fcd8606..f855b53 100644 --- a/mods/worldmap-reveal.lua +++ b/mods/worldmap-reveal.lua @@ -1,5 +1,6 @@ local _G = ShaguTweaks.GetGlobalEnv() local T = ShaguTweaks.T +local hooksecurefunc = ShaguTweaks.hooksecurefunc local hooksecurefunc = hooksecurefunc or ShaguTweaks.hooksecurefunc local module = ShaguTweaks:register({ @@ -197,7 +198,7 @@ module.enable = function(self) local function ShaguTweaksWorldMapFrame_Update() -- create metatable if not yet created - this.overlayData = this.overlayData or setmetatable(ShaguTweaks.MapOverlayData, {__index = function(t,k) + WorldMapFrame.overlayData = WorldMapFrame.overlayData or setmetatable(ShaguTweaks.MapOverlayData, {__index = function(t,k) local v = {} rawset(t,k,v) return v @@ -213,7 +214,7 @@ module.enable = function(self) local alreadyknown = {} for i=1, numOverlays do local textureName, textureWidth, textureHeight, offsetX, offsetY, mapPointX, mapPointY = GetMapOverlayInfo(i) - local overlayHash = create_hash(textureName, textureWidth, textureHeight, offsetX, offsetY, mapPointX, mapPointY) + local overlayHash = create_hash(prefix, textureName, textureWidth, textureHeight, offsetX, offsetY, mapPointX, mapPointY) alreadyknown[textureName] = overlayHash end @@ -222,7 +223,7 @@ module.enable = function(self) frame:Hide() end - local zoneData = this.overlayData[mapFileName] + local zoneData = WorldMapFrame.overlayData[mapFileName] local textureCount = 0 local texturePixelWidth, textureFileWidth, texturePixelHeight, textureFileHeight for i, hash in ipairs(zoneData) do @@ -317,18 +318,16 @@ module.enable = function(self) end end - -- hook map reveal functions before and after the actual call - local ShaguTweaksHookWorldMapFrame_Update = _G.WorldMapFrame_Update - _G.WorldMapFrame_Update = function(self) - -- hide all previously set textures + -- Preserve the native updater: clear custom overlays before it runs, then + -- append the reveal layer afterwards. + hooksecurefunc("WorldMapFrame_Update", function() for i = 1, NUM_WORLDMAP_OVERLAYS do - _G[string.format("%s%s","WorldMapOverlay",i)]:Hide() + local texture = _G[string.format("%s%s","WorldMapOverlay",i)] + if texture then texture:Hide() end end + end, true) - -- let the game put its explored tiles on the map - ShaguTweaksHookWorldMapFrame_Update(self) - - -- let the addon extend it with its own data + hooksecurefunc("WorldMapFrame_Update", function() ShaguTweaksWorldMapFrame_Update() - end + end) end