local ADDON_NAME = "HailMaryGuildTools" local HMGT = LibStub("AceAddon-3.0"):GetAddon(ADDON_NAME) if not HMGT then return end HMGT.TrackerAvailability = HMGT.TrackerAvailability or {} local internals = HMGT.TrackerInternals or {} local GetPlayerAuraApplications = internals.GetPlayerAuraApplications local GetSpellCastCountInfo = internals.GetSpellCastCountInfo function HMGT:GetOwnAvailabilityProgress(spellEntry) local availability = self:GetAvailabilityConfig(spellEntry) if not availability then return nil, nil end local required = self:GetAvailabilityRequiredCount(spellEntry) if required <= 0 then return nil, nil end local current = 0 if availability.type == "auraStacks" then current = GetPlayerAuraApplications and GetPlayerAuraApplications(availability.auraSpellId) or 0 if current <= 0 then local fallbackSpellId = tonumber(availability.fallbackSpellCountId) or tonumber(availability.progressSpellId) or tonumber(spellEntry and spellEntry.spellId) if fallbackSpellId and fallbackSpellId > 0 and GetSpellCastCountInfo then current = GetSpellCastCountInfo(fallbackSpellId) end end else return nil, nil end current = math.max(0, math.min(required, tonumber(current) or 0)) return current, required end function HMGT:GetAvailabilityState(playerName, spellId) local state = self:GetAvailabilityStateEntry(playerName, spellId) if not state then return nil, nil end return tonumber(state.current) or 0, tonumber(state.max) or 0 end function HMGT:HasAvailabilityState(playerName, spellId) local _, max = self:GetAvailabilityState(playerName, spellId) return (tonumber(max) or 0) > 0 end function HMGT:StoreAvailabilityState(playerName, spellId, current, max, spellEntry) local normalizedName = self:NormalizePlayerName(playerName) local sid = tonumber(spellId) if not normalizedName or not sid or sid <= 0 then return false end local maxCount = math.max(0, math.floor((tonumber(max) or 0) + 0.5)) if maxCount <= 0 then return self:ClearAvailabilityState(normalizedName, sid) end local currentCount = math.max(0, math.min(maxCount, math.floor((tonumber(current) or 0) + 0.5))) local previous = self:GetAvailabilityStateEntry(normalizedName, sid) local changed = (not previous) or (tonumber(previous.current) or -1) ~= currentCount or (tonumber(previous.max) or -1) ~= maxCount self:SetAvailabilityStateEntry(normalizedName, sid, { current = currentCount, max = maxCount, spellEntry = spellEntry, updatedAt = GetTime(), }) return changed end function HMGT:RefreshOwnAvailabilitySpell(spellEntry) if not self:IsAvailabilitySpell(spellEntry) then return false end local playerName = self:NormalizePlayerName(UnitName("player")) if not playerName then return false end local current, max = self:GetOwnAvailabilityProgress(spellEntry) if (tonumber(max) or 0) > 0 then local pData = self.playerData[playerName] if pData and type(pData.knownSpells) == "table" then pData.knownSpells[tonumber(spellEntry.spellId)] = true end end return self:StoreAvailabilityState(playerName, spellEntry.spellId, current, max, spellEntry) end function HMGT:RefreshOwnAvailabilityStates() local playerName = self:NormalizePlayerName(UnitName("player")) local pData = playerName and self.playerData[playerName] if not pData or not pData.class or not pData.specIndex then return false end local changed = false local groupCooldowns = HMGT_SpellData.GetSpellsForSpec(pData.class, pData.specIndex, HMGT_SpellData.GroupCooldowns) for _, spellEntry in ipairs(groupCooldowns or {}) do if self:IsAvailabilitySpell(spellEntry) and self:RefreshOwnAvailabilitySpell(spellEntry) then changed = true end end if self:PruneAvailabilityStates(playerName, pData.knownSpells or {}) then changed = true end return changed end function HMGT:RefreshAndPublishOwnAvailabilityStates() local playerName = self:NormalizePlayerName(UnitName("player")) local pData = playerName and self.playerData[playerName] if not pData or not pData.class or not pData.specIndex then return false end local changed = false local groupCooldowns = HMGT_SpellData.GetSpellsForSpec(pData.class, pData.specIndex, HMGT_SpellData.GroupCooldowns) for _, spellEntry in ipairs(groupCooldowns or {}) do if self:IsAvailabilitySpell(spellEntry) and self:RefreshOwnAvailabilitySpell(spellEntry) then self:PublishOwnSpellState(spellEntry.spellId, { sendLegacy = true }) changed = true end end if self:PruneAvailabilityStates(playerName, pData.knownSpells or {}) then changed = true end return changed end function HMGT:SendOwnAvailabilityStates(target) local playerName = self:NormalizePlayerName(UnitName("player")) local pData = playerName and self.playerData[playerName] if not pData or not pData.class or not pData.specIndex then return 0 end self:RefreshOwnAvailabilityStates() local sent = 0 local groupCooldowns = HMGT_SpellData.GetSpellsForSpec(pData.class, pData.specIndex, HMGT_SpellData.GroupCooldowns) for _, spellEntry in ipairs(groupCooldowns or {}) do if self:IsAvailabilitySpell(spellEntry) and self:IsTrackedSpellKnownForPlayer(playerName, spellEntry.spellId) then local current, max = self:GetAvailabilityState(playerName, spellEntry.spellId) if (tonumber(max) or 0) > 0 then self:BroadcastAvailabilityState(spellEntry.spellId, current, max, target) sent = sent + 1 end end end return sent end