966 lines
24 KiB
Lua
966 lines
24 KiB
Lua
--
|
|
-- **LibCompat-1.0** provided few handy functions that can be embed to addons.
|
|
-- This library was originally created for Skada as of 1.8.50.
|
|
-- @author: Kader B (https://github.com/bkader)
|
|
--
|
|
|
|
local MAJOR, MINOR = "LibCompat-1.0", 16
|
|
local LibCompat, oldminor = LibStub:NewLibrary(MAJOR, MINOR)
|
|
if not LibCompat then return end
|
|
|
|
LibCompat.embeds = LibCompat.embeds or {}
|
|
|
|
local pairs, ipairs, select, type = pairs, ipairs, select, type
|
|
local tinsert, tremove, tconcat, wipe = table.insert, table.remove, table.concat, wipe
|
|
local floor, ceil, max = math.floor, math.ceil, math.max
|
|
local setmetatable, format = setmetatable, string.format
|
|
local CreateFrame = CreateFrame
|
|
|
|
-------------------------------------------------------------------------------
|
|
|
|
do
|
|
local tostring = tostring
|
|
|
|
local tmp = {}
|
|
local function Print(self, frame, ...)
|
|
local n = 0
|
|
if self ~= LibCompat then
|
|
n = n + 1
|
|
tmp[n] = "|cff33ff99" .. tostring(self) .. "|r:"
|
|
end
|
|
for i = 1, select("#", ...) do
|
|
n = n + 1
|
|
tmp[n] = tostring(select(i, ...))
|
|
end
|
|
frame:AddMessage(tconcat(tmp, " ", 1, n))
|
|
end
|
|
|
|
function LibCompat:Print(...)
|
|
local frame = ...
|
|
if type(frame) == "table" and frame.AddMessage then
|
|
return Print(self, frame, select(2, ...))
|
|
end
|
|
return Print(self, DEFAULT_CHAT_FRAME, ...)
|
|
end
|
|
|
|
function LibCompat:Printf(...)
|
|
local frame = ...
|
|
if type(frame) == "table" and frame.AddMessage then
|
|
return Print(self, frame, format(select(2, ...)))
|
|
else
|
|
return Print(self, DEFAULT_CHAT_FRAME, format(...))
|
|
end
|
|
end
|
|
end
|
|
|
|
-------------------------------------------------------------------------------
|
|
|
|
do
|
|
local pcall = pcall
|
|
|
|
local function DispatchError(err)
|
|
print("|cffff9900Error|r:" .. (err or "<no error given>"))
|
|
end
|
|
|
|
function LibCompat.QuickDispatch(func, ...)
|
|
if type(func) ~= "function" then
|
|
return
|
|
end
|
|
local ok, err = pcall(func, ...)
|
|
if not ok then
|
|
DispatchError(err)
|
|
return
|
|
end
|
|
return true
|
|
end
|
|
end
|
|
|
|
-------------------------------------------------------------------------------
|
|
|
|
do
|
|
local function SafePack(...)
|
|
local tbl = {...}
|
|
tbl.n = select("#", ...)
|
|
return tbl
|
|
end
|
|
|
|
local function SafeUnpack(tbl)
|
|
return unpack(tbl, 1, tbl.n)
|
|
end
|
|
|
|
local function tLength(tbl)
|
|
local len = 0
|
|
for _ in pairs(tbl) do
|
|
len = len + 1
|
|
end
|
|
return len
|
|
end
|
|
|
|
-- copies a table from another
|
|
local function tCopy(to, from, ...)
|
|
for k, v in pairs(from) do
|
|
local skip = false
|
|
if ... then
|
|
for i, j in ipairs(...) do
|
|
if j == k then
|
|
skip = true
|
|
break
|
|
end
|
|
end
|
|
end
|
|
if not skip then
|
|
if type(v) == "table" then
|
|
to[k] = {}
|
|
tCopy(to[k], v, ...)
|
|
else
|
|
to[k] = v
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local function tAppendAll(tbl, elems)
|
|
for _, elem in ipairs(elems) do
|
|
tinsert(tbl, elem)
|
|
end
|
|
end
|
|
|
|
local weaktable = {__mode = "v"}
|
|
local function WeakTable(t)
|
|
return setmetatable(wipe(t or {}), weaktable)
|
|
end
|
|
|
|
-- Shamelessly copied from Omen - thanks!
|
|
local tablePool = setmetatable({}, {__mode = "kv"})
|
|
|
|
-- get a new table
|
|
local function newTable(...)
|
|
local t = next(tablePool)
|
|
if t then
|
|
tablePool[t] = nil
|
|
for i = 1, select("#", ...) do
|
|
t[i] = select(i, ...)
|
|
end
|
|
return t
|
|
else
|
|
return {...}
|
|
end
|
|
end
|
|
|
|
-- delete table and return to pool
|
|
local function delTable(t, recursive)
|
|
if type(t) == "table" then
|
|
for k, v in pairs(t) do
|
|
if recursive and type(v) == "table" then
|
|
delTable(v, recursive)
|
|
end
|
|
t[k] = nil
|
|
end
|
|
t[true] = true
|
|
t[true] = nil
|
|
setmetatable(t, nil)
|
|
tablePool[t] = true
|
|
end
|
|
return nil
|
|
end
|
|
|
|
LibCompat.SafePack = SafePack
|
|
LibCompat.SafeUnpack = SafeUnpack
|
|
LibCompat.tLength = tLength
|
|
LibCompat.tCopy = tCopy
|
|
LibCompat.tAppendAll = tAppendAll
|
|
LibCompat.WeakTable = WeakTable
|
|
LibCompat.newTable = newTable
|
|
LibCompat.delTable = delTable
|
|
end
|
|
|
|
-------------------------------------------------------------------------------
|
|
|
|
do
|
|
local function Round(val)
|
|
return (val < 0.0) and ceil(val - 0.5) or floor(val + 0.5)
|
|
end
|
|
|
|
local function Square(val)
|
|
return val * val
|
|
end
|
|
|
|
local function Clamp(val, minval, maxval)
|
|
return (val > maxval) and maxval or (val < minval) and minval or val
|
|
end
|
|
|
|
local function WithinRange(val, minval, maxval)
|
|
return val >= minval and val <= maxval
|
|
end
|
|
|
|
local function WithinRangeExclusive(val, minval, maxval)
|
|
return val > minval and val < maxval
|
|
end
|
|
|
|
LibCompat.Round = Round
|
|
LibCompat.Square = Square
|
|
LibCompat.Clamp = Clamp
|
|
LibCompat.WithinRange = WithinRange
|
|
LibCompat.WithinRangeExclusive = WithinRangeExclusive
|
|
end
|
|
|
|
-------------------------------------------------------------------------------
|
|
|
|
do
|
|
local GetNumRaidMembers, GetNumPartyMembers = GetNumRaidMembers, GetNumPartyMembers
|
|
local UnitExists, UnitAffectingCombat, UnitIsDeadOrGhost = UnitExists, UnitAffectingCombat, UnitIsDeadOrGhost
|
|
local UnitHealth, UnitHealthMax = UnitHealth, UnitHealthMax
|
|
local UnitPower, UnitPowerMax = UnitPower, UnitPowerMax
|
|
|
|
local function IsInRaid()
|
|
return (GetNumRaidMembers() > 0)
|
|
end
|
|
|
|
local function IsInGroup()
|
|
return (GetNumRaidMembers() > 0 or GetNumPartyMembers() > 0)
|
|
end
|
|
|
|
local function GetNumGroupMembers()
|
|
return IsInRaid() and GetNumRaidMembers() or GetNumPartyMembers()
|
|
end
|
|
|
|
local function GetNumSubgroupMembers()
|
|
return GetNumPartyMembers()
|
|
end
|
|
|
|
local function GetGroupTypeAndCount()
|
|
if IsInRaid() then
|
|
return "raid", 1, GetNumRaidMembers()
|
|
elseif IsInGroup() then
|
|
return "party", 0, GetNumPartyMembers()
|
|
else
|
|
return nil, 0, 0
|
|
end
|
|
end
|
|
|
|
local UnitIterator, roster, _
|
|
do
|
|
local rmem, pmem, step, count
|
|
|
|
local function SelfIterator()
|
|
while step do
|
|
local unit, owner
|
|
if step == 1 then
|
|
unit, owner, step = "player", nil, 2
|
|
elseif step == 2 then
|
|
unit, owner, step = "playerpet", "player", nil
|
|
end
|
|
if unit and UnitExists(unit) then
|
|
return unit, owner
|
|
end
|
|
end
|
|
end
|
|
|
|
local function PartyIterator()
|
|
while step do
|
|
local unit, owner
|
|
if step <= 2 then
|
|
unit, owner = SelfIterator()
|
|
step = step or 3
|
|
elseif step == 3 then
|
|
unit, owner, step = format("party%d", count), nil, 4
|
|
elseif step == 4 then
|
|
unit, owner = format("partypet%d", count), format("party%d", count)
|
|
count = count + 1
|
|
step = count <= pmem and 3 or nil
|
|
end
|
|
if unit and UnitExists(unit) then
|
|
return unit, owner
|
|
end
|
|
end
|
|
end
|
|
|
|
local function RaidIterator()
|
|
while step do
|
|
local unit, owner
|
|
if step == 1 then
|
|
unit, owner, step = format("raid%d", count), nil, 2
|
|
elseif step == 2 then
|
|
unit, owner = format("raidpet%d", count), format("raid%d", count)
|
|
count = count + 1
|
|
step = count <= rmem and 1 or nil
|
|
end
|
|
if unit and UnitExists(unit) then
|
|
return unit, owner
|
|
end
|
|
end
|
|
end
|
|
|
|
function UnitIterator()
|
|
rmem, step = GetNumRaidMembers(), 1
|
|
if rmem == 0 then
|
|
pmem = GetNumPartyMembers()
|
|
if pmem == 0 then
|
|
return SelfIterator, false
|
|
end
|
|
count = 1
|
|
return PartyIterator, false
|
|
end
|
|
count = 1
|
|
return RaidIterator, true
|
|
end
|
|
end
|
|
|
|
local function IsGroupDead()
|
|
roster, _ = UnitIterator()
|
|
for unit in roster do
|
|
if not UnitIsDeadOrGhost(unit) then
|
|
return false
|
|
end
|
|
end
|
|
return true
|
|
end
|
|
|
|
local function IsGroupInCombat()
|
|
roster, _ = UnitIterator()
|
|
for unit in roster do
|
|
if UnitAffectingCombat(unit) then
|
|
return true
|
|
end
|
|
end
|
|
return false
|
|
end
|
|
|
|
local function GroupIterator(func, ...)
|
|
roster, _ = UnitIterator()
|
|
for unit, owner in roster do
|
|
LibCompat.QuickDispatch(func, unit, owner, ...)
|
|
end
|
|
end
|
|
|
|
local function GetUnitIdFromGUID(guid, specific)
|
|
if specific == nil or specific == "boss" then
|
|
for i = 1, 4 do
|
|
if UnitExists("boss" .. i) and UnitGUID("boss" .. i) == guid then
|
|
return "boss" .. i
|
|
end
|
|
end
|
|
end
|
|
|
|
if specific == nil or specific == "player" then
|
|
if UnitExists("target") and UnitGUID("target") == guid then
|
|
return "target"
|
|
elseif UnitExists("focus") and UnitGUID("focus") == guid then
|
|
return "focus"
|
|
elseif UnitExists("targettarget") and UnitGUID("targettarget") == guid then
|
|
return "targettarget"
|
|
elseif UnitExists("focustarget") and UnitGUID("focustarget") == guid then
|
|
return "focustarget"
|
|
elseif UnitExists("mouseover") and UnitGUID("mouseover") == guid then
|
|
return "mouseover"
|
|
end
|
|
end
|
|
|
|
if specific == nil or specific == "group" then
|
|
roster, _ = UnitIterator()
|
|
for unit in roster do
|
|
if UnitGUID(unit) == guid then
|
|
return unit
|
|
elseif UnitExists(unit .. "target") and UnitGUID(unit .. "target") == guid then
|
|
return unit .. "target"
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local function GetClassFromGUID(guid)
|
|
local unit = GetUnitIdFromGUID(guid)
|
|
local class
|
|
if unit and unit:find("pet") then
|
|
class = "PET"
|
|
elseif unit and unit:find("boss") then
|
|
class = "BOSS"
|
|
elseif unit then
|
|
class = select(2, UnitClass(unit))
|
|
end
|
|
return class, unit
|
|
end
|
|
|
|
local function GetCreatureId(guid)
|
|
return guid and tonumber(guid:sub(9, 12), 16) or 0
|
|
end
|
|
|
|
local function GetUnitCreatureId(unit)
|
|
return GetCreatureId(UnitGUID(unit))
|
|
end
|
|
|
|
local function UnitHealthInfo(unit, guid)
|
|
unit = unit or guid and GetUnitIdFromGUID(guid)
|
|
local percent, health, maxhealth
|
|
if unit and UnitExists(unit) then
|
|
health, maxhealth = UnitHealth(unit), UnitHealthMax(unit)
|
|
if health and maxhealth then
|
|
percent = 100 * health / max(1, maxhealth)
|
|
end
|
|
end
|
|
return percent, health, maxhealth
|
|
end
|
|
|
|
local function UnitPowerInfo(unit, guid, powerType)
|
|
unit = unit or guid and GetUnitIdFromGUID(guid)
|
|
local percent, power, maxpower
|
|
if unit and UnitExists(unit) then
|
|
power, maxpower = UnitPower(unit, powerType), UnitPowerMax(unit, powerType)
|
|
if power and maxpower then
|
|
percent = 100 * power / max(1, maxpower)
|
|
end
|
|
end
|
|
return percent, power, maxpower
|
|
end
|
|
|
|
local function UnitFullName(unit)
|
|
local name, realm = UnitName(unit)
|
|
local namerealm = realm and realm ~= "" and name .. "-" .. realm or name
|
|
return namerealm
|
|
end
|
|
|
|
LibCompat.IsInRaid = IsInRaid
|
|
LibCompat.IsInGroup = IsInGroup
|
|
LibCompat.GetNumGroupMembers = GetNumGroupMembers
|
|
LibCompat.GetNumSubgroupMembers = GetNumSubgroupMembers
|
|
LibCompat.GetGroupTypeAndCount = GetGroupTypeAndCount
|
|
LibCompat.IsGroupDead = IsGroupDead
|
|
LibCompat.IsGroupInCombat = IsGroupInCombat
|
|
LibCompat.GroupIterator = GroupIterator
|
|
LibCompat.UnitIterator = UnitIterator
|
|
LibCompat.GetUnitIdFromGUID = GetUnitIdFromGUID
|
|
LibCompat.GetClassFromGUID = GetClassFromGUID
|
|
LibCompat.GetCreatureId = GetCreatureId
|
|
LibCompat.GetUnitCreatureId = GetUnitCreatureId
|
|
LibCompat.UnitHealthInfo = UnitHealthInfo
|
|
LibCompat.UnitHealthPercent = UnitHealthInfo -- backward compatibility
|
|
LibCompat.UnitPowerInfo = UnitPowerInfo
|
|
LibCompat.UnitFullName = UnitFullName
|
|
end
|
|
|
|
-------------------------------------------------------------------------------
|
|
|
|
do
|
|
local IsRaidLeader, GetPartyLeaderIndex = IsRaidLeader, GetPartyLeaderIndex
|
|
local GetRealNumRaidMembers, GetRaidRosterInfo = GetRealNumRaidMembers, GetRaidRosterInfo
|
|
|
|
local function UnitIsGroupLeader(unit)
|
|
if LibCompat.IsInRaid() then
|
|
if unit == "player" then
|
|
return IsRaidLeader()
|
|
end
|
|
|
|
local rank = select(2, GetRaidRosterInfo(unit:match("%d+")))
|
|
return (rank and rank == 2)
|
|
end
|
|
|
|
if unit == "player" then
|
|
return (GetPartyLeaderIndex() == 0)
|
|
end
|
|
local index = unit:match("%d+")
|
|
return (index and index == GetPartyLeaderIndex())
|
|
end
|
|
|
|
local function UnitIsGroupAssistant(unit)
|
|
for i = 1, GetRealNumRaidMembers() do
|
|
local name, rank = GetRaidRosterInfo(i)
|
|
if name == UnitName(unit) then
|
|
return (rank == 1)
|
|
end
|
|
end
|
|
return false
|
|
end
|
|
|
|
LibCompat.UnitIsGroupLeader = UnitIsGroupLeader
|
|
LibCompat.UnitIsGroupAssistant = UnitIsGroupAssistant
|
|
end
|
|
|
|
-------------------------------------------------------------------------------
|
|
-- Class Colors
|
|
|
|
do
|
|
local classColorsTable
|
|
local colors = CUSTOM_CLASS_COLORS or RAID_CLASS_COLORS
|
|
|
|
local function GetClassColorsTable()
|
|
if not classColorsTable then
|
|
-- add missing class color strings
|
|
colors.DEATHKNIGHT.colorStr = "ffc41f3b"
|
|
colors.DRUID.colorStr = "ffff7d0a"
|
|
colors.HUNTER.colorStr = "ffabd473"
|
|
colors.MAGE.colorStr = "ff3fc7eb"
|
|
colors.PALADIN.colorStr = "fff58cba"
|
|
colors.PRIEST.colorStr = "ffffffff"
|
|
colors.ROGUE.colorStr = "fffff569"
|
|
colors.SHAMAN.colorStr = "ff0070de"
|
|
colors.WARLOCK.colorStr = "ff8788ee"
|
|
colors.WARRIOR.colorStr = "ffc79c6e"
|
|
|
|
-- cache it once and for all.
|
|
classColorsTable = {}
|
|
for class, tbl in pairs(colors) do
|
|
classColorsTable[class] = tbl
|
|
end
|
|
end
|
|
|
|
return classColorsTable
|
|
end
|
|
|
|
local function GetClassColorObj(class)
|
|
classColorsTable = classColorsTable or GetClassColorsTable()
|
|
return class and classColorsTable[class]
|
|
end
|
|
|
|
local function GetClassColor(class)
|
|
local obj = GetClassColorObj(class)
|
|
if obj then
|
|
return obj.r, obj.g, obj.b, obj.colorStr
|
|
end
|
|
return 1, 1, 1, "ffffffff"
|
|
end
|
|
|
|
LibCompat.GetClassColorsTable = GetClassColorsTable
|
|
LibCompat.GetClassColorObj = GetClassColorObj
|
|
LibCompat.GetClassColor = GetClassColor
|
|
end
|
|
|
|
-------------------------------------------------------------------------------
|
|
-- C_Timer mimic
|
|
|
|
do
|
|
local TickerPrototype, waitTable = {}, {}
|
|
local TickerMetatable = {__index = TickerPrototype, __metatable = true}
|
|
|
|
local waitFrame = LibCompat_TimerFrame or CreateFrame("Frame", "LibCompat_TimerFrame", UIParent)
|
|
waitFrame:SetScript("OnUpdate", function(self, elapsed)
|
|
local total = #waitTable
|
|
for i = 1, total do
|
|
local ticker = waitTable[i]
|
|
|
|
if ticker then
|
|
if ticker._cancelled then
|
|
tremove(waitTable, i)
|
|
elseif ticker._delay > elapsed then
|
|
ticker._delay = ticker._delay - elapsed
|
|
i = i + 1
|
|
else
|
|
ticker._callback(ticker, LibCompat.SafeUnpack(ticker._args))
|
|
|
|
if ticker._iterations == -1 then
|
|
ticker._delay = ticker._duration
|
|
i = i + 1
|
|
elseif ticker._iterations > 1 then
|
|
ticker._iterations = ticker._iterations - 1
|
|
ticker._delay = ticker._duration
|
|
i = i + 1
|
|
elseif ticker._iterations == 1 then
|
|
tremove(waitTable, i)
|
|
total = total - 1
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
if #waitTable == 0 then
|
|
self:Hide()
|
|
end
|
|
end)
|
|
|
|
local function AddDelayedCall(ticker, oldTicker)
|
|
if oldTicker and type(oldTicker) == "table" then
|
|
ticker = oldTicker
|
|
end
|
|
|
|
tinsert(waitTable, ticker)
|
|
waitFrame:Show()
|
|
end
|
|
|
|
local function CreateTicker(duration, callback, iterations, ...)
|
|
local ticker = setmetatable({}, TickerMetatable)
|
|
|
|
ticker._iterations = iterations or -1
|
|
ticker._duration = duration
|
|
ticker._delay = duration
|
|
ticker._callback = callback
|
|
ticker._args = LibCompat.SafePack(...)
|
|
|
|
AddDelayedCall(ticker)
|
|
return ticker
|
|
end
|
|
|
|
function TickerPrototype:IsCancelled()
|
|
return self._cancelled
|
|
end
|
|
|
|
function TickerPrototype:Cancel()
|
|
self._cancelled = true
|
|
end
|
|
|
|
local function After(duration, callback, ...)
|
|
AddDelayedCall({
|
|
_iterations = 1,
|
|
_delay = duration,
|
|
_callback = callback,
|
|
_args = LibCompat.SafePack(...)
|
|
})
|
|
end
|
|
|
|
local function NewTimer(duration, callback, ...)
|
|
return CreateTicker(duration, callback, 1, ...)
|
|
end
|
|
|
|
local function NewTicker(duration, callback, iterations, ...)
|
|
return CreateTicker(duration, callback, iterations, ...)
|
|
end
|
|
|
|
local function CancelTimer(ticker)
|
|
if ticker and type(ticker.Cancel) == "function" then
|
|
ticker:Cancel()
|
|
end
|
|
return nil -- return nil to assign input reference
|
|
end
|
|
|
|
LibCompat.After = After
|
|
LibCompat.NewTimer = NewTimer
|
|
LibCompat.NewTicker = NewTicker
|
|
LibCompat.CancelTimer = CancelTimer
|
|
end
|
|
|
|
-------------------------------------------------------------------------------
|
|
|
|
do
|
|
local GetSpellInfo, GetSpellLink = GetSpellInfo, GetSpellLink
|
|
|
|
local custom = {
|
|
[3] = {ACTION_ENVIRONMENTAL_DAMAGE_FALLING, "Interface\\Icons\\ability_rogue_quickrecovery"},
|
|
[4] = {ACTION_ENVIRONMENTAL_DAMAGE_DROWNING, "Interface\\Icons\\spell_shadow_demonbreath"},
|
|
[5] = {ACTION_ENVIRONMENTAL_DAMAGE_FATIGUE, "Interface\\Icons\\ability_creature_cursed_05"},
|
|
[6] = {ACTION_ENVIRONMENTAL_DAMAGE_FIRE, "Interface\\Icons\\spell_fire_fire"},
|
|
[7] = {ACTION_ENVIRONMENTAL_DAMAGE_LAVA, "Interface\\Icons\\spell_shaman_lavaflow"},
|
|
[8] = {ACTION_ENVIRONMENTAL_DAMAGE_SLIME, "Interface\\Icons\\inv_misc_slime_01"}
|
|
}
|
|
|
|
local function _GetSpellInfo(spellid)
|
|
local res1, res2, res3, res4, res5, res6, res7, res8, res9
|
|
if spellid then
|
|
if custom[spellid] then
|
|
res1, res3 = custom[spellid][1], custom[spellid][2]
|
|
else
|
|
res1, res2, res3, res4, res5, res6, res7, res8, res9 = GetSpellInfo(spellid)
|
|
if spellid == 75 then
|
|
res3 = "Interface\\Icons\\INV_Weapon_Bow_07"
|
|
elseif spellid == 6603 then
|
|
res1, res3 = MELEE, "Interface\\Icons\\INV_Sword_04"
|
|
end
|
|
end
|
|
end
|
|
return res1, res2, res3, res4, res5, res6, res7, res8, res9
|
|
end
|
|
|
|
local function _GetSpellLink(spellid)
|
|
if not custom[spellid] then
|
|
return GetSpellLink(spellid)
|
|
end
|
|
end
|
|
|
|
LibCompat.GetSpellInfo = _GetSpellInfo
|
|
LibCompat.GetSpellLink = _GetSpellLink
|
|
end
|
|
|
|
-------------------------------------------------------------------------------
|
|
|
|
do
|
|
local band, rshift, lshift = bit.band, bit.rshift, bit.lshift
|
|
local byte, char = string.byte, string.char
|
|
|
|
local function HexEncode(str, title)
|
|
local hex = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"}
|
|
local t = (title and title ~= "") and {format("[=== %s ===]", title)} or {}
|
|
local j = 0
|
|
for i = 1, #str do
|
|
if j <= 0 then
|
|
t[#t + 1], j = "\n", 32
|
|
end
|
|
j = j - 1
|
|
|
|
local b = byte(str, i)
|
|
t[#t + 1] = hex[band(b, 15) + 1]
|
|
t[#t + 1] = hex[band(rshift(b, 4), 15) + 1]
|
|
end
|
|
if title and title ~= "" then
|
|
t[#t + 1] = "\n" .. t[1]
|
|
end
|
|
return tconcat(t)
|
|
end
|
|
|
|
local function HexDecode(str)
|
|
str = str:gsub("%[.-%]", ""):gsub("[^0123456789ABCDEF]", "")
|
|
if (#str == 0) or (#str % 2 ~= 0) then
|
|
return false, "Invalid Hex string"
|
|
end
|
|
|
|
local t, bl, bh = {}
|
|
local i = 1
|
|
repeat
|
|
bl = byte(str, i)
|
|
bl = bl >= 65 and bl - 55 or bl - 48
|
|
i = i + 1
|
|
bh = byte(str, i)
|
|
bh = bh >= 65 and bh - 55 or bh - 48
|
|
i = i + 1
|
|
t[#t + 1] = char(lshift(bh, 4) + bl)
|
|
until i >= #str
|
|
return tconcat(t)
|
|
end
|
|
|
|
local function EscapeStr(str)
|
|
local res = ""
|
|
for i = 1, str:len() do
|
|
local n = str:sub(i, i)
|
|
res = res .. n
|
|
if n == "|" then
|
|
res = res .. "\124"
|
|
end
|
|
end
|
|
return (res ~= "") and res or str
|
|
end
|
|
|
|
LibCompat.HexEncode = HexEncode
|
|
LibCompat.HexDecode = HexDecode
|
|
LibCompat.EscapeStr = EscapeStr
|
|
end
|
|
|
|
-------------------------------------------------------------------------------
|
|
|
|
do
|
|
local LGT = LibStub("LibGroupTalents-1.0")
|
|
local UnitClass, MAX_TALENT_TABS = UnitClass, MAX_TALENT_TABS or 3
|
|
local GetActiveTalentGroup, GetTalentTabInfo = GetActiveTalentGroup, GetTalentTabInfo
|
|
local LGTRoleTable = {melee = "DAMAGER", caster = "DAMAGER", healer = "HEALER", tank = "TANK"}
|
|
|
|
-- list of class to specs
|
|
local specsTable = {
|
|
["MAGE"] = {62, 63, 64},
|
|
["PRIEST"] = {256, 257, 258},
|
|
["ROGUE"] = {259, 260, 261},
|
|
["WARLOCK"] = {265, 266, 267},
|
|
["WARRIOR"] = {71, 72, 73},
|
|
["PALADIN"] = {65, 66, 70},
|
|
["DEATHKNIGHT"] = {250, 251, 252},
|
|
["DRUID"] = {102, 103, 104, 105},
|
|
["HUNTER"] = {253, 254, 255},
|
|
["SHAMAN"] = {262, 263, 264}
|
|
}
|
|
|
|
local function GetSpecialization(isInspect, isPet, specGroup)
|
|
local currentSpecGroup = GetActiveTalentGroup(isInspect, isPet) or (specGroup or 1)
|
|
local points, specname, specid = 0, nil, nil
|
|
|
|
for i = 1, MAX_TALENT_TABS do
|
|
local name, _, pointsSpent = GetTalentTabInfo(i, isInspect, isPet, currentSpecGroup)
|
|
if points <= pointsSpent then
|
|
points = pointsSpent
|
|
specname = name
|
|
specid = i
|
|
end
|
|
end
|
|
return specid, specname, points
|
|
end
|
|
|
|
-- checks if the feral druid is a cat or tank spec
|
|
local function GetDruidSpec(unit)
|
|
-- 57881 : Natural Reaction -- used by druid tanks
|
|
local points = LGT:UnitHasTalent(unit, LibCompat.GetSpellInfo(57881), LGT:GetActiveTalentGroup(unit))
|
|
return (points and points > 0) and 3 or 2
|
|
end
|
|
|
|
local function GetInspectSpecialization(unit, class)
|
|
local spec -- start with nil
|
|
|
|
if unit and UnitExists(unit) then
|
|
class = class or select(2, UnitClass(unit))
|
|
if class and specsTable[class] then
|
|
local talentGroup = LGT:GetActiveTalentGroup(unit)
|
|
local maxPoints, index = 0, 0
|
|
|
|
for i = 1, MAX_TALENT_TABS do
|
|
local _, _, pointsSpent = LGT:GetTalentTabInfo(unit, i, talentGroup)
|
|
if pointsSpent ~= nil then
|
|
if maxPoints < pointsSpent then
|
|
maxPoints = pointsSpent
|
|
if class == "DRUID" and i >= 2 then
|
|
if i == 3 then
|
|
index = 4
|
|
elseif i == 2 then
|
|
index = GetDruidSpec(unit)
|
|
end
|
|
else
|
|
index = i
|
|
end
|
|
end
|
|
end
|
|
end
|
|
spec = specsTable[class][index]
|
|
end
|
|
end
|
|
|
|
return spec
|
|
end
|
|
|
|
local function GetSpecializationRole(unit)
|
|
return LGTRoleTable[LGT:GetUnitRole(unit or "player")] or "NONE"
|
|
end
|
|
|
|
local function GetSpecializationInfo(specIndex, isInspect, isPet, specGroup)
|
|
local name, icon, _, background = GetTalentTabInfo(specIndex, isInspect, isPet, specGroup)
|
|
local id, role
|
|
if isInspect and UnitExists("target") then
|
|
id, role = GetInspectSpecialization("target"), GetSpecializationRole("target")
|
|
else
|
|
id, role = GetInspectSpecialization("player"), GetSpecializationRole("player")
|
|
end
|
|
return id, name, nil, icon, background, role
|
|
end
|
|
|
|
local function UnitGroupRolesAssigned(unit)
|
|
return LGTRoleTable[LGT:GetUnitRole(unit or "player")] or "NONE"
|
|
end
|
|
|
|
local function GetUnitRole(unit)
|
|
return LGTRoleTable[LGT:GetUnitRole(unit or "player")] or "NONE"
|
|
end
|
|
|
|
local function GetGUIDRole(guid)
|
|
return LGTRoleTable[LGT:GetGUIDRole(guid)] or "NONE"
|
|
end
|
|
|
|
LibCompat.GetSpecialization = GetSpecialization
|
|
LibCompat.GetInspectSpecialization = GetInspectSpecialization
|
|
LibCompat.GetSpecializationRole = GetSpecializationRole
|
|
LibCompat.GetSpecializationInfo = GetSpecializationInfo
|
|
|
|
LibCompat.UnitGroupRolesAssigned = UnitGroupRolesAssigned
|
|
LibCompat.GetUnitRole = UnitGroupRolesAssigned
|
|
LibCompat.GetGUIDRole = GetGUIDRole
|
|
LibCompat.GetUnitSpec = GetInspectSpecialization
|
|
|
|
-- functions that simply replaced other api functions
|
|
LibCompat.GetNumSpecializations = GetNumTalentTabs
|
|
LibCompat.GetNumSpecGroups = GetNumTalentGroups
|
|
LibCompat.GetNumUnspentTalents = GetUnspentTalentPoints
|
|
LibCompat.GetActiveSpecGroup = GetActiveTalentGroup
|
|
LibCompat.SetActiveSpecGroup = SetActiveTalentGroup
|
|
end
|
|
|
|
-------------------------------------------------------------------------------
|
|
|
|
do
|
|
local C_PvP = {}
|
|
local IsInInstance, instanceType = IsInInstance, nil
|
|
|
|
function C_PvP.IsPvPMap()
|
|
instanceType = select(2, IsInInstance())
|
|
return (instanceType == "pvp" or instanceType == "arena")
|
|
end
|
|
|
|
function C_PvP.IsBattleground()
|
|
instanceType = select(2, IsInInstance())
|
|
return (instanceType == "pvp")
|
|
end
|
|
|
|
function C_PvP.IsArena()
|
|
instanceType = select(2, IsInInstance())
|
|
return (instanceType == "arena")
|
|
end
|
|
|
|
LibCompat.IsInPvP = C_PvP.IsPvPMap
|
|
LibCompat.C_PvP = C_PvP
|
|
end
|
|
|
|
-------------------------------------------------------------------------------
|
|
|
|
local mixins = {
|
|
"QuickDispatch",
|
|
-- table util
|
|
"SafePack",
|
|
"SafeUnpack",
|
|
"tLength",
|
|
"tCopy",
|
|
"tAppendAll",
|
|
"WeakTable",
|
|
"newTable",
|
|
"delTable",
|
|
-- math util
|
|
"Round",
|
|
"Square",
|
|
"Clamp",
|
|
"WithinRange",
|
|
"WithinRangeExclusive",
|
|
-- roster util
|
|
"IsInRaid",
|
|
"IsInGroup",
|
|
"IsInPvP",
|
|
"GetNumGroupMembers",
|
|
"GetNumSubgroupMembers",
|
|
"GetGroupTypeAndCount",
|
|
"IsGroupDead",
|
|
"IsGroupInCombat",
|
|
"GroupIterator",
|
|
"UnitIterator",
|
|
"UnitFullName",
|
|
"C_PvP",
|
|
-- unit util
|
|
"GetUnitIdFromGUID",
|
|
"GetClassFromGUID",
|
|
"GetCreatureId",
|
|
"GetUnitCreatureId",
|
|
"UnitHealthInfo",
|
|
"UnitHealthPercent", -- backward compatibility
|
|
"UnitPowerInfo",
|
|
"UnitIsGroupLeader",
|
|
"UnitIsGroupAssistant",
|
|
"GetUnitSpec", -- backward compatibility
|
|
"GetSpecialization",
|
|
"GetInspectSpecialization",
|
|
"GetSpecializationRole",
|
|
"GetNumSpecializations",
|
|
"GetSpecializationInfo",
|
|
"UnitGroupRolesAssigned",
|
|
"GetNumSpecGroups",
|
|
"GetNumUnspentTalents",
|
|
"GetActiveSpecGroup",
|
|
"SetActiveSpecGroup",
|
|
"GetUnitRole",
|
|
"GetGUIDRole",
|
|
-- timer util
|
|
"After",
|
|
"NewTimer",
|
|
"NewTicker",
|
|
"CancelTimer",
|
|
-- spell util
|
|
"GetSpellInfo",
|
|
"GetSpellLink",
|
|
-- misc util
|
|
"HexEncode",
|
|
"HexDecode",
|
|
"EscapeStr",
|
|
"GetClassColorsTable",
|
|
"GetClassColorObj",
|
|
"GetClassColor",
|
|
"Print",
|
|
"Printf"
|
|
}
|
|
|
|
function LibCompat:Embed(target)
|
|
for _, v in pairs(mixins) do
|
|
target[v] = self[v]
|
|
end
|
|
target.locale = target.locale or GetLocale()
|
|
self.embeds[target] = true
|
|
return target
|
|
end
|
|
|
|
for addon in pairs(LibCompat.embeds) do
|
|
LibCompat:Embed(addon)
|
|
end
|