Skip to content

Instantly share code, notes, and snippets.

@RA80533
Forked from GabeStah/snippets.md
Created August 28, 2024 01:48
Show Gist options
  • Save RA80533/163c3e8610b3c0693f19f5c1df11fec0 to your computer and use it in GitHub Desktop.
Save RA80533/163c3e8610b3c0693f19f5c1df11fec0 to your computer and use it in GitHub Desktop.
World of Warcraft WeakAuras / Lua Functions

Custom Values

SetValue

-- 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(...)
-- ... = 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

Displays

GetRegion

-- 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

-- 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

-- 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

-- 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

-- 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

-- 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

Distance

DistanceBetweenPoints

-- 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

-- 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

-- 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

-- 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

-- 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

Timers

HasTimeElapsed

-- 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.

Timer Set

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

Aura

GetUnitAuraValue

-- 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

--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

GetAuraByType

-- 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

-- 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

COMBAT_LOG Functions

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

-- 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

-- 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

-- 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

-- 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

-- 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

-- 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

-- 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

-- 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

-- 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

-- 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

-- 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

-- 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

Spell Info

GetSpellCooldown

-- 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

-- 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

-- 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

UnitCastingTime

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

UnitChannelingTime

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

UnitIsCasting

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

UnitIsChanneling

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

Talents/Specializations

HasTalent

-- 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

Miscellaneous

ParseGUID

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

-- 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

-- 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

GetVengeanceCapValue

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

-- 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

-- 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

-- 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

-- 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

-- 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

-- 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

-- 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

StringSubstitutions

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

Grid

Grid_GetUnitFrame

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

Grid_SetUnitFrameBackdropColor

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

Grid_SetUnitFrameBorderColor

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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment