diff --git a/WeakAuras/AuraEnvironment.lua b/WeakAuras/AuraEnvironment.lua index 2857ec0..23819d8 100644 --- a/WeakAuras/AuraEnvironment.lua +++ b/WeakAuras/AuraEnvironment.lua @@ -514,8 +514,20 @@ local exec_env_custom = setmetatable({}, return {} elseif overridden[k] then return overridden[k] - else + elseif _G[k] then return _G[k] + elseif k:find(".", 1, true) then + local f + for i, n in ipairs{strsplit(".", k)} do + if i == 1 then + f = _G[n] + elseif f then + f = f[n] + else + return + end + end + return f end end, __newindex = function(table, key, value) diff --git a/WeakAuras/Compatibility.lua b/WeakAuras/Compatibility.lua index 4754f80..010a447 100644 --- a/WeakAuras/Compatibility.lua +++ b/WeakAuras/Compatibility.lua @@ -70,6 +70,24 @@ function MergeTable(t1, t2) return merged end +function tCompare(t1, t2) + for k, v in pairs(t1) do + if type(v) == "table" and type(t2[k]) == "table" then + if not tCompare(v, t2[k]) then + return false + end + elseif t2[k] ~= v then + return false + end + end + for k in pairs(t2) do + if t1[k] == nil then + return false + end + end + return true +end + function IsInGroup() return GetNumPartyMembers() > 0 or GetNumRaidMembers() > 0 end diff --git a/WeakAuras/Prototypes.lua b/WeakAuras/Prototypes.lua index 0f92bc3..cf43d06 100644 --- a/WeakAuras/Prototypes.lua +++ b/WeakAuras/Prototypes.lua @@ -647,6 +647,68 @@ Private.tinySecondFormat = function(value) end end +function Private.ExecEnv.ParseStringCheck(input) + if not input then return end + local matcher = { + entries = {}, + negativeEntries = {}, + Check = function(self, e) + return false + end, + CheckBoth = function(self, e) + return self.entries[e] and not self.negativeEntries[e] + end, + CheckPositive = function(self, e) + return self.entries[e] + end, + CheckNegative = function(self, e) + return not self.negativeEntries[e] + end, + Add = function(self, e, negate) + if negate then + self.negativeEntries[e] = true + else + self.entries[e] = true + end + end + } + + local start = 1 + local escaped = false + local partial = "" + local negate = false + for i = 1, #input do + local c = input:sub(i, i) + if escaped then + escaped = false + elseif c == '\\' then + partial = partial .. input:sub(start, i - 1) + start = i + 1 + escaped = true + elseif c == "," then + matcher:Add(partial .. input:sub(start, i - 1):trim(), negate) + start = i + 1 + partial = "" + negate = false + elseif c == "-" and partial:trim() == "" and input:sub(start, i - 1):trim() == "" then + start = i + 1 + negate = true + end + end + matcher:Add(partial .. input:sub(start, #input):trim(), negate) + + -- Update check function + if next(matcher.entries) and next(matcher.negativeEntries) then + matcher.Check = matcher.CheckBoth + elseif next(matcher.entries) then + matcher.Check = matcher.CheckPositive + elseif next(matcher.negativeEntries) then + matcher.Check = matcher.CheckNegative + end + + return matcher +end + function WeakAuras.ValidateNumericOrPercent(info, val) if val ~= nil and val ~= "" then local percent = string.match(val, "(%d+)%%") @@ -1077,7 +1139,7 @@ Private.load_prototype = { test = "zoneChecker:Check(zone)", events = {"ZONE_CHANGED", "ZONE_CHANGED_INDOORS", "ZONE_CHANGED_NEW_AREA", "VEHICLE_UPDATE", "WA_DELAYED_PLAYER_ENTERING_WORLD" }, desc = function() - return ("\n|cffffd200%s|r%s\n\n%s"):format(L["Current Zone\n"], GetRealZoneText(), L["Supports multiple entries, separated by commas"]) + return ("\n|cffffd200%s|r%s\n\n%s"):format(L["Current Zone\n"], GetRealZoneText(), L["Supports multiple entries, separated by commas. Escape ',' with \\. Prefix with '-' for negation."]) end, optional = true, }, @@ -1090,7 +1152,7 @@ Private.load_prototype = { test = "WeakAuras.CheckNumericIds(%q, zoneId)", events = {"ZONE_CHANGED", "ZONE_CHANGED_INDOORS", "ZONE_CHANGED_NEW_AREA", "VEHICLE_UPDATE", "WA_DELAYED_PLAYER_ENTERING_WORLD" }, desc = function() - return ("\n|cffffd200%s|r%s: %d\n\n%s"):format(L["Current Zone\n"], GetRealZoneText(), GetCurrentMapAreaID(), L["Supports multiple entries, separated by commas"]) + return ("\n|cffffd200%s|r%s: %d\n\n%s"):format(L["Current Zone\n"], GetRealZoneText(), GetCurrentMapAreaID(), L["Supports multiple entries, separated by commas. Escape ',' with \\. Prefix with '-' for negation."]) end, optional = true, }, @@ -1104,7 +1166,7 @@ Private.load_prototype = { test = "subzoneChecker:Check(subzone)", events = { "ZONE_CHANGED", "ZONE_CHANGED_INDOORS", "ZONE_CHANGED_NEW_AREA", "VEHICLE_UPDATE", "WA_DELAYED_PLAYER_ENTERING_WORLD" }, desc = function() - return ("\n|cffffd200%s|r%s\n\n%s"):format(L["Current Zone\n"], GetMinimapZoneText(), L["Supports multiple entries, separated by commas"]) + return ("\n|cffffd200%s|r%s\n\n%s"):format(L["Current Zone\n"], GetMinimapZoneText(), L["Supports multiple entries, separated by commas. Escape ',' with \\. Prefix with '-' for negation."]) end, optional = true, }, @@ -1608,7 +1670,7 @@ Private.event_prototypes = { return preamble:Check(state.npcId) end, operator_types = "none", - desc = L["Supports multiple entries, separated by commas"], + desc = L["Supports multiple entries, separated by commas. Escape ',' with \\. Prefix with '-' for negation."], enable = function(trigger) return not trigger.use_inverse end, @@ -1977,7 +2039,7 @@ Private.event_prototypes = { return preamble:Check(state.npcId) end, operator_types = "none", - desc = L["Supports multiple entries, separated by commas"], + desc = L["Supports multiple entries, separated by commas. Escape ',' with \\. Prefix with '-' for negation."], enable = function(trigger) return not trigger.use_inverse end, @@ -2332,7 +2394,7 @@ Private.event_prototypes = { return preamble:Check(state.npcId) end, operator_types = "none", - desc = L["Supports multiple entries, separated by commas"], + desc = L["Supports multiple entries, separated by commas. Escape ',' with \\. Prefix with '-' for negation."], enable = function(trigger) return not trigger.use_inverse end, @@ -2504,7 +2566,7 @@ Private.event_prototypes = { conditionType = "string", preamble = "local sourceNameChecker = Private.ExecEnv.ParseStringCheck(%q)", test = "sourceNameChecker:Check(sourceName)", - desc = L["Supports multiple entries, separated by commas"], + desc = L["Supports multiple entries, separated by commas. Escape ',' with \\. Prefix with '-' for negation."], }, { name = "sourceNpcId", @@ -2523,7 +2585,7 @@ Private.event_prototypes = { return preamble:Check(state.sourceNpcId) end, operator_types = "none", - desc = L["Supports multiple entries, separated by commas"], + desc = L["Supports multiple entries, separated by commas. Escape ',' with \\. Prefix with '-' for negation."], enable = function(trigger) return not (trigger.subeventPrefix == "ENVIRONMENTAL") end, @@ -2641,7 +2703,7 @@ Private.event_prototypes = { conditionType = "string", preamble = "local destNameChecker = Private.ExecEnv.ParseStringCheck(%q)", test = "destNameChecker:Check(destName)", - desc = L["Supports multiple entries, separated by commas"], + desc = L["Supports multiple entries, separated by commas. Escape ',' with \\. Prefix with '-' for negation."], enable = function(trigger) return not (trigger.subeventPrefix == "SPELL" and trigger.subeventSuffix == "_CAST_START"); end, @@ -2663,7 +2725,7 @@ Private.event_prototypes = { return preamble:Check(state.destNpcId) end, operator_types = "none", - desc = L["Supports multiple entries, separated by commas"], + desc = L["Supports multiple entries, separated by commas. Escape ',' with \\. Prefix with '-' for negation."], enable = function(trigger) return not (trigger.subeventPrefix == "SPELL" and trigger.subeventSuffix == "_CAST_START"); end, @@ -5098,10 +5160,20 @@ Private.event_prototypes = { { name = "enchant", display = L["Weapon Enchant"], - desc = L["Enchant Name"], + desc = L["Enchant Name or ID"], type = "string", test = "true" }, + { + name = "enchantID", + hidden = true, + test = "true", + display = L["Enchant ID"], + store = true, + conditionType = "number", + operator_types = "only_equal", + noProgressSource = true + }, { name = "stacks", display = L["Stack Count"], @@ -5145,6 +5217,18 @@ Private.event_prototypes = { test = "true", store = true }, + { + name = "enchanted", + display = L["Enchanted"], + hidden = true, + init = "found == true", + test = "true", + store = true, + conditionType = "bool", + conditionTest = function(state, needle) + return state and state.show and state.enchanted == (needle == 1) + end, + }, { name = "remaining", display = L["Remaining Time"], @@ -5903,7 +5987,7 @@ Private.event_prototypes = { return preamble:Check(state.name) end, operator_types = "none", - desc = L["Supports multiple entries, separated by commas"] + desc = L["Supports multiple entries, separated by commas. Escape ',' with \\. Prefix with '-' for negation."] }, { name = "npcId", @@ -5922,7 +6006,7 @@ Private.event_prototypes = { return preamble:Check(state.npcId) end, operator_types = "none", - desc = L["Supports multiple entries, separated by commas"] + desc = L["Supports multiple entries, separated by commas. Escape ',' with \\. Prefix with '-' for negation."] }, { name = "value", @@ -6218,7 +6302,7 @@ Private.event_prototypes = { return preamble:Check(state.npcId) end, operator_types = "none", - desc = L["Supports multiple entries, separated by commas"], + desc = L["Supports multiple entries, separated by commas. Escape ',' with \\. Prefix with '-' for negation."], enable = function(trigger) return not trigger.use_inverse end, @@ -7585,7 +7669,7 @@ Private.event_prototypes = { name = "zoneIds", display = L["Player Location ID(s)"], desc = function() - return ("\n|cffffd200%s|r%s: %d\n\n%s"):format(L["Current Zone\n"], GetRealZoneText(), GetCurrentMapAreaID(), L["Supports multiple entries, separated by commas"]) + return ("\n|cffffd200%s|r%s: %d\n\n%s"):format(L["Current Zone\n"], GetRealZoneText(), GetCurrentMapAreaID(), L["Supports multiple entries, separated by commas. Escape ',' with \\. Prefix with '-' for negation."]) end, type = "string", multiline = true, diff --git a/WeakAuras/RegionTypes/StopMotion.lua b/WeakAuras/RegionTypes/StopMotion.lua index 13d435b..f2b0684 100644 --- a/WeakAuras/RegionTypes/StopMotion.lua +++ b/WeakAuras/RegionTypes/StopMotion.lua @@ -493,6 +493,7 @@ local function modify(parent, region, data) region.FrameTick = FrameTickFunctions.timed region.subRegionEvents:AddSubscriber("FrameTick", region, true) function region:Update() + region:UpdateProgress() end elseif data.animationType == "progress" then diff --git a/WeakAuras/Types.lua b/WeakAuras/Types.lua index 71e5d11..2577853 100644 --- a/WeakAuras/Types.lua +++ b/WeakAuras/Types.lua @@ -876,8 +876,9 @@ Private.faction_group = { Private.form_types = {}; local function update_forms() - wipe(Private.form_types); - Private.form_types[0] = "0 - "..L["Humanoid"] + local oldForms = Private.form_types + Private.form_types = {} + Private.form_types[0] = "0 - " .. L["Humanoid"] for i = 1, GetNumShapeshiftForms() do local _, name = GetShapeshiftFormInfo(i); if(name) then @@ -885,6 +886,9 @@ local function update_forms() end end end +if Private.OptionsFrame and not tCompare(oldForms, Private.form_types) then + Private.OptionsFrame():ReloadOptions() +end local form_frame = CreateFrame("Frame"); form_frame:RegisterEvent("UPDATE_SHAPESHIFT_FORMS") form_frame:RegisterEvent("PLAYER_LOGIN") diff --git a/WeakAuras/WeakAuras.lua b/WeakAuras/WeakAuras.lua index 72dd189..4c55c2e 100644 --- a/WeakAuras/WeakAuras.lua +++ b/WeakAuras/WeakAuras.lua @@ -81,7 +81,7 @@ do local currentErrorHandlerUid local currentErrorHandlerContext local function waErrorHandler(errorMessage) - local prefix = "" + local juicedMessage = {} local data if currentErrorHandlerId then data = WeakAuras.GetData(currentErrorHandlerId) @@ -91,23 +91,27 @@ do if data then Private.AuraWarnings.UpdateWarning(data.uid, "LuaError", "error", L["This aura has caused a Lua error."] .. "\n" .. L["Install the addons BugSack and BugGrabber for detailed error logs."], true) - prefix = L["Lua error in aura '%s': %s"]:format(data.id, currentErrorHandlerContext or L["unknown location"]) .. "\n" + table.insert(juicedMessage, L["Lua error in aura '%s': %s"]:format(data.id, currentErrorHandlerContext or L["unknown location"])) else - prefix = L["Lua error"] .. "\n" + table.insert(juicedMessage, L["Lua error"]) end - prefix = prefix .. L["WeakAuras Version: %s"]:format(WeakAuras.versionString) .. "\n" + table.insert(juicedMessage, L["WeakAuras Version: %s"]:format(WeakAuras.versionString)) local version = data and (data.semver or data.version) if version then - prefix = prefix .. L["Aura Version: %s"]:format(version) .. "\n" + table.insert(juicedMessage, L["Aura Version: %s"]:format(version)) end - geterrorhandler()(prefix .. errorMessage) + table.insert(juicedMessage, L["Stack trace:"]) + table.insert(juicedMessage, errorMessage) + geterrorhandler()(table.concat(juicedMessage, "\n")) end + function Private.GetErrorHandlerId(id, context) currentErrorHandlerUid = nil currentErrorHandlerId = id currentErrorHandlerContext = context return waErrorHandler end + function Private.GetErrorHandlerUid(uid, context) currentErrorHandlerUid = uid currentErrorHandlerId = nil @@ -5335,22 +5339,22 @@ function WeakAuras.SafeToNumber(input) end local textSymbols = { - ["{rt1}"] = "|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_1:0|t", - ["{rt2}"] = "|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_2:0|t", - ["{rt3}"] = "|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_3:0|t", - ["{rt4}"] = "|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_4:0|t", - ["{rt5}"] = "|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_5:0|t", - ["{rt6}"] = "|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_6:0|t", - ["{rt7}"] = "|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_7:0|t", - ["{rt8}"] = "|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_8:0|t", - ["{rt9}"] = "|TInterface\\TargetingFrame\\UI-RaidTargetingIcons.blp:0:0:0:0:64:64:0:16:32:48|t", - ["{rt10}"] = "|TInterface\\TargetingFrame\\UI-RaidTargetingIcons.blp:0:0:0:0:64:64:16:32:32:48|t", - ["{rt11}"] = "|TInterface\\TargetingFrame\\UI-RaidTargetingIcons.blp:0:0:0:0:64:64:32:48:32:48|t", - ["{rt12}"] = "|TInterface\\TargetingFrame\\UI-RaidTargetingIcons.blp:0:0:0:0:64:64:48:64:32:48|t", - ["{rt13}"] = "|TInterface\\TargetingFrame\\UI-RaidTargetingIcons.blp:0:0:0:0:64:64:0:16:48:64|t", - ["{rt14}"] = "|TInterface\\TargetingFrame\\UI-RaidTargetingIcons.blp:0:0:0:0:64:64:16:32:48:64|t", - ["{rt15}"] = "|TInterface\\TargetingFrame\\UI-RaidTargetingIcons.blp:0:0:0:0:64:64:32:48:48:64|t", - ["{rt16}"] = "|TInterface\\TargetingFrame\\UI-RaidTargetingIcons.blp:0:0:0:0:64:64:48:64:48:64|t" + ["{rt1}"] = "|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_1:0|t", + ["{rt2}"] = "|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_2:0|t", + ["{rt3}"] = "|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_3:0|t", + ["{rt4}"] = "|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_4:0|t", + ["{rt5}"] = "|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_5:0|t", + ["{rt6}"] = "|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_6:0|t", + ["{rt7}"] = "|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_7:0|t", + ["{rt8}"] = "|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_8:0|t", + ["{rt9}"] = "|TInterface\\TargetingFrame\\UI-RaidTargetingIcons.blp:0:0:0:0:64:64:0:16:32:48|t", + ["{rt10}"] = "|TInterface\\TargetingFrame\\UI-RaidTargetingIcons.blp:0:0:0:0:64:64:16:32:32:48|t", + ["{rt11}"] = "|TInterface\\TargetingFrame\\UI-RaidTargetingIcons.blp:0:0:0:0:64:64:32:48:32:48|t", + ["{rt12}"] = "|TInterface\\TargetingFrame\\UI-RaidTargetingIcons.blp:0:0:0:0:64:64:48:64:32:48|t", + ["{rt13}"] = "|TInterface\\TargetingFrame\\UI-RaidTargetingIcons.blp:0:0:0:0:64:64:0:16:48:64|t", + ["{rt14}"] = "|TInterface\\TargetingFrame\\UI-RaidTargetingIcons.blp:0:0:0:0:64:64:16:32:48:64|t", + ["{rt15}"] = "|TInterface\\TargetingFrame\\UI-RaidTargetingIcons.blp:0:0:0:0:64:64:32:48:48:64|t", + ["{rt16}"] = "|TInterface\\TargetingFrame\\UI-RaidTargetingIcons.blp:0:0:0:0:64:64:48:64:48:64|t", } function WeakAuras.ReplaceRaidMarkerSymbols(txt) @@ -5549,40 +5553,6 @@ function Private.ExecEnv.ParseZoneCheck(input) return matcher end -function Private.ExecEnv.ParseStringCheck(input) - if not input then return end - local matcher = { - zones = {}, - Check = function(self, zone) - return self.zones[zone] - end, - Add = function(self, z) - self.zones[z] = true - end - } - - local start = 1 - local escaped = false - local partial = "" - for i = 1, #input do - local c = input:sub(i, i) - if escaped then - escaped = false - elseif c == '\\' then - partial = partial .. input:sub(start, i - 1) - start = i + 1 - escaped = true - elseif c == "," then - matcher:Add(partial .. input:sub(start, i - 1):trim()) - start = i + 1 - partial = "" - end - end - matcher:Add(partial .. input:sub(start, #input):trim()) - - return matcher -end - function WeakAuras.IsAuraLoaded(id) return Private.loaded[id] end diff --git a/WeakAurasOptions/BuffTrigger2.lua b/WeakAurasOptions/BuffTrigger2.lua index 445d01f..ff66d6a 100644 --- a/WeakAurasOptions/BuffTrigger2.lua +++ b/WeakAurasOptions/BuffTrigger2.lua @@ -798,10 +798,14 @@ local function GetBuffTriggerOptions(data, triggernum) useHostility = { type = "toggle", width = WeakAuras.normalWidth, - name = L["Filter by Nameplate Type"], + name = L["Filter by Hostility"], order = 69.1, - hidden = function() return - not (trigger.type == "aura2" and trigger.unit == "nameplate") + hidden = function() + return not (trigger.type == "aura2" + and (trigger.unit == "group" + or trigger.unit == "raid" + or trigger.unit == "party" + or trigger.unit == "nameplate")) end }, hostility = { @@ -809,7 +813,14 @@ local function GetBuffTriggerOptions(data, triggernum) width = WeakAuras.normalWidth, name = L["Hostility"], values = OptionsPrivate.Private.hostility_types, - hidden = function() return not (trigger.type == "aura2" and trigger.useHostility) end, + hidden = function() + return not (trigger.type == "aura2" + and trigger.useHostility + and (trigger.unit == "group" + or trigger.unit == "raid" + or trigger.unit == "party" + or trigger.unit == "nameplate")) + end, order = 69.2 }, hostilitySpace = { @@ -817,7 +828,14 @@ local function GetBuffTriggerOptions(data, triggernum) name = "", order = 69.3, width = WeakAuras.normalWidth, - hidden = function() return not (trigger.type == "aura2" and trigger.unit == "nameplate" and not trigger.useHostility) end + hidden = function() + return not (trigger.type == "aura2" + and not trigger.useHostility + and (trigger.unit == "group" + or trigger.unit == "raid" + or trigger.unit == "party" + or trigger.unit == "nameplate")) + end }, useNpcId = { diff --git a/WeakAurasOptions/Cache.lua b/WeakAurasOptions/Cache.lua index b036ff9..b3edab5 100644 --- a/WeakAurasOptions/Cache.lua +++ b/WeakAurasOptions/Cache.lua @@ -92,7 +92,7 @@ function spellCache.GetIcon(name) if (icons) then if (icons.spells) then for spellId, icon in pairs(icons.spells) do - if not bestMatch or (type(spellId) == "number" and IsSpellKnown(spellId)) then + if not bestMatch or (type(spellId) == "number" and spellId ~= 0 and IsSpellKnown(spellId)) then bestMatch = spellId end end diff --git a/WeakAurasOptions/OptionsFrames/FrameChooser.lua b/WeakAurasOptions/OptionsFrames/FrameChooser.lua index f1daa70..f9037ad 100644 --- a/WeakAurasOptions/OptionsFrames/FrameChooser.lua +++ b/WeakAurasOptions/OptionsFrames/FrameChooser.lua @@ -16,6 +16,23 @@ local frameChooserBox local oldFocus local oldFocusName + +-- if frame doesn't have a name, try to use the key from it's parent +local function recurseGetName(frame) + local name = frame.GetName and frame:GetName() or nil + if name then + return name + end + local parent = frame.GetParent and frame:GetParent() + if parent then + for key, child in pairs(parent) do + if child == frame then + return (recurseGetName(parent) or "") .. "." .. key + end + end + end +end + function OptionsPrivate.StartFrameChooser(data, path) local frame = OptionsPrivate.Private.OptionsFrame(); if not(frameChooserFrame) then @@ -46,7 +63,7 @@ function OptionsPrivate.StartFrameChooser(data, path) local focusName; if(focus) then - focusName = focus:GetName(); + focusName = recurseGetName(focus) if(focusName == "WorldFrame" or not focusName) then focusName = nil; local focusIsGroup = false; diff --git a/WeakAurasOptions/OptionsFrames/OptionsFrame.lua b/WeakAurasOptions/OptionsFrames/OptionsFrame.lua index 0de081a..38da717 100644 --- a/WeakAurasOptions/OptionsFrames/OptionsFrame.lua +++ b/WeakAurasOptions/OptionsFrames/OptionsFrame.lua @@ -975,6 +975,13 @@ function OptionsPrivate.CreateFrame() end end + frame.ReloadOptions = function(self) + if self.pickedDisplay then + self:ClearAndUpdateOptions(self.pickedDisplay, true) + self:FillOptions() + end + end + frame.ClearAndUpdateOptions = function(self, id, clearChildren) frame:ClearOptions(id)