Files
coa-weakauras/WeakAuras/Prototypes.lua
T
NoM0Re 909a0e97f9 (fix/Prototypes) Add inRange trigger properly to Prototypes too
(cherry picked from commit ade6cb124a76fbb5ebd1a91936f1cb188d70789f)
2026-02-16 08:21:25 -07:00

9017 lines
264 KiB
Lua

if not WeakAuras.IsLibsOK() then return end
local AddonName = ...
local Private = select(2, ...)
-- Lua APIs
local tinsert, tsort = table.insert, table.sort
local tostring = tostring
local select, pairs, type = select, pairs, type
local ceil = ceil
-- WoW APIs
local GetTalentInfo = GetTalentInfo
local UnitClass = UnitClass
local GetSpellInfo, GetItemInfo, GetItemCount, GetItemIcon = GetSpellInfo, GetItemInfo, GetItemCount, GetItemIcon
local GetShapeshiftFormInfo, GetShapeshiftForm = GetShapeshiftFormInfo, GetShapeshiftForm
local GetRuneCooldown, UnitCastingInfo, UnitChannelInfo = GetRuneCooldown, UnitCastingInfo, UnitChannelInfo
local UnitDetailedThreatSituation = UnitDetailedThreatSituation
local MAX_NUM_TALENTS = MAX_NUM_TALENTS or 40
local WeakAuras = WeakAuras
local L = WeakAuras.L
local SpellRange = LibStub("SpellRange-1.0")
function WeakAuras.IsSpellInRange(spellId, unit)
return SpellRange.IsSpellInRange(spellId, unit)
end
local LibRangeCheck = LibStub("LibRangeCheck-2.0")
function WeakAuras.GetRange(unit, checkVisible)
return LibRangeCheck:GetRange(unit, checkVisible);
end
function WeakAuras.CheckRange(unit, range, operator)
local min, max = LibRangeCheck:GetRange(unit, true);
if (type(range) ~= "number") then
range = tonumber(range);
end
if (not range) then
return
end
if (operator == "<=") then
return (max or 999) <= range;
else
return (min or 0) >= range;
end
end
local RangeCacheStrings = {friend = "", harm = "", misc = ""}
local function RangeCacheUpdate()
local friend, harm, misc = {}, {}, {}
local friendString, harmString, miscString
for range in LibRangeCheck:GetFriendCheckers() do
tinsert(friend, range)
end
tsort(friend)
for range in LibRangeCheck:GetHarmCheckers() do
tinsert(harm, range)
end
tsort(harm)
for range in LibRangeCheck:GetMiscCheckers() do
tinsert(misc, range)
end
tsort(misc)
for _, key in pairs(friend) do
friendString = (friendString and (friendString .. ", ") or "") .. key
end
for _, key in pairs(harm) do
harmString = (harmString and (harmString .. ", ") or "") .. key
end
for _, key in pairs(misc) do
miscString = (miscString and (miscString .. ", ") or "") .. key
end
RangeCacheStrings.friend, RangeCacheStrings.harm, RangeCacheStrings.misc = friendString, harmString, miscString
end
LibRangeCheck:RegisterCallback(LibRangeCheck.CHECKERS_CHANGED, RangeCacheUpdate)
function WeakAuras.UnitDetailedThreatSituation(unit1, unit2)
local ok, aggro, status, threatpct, rawthreatpct, threatvalue = pcall(UnitDetailedThreatSituation, unit1, unit2)
if ok then
return aggro, status, threatpct, rawthreatpct, threatvalue
end
end
local constants = {
nameRealmFilterDesc = L[" Filter formats: 'Name', 'Name-Realm', '-Realm'. \n\nSupports multiple entries, separated by commas\nCan use \\ to escape -."],
instanceFilterDeprecated = L["This filter has been moved to the Location trigger. Change your aura to use the new Location trigger or join the WeakAuras Discord server for help."],
guildFilterDesc = L["Supports multiple entries, separated by commas. Escape with \\. Prefix with '-' for negation."],
encounterDBMDesc = (WeakAuras.IsDBMRegistered() and "" or "|cFFFF0000") .. L["Requires Deadly Boss Mods (DBM) to detect encounters."] .. (WeakAuras.IsDBMRegistered() and "" or "|r")
}
WeakAuras.UnitRaidRole = function(unit)
local raidID = UnitInRaid(unit)
if raidID then
return select(10, GetRaidRosterInfo(raidID + 1)) or "NONE"
end
end
function WeakAuras.SpellSchool(school)
return Private.combatlog_spell_school_types[school] or ""
end
function WeakAuras.RaidFlagToIndex(flag)
return Private.combatlog_raidFlags[flag] or 0
end
Private.function_strings = {
count = [[
return function(count)
if(count %s %s) then
return true
else
return false
end
end
]],
count_fraction = [[
return function(count, max)
if max == 0 then
return false
end
local fraction = count/max
if(fraction %s %s) then
return true
else
return false
end
end
]],
always = [[
return function()
return true
end
]]
};
local hsvFrame = CreateFrame("ColorSelect")
-- HSV transition, for a much prettier color transition in many cases
-- see http://www.wowinterface.com/forums/showthread.php?t=48236
function WeakAuras.GetHSVTransition(perc, r1, g1, b1, a1, r2, g2, b2, a2)
--get hsv color for colorA
hsvFrame:SetColorRGB(r1, g1, b1)
local h1, s1, v1 = hsvFrame:GetColorHSV() -- hue, saturation, value
--get hsv color for colorB
hsvFrame:SetColorRGB(r2, g2, b2)
local h2, s2, v2 = hsvFrame:GetColorHSV() -- hue, saturation, value
local h3 = floor(h1 - (h1 - h2) * perc)
-- find the shortest arc through the color circle, then interpolate
local diff = h2 - h1
if diff < -180 then
diff = diff + 360
elseif diff > 180 then
diff = diff - 360
end
h3 = (h1 + perc * diff) % 360
local s3 = s1 - ( s1 - s2 ) * perc
local v3 = v1 - ( v1 - v2 ) * perc
--get the RGB values of the new color
hsvFrame:SetColorHSV(h3, s3, v3)
local r, g, b = hsvFrame:GetColorRGB()
--interpolate alpha
local a = a1 - ( a1 - a2 ) * perc
--return the new color
return r, g, b, a
end
Private.anim_function_strings = {
straight = [[
function(progress, start, delta)
return start + (progress * delta)
end
]],
straightTranslate = [[
function(progress, startX, startY, deltaX, deltaY)
return startX + (progress * deltaX), startY + (progress * deltaY)
end
]],
straightScale = [[
function(progress, startX, startY, scaleX, scaleY)
return startX + (progress * (scaleX - startX)), startY + (progress * (scaleY - startY))
end
]],
straightColor = [[
function(progress, r1, g1, b1, a1, r2, g2, b2, a2)
return r1 + (progress * (r2 - r1)), g1 + (progress * (g2 - g1)), b1 + (progress * (b2 - b1)), a1 + (progress * (a2 - a1))
end
]],
straightHSV = [[
function(progress, r1, g1, b1, a1, r2, g2, b2, a2)
return WeakAuras.GetHSVTransition(progress, r1, g1, b1, a1, r2, g2, b2, a2)
end
]],
circle = [[
function(progress, startX, startY, deltaX, deltaY)
local angle = progress * 2 * math.pi
return startX + (deltaX * math.cos(angle)), startY + (deltaY * math.sin(angle))
end
]],
circle2 = [[
function(progress, startX, startY, deltaX, deltaY)
local angle = progress * 2 * math.pi
return startX + (deltaX * math.sin(angle)), startY + (deltaY * math.cos(angle))
end
]],
spiral = [[
function(progress, startX, startY, deltaX, deltaY)
local angle = progress * 2 * math.pi
return startX + (progress * deltaX * math.cos(angle)), startY + (progress * deltaY * math.sin(angle))
end
]],
spiralandpulse = [[
function(progress, startX, startY, deltaX, deltaY)
local angle = (progress + 0.25) * 2 * math.pi
return startX + (math.cos(angle) * deltaX * math.cos(angle*2)), startY + (math.abs(math.cos(angle)) * deltaY * math.sin(angle*2))
end
]],
shake = [[
function(progress, startX, startY, deltaX, deltaY)
local prog
if(progress < 0.25) then
prog = progress * 4
elseif(progress < .75) then
prog = 2 - (progress * 4)
else
prog = (progress - 1) * 4
end
return startX + (prog * deltaX), startY + (prog * deltaY)
end
]],
starShakeDecay = [[
function(progress, startX, startY, deltaX, deltaY)
local spokes = 10
local fullCircles = 4
local r = min(abs(deltaX), abs(deltaY))
local xScale = deltaX / r
local yScale = deltaY / r
local deltaAngle = fullCircles *2 / spokes * math.pi
local p = progress * spokes
local i1 = floor(p)
p = p - i1
local angle1 = i1 * deltaAngle
local angle2 = angle1 + deltaAngle
local x1 = r * math.cos(angle1)
local y1 = r * math.sin(angle1)
local x2 = r * math.cos(angle2)
local y2 = r * math.sin(angle2)
local x, y = p * x2 + (1-p) * x1, p * y2 + (1-p) * y1
local ease = math.sin(progress * math.pi / 2)
return ease * x * xScale, ease * y * yScale
end
]],
bounceDecay = [[
function(progress, startX, startY, deltaX, deltaY)
local prog = (progress * 3.5) % 1
local bounce = math.ceil(progress * 3.5)
local bounceDistance = math.sin(prog * math.pi) * (bounce / 4)
return startX + (bounceDistance * deltaX), startY + (bounceDistance * deltaY)
end
]],
bounce = [[
function(progress, startX, startY, deltaX, deltaY)
local bounceDistance = math.sin(progress * math.pi)
return startX + (bounceDistance * deltaX), startY + (bounceDistance * deltaY)
end
]],
flash = [[
function(progress, start, delta)
local prog
if(progress < 0.5) then
prog = progress * 2
else
prog = (progress - 1) * 2
end
return start + (prog * delta)
end
]],
pulse = [[
function(progress, startX, startY, scaleX, scaleY)
local angle = (progress * 2 * math.pi) - (math.pi / 2)
return startX + (((math.sin(angle) + 1)/2) * (scaleX - 1)), startY + (((math.sin(angle) + 1)/2) * (scaleY - 1))
end
]],
alphaPulse = [[
function(progress, start, delta)
local angle = (progress * 2 * math.pi) - (math.pi / 2)
return start + (((math.sin(angle) + 1)/2) * delta)
end
]],
pulseColor = [[
function(progress, r1, g1, b1, a1, r2, g2, b2, a2)
local angle = (progress * 2 * math.pi) - (math.pi / 2)
local newProgress = ((math.sin(angle) + 1)/2);
return r1 + (newProgress * (r2 - r1)),
g1 + (newProgress * (g2 - g1)),
b1 + (newProgress * (b2 - b1)),
a1 + (newProgress * (a2 - a1))
end
]],
pulseHSV = [[
function(progress, r1, g1, b1, a1, r2, g2, b2, a2)
local angle = (progress * 2 * math.pi) - (math.pi / 2)
local newProgress = ((math.sin(angle) + 1)/2);
return WeakAuras.GetHSVTransition(newProgress, r1, g1, b1, a1, r2, g2, b2, a2)
end
]],
fauxspin = [[
function(progress, startX, startY, scaleX, scaleY)
local angle = progress * 2 * math.pi
return math.cos(angle) * scaleX, startY + (progress * (scaleY - startY))
end
]],
fauxflip = [[
function(progress, startX, startY, scaleX, scaleY)
local angle = progress * 2 * math.pi
return startX + (progress * (scaleX - startX)), math.cos(angle) * scaleY
end
]],
backandforth = [[
function(progress, start, delta)
local prog
if(progress < 0.25) then
prog = progress * 4
elseif(progress < .75) then
prog = 2 - (progress * 4)
else
prog = (progress - 1) * 4
end
return start + (prog * delta)
end
]],
wobble = [[
function(progress, start, delta)
local angle = progress * 2 * math.pi
return start + math.sin(angle) * delta
end
]],
hide = [[
function()
return 0
end
]]
};
Private.anim_presets = {
-- Start and Finish
slidetop = {
type = "custom",
duration = 0.25,
use_translate = true,
x = 0, y = 50,
use_alpha = true,
alpha = 0
},
slideleft = {
type = "custom",
duration = 0.25,
use_translate = true,
x = -50,
y = 0,
use_alpha = true,
alpha = 0
},
slideright = {
type = "custom",
duration = 0.25,
use_translate = true,
x = 50,
y = 0,
use_alpha = true,
alpha = 0
},
slidebottom = {
type = "custom",
duration = 0.25,
use_translate = true,
x = 0,
y = -50,
use_alpha = true,
alpha = 0
},
fade = {
type = "custom",
duration = 0.25,
use_alpha = true,
alpha = 0
},
grow = {
type = "custom",
duration = 0.25,
use_scale = true,
scalex = 2,
scaley = 2,
use_alpha = true,
alpha = 0
},
shrink = {
type = "custom",
duration = 0.25,
use_scale = true,
scalex = 0,
scaley = 0,
use_alpha = true,
alpha = 0
},
spiral = {
type = "custom",
duration = 0.5,
use_translate = true,
x = 100,
y = 100,
translateType = "spiral",
use_alpha = true,
alpha = 0
},
bounceDecay = {
type = "custom",
duration = 1.5,
use_translate = true,
x = 50,
y = 50,
translateType = "bounceDecay",
use_alpha = true,
alpha = 0
},
starShakeDecay = {
type = "custom",
duration = 1,
use_translate = true,
x = 50,
y = 50,
translateType = "starShakeDecay",
use_alpha = true,
alpha = 0
},
-- Main
shake = {
type = "custom",
duration = 0.5,
use_translate = true,
x = 10,
y = 0,
translateType = "circle2"
},
spin = {
type = "custom",
duration = 1,
use_scale = true,
scalex = 1,
scaley = 1,
scaleType = "fauxspin"
},
flip = {
type = "custom",
duration = 1,
use_scale = true,
scalex = 1,
scaley = 1,
scaleType = "fauxflip"
},
wobble = {
type = "custom",
duration = 0.5,
use_rotate = true,
rotate = 3,
rotateType = "wobble"
},
pulse = {
type = "custom",
duration = 0.75,
use_scale = true,
scalex = 1.05,
scaley = 1.05,
scaleType = "pulse"
},
alphaPulse = {
type = "custom",
duration = 0.5,
use_alpha = true,
alpha = 0.5,
alphaType = "alphaPulse"
},
rotateClockwise = {
type = "custom",
duration = 4,
use_rotate = true,
rotate = -360
},
rotateCounterClockwise = {
type = "custom",
duration = 4,
use_rotate = true,
rotate = 360
},
spiralandpulse = {
type = "custom",
duration = 6,
use_translate = true,
x = 100,
y = 100,
translateType = "spiralandpulse"
},
circle = {
type = "custom",
duration = 4,
use_translate = true,
x = 100,
y = 100,
translateType = "circle"
},
orbit = {
type = "custom",
duration = 4,
use_translate = true,
x = 100,
y = 100,
translateType = "circle",
use_rotate = true,
rotate = 360
},
bounce = {
type = "custom",
duration = 0.6,
use_translate = true,
x = 0,
y = 25,
translateType = "bounce"
}
};
function WeakAuras.CheckTalentByIndex(index, extraOption)
local tab = ceil(index / MAX_NUM_TALENTS)
local num_talent = (index - 1) % MAX_NUM_TALENTS + 1
local name, _, _, _, rank = GetTalentInfo(tab, num_talent)
if name == nil then
if GetTalentInfo(1, 1) == nil then
-- No talents at all, likely to early to grab
return nil
else
-- Talent doesn't exist; ignore it
-- Should be cleared if missing, but struc doesn't exist yet
return true
end
end
local result = rank and rank > 0
if extraOption == 4 then
return result
elseif extraOption == 5 then
return not result
end
return result;
end
function WeakAuras.CheckNumericIds(loadids, currentId)
if (not loadids or not currentId) then
return false;
end
local searchFrom = 0;
local startI, endI = string.find(loadids, currentId, searchFrom);
while (startI) do
searchFrom = endI + 1; -- start next search from end
if (startI == 1 or tonumber(string.sub(loadids, startI - 1, startI - 1)) == nil) then
-- Either right at start, or character before is not a number
if (endI == string.len(loadids) or tonumber(string.sub(loadids, endI + 1, endI + 1)) == nil) then
return true;
end
end
startI, endI = string.find(loadids, currentId, searchFrom);
end
return false;
end
function WeakAuras.ValidateNumeric(info, val)
if val ~= nil and val ~= "" and (not tonumber(val) or tonumber(val) >= 2^31) then
return false;
end
return true
end
function WeakAuras.ValidateTime(info, val)
if val ~= nil and val ~= "" then
if not tonumber(val) then
if val:sub(1,1) == "-" then
val = val:sub(2, #val)
end
return (val:match("^%d+:%d+:[%d%.]+$") or val:match("^%d+:[%d+%.]+$")) and true or false
elseif tonumber(val) >= 2^31 then
return false
end
end
return true
end
function WeakAuras.TimeToSeconds(val)
if tonumber(val) then
return tonumber(val)
else
local sign = 1
if val:sub(1,1) == "-" then
sign = -1
val = val:sub(2, #val)
end
local h, m, s = val:match("^(%d+):(%d+):([%d%.]+)$")
if h and m and s then
return (h*3600 + m*60 + s) * sign
else
local m, s = val:match("^(%d+):([%d%.]+)$")
if m and s then
return (m*60 + s) * sign
end
end
end
end
Private.tinySecondFormat = function(value)
if type(value) == "string" then value = tonumber(value) end
if type(value) == "number" then
local negative = value < 0
value = math.abs(value)
local fraction = value - math.floor(value)
local ret
if value > 3600 then
ret = ("%i:%02i:%02i"):format(math.floor(value / 3600), math.floor((value % 3600) / 60), value % 60)
elseif value > 60 then
ret = ("%i:%02i"):format(math.floor(value / 60), value % 60)
else
ret = ("%i"):format(value)
end
local negSign = negative and "-" or ""
if fraction > 0 then
return negSign .. ret .. tostring(Round(fraction * 100) / 100):sub(2)
else
return negSign .. ret
end
end
end
function Private.ExecEnv.GetSpecIcon(specID)
return specID and Private.specid_to_icon[specID] or ""
end
function Private.ExecEnv.GetSpecName(specID)
return specID and Private.specid_to_name[specID] or ""
end
function Private.ExecEnv.GetSpecID(specName)
return specName and Private.specname_to_id[specName] or 0
end
function Private.ExecEnv.GetUnitTalentSpec(unit)
local spec = WeakAuras.LGT:GetUnitTalentSpec(unit)
-- LibGroupTalents misses Guardian for tanks, so we fix it here
if spec == L["Feral Combat"] then
return (WeakAuras.LGT:GetUnitRole(unit) == "tank" and L["Guardian"]) or spec
end
return spec
end
function WeakAuras.CheckClassSpec(specID)
specID = tonumber(specID)
if not specID then return end
local class = select(2, UnitClass("player")) or ""
local currentSpec = Private.ExecEnv.GetUnitTalentSpec("player") or ""
return Private.ExecEnv.GetSpecName(specID) == class .. currentSpec
end
function WeakAuras.SpecForUnit(unit)
if not unit then return 0 end
local spec = Private.ExecEnv.GetUnitTalentSpec(unit)
local class = select(2, UnitClass(unit))
return (spec and class) and Private.ExecEnv.GetSpecID(class .. spec) or 0
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 index = val:find("%% *$")
local number = index and tonumber(val:sub(1, index-1)) or tonumber(val)
if(not number or number >= 2^31) then
return false;
end
end
return true
end
function Private.ExecEnv.CheckGroupMemberType(loadSetting, currentFlags)
if loadSetting == "LEADER" then
return bit.band(currentFlags, 1) == 1
elseif loadSetting == "ASSIST" then
return bit.band(currentFlags, 2) == 2
else
return currentFlags == 0
end
end
function Private.ExecEnv.CheckChargesDirection(direction, triggerDirection)
return triggerDirection == "CHANGED"
or (triggerDirection == "GAINED" and direction > 0)
or (triggerDirection == "LOST" and direction < 0)
end
function Private.ExecEnv.CheckCombatLogFlags(flags, flagToCheck)
if type(flags) ~= "number" then return end
if(flagToCheck == "Mine") then
return bit.band(flags, COMBATLOG_OBJECT_AFFILIATION_MINE) > 0
elseif (flagToCheck == "InGroup") then
return bit.band(flags, COMBATLOG_OBJECT_AFFILIATION_OUTSIDER) == 0
elseif (flagToCheck == "InParty") then
return bit.band(flags, COMBATLOG_OBJECT_AFFILIATION_PARTY) > 0
elseif (flagToCheck == "NotInGroup") then
return bit.band(flags, COMBATLOG_OBJECT_AFFILIATION_OUTSIDER) > 0
end
end
function Private.ExecEnv.CheckCombatLogFlagsReaction(flags, flagToCheck)
if type(flags) ~= "number" then return end
if (flagToCheck == "Hostile") then
return bit.band(flags, 64) ~= 0;
elseif (flagToCheck == "Neutral") then
return bit.band(flags, 32) ~= 0;
elseif (flagToCheck == "Friendly") then
return bit.band(flags, 16) ~= 0;
end
end
local objectTypeToBit = {
Object = 16384,
Guardian = 8192,
Pet = 4096,
NPC = 2048,
Player = 1024,
}
function Private.ExecEnv.CheckCombatLogFlagsObjectType(flags, flagToCheck)
if type(flags) ~= "number" then return end
local bitToCheck = objectTypeToBit[flagToCheck]
if not bitToCheck then return end
return bit.band(flags, bitToCheck) ~= 0;
end
function WeakAuras.IsSpellKnownForLoad(spell, exact)
local result = WeakAuras.IsSpellKnown(spell)
if exact or result then
return result
end
-- Dance through the spellname to the current spell id
spell = GetSpellInfo(spell)
if spell then
return WeakAuras.IsSpellKnown(spell)
end
end
function WeakAuras.IsSpellKnown(spell, pet)
local id = tonumber(spell)
if id then
if id > 0 and id < 2^31 then
return IsSpellKnown(id, pet)
end
return false
end
return GetSpellInfo(spell) and true or false
end
function WeakAuras.IsSpellKnownIncludingPet(spell)
if (not spell) then
return false;
end
return WeakAuras.IsSpellKnown(spell, false) or WeakAuras.IsSpellKnown(spell, true)
end
function WeakAuras.IsGlyphActive(glyphID)
for slot = 1, GetNumGlyphSockets() or 6 do
local enabled, _, glyphId = GetGlyphSocketInfo(slot)
if glyphID == glyphId then
return enabled == 1
end
end
return false
end
function WeakAuras.GetEffectiveAttackPower()
local base, pos, neg = UnitAttackPower("player")
return base + pos + neg
end
function WeakAuras.GetEffectiveSpellPower()
-- Straight from the PaperDoll
local spellPower = 0
for i = 2, MAX_SPELL_SCHOOLS or 7 do
spellPower = max(spellPower, GetSpellBonusDamage(i))
end
return spellPower
end
function WeakAuras.GetEffectiveRangedAttackPower()
local base, pos, neg = UnitRangedAttackPower("player")
return base + pos + neg
end
function WeakAuras.IsTalentKnownForLoad(spell, exact)
local result = WeakAuras.IsTalentKnown(spell)
if exact or result then
return result
end
return false
end
function WeakAuras.IsTalentKnown(spell)
if (spell) then
if tonumber(spell) then
return C_CharacterAdvancement.IsKnownSpellID(spell) and true or false;
else
-- name of talent zzz
if (GetSpellInfo(spell)) then -- maybe talent ability?
return true
end
end
end
return false
end
function WeakAuras.IsSpecActive(specID)
specID = specID and tonumber(specID)
if not specID then return false end
return SpecializationUtil.GetActiveSpecialization() == specID
end
function WeakAuras.IsMysticEnchantApplied(spellID)
spellID = spellID and tonumber(spellID)
if not spellID then return false end
return MysticEnchantUtil.IsEnchantApplied("player", spellID)
end
---helper to check if a condition is checked and have a single value, and return it
function Private.checkForSingleLoadCondition(trigger, name, validateFn)
local use_name = "use_"..name
local trigger_use_name = trigger[use_name]
local trigger_name = trigger[name]
if trigger_use_name == true
and trigger_name
and trigger_name.single ~= nil
and (validateFn == nil or validateFn(trigger_name.single))
then
return trigger_name.single
end
if trigger_use_name == false and trigger_name and trigger_name.multi ~= nil then
local count = 0
local key
for k, v in pairs(trigger_name.multi) do
if v ~= nil
and (validateFn == nil or validateFn(k))
then
count = count + 1
key = k
end
end
if count == 1 then
return key
end
end
end
Private.load_prototype = {
-- Each entry
-- name: name of argument for load function/option for options/setting in saved data
-- Options data
-- display: name to be displayed in the options
-- type: type to be used for the options
-- width: width in the options
-- hidden: whether the option is shown in the options, defaults to false
-- Load Function Data
-- enable: whether the test should be tested or not, defaults to true
-- test: overrides the default test
-- init: whether the argument should be a function parameter or not. "arg" for yes. Defaults to no argument
-- events: the events on which the test must be reevaluated
-- optional: whether the test is relevant for the options classification between loaded and unloaded, defaults to false
args = {
{
name ="generalTitle",
display = L["General"],
type = "description",
},
{
name = "combat",
display = L["In Combat"],
type = "tristate",
width = WeakAuras.normalWidth,
init = "arg",
optional = true,
events = {"PLAYER_REGEN_DISABLED", "PLAYER_REGEN_ENABLED"}
},
{
name = "never",
display = L["Never"],
type = "toggle",
width = WeakAuras.normalWidth,
test = "false",
},
{
name = "alive",
display = L["Alive"],
type = "tristate",
init = "arg",
width = WeakAuras.normalWidth,
optional = true,
events = {"PLAYER_DEAD", "PLAYER_ALIVE", "PLAYER_UNGHOST"}
},
{
name = "encounter",
display = WeakAuras.newFeatureString .. L["In Encounter"],
desc = constants.encounterDBMDesc,
type = "tristate",
width = WeakAuras.normalWidth,
init = "arg",
optional = true,
events = {"ENCOUNTER_START", "ENCOUNTER_END"}
},
{
name = "pvpmode",
display = L["PvP Mode Active"],
type = "tristate",
init = "arg",
width = WeakAuras.normalWidth,
optional = true,
events = {"PLAYER_FLAGS_CHANGED", "UNIT_FACTION", "ZONE_CHANGED"}
},
{
name = "manastorm",
display = L["In Manastorm"],
type = "tristate",
init = "arg",
width = WeakAuras.normalWidth,
events = {"ACTIVE_MANASTORM_UPDATED"}
},
{
name = "vehicle",
display = L["In Vehicle"],
type = "tristate",
init = "arg",
width = WeakAuras.normalWidth,
optional = true,
events = {"VEHICLE_UPDATE", "UNIT_ENTERED_VEHICLE", "UNIT_EXITED_VEHICLE", "UNIT_FLAGS"}
},
{
name = "vehicleUi",
display = L["Has Vehicle UI"],
type = "tristate",
init = "arg",
width = WeakAuras.normalWidth,
optional = true,
events = {"VEHICLE_UPDATE", "UNIT_ENTERED_VEHICLE", "UNIT_EXITED_VEHICLE"}
},
{
name = "mounted",
display = L["Mounted"],
type = "tristate",
init = "arg",
width = WeakAuras.normalWidth,
optional = true,
events = {"MOUNTED_UPDATE"}
},
{
name ="playerTitle",
display = L["Player"],
type = "description",
},
{
name = "class",
display = L["Player Class"],
type = "multiselect",
values = "class_types",
init = "arg"
},
{
name = "specialization",
display = L["Talent Specialization"],
type = "multiselect",
values = "specialization_types",
test = "WeakAuras.IsSpecActive(%s)",
preamble = "wipe(WeakAuras.specialization_types) for i = 1, SpecializationUtil.GetNumSpecializations() do WeakAuras.specialization_types[i] = i .. \". \" .. SpecializationUtil.GetSpecializationInfo(i) end",
events = {"ASCENSION_CA_SPECIALIZATION_ACTIVE_ID_CHANGED"},
init = "arg"
},
{
name = "knowntalent",
display = L["Talent"],
type = "talent",
test = "WeakAuras.IsTalentKnownForLoad(%s, %s)",
events = {"ASCENSION_KNOWN_ENTRIES_UPDATED"},
orConjunctionGroup = "knowntalent",
showExactOption = true,
},
{
name = "mysticenchantactive",
display = L["Mystic Enchant"],
type = "mysticenchant",
test = "WeakAuras.IsMysticEnchantApplied(%s)",
events = {"MYSTIC_ENCHANT_PRESET_SET_ACTIVE_RESULT", "MYSTIC_ENCHANT_SLOT_UPDATE", "PLAYER_EQUIPMENT_CHANGED", "SPELLS_CHANGED"},
showExactOption = true,
},
{
name = "not_mysticenchantactive",
display = WeakAuras.newFeatureString .. L["|cFFFF0000Not|r Mystic Enchant"],
type = "mysticenchant",
test = "not WeakAuras.IsMysticEnchantApplied(%s)",
events = {"MYSTIC_ENCHANT_PRESET_SET_ACTIVE_RESULT", "MYSTIC_ENCHANT_SLOT_UPDATE", "PLAYER_EQUIPMENT_CHANGED", "SPELLS_CHANGED"},
showExactOption = true,
},
{
name = "spellknown",
display = L["Spell Known"],
type = "spell",
test = "WeakAuras.IsSpellKnownForLoad(%s, %s)",
events = {"SPELLS_CHANGED", "UNIT_PET"},
showExactOption = true
},
{
name = "not_spellknown",
display = WeakAuras.newFeatureString .. L["|cFFFF0000Not|r Spell Known"],
type = "spell",
test = "not WeakAuras.IsSpellKnownForLoad(%s, %s)",
events = {"SPELLS_CHANGED", "UNIT_PET", "ASCENSION_KNOWN_ENTRIES_UPDATED"},
showExactOption = true
},
{
name = "player",
init = "arg",
enable = false,
hidden = true
},
{
name = "realm",
init = "arg",
enable = false,
hidden = true
},
{
name = "guild",
init = "arg",
enable = false,
hidden = true
},
{
name = "namerealm",
display = L["Player Name/Realm"],
type = "string",
multiline = true,
test = "nameRealmChecker:Check(player, realm)",
preamble = "local nameRealmChecker = Private.ExecEnv.ParseNameCheck(%q)",
desc = constants.nameRealmFilterDesc,
},
{
name = "ignoreNameRealm",
display = L["|cFFFF0000Not|r Player Name/Realm"],
type = "string",
multiline = true,
test = "not nameRealmIgnoreChecker:Check(player, realm)",
preamble = "local nameRealmIgnoreChecker = Private.ExecEnv.ParseNameCheck(%q)",
desc = constants.nameRealmFilterDesc,
},
{
name = "guildcheck",
display = L["Guild"],
type = "string",
multiline = true,
test = "guildChecker:Check(guild)",
preamble = "local guildChecker = Private.ExecEnv.ParseStringCheck(%q)",
desc = constants.guildFilterDesc,
events = {"PLAYER_GUILD_UPDATE"}
},
{
name = "race",
display = L["Player Race"],
type = "multiselect",
values = "race_types",
init = "arg"
},
{
name = "faction",
display = L["Player Faction"],
type = "multiselect",
values = "faction_group",
init = "arg"
},
{
name = "level",
display = L["Player Level"],
type = "number",
init = "arg",
events = {"PLAYER_LEVEL_UP"},
multiEntry = {
operator = "and",
limit = 2
},
},
{
name = "role",
display = L["Spec Role"],
type = "multiselect",
values = "role_types",
init = "arg",
events = {"PLAYER_ROLES_ASSIGNED", "PLAYER_TALENT_UPDATE", "WA_DELAYED_PLAYER_ENTERING_WORLD"}
},
{
name = "spec_position",
display = WeakAuras.newFeatureString .. L["Spec Position"],
type = "multiselect",
values = "spec_position_types",
init = "arg",
events = {"PLAYER_ROLES_ASSIGNED", "PLAYER_TALENT_UPDATE", "WA_DELAYED_PLAYER_ENTERING_WORLD"}
},
{
name = "raid_role",
display = L["Raid Role"],
type = "multiselect",
values = "raid_role_types",
init = "arg",
events = {"PLAYER_ROLES_ASSIGNED"}
},
{
name = "ingroup",
display = L["Group Type"],
type = "multiselect",
width = WeakAuras.normalWidth,
init = "arg",
values = "group_types",
events = {"PARTY_MEMBERS_CHANGED", "RAID_ROSTER_UPDATE"},
optional = true,
},
{
name = "groupSize",
display = L["Group Size"],
type = "number",
init = "arg",
events = {"PARTY_MEMBERS_CHANGED", "RAID_ROSTER_UPDATE"},
multiEntry = {
operator = "and",
limit = 2
},
optional = true,
},
{
name = "group_leader",
display = WeakAuras.newFeatureString .. L["Group Leader/Assist"],
type = "multiselect",
init = "arg",
events = {"PARTY_LEADER_CHANGED", "PLAYER_FLAGS_CHANGED", "RAID_ROSTER_UPDATE"},
values = "group_member_types",
test = "Private.ExecEnv.CheckGroupMemberType(%s, group_leader)",
optional = true,
},
{
name = "ruleset",
display = "PvP Ruleset",
type = "multiselect",
width = WeakAuras.normalWidth,
init = "arg",
values = "ruleset_types",
events = {"ZONE_CHANGED_NEW_AREA", "PLAYER_FLAGS_CHANGED"}
},
{
name ="locationTitle",
display = L["Location"],
type = "description",
},
{
name = "zone",
display = L["Zone Name"],
type = "string",
multiline = true,
init = "arg",
preamble = "local checker = Private.ExecEnv.ParseStringCheck(%q)",
test = "checker: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. Prefix with '-' for negation."])
end,
optional = true,
},
{
name = "zoneId",
display = L["Player Location ID(s)"],
type = "string",
multiline = true,
init = "arg",
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. Prefix with '-' for negation."])
end,
optional = true,
},
{
name = "subzone",
display = L["Subzone Name"],
type = "string",
multiline = true,
init = "arg",
preamble = "local subzoneChecker = Private.ExecEnv.ParseStringCheck(%q)",
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. Prefix with '-' for negation."])
end,
optional = true,
},
{
name = "encounterid",
display = WeakAuras.newFeatureString .. L["Encounter ID(s)"],
type = "string",
init = "arg",
multiline = true,
desc = Private.get_encounters_list,
test = "WeakAuras.CheckNumericIds(%q, encounterid)",
events = {"ENCOUNTER_START", "ENCOUNTER_END"},
optional = true,
},
{
name = "size",
display = L["Instance Size Type"],
type = "multiselect",
values = "instance_types",
sorted = true,
init = "arg",
events = {"ZONE_CHANGED", "ZONE_CHANGED_INDOORS", "ZONE_CHANGED_NEW_AREA", "WA_DELAYED_PLAYER_ENTERING_WORLD"},
optional = true,
},
{
name = "difficulty",
display = L["Instance Difficulty"],
type = "multiselect",
values = "difficulty_types",
init = "arg",
events = {"PLAYER_DIFFICULTY_CHANGED", "ZONE_CHANGED", "ZONE_CHANGED_INDOORS", "ZONE_CHANGED_NEW_AREA", "WA_DELAYED_PLAYER_ENTERING_WORLD"},
optional = true,
},
{
name ="equipmentTitle",
display = L["Equipment"],
type = "description",
},
{
name = "itemequiped",
display = L["Item Equipped"],
type = "item",
multiEntry = {
operator = "or"
},
test = "IsEquippedItem(%s or '')",
events = { "UNIT_INVENTORY_CHANGED", "PLAYER_EQUIPMENT_CHANGED"},
only_exact = true,
},
{
name = "not_itemequiped",
display = WeakAuras.newFeatureString .. L["|cFFFF0000Not|r Item Equipped"],
type = "item",
multiEntry = {
operator = "or"
},
test = "not IsEquippedItem(%s or '')",
events = { "UNIT_INVENTORY_CHANGED", "PLAYER_EQUIPMENT_CHANGED"},
only_exact = true,
},
{
name = "itemtypeequipped",
display = L["Item Type Equipped"],
type = "multiselect",
test = "Private.ExecEnv.IsEquippedItemType(%s or '')",
events = { "UNIT_INVENTORY_CHANGED", "PLAYER_EQUIPMENT_CHANGED"},
values = "item_weapon_types"
},
}
};
local function AddUnitChangeInternalEvents(triggerUnit, t, includePets, unitisunit)
if (triggerUnit == nil) then
return
end
if (triggerUnit == "multi") then
-- Handled by normal events"
elseif triggerUnit == "pet" then
tinsert(t, "PET_UPDATE")
else
if Private.multiUnitUnits[triggerUnit] then
local isPet
for unit in pairs(Private.multiUnitUnits[triggerUnit]) do
isPet = WeakAuras.UnitIsPet(unit)
if (includePets ~= nil and isPet) or (includePets ~= "PetsOnly" and not isPet) then
tinsert(t, "UNIT_CHANGED_" .. string.lower(unit))
if unitisunit then
tinsert(t, "UNIT_IS_UNIT_CHANGED_" .. string.lower(unit) .. "_" .. string.lower(unitisunit))
end
end
end
else
tinsert(t, "UNIT_CHANGED_" .. string.lower(triggerUnit))
if unitisunit then
tinsert(t, "UNIT_IS_UNIT_CHANGED_" .. string.lower(triggerUnit) .. "_" .. string.lower(unitisunit))
end
end
end
end
local function AddWatchedUnits(triggerUnit, includePets, unitisunit)
if (triggerUnit == nil) then
return
end
if (triggerUnit == "multi") then
-- Handled by normal events"
elseif triggerUnit == "pet" then
WeakAuras.WatchForPetDeath();
else
if Private.multiUnitUnits[triggerUnit] then
local isPet
for unit in pairs(Private.multiUnitUnits[triggerUnit]) do
isPet = WeakAuras.UnitIsPet(unit)
if (includePets ~= nil and isPet) or (includePets ~= "PetsOnly" and not isPet) then
if unitisunit then
WeakAuras.WatchUnitChange(unitisunit)
end
WeakAuras.WatchUnitChange(unit)
end
end
else
if unitisunit then
WeakAuras.WatchUnitChange(unitisunit)
end
WeakAuras.WatchUnitChange(triggerUnit)
end
end
end
local function AddUnitSpecChangeInternalEvents(triggerUnit, t)
if (triggerUnit == nil) then
return
end
if Private.multiUnitUnits[triggerUnit] then
for unit in pairs(Private.multiUnitUnits[triggerUnit]) do
local isPet = WeakAuras.UnitIsPet(unit)
if (not isPet) then
tinsert(t, "UNIT_SPEC_CHANGED_" .. string.lower(unit))
end
end
else
tinsert(t, "UNIT_SPEC_CHANGED_" .. string.lower(triggerUnit))
end
end
local function AddUnitRoleChangeInternalEvents(triggerUnit, t)
if (triggerUnit == nil) then
return
end
if Private.multiUnitUnits[triggerUnit] then
for unit in pairs(Private.multiUnitUnits[triggerUnit]) do
if not WeakAuras.UnitIsPet(unit) then
tinsert(t, "UNIT_ROLE_CHANGED_" .. string.lower(unit))
end
end
else
if not WeakAuras.UnitIsPet(triggerUnit) then
tinsert(t, "UNIT_ROLE_CHANGED_" .. string.lower(triggerUnit))
end
end
end
local function AddRemainingCastInternalEvents(triggerUnit, t)
if (triggerUnit == nil) then
return
end
if Private.multiUnitUnits[triggerUnit] then
for unit in pairs(Private.multiUnitUnits[triggerUnit]) do
tinsert(t, "CAST_REMAINING_CHECK_" .. string.lower(unit))
end
else
tinsert(t, "CAST_REMAINING_CHECK_" .. string.lower(triggerUnit))
end
end
local function AddUnitEventForEvents(result, unit, event)
if unit then
if not result.unit_events then
result.unit_events = {}
end
if not result.unit_events[unit] then
result.unit_events[unit] = {}
end
tinsert(result.unit_events[unit], event)
else
if not result.events then
result.events = {}
end
tinsert(result.events, event)
end
end
local powerEvents = {
[0] = { "UNIT_MANA", "UNIT_MAXMANA" },
[1] = { "UNIT_RAGE", "UNIT_MAXRAGE" },
[2] = { "UNIT_FOCUS", "UNIT_MAXFOCUS" },
[3] = { "UNIT_ENERGY", "UNIT_MAXENERGY" },
[27] = { "UNIT_HAPPINESS", "UNIT_MAXHAPPINESS" },
[6] = { "UNIT_RUNIC_POWER", "UNIT_MAXRUNIC_POWER" }
}
local function AddUnitEventForPowerEvents(result, unit, powerType)
if powerType then
if powerType == 4 then return end
for _, event in ipairs(powerEvents[powerType]) do
AddUnitEventForEvents(result, unit, event)
end
else
for _, eventsList in pairs(powerEvents) do
for _, event in ipairs(eventsList) do
AddUnitEventForEvents(result, unit, event)
end
end
end
return result
end
local function AddTargetConditionEvents(result, useFocus)
if useFocus then
tinsert(result, "PLAYER_FOCUS_CHANGED")
end
tinsert(result, "PLAYER_TARGET_CHANGED")
return result
end
Private.AddTargetConditionEvents = AddTargetConditionEvents
local unitHelperFunctions = {
UnitChangedForceEventsWithPets = function(trigger)
local events = {}
local includePets = trigger.use_includePets == true and trigger.includePets or nil
if Private.multiUnitUnits[trigger.unit] then
local isPet
for unit in pairs(Private.multiUnitUnits[trigger.unit]) do
isPet = WeakAuras.UnitIsPet(unit)
if (includePets ~= nil and isPet) or (includePets ~= "PetsOnly" and not isPet) then
tinsert(events, {"UNIT_CHANGED_" .. unit, unit})
end
end
else
if trigger.unit then
tinsert(events, {"UNIT_CHANGED_" .. trigger.unit, trigger.unit})
end
end
return events
end,
UnitChangedForceEvents = function(trigger)
local events = {}
if Private.multiUnitUnits[trigger.unit] then
for unit in pairs(Private.multiUnitUnits[trigger.unit]) do
if not WeakAuras.UnitIsPet(unit) then
tinsert(events, {"UNIT_CHANGED_" .. unit, unit})
end
end
else
if trigger.unit then
tinsert(events, {"UNIT_CHANGED_" .. trigger.unit, trigger.unit})
end
end
return events
end,
SpecificUnitCheck = function(trigger)
if not trigger.use_specific_unit then
return "local specificUnitCheck = true\n"
end
if trigger.unit == nil then
return "local specificUnitCheck = false\n"
end
return string.format([=[
local specificUnitCheck = UnitIsUnit(%q, unit)
]=], trigger.unit or "")
end
}
Private.event_categories = {
spell = {
name = L["Spell"],
default = "Cooldown Progress (Spell)"
},
item = {
name = L["Item"],
default = "Cooldown Progress (Item)"
},
unit = {
name = L["Player/Unit Info"],
default = "Health"
},
addons = {
name = L["Other Addons"],
default = "GTFO"
},
combatlog = {
name = L["Combat Log"],
default = "Combat Log",
},
event = {
name = L["Other Events"],
default = "Chat Message"
},
custom = {
name = L["Custom"],
}
}
local GetNameAndIconForSpellName = function(trigger)
if type(trigger.spellName) == "table" then return end
local name, _, icon = GetSpellInfo(trigger.spellName or 0)
return name, icon
end
Private.event_prototypes = {
["Unit Characteristics"] = {
type = "unit",
events = function(trigger)
local unit = trigger.unit
local result = {}
AddUnitEventForEvents(result, unit, "UNIT_LEVEL")
AddUnitEventForEvents(result, unit, "UNIT_FACTION")
AddUnitEventForEvents(result, unit, "UNIT_NAME_UPDATE")
AddUnitEventForEvents(result, unit, "UNIT_FLAGS")
AddUnitEventForEvents(result, unit, "PLAYER_FLAGS_CHANGED")
if trigger.use_inRange then
AddUnitEventForEvents(result, unit, "UNIT_IN_RANGE_UPDATE")
end
return result;
end,
internal_events = function(trigger)
local unit = trigger.unit
local result = {}
AddUnitChangeInternalEvents(unit, result, nil, trigger.use_unitisunit and trigger.unitisunit or nil)
AddUnitRoleChangeInternalEvents(unit, result)
AddUnitSpecChangeInternalEvents(unit, result)
return result
end,
loadFunc = function(trigger)
AddWatchedUnits(trigger.unit, nil, trigger.use_unitisunit and trigger.unitisunit or nil)
if trigger.use_inRange then
WeakAuras.WatchForPlayerInRange()
end
end,
force_events = unitHelperFunctions.UnitChangedForceEvents,
name = L["Unit Characteristics"],
init = function(trigger)
trigger.unit = trigger.unit or "target";
local ret = [=[
unit = string.lower(unit)
local smart = %s
local extraUnit = %q;
local name, realm = WeakAuras.UnitNameWithRealm(unit)
]=];
ret = ret .. unitHelperFunctions.SpecificUnitCheck(trigger)
return ret:format(trigger.unit == "group" and "true" or "false", trigger.unitisunit or "");
end,
statesParameter = "unit",
args = {
{
name = "unit",
required = true,
display = L["Unit"],
type = "unit",
init = "arg",
values = "actual_unit_types_cast",
desc = Private.actual_unit_types_cast_tooltip,
test = "true",
store = true,
reloadOptions = true,
},
{
name = "unitisunit",
display = L["Unit is Unit"],
type = "unit",
init = "UnitIsUnit(unit, extraUnit)",
values = function(trigger)
if Private.multiUnitUnits[trigger.unit] then
return Private.actual_unit_types
else
return Private.actual_unit_types_with_specific
end
end,
test = "unitisunit",
desc = function() return L["Can be used for e.g. checking if \"boss1target\" is the same as \"player\"."] end,
},
{
name = "name",
display = L["Name"],
type = "string",
store = true,
hidden = true,
test = "true"
},
{
name = "realm",
display = L["Realm"],
type = "string",
store = true,
hidden = true,
test = "true"
},
{
name = "namerealm",
display = L["Unit Name/Realm"],
desc = constants.nameRealmFilterDesc,
type = "string",
multiline = true,
preamble = "local nameRealmChecker = Private.ExecEnv.ParseNameCheck(%q)",
test = "nameRealmChecker:Check(name, realm)",
conditionType = "string",
conditionPreamble = function(input)
return Private.ExecEnv.ParseNameCheck(input)
end,
conditionTest = function(state, needle, op, preamble)
return preamble:Check(state.name, state.realm)
end,
operator_types = "none",
},
{
name = "class",
display = L["Class"],
type = "select",
init = "select(2, UnitClass(unit))",
values = "class_types",
store = true,
conditionType = "select"
},
{
name = "specId",
display = L["Specialization"],
type = "multiselect",
init = "WeakAuras.SpecForUnit(unit)",
values = "spec_types_all",
store = true,
conditionType = "select",
enable = function(trigger)
return trigger.unit == "group" or trigger.unit == "raid" or trigger.unit == "party" or trigger.unit == "player"
end,
desc = L["Requires syncing the specialization via LibGroupTalents."],
},
{
name = "classification",
display = L["Classification"],
type = "multiselect",
init = "UnitClassification(unit)",
values = "classification_types",
store = true,
conditionType = "select"
},
{
name = "creatureTypeIndex",
display = L["Creature Type"],
type = "multiselect",
init = "Private.ExecEnv.creature_type_name_to_id[UnitCreatureType(unit or '') or 0]",
values = "creature_type_types",
store = true,
sorted = true,
conditionType = "select",
},
{
name = "creatureType",
display = L["Creature Type Name"],
init = "UnitCreatureType(unit)",
store = true,
test = "true",
hidden = true,
},
{
name = "creatureFamilyIndex",
display = L["Creature Family"],
type = "multiselect",
init = "Private.ExecEnv.creature_family_name_to_id[UnitCreatureFamily(unit or '') or 0]",
values = "creature_family_types",
store = true,
sorted = true,
conditionType = "select",
},
{
name = "creatureFamily",
display = L["Creature Family Name"],
init = "UnitCreatureFamily(unit)",
store = true,
test = "true",
hidden = true,
},
{
name = "role",
display = L["Spec Role"],
type = "select",
init = "WeakAuras.LGT:GetUnitRole(unit)",
values = "role_types",
store = true,
conditionType = "select",
},
{
name = "raid_role",
display = L["Raid Role"],
type = "select",
init = "WeakAuras.UnitRaidRole(unit)",
values = "raid_role_types",
store = true,
conditionType = "select",
enable = function(trigger)
return trigger.unit == "group" or trigger.unit == "raid" or trigger.unit == "party"
end
},
{
name = "raidMarkIndex",
display = L["Raid Mark"],
type = "multiselect",
values = "raid_mark_check_type",
store = true,
conditionType = "select",
init = "GetRaidTargetIndex(unit) or 0"
},
{
name = "raidMark",
display = L["Raid Mark Icon"],
store = true,
hidden = true,
test = "true",
init = "raidMarkIndex > 0 and '{rt'..raidMarkIndex..'}' or ''"
},
{
name = "dead",
display = L["Dead"],
type = "tristate",
width = WeakAuras.doubleWidth,
init = "UnitIsDeadOrGhost(unit)",
store = true,
conditionType = "bool",
},
{
name = "ignoreSelf",
display = L["Ignore Self"],
type = "toggle",
width = WeakAuras.doubleWidth,
enable = function(trigger)
return trigger.unit == "nameplate" or trigger.unit == "group" or trigger.unit == "raid" or trigger.unit == "party"
end,
init = "not UnitIsUnit(\"player\", unit)"
},
{
name = "ignoreDisconnected",
display = L["Ignore Disconnected"],
type = "toggle",
width = WeakAuras.doubleWidth,
enable = function(trigger)
return trigger.unit == "group" or trigger.unit == "raid" or trigger.unit == "party"
end,
init = "UnitIsConnected(unit)"
},
{
name = "inRange",
display = L["In Range"],
desc = L["Uses UnitInRange() to check if in range. Matches default raid frames out of range behavior, which is between 25 to 40 yards depending on your class and spec."],
type = "toggle",
width = WeakAuras.doubleWidth,
enable = function(trigger)
return trigger.unit == "group" or trigger.unit == "raid" or trigger.unit == "party"
end,
init = "Private.ExecEnv.UnitInRangeFixed(unit)"
},
{
name = "hostility",
display = L["Hostility"],
type = "select",
init = "WeakAuras.GetPlayerReaction(unit)",
values = "hostility_types",
store = true,
conditionType = "select",
},
{
name = "character",
display = L["Character Type"],
type = "select",
init = "UnitIsPlayer(unit) and 'player' or 'npc'",
values = "character_types",
store = true,
conditionType = "select"
},
{
name = "level",
display = L["Level"],
type = "number",
init = "UnitLevel(unit)",
store = true,
conditionType = "number",
multiEntry = {
operator = "and",
limit = 2
},
},
{
name = "npcId",
display = L["Npc ID"],
type = "string",
multiline = true,
store = true,
init = "tostring(tonumber(string.sub(UnitGUID(unit) or '', 8, 12), 16) or '')",
conditionType = "string",
preamble = "local npcIdChecker = Private.ExecEnv.ParseStringCheck(%q)",
test = "npcIdChecker:Check(npcId)",
conditionPreamble = function(input)
return Private.ExecEnv.ParseStringCheck(input)
end,
conditionTest = function(state, needle, op, preamble)
return preamble:Check(state.npcId)
end,
operator_types = "none",
desc = L["Supports multiple entries, separated by commas. Prefix with '-' for negation."]
},
{
name = "attackable",
display = L["Attackable"],
type = "tristate",
init = "UnitCanAttack('player', unit)",
store = true,
conditionType = "bool"
},
{
name = "inCombat",
display = L["In Combat"],
type = "tristate",
init = "UnitAffectingCombat(unit)",
store = true,
conditionType = "bool"
},
{
name = "afk",
display = L["Afk"],
type = "tristate",
init = "UnitIsAFK(unit)",
store = true,
conditionType = "bool"
},
{
name = "dnd",
display = L["Do Not Disturb"],
type = "tristate",
init = "UnitIsDND(unit)",
store = true,
conditionType = "bool"
},
{
hidden = true,
test = "WeakAuras.UnitExistsFixed(unit, smart) and specificUnitCheck"
}
},
automaticrequired = true,
progressType = "none"
},
["Faction Reputation"] = {
type = "unit",
progressType = "static",
events = {
["events"] = {
"UPDATE_FACTION",
}
},
internal_events = {"WA_DELAYED_PLAYER_ENTERING_WORLD"},
force_events = "UPDATE_FACTION",
name = L["Faction Reputation"],
statesParameter = "one",
automaticrequired = true,
init = function(trigger)
local ret = [=[
local useWatched = %s
local factionID = useWatched and Private.ExecEnv.GetWatchedFactionId() or %q
local minValue, maxValue, currentValue
local factionData = Private.ExecEnv.GetFactionDataByID(factionID)
if not factionData then return end;
local name, description = factionData.name, factionData.description
local standingID = factionData.reaction
local hasRep = factionData.isHeaderWithRep
local barMin, barMax, barValue = factionData.currentReactionThreshold, factionData.nextReactionThreshold, factionData.currentStanding
local atWarWith, canToggleAtWar, isHeader, isCollapsed, isWatched, isChild = factionData.atWarWith, factionData. canToggleAtWar, factionData.isHeader, factionData.isCollapsed, factionData.isWatched, factionData.isChild
minValue, maxValue, currentValue = barMin, barMax, barValue
local standing
if tonumber(standingID) then
standing = GetText("FACTION_STANDING_LABEL"..standingID, UnitSex("player"))
end
local isCapped = standingID == 8 and currentValue >= 42999
]=]
return ret:format(trigger.use_watched and "true" or "false", trigger.factionID or 0)
end,
args = {
{
name = "progressType",
hidden = true,
init = "'static'",
store = true,
test = "true"
},
{
name = "watched",
display = L["Use Watched Faction"],
type = "toggle",
test = "true",
reloadOptions = true,
},
{
name = "factionID",
display = L["Faction"],
required = true,
type = "select",
itemControl = "Dropdown-Currency",
values = Private.GetReputations,
headers = Private.GetReputationsHeaders,
sorted = true,
sortOrder = function()
local sorted = Private.GetReputationsSorted()
local sortOrder = {}
for key, value in pairs(Private.GetReputations()) do
tinsert(sortOrder, key)
end
table.sort(sortOrder, function(aKey, bKey)
local aValue = sorted[aKey]
local bValue = sorted[bKey]
return aValue < bValue
end)
return sortOrder
end,
conditionType = "select",
enable = function(trigger)
return not trigger.use_watched
end,
reloadOptions = true,
test = "true",
},
{
name = "name",
display = L["Faction Name"],
type = "string",
store = true,
hidden = "true",
init = "name",
test = "true"
},
{
name = "value",
display = L["Reputation"],
type = "number",
store = true,
init = [[currentValue - minValue]],
conditionType = "number",
progressTotal = "total",
multiEntry = {
operator = "and",
limit = 2
},
},
{
name = "total",
display = L["Total Reputation"],
type = "number",
store = true,
init = [[maxValue - minValue]],
conditionType = "number",
noProgressSource = true,
multiEntry = {
operator = "and",
limit = 2
},
},
{
name = "percentRep",
display = L["Reputation (%)"],
type = "number",
init = "total ~= 0 and (value / total) * 100 or nil",
store = true,
conditionType = "number",
noProgressSource = true,
multiEntry = {
operator = "and",
limit = 2
},
formatter = "Number",
},
{
name = "standing",
display = L["Standing"],
type = "string",
init = "standing",
store = true,
hidden = "true",
test = "true"
},
{
name = "standingId",
display = L["Standing"],
type = "select",
values = function()
local ret = {}
for i = 1, 8 do
ret[i] = GetText("FACTION_STANDING_LABEL"..i, UnitSex("player"))
end
return ret
end,
init = "standingID",
store = true,
conditionType = "select",
},
{
name = "capped",
display = L["Capped"],
type = "tristate",
init = "isCapped",
conditionType = "bool",
store = true,
},
{
name = "atWar",
display = L["At War"],
type = "tristate",
init = "atWarWith",
conditionType = "bool",
store = true,
},
}
},
["Experience"] = {
type = "unit",
progressType = "static",
events = {
["events"] = {
"PLAYER_XP_UPDATE",
}
},
internal_events = {"WA_DELAYED_PLAYER_ENTERING_WORLD"},
force_events = "PLAYER_XP_UPDATE",
name = L["Player Experience"],
init = function(trigger)
return ""
end,
statesParameter = "one",
args = {
{
name = "level",
display = L["Level"],
required = false,
type = "number",
store = true,
init = [[UnitLevel("player")]],
conditionType = "number",
multiEntry = {
operator = "and",
limit = 2
},
},
{
name = "currentXP",
display = L["Current Experience"],
type = "number",
store = true,
init = [[UnitXP("player")]],
conditionType = "number",
multiEntry = {
operator = "and",
limit = 2
},
progressTotal = "totalXP"
},
{
name = "totalXP",
display = L["Total Experience"],
type = "number",
store = true,
init = [[UnitXPMax("player")]],
conditionType = "number",
multiEntry = {
operator = "and",
limit = 2
},
},
{
name = "value",
type = "number",
store = true,
init = "currentXP",
hidden = true,
test = "true",
},
{
name = "total",
type = "number",
store = true,
init = "totalXP",
hidden = true,
test = "true",
},
{
name = "progressType",
hidden = true,
init = "'static'",
store = true,
test = "true"
},
{
name = "percentXP",
display = L["Experience (%)"],
type = "number",
init = "total ~= 0 and (value / total) * 100 or nil",
store = true,
conditionType = "number",
multiEntry = {
operator = "and",
limit = 2
},
formatter = "Number",
},
{
type = "header",
name = "restedExperienceHeader",
display = L["Rested Experience"],
},
{
name = "showRested",
display = L["Show Rested Overlay"],
type = "toggle",
test = "true",
reloadOptions = true,
},
{
name = "restedXP",
display = L["Rested Experience"],
init = [[GetXPExhaustion() or 0]],
type = "number",
store = true,
conditionType = "number",
multiEntry = {
operator = "and",
limit = 2
},
},
{
name = "percentrested",
display = L["Rested Experience (%)"],
init = "total ~= 0 and (restedXP / total) * 100 or nil",
type = "number",
store = true,
conditionType = "number",
multiEntry = {
operator = "and",
limit = 2
},
formatter = "Number",
},
},
overlayFuncs = {
{
name = L["Rested"],
func = function(trigger, state)
return "forward", state.restedXP
end,
enable = function(trigger)
return trigger.use_showRested
end
},
},
automaticrequired = true
},
["Health"] = {
type = "unit",
includePets = "true",
progressType = "static",
events = function(trigger)
local unit = trigger.unit
local result = {}
AddUnitEventForEvents(result, unit, "UNIT_HEALTH")
AddUnitEventForEvents(result, unit, "UNIT_MAXHEALTH")
AddUnitEventForEvents(result, unit, "UNIT_NAME_UPDATE")
if trigger.use_ignoreDead or trigger.use_ignoreDisconnected then
AddUnitEventForEvents(result, unit, "UNIT_FLAGS")
end
if trigger.use_showAbsorb then
AddUnitEventForEvents(result, unit, "UNIT_ABSORB_AMOUNT_CHANGED")
end
if trigger.use_showHealAbsorb then
AddUnitEventForEvents(result, unit, "UNIT_HEAL_ABSORB_AMOUNT_CHANGED")
end
if trigger.use_inRange then
AddUnitEventForEvents(result, unit, "UNIT_IN_RANGE_UPDATE")
end
return result
end,
internal_events = function(trigger)
local unit = trigger.unit
local result = {}
local includePets = trigger.use_includePets == true and trigger.includePets or nil
AddUnitChangeInternalEvents(unit, result, includePets)
if includePets ~= "PetsOnly" then
AddUnitRoleChangeInternalEvents(unit, result)
end
AddUnitSpecChangeInternalEvents(unit, result)
return result
end,
loadFunc = function(trigger)
local includePets = trigger.use_includePets == true and trigger.includePets or nil
AddWatchedUnits(trigger.unit, includePets)
if trigger.use_inRange then
WeakAuras.WatchForPlayerInRange()
end
end,
force_events = unitHelperFunctions.UnitChangedForceEventsWithPets,
name = L["Health"],
init = function(trigger)
trigger.unit = trigger.unit or "player";
local ret = [=[
unit = string.lower(unit)
local name, realm = WeakAuras.UnitNameWithRealm(unit)
local smart = %s
]=];
ret = ret .. unitHelperFunctions.SpecificUnitCheck(trigger)
return ret:format(trigger.unit == "group" and "true" or "false");
end,
statesParameter = "unit",
args = {
{
name = "unit",
required = true,
display = L["Unit"],
type = "unit",
init = "arg",
values = "actual_unit_types_cast",
desc = Private.actual_unit_types_cast_tooltip,
test = "true",
store = true
},
{
name = "health",
display = L["Health"],
type = "number",
init = "UnitHealth(unit)",
store = true,
conditionType = "number",
multiEntry = {
operator = "and",
limit = 2
},
progressTotal = "maxhealth",
formatter = "BigNumber",
},
{
name = "value",
hidden = true,
init = "health",
store = true,
test = "true"
},
{
name = "total",
hidden = true,
init = "UnitHealthMax(unit)",
store = true,
test = "true"
},
{
name = "progressType",
hidden = true,
init = "'static'",
store = true,
test = "true"
},
{
name = "percenthealth",
display = L["Health (%)"],
type = "number",
init = "total ~= 0 and (value / total) * 100 or nil",
store = true,
conditionType = "number",
multiEntry = {
operator = "and",
limit = 2
},
formatter = "Number",
},
{
name = "deficit",
display = L["Health Deficit"],
type = "number",
init = "total - value",
store = true,
conditionType = "number",
multiEntry = {
operator = "and",
limit = 2
},
progressTotal = "total",
formatter = "BigNumber",
},
{
name = "maxhealth",
display = WeakAuras.newFeatureString .. L["Max Health"],
type = "number",
init = "total",
store = true,
conditionType = "number",
multiEntry = {
operator = "and",
limit = 2
},
formatter = "BigNumber",
},
{
name = "showAbsorb",
display = L["Show Absorb"],
type = "toggle",
test = "true",
reloadOptions = true
},
{
name = "absorbMode",
display = L["Absorb Display"],
type = "select",
test = "true",
values = "absorb_modes",
required = true,
enable = function(trigger) return trigger.use_showAbsorb end
},
{
name = "absorb",
type = "number",
display = L["Absorb"],
init = "UnitGetTotalAbsorbs(unit)",
store = true,
conditionType = "number",
enable = function(trigger) return trigger.use_showAbsorb end
},
{
type = "header",
name = "unitCharacteristicsHeader",
display = L["Unit Characteristics"],
},
{
name = "name",
display = L["Unit Name"],
type = "string",
store = true,
hidden = true,
test = "true"
},
{
name = "realm",
display = L["Realm"],
type = "string",
store = true,
hidden = true,
test = "true"
},
{
name = "namerealm",
display = L["Unit Name/Realm"],
type = "string",
multiline = true,
preamble = "local nameRealmChecker = Private.ExecEnv.ParseNameCheck(%q)",
test = "nameRealmChecker:Check(name, realm)",
conditionType = "string",
conditionPreamble = function(input)
return Private.ExecEnv.ParseNameCheck(input)
end,
conditionTest = function(state, needle, op, preamble)
return preamble:Check(state.name, state.realm)
end,
operator_types = "none",
desc = constants.nameRealmFilterDesc,
},
{
name = "npcId",
display = L["Npc ID"],
type = "string",
multiline = true,
store = true,
init = "tostring(tonumber(string.sub(UnitGUID(unit) or '', 8, 12), 16) or '')",
conditionType = "string",
preamble = "local npcIdChecker = Private.ExecEnv.ParseStringCheck(%q)",
test = "npcIdChecker:Check(npcId)",
conditionPreamble = function(input)
return Private.ExecEnv.ParseStringCheck(input)
end,
conditionTest = function(state, needle, op, preamble)
return preamble:Check(state.npcId)
end,
operator_types = "none",
desc = L["Supports multiple entries, separated by commas. Prefix with '-' for negation."]
},
{
name = "class",
display = L["Class"],
type = "select",
init = "select(2, UnitClass(unit))",
values = "class_types",
store = true,
conditionType = "select"
},
{
name = "specId",
display = L["Specialization"],
type = "multiselect",
init = "WeakAuras.SpecForUnit(unit)",
values = "spec_types_all",
store = true,
conditionType = "select",
enable = function(trigger)
return trigger.unit == "group" or trigger.unit == "raid" or trigger.unit == "party" or trigger.unit == "player"
end,
desc = L["Requires syncing the specialization via LibGroupTalents."],
},
{
name = "role",
display = L["Spec Role"],
type = "select",
init = "WeakAuras.LGT:GetUnitRole(unit)",
values = "role_types",
store = true,
conditionType = "select",
enable = function(trigger)
return trigger.unit == "group" or trigger.unit == "raid" or trigger.unit == "party" or trigger.unit == "player"
end
},
{
name = "raid_role",
display = L["Raid Role"],
type = "select",
init = "WeakAuras.UnitRaidRole(unit)",
values = "raid_role_types",
store = true,
conditionType = "select",
enable = function(trigger)
return trigger.unit == "group" or trigger.unit == "raid" or trigger.unit == "party"
end
},
{
name = "raidMarkIndex",
display = L["Raid Mark"],
type = "multiselect",
values = "raid_mark_check_type",
store = true,
conditionType = "select",
init = "GetRaidTargetIndex(unit) or 0"
},
{
name = "raidMark",
display = L["Raid Mark Icon"],
store = true,
hidden = true,
test = "true",
init = "raidMarkIndex > 0 and '{rt'..raidMarkIndex..'}' or ''"
},
{
type = "header",
name = "miscellaneousHeader",
display = L["Miscellaneous"],
enable = function(trigger)
return trigger.unit == "nameplate" or trigger.unit == "group" or trigger.unit == "raid" or trigger.unit == "party"
end,
},
{
name = "includePets",
display = L["Include Pets"],
type = "select",
values = "include_pets_types",
width = WeakAuras.normalWidth,
test = "true",
enable = function(trigger)
return trigger.unit == "group" or trigger.unit == "raid" or trigger.unit == "party"
end
},
{
name = "ignoreSelf",
display = L["Ignore Self"],
type = "toggle",
width = WeakAuras.doubleWidth,
enable = function(trigger)
return trigger.unit == "nameplate" or trigger.unit == "group" or trigger.unit == "raid" or trigger.unit == "party"
end,
init = "not UnitIsUnit(\"player\", unit)"
},
{
name = "ignoreDead",
display = L["Ignore Dead"],
type = "toggle",
width = WeakAuras.doubleWidth,
enable = function(trigger)
return trigger.unit == "group" or trigger.unit == "raid" or trigger.unit == "party"
end,
init = "not UnitIsDeadOrGhost(unit)"
},
{
name = "ignoreDisconnected",
display = L["Ignore Disconnected"],
type = "toggle",
width = WeakAuras.doubleWidth,
enable = function(trigger)
return trigger.unit == "group" or trigger.unit == "raid" or trigger.unit == "party"
end,
init = "UnitIsConnected(unit)"
},
{
name = "inRange",
display = L["In Range"],
desc = L["Uses UnitInRange() to check if in range. Matches default raid frames out of range behavior, which is between 25 to 40 yards depending on your class and spec."],
type = "toggle",
width = WeakAuras.doubleWidth,
enable = function(trigger)
return trigger.unit == "group" or trigger.unit == "raid" or trigger.unit == "party"
end,
init = "Private.ExecEnv.UnitInRangeFixed(unit)"
},
{
name = "nameplateType",
display = L["Hostility"],
type = "select",
init = "WeakAuras.GetPlayerReaction(unit)",
values = "hostility_types",
conditionType = "select",
store = true,
},
{
name = "name",
hidden = true,
init = "UnitName(unit)",
test = "true"
},
{
hidden = true,
test = "WeakAuras.UnitExistsFixed(unit, smart) and specificUnitCheck"
}
},
overlayFuncs = {
{
name = L["Absorb"],
func = function(trigger, state)
local absorb = state.absorb
if (trigger.absorbMode == "OVERLAY_FROM_START") then
return 0, absorb;
else
return "forward", absorb;
end
end,
enable = function(trigger)
return trigger.use_showAbsorb;
end
},
{
name = L["Heal Absorb"],
func = function(trigger, state)
local healabsorb = state.healabsorb
if (trigger.absorbHealMode == "OVERLAY_FROM_START") then
return 0, healabsorb;
else
return "forward", healabsorb;
end
end,
enable = function(trigger)
return trigger.use_showHealAbsorb;
end
},
},
automaticrequired = true
},
["Power"] = {
type = "unit",
progressType = "static",
events = function(trigger)
local unit = trigger.unit
local result = {}
local powerType = trigger.use_powertype and trigger.powertype
if trigger.powertype == 4 then
local _, class = UnitClass("player")
AddUnitEventForEvents(result, unit, "UNIT_COMBO_POINTS")
AddUnitEventForEvents(result, unit, "UNIT_TARGET")
if class == "DRUID" then
AddUnitEventForEvents(result, unit, "UNIT_MODEL_CHANGED")
end
-- For units not in multiUnitUnits, add FRAME_UPDATE to ensure smooth power updates
elseif unit and not Private.multiUnitUnits[unit] then
if not result.events then
result.events = {}
end
tinsert(result.events, "FRAME_UPDATE")
else
AddUnitEventForPowerEvents(result, unit, powerType)
end
-- The api for spell power costs is not meant to be for other units
if trigger.use_showCost and unit == "player" then
AddUnitEventForEvents(result, unit, "UNIT_SPELLCAST_START")
AddUnitEventForEvents(result, unit, "UNIT_SPELLCAST_STOP")
AddUnitEventForEvents(result, unit, "UNIT_SPELLCAST_FAILED")
AddUnitEventForEvents(result, unit, "UNIT_SPELLCAST_SUCCEEDED")
end
-- Register shared events unless we're in the FRAME_UPDATE case
if (not (unit and not Private.multiUnitUnits[unit])) or (trigger.powertype == 4) then
AddUnitEventForEvents(result, unit, "UNIT_DISPLAYPOWER")
AddUnitEventForEvents(result, unit, "UNIT_NAME_UPDATE")
if trigger.use_ignoreDead or trigger.use_ignoreDisconnected then
AddUnitEventForEvents(result, unit, "UNIT_FLAGS")
end
if trigger.use_inRange then
AddUnitEventForEvents(result, unit, "UNIT_IN_RANGE_UPDATE")
end
end
return result;
end,
internal_events = function(trigger)
local unit = trigger.unit
local result = {}
local includePets = trigger.use_includePets == true and trigger.includePets or nil
AddUnitChangeInternalEvents(unit, result, includePets)
if includePets ~= "PetsOnly" then
AddUnitRoleChangeInternalEvents(unit, result)
end
AddUnitSpecChangeInternalEvents(unit, result)
if trigger.use_showCost and trigger.unit == "player" then
tinsert(result, "WA_UNIT_QUEUED_SPELL_CHANGED");
end
return result
end,
loadFunc = function(trigger)
if trigger.use_showCost and trigger.unit == "player" then
WeakAuras.WatchForQueuedSpell()
end
local includePets = trigger.use_includePets == true and trigger.includePets or nil
AddWatchedUnits(trigger.unit, includePets)
if trigger.use_inRange then
WeakAuras.WatchForPlayerInRange()
end
end,
force_events = unitHelperFunctions.UnitChangedForceEventsWithPets,
name = L["Power"],
init = function(trigger)
trigger.unit = trigger.unit or "player";
local ret = {}
table.insert(ret, ([=[
unit = string.lower(unit)
local name, realm = WeakAuras.UnitNameWithRealm(unit)
local smart = %s
local powerType = %s
local unitPowerType = UnitPowerType(unit);
local powerTypeToCheck = powerType or unitPowerType;
]=]):format(trigger.unit == "group" and "true" or "false", trigger.use_powertype and trigger.powertype or "nil"))
local powerType = trigger.use_powertype and trigger.powertype or nil
-- Combo Points
if powerType == 4 then
local _, class = UnitClass("player")
table.insert(ret, [[
local comboUnit = UnitInVehicle(unit) and 'vehicle' or unit
local power = GetComboPoints(comboUnit, 'target')
local total = MAX_COMBO_POINTS
]])
if class == "ROGUE" then
table.insert(ret, [[
unitPowerType = 4
]])
elseif class == "DRUID" then
local formName = GetSpellInfo(768) or ""
table.insert(ret, ([[
local index = GetShapeshiftForm() or 0
local form = index > 0 and select(2, GetShapeshiftFormInfo(index)) == %q
if form or comboUnit == 'vehicle' then
unitPowerType = 4
end
]]):format(formName))
end
-- Happiness
elseif powerType == 27 then
table.insert(ret, [[
local power = UnitPower(unit, 4)
local total = math.max(1, UnitPowerMax(unit, 4))
]])
else
table.insert(ret, [[
local power = UnitPower(unit, powerType)
local total = math.max(1, UnitPowerMax(unit, powerType))
]])
end
table.insert(ret, unitHelperFunctions.SpecificUnitCheck(trigger))
local canEnableShowCost = (not trigger.use_powertype) and trigger.unit == "player";
if (canEnableShowCost and trigger.use_showCost) then
table.insert(ret, [[
if (event == "UNIT_DISPLAYPOWER") then
local cost = WeakAuras.GetSpellCost(powerTypeToCheck)
if state.cost ~= cost then
state.cost = cost
state.changed = true
end
elseif ( (event == "UNIT_SPELLCAST_START" or event == "UNIT_SPELLCAST_STOP" or event == "UNIT_SPELLCAST_FAILED" or event == "UNIT_SPELLCAST_SUCCEEDED") and unit == "player") or event == "WA_UNIT_QUEUED_SPELL_CHANGED" then
local cost = WeakAuras.GetSpellCost(powerTypeToCheck)
if state.cost ~= cost then
state.cost = cost
state.changed = true
end
end
]])
end
return table.concat(ret)
end,
statesParameter = "unit",
args = {
{
name = "unit",
required = true,
display = L["Unit"],
type = "unit",
init = "arg",
values = "actual_unit_types_cast",
desc = Private.actual_unit_types_cast_tooltip,
test = "true",
store = true
},
{
name = "powertype",
display = L["Power Type"],
type = "select",
values = function(trigger)
if trigger and trigger.unit ~= "player" then
return Private.power_types
else
return Private.power_types_player
end
end,
init = "powerTypeToCheck",
test = "true",
store = true,
conditionType = "select",
reloadOptions = true
},
{
name = "requirePowerType",
display = L["Only if Primary"],
type = "toggle",
test = "unitPowerType == powerType",
enable = function(trigger)
return trigger.use_powertype
end,
},
{
name = "showCost",
display = L["Overlay Cost of Casts"],
type = "toggle",
test = "true",
enable = function(trigger)
return (not trigger.use_powertype) and trigger.unit == "player";
end,
reloadOptions = true
},
{
name = "power",
display = L["Power"],
type = "number",
init = "power",
store = true,
conditionType = "number",
multiEntry = {
operator = "and",
limit = 2
},
progressTotal = "total"
},
{
name = "value",
hidden = true,
init = "power",
store = true,
test = "true"
},
{
name = "total",
hidden = true,
init = "total",
store = true,
test = "true"
},
{
name = "stacks",
hidden = true,
init = "power",
store = true,
test = "true"
},
{
name = "progressType",
hidden = true,
init = "'static'",
store = true,
test = "true"
},
{
name = "percentpower",
display = L["Power (%)"],
type = "number",
init = "total ~= 0 and (value / total) * 100 or nil",
store = true,
conditionType = "number",
multiEntry = {
operator = "and",
limit = 2
},
formatter = "Number",
},
{
name = "deficit",
display = L["Power Deficit"],
type = "number",
init = "total - value",
store = true,
conditionType = "number",
multiEntry = {
operator = "and",
limit = 2
},
progressTotal = "total"
},
{
name = "maxpower",
display = WeakAuras.newFeatureString .. L["Max Power"],
type = "number",
init = "total",
store = true,
conditionType = "number",
multiEntry = {
operator = "and",
limit = 2
},
},
{
name = "name",
display = L["Unit Name"],
type = "string",
store = true,
hidden = true,
test = "true"
},
{
name = "realm",
display = L["Realm"],
type = "string",
store = true,
hidden = true,
test = "true"
},
{
type = "header",
name = "unitCharacteristicsHeader",
display = L["Unit Characteristics"],
},
{
name = "namerealm",
display = L["Unit Name/Realm"],
type = "string",
multiline = true,
preamble = "local nameRealmChecker = Private.ExecEnv.ParseNameCheck(%q)",
test = "nameRealmChecker:Check(name, realm)",
conditionType = "string",
conditionPreamble = function(input)
return Private.ExecEnv.ParseNameCheck(input)
end,
conditionTest = function(state, needle, op, preamble)
return preamble:Check(state.name, state.realm)
end,
operator_types = "none",
desc = constants.nameRealmFilterDesc,
},
{
name = "npcId",
display = L["Npc ID"],
type = "string",
multiline = true,
store = true,
init = "tostring(tonumber(string.sub(UnitGUID(unit) or '', 8, 12), 16) or '')",
conditionType = "string",
preamble = "local npcIdChecker = Private.ExecEnv.ParseStringCheck(%q)",
test = "npcIdChecker:Check(npcId)",
conditionPreamble = function(input)
return Private.ExecEnv.ParseStringCheck(input)
end,
conditionTest = function(state, needle, op, preamble)
return preamble:Check(state.npcId)
end,
operator_types = "none",
desc = L["Supports multiple entries, separated by commas. Prefix with '-' for negation."],
enable = function(trigger)
return trigger.powertype ~= 4
end
},
{
name = "class",
display = L["Class"],
type = "select",
init = "select(2, UnitClass(unit))",
values = "class_types",
store = true,
conditionType = "select"
},
{
name = "specId",
display = L["Specialization"],
type = "multiselect",
init = "WeakAuras.SpecForUnit(unit)",
values = "spec_types_all",
store = true,
conditionType = "select",
enable = function(trigger)
return trigger.unit == "group" or trigger.unit == "raid" or trigger.unit == "party" or trigger.unit == "player"
end,
desc = L["Requires syncing the specialization via LibGroupTalents."],
},
{
name = "role",
display = L["Spec Role"],
type = "select",
init = "WeakAuras.LGT:GetUnitRole(unit)",
values = "role_types",
store = true,
conditionType = "select",
enable = function(trigger)
return trigger.unit == "group" or trigger.unit == "raid" or trigger.unit == "party" or trigger.unit == "player"
end
},
{
name = "raid_role",
display = L["Raid Role"],
type = "select",
init = "WeakAuras.UnitRaidRole(unit)",
values = "raid_role_types",
store = true,
conditionType = "select",
enable = function(trigger)
return trigger.unit == "group" or trigger.unit == "raid" or trigger.unit == "party"
end
},
{
name = "raidMarkIndex",
display = L["Raid Mark"],
type = "multiselect",
values = "raid_mark_check_type",
store = true,
conditionType = "select",
init = "GetRaidTargetIndex(unit) or 0"
},
{
name = "raidMark",
display = L["Raid Mark Icon"],
store = true,
hidden = true,
test = "true",
init = "raidMarkIndex > 0 and '{rt'..raidMarkIndex..'}' or ''"
},
{
type = "header",
name = "miscellaneousHeader",
display = L["Miscellaneous"],
enable = function(trigger)
return trigger.unit == "nameplate" or trigger.unit == "group" or trigger.unit == "raid" or trigger.unit == "party"
end,
},
{
name = "includePets",
display = L["Include Pets"],
type = "select",
values = "include_pets_types",
width = WeakAuras.normalWidth,
test = "true",
enable = function(trigger)
return trigger.unit == "group" or trigger.unit == "raid" or trigger.unit == "party"
end
},
{
name = "ignoreSelf",
display = L["Ignore Self"],
type = "toggle",
width = WeakAuras.doubleWidth,
enable = function(trigger)
return trigger.unit == "nameplate" or trigger.unit == "group" or trigger.unit == "raid" or trigger.unit == "party"
end,
init = "not UnitIsUnit(\"player\", unit)"
},
{
name = "ignoreDead",
display = L["Ignore Dead"],
type = "toggle",
width = WeakAuras.doubleWidth,
enable = function(trigger)
return trigger.unit == "group" or trigger.unit == "raid" or trigger.unit == "party"
end,
init = "not UnitIsDeadOrGhost(unit)"
},
{
name = "ignoreDisconnected",
display = L["Ignore Disconnected"],
type = "toggle",
width = WeakAuras.doubleWidth,
enable = function(trigger)
return trigger.unit == "group" or trigger.unit == "raid" or trigger.unit == "party"
end,
init = "UnitIsConnected(unit)"
},
{
name = "inRange",
display = L["In Range"],
desc = L["Uses UnitInRange() to check if in range. Matches default raid frames out of range behavior, which is between 25 to 40 yards depending on your class and spec."],
type = "toggle",
width = WeakAuras.doubleWidth,
enable = function(trigger)
return trigger.unit == "group" or trigger.unit == "raid" or trigger.unit == "party"
end,
init = "Private.ExecEnv.UnitInRangeFixed(unit)"
},
{
name = "nameplateType",
display = L["Hostility"],
type = "select",
init = "WeakAuras.GetPlayerReaction(unit)",
values = "hostility_types",
store = true,
conditionType = "select",
enable = function(trigger)
return trigger.powertype ~= 4
end
},
{
hidden = true,
test = "WeakAuras.UnitExistsFixed(unit, smart) and specificUnitCheck"
}
},
overlayFuncs = {
{
name = L["Spell Cost"],
func = function(trigger, state)
return "back", type(state.cost) == "number" and state.cost;
end,
enable = function(trigger)
return trigger.use_showCost and (not trigger.use_powertype) and trigger.unit == "player";
end
},
},
automaticrequired = true
},
["Combat Log"] = {
type = "combatlog",
events = {
["events"] = {"COMBAT_LOG_EVENT_UNFILTERED"}
},
init = function(trigger)
local ret = [[
local use_cloneId = %s;
]];
return ret:format(trigger.use_cloneId and "true" or "false");
end,
name = L["Combat Log"],
statesParameter = "all",
args = {
{}, -- timestamp ignored with _ argument
{}, -- messageType ignored with _ argument (it is checked before the dynamic function)
-- {}, -- we don't have hideCaster
{
type = "header",
name = "sourceHeader",
display = L["Source Info"],
},
{
name = "sourceGUID",
init = "arg",
hidden = "true",
test = "true",
store = true,
display = L["Source GUID"],
formatter = "guid",
formatterArgs = { color = "class" }
},
{
name = "sourceUnit",
display = L["Source Unit"],
type = "unit",
test = "(sourceGUID or '') == (UnitGUID(%q) or '') and sourceGUID",
values = "actual_unit_types_with_specific",
enable = function(trigger)
return not (trigger.subeventPrefix == "ENVIRONMENTAL")
end,
store = true,
conditionType = "select",
conditionTest = function(state, needle, op)
return state and state.show and ((state.sourceGUID or '') == (UnitGUID(needle) or '')) == (op == "==")
end
},
{
name = "sourceName",
display = L["Source Name"],
type = "string",
multiline = true,
init = "arg",
store = true,
conditionType = "string",
preamble = "local sourceNameChecker = Private.ExecEnv.ParseStringCheck(%q)",
test = "sourceNameChecker:Check(sourceName)",
desc = L["Supports multiple entries, separated by commas. Prefix with '-' for negation."],
},
{
name = "sourceNpcId",
display = L["Source NPC Id"],
type = "string",
multiline = true,
init = "tostring(tonumber(string.sub(sourceGUID or '', 8, 12), 16) or '')",
store = true,
conditionType = "string",
preamble = "local sourceNpcIdChecker = Private.ExecEnv.ParseStringCheck(%q)",
test = "sourceNpcIdChecker:Check(sourceNpcId)",
conditionPreamble = function(input)
return Private.ExecEnv.ParseStringCheck(input)
end,
conditionTest = function(state, needle, op, preamble)
return preamble:Check(state.sourceNpcId)
end,
operator_types = "none",
desc = L["Supports multiple entries, separated by commas. Prefix with '-' for negation."],
enable = function(trigger)
return not (trigger.subeventPrefix == "ENVIRONMENTAL")
end,
},
{
name = "sourceFlags",
display = L["Source Affiliation"],
type = "select",
values = "combatlog_flags_check_type",
init = "arg",
store = true,
test = "Private.ExecEnv.CheckCombatLogFlags(sourceFlags, %q)",
conditionType = "select",
conditionTest = function(state, needle, op)
if state and state.show then
return Private.ExecEnv.CheckCombatLogFlags(state.sourceFlags, needle) == (op == "==")
end
end
},
{
name = "sourceFlags2",
display = L["Source Reaction"],
type = "select",
values = "combatlog_flags_check_reaction",
test = "Private.ExecEnv.CheckCombatLogFlagsReaction(sourceFlags, %q)",
conditionType = "select",
conditionTest = function(state, needle, op)
if state and state.show then
return Private.ExecEnv.CheckCombatLogFlagsReaction(state.sourceFlags, needle) == (op == "==")
end
end
},
{
name = "sourceFlags3",
display = L["Source Object Type"],
type = "select",
values = "combatlog_flags_check_object_type",
test = "Private.ExecEnv.CheckCombatLogFlagsObjectType(sourceFlags, %q)",
conditionType = "select",
conditionTest = function(state, needle, op)
if state and state.show then
return Private.ExecEnv.CheckCombatLogFlagsObjectType(state.sourceFlags, needle) == (op == "==")
end
end
},
-- we don't have sourceRaidFlags
{
type = "header",
name = "destHeader",
display = L["Destination Info"],
enable = function(trigger)
return not (trigger.subeventPrefix == "SPELL" and trigger.subeventSuffix == "_CAST_START");
end,
},
{
name = "destGUID",
init = "arg",
hidden = "true",
test = "true",
store = true,
display = L["Destination GUID"],
formatter = "guid",
formatterArgs = { color = "class" }
},
{
name = "destUnit",
display = L["Destination Unit"],
type = "unit",
test = "(destGUID or '') == (UnitGUID(%q) or '') and destGUID",
values = "actual_unit_types_with_specific",
enable = function(trigger)
return not (trigger.subeventPrefix == "SPELL" and trigger.subeventSuffix == "_CAST_START");
end,
store = true,
conditionType = "select",
conditionTest = function(state, needle, op)
return state and state.show and ((state.destGUID or '') == (UnitGUID(needle) or '')) == (op == "==")
end
},
{
name = "destName",
display = L["Destination Name"],
type = "string",
multiline = true,
init = "arg",
store = true,
conditionType = "string",
preamble = "local destNameChecker = Private.ExecEnv.ParseStringCheck(%q)",
test = "destNameChecker:Check(destName)",
desc = L["Supports multiple entries, separated by commas. Prefix with '-' for negation."],
enable = function(trigger)
return not (trigger.subeventPrefix == "SPELL" and trigger.subeventSuffix == "_CAST_START");
end,
},
{
name = "destNpcId",
display = L["Destination NPC Id"],
type = "string",
multiline = true,
init = "tostring(tonumber(string.sub(destGUID or '', 8, 12), 16) or '')",
store = true,
conditionType = "string",
preamble = "local destNpcIdChecker = Private.ExecEnv.ParseStringCheck(%q)",
test = "destNpcIdChecker:Check(destNpcId)",
conditionPreamble = function(input)
return Private.ExecEnv.ParseStringCheck(input)
end,
conditionTest = function(state, needle, op, preamble)
return preamble:Check(state.destNpcId)
end,
operator_types = "none",
desc = L["Supports multiple entries, separated by commas. Prefix with '-' for negation."],
enable = function(trigger)
return not (trigger.subeventPrefix == "SPELL" and trigger.subeventSuffix == "_CAST_START");
end,
},
{ -- destName ignore for SPELL_CAST_START
enable = function(trigger)
return (trigger.subeventPrefix == "SPELL" and trigger.subeventSuffix == "_CAST_START");
end
},
{
name = "destFlags",
display = L["Destination Affiliation"],
type = "select",
values = "combatlog_flags_check_type",
init = "arg",
store = true,
test = "Private.ExecEnv.CheckCombatLogFlags(destFlags, %q)",
conditionType = "select",
conditionTest = function(state, needle, op)
if state and state.show then
return Private.ExecEnv.CheckCombatLogFlags(state.destFlags, needle) == (op == "==")
end
end,
enable = function(trigger)
return not (trigger.subeventPrefix == "SPELL" and trigger.subeventSuffix == "_CAST_START");
end,
},
{
name = "destFlags2",
display = L["Destination Reaction"],
type = "select",
values = "combatlog_flags_check_reaction",
test = "Private.ExecEnv.CheckCombatLogFlagsReaction(destFlags, %q)",
conditionType = "select",
conditionTest = function(state, needle, op)
if state and state.show then
return Private.ExecEnv.CheckCombatLogFlagsReaction(state.destFlags, needle) == (op == "==")
end
end,
enable = function(trigger)
return not (trigger.subeventPrefix == "SPELL" and trigger.subeventSuffix == "_CAST_START");
end,
},
{
name = "destFlags3",
display = L["Destination Object Type"],
type = "select",
values = "combatlog_flags_check_object_type",
test = "Private.ExecEnv.CheckCombatLogFlagsObjectType(destFlags, %q)",
conditionType = "select",
conditionTest = function(state, needle, op)
if state and state.show then
return Private.ExecEnv.CheckCombatLogFlagsObjectType(state.destFlags, needle) == (op == "==")
end
end,
enable = function(trigger)
return not (trigger.subeventPrefix == "SPELL" and trigger.subeventSuffix == "_CAST_START");
end,
},
{-- destFlags ignore for SPELL_CAST_START
enable = function(trigger)
return (trigger.subeventPrefix == "SPELL" and trigger.subeventSuffix == "_CAST_START");
end,
},
-- we don't have destRaidFlags
{
type = "header",
name = "subeventHeader",
display = L["Subevent Info"],
enable = function(trigger)
return trigger.subeventPrefix and (
trigger.subeventPrefix == "RANGE"
or trigger.subeventPrefix == "ENVIRONMENTAL"
or trigger.subeventPrefix:find("DAMAGE")
or trigger.subeventPrefix:find("SPELL"))
or trigger.subeventSuffix and (
-- trigger.subeventSuffix == "_ABSORBED" -- we don't have that
trigger.subeventSuffix == "_INTERRUPT"
or trigger.subeventSuffix == "_DISPEL"
or trigger.subeventSuffix == "_DISPEL_FAILED"
or trigger.subeventSuffix == "_STOLEN"
or trigger.subeventSuffix == "_AURA_BROKEN_SPELL"
or trigger.subeventSuffix == "_DAMAGE"
or trigger.subeventSuffix == "_HEAL"
or trigger.subeventSuffix == "_ENERGIZE"
or trigger.subeventSuffix == "_DRAIN"
or trigger.subeventSuffix == "_LEECH"
or trigger.subeventSuffix == "_DAMAGE"
or trigger.subeventSuffix == "_MISSED"
or trigger.subeventSuffix == "_EXTRA_ATTACKS"
or trigger.subeventSuffix == "_CAST_FAILED"
or trigger.subeventSuffix:find("DOSE")
or trigger.subeventSuffix:find("AURA"))
end,
},
{
name = "spellId",
display = L["Spell Id"],
init = "arg",
enable = function(trigger)
return trigger.subeventPrefix and (trigger.subeventPrefix:find("SPELL") or trigger.subeventPrefix == "RANGE" or trigger.subeventPrefix:find("DAMAGE"))
end,
store = true,
preambleGroup = "spell",
preamble = "local spellChecker = Private.ExecEnv.CreateSpellChecker()",
multiEntry = {
operator = "preamble",
preambleAdd = "spellChecker:AddExact(%q)"
},
test = "spellChecker:Check(spellId)",
conditionType = "number",
type = "spell",
showExactOption = false,
noProgressSource = true
},
{
name = "spellName",
display = L["Spell Name"],
type = "spell",
noValidation = true,
init = "arg",
enable = function(trigger)
return trigger.subeventPrefix and (trigger.subeventPrefix:find("SPELL") or trigger.subeventPrefix == "RANGE" or trigger.subeventPrefix:find("DAMAGE"))
end,
store = true,
preambleGroup = "spell",
preamble = "local spellChecker = Private.ExecEnv.CreateSpellChecker()",
multiEntry = {
operator = "preamble",
preambleAdd = "spellChecker:AddName(%q)"
},
test = "spellChecker:Check(spellId)",
conditionType = "string"
},
{
name = "spellSchool",
display = WeakAuras.newFeatureString .. L["Spell School"],
type = "select",
values = "combatlog_spell_school_types_for_ui",
sorted = true,
test = "spellSchool == %d",
init = "arg",
conditionType = "select",
store = true,
enable = function(trigger)
return trigger.subeventPrefix and (trigger.subeventPrefix:find("SPELL") or trigger.subeventPrefix == "RANGE" or trigger.subeventPrefix:find("DAMAGE"))
end
},
{
name = "environmentalType",
display = L["Environment Type"],
type = "select",
init = "arg",
values = "environmental_types",
enable = function(trigger)
return trigger.subeventPrefix == "ENVIRONMENTAL"
end,
store = true,
conditionType = "select"
},
{
name = "missType",
display = L["Miss Type"],
type = "select",
init = "arg",
values = "miss_types",
enable = function(trigger)
return trigger.subeventSuffix and trigger.subeventPrefix and (trigger.subeventSuffix == "_MISSED" or trigger.subeventPrefix == "DAMAGE_SHIELD_MISSED")
end,
conditionType = "select",
store = true
},
{
name = "extraSpellId",
display = WeakAuras.newFeatureString .. L["Extra Spell Id"],
init = "arg",
enable = function(trigger)
return trigger.subeventSuffix and (trigger.subeventSuffix == "_INTERRUPT" or trigger.subeventSuffix == "_DISPEL" or trigger.subeventSuffix == "_DISPEL_FAILED" or trigger.subeventSuffix == "_STOLEN" or trigger.subeventSuffix == "_AURA_BROKEN_SPELL")
end,
test = "GetSpellInfo(%q or '') == extraSpellName",
type = "spell",
showExactOption = false,
store = true,
conditionType = "number",
noProgressSource = true
},
{
name = "extraSpellName",
display = L["Extra Spell Name"],
type = "spell",
noValidation = true,
init = "arg",
enable = function(trigger)
return trigger.subeventSuffix and (trigger.subeventSuffix == "_INTERRUPT" or trigger.subeventSuffix == "_DISPEL" or trigger.subeventSuffix == "_DISPEL_FAILED" or trigger.subeventSuffix == "_STOLEN" or trigger.subeventSuffix == "_AURA_BROKEN_SPELL")
end,
store = true,
conditionType = "string"
},
{
enable = function(trigger)
return trigger.subeventSuffix and (trigger.subeventSuffix == "_INTERRUPT" or trigger.subeventSuffix == "_DISPEL" or trigger.subeventSuffix == "_DISPEL_FAILED" or trigger.subeventSuffix == "_STOLEN" or trigger.subeventSuffix == "_AURA_BROKEN_SPELL")
end
}, -- extraSchool ignored with _ argument
{
name = "auraType",
display = L["Aura Type"],
type = "select",
init = "arg",
values = "aura_types",
store = true,
enable = function(trigger)
return trigger.subeventSuffix and (trigger.subeventSuffix:find("AURA") or trigger.subeventSuffix == "_DISPEL" or trigger.subeventSuffix == "_STOLEN")
end,
conditionType = "select"
},
{
name = "amount",
display = L["Amount"],
type = "number",
init = "arg",
enable = function(trigger)
return trigger.subeventSuffix and trigger.subeventPrefix and (trigger.subeventSuffix == "_DAMAGE" or trigger.subeventSuffix == "_HEAL" or trigger.subeventSuffix == "_ENERGIZE" or trigger.subeventSuffix == "_DRAIN" or trigger.subeventSuffix == "_LEECH" or trigger.subeventPrefix:find("DAMAGE"))
end,
store = true,
conditionType = "number"
},
{
name = "overkill",
display = L["Overkill"],
type = "number",
init = "arg",
enable = function(trigger)
return trigger.subeventSuffix and trigger.subeventPrefix and (trigger.subeventSuffix == "_DAMAGE" or trigger.subeventPrefix == "DAMAGE_SHIELD" or trigger.subeventPrefix == "DAMAGE_SPLIT")
end,
store = true,
conditionType = "number"
},
{
name = "overhealing",
display = L["Overhealing"],
type = "number",
init = "arg",
enable = function(trigger)
return trigger.subeventSuffix and trigger.subeventSuffix == "_HEAL"
end,
store = true,
conditionType = "number"
},
{
enable = function(trigger)
return trigger.subeventSuffix and trigger.subeventPrefix and (trigger.subeventSuffix == "_DAMAGE" or trigger.subeventPrefix == "DAMAGE_SHIELD" or trigger.subeventPrefix == "DAMAGE_SPLIT")
end
}, -- damage school ignored with _ argument
{
name = "resisted",
display = L["Resisted"],
type = "number",
init = "arg",
enable = function(trigger)
return trigger.subeventSuffix and trigger.subeventPrefix and (trigger.subeventSuffix == "_DAMAGE" or trigger.subeventPrefix == "DAMAGE_SHIELD" or trigger.subeventPrefix == "DAMAGE_SPLIT")
end,
store = true,
conditionType = "number"
},
{
name = "blocked",
display = L["Blocked"],
type = "number",
init = "arg",
enable = function(trigger)
return trigger.subeventSuffix and trigger.subeventPrefix and (trigger.subeventSuffix == "_DAMAGE" or trigger.subeventPrefix == "DAMAGE_SHIELD" or trigger.subeventPrefix == "DAMAGE_SPLIT")
end,
store = true,
conditionType = "number"
},
{
name = "absorbed",
display = L["Absorbed"],
type = "number",
init = "arg",
enable = function(trigger)
return trigger.subeventSuffix and trigger.subeventPrefix and (trigger.subeventSuffix == "_DAMAGE" or trigger.subeventPrefix == "DAMAGE_SHIELD" or trigger.subeventPrefix == "DAMAGE_SPLIT" or trigger.subeventSuffix == "_HEAL")
end,
store = true,
conditionType = "number"
},
{
name = "critical",
display = L["Critical"],
type = "tristate",
init = "arg",
enable = function(trigger)
return trigger.subeventSuffix and trigger.subeventPrefix and (trigger.subeventSuffix == "_DAMAGE" or trigger.subeventPrefix == "DAMAGE_SHIELD" or trigger.subeventPrefix == "DAMAGE_SPLIT" or trigger.subeventSuffix == "_HEAL")
end,
store = true,
conditionType = "bool"
},
{
name = "glancing",
display = L["Glancing"],
type = "tristate",
init = "arg",
enable = function(trigger)
return trigger.subeventSuffix and trigger.subeventPrefix and (trigger.subeventSuffix == "_DAMAGE" or trigger.subeventPrefix == "DAMAGE_SHIELD" or trigger.subeventPrefix == "DAMAGE_SPLIT")
end,
store = true,
conditionType = "bool"
},
{
name = "crushing",
display = L["Crushing"],
type = "tristate",
init = "arg",
enable = function(trigger)
return trigger.subeventSuffix and trigger.subeventPrefix and (trigger.subeventSuffix == "_DAMAGE" or trigger.subeventPrefix == "DAMAGE_SHIELD" or trigger.subeventPrefix == "DAMAGE_SPLIT")
end,
store = true,
conditionType = "bool"
},
-- we don't have isOffHand :(
{
name = "number",
display = L["Number"],
type = "number",
init = "arg",
enable = function(trigger)
return trigger.subeventSuffix and (trigger.subeventSuffix == "_EXTRA_ATTACKS" or trigger.subeventSuffix:find("DOSE"))
end,
store = true,
conditionType = "number"
},
{
name = "overEnergize",
display = L["Over Energize"],
type = "number",
init = "arg",
store = true,
conditionType = "number",
enable = function(trigger)
return trigger.subeventSuffix and (trigger.subeventSuffix == "_ENERGIZE")
end
},
{
name = "powerType",
display = L["Power Type"],
type = "select",
init = "arg",
values = "power_types",
store = true,
enable = function(trigger)
return trigger.subeventSuffix and (trigger.subeventSuffix == "_ENERGIZE" or trigger.subeventSuffix == "_DRAIN" or trigger.subeventSuffix == "_LEECH")
end,
conditionType = "select"
},
{
name = "extraAmount",
display = L["Extra Amount"],
type = "number",
init = "arg",
enable = function(trigger)
return trigger.subeventSuffix and (trigger.subeventSuffix == "_DRAIN" or trigger.subeventSuffix == "_LEECH")
end,
store = true,
conditionType = "number"
},
{
enable = function(trigger)
return trigger.subeventSuffix == "_CAST_FAILED"
end
}, -- failedType ignored with _ argument - theoretically this is not necessary because it is the last argument in the event, but it is added here for completeness
{
type = "header",
name = "miscellaneousHeader",
display = L["Miscellaneous"],
},
{
name = "cloneId",
display = L["Clone per Event"],
type = "toggle",
test = "true",
init = "use_cloneId and WeakAuras.GetUniqueCloneId() or ''"
},
{
hidden = true,
name = "icon",
init = "(spellId and select(3, GetSpellInfo(spellId))) or 'Interface\\\\Icons\\\\INV_Misc_QuestionMark'",
store = true,
test = "true"
},
},
countEvents = true,
delayEvents = true,
timedrequired = true,
progressType = "timed"
},
["Cooldown Progress (Spell)"] = {
type = "spell",
events = {},
loadInternalEventFunc = function(trigger, untrigger)
local spellName = type(trigger.spellName) ~= "table" and trigger.spellName or 0;
if not trigger.use_exact_spellName then
spellName = type(spellName) == "number" and GetSpellInfo(spellName) or spellName;
end
if spellName == nil then return {} end
local events = {
"SPELL_COOLDOWN_CHANGED:" .. spellName,
"COOLDOWN_REMAINING_CHECK:" .. spellName,
"WA_DELAYED_PLAYER_ENTERING_WORLD"
};
if (trigger.use_showgcd) then
tinsert(events, "GCD_START");
tinsert(events, "GCD_CHANGE");
tinsert(events, "GCD_END");
end
return events;
end,
force_events = "SPELL_COOLDOWN_FORCE",
name = L["Cooldown/Charges/Count"],
loadFunc = function(trigger)
local spellName = type(trigger.spellName) ~= "table" and trigger.spellName or 0;
if not trigger.use_exact_spellName then
spellName = type(spellName) == "number" and GetSpellInfo(spellName) or spellName;
end
WeakAuras.WatchSpellCooldown(spellName, trigger.use_matchedRune)
if (trigger.use_showgcd) then
WeakAuras.WatchGCD();
end
end,
init = function(trigger)
local spellName = type(trigger.spellName) ~= "table" and trigger.spellName or 0
if not trigger.use_exact_spellName then
spellName = type(spellName) == "number" and GetSpellInfo(spellName) or spellName;
end
if (type(spellName) == "string") then
spellName = "[[" .. spellName .. "]]";
end
local ret = {}
local showOnCheck = "false";
if (trigger.genericShowOn == "showOnReady") then
showOnCheck = "startTime and startTime == 0 or gcdCooldown";
elseif (trigger.genericShowOn == "showOnCooldown") then
showOnCheck = "startTime and startTime > 0 and not gcdCooldown";
elseif (trigger.genericShowOn == "showAlways") then
showOnCheck = "startTime ~= nil";
end
local trackSpecificCharge = trigger.use_trackcharge and trigger.trackcharge and trigger.trackcharge ~= ""
local track = trigger.track or "auto"
if track == "auto" and trackSpecificCharge then
track = "charges"
end
table.insert(ret, ([=[
local spellname = %s
local ignoreRuneCD = %s
local showgcd = %s;
local ignoreSpellKnown = %s;
local track = %q
local effectiveSpellId = spellname
local name, _, icon = GetSpellInfo(effectiveSpellId)
local startTime, duration, gcdCooldown, readyTime, paused = WeakAuras.GetSpellCooldown(effectiveSpellId, ignoreRuneCD, showgcd, ignoreSpellKnown, track)
local charges, maxCharges, spellCount, chargeGainTime, chargeLostTime = WeakAuras.GetSpellCharges(effectiveSpellId, ignoreSpellKnown)
local stacks = maxCharges and maxCharges > 1 and charges or (spellCount and spellCount > 0 and spellCount) or nil;
if (charges == nil) then
-- Use fake charges for spells that use GetSpellCooldown
charges = (duration == 0 or gcdCooldown) and 1 or 0;
end
local genericShowOn = %s
local expirationTime = startTime and duration and startTime + duration
state.spellname = spellname;
]=]):format(
spellName,
(trigger.use_matchedRune and "true" or "false"),
(trigger.use_showgcd and "true" or "false"),
(trigger.use_ignoreSpellKnown and "true" or "false"),
track,
showOnCheck
))
if (not trackSpecificCharge) then
table.insert(ret, [=[
if paused then
if not state.paused then
state.paused = true
state.expirationTime = nil
state.changed = true
end
if state.remaining ~= startTime then
state.remaining = startTime
state.changed = true
end
else
if (state.expirationTime ~= expirationTime) then
state.expirationTime = expirationTime;
state.changed = true;
end
if state.paused then
state.paused = false
state.remaining = nil
state.changed = true
end
end
if (state.duration ~= duration) then
state.duration = duration;
state.changed = true;
end
state.progressType = 'timed';
]=])
else -- Tracking charges
local trackedCharge = tonumber(trigger.trackcharge) or 1;
table.insert(ret, ([=[
local trackedCharge = %s
if (charges > trackedCharge) then
if (state.expirationTime ~= 0) then
state.expirationTime = 0;
state.changed = true;
end
if (state.duration ~= 0) then
state.duration = 0;
state.changed = true;
end
state.value = nil;
state.total = nil;
state.progressType = 'timed';
else
if duration then
expirationTime = expirationTime + (trackedCharge - charges) * duration
end
if (state.expirationTime ~= expirationTime) then
state.expirationTime = expirationTime;
state.changed = true;
end
if (state.duration ~= duration) then
state.duration = duration;
state.changed = true;
end
state.value = nil;
state.total = nil;
state.progressType = 'timed';
end
]=]):format(trackedCharge - 1))
end
if(trigger.use_remaining and trigger.genericShowOn ~= "showOnReady") then
table.insert(ret, ([[
local remaining = 0;
if (not paused and expirationTime and expirationTime > 0) then
remaining = expirationTime - GetTime();
local remainingCheck = %s;
if(remaining >= remainingCheck and remaining > 0) then
local event = "COOLDOWN_REMAINING_CHECK:" .. %s
Private.ExecEnv.ScheduleScan(expirationTime - remainingCheck, event);
end
end
]]):format(tonumber(trigger.remaining or 0) or 0, spellName))
end
return table.concat(ret)
end,
GetNameAndIcon = GetNameAndIconForSpellName,
statesParameter = "one",
progressType = "timed",
args = {
{
}, -- Ignore first argument (id)
{
name = "spellName",
required = true,
display = L["Spell"],
type = "spell",
test = "true",
showExactOption = true,
},
{
name = "extra Cooldown Progress (Spell)",
display = function(trigger)
return function()
local text = "";
if trigger.track == "charges" then
text = L["Tracking Charge CDs"]
elseif trigger.track == "cooldown" then
text = L["Tracking Only Cooldown"]
end
if trigger.use_showgcd then
if text ~= "" then text = text .. "; " end
text = text .. L["Show GCD"]
end
if trigger.use_matchedRune then
if text ~= "" then text = text .. "; " end
text = text ..L["Ignore Rune CDs"]
end
if trigger.use_ignoreSpellKnown then
if text ~= "" then text = text .. "; " end
text = text .. L["Disabled Spell Known Check"]
end
if trigger.genericShowOn ~= "showOnReady" and trigger.track ~= "cooldown" then
if trigger.use_trackcharge and trigger.trackcharge and trigger.trackcharge ~= "" then
if text ~= "" then text = text .. "; " end
text = text .. L["Tracking Charge %i"]:format(trigger.trackcharge)
end
end
if text == "" then
return L["|cFFffcc00Extra Options:|r None"]
end
return L["|cFFffcc00Extra Options:|r %s"]:format(text)
end
end,
type = "collapse",
},
{
name = "track",
display = L["Track Cooldowns"],
type = "select",
values = "cooldown_types",
collapse = "extra Cooldown Progress (Spell)",
test = "true",
required = true,
default = "auto"
},
{
name = "showgcd",
display = L["Show Global Cooldown"],
type = "toggle",
test = "true",
collapse = "extra Cooldown Progress (Spell)"
},
{
name = "matchedRune",
display = L["Ignore Rune CD"],
type = "toggle",
test = "true",
collapse = "extra Cooldown Progress (Spell)"
},
{
name = "ignoreSpellKnown",
display = L["Disable Spell Known Check"],
type = "toggle",
test = "true",
collapse = "extra Cooldown Progress (Spell)"
},
{
name = "trackcharge",
display = L["Show CD of Charge"],
type = "number",
enable = function(trigger)
return (trigger.genericShowOn ~= "showOnReady") and trigger.track ~= "cooldown"
end,
test = "true",
noOperator = true,
collapse = "extra Cooldown Progress (Spell)"
},
{
name = "remaining",
display = L["Remaining Time"],
type = "number",
enable = function(trigger) return (trigger.genericShowOn ~= "showOnReady") end
},
{
name = "charges",
display = L["Charges"],
type = "number",
store = true,
conditionType = "number",
progressTotal = "maxCharges"
},
{
name = "spellCount",
display = L["Spell Count"],
type = "number",
store = true,
conditionType = "number"
},
{
name = "stacks",
init = "stacks",
hidden = true,
test = "true",
store = true
},
{
hidden = true,
name = "maxCharges",
store = true,
display = L["Max Charges"],
conditionType = "number",
test = "true",
},
{
hidden = true,
name = "readyTime",
display = L["Since Ready"],
conditionType = "elapsedTimer",
store = true,
test = "true"
},
{
hidden = true,
name = "chargeGainTime",
display = L["Since Charge Gain"],
conditionType = "elapsedTimer",
store = true,
test = "true"
},
{
hidden = true,
name = "chargeLostTime",
display = L["Since Charge Lost"],
conditionType = "elapsedTimer",
store = true,
test = "true"
},
{
hidden = true,
name = "effectiveSpellId",
display = L["Effective Spell Id"],
conditionType = "number",
store = true,
test = "true",
operator_types = "only_equal"
},
{
name = "genericShowOn",
display = L["Show"],
type = "select",
values = "cooldown_progress_behavior_types",
test = "true",
required = true,
default = "showOnCooldown"
},
{
hidden = true,
name = "onCooldown",
test = "true",
display = L["On Cooldown"],
conditionType = "bool",
conditionTest = function(state, needle)
return state and state.show and (state.paused or (not state.gcdCooldown and state.expirationTime and state.expirationTime > GetTime())) == (needle == 1)
end,
},
{
hidden = true,
name = "gcdCooldown",
store = true,
test = "true"
},
{
name = "spellUsable",
display = L["Spell Usable"],
hidden = true,
test = "true",
conditionType = "bool",
conditionTest = function(state, needle)
return state and state.show and
((IsUsableSpell((type(state.spellname) == "number" and GetSpellInfo(state.spellname)) or state.spellname) == 1 and true or false) == (needle == 1))
end,
conditionEvents = AddTargetConditionEvents({
"SPELL_UPDATE_USABLE",
"UNIT_MANA:player", "UNIT_RAGE:player", "UNIT_FOCUS:player", "UNIT_ENERGY:player", "UNIT_RUNIC_POWER:player"
}),
},
{
name = "insufficientResources",
display = L["Insufficient Resources"],
hidden = true,
test = "true",
conditionType = "bool",
conditionTest = function(state, needle)
return state and state.show and
((select(2, IsUsableSpell((type(state.spellname) == "number" and GetSpellInfo(state.spellname)) or state.spellname)) == 1 and true or false) == (needle == 1))
end,
conditionEvents = AddTargetConditionEvents({
"SPELL_UPDATE_USABLE",
"UNIT_MANA:player", "UNIT_RAGE:player", "UNIT_FOCUS:player", "UNIT_ENERGY:player", "UNIT_RUNIC_POWER:player"
}),
},
{
name = "spellInRange",
display = L["Spell in Range"],
hidden = true,
test = "true",
conditionType = "bool",
conditionTest = function(state, needle)
return state and state.show and (UnitExists('target') and state.spellname and WeakAuras.IsSpellInRange(state.spellname, 'target') == needle)
end,
conditionEvents = AddTargetConditionEvents({
"WA_SPELL_RANGECHECK",
}),
},
{
hidden = true,
test = "genericShowOn"
},
{
name = "name",
display = L["Name"],
hidden = true,
init = "name",
test = "true",
store = true,
conditionType = "string"
},
{
name = "icon",
hidden = true,
init = "icon",
test = "true",
store = true
},
},
hasSpellID = true,
automaticrequired = true,
},
["Cooldown Ready (Spell)"] = {
type = "spell",
events = {},
loadInternalEventFunc = function(trigger, untrigger)
local spellName = type(trigger.spellName) ~= "table" and trigger.spellName or 0
if not trigger.use_exact_spellName then
spellName = type(spellName) == "number" and GetSpellInfo(spellName) or spellName;
end
if spellName == nil then return {} end
return { "SPELL_COOLDOWN_READY:" .. spellName }
end,
name = L["Cooldown Ready Event"],
loadFunc = function(trigger)
local spellName = type(trigger.spellName) ~= "table" and trigger.spellName or 0
if not trigger.use_exact_spellName then
spellName = type(spellName) == "number" and GetSpellInfo(spellName) or spellName;
end
WeakAuras.WatchSpellCooldown(spellName, false)
end,
init = function(trigger)
local spellName = type(trigger.spellName) ~= "table" and trigger.spellName or 0
if not trigger.use_exact_spellName then
spellName = type(spellName) == "number" and GetSpellInfo(spellName) or spellName;
end
if (type(spellName) == "string") then
spellName = "[[" .. spellName .. "]]";
end
local ret = [=[
local triggerSpellName = %s
local name, _, icon = GetSpellInfo(triggerSpellName)
]=]
return ret:format(spellName)
end,
GetNameAndIcon = GetNameAndIconForSpellName,
statesParameter = "one",
args = {
{
name = "spellName",
required = true,
display = L["Spell"],
type = "spell",
init = "arg",
showExactOption = true,
test = "true"
},
{
name = "name",
display = L["Name"],
hidden = true,
init = "name",
test = "true",
store = true,
conditionType = "string"
},
{
name = "icon",
hidden = true,
init = "icon",
test = "true",
store = true
},
},
hasSpellID = true,
timedrequired = true,
progressType = "timed"
},
["Charges Changed"] = {
type = "spell",
events = {},
loadInternalEventFunc = function(trigger, untrigger)
local spellName = type(trigger.spellName) ~= "table" and trigger.spellName or 0
if not trigger.use_exact_spellName then
spellName = type(spellName) == "number" and GetSpellInfo(spellName) or spellName;
end
if spellName == nil then return {} end
return { "SPELL_CHARGES_CHANGED:" .. spellName }
end,
name = L["Charges Changed Event"],
loadFunc = function(trigger)
local spellName = type(trigger.spellName) ~= "table" and trigger.spellName or 0
if not trigger.use_exact_spellName then
spellName = type(spellName) == "number" and GetSpellInfo(spellName) or spellName;
end
WeakAuras.WatchSpellCooldown(spellName);
end,
init = function(trigger)
local spellName = type(trigger.spellName) ~= "table" and trigger.spellName or 0
if not trigger.use_exact_spellName then
spellName = type(spellName) == "number" and GetSpellInfo(spellName) or spellName;
end
if (type(spellName) == "string") then
spellName = "[[" .. spellName .. "]]";
end
local ret = [=[
local triggerSpellName = %s
local name, _, icon = GetSpellInfo(triggerSpellName)
]=]
return ret:format(spellName)
end,
statesParameter = "one",
GetNameAndIcon = GetNameAndIconForSpellName,
args = {
{
name = "spellName",
required = true,
display = L["Spell"],
type = "spell",
init = "arg",
showExactOption = true,
test = "true"
},
{
name = "direction",
required = true,
display = L["Charge gained/lost"],
type = "select",
values = "charges_change_type",
init = "arg",
test = "Private.ExecEnv.CheckChargesDirection(direction, %q)",
store = true,
conditionType = "select",
conditionValues = "charges_change_condition_type";
conditionTest = function(state, needle)
return state and state.show and state.direction and Private.ExecEnv.CheckChargesDirection(state.direction, needle)
end,
},
{
name = "charges",
display = L["Charges"],
type = "number",
init = "arg",
store = true,
conditionType = "number"
},
{
name = "name",
display = L["Name"],
hidden = true,
init = "name",
test = "true",
store = true,
conditionType = "string"
},
{
name = "icon",
hidden = true,
init = "icon",
test = "true",
store = true
},
},
hasSpellID = true,
timedrequired = true,
progressType = "timed"
},
["Cooldown Progress (Item)"] = {
type = "item",
events = {},
internal_events = function(trigger, untrigger)
local itemName = type(trigger.itemName) == "number" and trigger.itemName or string.format("%q", trigger.itemName or "0")
local events = {
"ITEM_COOLDOWN_READY:" .. itemName,
"ITEM_COOLDOWN_CHANGED:" .. itemName,
"ITEM_COOLDOWN_STARTED:" .. itemName,
"COOLDOWN_REMAINING_CHECK:" .. itemName,
}
if (trigger.use_showgcd) then
tinsert(events, "GCD_START");
tinsert(events, "GCD_CHANGE");
tinsert(events, "GCD_END");
end
return events
end,
force_events = "ITEM_COOLDOWN_FORCE",
name = L["Cooldown Progress (Item)"],
loadFunc = function(trigger)
WeakAuras.WatchItemCooldown(trigger.itemName or 0)
if (trigger.use_showgcd) then
WeakAuras.WatchGCD();
end
end,
init = function(trigger)
local itemName = type(trigger.itemName) == "number" and trigger.itemName or string.format("%q", trigger.itemName or "0")
local ret = [=[
local itemname = %s;
local name = GetItemInfo(itemname or 0) or "Invalid"
local icon = GetItemIcon(itemname) or ""
local showgcd = %s
local startTime, duration, enabled, gcdCooldown = WeakAuras.GetItemCooldown(itemname, showgcd);
local expirationTime = startTime + duration
local genericShowOn = %s
state.itemname = itemname;
]=];
if(trigger.use_remaining and trigger.genericShowOn ~= "showOnReady") then
local ret2 = [[
local remaining = expirationTime > 0 and (expirationTime - GetTime()) or 0;
local remainingCheck = %s;
if(remaining >= remainingCheck and remaining > 0) then
local event = "COOLDOWN_REMAINING_CHECK:" .. %s
Private.ExecEnv.ScheduleScan(expirationTime - remainingCheck, event);
end
]];
ret = ret..ret2:format(tonumber(trigger.remaining or 0) or 0, itemName);
end
return ret:format(itemName,
trigger.use_showgcd and "true" or "false",
"[[" .. (trigger.genericShowOn or "") .. "]]");
end,
GetNameAndIcon = function(trigger)
local name = GetItemInfo(trigger.itemName or 0)
local icon = GetItemIcon(trigger.itemName or 0)
return name, icon
end,
statesParameter = "one",
args = {
{
name = "itemName",
required = true,
display = L["Item"],
type = "item",
test = "true"
},
--[[{ maybe some day
name = "itemId",
display = WeakAuras.newFeatureString .. L["ItemId"],
hidden = true,
init = "itemId",
test = "true",
store = true,
conditionType = "number",
operator_types = "only_equal",
},]]
{
name = "remaining",
display = L["Remaining Time"],
type = "number",
enable = function(trigger) return (trigger.genericShowOn ~= "showOnReady") end,
init = "remaining"
},
{
name = "extra Cooldown Progress (Item)",
display = function(trigger)
return function()
local text = "";
if trigger.use_showgcd then
if text ~= "" then text = text .. "; " end
text = text .. L["Show GCD"]
end
if text == "" then
return L["|cFFffcc00Extra Options:|r None"]
end
return L["|cFFffcc00Extra Options:|r %s"]:format(text)
end
end,
type = "collapse",
},
{
name = "showgcd",
display = L["Show Global Cooldown"],
type = "toggle",
test = "true",
collapse = "extra Cooldown Progress (Item)"
},
{
name = "genericShowOn",
display = L["Show"],
type = "select",
values = "cooldown_progress_behavior_types",
test = "true",
required = true,
default = "showOnCooldown"
},
{
hidden = true,
name = "enabled",
store = true,
test = "true",
},
{
hidden = true,
name = "onCooldown",
test = "true",
display = L["On Cooldown"],
conditionType = "bool",
conditionTest = function(state, needle)
return state and state.show and (not state.gcdCooldown and state.expirationTime and state.expirationTime > GetTime() or state.enabled == 0) == (needle == 1)
end,
},
{
hidden = true,
name = "gcdCooldown",
store = true,
test = "true"
},
{
name = "name",
display = L["Name"],
hidden = true,
init = "name",
test = "true",
store = true,
conditionType = "string"
},
{
name = "icon",
hidden = true,
init = "icon",
test = "true",
store = true
},
{
name = "progressType",
hidden = true,
init = "'timed'",
store = true,
test = "true"
},
{
name = "duration",
hidden = true,
init = "duration",
test = "true",
store = true
},
{
name = "expirationTime",
init = "expirationTime",
hidden = true,
test = "true",
store = true
},
{
hidden = true,
test = "(genericShowOn == \"showOnReady\" and (startTime == 0 and enabled == 1 or gcdCooldown))" ..
"or (genericShowOn == \"showOnCooldown\" and (startTime > 0 or enabled == 0) and not gcdCooldown) " ..
"or (genericShowOn == \"showAlways\")"
}
},
hasItemID = true,
automaticrequired = true,
progressType = "timed"
},
["Cooldown Progress (Equipment Slot)"] = {
type = "item",
events = {
["unit_events"] = {
["player"] = {"UNIT_INVENTORY_CHANGED"}
}
},
internal_events = function(trigger, untrigger)
local slot = trigger.itemSlot or 0
local events = {
"ITEM_SLOT_COOLDOWN_STARTED:" .. slot,
"ITEM_SLOT_COOLDOWN_CHANGED:" .. slot,
"COOLDOWN_REMAINING_CHECK:" .. slot,
"ITEM_SLOT_COOLDOWN_ITEM_CHANGED:" .. slot,
"ITEM_SLOT_COOLDOWN_READY:" .. slot,
"WA_DELAYED_PLAYER_ENTERING_WORLD"
}
if (trigger.use_showgcd) then
tinsert(events, "GCD_START");
tinsert(events, "GCD_CHANGE");
tinsert(events, "GCD_END");
end
return events
end,
force_events = "ITEM_COOLDOWN_FORCE",
name = L["Cooldown Progress (Slot)"],
loadFunc = function(trigger)
WeakAuras.WatchItemSlotCooldown(trigger.itemSlot);
if (trigger.use_showgcd) then
WeakAuras.WatchGCD();
end
end,
init = function(trigger)
local ret = [[
local showgcd = %s
local itemSlot = %s
local startTime, duration, enable, gcdCooldown = WeakAuras.GetItemSlotCooldown(itemSlot, showgcd)
local expirationTime = startTime + duration
local genericShowOn = %s
local remaining = startTime + duration - GetTime();
local name = ""
local item = GetInventoryItemID("player", itemSlot or 0)
if item then
name = GetItemInfo(item)
end
local icon = GetInventoryItemTexture("player", itemSlot or 0)
local stacks = GetInventoryItemCount("player", itemSlot or 0)
if ((stacks == 1) and (not GetInventoryItemTexture("player", itemSlot or 0))) then
stacks = 0
end
]];
if(trigger.use_remaining and trigger.genericShowOn ~= "showOnReady") then
local ret2 = [[
local remaining = expirationTime > 0 and (expirationTime - GetTime()) or 0;
local remainingCheck = %s;
if(remaining >= remainingCheck and remaining > 0) then
local event = "COOLDOWN_REMAINING_CHECK:" .. %s
Private.ExecEnv.ScheduleScan(expirationTime - remainingCheck, event);
end
]];
ret = ret..ret2:format(tonumber(trigger.remaining or 0) or 0, trigger.itemSlot or 0);
end
return ret:format(trigger.use_showgcd and "true" or "false",
trigger.itemSlot or "0",
"[[" .. (trigger.genericShowOn or "") .. "]]");
end,
GetNameAndIcon = function(trigger)
local item = GetInventoryItemID("player", trigger.itemSlot or 0);
local name
if (item) then
name = GetItemInfo(item)
end
local icon = GetInventoryItemTexture("player", trigger.itemSlot or 0)
return name, icon
end,
statesParameter = "one",
args = {
{
name = "itemId",
display = WeakAuras.newFeatureString .. L["ItemId"],
hidden = true,
init = "item",
test = "true",
store = true,
conditionType = "number",
operator_types = "only_equal",
},
{
name = "itemSlot",
required = true,
display = L["Equipment Slot"],
type = "select",
values = "item_slot_types",
test = "true"
},
{
name = "extra Cooldown Progress (Equipment Slot)",
display = function(trigger)
return function()
local text = "";
if trigger.use_showgcd then
if text ~= "" then text = text .. "; " end
text = text .. L["Show GCD"]
end
if text == "" then
return L["|cFFffcc00Extra Options:|r None"]
end
return L["|cFFffcc00Extra Options:|r %s"]:format(text)
end
end,
type = "collapse",
},
{
name = "showgcd",
display = L["Show Global Cooldown"],
type = "toggle",
test = "true",
collapse = "extra Cooldown Progress (Equipment Slot)"
},
{
name = "remaining",
display = L["Remaining Time"],
type = "number",
enable = function(trigger) return (trigger.genericShowOn ~= "showOnReady") end,
init = "remaining"
},
{
name = "testForCooldown",
display = L["is useable"],
type = "toggle",
test = "enable == 1"
},
{
name = "genericShowOn",
display = L["Show"],
type = "select",
values = "cooldown_progress_behavior_types",
test = "true",
required = true,
default = "showOnCooldown"
},
{
name = "progressType",
hidden = true,
init = "'timed'",
store = true,
test = "true"
},
{
name = "duration",
hidden = true,
init = "duration",
test = "true",
store = true
},
{
name = "expirationTime",
init = "expirationTime",
hidden = true,
test = "true",
store = true
},
{
name = "name",
display = L["Name"],
hidden = true,
init = "name",
test = "true",
store = true,
conditionType = "string"
},
--[[{ maybe some day
name = "itemId",
display = L["ItemId"],
hidden = true,
init = "item",
test = "true",
store = true,
conditionType = "number",
operator_types = "only_equal",
},]]
{
name = "icon",
hidden = true,
init = "icon",
test = "true",
store = true
},
{
name = "stacks",
display = L["Stacks"],
init = "stacks",
hidden = true,
test = "true",
store = true,
conditionType = "number"
},
{
hidden = true,
name = "onCooldown",
test = "true",
display = L["On Cooldown"],
conditionType = "bool",
conditionTest = function(state, needle)
return state and state.show and (not state.gcdCooldown and state.expirationTime and state.expirationTime > GetTime()) == (needle == 1);
end,
},
{
hidden = true,
name = "gcdCooldown",
store = true,
test = "true"
},
{
hidden = true,
test = "(genericShowOn == \"showOnReady\" and (startTime == 0 or gcdCooldown)) " ..
"or (genericShowOn == \"showOnCooldown\" and startTime > 0 and not gcdCooldown) " ..
"or (genericShowOn == \"showAlways\")"
}
},
automaticrequired = true,
hasItemID = true,
progressType = "timed"
},
["Cooldown Ready (Item)"] = {
type = "item",
events = {},
internal_events = function(trigger)
return { "ITEM_COOLDOWN_READY:" .. (trigger.itemName or 0) }
end,
name = L["Cooldown Ready Event (Item)"],
loadFunc = function(trigger)
WeakAuras.WatchItemCooldown(trigger.itemName or 0)
end,
init = function(trigger)
local ret = [[
local itemName = %s
local name = GetItemInfo(itemName) or "Invalid"
local icon = GetItemIcon(itemName) or ""
]]
local itemName = type(trigger.itemName) == "number" and trigger.itemName or string.format("%q", trigger.itemName or "0")
return ret:format(itemName)
end,
GetNameAndIcon = function(trigger)
local name = GetItemInfo(trigger.itemName or 0)
local icon = GetItemIcon(trigger.itemName or 0)
return name, icon
end,
statesParameter = "one",
args = {
{
name = "itemName",
required = true,
display = L["Item"],
type = "item",
init = "arg"
},
--[[{ maybe some day
name = "itemId",
display = WeakAuras.newFeatureString .. L["ItemId"],
hidden = true,
init = "itemId",
test = "true",
store = true,
conditionType = "number",
operator_types = "only_equal",
},]]
{
name = "name",
display = L["Name"],
hidden = true,
init = "name",
test = "true",
store = true,
conditionType = "string"
},
{
name = "icon",
hidden = true,
init = "icon",
test = "true",
store = true
},
},
hasItemID = true,
timedrequired = true,
progressType = "timed"
},
["Cooldown Ready (Equipment Slot)"] = {
type = "item",
events = {},
internal_events = function(trigger)
return {
"ITEM_SLOT_COOLDOWN_READY:" .. (trigger.itemSlot or 0)
}
end,
name = L["Cooldown Ready Event (Slot)"],
loadFunc = function(trigger)
WeakAuras.WatchItemSlotCooldown(trigger.itemSlot);
end,
init = function(trigger)
local ret = [[
local itemSlot = %s
local item = GetInventoryItemID("player", itemSlot)
local name = ""
if (item) then
name = GetItemInfo(item)
end
local icon = GetInventoryItemTexture("player", itemSlot)
]]
return ret:format(trigger.itemSlot or 0)
end,
GetNameAndIcon = function(trigger)
local item = GetInventoryItemID("player", trigger.itemSlot or 0)
local name = item and GetItemInfo(item) or nil
local icon = GetInventoryItemTexture("player", trigger.itemSlot or 0)
return name, icon
end,
statesParameter = "one",
args = {
{
name = "itemSlot",
required = true,
display = L["Equipment Slot"],
type = "select",
values = "item_slot_types",
init = "arg"
},
{
name = "itemId",
display = WeakAuras.newFeatureString .. L["ItemId"],
hidden = true,
init = "item",
test = "true",
store = true,
conditionType = "number",
operator_types = "only_equal",
},
{
name = "name",
display = L["Name"],
hidden = true,
init = "name",
test = "true",
store = true,
conditionType = "string"
},
{
name = "icon",
hidden = true,
init = "icon",
test = "true",
store = true
},
},
hasItemID = true,
timedrequired = true,
progressType = "timed"
},
["GTFO"] = {
type = "addons",
events = {
["events"] = {"GTFO_DISPLAY"}
},
name = L["GTFO Alert"],
statesParameter = "one",
args = {
{
name = "alertType",
display = L["Alert Type"],
type = "select",
init = "arg",
values = "gtfo_types",
store = true,
conditionType = "select"
},
},
timedrequired = true,
progressType = "timed"
},
["Global Cooldown"] = {
type = "spell",
events = {},
internal_events = {
"GCD_START",
"GCD_CHANGE",
"GCD_END",
"GCD_UPDATE",
"WA_DELAYED_PLAYER_ENTERING_WORLD"
},
force_events = "GCD_UPDATE",
name = L["Global Cooldown"],
loadFunc = function(trigger)
WeakAuras.WatchGCD();
end,
init = function(trigger)
local ret = [[
local inverse = %s;
local duration, expirationTime, name, icon = WeakAuras.GetGCDInfo()
local hasSpellName = WeakAuras.GcdSpellName();
]];
return ret:format(trigger.use_inverse and "true" or "false");
end,
statesParameter = "one",
args = {
{
name = "inverse",
display = L["Inverse"],
type = "toggle",
test = "true"
},
{
name = "name",
display = L["Name"],
hidden = true,
init = "name",
test = "true",
store = true,
conditionType = "string"
},
{
name = "icon",
hidden = true,
init = "icon",
test = "true",
store = true
},
{
name = "duration",
hidden = true,
init = "duration",
test = "true",
store = true
},
{
name = "expirationTime",
init = "expirationTime",
hidden = true,
test = "true",
store = true
},
{
name = "progressType",
hidden = true,
init = "'timed'",
test = "true",
store = true
},
{
hidden = true,
test = "(inverse and duration == 0) or (not inverse and duration > 0 and hasSpellName)"
}
},
hasSpellID = true,
automaticrequired = true,
progressType = "timed"
},
["Swing Timer"] = {
type = "unit",
events = {},
internal_events = {
"SWING_TIMER_UPDATE"
},
force_events = "SWING_TIMER_UPDATE",
name = L["Swing Timer"],
loadFunc = function()
WeakAuras.InitSwingTimer();
end,
init = function(trigger)
local ret = [=[
local inverse = %s;
local hand = %q;
local triggerRemaining = %s
local duration, expirationTime, name, icon = WeakAuras.GetSwingTimerInfo(hand)
local remaining = expirationTime and expirationTime - GetTime()
local remainingCheck = not triggerRemaining or remaining and remaining %s triggerRemaining
if triggerRemaining and remaining and remaining >= triggerRemaining and remaining > 0 then
Private.ExecEnv.ScheduleScan(expirationTime - triggerRemaining, "SWING_TIMER_UPDATE")
end
]=];
return ret:format(
(trigger.use_inverse and "true" or "false"),
trigger.hand or "main",
trigger.use_remaining and tonumber(trigger.remaining or 0) or "nil",
trigger.remaining_operator or "<"
);
end,
args = {
{
name = "note",
type = "description",
display = "",
text = function()
return L["Note: Due to how complicated the swing timer behavior is and the lack of APIs from Blizzard, results are inaccurate in edge cases."]
end,
},
{
name = "hand",
required = true,
display = L["Weapon"],
type = "select",
values = "swing_types",
test = "true"
},
{
name = "duration",
hidden = true,
init = "duration",
test = "true",
store = true
},
{
name = "expirationTime",
init = "expirationTime",
hidden = true,
test = "true",
store = true
},
{
name = "progressType",
hidden = true,
init = "'timed'",
test = "true",
store = true
},
{
name = "name",
hidden = true,
init = "name",
test = "true",
store = true
},
{
name = "icon",
hidden = true,
init = "icon",
test = "true",
store = true
},
{
name = "remaining",
display = L["Remaining Time"],
type = "number",
enable = function(trigger) return not trigger.use_inverse end,
test = "true"
},
{
name = "inverse",
display = L["Inverse"],
type = "toggle",
test = "true"
},
{
hidden = true,
test = "(inverse and duration == 0) or (not inverse and duration > 0)"
},
{
hidden = true,
test = "remainingCheck"
}
},
automaticrequired = true,
progressType = "timed",
statesParameter = "one"
},
["Action Usable"] = {
type = "spell",
events = function()
local events = {
"SPELL_UPDATE_USABLE",
"ACTIONBAR_UPDATE_USABLE",
"PLAYER_TARGET_CHANGED",
}
local unit_events
if UnitPowerType("player") == 6 then
tinsert(events, "RUNE_POWER_UPDATE")
tinsert(events, "RUNE_TYPE_UPDATE")
unit_events = {}
end
return {
["events"] = events,
["unit_events"] = unit_events or {
["player"] = {
"UNIT_POWER",
"UNIT_ENERGY",
"UNIT_MANA",
"UNIT_RAGE"
}
}
}
end,
loadInternalEventFunc = function(trigger)
local spellName = type(trigger.spellName) ~= "table" and trigger.spellName or 0
if type(trigger.spellName) == "number" then
spellName = GetSpellInfo(spellName)
end
if spellName == nil then return {} end
return { "SPELL_COOLDOWN_CHANGED:" .. spellName }
end,
force_events = "SPELL_UPDATE_USABLE",
name = L["Spell Usable"],
statesParameter = "one",
loadFunc = function(trigger)
local spellName = type(trigger.spellName) ~= "table" and trigger.spellName or 0
if type(trigger.spellName) == "number" then
spellName = GetSpellInfo(spellName)
end
WeakAuras.WatchSpellCooldown(spellName, false);
end,
init = function(trigger)
local spellName = type(trigger.spellName) ~= "table" and trigger.spellName or 0
if type(trigger.spellName) == "number" then
spellName = GetSpellInfo(spellName) or ""
end
local ret = [=[
local spellName = %s
local effectiveSpellId = spellName
local name, _, icon = GetSpellInfo(effectiveSpellId)
]=]
if trigger.use_ignoreSpellCooldown then
ret = ret .. [=[local active = IsUsableSpell(spellName or "")]=]
else
ret = ret .. [=[
local startTime, duration, gcdCooldown, readyTime, paused = WeakAuras.GetSpellCooldown(effectiveSpellId)
local charges, maxCharges, spellCount, chargeGainTime, chargeLostTime = WeakAuras.GetSpellCharges(effectiveSpellId)
local stacks = maxCharges and maxCharges > 1 and charges
or spellCount and spellCount > 0 and spellCount
or nil
if (charges == nil) then
charges = (duration == 0 or gcdCooldown) and 1 or 0;
end
local ready = (startTime == 0 and not paused) or charges > 0
local active = IsUsableSpell(spellName or "") and ready
]=]
end
if(trigger.use_targetRequired) then
ret = ret.."active = active and WeakAuras.IsSpellInRange(spellName or '', 'target')\n";
end
if(trigger.use_inverse) then
ret = ret.."active = not active\n";
end
if (type(spellName) == "string") then
spellName = string.format("%q", spellName)
end
return ret:format(spellName)
end,
GetNameAndIcon = GetNameAndIconForSpellName,
args = {
{
name = "spellName",
display = L["Spell"],
required = true,
type = "spell",
test = "true",
showExactOption = true,
store = true
},
-- This parameter uses the IsSpellInRange API function, but it does not check spell range at all
-- IsSpellInRange returns nil for invalid targets, 0 for out of range, 1 for in range (0 and 1 are both "positive" values)
{
name = "targetRequired",
display = L["Require Valid Target"],
type = "toggle",
test = "true"
},
{
name = "ignoreSpellCooldown",
display = L["Ignore Spell Cooldown/Charges"],
type = "toggle",
test = "true"
},
{
name = "charges",
display = L["Charges"],
type = "number",
enable = function(trigger) return not trigger.use_inverse and not trigger.use_ignoreSpellCooldown end,
store = true,
conditionType = "number",
},
{
name = "spellCount",
display = L["Spell Count"],
type = "number",
enable = function(trigger) return not trigger.use_ignoreSpellCooldown end,
store = true,
conditionType = "number",
},
{
hidden = true,
name = "readyTime",
display = L["Since Ready"],
conditionType = "elapsedTimer",
store = true,
test = "true",
enable = function(trigger) return not trigger.use_ignoreSpellCooldown end,
},
{
hidden = true,
name = "chargeGainTime",
display = L["Since Charge Gain"],
conditionType = "elapsedTimer",
store = true,
test = "true",
enable = function(trigger) return not trigger.use_ignoreSpellCooldown end,
},
{
hidden = true,
name = "chargeLostTime",
display = L["Since Charge Lost"],
conditionType = "elapsedTimer",
store = true,
test = "true",
enable = function(trigger) return not trigger.use_ignoreSpellCooldown end,
},
{
name = "inverse",
display = L["Inverse"],
type = "toggle",
test = "true",
reloadOptions = true
},
{
name = "spellInRange",
display = L["Spell in Range"],
hidden = true,
test = "true",
conditionType = "bool",
conditionTest = function(state, needle)
return state and state.show and (UnitExists('target') and state.spellName and WeakAuras.IsSpellInRange(state.spellName, 'target') == needle)
end,
conditionEvents = AddTargetConditionEvents({
"WA_SPELL_RANGECHECK",
})
},
{
name = "name",
display = L["Name"],
hidden = true,
init = "name",
test = "true",
store = true,
conditionType = "string"
},
{
name = "icon",
hidden = true,
init = "icon",
test = "true",
store = true
},
{
name = "stacks",
display = L["Stacks"],
hidden = true,
init = "stacks",
test = "true",
store = true,
conditionType = "number",
enable = function(trigger) return not trigger.use_ignoreSpellCooldown end,
},
{
hidden = true,
test = "active"
}
},
hasSpellID = true,
automaticrequired = true,
progressType = "none"
},
["Talent Known"] = {
type = "unit",
events = {
["events"] = {"PLAYER_TALENT_UPDATE", "SPELL_UPDATE_USABLE"}
},
force_events = "PLAYER_TALENT_UPDATE",
name = L["Talent Known"],
init = function(trigger)
local inverse = trigger.use_inverse
local ret = {}
if (trigger.use_talent) then
-- Single selection
local index = trigger.talent and trigger.talent.single;
local tier = index and ceil(index / MAX_NUM_TALENTS)
local column = index and ((index - 1) % MAX_NUM_TALENTS + 1)
table.insert(ret, ([[
local tier = %s;
local column = %s;
local active = false
local name, icon, _, _, rank = GetTalentInfo(tier, column)
if rank and rank > 0 then
active = true;
activeName = name;
activeIcon = icon;
end
]]):format(tier or 0, column or 0))
if (inverse) then
table.insert(ret, [[
active = not (active);
]])
end
elseif (trigger.use_talent == false) then
if (trigger.talent.multi) then
table.insert(ret, [[
local active = true
local activeIcon, activeName, _
]])
table.insert(ret, [[
local tier
local column
]])
for index, value in pairs(trigger.talent.multi) do
local tier = index and ceil(index / MAX_NUM_TALENTS)
local column = index and ((index - 1) % MAX_NUM_TALENTS + 1)
table.insert(ret, ([[
if (not active) then
tier = %s
column = %s
local name, icon, _, _, rank = GetTalentInfo(tier, column)
if rank > 0 then
active = true;
activeName = name;
activeIcon = icon;
end
end
]]):format(tier, column))
end
if (inverse) then
table.insert(ret, [[
active = not (active);
]])
end
end
end
return table.concat(ret)
end,
args = {
{
name = "talent",
display = L["Talent"],
type = "multiselect",
values = function(trigger)
local class = select(2, UnitClass("player"));
if Private.talent_types_specific and Private.talent_types_specific[class] then
return Private.talent_types_specific[class];
end
end,
test = "active",
reloadOptions = true,
},
{
name = "inverse",
display = L["Inverse"],
type = "toggle",
test = "true",
},
{
hidden = true,
name = "icon",
init = "activeIcon",
store = "true",
test = "true"
},
{
hidden = true,
name = "name",
init = "activeName",
store = "true",
test = "true"
},
},
automaticrequired = true,
statesParameter = "one",
progressType = "none"
},
["Class/Spec"] = {
type = "unit",
events = {},
internal_events = {"UNIT_SPEC_CHANGED_player", "WA_DELAYED_PLAYER_ENTERING_WORLD"},
force_events = "UNIT_SPEC_CHANGED_player",
name = L["Class and Specialization"],
init = function(trigger)
local class = select(2, UnitClass("player")) or "UNKNOWN"
return ([[
local specName = Private.ExecEnv.GetUnitTalentSpec("player") or "Unknown"
local specId = Private.ExecEnv.GetSpecID("%s" .. specName)
local specIcon = Private.ExecEnv.GetSpecIcon(specId)
]]):format(class)
end,
args = {
{
name = "specId",
display = L["Class and Specialization"],
type = "multiselect",
values = "spec_types_all",
store = "true",
conditionType = "select",
},
{
hidden = true,
name = "icon",
init = "specIcon",
store = "true",
test = "true"
},
{
hidden = true,
name = "name",
init = "specName",
store = "true",
test = "true"
},
},
automaticrequired = true,
statesParameter = "one",
progressType = "none"
},
["Totem"] = {
type = "spell",
events = {
["events"] = {
"PLAYER_TOTEM_UPDATE",
"PLAYER_ENTERING_WORLD"
}
},
internal_events = {
"COOLDOWN_REMAINING_CHECK",
},
force_events = "PLAYER_ENTERING_WORLD",
name = L["Totem"],
statesParameter = "full",
progressType = "timed",
triggerFunction = function(trigger)
local ret = [[return
function (states)
local totemType = %s;
local triggerTotemName = %q
local triggerTotemPattern = %q
local triggerTotemPatternOperator = %q
local triggerTotemIcon = %s
local triggerTotemIconOperator = %q
local clone = %s
local inverse = %s
local remainingCheck = %s
local function checkActive(remaining)
return remaining %s remainingCheck;
end
if (totemType) then -- Check a specific totem slot
local _, totemName, startTime, duration, icon = GetTotemInfo(totemType);
active = (startTime and startTime ~= 0);
if not Private.ExecEnv.CheckTotemName(totemName, triggerTotemName, triggerTotemPattern, triggerTotemPatternOperator) then
active = false;
end
if not Private.ExecEnv.CheckTotemIcon(icon, triggerTotemIcon, triggerTotemIconOperator) then
active = false
end
if (inverse) then
active = not active;
if (triggerTotemName) then
icon = select(3, GetSpellInfo(triggerTotemName));
end
elseif (active and remainingCheck) then
local expirationTime = startTime and (startTime + duration) or 0;
local remainingTime = expirationTime - GetTime()
if (remainingTime >= remainingCheck) then
Private.ExecEnv.ScheduleScan(expirationTime - remainingCheck);
end
active = checkActive(remainingTime);
end
states[""] = states[""] or {}
local state = states[""];
state.show = active;
state.changed = true;
if (active) then
state.name = totemName;
state.totemName = totemName;
state.progressType = "timed";
state.duration = duration;
state.expirationTime = startTime and (startTime + duration);
state.icon = icon;
end
elseif inverse then -- inverse without a specific slot
local found = false;
for i = 1, 4 do
local _, totemName, startTime, duration, icon = GetTotemInfo(i);
if ((startTime and startTime ~= 0)
and Private.ExecEnv.CheckTotemName(totemName, triggerTotemName, triggerTotemPattern, triggerTotemPatternOperator)
and Private.ExecEnv.CheckTotemIcon(icon, triggerTotemIcon, triggerTotemIconOperator)
) then
found = true;
end
end
local cloneId = "";
states[cloneId] = states[cloneId] or {};
local state = states[cloneId];
state.show = not found;
state.changed = true;
state.name = triggerTotemName;
state.totemName = triggerTotemName;
if (triggerTotemName) then
state.icon = select(3, GetSpellInfo(triggerTotemName));
end
else -- check all slots
for i = 1, 4 do
local _, totemName, startTime, duration, icon = GetTotemInfo(i);
active = (startTime and startTime ~= 0);
if not Private.ExecEnv.CheckTotemName(totemName, triggerTotemName, triggerTotemPattern, triggerTotemPatternOperator)
or not Private.ExecEnv.CheckTotemIcon(icon, triggerTotemIcon, triggerTotemIconOperator)
then
active = false;
end
if (active and remainingCheck) then
local expirationTime = startTime and (startTime + duration) or 0;
local remainingTime = expirationTime - GetTime()
if (remainingTime >= remainingCheck) then
Private.ExecEnv.ScheduleScan(expirationTime - remainingCheck);
end
active = checkActive(remainingTime);
end
local cloneId = clone and tostring(i) or "";
states[cloneId] = states[cloneId] or {};
local state = states[cloneId];
state.show = active;
state.changed = true;
if (active) then
state.name = totemName;
state.totemName = totemName;
state.progressType = "timed";
state.duration = duration;
state.expirationTime = startTime and (startTime + duration);
state.icon = icon;
end
if (active and not clone) then
break;
end
end
end
return true;
end
]];
local totemName = tonumber(trigger.totemName) and GetSpellInfo(tonumber(trigger.totemName)) or trigger.totemName;
ret = ret:format(trigger.use_totemType and tonumber(trigger.totemType) or "nil",
trigger.use_totemName and totemName or "",
trigger.use_totemNamePattern and trigger.totemNamePattern or "",
trigger.use_totemNamePattern and trigger.totemNamePattern_operator or "",
trigger.use_icon and trigger.icon or "nil",
trigger.use_icon and trigger.icon_operator or "",
trigger.use_clones and "true" or "false",
trigger.use_inverse and "true" or "false",
trigger.use_remaining and tonumber(trigger.remaining or 0) or "nil",
trigger.use_remaining and trigger.remaining_operator or "<");
return ret;
end,
args = {
{
name = "totemType",
display = L["Totem Number"],
type = "select",
values = "totem_types"
},
{
name = "totemName",
display = L["Totem Name"],
type = "string",
conditionType = "string",
store = true,
desc = L["Enter a name or a spellId"]
},
{
name = "totemNamePattern",
display = L["Totem Name Pattern Match"],
type = "longstring",
},
{
name = "icon",
display = L["Totem Icon"],
type = "number",
conditionType = "number",
operator_types = "only_equal",
store = true,
},
{
name = "inverse",
display = L["Inverse"],
type = "toggle",
test = "true",
},
{
name = "clones",
display = L["Clone per Match"],
type = "toggle",
test = "true",
enable = function(trigger) return not (trigger.use_totemType or trigger.use_inverse) end,
},
{
name = "remaining",
display = L["Remaining Time"],
type = "number",
enable = function(trigger) return not(trigger.use_inverse) end
},
},
automaticrequired = true
},
["Item Count"] = {
type = "item",
events = {
["events"] = {
"BAG_UPDATE",
"BAG_UPDATE_COOLDOWN",
"PLAYER_ENTERING_WORLD"
}
},
internal_events = {
"ITEM_COUNT_UPDATE",
},
force_events = "BAG_UPDATE",
name = L["Item Count"],
loadFunc = function(trigger)
if(trigger.use_includeCharges) then
WeakAuras.RegisterItemCountWatch();
end
end,
init = function(trigger)
local itemName = type(trigger.itemName) == "number" and trigger.itemName or string.format("%q", trigger.itemName or "0")
local ret = [[
local itemName = %s
local exactSpellMatch = %s
if not exactSpellMatch and tonumber(itemName) then
itemName = GetItemInfo(itemName)
end
local count = GetItemCount(itemName or "", %s, %s);
]];
return ret:format(
itemName,
trigger.use_exact_itemName and "true" or "nil",
trigger.use_includeBank and "true" or "nil",
trigger.use_includeCharges and "true" or "nil"
)
end,
args = {
{
name = "itemName",
required = true,
display = L["Item"],
type = "item",
showExactOption = true,
test = "true"
},
--[[{ maybe some day
name = "itemId",
display = WeakAuras.newFeatureString .. L["ItemId"],
hidden = true,
init = "itemId",
test = "true",
store = true,
conditionType = "number",
operator_types = "only_equal",
},]]
{
name = "name",
display = L["Name"],
init = "itemName",
type = "string",
hidden = true,
store = true,
test = "true",
conditionType = "string"
},
{
name = "includeBank",
display = L["Include Bank"],
type = "toggle",
test = "true"
},
{
name = "includeCharges",
display = L["Include Charges"],
type = "toggle",
test = "true"
},
{
name = "count",
display = L["Item Count"],
type = "number"
},
{
name = "stacks",
display = L["Stacks"],
init = "count",
hidden = true,
store = true,
test = "true",
conditionType = "number"
},
{
name = "value",
init = "count",
hidden = true,
store = true,
test = "true",
display = L["Progress Value"],
conditionType = "number"
},
{
name = "total",
init = 0,
hidden = true,
store = true,
test = "true",
display = L["Progress Total"],
conditionType = "number"
},
{
name = "progressType",
init = "'static'",
hidden = true,
store = true,
test = "true",
},
{
name = "icon",
init = "GetItemIcon(itemName or '')",
hidden = true,
store = true,
test = "true"
},
{
name = "name",
init = "itemName and itemName ~= '' and GetItemInfo(itemName) or itemName",
hidden = true,
store = true,
test = "true"
},
},
statesParameter = "one",
hasItemID = true,
automaticrequired = true,
progressType = "static"
},
["Stance/Form/Aura"] = {
type = "unit",
events = function()
local events = {
"UPDATE_SHAPESHIFT_FORM",
"UPDATE_SHAPESHIFT_COOLDOWN"
}
if WeakAuras.IsClassicPlus() then -- Stances workaround for Epoch
tinsert(events, "ACTIONBAR_SLOT_CHANGED")
end
return { ["events"] = events }
end,
internal_events = { "WA_DELAYED_PLAYER_ENTERING_WORLD" },
force_events = "WA_DELAYED_PLAYER_ENTERING_WORLD",
name = L["Stance/Form/Aura"],
init = function(trigger)
local inverse = trigger.use_inverse;
local ret = {[[
local form = GetShapeshiftForm()
local active = false
]]}
if trigger.use_form and trigger.form and trigger.form.single then
-- Single selection
table.insert(ret, ([[
local trigger_form = %d
active = form == trigger_form
]]):format(trigger.form.single))
if inverse then
table.insert(ret, [[
active = not active
]])
end
elseif trigger.use_form == false and trigger.form and trigger.form.multi then
for index in pairs(trigger.form.multi) do
table.insert(ret, ([[
if not active then
local index = %d
active = form == index
end
]]):format(index))
end
if inverse then
table.insert(ret, [[
active = not active
]])
end
elseif trigger.use_form == nil then
table.insert(ret, [[
active = true
]])
end
return table.concat(ret)
end,
statesParameter = "one",
args = {
{
name = "note",
type = "description",
display = "",
text = function()
return L["Note: This trigger internally stores the shapeshift position, and thus is incompatible with learning stances on the fly, like e.g. the Gladiator Rune."]
end,
},
{
name = "form",
display = L["Form"],
type = "multiselect",
values = "form_types",
test = "active",
store = true,
conditionType = "select"
},
{
name = "inverse",
display = L["Inverse"],
type = "toggle",
test = "true",
enable = function(trigger) return type(trigger.use_form) == "boolean" end
},
},
nameFunc = function(trigger)
local _, class = UnitClass("player");
local name
if(class == trigger.class) then
local form = GetShapeshiftForm();
if form > 0 then
local _, name = GetShapeshiftFormInfo(form);
else
name = "Humanoid";
end
return name;
else
local types = WeakAuras[class:lower().."_form_types"];
if(types) then
return types[GetShapeshiftForm()];
end
end
end,
iconFunc = function(trigger)
local icon = "Interface\\Icons\\Spell_Nature_WispSplode"
local form = GetShapeshiftForm()
if form and form > 0 then
icon = GetShapeshiftFormInfo(form);
end
return icon or "Interface\\Icons\\Spell_Nature_WispSplode"
end,
automaticrequired = true,
progressType = "none"
},
["Weapon Enchant"] = {
type = "item",
events = {},
internal_events = {
"TENCH_UPDATE",
},
force_events = "TENCH_UPDATE",
name = L["Weapon Enchant / Fishing Lure"],
init = function(trigger)
WeakAuras.TenchInit();
local ret = [[
local triggerWeaponType = %q
local triggerName = %q
local triggerStack = %s
local triggerRemaining = %s
local triggerShowOn = %q
local expirationTime, duration, name, icon, stacks
if triggerWeaponType == "main" then
expirationTime, duration, name, shortenedName, icon, stacks = WeakAuras.GetMHTenchInfo()
elseif triggerWeaponType == "off" then
expirationTime, duration, name, shortenedName, icon, stacks = WeakAuras.GetOHTenchInfo()
elseif triggerWeaponType == "ranged" then
expirationTime, duration, name, shortenedName, icon, stacks = WeakAuras.GetRangeTenchInfo()
end
local remaining = expirationTime and expirationTime - GetTime()
local nameCheck = triggerName == "" or name and triggerName == name or shortenedName and triggerName == shortenedName
local stackCheck = not triggerStack or stacks and stacks %s triggerStack
local remainingCheck = not triggerRemaining or remaining and remaining %s triggerRemaining
local found = expirationTime and nameCheck and stackCheck and remainingCheck
if(triggerRemaining and remaining and remaining >= triggerRemaining and remaining > 0) then
Private.ExecEnv.ScheduleScan(expirationTime - triggerRemaining, "TENCH_UPDATE");
end
if not found then
expirationTime = nil
duration = nil
remaining = nil
end
]];
local showOnActive = trigger.showOn == 'showOnActive' or not trigger.showOn
return ret:format(trigger.weapon or "main",
trigger.use_enchant and trigger.enchant or "",
showOnActive and trigger.use_stacks and tonumber(trigger.stacks or 0) or "nil",
showOnActive and trigger.use_remaining and tonumber(trigger.remaining or 0) or "nil",
trigger.showOn or "showOnActive",
trigger.stacks_operator or "<",
trigger.remaining_operator or "<")
end,
args = {
{
name = "weapon",
display = L["Weapon"],
type = "select",
values = "weapon_types",
test = "true",
default = "main",
required = true
},
{
name = "enchant",
display = L["Weapon Enchant"],
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"],
type = "number",
conditionType = "number",
test = "true",
store = true
},
{
name = "duration",
hidden = true,
init = "duration",
test = "true",
store = true
},
{
name = "expirationTime",
init = "expirationTime",
hidden = true,
test = "true",
store = true
},
{
name = "progressType",
hidden = true,
init = "duration and 'timed'",
test = "true",
store = true
},
{
name = "name",
hidden = true,
init = "name",
test = "true",
store = true
},
{
name = "icon",
hidden = true,
init = "icon",
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"],
type = "number",
test = "true",
enable = function(trigger)
return not trigger.showOn or trigger.showOn == "showOnActive"
end
},
{
name = "showOn",
display = L["Show On"],
type = "select",
values = "weapon_enchant_types",
test = 'true',
default = "showOnActive",
required = true
},
{
hidden = true,
test = "(triggerShowOn == 'showOnActive' and found) " ..
"or (triggerShowOn == 'showOnMissing' and not found) " ..
"or (triggerShowOn == 'showAlways')"
}
},
automaticrequired = true,
progressType = "timed",
statesParameter = "one"
},
["Chat Message"] = {
type = "event",
events = function(trigger)
if trigger.use_messageType and trigger.messageType and Private.chat_message_types[trigger.messageType] then
local events = {trigger.messageType}
if Private.chat_message_leader_event[trigger.messageType] then
table.insert(events, Private.chat_message_leader_event[trigger.messageType])
end
if trigger.messageType == "CHAT_MSG_EMOTE" then
table.insert(events, "CHAT_MSG_TEXT_EMOTE")
end
return { events = events }
end
return {
["events"] = {
"CHAT_MSG_BATTLEGROUND",
"CHAT_MSG_BATTLEGROUND_LEADER",
"CHAT_MSG_BG_SYSTEM_ALLIANCE",
"CHAT_MSG_BG_SYSTEM_HORDE",
"CHAT_MSG_BG_SYSTEM_NEUTRAL",
"CHAT_MSG_BN_WHISPER",
"CHAT_MSG_CHANNEL",
"CHAT_MSG_EMOTE",
"CHAT_MSG_GUILD",
"CHAT_MSG_MONSTER_EMOTE",
"CHAT_MSG_MONSTER_PARTY",
"CHAT_MSG_MONSTER_SAY",
"CHAT_MSG_MONSTER_WHISPER",
"CHAT_MSG_MONSTER_YELL",
"CHAT_MSG_OFFICER",
"CHAT_MSG_PARTY",
"CHAT_MSG_PARTY_LEADER",
"CHAT_MSG_RAID",
"CHAT_MSG_RAID_LEADER",
"CHAT_MSG_RAID_BOSS_EMOTE",
"CHAT_MSG_RAID_BOSS_WHISPER",
"CHAT_MSG_RAID_WARNING",
"CHAT_MSG_SAY",
"CHAT_MSG_WHISPER",
"CHAT_MSG_YELL",
"CHAT_MSG_SYSTEM",
"CHAT_MSG_TEXT_EMOTE",
"CHAT_MSG_LOOT",
}
}
end,
name = L["Chat Message"],
init = function(trigger)
local ret = [[
if (event:find('LEADER')) then
event = event:sub(1, -8);
end
if (event == 'CHAT_MSG_TEXT_EMOTE') then
event = 'CHAT_MSG_EMOTE';
end
local use_cloneId = %s;
]];
return ret:format(trigger.use_cloneId and "true" or "false");
end,
statesParameter = "all",
args = {
{
name = "messageType",
display = L["Message Type"],
type = "select",
values = "chat_message_types",
sorted = true,
test = "event == %q",
},
{
name = "message",
display = L["Message"],
init = "arg",
type = "longstring",
canBeCaseInsensitive = true,
store = true,
conditionType = "string",
},
{
name = "sourceName",
display = L["Source Name"],
init = "arg",
type = "string",
store = true,
conditionType = "string",
},
{ -- language Name
},
{ -- Channel Name
},
{
name = "destName",
display = L["Destination Name"],
init = "arg",
type = "string",
store = true,
conditionType = "string",
},
{
-- flags
},
{
-- zone Channel id
},
{
-- channel index
},
{
-- channel base name
},
{
-- language id
},
{
-- line id
},
{
name = "sourceGUID",
display = L["Source GUID"],
init = "arg",
store = true,
hidden = true,
test = "true",
formatter = "guid",
formatterArgs = { color = "class" }
},
{
name = "cloneId",
display = L["Clone per Event"],
type = "toggle",
test = "true",
init = "use_cloneId and WeakAuras.GetUniqueCloneId() or ''",
reloadOptions = true
},
},
countEvents = true,
delayEvents = true,
timedrequired = true,
progressType = "timed"
},
["Spell Cast Succeeded"] = {
type = "event",
events = function(trigger)
local result = {}
local unit = trigger.unit
AddUnitEventForEvents(result, unit, "UNIT_SPELLCAST_SUCCEEDED")
return result
end,
name = L["Spell Cast Succeeded"],
statesParameter = "unit",
args = {
{
name = "unit",
init = "arg",
display = L["Caster Unit"],
type = "unit",
test = "true",
values = "actual_unit_types_cast",
store = true,
conditionType = "select",
conditionTest = function(state, needle, op)
return state and state.show and (UnitIsUnit(needle, state.unit or '') == (op == "=="))
end
},
{ -- castGUID
},
{
name = "spellNames",
init = "arg",
display = L["Name(s)"],
type = "spell",
multiEntry = {
operator = "preamble",
preambleAdd = "spellChecker:AddName(%q)"
},
preamble = "local spellChecker = Private.ExecEnv.CreateSpellChecker()",
preambleGroup = "spell",
test = "spellChecker:Check(spellNames)",
noValidation = true,
},
{
name = "spellId",
display = L["Exact Spell ID(s)"],
type = "spell",
init = "spellNames",
store = true,
multiEntry = {
operator = "preamble",
preambleAdd = "spellChecker:AddName(%q)"
},
preamble = "local spellChecker = Private.ExecEnv.CreateSpellChecker()",
preambleGroup = "spell",
test = "spellChecker:CheckName(spellNames)",
--conditionType = "number", -- Disabled because input would be string and would break imports to retail
noProgressSource = true
},
{
name = "icon",
hidden = true,
init = "(spellId and select(3, GetSpellInfo(spellId))) or 'Interface\\\\Icons\\\\INV_Misc_QuestionMark'",
store = true,
test = "true"
},
{
name = "name",
hidden = true,
init = "GetSpellInfo(spellId or 0)",
store = true,
test = "true"
},
},
countEvents = true,
delayEvents = true,
timedrequired = true,
progressType = "timed"
},
["Ready Check"] = {
type = "event",
events = {
["events"] = {"READY_CHECK"}
},
name = L["Ready Check"],
args = {},
statesParameter = "one",
delayEvents = true,
timedrequired = true,
progressType = "timed"
},
["Combat Events"] = {
type = "event",
events = {
["events"] = {
"PLAYER_REGEN_ENABLED",
"PLAYER_REGEN_DISABLED"
}
},
name = L["Entering/Leaving Combat"],
args = {
{
name = "eventtype",
required = true,
display = L["Type"],
type = "select",
values = "combat_event_type",
test = "event == %q"
}
},
statesParameter = "one",
countEvents = true,
delayEvents = true,
timedrequired = true,
progressType = "timed"
},
["Encounter Events"] = {
type = "event",
events = {
["events"] = {
"ENCOUNTER_START",
"ENCOUNTER_END"
}
},
name = WeakAuras.newFeatureString..L["Entering/Leaving Encounter"],
args = {
{
name = "note",
type = "description",
display = "",
text = constants.encounterDBMDesc
},
{
name = "eventtype",
required = true,
display = L["Type"],
type = "select",
values = "encounter_event_type",
test = "event == %q",
reloadOptions = true
},
{
name = "encounterId",
display = L["Id"],
type = "string",
desc = Private.get_encounters_list,
validate = WeakAuras.ValidateNumeric,
conditionType = "number",
store = true,
init = "arg"
},
{
name = "encounterName",
display = L["Name"],
type = "string",
conditionType = "string",
store = true,
init = "arg"
},
{
name = "difficulty",
display = L["Difficulty"],
type = "select",
values = "difficulty_types",
test = "%q == WeakAuras.InstanceDifficulty()",
conditionType = "select",
conditionTest = function(state, needle)
return WeakAuras.InstanceDifficulty() == needle
end,
store = true,
init = "arg"
},
{},
{
name = "success",
display = L["Success"],
type = "toggle",
conditionType = "bool",
enable = function(trigger)
return trigger.eventtype == "ENCOUNTER_END"
end,
store = true,
test = "success == 1",
conditionTest = function(state, needle)
return state and (state.success == needle)
end,
init = "arg"
}
},
statesParameter = "one",
countEvents = true,
delayEvents = true,
timedrequired = true,
progressType = "timed"
},
["Death Knight Rune"] = {
type = "unit",
events = {
["events"] = {
"RUNE_POWER_UPDATE",
"RUNE_TYPE_UPDATE"
}
},
internal_events = {
"RUNE_COOLDOWN_READY",
"RUNE_COOLDOWN_CHANGED",
"RUNE_COOLDOWN_STARTED",
"COOLDOWN_REMAINING_CHECK",
"WA_DELAYED_PLAYER_ENTERING_WORLD"
},
force_events = "RUNE_COOLDOWN_FORCE",
name = L["Death Knight Rune"],
loadFunc = function(trigger)
trigger.rune = trigger.rune or 0;
if (trigger.use_rune) then
WeakAuras.WatchRuneCooldown(trigger.rune);
else
for i = 1, 6 do
WeakAuras.WatchRuneCooldown(i);
end
end
end,
init = function(trigger)
trigger.rune = trigger.rune or 0;
WeakAuras.WatchRuneCooldown(trigger.rune);
local ret = [[
local rune = %s;
local genericShowOn = %s
local includeDeathRunes = %s;
local startTime, duration = WeakAuras.GetRuneCooldown(rune);
local numBloodRunes = 0;
local numUnholyRunes = 0;
local numFrostRunes = 0;
local numDeathRunes = 0;
local numRunes = 0;
local isDeathRune = GetRuneType(rune) == 4
for index = 1, 6 do
local startTime = GetRuneCooldown(index);
if startTime == 0 then
numRunes = numRunes + 1;
local runeType = GetRuneType(index)
if runeType == 1 then
numBloodRunes = numBloodRunes + 1;
elseif runeType == 2 then
numFrostRunes = numFrostRunes + 1;
elseif runeType == 3 then
numUnholyRunes = numUnholyRunes + 1;
elseif runeType == 4 then
numDeathRunes = numDeathRunes + 1;
end
end
end
if includeDeathRunes then
numBloodRunes = numBloodRunes + numDeathRunes;
numUnholyRunes = numUnholyRunes + numDeathRunes;
numFrostRunes = numFrostRunes + numDeathRunes;
end
]];
if trigger.use_remaining then
local ret2 = [[
local expirationTime = startTime + duration
local remaining = expirationTime - GetTime();
local remainingCheck = %s;
if(remaining >= remainingCheck and remaining > 0) then
Private.ExecEnv.ScheduleScan(expirationTime - remainingCheck);
end
]];
ret = ret..ret2:format(tonumber(trigger.remaining or 0) or 0);
end
return ret:format(
trigger.rune,
"[[" .. (trigger.genericShowOn or "") .. "]]",
(trigger.use_includeDeathRunes and "true" or "false")
);
end,
statesParameter = "one",
args = {
{
name = "rune",
display = L["Rune"],
type = "select",
values = "rune_specific_types",
test = "(genericShowOn == \"showOnReady\" and (startTime == 0)) " ..
"or (genericShowOn == \"showOnCooldown\" and startTime > 0) " ..
"or (genericShowOn == \"showAlways\")",
reloadOptions = true
},
{
name = "isDeathRune",
display = L["Is Death Rune"],
type = "tristate",
init = "isDeathRune",
store = true,
conditionType = "bool",
enable = function(trigger) return trigger.use_rune end,
},
{
name = "remaining",
display = L["Remaining Time"],
type = "number",
enable = function(trigger) return trigger.use_rune and not(trigger.genericShowOn == "showOnReady") end
},
{
name = "genericShowOn",
display = L["Show"],
type = "select",
values = "cooldown_progress_behavior_types",
test = "true",
enable = function(trigger) return trigger.use_rune end,
required = true
},
{
name = "runesCount",
display = L["Rune Count"],
type = "number",
init = "numRunes",
enable = function(trigger) return not trigger.use_rune end
},
{
hidden = true,
name = "onCooldown",
test = "true",
display = L["On Cooldown"],
conditionType = "bool",
conditionTest = function(state, needle)
return state and state.show and (state.expirationTime and state.expirationTime > GetTime()) == (needle == 1)
end,
enable = function(trigger) return trigger.use_rune end
},
{
name = "bloodRunes",
display = L["Rune Count - Blood"],
type = "number",
init = "numBloodRunes",
store = true,
conditionType = "number",
enable = function(trigger) return not trigger.use_rune end,
},
{
name = "frostRunes",
display = L["Rune Count - Frost"],
type = "number",
init = "numFrostRunes",
store = true,
conditionType = "number",
enable = function(trigger) return not trigger.use_rune end,
},
{
name = "unholyRunes",
display = L["Rune Count - Unholy"],
type = "number",
init = "numUnholyRunes",
store = true,
conditionType = "number",
enable = function(trigger) return not trigger.use_rune end,
},
{
name = "includeDeathRunes",
display = L["Include Death Runes"],
type = "toggle",
test = "true",
enable = function(trigger) return trigger.use_bloodRunes or trigger.use_unholyRunes or trigger.use_frostRunes end,
},
},
durationFunc = function(trigger)
if trigger.use_rune then
local startTime, duration = WeakAuras.GetRuneCooldown(trigger.rune)
return duration, startTime + duration
else
local numRunes = 0;
for index = 1, 6 do
if GetRuneCooldown(index) == 0 then
numRunes = numRunes + 1;
end
end
return numRunes, 6, true;
end
end,
stacksFunc = function(trigger)
local numRunes = 0;
for index = 1, 6 do
if GetRuneCooldown(index) == 0 then
numRunes = numRunes + 1;
end
end
return numRunes;
end,
nameFunc = function(trigger)
local runeNames = { L["Blood"], L["Frost"], L["Unholy"], L["Death"] }
return runeNames[GetRuneType(trigger.rune)];
end,
iconFunc = function(trigger)
if trigger.rune then
local runeIcons = {
"Interface\\PlayerFrame\\UI-PlayerFrame-Deathknight-Blood",
"Interface\\PlayerFrame\\UI-PlayerFrame-Deathknight-Frost",
"Interface\\PlayerFrame\\UI-PlayerFrame-Deathknight-Unholy",
"Interface\\PlayerFrame\\UI-PlayerFrame-Deathknight-Death"
};
return runeIcons[GetRuneType(trigger.rune)];
end
end,
automaticrequired = true,
progressType = function(trigger)
if trigger.use_rune then
return "timed"
else
return "static"
end
end
},
["Item Equipped"] = {
type = "item",
events = {
["events"] = {
"PLAYER_EQUIPMENT_CHANGED",
},
["unit_events"] = {
["player"] = {"UNIT_INVENTORY_CHANGED"}
}
},
internal_events = { "WA_DELAYED_PLAYER_ENTERING_WORLD", },
force_events = "UNIT_INVENTORY_CHANGED",
name = L["Item Equipped"],
init = function(trigger)
local itemName = type(trigger.itemName) == "number" and trigger.itemName or string.format("%q", trigger.itemName or "0")
local ret = [[
local inverse = %s
local triggerItemName = %s
local icon = GetItemIcon(triggerItemName) or ""
local itemSlot = %s
]]
ret = ret ..[[
local itemName = triggerItemName
local equipped = WeakAuras.CheckForItemEquipped(triggerItemName, itemSlot)
]]
return ret:format(trigger.use_inverse and "true" or "false", itemName, trigger.use_itemSlot and trigger.itemSlot or "nil");
end,
GetNameAndIcon = function(trigger)
local name = GetItemInfo(trigger.itemName or 0)
local icon = GetItemIcon(trigger.itemName or 0)
return name, icon
end,
statesParameter = "one",
args = {
{
name = "itemName",
display = L["Item"],
type = "item",
required = true,
test = "true",
only_exact = true
},
--[[{ maybe some day
name = "itemId",
display = WeakAuras.newFeatureString .. L["ItemId"],
hidden = true,
init = "itemId",
test = "true",
store = true,
conditionType = "number",
operator_types = "only_equal",
},]]
{
name = "itemSlot",
display = WeakAuras.newFeatureString .. L["Item Slot"],
type = "select",
values = "item_slot_types",
test = "true",
},
{
name = "inverse",
display = L["Inverse"],
type = "toggle",
test = "true"
},
{
name = "name",
display = L["Name"],
hidden = true,
init = "itemName",
test = "true",
store = true,
conditionType = "string"
},
{
name = "icon",
hidden = true,
init = "icon",
test = "true",
store = true
},
{
hidden = true,
test = "(inverse and not equipped) or (equipped and not inverse)"
}
},
hasItemID = true,
automaticrequired = true,
progressType = "none"
},
["Item Type Equipped"] = {
type = "item",
events = {
["events"] = {
"PLAYER_EQUIPMENT_CHANGED",
},
["unit_events"] = {
["player"] = {"UNIT_INVENTORY_CHANGED"}
}
},
internal_events = { "WA_DELAYED_PLAYER_ENTERING_WORLD", },
force_events = "UNIT_INVENTORY_CHANGED",
name = L["Item Type Equipped"],
args = {
{
name = "itemTypeName",
display = L["Item Type"],
type = "multiselect",
values = "item_weapon_types",
required = true,
test = "Private.ExecEnv.IsEquippedItemType(%s)",
multiNoSingle = true
},
},
automaticrequired = true,
progressType = "none"
},
["Equipment Set"] = {
type = "item",
events = {
["events"] = {
"PLAYER_EQUIPMENT_CHANGED",
"WEAR_EQUIPMENT_SET",
"EQUIPMENT_SETS_CHANGED",
"EQUIPMENT_SWAP_FINISHED",
}
},
internal_events = {"WA_DELAYED_PLAYER_ENTERING_WORLD"},
force_events = "PLAYER_EQUIPMENT_CHANGED",
name = L["Equipment Set Equipped"],
init = function(trigger)
trigger.itemSetName = trigger.itemSetName or "";
local itemSetName = type(trigger.itemSetName) == "string" and ("[=[" .. trigger.itemSetName .. "]=]") or "nil";
local ret = [[
local useItemSetName = %s;
local triggerItemSetName = %s;
local inverse = %s;
local partial = %s;
local itemSetName, icon, numEquipped, numItems = WeakAuras.GetEquipmentSetInfo(useItemSetName and triggerItemSetName or nil, partial);
]];
return ret:format(trigger.use_itemSetName and "true" or "false", itemSetName, trigger.use_inverse and "true" or "false", trigger.use_partial and "true" or "false");
end,
GetNameAndIcon = function(trigger)
local name, icon = WeakAuras.GetEquipmentSetInfo(trigger.use_itemSetName and trigger.itemSetName or nil, true)
return name, icon
end,
statesParameter = "one",
args = {
{
name = "itemSetName",
display = L["Equipment Set"],
type = "string",
test = "true",
store = true,
conditionType = "string",
init = "itemSetName"
},
{
name = "partial",
display = L["Allow partial matches"],
type = "toggle",
test = "true"
},
{
name = "inverse",
display = L["Inverse"],
type = "toggle",
test = "true"
},
{
name = "name",
display = L["Name"],
hidden = true,
init = "name",
test = "true",
store = true,
conditionType = "string"
},
{
name = "icon",
hidden = true,
init = "icon",
test = "true",
store = true
},
{
name = "value",
init = "numEquipped",
hidden = true,
store = true,
test = "true",
},
{
name = "total",
init = "numItems",
hidden = true,
store = true,
test = "true",
},
{
name = "progressType",
init = "'static'",
hidden = true,
store = true,
test = "true",
},
{
hidden = true,
test = "(inverse and itemSetName == nil) or (not inverse and itemSetName)"
}
},
hasItemID = true,
automaticrequired = true,
progressType = "static"
},
["Threat Situation"] = {
type = "unit",
events = function(trigger)
local unit = trigger.unit
local result = {}
if unit and unit ~= "none" then
AddUnitEventForEvents(result, unit, "UNIT_THREAT_LIST_UPDATE")
else
AddUnitEventForEvents(result, "player", "UNIT_THREAT_SITUATION_UPDATE")
end
return result
end,
internal_events = function(trigger)
local unit = trigger.unit
local result = {}
if unit and unit ~= "none" then
AddUnitChangeInternalEvents(unit, result)
end
return result
end,
loadFunc = function(trigger)
local unit = trigger.unit
if unit and unit ~= "none" then
AddWatchedUnits(unit)
end
end,
force_events = unitHelperFunctions.UnitChangedForceEvents,
name = L["Threat Situation"],
init = function(trigger)
trigger.unit = trigger.unit or "target";
local ret = [[
unit = string.lower(unit)
local name = UnitName(unit, false) or (unit == "none" and "Unknown")
local ok = true
local aggro, status, threatpct, rawthreatpct, threatvalue, threattotal
if unit and unit ~= "none" then
aggro, status, threatpct, rawthreatpct, threatvalue = WeakAuras.UnitDetailedThreatSituation('player', unit)
threattotal = (threatvalue or 0) * 100 / (threatpct ~= 0 and threatpct or 1)
else
status = UnitThreatSituation('player')
aggro = status == 2 or status == 3
threatpct, rawthreatpct, threatvalue, threattotal = 100, 100, 0, 100
end
]];
return ret .. unitHelperFunctions.SpecificUnitCheck(trigger);
end,
progressType = "static",
statesParameter = "unit",
args = {
{
name = "unit",
display = L["Unit"],
required = true,
type = "unit",
init = "arg",
values = "threat_unit_types",
test = "true",
store = true,
default = "target"
},
{
name = "status",
display = L["Status"],
type = "select",
values = "unit_threat_situation_types",
store = true,
conditionType = "select"
},
{
name = "aggro",
display = L["Aggro"],
type = "tristate",
store = true,
conditionType = "bool",
},
{
name = "threatpct",
display = L["Threat Percent"],
desc = L["Your threat on the mob as a percentage of the amount required to pull aggro. Will pull aggro at 100."],
type = "number",
store = true,
conditionType = "number",
enable = function(trigger) return trigger.unit ~= "none" end,
multiEntry = {
operator = "and",
limit = 2
},
formatter = "Number",
},
{
name = "rawthreatpct",
display = L["Raw Threat Percent"],
desc = L["Your threat as a percentage of the tank's current threat."],
type = "number",
store = true,
conditionType = "number",
enable = function(trigger) return trigger.unit ~= "none" end,
multiEntry = {
operator = "and",
limit = 2
},
formatter = "Number",
},
{
name = "threatvalue",
display = L["Threat Value"],
desc = L["Your total threat on the mob."],
type = "number",
store = true,
conditionType = "number",
enable = function(trigger) return trigger.unit ~= "none" end,
multiEntry = {
operator = "and",
limit = 2
},
},
{
type = "header",
name = "unitCharacteristicsHeader",
display = L["Unit Characteristics"],
},
{
name = "name",
display = L["Unit Name"],
type = "string",
store = true,
multiline = true,
preamble = "local nameChecker = Private.ExecEnv.ParseStringCheck(%q)",
test = "nameChecker:Check(name)",
conditionType = "string",
conditionPreamble = function(input)
return Private.ExecEnv.ParseStringCheck(input)
end,
conditionTest = function(state, needle, op, preamble)
return preamble:Check(state.name)
end,
operator_types = "none",
desc = L["Supports multiple entries, separated by commas. Prefix with '-' for negation."]
},
{
name = "npcId",
display = L["Npc ID"],
type = "string",
multiline = true,
store = true,
init = "tostring(tonumber(string.sub(UnitGUID(unit) or '', 8, 12), 16) or '')",
conditionType = "string",
preamble = "local npcIdChecker = Private.ExecEnv.ParseStringCheck(%q)",
test = "npcIdChecker:Check(npcId)",
conditionPreamble = function(input)
return Private.ExecEnv.ParseStringCheck(input)
end,
conditionTest = function(state, needle, op, preamble)
return preamble:Check(state.npcId)
end,
operator_types = "none",
desc = L["Supports multiple entries, separated by commas. Prefix with '-' for negation."]
},
{
name = "value",
hidden = true,
init = "threatvalue",
store = true,
test = "true"
},
{
name = "total",
hidden = true,
init = "threattotal",
store = true,
test = "true"
},
{
name = "progressType",
hidden = true,
init = "'static'",
store = true,
test = "true"
},
{
hidden = true,
test = "status ~= nil and ok"
},
{
hidden = true,
test = "((WeakAuras.UnitExistsFixed(unit, false) or unit == 'none') and specificUnitCheck)"
}
},
automaticrequired = true
},
["Crowd Controlled"] = {
type = "unit",
events = {
["unit_events"] = {
["player"] = {"UNIT_AURA"}
}
},
force_events = "UNIT_AURA",
name = L["Crowd Controlled"],
args = {
{
name = "controlled",
display = L["Crowd Controlled"],
type = "tristate",
init = "not HasFullControl()"
}
},
automaticrequired = true,
},
["Cast"] = {
type = "unit",
events = function(trigger)
local result = {}
local unit = trigger.unit
AddUnitEventForEvents(result, unit, "UNIT_SPELLCAST_START")
AddUnitEventForEvents(result, unit, "UNIT_SPELLCAST_DELAYED")
AddUnitEventForEvents(result, unit, "UNIT_SPELLCAST_STOP")
AddUnitEventForEvents(result, unit, "UNIT_SPELLCAST_CHANNEL_START")
AddUnitEventForEvents(result, unit, "UNIT_SPELLCAST_CHANNEL_UPDATE")
AddUnitEventForEvents(result, unit, "UNIT_SPELLCAST_CHANNEL_STOP")
AddUnitEventForEvents(result, unit, "UNIT_SPELLCAST_INTERRUPTIBLE")
AddUnitEventForEvents(result, unit, "UNIT_SPELLCAST_NOT_INTERRUPTIBLE")
AddUnitEventForEvents(result, unit, "UNIT_SPELLCAST_INTERRUPTED")
AddUnitEventForEvents(result, unit, "UNIT_NAME_UPDATE")
AddUnitEventForEvents(result, unit, "UNIT_TARGET")
return result
end,
internal_events = function(trigger)
local unit = trigger.unit
local result = {}
if unit == "nameplate" and trigger.use_onUpdateUnitTarget then
tinsert(result, "WA_UNIT_TARGET_NAME_PLATE")
end
AddRemainingCastInternalEvents(unit, result)
local includePets = trigger.use_includePets == true and trigger.includePets or nil
AddUnitChangeInternalEvents(unit, result, includePets)
if includePets ~= "PetsOnly" then
AddUnitRoleChangeInternalEvents(unit, result)
end
return result
end,
loadFunc = function(trigger)
if trigger.use_showLatency and trigger.unit == "player" then
WeakAuras.WatchForCastLatency()
end
if trigger.unit == "nameplate" and trigger.use_onUpdateUnitTarget then
WeakAuras.WatchForNameplateTargetChange()
end
local includePets = trigger.use_includePets == true and trigger.includePets or nil
AddWatchedUnits(trigger.unit, includePets)
end,
force_events = unitHelperFunctions.UnitChangedForceEventsWithPets,
progressType = "timed",
name = L["Cast"],
init = function(trigger)
trigger.unit = trigger.unit or "player";
local ret = [=[
unit = string.lower(unit)
local destUnit = unit .. '-target'
local sourceName, sourceRealm = WeakAuras.UnitNameWithRealm(unit)
local destName, destRealm = WeakAuras.UnitNameWithRealm(destUnit)
destName = destName or ""
destRealm = destRealm or ""
local smart = %s
local remainingCheck = %s
local inverseTrigger = %s
local show, expirationTime, castType, spell, icon, startTime, endTime, interruptible, remaining, _
spell, _, _, icon, startTime, endTime, _, _, interruptible = UnitCastingInfo(unit)
if spell then
castType = "cast"
else
spell, _, _, icon, startTime, endTime, _, interruptible = UnitChannelInfo(unit)
if spell then
castType = "channel"
end
end
interruptible = not interruptible
expirationTime = endTime and endTime > 0 and (endTime / 1000) or 0
remaining = expirationTime - GetTime()
if remainingCheck and remaining >= remainingCheck and remaining > 0 then
Private.ExecEnv.ScheduleCastCheck(expirationTime - remainingCheck, unit)
end
]=];
ret = ret:format(trigger.unit == "group" and "true" or "false",
trigger.use_remaining and tonumber(trigger.remaining or 0) or "nil",
trigger.use_inverse and "true" or "false");
ret = ret .. unitHelperFunctions.SpecificUnitCheck(trigger)
return ret
end,
statesParameter = "unit",
args = {
{
name = "unit",
required = true,
display = L["Unit"],
type = "unit",
init = "arg",
values = function(trigger)
if trigger.use_inverse then
return Private.actual_unit_types_with_specific
else
return Private.actual_unit_types_cast
end
end,
desc = Private.actual_unit_types_cast_tooltip,
test = "true",
store = true
},
{
name = "spellNames",
display = L["Name(s)"],
type = "spell",
enable = function(trigger) return not trigger.use_inverse end,
preambleGroup = "spell",
preamble = "local spellChecker = Private.ExecEnv.CreateSpellChecker()",
multiEntry = {
operator = "preamble",
preambleAdd = "spellChecker:AddName(%q)"
},
test = "spellChecker:CheckName(spell)",
noValidation = true,
},
{
name = "spellIds",
display = L["Exact Spell ID(s)"],
type = "spell",
enable = function(trigger) return not trigger.use_inverse end,
preambleGroup = "spell",
preamble = "local spellChecker = Private.ExecEnv.CreateSpellChecker()",
multiEntry = {
operator = "preamble",
preambleAdd = "spellChecker:AddName(GetSpellInfo(%q))"
},
test = "spellChecker:CheckName(spell)",
},
{
name = "spellId",
display = L["Spell ID"],
conditionType = "number",
store = true,
test = "true",
hidden = true,
noProgressSource = true
},
{
name = "spell",
display = L["Spellname"],
type = "string",
conditionType = "string",
store = true,
test = "true",
hidden = true
},
{
name = "castType",
display = L["Cast Type"],
type = "select",
values = "cast_types",
enable = function(trigger) return not trigger.use_inverse end,
store = true,
conditionType = "select"
},
{
name = "interruptible",
display = L["Interruptible"],
type = "tristate",
enable = function(trigger) return not trigger.use_inverse end,
store = true,
conditionType = "bool",
},
{
name = "remaining",
display = L["Remaining Time"],
type = "number",
enable = function(trigger) return not trigger.use_inverse end,
},
{
name = "name",
hidden = true,
init = "spell",
test = "true",
store = true
},
{
name = "icon",
hidden = true,
init = "icon",
test = "true",
store = true
},
{
name = "duration",
hidden = true,
init = "endTime and startTime and (endTime - startTime)/1000 or 0",
test = "true",
store = true
},
{
name = "expirationTime",
init = "expirationTime",
hidden = true,
test = "true",
store = true
},
{
name = "progressType",
hidden = true,
init = "'timed'",
test = "true",
store = true
},
{
name = "inverse",
hidden = true,
init = "castType == 'cast'",
test = "true",
store = true
},
{
name = "autoHide",
hidden = true,
init = "true",
test = "true",
store = true,
enable = function(trigger)
return not trigger.use_inverse
end
},
{
type = "header",
name = "unitCharacteristicsHeader",
display = L["Unit Characteristics"],
},
{
name = "npcId",
display = L["Npc ID"],
type = "string",
multiline = true,
store = true,
init = "tostring(tonumber(string.sub(UnitGUID(unit) or '', 8, 12), 16) or '')",
conditionType = "string",
preamble = "local npcIdChecker = Private.ExecEnv.ParseStringCheck(%q)",
test = "npcIdChecker:Check(npcId)",
conditionPreamble = function(input)
return Private.ExecEnv.ParseStringCheck(input)
end,
conditionTest = function(state, needle, op, preamble)
return preamble:Check(state.npcId)
end,
operator_types = "none",
desc = L["Supports multiple entries, separated by commas. Prefix with '-' for negation."],
enable = function(trigger)
return not trigger.use_inverse
end,
},
{
name = "class",
display = L["Class"],
type = "select",
init = "select(2, UnitClass(unit))",
values = "class_types",
store = true,
conditionType = "select",
enable = function(trigger)
return not trigger.use_inverse
end
},
{
name = "role",
display = L["Spec Role"],
type = "select",
init = "WeakAuras.LGT:GetUnitRole(unit)",
values = "role_types",
store = true,
conditionType = "select",
enable = function(trigger)
return trigger.unit == "group" or trigger.unit == "raid" or trigger.unit == "party"
or trigger.unit == "player" and not trigger.use_inverse
end
},
{
name = "raid_role",
display = L["Raid Role"],
type = "select",
init = "WeakAuras.UnitRaidRole(unit)",
values = "raid_role_types",
store = true,
conditionType = "select",
enable = function(trigger)
return trigger.unit == "group" or trigger.unit == "raid" or trigger.unit == "party" and not trigger.use_inverse
end
},
{
name = "raidMarkIndex",
display = L["Raid Mark"],
type = "multiselect",
values = "raid_mark_check_type",
store = true,
conditionType = "select",
init = "GetRaidTargetIndex(unit) or 0"
},
{
name = "raidMark",
display = L["Raid Mark Icon"],
store = true,
hidden = true,
test = "true",
init = "raidMarkIndex > 0 and '{rt'..raidMarkIndex..'}' or ''"
},
{
name = "nameplateType",
display = L["Hostility"],
type = "select",
init = "WeakAuras.GetPlayerReaction(unit)",
values = "hostility_types",
store = true,
conditionType = "select",
},
{
name = "sourceUnit",
init = "unit",
display = L["Caster"],
type = "unit",
values = "actual_unit_types_with_specific",
conditionType = "unit",
conditionTest = function(state, unit, op)
return state and state.show and state.unit and (UnitIsUnit(state.sourceUnit, unit) == (op == "=="))
end,
store = true,
hidden = true,
enable = function(trigger) return not trigger.use_inverse end,
test = "true"
},
{
name = "sourceName",
display = L["Caster Name"],
type = "string",
store = true,
hidden = true,
test = "true",
enable = function(trigger) return not trigger.use_inverse end,
},
{
name = "sourceRealm",
display = L["Caster Realm"],
type = "string",
store = true,
hidden = true,
test = "true",
enable = function(trigger) return not trigger.use_inverse end,
},
{
name = "sourceNameRealm",
display = L["Source Unit Name/Realm"],
type = "string",
multiline = true,
preamble = "local sourceNameRealmChecker = Private.ExecEnv.ParseNameCheck(%q)",
test = "sourceNameRealmChecker:Check(sourceName, sourceRealm)",
conditionType = "string",
conditionPreamble = function(input)
return Private.ExecEnv.ParseNameCheck(input)
end,
conditionTest = function(state, needle, op, preamble)
return preamble:Check(state.sourceName, state.sourceRealm)
end,
operator_types = "none",
enable = function(trigger) return not trigger.use_inverse end,
desc = constants.nameRealmFilterDesc,
},
{
name = "destUnit",
display = L["Caster's Target"],
type = "unit",
values = "actual_unit_types_with_specific",
conditionType = "unit",
conditionTest = function(state, unit, op)
return state and state.show and state.destUnit and (UnitIsUnit(state.destUnit, unit) == (op == "=="))
end,
store = true,
enable = function(trigger) return not trigger.use_inverse end,
test = "UnitIsUnit(destUnit, [[%s]])"
},
{
name = "destName",
display = L["Name of Caster's Target"],
type = "string",
store = true,
hidden = true,
test = "true",
enable = function(trigger) return not trigger.use_inverse end,
},
{
name = "destRealm",
display = L["Realm of Caster's Target"],
type = "string",
store = true,
hidden = true,
test = "true",
enable = function(trigger) return not trigger.use_inverse end,
},
{
name = "destNameRealm",
display = L["Name/Realm of Caster's Target"],
type = "string",
multiline = true,
preamble = "local destNameRealmChecker = Private.ExecEnv.ParseNameCheck(%q)",
test = "destNameRealmChecker:Check(destName, destRealm)",
conditionType = "string",
conditionPreamble = function(input)
return Private.ExecEnv.ParseNameCheck(input)
end,
conditionTest = function(state, needle, op, preamble)
return preamble:Check(state.destName, state.destRealm)
end,
operator_types = "none",
enable = function(trigger) return not trigger.use_inverse end,
desc = constants.nameRealmFilterDesc,
},
{
type = "header",
name = "miscellaneousHeader",
display = L["Miscellaneous"],
},
{
name = "showLatency",
display = L["Overlay Latency"],
type = "toggle",
test = "true",
enable = function(trigger)
return trigger.unit == "player" and not trigger.use_inverse
end,
reloadOptions = true
},
{
name = "includePets",
display = L["Include Pets"],
type = "select",
values = "include_pets_types",
width = WeakAuras.normalWidth,
test = "true",
enable = function(trigger)
return trigger.unit == "group" or trigger.unit == "raid" or trigger.unit == "party"
end
},
{
name = "ignoreSelf",
display = L["Ignore Self"],
type = "toggle",
width = WeakAuras.doubleWidth,
enable = function(trigger)
return trigger.unit == "nameplate" or trigger.unit == "group" or trigger.unit == "raid" or trigger.unit == "party"
end,
init = "not UnitIsUnit(\"player\", unit)"
},
{
name = "onUpdateUnitTarget",
display = WeakAuras.newFeatureString .. L["Advanced Caster's Target Check"],
desc = L["Check nameplate's target every 0.2s"],
type = "toggle",
test = "true",
enable = function(trigger)
return trigger.unit == "nameplate"
end
},
{
name = "inverse",
display = L["Inverse"],
type = "toggle",
test = "true",
reloadOptions = true
},
{
hidden = true,
test = "WeakAuras.UnitExistsFixed(unit, smart) and ((not inverseTrigger and spell) or (inverseTrigger and not spell)) and specificUnitCheck"
}
},
overlayFuncs = {
{
name = L["Latency"],
func = function(trigger, state)
local latency = WeakAuras.GetCastLatency()
if not latency then return 0, 0 end
return 0, latency
end,
enable = function(trigger)
return trigger.use_showLatency and trigger.unit == "player"
end
},
},
GetNameAndIcon = function(trigger)
local name, icon, spellId, _
if trigger.use_spellNames and type(trigger.spellNames) == "table" then
for _, spellName in ipairs(trigger.spellNames) do
spellId = WeakAuras.SafeToNumber(spellName)
if spellId then
name, _, icon = GetSpellInfo(spellName)
if name and icon then
return name, icon
end
elseif not tonumber(spellName) then
name, _, icon = GetSpellInfo(spellName)
if name and icon then
return name, icon
end
end
end
end
if trigger.use_spellIds and type(trigger.spellIds) == "table" then
for _, spellIdString in ipairs(trigger.spellIds) do
spellId = WeakAuras.SafeToNumber(spellIdString)
if spellId then
name, _, icon = GetSpellInfo(spellIdString)
if name and icon then
return name, icon
end
end
end
end
end,
automaticrequired = true,
},
["Character Stats"] = {
type = "unit",
name = L["Character Stats"],
events = {
["events"] = {
"COMBAT_RATING_UPDATE",
"PLAYER_TARGET_CHANGED"
},
["unit_events"] = {
["player"] = {"UNIT_STATS", "UNIT_ATTACK_POWER", "UNIT_AURA", "PLAYER_DAMAGE_DONE_MODS", "UNIT_RESISTANCES"}
}
},
internal_events = function(trigger, untrigger)
local events = { "WA_DELAYED_PLAYER_ENTERING_WORLD" }
if trigger.use_moveSpeed then
tinsert(events, "PLAYER_MOVE_SPEED_UPDATE")
end
return events
end,
loadFunc = function(trigger)
if trigger.use_moveSpeed then
WeakAuras.WatchForPlayerMoving()
end
end,
force_events = "CONDITIONS_CHECK",
statesParameter = "one",
args = {
{
type = "header",
name = "primaryStatsHeader",
display = L["Primary Stats"],
},
{
name = "strength",
display = L["Strength"],
type = "number",
init = "UnitStat('player', 1)",
store = true,
conditionType = "number",
multiEntry = {
operator = "and",
limit = 2
},
},
{
name = "agility",
display = L["Agility"],
type = "number",
init = "UnitStat('player', 2)",
store = true,
conditionType = "number",
multiEntry = {
operator = "and",
limit = 2
},
},
{
name = "stamina",
display = L["Stamina"],
type = "number",
init = "UnitStat('player', 3)",
store = true,
conditionType = "number",
multiEntry = {
operator = "and",
limit = 2
},
},
{
name = "intellect",
display = L["Intellect"],
type = "number",
init = "UnitStat('player', 4)",
store = true,
conditionType = "number",
multiEntry = {
operator = "and",
limit = 2
},
},
{
name = "spirit",
display = L["Spirit"],
type = "number",
init = "UnitStat('player', 5)",
store = true,
conditionType = "number",
multiEntry = {
operator = "and",
limit = 2
},
},
{
type = "header",
name = "secondaryStatsHeader",
display = L["Secondary Stats"],
},
{
name = "criticalrating",
display = L["Critical Rating"],
type = "number",
init = "max(GetCombatRating(CR_CRIT_MELEE), GetCombatRating(CR_CRIT_RANGED), GetCombatRating(CR_CRIT_SPELL))",
store = true,
conditionType = "number",
multiEntry = {
operator = "and",
limit = 2
},
},
{
name = "criticalpercent",
display = L["Critical (%)"],
type = "number",
init = "WeakAuras.GetCritChance()",
store = true,
conditionType = "number",
multiEntry = {
operator = "and",
limit = 2
},
formatter = "Number",
},
{
name = "hitrating",
display = L["Hit Rating"],
type = "number",
init = "max(GetCombatRating(CR_HIT_MELEE), GetCombatRating(CR_HIT_RANGED), GetCombatRating(CR_HIT_SPELL))",
store = true,
conditionType = "number",
multiEntry = {
operator = "and",
limit = 2
},
},
{
name = "hitpercent",
display = L["Hit (%)"],
type = "number",
init = "WeakAuras.GetHitChance()",
store = true,
conditionType = "number",
multiEntry = {
operator = "and",
limit = 2
},
formatter = "Number",
},
{
name = "hasterating",
display = L["Haste Rating"],
type = "number",
init = "max(GetCombatRating(CR_HASTE_SPELL), GetCombatRating(CR_HASTE_MELEE), GetCombatRating(CR_HASTE_RANGED))",
store = true,
conditionType = "number",
multiEntry = {
operator = "and",
limit = 2
},
},
{
name = "hastepercent",
display = L["Haste (%)"],
type = "number",
init = "max(GetCombatRatingBonus(CR_HASTE_SPELL), GetCombatRatingBonus(CR_HASTE_MELEE), GetCombatRatingBonus(CR_HASTE_RANGED))",
store = true,
conditionType = "number",
multiEntry = {
operator = "and",
limit = 2
},
formatter = "Number",
},
{
name = "expertiserating",
display = L["Expertise Rating"],
type = "number",
init = "GetCombatRating(CR_EXPERTISE)",
store = true,
conditionType = "number",
multiEntry = {
operator = "and",
limit = 2
},
},
{
name = "expertisebonus",
display = L["Expertise Bonus"],
type = "number",
init = "GetCombatRatingBonus(CR_EXPERTISE)",
store = true,
conditionType = "number",
multiEntry = {
operator = "and",
limit = 2
},
},
{
name = "armorpenrating",
display = L["Armor Peneration Rating"],
type = "number",
init = "GetCombatRating(CR_ARMOR_PENETRATION)",
store = true,
conditionType = "number",
multiEntry = {
operator = "and",
limit = 2
},
},
{
name = "armorpenpercent",
display = L["Armor Peneration (%)"],
type = "number",
init = "GetArmorPenetration()",
store = true,
conditionType = "number",
multiEntry = {
operator = "and",
limit = 2
},
formatter = "Number",
},
{
name = "spellpenpercent",
display = L["Spell Peneration (%)"],
type = "number",
init = "GetSpellPenetration()",
store = true,
conditionType = "number",
multiEntry = {
operator = "and",
limit = 2
},
formatter = "Number",
},
{
name = "resiliencerating",
display = L["Resilience Rating"],
type = "number",
init = "GetCombatRating(CR_CRIT_TAKEN_MELEE)",
store = true,
conditionType = "number",
multiEntry = {
operator = "and",
limit = 2
},
},
{
name = "resiliencepercent",
display = L["Resilience (%)"],
type = "number",
init = "GetCombatRatingBonus(CR_CRIT_TAKEN_MELEE)",
store = true,
conditionType = "number",
multiEntry = {
operator = "and",
limit = 2
},
formatter = "Number",
},
{
name = "attackpower",
display = L["Attack Power"],
type = "number",
init = "WeakAuras.GetEffectiveAttackPower()",
store = true,
conditionType = "number",
multiEntry = {
operator = "and",
limit = 2
},
},
{
name = "spellpower",
display = L["Spell Power"],
type = "number",
init = "WeakAuras.GetEffectiveSpellPower()",
store = true,
conditionType = "number",
multiEntry = {
operator = "and",
limit = 2
},
},
{
name = "rangedattackpower",
display = L["Ranged Attack Power"],
type = "number",
init = "WeakAuras.GetEffectiveRangedAttackPower()",
store = true,
conditionType = "number",
multiEntry = {
operator = "and",
limit = 2
},
},
{
type = "header",
name = "resistanceHeader",
display = L["Resistances"],
},
{
name = "resistancefire",
display = L["Fire Resistance"],
type = "number",
init = "select(2, UnitResistance('player', 2))",
store = true,
conditionType = "number",
multiEntry = {
operator = "and",
limit = 2
},
},
{
name = "resistancenature",
display = L["Nature Resistance"],
type = "number",
init = "select(2, UnitResistance('player', 3))",
store = true,
conditionType = "number",
multiEntry = {
operator = "and",
limit = 2
},
},
{
name = "resistancefrost",
display = L["Frost Resistance"],
type = "number",
init = "select(2, UnitResistance('player', 4))",
store = true,
conditionType = "number",
multiEntry = {
operator = "and",
limit = 2
},
},
{
name = "resistanceshadow",
display = L["Shadow Resistance"],
type = "number",
init = "select(2, UnitResistance('player', 5))",
store = true,
conditionType = "number",
multiEntry = {
operator = "and",
limit = 2
},
},
{
name = "resistancearcane",
display = L["Arcane Resistance"],
type = "number",
init = "select(2, UnitResistance('player', 6))",
store = true,
conditionType = "number",
multiEntry = {
operator = "and",
limit = 2
},
},
{
type = "header",
name = "tertiaryStatsHeader",
display = L["Tertiary Stats"],
},
{
name = "moveSpeed",
display = L["Continuously update Movement Speed"],
type = "boolean",
test = true,
width = WeakAuras.doubleWidth
},
{
name = "movespeedpercent",
display = L["Current Movement Speed (%)"],
type = "number",
init = "GetUnitSpeed('player') / 7 * 100",
store = true,
conditionType = "number",
multiEntry = {
operator = "and",
limit = 2
},
formatter = "Number",
},
{
type = "header",
name = "defensiveStatsHeader",
display = L["Defensive Stats"],
},
{
name = "defensevalue",
display = L["Defense Value"],
type = "number",
init = "UnitDefense('player')",
store = true,
conditionType = "number"
},
{
name = "defensepercent",
display = L["Defense (%)"],
type = "number",
init = "0.04 * ( UnitDefense('player') + select(2,UnitDefense('player') ) - UnitLevel('player')*5 )",
store = true,
conditionType = "number"
},
{
name = "dodgerating",
display = L["Dodge Rating"],
type = "number",
init = "GetCombatRating(CR_DODGE)",
store = true,
conditionType = "number",
multiEntry = {
operator = "and",
limit = 2
},
},
{
name = "dodgepercent",
display = L["Dodge (%)"],
type = "number",
init = "GetDodgeChance()",
store = true,
conditionType = "number",
multiEntry = {
operator = "and",
limit = 2
},
formatter = "Number",
},
{
name = "parryrating",
display = L["Parry Rating"],
type = "number",
init = "GetCombatRating(CR_PARRY)",
store = true,
conditionType = "number",
multiEntry = {
operator = "and",
limit = 2
},
},
{
name = "parrypercent",
display = L["Parry (%)"],
type = "number",
init = "GetParryChance()",
store = true,
conditionType = "number",
multiEntry = {
operator = "and",
limit = 2
},
formatter = "Number",
},
{
name = "blockpercent",
display = L["Block (%)"],
type = "number",
init = "GetBlockChance()",
store = true,
conditionType = "number",
multiEntry = {
operator = "and",
limit = 2
},
formatter = "Number",
},
{
name = "blockvalue",
display = L["Block Value"],
type = "number",
init = "GetShieldBlock()",
store = true,
conditionType = "number",
multiEntry = {
operator = "and",
limit = 2
},
},
{
name = "armorrating",
display = L["Armor Rating"],
type = "number",
init = "select(2, UnitArmor('player'))",
store = true,
conditionType = "number",
multiEntry = {
operator = "and",
limit = 2
},
},
{
name = "armorpercent",
display = L["Armor (%)"],
type = "number",
init = "PaperDollFrame_GetArmorReduction(select(2, UnitArmor('player')), UnitLevel('player'))",
store = true,
conditionType = "number",
multiEntry = {
operator = "and",
limit = 2
},
formatter = "Number",
},
{
name = "avoidancetotalpercent",
display = L["Total Avoidance (%)"],
type = "number",
init = "0.04 * ( UnitDefense('player') + select(2,UnitDefense('player') ) - UnitLevel('player')*5 ) + GetDodgeChance() + GetParryChance() + GetBlockChance()",
store = true,
conditionType = "number"
},
},
automaticrequired = true,
progressType = "none"
},
["Conditions"] = {
type = "unit",
events = function(trigger, untrigger)
local events = {}
if trigger.use_incombat ~= nil then
tinsert(events, "PLAYER_REGEN_ENABLED")
tinsert(events, "PLAYER_REGEN_DISABLED")
tinsert(events, "PLAYER_ENTERING_WORLD")
end
if trigger.use_pvpflagged ~= nil or trigger.use_afk ~= nil then
tinsert(events, "PLAYER_FLAGS_CHANGED")
end
if trigger.use_alive ~= nil then
tinsert(events, "PLAYER_DEAD")
tinsert(events, "PLAYER_ALIVE")
tinsert(events, "PLAYER_UNGHOST")
end
if trigger.use_resting ~= nil then
tinsert(events, "PLAYER_UPDATE_RESTING")
tinsert(events, "PLAYER_ENTERING_WORLD")
end
if trigger.use_mounted ~= nil then
tinsert(events, "MOUNTED_UPDATE")
tinsert(events, "PLAYER_ENTERING_WORLD")
end
local unit_events = {}
local pet_unit_events = {}
if trigger.use_vehicle ~= nil then
tinsert(unit_events, "UNIT_ENTERED_VEHICLE")
tinsert(unit_events, "UNIT_EXITED_VEHICLE")
tinsert(events, "PLAYER_ENTERING_WORLD")
end
if trigger.use_HasPet ~= nil then
tinsert(pet_unit_events, "UNIT_HEALTH")
end
if trigger.use_ingroup ~= nil then
tinsert(events, "PARTY_MEMBERS_CHANGED")
tinsert(events, "RAID_ROSTER_UPDATE")
end
if trigger.use_ruleset ~= nil then
tinsert(events, "ZONE_CHANGED_NEW_AREA")
tinsert(events, "PLAYER_FLAGS_CHANGED")
end
if trigger.use_instance_difficulty ~= nil
or trigger.use_instance_size ~= nil
then
tinsert(events, "PLAYER_DIFFICULTY_CHANGED")
end
return {
["events"] = events,
["unit_events"] = {
["player"] = unit_events,
["pet"] = pet_unit_events
}
}
end,
internal_events = function(trigger, untrigger)
local events = { "CONDITIONS_CHECK"};
if trigger.use_ismoving ~= nil then
tinsert(events, "PLAYER_MOVING_UPDATE");
end
if trigger.use_instance_difficulty ~= nil
or trigger.use_instance_size ~= nil
or trigger.use_pvpflagged ~= nil
then
tinsert(events, "WA_DELAYED_PLAYER_ENTERING_WORLD")
end
if (trigger.use_HasPet ~= nil) then
AddUnitChangeInternalEvents("pet", events);
end
return events;
end,
force_events = "CONDITIONS_CHECK",
name = L["Conditions"],
loadFunc = function(trigger)
if (trigger.use_ismoving ~= nil) then
WeakAuras.WatchForPlayerMoving();
end
if (trigger.use_HasPet ~= nil) then
AddWatchedUnits("pet")
end
end,
init = function(trigger)
return "";
end,
args = {
{
name = "alwaystrue",
display = L["Always active trigger"],
type = "tristate",
init = "true"
},
{
name = "incombat",
display = L["In Combat"],
type = "tristate",
init = "UnitAffectingCombat('player')"
},
{
name = "pvpflagged",
display = L["PvP Flagged"],
type = "tristate",
init = "UnitIsPVP('player')",
},
{
name = "alive",
display = L["Alive"],
type = "tristate",
init = "not UnitIsDeadOrGhost('player')"
},
{
name = "vehicle",
display = L["In Vehicle"],
type = "tristate",
init = "UnitInVehicle('player')",
},
{
name = "resting",
display = L["Resting"],
type = "tristate",
init = "IsResting()"
},
{
name = "mounted",
display = L["Mounted"],
type = "tristate",
init = "IsMounted()"
},
{
name = "HasPet",
display = L["HasPet"],
type = "tristate",
init = "UnitExists('pet') and not UnitIsDead('pet')"
},
{
name = "ismoving",
display = L["Is Moving"],
type = "tristate",
init = "GetUnitSpeed('player') > 0"
},
{
name = "afk",
display = L["Is Away from Keyboard"],
type = "tristate",
init = "UnitIsAFK('player')"
},
{
name = "ingroup",
display = L["Group Type"],
type = "multiselect",
values = "group_types",
init = "Private.ExecEnv.GroupType()",
events = {"PARTY_MEMBERS_CHANGED", "RAID_ROSTER_UPDATE"}
},
{
name = "ruleset",
display = "PvP Ruleset",
type = "multiselect",
values = "ruleset_types",
init = "WeakAuras.Ruleset()",
events = {"ZONE_CHANGED_NEW_AREA", "PLAYER_FLAGS_CHANGED"}
},
{
name = "instance_size",
display = L["Instance Type"],
desc = constants.instanceFilterDeprecated,
type = "multiselect",
values = "instance_types",
sorted = true,
init = "WeakAuras.InstanceType()",
events = {"ZONE_CHANGED", "ZONE_CHANGED_INDOORS", "ZONE_CHANGED_NEW_AREA"}
},
{
name = "instance_difficulty",
display = L["Instance Difficulty"],
desc = constants.instanceFilterDeprecated,
type = "multiselect",
values = "difficulty_types",
init = "WeakAuras.InstanceDifficulty()"
},
},
automaticrequired = true,
progressType = "none"
},
["Spell Known"] = {
type = "spell",
events = {
["events"] = {"SPELLS_CHANGED", "PLAYER_TALENT_UPDATE"},
["unit_events"] = {
["player"] = {"UNIT_PET"}
}
},
internal_events = {
"WA_DELAYED_PLAYER_ENTERING_WORLD"
},
force_events = "SPELLS_CHANGED",
name = L["Spell Known"],
statesParameter = "one",
init = function(trigger)
local spellName;
local ret = {};
spellName = type(trigger.spellName) == "number" and trigger.spellName or 0;
table.insert(ret, ([[
local spellName = %s;
local name, _, icon = GetSpellInfo(spellName)
]]):format(spellName))
local spellCheck = spellName ~= 0 and "true" or "false"
if (trigger.use_inverse) then
table.insert(ret, ([[
local usePet = %s;
local active = %s and IsSpellKnown(spellName, usePet) or false
]]):format(trigger.use_petspell and "true" or "false", spellCheck))
else
table.insert(ret, ([[
local usePet = %s;
local active = %s and IsSpellKnown(spellName, usePet)
]]):format(trigger.use_petspell and "true" or "false", spellCheck))
end
return table.concat(ret)
end,
GetNameAndIcon = function(trigger)
local name, _, icon = GetSpellInfo(trigger.spellName or 0)
return name, icon
end,
args = {
{
name = "spellName",
required = true,
display = L["Spell"],
type = "spell",
test = "true",
},
{
name = "petspell",
display = L["Pet Spell"],
type = "toggle",
test = "true"
},
{
name = "inverse",
display = WeakAuras.newFeatureString .. L["Inverse"],
type = "toggle",
test = "true",
},
{
name = "name",
display = L["Name"],
hidden = true,
init = "name",
test = "true",
store = true,
conditionType = "string"
},
{
name = "icon",
hidden = true,
init = "icon",
test = "true",
store = true
},
{
hidden = true,
test = "active"
}
},
automaticrequired = true,
progressType = "none"
},
["Pet Behavior"] = {
type = "unit",
events = function(trigger)
local result = {};
if (trigger.use_behavior) then
tinsert(result, "PET_BAR_UPDATE");
end
return {
["events"] = result,
["unit_events"] = {
["player"] = {"UNIT_PET"}
}
};
end,
internal_events = {
"WA_DELAYED_PLAYER_ENTERING_WORLD"
},
force_events = "WA_DELAYED_PLAYER_ENTERING_WORLD",
name = L["Pet"],
init = function(trigger)
local ret = "local activeIcon\n";
if (trigger.use_behavior) then
ret = [[
local inverse = %s
local check_behavior = %s
local name, i, token, active, behavior, _
for index = 1, NUM_PET_ACTION_SLOTS do
name, _, i, token, active = GetPetActionInfo(index)
if active then
activeIcon = not token and i or _G[i]
if name == "PET_MODE_AGGRESSIVE" then
behavior = "aggressive"
break
elseif name == "PET_MODE_DEFENSIVE" then
behavior = "defensive"
break
elseif name == "PET_MODE_PASSIVE" then
behavior = "passive"
break
end
end
end
]]
ret = ret:format(trigger.use_inverse and "true" or "false", trigger.use_behavior and ('"' .. (trigger.behavior or "") .. '"') or "nil");
end
return ret;
end,
statesParameter = "one",
args = {
{
name = "behavior",
display = L["Pet Behavior"],
type = "select",
values = "pet_behavior_types",
test = "UnitExists('pet') and (not check_behavior or (inverse and check_behavior ~= behavior) or (not inverse and check_behavior == behavior))",
},
{
name = "inverse",
display = L["Inverse Pet Behavior"],
type = "toggle",
test = "true",
enable = function(trigger) return trigger.use_behavior end
},
{
hidden = true,
name = "icon",
init = "activeIcon",
store = "true",
test = "true"
},
},
automaticrequired = true,
progressType = "none"
},
["Queued Action"] = {
type = "spell",
events = {
["events"] = {"ACTIONBAR_UPDATE_STATE"}
},
internal_events = {
"ACTIONBAR_SLOT_CHANGED",
"ACTIONBAR_PAGE_CHANGED"
},
name = L["Queued Action"],
init = function(trigger)
local spellName = type(trigger.spellName) ~= "table" and trigger.spellName or 0
if trigger.use_exact_spellName then
spellName = trigger.spellName
else
spellName = type(trigger.spellName) == "number" and GetSpellInfo(trigger.spellName) or trigger.spellName
end
local ret = [=[
local spellname = %q
]=]
return ret:format(spellName)
end,
args = {
{
name = "spellName",
required = true,
display = L["Spell"],
type = "spell",
test = "true",
showExactOption = true,
},
{
hidden = true,
test = "spellname and IsCurrentSpell(spellname)";
},
},
iconFunc = function(trigger)
local _, _, icon = GetSpellInfo(trigger.spellName or 0);
return icon;
end,
automaticrequired = true,
progressType = "none"
},
["Range Check"] = {
type = "unit",
events = {
["events"] = {"FRAME_UPDATE"}
},
name = L["Range Check"],
init = function(trigger)
trigger.unit = trigger.unit or "target";
local ret = [=[
local unit = %q;
local min, max = WeakAuras.GetRange(unit, true);
min = min or 0;
max = max or 999;
local triggerResult = true;
]=]
if (trigger.use_range) then
trigger.range = trigger.range or 8;
if (trigger.range_operator == "<=") then
ret = ret .. "triggerResult = max <= " .. tostring(trigger.range) .. "\n";
else
ret = ret .. "triggerResult = min >= " .. tostring(trigger.range).. "\n";
end
end
return ret:format(trigger.unit);
end,
statesParameter = "one",
args = {
{
name = "note",
type = "description",
display = "",
text = function() return L["Note: This trigger type estimates the range to the hitbox of a unit. The actual range of friendly players is usually 3 yards more than the estimate. Range checking capabilities depend on your current class and known abilities as well as the type of unit being checked. Some of the ranges may also not work with certain NPCs.|n|n|cFFAAFFAAFriendly Units:|r %s|n|cFFFFAAAAHarmful Units:|r %s|n|cFFAAAAFFMiscellanous Units:|r %s"]:format(RangeCacheStrings.friend or "", RangeCacheStrings.harm or "", RangeCacheStrings.misc or "") end
},
{
name = "unit",
required = true,
display = L["Unit"],
type = "unit",
init = "unit",
values = "unit_types_range_check",
test = "true",
store = true
},
{
hidden = true,
name = "minRange",
display = L["Minimum Estimate"],
type = "number",
init = "min",
store = true,
test = "true",
conditionType = "number",
operator_types = "without_equal",
},
{
hidden = true,
name = "maxRange",
display = L["Maximum Estimate"],
type = "number",
init = "max",
store = true,
test = "true",
conditionType = "number",
operator_types = "without_equal",
},
{
name = "range",
display = L["Distance"],
type = "number",
operator_types = "without_equal",
test = "triggerResult",
conditionType = "number",
conditionTest = function(state, needle, needle2)
return state and state.show and WeakAuras.CheckRange(state.unit, needle, needle2);
end,
noProgressSource = true
},
{
hidden = true,
test = "UnitExists(unit)"
}
},
automaticrequired = true,
progressType = "none"
},
["Money"] = {
type = "unit",
statesParameter = "one",
progressType = "none",
automaticrequired = true,
events = {
["events"] = {"PLAYER_MONEY"}
},
internal_events = {"WA_DELAYED_PLAYER_ENTERING_WORLD"},
force_events = "WA_DELAYED_PLAYER_ENTERING_WORLD",
name = WeakAuras.newFeatureString..L["Player Money"],
init = function()
return [=[
local money = GetMoney()
local gold = floor(money / 1e4)
local silver = floor(money / 100 % 100)
local copper = money % 100
]=]
end,
args = {
{
name = "money",
init = "money",
type = "number",
display = L["Money"],
store = true,
hidden = true,
test = "true",
},
{
name = "gold",
init = "gold",
type = "number",
display = Private.coin_icons.gold .. L["Gold"],
store = true,
conditionType = "number",
formatter = "BigNumber"
},
{
name = "silver",
init = "silver",
type = "number",
display = Private.coin_icons.silver .. L["Silver"],
store = true,
hidden = true,
test = "true",
},
{
name = "copper",
init = "copper",
type = "number",
display = Private.coin_icons.copper .. L["Copper"],
store = true,
hidden = true,
test = "true",
},
{
name = "icon",
init = "GetCoinIcon(money)",
store = true,
hidden = true,
test = "true",
},
},
GetNameAndIcon = function()
return MONEY, GetCoinIcon(GetMoney())
end,
},
["Currency"] = {
type = "unit",
progressType = "static",
events = {
["events"] = {
"CURRENCY_DISPLAY_UPDATE",
}
},
force_events = "CURRENCY_DISPLAY_UPDATE",
name = WeakAuras.newFeatureString..L["Currency"],
init = function(trigger)
if type(trigger.value) ~= "string" then trigger.value = "" end
if type(trigger.value_operator) ~= "string" then trigger.value_operator = "" end
local ret = [=[
local currencyID = %d
local quantity, totalEarned, icon
if currencyID == 43308 then
quantity, totalEarned = GetHonorCurrency()
icon = UnitFactionGroup("player") == "Alliance" and
"Interface/Icons/inv_misc_tournaments_symbol_human" or
"Interface/Icons/Achievement_PVP_H_16"
elseif currencyID == 43307 then
quantity, totalEarned = GetArenaCurrency()
icon = "Interface/PVPFrame/PVP-ArenaPoints-Icon"
end
local name = GetItemInfo(currencyID)
local currencyInfo = {
name = name or "Unknown Currency",
quantity = quantity or GetItemCount(currencyID) or 0,
icon = icon or GetItemIcon(currencyID) or "Interface/Icons/INV_Misc_QuestionMark",
totalEarned = totalEarned or Private.ExecEnv.GetTotalCountCurrencies(currencyID) or 0,
discovered = ((Private.ExecEnv.GetDiscoveredCurrencies() or {})[currencyID]) and true or false
}
]=]
return ret:format(tonumber(trigger.currencyId) or 0)
end,
statesParameter = "one",
args = {
{
name = "currencyId",
type = "currency",
itemControl = "Dropdown-Currency",
values = Private.ExecEnv.GetDiscoveredCurrencies,
headers = Private.GetDiscoveredCurrenciesHeaders,
sorted = true,
sortOrder = function()
local discovered_currencies_sorted = Private.GetDiscoveredCurrenciesSorted()
local sortOrder = {}
for key, value in pairs(Private.ExecEnv.GetDiscoveredCurrencies()) do
tinsert(sortOrder, key)
end
table.sort(sortOrder, function(aKey, bKey)
local aValue = discovered_currencies_sorted[aKey]
local bValue = discovered_currencies_sorted[bKey]
return aValue < bValue
end)
return sortOrder
end,
required = true,
display = L["Currency"],
store = true,
test = "true",
},
{
name = "name",
init = "currencyInfo.name",
hidden = true,
store = true,
test = "true",
},
{
name = "value",
init = "currencyInfo.quantity",
type = "number",
display = L["Quantity"],
store = true,
conditionType = "number",
},
{
name = "totalEarned",
init = "currencyInfo.totalEarned",
type = "number",
display = L["Total"],
store = true,
conditionType = "number",
},
{
name = "progressType",
init = "'static'",
hidden = true,
store = true,
test = "true",
},
{
name = "icon",
init = "currencyInfo.icon",
store = true,
hidden = true,
test = "true",
},
{
name = "description",
init = "currencyInfo.description",
type = "string",
display = L["Description"],
store = true,
hidden = true,
test = "true",
},
{
name = "discovered",
init = "currencyInfo.discovered",
type = "tristate",
display = L["Discovered"],
store = true,
conditionType = "bool",
},
},
GetNameAndIcon = function(trigger)
local id = trigger.currencyId or 0
local name = GetItemInfo(id)
local icon = GetItemIcon(id)
if id == 43308 then
icon = UnitFactionGroup("player") == "Alliance" and
"Interface/Icons/inv_misc_tournaments_symbol_human" or
"Interface/Icons/Achievement_PVP_H_16"
elseif id == 43307 then
icon = "Interface/PVPFrame/PVP-ArenaPoints-Icon"
end
return name, icon
end,
automaticrequired = true
},
["Location"] = {
type = "unit",
events = {
["events"] = {
"ZONE_CHANGED",
"ZONE_CHANGED_INDOORS",
"ZONE_CHANGED_NEW_AREA",
"PLAYER_DIFFICULTY_CHANGED",
"WA_DELAYED_PLAYER_ENTERING_WORLD"
}
},
internal_events = {"INSTANCE_LOCATION_CHECK"},
force_events = "INSTANCE_LOCATION_CHECK",
name = WeakAuras.newFeatureString..L["Location"],
init = function(trigger)
local ret = [=[
local uiMapId = GetCurrentMapAreaID()
local instanceName, instanceType, difficultyID = GetInstanceInfo()
local minimapZoneText = GetMinimapZoneText()
local zoneText = GetZoneText()
]=]
return ret
end,
statesParameter = "one",
args = {
{
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. Prefix with '-' for negation."])
end,
type = "string",
multiline = true,
preamble = "local zoneChecker = Private.ExecEnv.ParseZoneCheck(%q)",
test = "zoneChecker:Check(MapId)",
conditionType = "string",
conditionPreamble = function(input)
return Private.ExecEnv.ParseZoneCheck(input)
end,
conditionTest = function(state, needle, op, preamble)
return preamble:Check(state.zoneId)
end,
operator_types = "none",
},
{
name = "zoneId",
display = L["Zone ID"],
init = "uiMapId",
store = true,
hidden = true,
test = "true",
},
{
name = "zone",
display = L["Zone Name"],
desc = function()
return ("|cffffd200%s|r%s"):format(L["Current Zone\n"], GetRealZoneText())
end,
type = "string",
conditionType = "string",
store = true,
init = "zoneText",
multiEntry = {
operator = "or",
}
},
{
name = "subzone",
display = L["Subzone Name"],
desc = function()
return ("%s\n\n|cffffd200%s|r%s"):format(L["Name of the (sub-)zone currently shown above the minimap."], L["Current Zone\n"], GetMinimapZoneText())
end,
type = "string",
conditionType = "string",
store = true,
init = "minimapZoneText",
multiEntry = {
operator = "or",
},
},
{
type = "header",
name = "instanceHeader",
display = L["Instance Info"],
},
{
name = "instance",
display = L["Instance Name"],
test = "true",
hidden = "true",
store = true,
},
{
name = "instanceSize",
display = L["Instance Size Type"],
type = "multiselect",
values = "instance_types",
sorted = true,
init = "WeakAuras.InstanceType()",
conditionType = "select",
store = true,
},
{
name = "instanceDifficulty",
display = L["Instance Difficulty"],
type = "multiselect",
values = "difficulty_types",
init = "WeakAuras.InstanceDifficulty()",
conditionType = "select",
store = true,
},
},
automaticrequired = true,
progressType = "none"
},
};
--[[
Disable any event here
if () then
Private.event_prototypes[] = nil
end
]]
Private.category_event_prototype = {}
for name, prototype in pairs(Private.event_prototypes) do
Private.category_event_prototype[prototype.type] = Private.category_event_prototype[prototype.type] or {}
Private.category_event_prototype[prototype.type][name] = prototype.name
end
Private.dynamic_texts = {
["p"] = {
get = function(state)
if not state then return nil end
if state.progressType == "static" then
return state.value or nil
end
if state.progressType == "timed" then
if state.paused then
return state.remaining and state.remaining >= 0 and state.remaining or nil
end
if not state.expirationTime or not state.duration then
return nil
end
local remaining = state.expirationTime - GetTime();
return remaining >= 0 and remaining or nil
end
end,
func = function(remaining, state, progressPrecision)
progressPrecision = progressPrecision or 1
if not state or state.progressType ~= "timed" then
return remaining
end
if type(remaining) ~= "number" then
return ""
end
local remainingStr = "";
if remaining == math.huge then
remainingStr = " ";
elseif remaining > 60 then
remainingStr = string.format("%i:", math.floor(remaining / 60));
remaining = remaining % 60;
remainingStr = remainingStr..string.format("%02i", remaining);
elseif remaining > 0 then
if progressPrecision == 4 and remaining <= 3 then
remainingStr = remainingStr..string.format("%.1f", remaining);
elseif progressPrecision == 5 and remaining <= 3 then
remainingStr = remainingStr..string.format("%.2f", remaining);
elseif progressPrecision == 6 and remaining <= 3 then
remainingStr = remainingStr..string.format("%.3f", remaining);
elseif (progressPrecision == 4 or progressPrecision == 5 or progressPrecision == 6) and remaining > 3 then
remainingStr = remainingStr..string.format("%d", remaining);
else
remainingStr = remainingStr..string.format("%.".. progressPrecision .."f", remaining);
end
else
remainingStr = " ";
end
return remainingStr
end
},
["t"] = {
get = function(state)
if not state then return "" end
if state.progressType == "static" then
return state.total, false
end
if state.progressType == "timed" then
if not state.duration then
return nil
end
return state.duration, true
end
end,
func = function(duration, state, totalPrecision)
if not state or state.progressType ~= "timed" then
return duration
end
if type(duration) ~= "number" then
return ""
end
local durationStr = "";
if math.abs(duration) == math.huge or tostring(duration) == "nan" then
durationStr = " ";
elseif duration > 60 then
durationStr = string.format("%i:", math.floor(duration / 60));
duration = duration % 60;
durationStr = durationStr..string.format("%02i", duration);
elseif duration > 0 then
if totalPrecision == 4 and duration <= 3 then
durationStr = durationStr..string.format("%.1f", duration);
elseif totalPrecision == 5 and duration <= 3 then
durationStr = durationStr..string.format("%.2f", duration);
elseif totalPrecision == 6 and duration <= 3 then
durationStr = durationStr..string.format("%.3f", duration);
elseif (totalPrecision == 4 or totalPrecision == 5 or totalPrecision == 6) and duration > 3 then
durationStr = durationStr..string.format("%d", duration);
else
durationStr = durationStr..string.format("%."..totalPrecision.."f", duration);
end
else
durationStr = " ";
end
return durationStr
end
},
["n"] = {
get = function(state)
if not state then return "" end
return state.name or state.id or "", true
end,
func = function(v)
return v
end
},
["i"] = {
get = function(state)
if not state then return "" end
return state.icon or "Interface\\Icons\\INV_Misc_QuestionMark"
end,
func = function(v)
return "|T".. v ..":12:12:0:0:64:64:4:60:4:60|t"
end
},
["s"] = {
get = function(state)
if not state or state.stacks == 0 then return "" end
return state.stacks
end,
func = function(v)
return v
end
}
};
-- Events in that list can be filtered by unitID
Private.UnitEventList = {
PLAYER_GUILD_UPDATE = true,
MINIMAP_PING = true,
PARTY_MEMBER_DISABLE = true,
PARTY_MEMBER_ENABLE = true,
READY_CHECK_CONFIRM = true,
PLAYER_GAINS_VEHICLE_DATA = true,
PLAYER_LOSES_VEHICLE_DATA = true,
KNOWN_TITLES_UPDATE = true,
PLAYER_DAMAGE_DONE_MODS = true,
PLAYER_FLAGS_CHANGED = true,
PLAYER_PVP_KILLS_CHANGED = true,
PLAYER_PVP_RANK_CHANGED = true,
PLAYER_XP_UPDATE = true,
}
Private.InternalEventByIDList = {
ITEM_COOLDOWN_STARTED = true,
ITEM_COOLDOWN_CHANGED = true,
ITEM_COOLDOWN_READY = true,
ITEM_SLOT_COOLDOWN_STARTED = true,
ITEM_SLOT_COOLDOWN_CHANGED = true,
ITEM_SLOT_COOLDOWN_READY = true,
ITEM_SLOT_COOLDOWN_ITEM_CHANGED = true,
SPELL_COOLDOWN_CHANGED = true,
SPELL_COOLDOWN_READY = true,
SPELL_CHARGES_CHANGED = true,
WA_UPDATE_OVERLAY_GLOW = true,
}