- Custom Values
- Displays
- Distance
- Timers
- Aura
- COMBAT_LOG Functions
- Spell Info
- Talents/Specializations
- Miscellaneous
- Grid
-- SetValue('MyNewValue', ...)
-- SetValue(1234, 'firstKey', 'secondKey')
-- SetValue({5,6,7}, 'firstKey', 'secondKey', 'thirdKey')
-- @value any - Any value to assign to the CustomValues table at the level indicated by the child keys
-- @... list - Any number of listed table ordered sub-child table keys of which to set the value
local SetValue = function(value, ...)
if not WeakAuras.CustomValues then WeakAuras.CustomValues = {} end
if not ... then return end
local count, data = #{...}
for i,v in pairs({...}) do
if i==1 then if count and count == 1 then WeakAuras.CustomValues[v] = value else
WeakAuras.CustomValues[v] = WeakAuras.CustomValues[v] or {}
data = WeakAuras.CustomValues[v] end
else if i ~= count then if not data[v] then data[v] = {} end data = data[v] else data[v] = value end end
end
end
-- ... = GetValue(...)
-- ... = GetValue('firstKey', 'secondKey')
-- @... list - Any number of listed table ordered sub-child table keys of which to retrieve the value
-- return any - Any returned value matching the CustomValues table and sub-children keys
local GetValue = function(...)
if not WeakAuras.CustomValues then WeakAuras.CustomValues = {} end
if not ... then return end
local count, data = #{...}
if count and (count > 1) then
for i,v in pairs({...}) do
if i==1 then WeakAuras.CustomValues[v] = WeakAuras.CustomValues[v] or {} data = WeakAuras.CustomValues[v]
else if i ~= count then if not data[v] then data[v] = {} else data = data[v] end else data = data[v] end end
end
else data = WeakAuras.CustomValues[select(1, ...)] end
return data
end
-- GetRegion('my-arrow') - Retrieve the Region WeakAura table.
-- @name string - name of the WeakAura Display to retrieve Region.
-- return table - WeakAura Display Region
local GetRegion = function(name)
local DisplayType = function(name)
if WeakAuras then
if WeakAuras.auras and WeakAuras.auras[name] then return 'auras' end
if WeakAuras.regions and WeakAuras.regions[name] then return 'regions' end
end
end
local displayType = DisplayType(name)
if not displayType then return end
if displayType == 'auras' then
if WeakAuras
and WeakAuras[displayType]
and WeakAuras[displayType][name]
and WeakAuras[displayType][name][0]
and WeakAuras[displayType][name][0]['region'] then
return WeakAuras[displayType][name][0]['region']
end
elseif displayType == 'regions' then
if WeakAuras
and WeakAuras[displayType]
and WeakAuras[displayType][name]
and WeakAuras[displayType][name]
and WeakAuras[displayType][name]['region'] then
return WeakAuras[displayType][name]['region']
end
end
end
-- RotateDisplayByDegrees('my-arrow', 90) - Rotate the Display named 'my-arrow' 90 degrees
-- RotateDisplayByDegrees('my-arrow', 180) - Rotate the 'my-arrow' 180 degrees (flip it)
-- RotateDisplayByDegrees('my-arrow', 400) - Rotate the 'my-arrow' 400 degrees (equivalent to 40 degrees)
-- @display string - Name of the WeakAura Display to be modified.
-- @degrees number - Degrees to rotate
local RotateDisplayByDegrees = function(name, degrees)
local GetRegion = function(name)
local DisplayType = function(name)
if WeakAuras then
if WeakAuras.auras and WeakAuras.auras[name] then return 'auras' end
if WeakAuras.regions and WeakAuras.regions[name] then return 'regions' end
end
end
local displayType = DisplayType(name)
if not displayType then return end
if displayType == 'auras' then
if WeakAuras
and WeakAuras[displayType]
and WeakAuras[displayType][name]
and WeakAuras[displayType][name][0]
and WeakAuras[displayType][name][0]['region'] then
return WeakAuras[displayType][name][0]['region']
end
elseif displayType == 'regions' then
if WeakAuras
and WeakAuras[displayType]
and WeakAuras[displayType][name]
and WeakAuras[displayType][name]
and WeakAuras[displayType][name]['region'] then
return WeakAuras[displayType][name]['region']
end
end
end
local region = GetRegion(name)
if not region
or not region['Rotate']
or not (type(region['Rotate']) == 'function') then return end
region['Rotate'](0, degrees and degrees or 0)
end
-- RotateDisplayToPoint('my-arrow', 500, 1250) - Rotate the Display named 'my-arrow' to face towards the point 500, 1250
-- RotateDisplayToPoint('my-arrow', UnitPosition('party1')) - Rotate the 'my-arrow' to face towards the position of the 'party1' unit
-- RotateDisplayToPoint('my-arrow', UnitPosition('raid15')) - Rotate the 'my-arrow' to face towards the position of the 'raid15' unit
-- RotateDisplayToPoint('my-arrow', 500, 1250, 180) - Rotate the 'my-arrow' to face towards the point 500, 1250 with a rotational offset of 180 degrees
-- @name string - Name of the WeakAura Display to be modified.
-- @pointX number - X coordinate of target point
-- @pointY number - Y coordinate of target point
-- [@offset] number - (Optional) Rotational degrees offset (Default: 0)
local RotateDisplayToPoint = function(name, pointX, pointY, offset)
local GetRegion = function(name)
local DisplayType = function(name)
if WeakAuras then
if WeakAuras.auras and WeakAuras.auras[name] then return 'auras' end
if WeakAuras.regions and WeakAuras.regions[name] then return 'regions' end
end
end
local displayType = DisplayType(name)
if not displayType then return end
if displayType == 'auras' then
if WeakAuras
and WeakAuras[displayType]
and WeakAuras[displayType][name]
and WeakAuras[displayType][name][0]
and WeakAuras[displayType][name][0]['region'] then
return WeakAuras[displayType][name][0]['region']
end
elseif displayType == 'regions' then
if WeakAuras
and WeakAuras[displayType]
and WeakAuras[displayType][name]
and WeakAuras[displayType][name]
and WeakAuras[displayType][name]['region'] then
return WeakAuras[displayType][name]['region']
end
end
end
if name and pointX and pointY then
local playerX, playerY = UnitPosition('player')
offset = offset or 0
local degrees = math.deg(math.atan2((playerY - pointY), (playerX - pointX)) - GetPlayerFacing()) + offset
local region = GetRegion(name)
if not region
or not region['Rotate']
or not (type(region['Rotate']) == 'function') then return end
region['Rotate'](0, degrees and degrees or 0)
end
end
-- GetDisplayColor('info') - Get the color of the 'info' display
-- @name string - Name of the WeakAura Display to be queried.
-- return table - Display's color values
local GetDisplayColor = function(name)
local GetRegion = function(name)
local DisplayType = function(name)
if WeakAuras then
if WeakAuras.auras and WeakAuras.auras[name] then return 'auras' end
if WeakAuras.regions and WeakAuras.regions[name] then return 'regions' end
end
end
local displayType = DisplayType(name)
if not displayType then return end
if displayType == 'auras' then
if WeakAuras
and WeakAuras[displayType]
and WeakAuras[displayType][name]
and WeakAuras[displayType][name][0]
and WeakAuras[displayType][name][0]['region'] then
return WeakAuras[displayType][name][0]['region']
end
elseif displayType == 'regions' then
if WeakAuras
and WeakAuras[displayType]
and WeakAuras[displayType][name]
and WeakAuras[displayType][name]
and WeakAuras[displayType][name]['region'] then
return WeakAuras[displayType][name]['region']
end
end
end
local region = GetRegion(name)
if not region
or not region['color_r']
or not region['color_g']
or not region['color_b']
or not region['color_a'] then return end
return {r = region['color_r'], g = region['color_g'], b = region['color_b'], a = region['color_a']}
end
-- SetDisplayColor('info', 1, 0, 0, 1) - Set the color for the 'info' display to red using 0..1 rgba values
-- SetDisplayColor('info', 'red') - Set the color for the 'info' display to red using the 'red' keyword syntax
-- @name string - Name of the WeakAura Display to be modified.
-- @r string/number - The (number) of the red rgb value OR the (string) color keyword (black, blue, green, orange, purple, red, white, yellow)
-- [@g] number - (Optional) The green rgb value
-- [@b] number - (Optional) The blue rgb value
-- [@a] number - (Optional) The alpha value (Default: 1)
local SetDisplayColor = function(name, r, g, b, a)
local GetRegion = function(name)
local DisplayType = function(name)
if WeakAuras then
if WeakAuras.auras and WeakAuras.auras[name] then return 'auras' end
if WeakAuras.regions and WeakAuras.regions[name] then return 'regions' end
end
end
local displayType = DisplayType(name)
if not displayType then return end
if displayType == 'auras' then
if WeakAuras
and WeakAuras[displayType]
and WeakAuras[displayType][name]
and WeakAuras[displayType][name][0]
and WeakAuras[displayType][name][0]['region'] then
return WeakAuras[displayType][name][0]['region']
end
elseif displayType == 'regions' then
if WeakAuras
and WeakAuras[displayType]
and WeakAuras[displayType][name]
and WeakAuras[displayType][name]
and WeakAuras[displayType][name]['region'] then
return WeakAuras[displayType][name]['region']
end
end
end
local colors = {
{ name = 'black', r = 0, g = 0, b = 0, a = 1, },
{ name = 'blue', r = 0, g = 0.2, b = 1, a = 1, },
{ name = 'green', r = 0, g = 1, b = 0, a = 1, },
{ name = 'orange', r = 1, g = 0.5, b = 0, a = 1, },
{ name = 'purple', r = 1, g = 0, b = 1, a = 1, },
{ name = 'red', r = 1, g = 0, b = 0, a = 1, },
{ name = 'white', r = 1, g = 1, b = 1, a = 1, },
{ name = 'yellow', r = 1, g = 1, b = 0, a = 1, },
}
-- Convert
if tonumber(r) == nil and type(r) == 'string' then
for i,v in pairs(colors) do
if v.name == strlower(r) then r = v.r g = v.g b = v.b a = v.a end
end
elseif type(r) == 'table' and (r.r or r.g or r.b) then
g = r.g or 1
b = r.b or 1
a = r.a or 1
r = r.r or 1
end
if r and b and g then
a = a or 1
local region = GetRegion(name)
if not region
or not region['Color']
or not (type(region['Color']) == 'function') then return end
-- Add space for self parameter if progress bar
if region.bar or region.texture then
region['Color'](region, r, g, b, a)
else
region['Color'](r, g, b, a)
end
end
end
-- SetDisplayText('info', 'hello') - Set the text for the 'info' display to 'hello'
-- @name string - Name of the WeakAura Display to be modified.
-- @text string/number - Text to show
local SetDisplayText = function(name, text)
local GetRegion = function(name)
local DisplayType = function(name)
if WeakAuras then
if WeakAuras.auras and WeakAuras.auras[name] then return 'auras' end
if WeakAuras.regions and WeakAuras.regions[name] then return 'regions' end
end
end
local displayType = DisplayType(name)
if not displayType then return end
if displayType == 'auras' then
if WeakAuras
and WeakAuras[displayType]
and WeakAuras[displayType][name]
and WeakAuras[displayType][name][0]
and WeakAuras[displayType][name][0]['region'] then
return WeakAuras[displayType][name][0]['region']
end
elseif displayType == 'regions' then
if WeakAuras
and WeakAuras[displayType]
and WeakAuras[displayType][name]
and WeakAuras[displayType][name]
and WeakAuras[displayType][name]['region'] then
return WeakAuras[displayType][name]['region']
end
end
end
local region = GetRegion(name)
if not region or not region['text'] then return end
region['text']:SetText(text or '')
end
-- DistanceBetweenPoints(100, 200, 500, 1200) - Get the distance (in yards) the points 100,200 and 500,1200
-- DistanceBetweenPoints(UnitPosition('raid3'), UnitPosition('player')) - Get the distance between the player and the 'raid3' unit
-- @ax number - Point A x-coordinate
-- @ay number - Point A y-coordinate
-- @bx number - Point B x-coordinate
-- @by number - Point B y-coordinate
-- return number - Distance (in yards) between both points.
local DistanceBetweenPoints = function(ax, ay, bx, by)
if ax and ay and by and by then
local dx = ax - bx
local dy = ay - by
return (dx * dx + dy * dy) ^ 0.5
end
return nil
end
-- DistanceBetweenUnits('raid3', 'player') - Get the distance (in yards) between the player and the third raid member.
-- DistanceBetweenUnits('raid3') - Same as above (default unit is 'player').
-- DistanceBetweenUnits('raid19, 'party4') - Distance between raid member nineteen and player's party member four.
-- [@unitA] string - (Optional) Friendly unit A to check. Defaults to 'player'.
-- [@unitB] string - (Optional) Friendly unit B to check. Defaults to 'player'.
-- return number - Distance (in yards) between both units.
local DistanceBetweenUnits = function(unitA, unitB)
unitA = unitA or 'player'
unitB = unitB or 'player'
local ax, ay = UnitPosition(unitA)
local bx, by = UnitPosition(unitB)
if ax and bx then
local dx = ax - bx
local dy = ay - by
return (dx * dx + dy * dy) ^ 0.5
end
return nil
end
-- DistanceToPoint(200, 500) - Get the distance (in yards) between the player and the point 200,500.
-- DistanceToPoint(UnitPosition('party4')) - Get the distance between player and the fourth party member of the player.
-- @x number - x-coordinate
-- @y number - y-coordinate
-- return number - Distance (in yards) between player and specified point.
local DistanceToPoint = function(x, y)
local playerX, playerY = UnitPosition('player')
if x and y and playerX and playerY then
local dx = playerX - x
local dy = playerY - y
return (dx * dx + dy * dy) ^ 0.5
end
end
-- DistanceToUnit('raid3') - Get the distance (in yards) between the player and the third raid member.
-- DistanceToUnit('party4') - Get the distance between player and the fourth party member of the player.
-- @unit string - Friendly unit to check.
-- return number - Distance (in yards) between player and specified unit.
local DistanceToUnit = function(unit)
local distanceSquared = UnitDistanceSquared(unit)
if distanceSquared then return distanceSquared ^ 0.5 end
return nil
end
-- NearestPlayer() - Get the unitId of the nearest player in party/raid
-- return string - UnitId string of nearest player OR nil if invalid
local NearestPlayer = function()
local numPlayers = GetNumGroupMembers()
if numPlayers == 0 then return nil end
local DistanceToUnit = function(unit)
local distanceSquared = UnitDistanceSquared(unit)
if distanceSquared then return distanceSquared ^ 0.5 end
return nil
end
local distance, nearestUnit, nearestDistance
for i = 1, numPlayers do
local unitId = IsInRaid() and "raid"..i or "party"..i
distance = DistanceToUnit(unitId)
if UnitExists(unitId) and not UnitIsUnit(unitId, 'player') and not UnitIsDeadOrGhost(unitId) then
if nearestUnit then
-- Shorter
if distance < nearestDistance then
nearestUnit = unitId
nearestDistance = distance
end
else
nearestUnit = unitId
nearestDistance = distance
end
end
end
return nearestUnit
end
-- Useful for Trigger > Every Frame Displays in WeakAuras.
-- HasTimeElapsed(2.5, 'my-display') - Return true if 2.5 seconds have elapsed
-- HasTimeElapsed(0.75, 'my-display') - Return true if 0.75 seconds have elapsed
-- @interval number - Time (in seconds) to elapsed before true
-- return boolean - Has specified time elapsed
local HasTimeElapsed = function(interval, id)
local GetValue = function(...)
if not WeakAuras.CustomValues then WeakAuras.CustomValues = {} end
if not ... then return end
local count, data = #{...}
if count and (count > 1) then
for i,v in pairs({...}) do
if i==1 then WeakAuras.CustomValues[v] = WeakAuras.CustomValues[v] or {} data = WeakAuras.CustomValues[v]
else if i ~= count then if not data[v] then data[v] = {} else data = data[v] end else data = data[v] end end
end
else data = WeakAuras.CustomValues[select(1, ...)] end
return data
end
local SetValue = function(value, ...)
if not WeakAuras.CustomValues then WeakAuras.CustomValues = {} end
if not ... then return end
local count, data = #{...}
for i,v in pairs({...}) do
if i==1 then if count and count == 1 then WeakAuras.CustomValues[v] = value else
WeakAuras.CustomValues[v] = WeakAuras.CustomValues[v] or {}
data = WeakAuras.CustomValues[v] end
else if i ~= count then if not data[v] then data[v] = {} end data = data[v] else data[v] = value end end
end
end
interval = interval or 1
local current_time = GetTime()
last_update = GetValue(id, 'LastUpdate')
SetValue(last_update or current_time, id, 'LastUpdate')
if (current_time - GetValue(id, 'LastUpdate')) >= interval then
SetValue(current_time, id, 'LastUpdate')
return true
end
end
Used for custom timer creation. ''Must'' be utilized in tandem with the GetValue and SetValue functions, and placed after these two functions in the execution stack.
local Timer_Cancel = function(id) SetValue(nil, id) end
local Timer_Create = function(id, start, expiration) start = start or GetTime() SetValue(start, id, 'start') SetValue(expiration, id, 'expiration') SetValue(false, id, 'fired') end
local Timer_Fire = function(id) SetValue(true, id, 'fired') return true end
local Timer_GetDuration = function(id) if not GetValue(id, 'start') or not GetValue(id, 'expiration') then return 0 else return (GetValue(id, 'expiration') - GetValue(id, 'start')) or 0 end end
local Timer_GetExpiration = function(id) if not GetValue(id, 'start') or not GetValue(id, 'expiration') then return 0 else return GetValue(id, 'expiration') or 0 end end
local Timer_GetStart = function(id) if not GetValue(id, 'start') or not GetValue(id, 'expiration') then return 0 else return GetValue(id, 'start') or 0 end end
local Timer_HasFired = function(id) return GetValue(id, 'fired') end
local Timer_IsActive = function(id)
if not GetValue(id, 'start') or not GetValue(id, 'expiration') then return false end
local currentTime, start, expiration = GetTime(), GetValue(id, 'start'), GetValue(id, 'expiration')
if (start <= currentTime) and (currentTime < expiration) then return true else return false end
end
-- GetUnitAuraValue(114908) - Get the default aura 'name' of Spirit Shell aura for default 'player' unitId
-- GetUnitAuraValue(114908, 'icon') - Get icon path value of Spirit Shell aura for default 'player' unitId
-- GetUnitAuraValue(114908, 'value2', 'mouseover') - Get value2 of Spirit Shell aura for 'mouseover' unitId
-- GetUnitAuraValue('Spirit Shell', 'duration', 'focus', 'player') - Get the duration value of Spirit Shell aura by name for 'focus' unitId from source unitId 'player'
-- GetUnitAuraValue({114908, 119611}, 'duration', 'focus', 'player') - Get the duration value of the first of two auras found (Spirit Shell or Renewing Mist) for 'focus' unitId from source unitId 'player'
-- @aura string/number - Any aura name or aura spell Id
-- [@valueType] string - (Optional) Value type ID to return, as found in the API_UnitAura return values. Default: 'name'
-- [@unit] string - (Optional) unitId to check for Aura. Default: 'player'
-- [@sourceUnit] string - (Optional) Specify the required source UnitId for the Aura. Default: N/A
-- return any - Returned value of found matching Aura
local GetUnitAuraValue = function(aura, valueType, unit, sourceUnit) -- v2
if not aura then
return
end
valueType, unit = valueType or "name", unit or "player"
if not UnitExists(unit) then
return
end
local v, value = {}
local GetAuraValues = function(unit, aura, filter)
local v, filter = {}, filter or "HELPFUL"
v.name,
v.icon,
v.count,
v.auraType,
v.duration,
v.expirationTime,
v.unitCaster,
v.isStealable,
v.nameplateShowPersonal,
v.spellId,
v.canApplyAura,
v.isBossDebuff,
v.castByPlayer,
v.nameplateShowAll,
v.timeMod,
v.value1,
v.value2,
v.value3 = UnitAura(unit, aura, type(aura) == "number" and filter or nil, filter)
return v
end
local GetAuraValue = function(v, t, s)
if v[t] then
if s then
if v.unitCaster and UnitExists(s) and v.unitCaster == s then
return v[t]
end
else
return v[t]
end
end
end
local ScanAuras = function(aura, valueType, unit, sourceUnit)
local output = nil
if type(aura) == "string" then
v = GetAuraValues(unit, aura)
output = GetAuraValue(v, valueType, sourceUnit)
if output then
return output
end
v = GetAuraValues(unit, aura, "HARMFUL")
output = GetAuraValue(v, valueType, sourceUnit)
if output then
return output
end
elseif type(aura) == "number" then
for i = 1, 40 do
v = GetAuraValues(unit, i)
output = GetAuraValue(v, valueType, sourceUnit)
if v.spellId and v.spellId == aura then
if output then
return output
end
end
v = GetAuraValues(unit, i, "HARMFUL")
output = GetAuraValue(v, valueType, sourceUnit)
if v.spellId and v.spellId == aura then
if output then
return output
end
end
end
end
end
if type(aura) == "table" then
local output = nil
for iAura, vAura in pairs(aura) do
output = ScanAuras(vAura, valueType, unit, sourceUnit)
if output then
return output
end
end
else
return ScanAuras(aura, valueType, unit, sourceUnit)
end
end
--GetUnitAuraValueByIndex('Vengeance', 15) - Get the Vengeance current value (index 15 of API_UnitBuff return) for the 'player' unit
--GetUnitAuraValueByIndex('Vengeance', 15, 'focus') - Get the Vengeance current value for the 'focus' unit
--GetUnitAuraValueByIndex('Immolate', 7, 'target', true) - Get the expiration time value (index 7 of API_UnitDebuff) of the Immolate debuff for the 'target' unit
local GetUnitAuraValueByIndex = function(spell, index, unit, isDebuff)
if not spell or not index then return end
if not type(index) == 'number' then return end
unit = unit or 'player'
if not UnitExists(unit) then return end
if isDebuff then return select(index, UnitDebuff(unit, spell)) end
return select(index, UnitBuff(unit, spell))
end
-- name, rank, ... = GetAuraByType('target', 'Disease')
-- name, rank, ... = GetAuraByType('boss3', 'Magic')
-- @unit string - UnitID to check for Aura
-- [@type] string - (Optional) Aura type to check for (e.g. 'Magic', 'Poison', etc). Defaults to 'Magic'.
-- return list - Matching list values from API_UnitAura() of first found aura that matches criteria. Returns nil if no match.
local GetAuraByType = function(unit, type)
if not UnitExists(unit) then return end
type = type or 'Magic'
for i=1,40 do
local name, rank, icon, count, auraType, duration, expirationTime, unitCaster, isStealable, shouldConsolidate, spellId, canApplyAura, isBossDebuff, value1, value2, value3 = UnitAura(unit, i, 'HELPFUL')
if auraType and auraType == type then
return name, rank, icon, count, auraType, duration, expirationTime, unitCaster, isStealable, shouldConsolidate, spellId, canApplyAura, isBossDebuff, value1, value2, value3
end
end
end
-- UnitShouldRefreshAura(115798) -- Check if Weakened Blows aura on TARGET unit is missing or has less than 4.5 (default) seconds remaining duration
-- UnitShouldRefreshAura('Weakened Blows', 5, 1) -- Same as above, but check for 6 (5 margin + 1 gcd) seconds remaining
-- UnitShouldRefreshAura(115789, 5, 1, 6348) -- Same as above, but check for 6 + THUNDER_CLAP_COOLDOWN seconds remaining
-- UnitShouldRefreshAura('Weakened Blows', 5, 1, 'Thunder Clap', 'focus') -- Same as above but check FOCUS unit
-- @aura string/number - Aura to check
-- [@margin] number - (Optional) Seconds of safety margin to add to duration before expiration to ensure refresh can occur in time. DEFAULT: 3
-- [@gcd] number - (Optional) Seconds of typical global cooldown. DEFAULT: 1.5
-- [@spell] string/number - (Optional) Spell that triggers tracked aura. Useful if spell has a cooldown, which will be applied to required duration to trigger refresh.
-- [@unit] string - (Optional) UnitId to check. DEFAULT: target
-- return boolean - Determines if the Aura is missing or has a duration less than the allowance time based on GCD, Margin, and applying Spell cooldown.
local UnitShouldRefreshAura = function(aura, margin, gcd, spell, unit)
if not aura then return end
margin, gcd, unit = margin or 3, gcd or 1.5, unit or 'target'
local GetSpellCooldown = function(spell, getDuration)
if not spell then return end local start, duration, enabled = GetSpellCooldown(spell)
if not start then return start end if getDuration then return duration end if start == 0 then return start end
return (start + duration - GetTime())
end
local GetUnitAuraValue = function(aura, valueType, unit, sourceUnit)
if not aura then return end valueType, unit = valueType or 'name', unit or 'player' if not UnitExists(unit) then return end local v, value = {}
local GetAuraValues = function(unit, aura, filter)
local v, filter = {}, filter or 'HELPFUL'
v.name, v.rank, v.icon, v.count, v.auraType, v.duration, v.expirationTime, v.unitCaster, v.isStealable, v.shouldConsolidate, v.spellId, v.canApplyAura, v.isBossDebuff, v.value1, v.value2, v.value3 = UnitAura(unit, aura, type(aura)=='number' and filter or nil, filter)
return v
end
local GetAuraValue = function(v, t, s) if v[t] then if s then if v.unitCaster and UnitExists(s) and v.unitCaster == s then return v[t] end else return v[t] end end end
if type(aura) == 'string' then
v = GetAuraValues(unit, aura)
if GetAuraValue(v,valueType,sourceUnit) then return GetAuraValue(v,valueType,sourceUnit) end
v = GetAuraValues(unit, aura, 'HARMFUL')
if GetAuraValue(v,valueType,sourceUnit) then return GetAuraValue(v,valueType,sourceUnit) end
elseif type(aura) == 'number' then
for i=1,40 do v = GetAuraValues(unit, i)
if v.spellId and v.spellId == aura then if GetAuraValue(v,valueType,sourceUnit) then return GetAuraValue(v,valueType,sourceUnit) end end
v = GetAuraValues(unit, i, 'HARMFUL')
if v.spellId and v.spellId == aura then if GetAuraValue(v,valueType,sourceUnit) then return GetAuraValue(v,valueType,sourceUnit) end end
end
end
end
if not UnitExists(unit) then return end
local expiration = GetUnitAuraValue(aura, 'expirationTime', unit)
if not expiration then return true end
local duration, allowance = expiration - GetTime(), (gcd or 0) + (GetSpellCooldown(spell) or 0) + (margin or 0)
if duration <= allowance then return true end
end
The following functions are intended for use with the COMBAT_LOG_EVENT_UNFILTERED trigger event.
To utilize these code snippets, create a WeakAura Display and set Trigger > Type: Custom, Event Type: Event
and add COMBAT_LOG_EVENT_UNFILTERED
to the Event(s)
field.
Within any of the Custom Function
fields for the Trigger be sure the parent function accepts a [[http://www.lua.org/pil/5.2.html|variable number of arguments]] using only the ...
parameter.
Now simply copy and paste any of the below COMBAT_LOG
snippets into the top of the parent function, then make calls to those snippet functions within your code as illustrated in the examples.
-- Example Custom Trigger Function
function(...) -- Accepts a variable number of arguments from the COMBAT_LOG event
-- SNIPPET FUNCTIONS GO HERE AT THE TOP
-- YOUR CUSTOM CODE UTILIZING SAID SNIPPETS GOES HERE AT THE BOTTOM
end
.
-- AuraStack('Destabilize', ...) - Get the stack size for Destabilize aura
-- AuraStack(123059, ...) - Get the stack size for Destabilize aura
-- @value string/number - SpellName or SpellId
-- @... list - Value list from CLEU function
-- return number - Stack size of aura if exists
local AuraStack = function(value, ...)
if not select(1, ...) or select(1, ...) ~= 'COMBAT_LOG_EVENT_UNFILTERED' or not value then return end
local event, comparison = select(3, ...)
if not event or not string.find(event, '_AURA_') then return end
if type(value) == 'string' then comparison = select(14, ...)
elseif type(value) == 'number' then
local comparisonNumber = select(13, ...)
comparison = tonumber(comparisonNumber)
else return end
if not comparison or not (value == comparison) then return end
local stack = select(17, ...)return stack
end
-- HasDestinationFlag(COMBATLOG_OBJECT_TYPE_NPC, ...) - Check if destination is an NPC type
-- HasDestinationFlag(COMBATLOG_OBJECT_TARGET, ...) - Check if destination is player's current target
-- @value CONSTANT - Unit flag (see: http://wow.gamepedia.com/UnitFlag)
-- @... list - Value list from CLEU function
-- return boolean - Whether specified Flag matches for destination unit
local HasDestinationFlag = function(value, ...)
if not select(1, ...) or select(1, ...) ~= 'COMBAT_LOG_EVENT_UNFILTERED' or not value then return end
local flags = select(11, ...)
if not flags then return end
return (bit.band(flags, value) ~= 0)
end
-- HasDestinationRaidFlag(COMBATLOG_OBJECT_RAIDTARGET_MASK, ...) - Check if destination is marked with a raid marker
-- HasDestinationRaidFlag(COMBATLOG_OBJECT_RAIDTARGET1, ...) - Check if destination is marked with the 'Star' raid marker
-- @value CONSTANT - Raid flag (see: http://wow.gamepedia.com/RaidFlag)
-- @... list - Value list from CLEU function
-- return boolean - Whether specified Flag matches for destination unit
local HasDestinationRaidFlag = function(value, ...)
if not select(1, ...) or select(1, ...) ~= 'COMBAT_LOG_EVENT_UNFILTERED' or not value then return end
local flags = select(12, ...)
if not flags then return end
return (bit.band(flags, value) ~= 0)
end
-- HasSourceFlag(COMBATLOG_OBJECT_TYPE_NPC, ...) - Check if source is an NPC type
-- HasSourceFlag(COMBATLOG_OBJECT_TARGET, ...) - Check if source is player's current target
-- @value CONSTANT - Unit flag (see: http://wow.gamepedia.com/UnitFlag)
-- @... list - Value list from CLEU function
-- return boolean - Whether specified Flag matches for destination unit
local HasSourceFlag = function(value, ...)
if not select(1, ...) or select(1, ...) ~= 'COMBAT_LOG_EVENT_UNFILTERED' or not value then return end
local flags = select(7, ...)
if not flags then return end
return (bit.band(flags, value) ~= 0)
end
-- HasSourceRaidFlag(COMBATLOG_OBJECT_RAIDTARGET_MASK, ...) - Check if source is marked with a raid marker
-- HasSourceRaidFlag(COMBATLOG_OBJECT_RAIDTARGET1, ...) - Check if source is marked with the 'Star' raid marker
-- @value CONSTANT - Raid flag (see: http://wow.gamepedia.com/RaidFlag)
-- @... list - Value list from CLEU function
-- return boolean - Whether specified Flag matches for destination unit
local HasSourceRaidFlag = function(value, ...)
if not select(1, ...) or select(1, ...) ~= 'COMBAT_LOG_EVENT_UNFILTERED' or not value then return end
local flags = select(8, ...)
if not flags then return end
return (bit.band(flags, value) ~= 0)
end
-- GetAmount('amount', ...) - Get the amount value of the combat log event
-- GetAmount('amount', ...) - Get the amount value of the combat log event
-- GetAmount('healing', ...) - Get the effective healing value of the combat log event
-- @returnType string - Type of amount value to return: 'amount', 'damage', 'overhealing', 'overkill', 'healing', 'effective-healing'
-- @... list - Value list from CLEU function
-- return number - Amount value
local GetAmount = function(returnType, ...)
if not select(1, ...) or select(1, ...) ~= 'COMBAT_LOG_EVENT_UNFILTERED' then return end
returnType = returnType or 'amount'
local amount, overkill, absorbed = select(16, ...)
if returnType == 'amount' or returnType == 'damage' then
return amount
elseif returnType == 'overhealing' or returnType == 'overkill' then
return overkill
elseif returnType == 'healing' or returnType == 'effective-healing' then
if amount then return (amount - overkill) end
end
end
-- GetDestination('name', ...) - Get the name of the destination
-- GetDestination('unit-id', ...) - Get the unitId of the destination
-- GetDestination('id', ...) - Get the NPC ID (if applicable) of the destination
-- GetDestination('guid', ...) - Get the guid of the destination
-- @value string - ReturnType (name, unit-id, id, guid)
-- @... list - Value list from CLEU function
-- return string - Destination value
local GetDestination = function(returnType, ...)
if not select(1, ...) or select(1, ...) ~= 'COMBAT_LOG_EVENT_UNFILTERED' then return end
local GetUnitId = function(unit)
local id
if not unit then return end
if type(unit) == 'string' then -- name or unitId
if UnitInRaid(unit) then return 'raid'..UnitInRaid(unit) end -- Player in raid
for i=1,10 do id = 'boss'..i if id == unit then return unit end if UnitExists(id) and UnitName(id) == unit then return id end end
if UnitExists('player') and UnitName('player') == unit then return 'player' end
if UnitExists('pet') and UnitName('pet') == unit then return 'pet' end
if UnitExists('target') and UnitName('target') == unit then return 'target' end
if UnitExists('focus') and UnitName('focus') == unit then return 'focus' end
if UnitExists('mouseover') and UnitName('mouseover') == unit then return 'mouseover' end
end
end
local ParseGUID = function(value, returnType)
local objectType
local returnType = returnType or 'unitType'
local validObjectTypes = {"Creature", "GameObject", "Pet", "Player", "Vehicle", "Vignette"}
for _,v in pairs(validObjectTypes) do if string.match(value, ("^%s%%-"):format(v)) then objectType = v end end
if not objectType then return end
local r = {}
if objectType == 'Creature' or objectType == 'GameObject' or objectType == 'Pet' or objectType == 'Vehicle' then
r.unitType, r.zero, r.serverId, r.instanceId, r.zoneId, r.id, r.spawnId = strsplit('-', value)
elseif objectType == 'Player' then
r.unitType, r.serverId, r.playerId = strsplit('-', value)
elseif objectType == 'Vignette' then
r.unitType, r.zero, r.serverId, r.instanceId, r.zoneId, r.zero, r.spawnId = strsplit('-', value)
end
return r[returnType]
end
returnType = returnType or 'name'
local GUID = select(9, ...)
if not GUID then return end
local name = select(10, ...)
if returnType == 'name' then return name end
if returnType == 'guid' then return GUID end
if returnType == 'unit-id' or returnType == 'unitId' then return GetUnitId(name) end
return ParseGUID(GUID, returnType)
end
-- GetSource('name', ...) - Get the name of the source
-- GetSource('unit-id', ...) - Get the unitId of the source
-- GetSource('id', ...) - Get the NPC ID (if applicable) of the source
-- GetSource('guid', ...) - Get the GUID of the source
-- @value string - ReturnType (name, unit-id, id, guid)
-- @... list - Value list from CLEU function
-- return string - Source value
local GetSource = function(returnType, ...)
if not select(1, ...) or select(1, ...) ~= 'COMBAT_LOG_EVENT_UNFILTERED' then return end
local GetUnitId = function(unit)
local id
if not unit then return end
if type(unit) == 'string' then -- name or unitId
if UnitInRaid(unit) then return 'raid'..UnitInRaid(unit) end -- Player in raid
for i=1,10 do id = 'boss'..i if id == unit then return unit end if UnitExists(id) and UnitName(id) == unit then return id end end
if UnitExists('player') and UnitName('player') == unit then return 'player' end
if UnitExists('pet') and UnitName('pet') == unit then return 'pet' end
if UnitExists('target') and UnitName('target') == unit then return 'target' end
if UnitExists('focus') and UnitName('focus') == unit then return 'focus' end
if UnitExists('mouseover') and UnitName('mouseover') == unit then return 'mouseover' end
end
end
local ParseGUID = function(value, returnType)
local objectType
local returnType = returnType or 'unitType'
local validObjectTypes = {"Creature", "GameObject", "Pet", "Player", "Vehicle", "Vignette"}
for _,v in pairs(validObjectTypes) do if string.match(value, ("^%s%%-"):format(v)) then objectType = v end end
if not objectType then return end
local r = {}
if objectType == 'Creature' or objectType == 'GameObject' or objectType == 'Pet' or objectType == 'Vehicle' then
r.unitType, r.zero, r.serverId, r.instanceId, r.zoneId, r.id, r.spawnId = strsplit('-', value)
elseif objectType == 'Player' then
r.unitType, r.serverId, r.playerId = strsplit('-', value)
elseif objectType == 'Vignette' then
r.unitType, r.zero, r.serverId, r.instanceId, r.zoneId, r.zero, r.spawnId = strsplit('-', value)
end
return r[returnType]
end
returnType = returnType or 'name'
local GUID = select(9, ...)
if not GUID then return end
local name = select(10, ...)
if returnType == 'name' then return name end
if returnType == 'guid' then return GUID end
if returnType == 'unit-id' or returnType == 'unitId' then return GetUnitId(name) end
return ParseGUID(GUID, returnType)
end
-- IsDestination('Boss Name', ...) -- Check if destination unit name matches 'Boss Name'
-- IsDestination('boss3', ...) -- Check if destination unit-id matches boss3
-- IsDestination('0xF130C3030000037F2', ...) -- Check if destination unit GUID matches '0xF130C3030000037F2'
-- IsDestination(84235, ...) -- Check if destination NPC id matches 84235
-- @value string/number - UnitName, UnitID, GUID, or numerical ID
-- @... list - Value list from CLEU function
-- return boolean - Whether param value matches logged destination.
local IsDestination = function(value, ...)
if not select(1, ...) or select(1, ...) ~= 'COMBAT_LOG_EVENT_UNFILTERED' or not value then return end
local comparison
local GUID = select(9, ...)
if type(value) == 'string' then comparison = select(10, ...)
if value == GUID then return true end
for i,v in pairs({'player', 'target', 'focus', 'raid'}) do
if type(value) == 'string' and string.find(value, v) then value = UnitExists(value) and UnitName(value) end
end
elseif type(value) == 'number' then
if GUID then comparison = tonumber(GUID:sub(6,10), 16) end
else return end
if not comparison then return end
return (value == comparison)
end
-- IsEventType('SPELL_AURA_APPLIED', ...)
-- IsEventType('UNIT_DIED', ...)
-- @value string - Event type
-- @... list - Value list from CLEU function
-- return boolean - Whether param value matches logged event type.
local IsEventType = function(value, ...)
if not select(1, ...) or select(1, ...) ~= 'COMBAT_LOG_EVENT_UNFILTERED' or not value or type(value) ~= 'string' then return end
local event = select(3, ...)
if not event then return end
if event == value then return true end
end
-- IsSource('Boss Name', ...) -- Check if source unit name matches 'Boss Name'
-- IsSource('boss3', ...) -- Check if source unit-id matches boss3
-- IsSource('0xF130C3030000037F2', ...) -- Check if source unit GUID matches '0xF130C3030000037F2'
-- IsSource(84235, ...) -- Check if source NPC id matches 84235
-- @value string/number - UnitName, UnitID, GUID, or numerical ID
-- @... list - Value list from CLEU function
-- return boolean - Whether param value matches logged source.
local IsSource = function(value, ...)
if not select(1, ...) or select(1, ...) ~= 'COMBAT_LOG_EVENT_UNFILTERED' or not value then return end
local comparison
local GUID = select(5, ...)
if type(value) == 'string' then comparison = select(6, ...)
if value == GUID then return true end
for i,v in pairs({'player', 'target', 'focus', 'raid'}) do
if type(value) == 'string' and string.find(value, v) then value = UnitExists(value) and UnitName(value) end
end
elseif type(value) == 'number' then
if GUID then comparison = tonumber(GUID:sub(6,10), 16) end
else return end
if not comparison then return end
return (value == comparison)
end
-- IsSpell('Moonfire', ...)
-- IsSpell(54982, ...)
-- @value string/number - SpellName or numerical SpellID
-- @... list - Value list from CLEU function
-- return boolean - Whether param value matches logged spell.
local IsSpell = function(value, ...)
if not select(1, ...) or select(1, ...) ~= 'COMBAT_LOG_EVENT_UNFILTERED' or not value then return end
local comparison
if type(value) == 'string' then comparison = select(14, ...)
elseif type(value) == 'number' then local n = select(13, ...) comparison = tonumber(n)
else return end
if not comparison then return end
return (value == comparison)
end
-- GetSpellCooldown('Guard') - Get the current time remaining on Guard's cooldown.
-- GetSpellCooldown(115295) - Get the current time remaining on Guard's cooldown.
-- GetSpellCooldown(115295, true) - Get the total duration of Guard's cooldown.
-- @spell string/number - Spell name, spell Id, or slot ID of spell to query
-- [@getDuration] boolean - Determine if return value should be cooldown total duration instead of cooldown remaining time.
-- return number - The cooldown remaining or total duration, if appropriate. Return of 0 (zero) indicates ability not on cooldown. Return of nil indicates ability not found.
local GetSpellCooldown = function(spell, getDuration)
if not spell then return end local start, duration, enabled = GetSpellCooldown(spell)
if not start then return start end if getDuration then return duration end if start == 0 then return start end
return (start + duration - GetTime())
end
-- IsSpellChanneled('Soothing Mist', ...) - Determines if Soothing Mist channel has started
-- IsSpellChanneled(115175, ...) - Determines if Soothing Mist channel has started
-- @value string/number - SpellName or SpellId
-- @... list - Value list from UNIT_SPELLCAST_CHANNEL_START event returns
-- return string - UnitId of unit firing channeled spell start event
local IsSpellChanneled = function(value, ...)
if not select(1, ...) or select(1, ...) ~= 'UNIT_SPELLCAST_CHANNEL_START' or not value then return end
if type(value) == 'string' then comparison = select(3, ...) else comparison = select(6, ...) end
if not comparison then return end
return (value == comparison) and select(2, ...)
end
-- IsSpellChannelStopped('Soothing Mist', ...) - Determines if Soothing Mist channel has stopped
-- IsSpellChannelStopped(115175, ...) - Determines if Soothing Mist channel has stopped
-- @value string/number - SpellName or SpellId
-- @... list - Value list from UNIT_SPELLCAST_CHANNEL_STOP event returns
-- return string - UnitId of unit firing channeled spell stop event
local IsSpellChannelStopped = function(value, ...)
if not select(1, ...) or select(1, ...) ~= 'UNIT_SPELLCAST_CHANNEL_STOP' or not value then return end
if type(value) == 'string' then comparison = select(3, ...) else comparison = select(6, ...) end
if not comparison then return end
return (value == comparison) and select(2, ...)
end
local UnitCastingTime = function(spell, unit, remaining)
local UnitIsCasting = function(spell, unit)
unit = unit or 'player'
if not UnitExists(unit) then return end
local spellName, _, _, _, spellStart, spellEnd, _, spellId = UnitCastingInfo(unit)
if not spellName then return end
if spell then
if type(spell) == 'string' then
if spellName == spell then return spellName, spellStart, spellEnd end
elseif type(tonumber(spell)) == 'number' then
if tonumber(spell) == spellId then return spellName, spellStart, spellEnd end
end
else
return spellName, spellStart, spellEnd
end
end
local _, startTime, endTime = UnitIsCasting(spell, unit)
if startTime and endTime then
if remaining then
return ((endTime - (GetTime() * 1000)) / 1000)
else
return (((GetTime() * 1000) - startTime) / 1000)
end
end
end
local UnitChannelingTime = function(spell, unit, remaining)
local UnitIsChanneling = function(spell, unit)
unit = unit or 'player'
if not UnitExists(unit) then return end
local spellName, _, _, _, spellStart, spellEnd = UnitChannelInfo(unit)
if not spellName then return end
if spell then
if type(spell) == 'string' then
if spellName == spell then return spellName, spellStart, spellEnd end
end
else
return spellName, spellStart, spellEnd
end
end
local _, startTime, endTime = UnitIsChanneling(spell, unit)
if startTime and endTime then
if remaining then
return ((endTime - (GetTime() * 1000)) / 1000)
else
return (((GetTime() * 1000) - startTime) / 1000)
end
end
end
local UnitIsCasting = function(spell, unit)
unit = unit or 'player'
if not UnitExists(unit) then return end
local spellName, _, _, _, spellStart, spellEnd, _, spellId = UnitCastingInfo(unit)
if not spellName then return end
if spell then
if type(spell) == 'string' then
if spellName == spell then return spellName, spellStart, spellEnd end
elseif type(tonumber(spell)) == 'number' then
if tonumber(spell) == spellId then return spellName, spellStart, spellEnd end
end
else
return spellName, spellStart, spellEnd
end
end
local UnitIsChanneling = function(spell, unit)
unit = unit or 'player'
if not UnitExists(unit) then return end
local spellName, _, _, _, spellStart, spellEnd = UnitChannelInfo(unit)
if not spellName then return end
if spell then
if type(spell) == 'string' then
if spellName == spell then return spellName, spellStart, spellEnd end
end
else
return spellName, spellStart, spellEnd
end
end
-- HasTalent(2) - Determine if the player is using the Talent with an index of 2.
-- HasTalent('Momentum') - Determine if the player is using the Talent named 'Momentum'.
-- @talent string/integer - The Talent name (string) or Talent index (integer) to check for.
-- return boolean - Whether the talent was found and is active or not.
local HasTalent = function(tier, column)
if not tier then return end
local selected
local specGroup = GetActiveSpecGroup()
if type(tier) == 'number' then -- Index
selected = select(5, GetTalentInfo(tier, column, specGroup))
return selected
elseif type(tier) == 'string' then
local name, talentTier, talentColumn
local talentCount = 18
if select(4, GetBuildInfo()) >= 60000 then
talentCount = 21
end
for i=1,talentCount do
talentTier = math.floor((i-1)/3) + 1
talentColumn = (i % 3) == 0 and 3 or i % 3
id, name, _, _, selected = GetTalentInfo(talentTier, talentColumn, specGroup)
if name and name == tier then return selected end
end
return false
end
end
Generally used to extract the NPC/creature Id from a GUID string or to identify the unitType
of a particular object from GUID.
-- ParseGUID("Player-976-0002FD64") - Return the default parse value (unitType of 'Player') from the passed in Player GUID
-- ParseGUID(UnitGUID('player')) - Return the default parse value (unitType of 'Player') from the passed in Player GUID
-- ParseGUID(UnitGUID('player'), 'serverId') - Return the server ID of the passed in Player GUID
-- ParseGUID(UnitGUID('target'), 'id') - Return the 'id' (creature/NPC id, pet ID, etc) if applicable of target unit
-- @value string - A valid GUID string to parse
-- [@returnType] string - (Optional) Type of value to return if applicable (id, instanceId, playerId, serverId, spawnId, unitType, zoneId). Default: 'unitType'
-- return string - Requested 'returnType' value
local ParseGUID = function(value, returnType)
local objectType
local returnType = returnType or 'unitType'
local validObjectTypes = {"Creature", "GameObject", "Pet", "Player", "Vehicle", "Vignette"}
for _,v in pairs(validObjectTypes) do if string.match(value, ("^%s%%-"):format(v)) then objectType = v end end
if not objectType then return end
local r = {}
if objectType == 'Creature' or objectType == 'GameObject' or objectType == 'Pet' or objectType == 'Vehicle' then
r.unitType, r.zero, r.serverId, r.instanceId, r.zoneId, r.id, r.spawnId = strsplit('-', value)
elseif objectType == 'Player' then
r.unitType, r.serverId, r.playerId = strsplit('-', value)
elseif objectType == 'Vignette' then
r.unitType, r.zero, r.serverId, r.instanceId, r.zoneId, r.zero, r.spawnId = strsplit('-', value)
end
return r[returnType]
end
-- CompareUnitHP() - Determine if PLAYER_HP == TARGET_HP
-- CompareUnitHP('raid1', '<=') - Determine if RAID1_HP <= TARGET_HP
-- CompareUnitHP('target', '<=', 'boss1') - Determine if TARGET_HP <= BOSS1_HP
-- CompareUnitHP('player', '>=', 'target', true) - Determine if PLAYER_HP_MAX >= TARGET_HP
-- CompareUnitHP('player', '<', 'target', true, true) - Determine if PLAYER_HP_MAX < TARGET_HP_MAX
-- [@unit1] string - (Optional) First UnitId to compare. Default: 'player'
-- [@compareType] string - (Optional) Type of mathematical comparison. Default: '==' or equal.
-- [@unit2] string - (Optional) Second UnitId to compare. Default: 'target'
-- [@unit1Max] boolean - (Optional) Determine if Unit1 should be compared using Max health instead of current health. Default: false
-- [@unit2Max] boolean - (Optional) Determine if Unit2 should be compared using Max health instead of current health. Default: false
-- return boolean - The outcome of the comparison.
local CompareUnitHP = function(unit1, compareType, unit2, unit1Max, unit2Max)
unit1, unit2 = unit1 or 'player', unit2 or 'target'
if not UnitExists(unit1) or not UnitExists(unit2) then return false end
compareType = compareType or '=='
local unit1Health, unit2Health = unit1Max and UnitHealthMax(unit1) or UnitHealth(unit1), unit2Max and UnitHealthMax(unit2) or UnitHealth(unit2)
local value = (unit1Health == unit2Health)
if compareType == '<' then value = (unit1Health < unit2Health)
elseif compareType == '>' then value = (unit1Health > unit2Health)
elseif compareType == '<=' then value = (unit1Health <= unit2Health)
elseif compareType == '>=' then value = (unit1Health >= unit2Health) end
return value
end
-- GetSpellPower() - Get the current spell power for the player.
-- GetSpellPower('fire') - Get the current spell power for the 'fire' school for the player.
-- [@school] string - (Optional) Specify the school of magic for which to return the spell power value. Default: nil, returning the base spell power value.
-- return number - The Spell Power value.
local GetSpellPower = function(school)
local schools, spellPower = {'physical', 'holy', 'fire', 'nature', 'frost', 'shadow', 'arcane'}
local GetIndex = function(table, value) for i,v in pairs(table) do if v == value then return i end end end
if school and tContains(schools, school) then spellPower = GetSpellBonusDamage(GetIndex(schools, school)) else
local holySchool = 2
minModifier, holySchool = GetSpellBonusDamage(holySchool), 2
for i=(holySchool+1), MAX_SPELL_SCHOOLS do
local bonusDamage = GetSpellBonusDamage(i)
minModifier = min(minModifier, bonusDamage)
spellPower = bonusDamage
end
end
return spellPower
end
local GetVengeanceCapValue = function(unit)
unit = unit or 'player'
if not UnitExists(unit) then return end
local unitHealthMax = UnitHealthMax(unit)
-- Get interface build
local build = select(4, GetBuildInfo())
if (build >= 50400) then -- Patch 5.4
if IsInRaid() and (GetNumGroupMembers() >= 20) then
return 0.5 * unitHealthMax
else
return 0.3 * unitHealthMax
end
else
return 1 * unitHealthMax
end
end
-- GetUnitAttackPower() - Get the current attack power for the current player
-- GetUnitAttackPower('raid2') - Get the current attack power for the 'raid2' UnitId player
-- GetUnitAttackPower('focus', 'negative') - Get the negative attack power value (from debuffs) for the 'focus' UnitId player
-- [@unit] string - (Optional) UnitId from which to obtain Attack Power value. Default: 'player'
-- [@type] string - (Optional) Attack Power value type ID, to return unique parts of the Attack Power makeup. Default: 'current'
-- return number - The Attack Power value.
local GetUnitAttackPower = function(unit, type)
unit, type = unit or 'player', type or 'current'
if not UnitExists(unit) then return end
local base, positive, negative = UnitAttackPower(unit)
local current = base + positive + negative
if type == 'base' then return base
elseif type == 'positive' then return positive
elseif type == 'negative' then return negative
else return current end
end
-- InZone('Orgrimmar') - Determine if player is currently in the zone or subzone "Orgrimmar"
-- InZone('Orgrimmar', 'zone') - Determine if player is currently in the zone "Orgrimmar"
-- InZone('Orgrimmar', 'subzone') - Determine if player is currently in the subzone "Orgrimmar"
-- [@zone] string - Name of the zone or subzone to check
-- [@zoneType] string - (Optional) Determines the type of zone to be checked. Valid: 'any', 'zone', 'subzone', or 'zone' Default: 'any'
-- return boolean - The player is in the specified zone.
local InZone = function(zone, zoneType)
if not zone then return end
zone, zoneType = string.lower(zone), zoneType and string.lower(zoneType) or 'any'
local zoneText, subZoneText = string.lower(GetRealZoneText()), string.lower(GetSubZoneText() or "")
if zoneType == 'any' then
return ((zone == zoneText) or (zone == subZoneText))
elseif zoneType == 'zone' then
return (zone == zoneText)
elseif (zoneType == 'sub' or zoneType == 'subzone') then
return (zone == subZoneText)
end
end
-- IsEvent('PLAYER_REGEN_DISABLED', ...) - Determine if the passed in event matches 'PLAYER_REGEN_DISABLED
local IsEvent = function(value, ...)
if not select(1, ...) or not value or type(value) ~= 'string' then return end
local event = select(1, ...)
return event == value
end
-- ShortenNumber(12345.67) - Return shortened, rounded value of 12345.67 (12k)
-- ShortenNumber(12345.67, 1) - Return 12345.67 shortened, with 1 decimal place (12.6k)
-- ShortenNumber(12345.67, 1, '%s - %s') - Return 12345.67 shortened, with 1 decimal place using format string '%s - %s' (12.6 - k)
-- @value number - Numeric value to format, shorten, or round.
-- [@decimal] number - (Optional) Number of decimal places to round (default 0)
-- [@pattern] string - (Optional) String pattern value to create output string (default '%s%s')
-- return string - Formatted value
local ShortenNumber = function(value, decimal, pattern)
if (not value) or not (type(value) == 'number') then return end
pattern = pattern or '%s%s'
function round(val, decimal)
if (decimal) then
return math.floor( (val * 10^decimal) + 0.5) / (10^decimal)
else
return math.floor(val+0.5)
end
end
if(value > 999999999) then return (pattern):format(round(value/1000000000, decimal), 'b') end
if(value > 999999) then return (pattern):format(round(value/1000000, decimal), 'm') end
if(value > 999) then return (pattern):format(round(value/1000, decimal), 'k') end
return (pattern):format(round(value, decimal), '')
end
-- TimeToEnergy() - Return time (in seconds) until player reaches 100 energy.
-- TimeToEnergy(70) - Return time until player reaches 70 energy.
-- [@energy] integer - (Optional) Max energy value to calculate time to reach. Default: 100
-- return number - Time (in seconds) for energy to reach specified value.
local TimeToEnergy = function(energy) return ((energy and energy or 100) - UnitPower('player')) / GetPowerRegen() end
-- UnitIsMinClassification('target', 'elite')
-- UnitIsMinClassification('boss3')
-- @unit string - UnitID to determine classification for
-- [@classification] string - (Optional) Minimum classification to check for (e.g. 'elite','rareelite','worldboss' etc). Defaults to 'elite'.
-- return boolean - Whether param unit is equal to or greater in classification to param classification value.
local UnitIsMinClassification = function(unit, classification)
local VALID_CLASSIFICATIONS = {'trivial','normal','rare','elite','rareelite','worldboss',}
classification = classification or 'elite'
if not UnitExists(unit) then return end
if not tContains(VALID_CLASSIFICATIONS, classification) then return end
local unitIndex, classIndex
for i,v in ipairs(VALID_CLASSIFICATIONS) do
if v == UnitClassification(unit) then unitIndex = i end
if v == classification then classIndex = i end
end
if unitIndex and classIndex then if unitIndex >= classIndex then return true end end
return false
end
-- IsClassInParty('Death Knight') - Determine if a Death Knight is in group
-- IsClassInParty('MONK') - Determine if a Monk is in group
-- IsClassInParty(4) - Determine if a Rogue is in the group (using ClassID number identifier: http://www.wowpedia.org/ClassId)
-- @class string/number - English class name or numeric ClassID to check.
-- return boolean - Whether class in question was found in the group
local IsClassInParty = function(class)
if not class or (not IsInRaid() and not IsInGroup()) then return end
local name, id, classDisplayName, className, classID
if type(class) == 'string' then name = string.upper(string.gsub(class, '(%s+)', '')) elseif type(class) == 'number' then id = class end
for i=1,GetNumGroupMembers() do
local unit = IsInRaid() and ('raid%s'):format(i) or IsInGroup() and ('party%s'):format(i)
if UnitExists(unit) then
classDisplayName, className, classID = UnitClass(unit)
if name then if name == className then return true end elseif id then if id == classID then return true end end
end
end
end
local StringSubstitution = function(text, ...)
for iLists,list in pairs({...}) do
for iItem,item in pairs(list) do
if item.pattern then
if type(item.pattern) == 'table' then
for iPattern,pattern in pairs(item.pattern) do
text = string.gsub(text, ("{%s}"):format(pattern), item.color and ('|cFF%s%s|r'):format(item.color, item.replacement) or item.replacement)
end
elseif type(item.pattern) == 'string' then
text = string.gsub(text, ("{%s}"):format(item.pattern), item.color and ('|cFF%s%s|r'):format(item.color, item.replacement) or item.replacement)
end
end
end
end
return text
end
Retrieve the Grid frame associated with a particular unit for modification.
-- Grid_GetUnitFrame('player') - Retrieve the Grid unit frame for 'player' unit.
-- Grid_GetUnitFrame('Player-3661-06DB7142') - Retrieve the Grid unit frame for 'player' unit (using example GUID).
-- Grid_GetUnitFrame('raid3') - Retrieve the Grid unit frame for 'raid2' unit.
-- @unit string [UnitId or GUID] - Unit to retrieve Grid frame for
-- return frame - Grid unit frame
local Grid_GetUnitFrame = function(unit)
if not IsAddOnLoaded("Grid2") then
return
end
local GridFrame = Grid2:GetModule("Grid2Frame")
local GUID = unit
if not (ParseGUID(unit) == "player") then
GUID = UnitGUID(unit)
end
if not GUID then
if GetPlayerInfoByGUID(unit) then
GUID = unit
end
end
if not GUID then
return
end
for _, frame in pairs(GridFrame.registeredFrames) do
if frame.unit and GUID == UnitGUID(frame.unit) then
return frame
end -- match
end
end
Alter the backdrop color of a Grid unit frame.
local Grid_SetUnitFrameBackdropColor = function(unit, r, g, b, a)
local Grid_GetUnitFrame = function(unit)
if not IsAddOnLoaded("Grid2") then
return
end
local GridFrame = Grid2:GetModule("Grid2Frame")
local GUID = unit
if not (ParseGUID(unit) == "player") then
GUID = UnitGUID(unit)
end
if not GUID then
if GetPlayerInfoByGUID(unit) then
GUID = unit
end
end
if not GUID then
return
end
for _, frame in pairs(GridFrame.registeredFrames) do
if frame.unit and GUID == UnitGUID(frame.unit) then
return frame
end -- match
end
end
local frame = Grid_GetUnitFrame(unit)
if not frame then
return
end
local colors = {
{name = "black", r = 0, g = 0, b = 0, a = 1},
{name = "blue", r = 0, g = 0.2, b = 1, a = 1},
{name = "green", r = 0, g = 1, b = 0, a = 1},
{name = "orange", r = 1, g = 0.5, b = 0, a = 1},
{name = "purple", r = 1, g = 0, b = 1, a = 1},
{name = "red", r = 1, g = 0, b = 0, a = 1},
{name = "white", r = 1, g = 1, b = 1, a = 1},
{name = "yellow", r = 1, g = 1, b = 0, a = 1}
}
-- Convert
if tonumber(r) == nil and type(r) == "string" then
for _, v in pairs(colors) do
if v.name == strlower(r) then
r = v.r
g = v.g
b = v.b
a = v.a
end
end
elseif type(r) == "table" and (r.r or r.g or r.b) then
g = r.g or 1
b = r.b or 1
a = r.a or 1
r = r.r or 1
end
if r and b and g then
frame:SetBackdropColor(r, g, b, a or 1)
end
end
Alter the border color of a Grid unit frame.
local Grid_SetUnitFrameBorderColor = function(unit, r, g, b, a)
local Grid_GetUnitFrame = function(unit)
if not IsAddOnLoaded("Grid2") then
return
end
local GridFrame = Grid2:GetModule("Grid2Frame")
local GUID = unit
if not (ParseGUID(unit) == "player") then
GUID = UnitGUID(unit)
end
if not GUID then
if GetPlayerInfoByGUID(unit) then
GUID = unit
end
end
if not GUID then
return
end
for _, frame in pairs(GridFrame.registeredFrames) do
if frame.unit and GUID == UnitGUID(frame.unit) then
return frame
end -- match
end
end
local frame = Grid_GetUnitFrame(unit)
if not frame then
return
end
local colors = {
{name = "black", r = 0, g = 0, b = 0, a = 1},
{name = "blue", r = 0, g = 0.2, b = 1, a = 1},
{name = "green", r = 0, g = 1, b = 0, a = 1},
{name = "orange", r = 1, g = 0.5, b = 0, a = 1},
{name = "purple", r = 1, g = 0, b = 1, a = 1},
{name = "red", r = 1, g = 0, b = 0, a = 1},
{name = "white", r = 1, g = 1, b = 1, a = 1},
{name = "yellow", r = 1, g = 1, b = 0, a = 1}
}
-- Convert
if tonumber(r) == nil and type(r) == "string" then
for _, v in pairs(colors) do
if v.name == strlower(r) then
r = v.r
g = v.g
b = v.b
a = v.a
end
end
elseif type(r) == "table" and (r.r or r.g or r.b) then
g = r.g or 1
b = r.b or 1
a = r.a or 1
r = r.r or 1
end
if r and b and g then
frame:SetBackdropBorderColor(r, g, b, a or 1)
end
end