269 lines
10 KiB
Lua
269 lines
10 KiB
Lua
local ADDON_NAME = "HailMaryGuildTools"
|
|
local HMGT = LibStub("AceAddon-3.0"):GetAddon(ADDON_NAME)
|
|
if not HMGT then return end
|
|
|
|
HMGT.TrackerDataProvider = HMGT.TrackerDataProvider or {}
|
|
|
|
local internals = HMGT.TrackerInternals or {}
|
|
local SafeApiNumber = internals.SafeApiNumber
|
|
local GetSpellChargesInfo = internals.GetSpellChargesInfo
|
|
local GetSpellCooldownInfo = internals.GetSpellCooldownInfo
|
|
|
|
function HMGT:GetCooldownInfo(playerName, spellId, opts)
|
|
opts = opts or {}
|
|
local deferUntilEmpty = opts.deferChargeCooldownUntilEmpty and true or false
|
|
local spellEntry = HMGT_SpellData.InterruptLookup[spellId]
|
|
or HMGT_SpellData.CooldownLookup[spellId]
|
|
local ownName = self:NormalizePlayerName(UnitName("player"))
|
|
local isOwnPlayer = playerName == ownName
|
|
local pData = isOwnPlayer and self.playerData[ownName] or nil
|
|
local talents = pData and pData.talents or {}
|
|
local effectiveCd = spellEntry and HMGT_SpellData.GetEffectiveCooldown(spellEntry, talents) or 0
|
|
local knownMaxCharges, knownChargeDuration = 0, 0
|
|
if spellEntry and isOwnPlayer then
|
|
knownMaxCharges, knownChargeDuration = self:GetKnownChargeInfo(spellEntry, talents, spellId, effectiveCd)
|
|
end
|
|
|
|
if self:IsAvailabilitySpell(spellEntry) then
|
|
local normalizedName = self:NormalizePlayerName(playerName)
|
|
if normalizedName == ownName then
|
|
local current, max = self:GetOwnAvailabilityProgress(spellEntry)
|
|
if (tonumber(max) or 0) > 0 then
|
|
self:StoreAvailabilityState(ownName, spellId, current, max, spellEntry)
|
|
return 0, 0, current, max
|
|
end
|
|
else
|
|
local current, max = self:GetAvailabilityState(normalizedName, spellId)
|
|
if (tonumber(max) or 0) > 0 then
|
|
return 0, 0, current, max
|
|
end
|
|
end
|
|
return 0, 0, nil, nil
|
|
end
|
|
|
|
local cdData = self:GetActiveCooldown(playerName, spellId)
|
|
|
|
if isOwnPlayer and not (InCombatLockdown and InCombatLockdown()) then
|
|
local charges, maxCharges, chargeStart, chargeDuration = nil, nil, nil, nil
|
|
if GetSpellChargesInfo then
|
|
charges, maxCharges, chargeStart, chargeDuration = GetSpellChargesInfo(spellId)
|
|
end
|
|
charges = SafeApiNumber and SafeApiNumber(charges, 0) or tonumber(charges) or 0
|
|
maxCharges = SafeApiNumber and SafeApiNumber(maxCharges, 0) or tonumber(maxCharges) or 0
|
|
chargeStart = SafeApiNumber and SafeApiNumber(chargeStart) or tonumber(chargeStart)
|
|
chargeDuration = SafeApiNumber and SafeApiNumber(chargeDuration, 0) or tonumber(chargeDuration) or 0
|
|
|
|
if maxCharges > 0 then
|
|
local tempChargeState = {
|
|
currentCharges = charges,
|
|
maxCharges = maxCharges,
|
|
chargeStart = chargeStart,
|
|
chargeDuration = chargeDuration,
|
|
duration = chargeDuration,
|
|
}
|
|
local remaining, total, curCharges, maxChargeCount = self:ResolveChargeState(tempChargeState)
|
|
self:StoreKnownChargeInfo(spellId, maxChargeCount, total > 0 and total or chargeDuration)
|
|
if (curCharges or 0) < maxChargeCount and remaining <= 0 and GetSpellCooldownInfo then
|
|
local cdStart, cdDuration = GetSpellCooldownInfo(spellId)
|
|
if cdDuration > 0 then
|
|
remaining = math.max(0, cdDuration - (GetTime() - cdStart))
|
|
total = math.max(total or 0, cdDuration)
|
|
end
|
|
end
|
|
if deferUntilEmpty and (curCharges or 0) > 0 then
|
|
remaining = 0
|
|
end
|
|
return remaining, total, curCharges, maxChargeCount
|
|
end
|
|
|
|
if GetSpellCooldownInfo then
|
|
local cdStart, cdDuration = GetSpellCooldownInfo(spellId)
|
|
cdStart = tonumber(cdStart) or 0
|
|
cdDuration = tonumber(cdDuration) or 0
|
|
if cdDuration > 0 then
|
|
local remaining = math.max(0, cdDuration - (GetTime() - cdStart))
|
|
remaining = math.max(0, math.min(cdDuration, remaining))
|
|
if cdData and (tonumber(cdData.maxCharges) or 0) <= 0 then
|
|
local cachedRemaining = (tonumber(cdData.duration) or 0) - (GetTime() - (tonumber(cdData.startTime) or GetTime()))
|
|
cachedRemaining = math.max(0, math.min(tonumber(cdData.duration) or cachedRemaining, cachedRemaining))
|
|
local cachedDuration = math.max(0, tonumber(cdData.duration) or 0)
|
|
if cachedDuration > 2.0 and cachedRemaining > 2.0 and cdDuration < math.max(2.0, cachedDuration * 0.35) then
|
|
return cachedRemaining, cachedDuration, nil, nil
|
|
end
|
|
end
|
|
return remaining, cdDuration, nil, nil
|
|
end
|
|
end
|
|
end
|
|
|
|
if not cdData then
|
|
if isOwnPlayer and knownMaxCharges > 1 then
|
|
return 0, math.max(0, knownChargeDuration or effectiveCd or 0), knownMaxCharges, knownMaxCharges
|
|
end
|
|
return 0, 0, nil, nil
|
|
end
|
|
if (tonumber(cdData.maxCharges) or 0) > 0 then
|
|
local remaining, chargeDur, charges, maxCharges = self:ResolveChargeState(cdData)
|
|
self:StoreKnownChargeInfo(spellId, maxCharges, chargeDur)
|
|
if deferUntilEmpty and charges > 0 then
|
|
remaining = 0
|
|
end
|
|
return remaining, chargeDur, charges, maxCharges
|
|
end
|
|
if isOwnPlayer and knownMaxCharges > 1 then
|
|
local remaining = (tonumber(cdData.duration) or 0) - (GetTime() - (tonumber(cdData.startTime) or GetTime()))
|
|
remaining = math.max(0, math.min(tonumber(cdData.duration) or remaining, remaining))
|
|
local currentCharges = knownMaxCharges
|
|
if remaining > 0 then
|
|
currentCharges = math.max(0, knownMaxCharges - 1)
|
|
end
|
|
if deferUntilEmpty and currentCharges > 0 then
|
|
remaining = 0
|
|
end
|
|
return remaining, math.max(0, knownChargeDuration or effectiveCd or 0), currentCharges, knownMaxCharges
|
|
end
|
|
local remaining = cdData.duration - (GetTime() - cdData.startTime)
|
|
remaining = math.max(0, math.min(cdData.duration, remaining))
|
|
return remaining, cdData.duration, nil, nil
|
|
end
|
|
|
|
function HMGT:ShouldDisplayEntry(settings, remaining, currentCharges, maxCharges, spellEntry)
|
|
local rem = tonumber(remaining) or 0
|
|
local cur = tonumber(currentCharges) or 0
|
|
local max = tonumber(maxCharges) or 0
|
|
local soon = tonumber(settings.readySoonSec) or 0
|
|
local isAvailabilitySpell = spellEntry and self:IsAvailabilitySpell(spellEntry) or false
|
|
local isReady
|
|
|
|
if isAvailabilitySpell then
|
|
isReady = max > 0 and cur >= max
|
|
else
|
|
isReady = rem <= 0 or (max > 0 and cur > 0)
|
|
end
|
|
|
|
if settings.showOnlyReady then
|
|
return isReady
|
|
end
|
|
if soon > 0 then
|
|
if isAvailabilitySpell then
|
|
return isReady
|
|
end
|
|
return isReady or rem <= soon
|
|
end
|
|
return true
|
|
end
|
|
|
|
local DEFAULT_CATEGORY_PRIORITY = {
|
|
interrupt = 1,
|
|
lust = 2,
|
|
defensive = 3,
|
|
tank = 4,
|
|
healing = 5,
|
|
offensive = 6,
|
|
utility = 7,
|
|
cc = 8,
|
|
}
|
|
|
|
local TRACKER_CATEGORY_PRIORITY = {
|
|
interruptTracker = {
|
|
interrupt = 1,
|
|
defensive = 2,
|
|
utility = 3,
|
|
cc = 4,
|
|
healing = 5,
|
|
tank = 6,
|
|
offensive = 7,
|
|
lust = 8,
|
|
},
|
|
raidCooldownTracker = {
|
|
lust = 1,
|
|
defensive = 2,
|
|
healing = 3,
|
|
tank = 4,
|
|
utility = 5,
|
|
offensive = 6,
|
|
cc = 7,
|
|
interrupt = 8,
|
|
},
|
|
groupCooldownTracker = {
|
|
tank = 1,
|
|
defensive = 2,
|
|
healing = 3,
|
|
cc = 4,
|
|
utility = 5,
|
|
offensive = 6,
|
|
lust = 7,
|
|
interrupt = 8,
|
|
},
|
|
}
|
|
|
|
local function GetCategoryPriority(category, trackerKey)
|
|
local cat = tostring(category or "utility")
|
|
local trackerOrder = trackerKey and TRACKER_CATEGORY_PRIORITY[trackerKey]
|
|
if trackerOrder and trackerOrder[cat] then
|
|
return trackerOrder[cat]
|
|
end
|
|
local order = HMGT_SpellData and HMGT_SpellData.CategoryOrder
|
|
if type(order) == "table" then
|
|
for idx, key in ipairs(order) do
|
|
if key == cat then
|
|
return idx
|
|
end
|
|
end
|
|
return #order + 10
|
|
end
|
|
return DEFAULT_CATEGORY_PRIORITY[cat] or 99
|
|
end
|
|
|
|
function HMGT:SortDisplayEntries(entries, trackerKey)
|
|
if type(entries) ~= "table" then return end
|
|
table.sort(entries, function(a, b)
|
|
local aRemaining = tonumber(a and a.remaining) or 0
|
|
local bRemaining = tonumber(b and b.remaining) or 0
|
|
local aActive = aRemaining > 0
|
|
local bActive = bRemaining > 0
|
|
if aActive ~= bActive then
|
|
return aActive
|
|
end
|
|
|
|
local aEntry = a and a.spellEntry
|
|
local bEntry = b and b.spellEntry
|
|
|
|
local aPriority = tonumber(aEntry and aEntry.priority) or GetCategoryPriority(aEntry and aEntry.category, trackerKey)
|
|
local bPriority = tonumber(bEntry and bEntry.priority) or GetCategoryPriority(bEntry and bEntry.category, trackerKey)
|
|
if aPriority ~= bPriority then
|
|
return aPriority < bPriority
|
|
end
|
|
|
|
if aActive and aRemaining ~= bRemaining then
|
|
return aRemaining < bRemaining
|
|
end
|
|
|
|
local aTotal = tonumber(a and a.total)
|
|
or tonumber(aEntry and HMGT_SpellData.GetBaseCooldown and HMGT_SpellData.GetBaseCooldown(aEntry))
|
|
or tonumber(aEntry and aEntry.cooldown)
|
|
or 0
|
|
local bTotal = tonumber(b and b.total)
|
|
or tonumber(bEntry and HMGT_SpellData.GetBaseCooldown and HMGT_SpellData.GetBaseCooldown(bEntry))
|
|
or tonumber(bEntry and bEntry.cooldown)
|
|
or 0
|
|
if (not aActive) and aTotal ~= bTotal then
|
|
return aTotal > bTotal
|
|
end
|
|
|
|
if aRemaining ~= bRemaining then
|
|
return aRemaining < bRemaining
|
|
end
|
|
|
|
local aName = tostring(a and a.playerName or "")
|
|
local bName = tostring(b and b.playerName or "")
|
|
if aName ~= bName then
|
|
return aName < bName
|
|
end
|
|
|
|
local aSpell = tonumber(aEntry and aEntry.spellId) or 0
|
|
local bSpell = tonumber(bEntry and bEntry.spellId) or 0
|
|
return aSpell < bSpell
|
|
end)
|
|
end
|