diff --git a/src/OmicronFrames.toc b/src/OmicronFrames.toc index cbc7486..1b6d960 100644 --- a/src/OmicronFrames.toc +++ b/src/OmicronFrames.toc @@ -11,6 +11,7 @@ types/types.lua types/object.lua types/triggers/trigger.lua types/triggers/auratrigger.lua +types/triggers/statustrigger.lua types/statusbar.lua types/auralist.lua types/indicators/indicator.lua diff --git a/src/types/auralist.lua b/src/types/auralist.lua index 67ac884..f5cb9b1 100644 --- a/src/types/auralist.lua +++ b/src/types/auralist.lua @@ -16,9 +16,9 @@ -- Omicron Frames. If not, see . local omi = select(2, ...) local types = omi.GetModule("types") -local AuraTrigger = types.AuraTrigger --- AuraList keeps track of all the auras attached to a unitframe +---@class AuraList: Object local AuraList = types.CreateClass("AuraList") types.AuraList = AuraList @@ -67,9 +67,16 @@ local function ForEachAura(unit, fn) ForEachAuraFiltered(unit, "HARMFUL", fn) end ---- Initialize AuraList --- unitframe --- The unitframe this list belongs to + +---@return AuraList +function AuraList.new(cls, ...) + --- I really dislike duplicating this everywhere but it makes + --lua-language-server able to deduce the type of Object:new calls and that + --is honestly worth it + return types.Object.new(cls, ...) +end + +---@param unitframe UnitFrame function AuraList:Init(unitframe) self.unitframe = unitframe self.unit = unitframe.unit @@ -80,22 +87,29 @@ function AuraList:Init(unitframe) self.triggers = {} self.triggersBySpell = {} + self.triggersByStatus = {} end ---- Add an AuraTrigger to this AuraList --- trigger --- an AuraTrigger object +---@param trigger AuraTrigger | StatusTrigger function AuraList:AddTrigger(trigger) table.insert(self.triggers, trigger) local spellId = trigger.spellId - if self.triggersBySpell[spellId] == nil then - self.triggersBySpell[spellId] = {} + local status = trigger.status + if spellId then + if self.triggersBySpell[spellId] == nil then + self.triggersBySpell[spellId] = {} + end + table.insert(self.triggersBySpell[spellId], trigger) + else + if self.triggersByStatus[status] == nil then + self.triggersByStatus[status] = {} + end + table.insert(self.triggersByStatus[status], trigger) end - table.insert(self.triggersBySpell[spellId], trigger) end ---- Reset the AuraList and do a full aura scan on the unit --- This also resets all the triggers that are attached to this AuraList +---Reset the AuraList and do a full aura scan on the unit +---This also resets all the triggers that are attached to this AuraList function AuraList:Reset() self.auras = {} @@ -110,9 +124,7 @@ function AuraList:Reset() end) end ---- Add an aura to the AuraList --- aura --- A UnitAuraInfo table for a newly added aura +---@param aura UnitAuraInfo function AuraList:AddAura(aura) local statusChanged = false self.auras[aura.auraInstanceID] = aura @@ -126,6 +138,7 @@ function AuraList:AddAura(aura) else count[status] = count[status] + 1 end + self:UpdateStatusTriggers(status) end for _, trigger in ipairs(self.triggersBySpell[aura.spellId] or {}) do @@ -136,9 +149,20 @@ function AuraList:AddAura(aura) return statusChanged end ---- Return a sequence table with all status names that match the given aura --- aura --- A UnitAuraInfo table +---@param status string +function AuraList:UpdateStatusTriggers(status) + local triggers = self.triggersByStatus[status] + if not triggers then + return + end + local count = self.statusCount[status] or 0 + for _, trigger in ipairs(triggers) do + trigger:UpdateStatus(count) + end +end + +---@param aura UnitAuraInfo +---@return string[] All status names associated with this aura function AuraList:GetStatusForAura(aura) local status = {} if aura.dispelName and aura.isHarmful then @@ -152,9 +176,7 @@ function AuraList:GetStatusForAura(aura) return status end ---- Add an aura to the AuraList --- aura --- A UnitAuraInfo table for a newly added aura +---@param aura UnitAuraInfo function AuraList:UpdateAura(aura) for _, trigger in ipairs(self.triggersBySpell[aura.spellId] or {}) do trigger:UpdateAura(self.auras[aura.auraInstanceId], aura) @@ -162,9 +184,7 @@ function AuraList:UpdateAura(aura) self.auras[aura.auraInstanceID] = aura end ---- Remove an aura from the AuraList --- iid --- The instance id for a removed aura +---@param iid number function AuraList:RemoveAura(iid) local aura = self.auras[iid] if aura == nil then @@ -184,6 +204,7 @@ function AuraList:RemoveAura(iid) else count[status] = count[status] - 1 end + self:UpdateStatusTriggers(status) end for _, trigger in ipairs(self.triggersBySpell[aura.spellId] or {}) do @@ -192,9 +213,7 @@ function AuraList:RemoveAura(iid) return statusChanged end ---- Update an aura in the AuraList --- info --- The new UnitAuraInfo structure +---@param info UnitAuraInfo function AuraList:Update(info) local GetAuraDataByAuraInstanceID = C_UnitAuras.GetAuraDataByAuraInstanceID local statusChanged = false diff --git a/src/types/triggers/statustrigger.lua b/src/types/triggers/statustrigger.lua new file mode 100644 index 0000000..a537ca6 --- /dev/null +++ b/src/types/triggers/statustrigger.lua @@ -0,0 +1,53 @@ +-- Copyright 2023 +-- +-- This file is part of Omicron Frames +-- +-- Omicron Frames is free software: you can redistribute it and/or modify it +-- under the terms of the GNU General Public License as published by the Free +-- Software Foundation, either version 3 of the License, or (at your option) +-- any later version. +-- +-- Omicron Frames is distributed in the hope that it will be useful, but +-- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +-- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +-- more details. +-- +-- You should have received a copy of the GNU General Public License along with +-- Omicron Frames. If not, see . +local omi = select(2, ...) +local types = omi.GetModule("types") +---@class Trigger +local Trigger = types.Trigger + +---StatusTrigger is a trigger that can be attached to AuraList as datasource +---@class StatusTrigger: Trigger +---@field status string +local StatusTrigger = types.CreateClass("StatusTrigger", Trigger) +types.StatusTrigger = StatusTrigger + +---@return StatusTrigger +function StatusTrigger.new(cls, ...) + --- I really dislike duplicating this everywhere but it makes + --lua-language-server able to deduce the type of Object:new calls and that + --is honestly worth it + return types.Object.new(cls, ...) +end + +--- Initialize a new AuraTrigger object +---@param status string The kind of status to trigger on +---@param requiredCount number | nil +---@param invert boolean | nil +function StatusTrigger:Init(status, requiredCount, invert) + Trigger.Init(self, invert) + self.status = status + self.requiredCount = requiredCount or 1 + self.invert = invert or false + self.active = invert +end + +--- Inform the trigger about a changed status +-- status: +-- Must be a valid UnitAuraInfo +function StatusTrigger:UpdateStatus(count) + self:SetState(count >= self.requiredCount) +end diff --git a/src/types/unitframe.lua b/src/types/unitframe.lua index 4e7cfcb..9c542bd 100644 --- a/src/types/unitframe.lua +++ b/src/types/unitframe.lua @@ -16,13 +16,22 @@ -- Omicron Frames. If not, see . local omif = select(2, ...) local types = omif.GetModule("types") + +---@class StatusBar local StatusBar = types.StatusBar + +---@class AuraList local AuraList = types.AuraList + +---@class SquareIndicator local SquareIndicator = types.SquareIndicator ---@class AuraTrigger local AuraTrigger = types.AuraTrigger +---@class StatusTrigger +local StatusTrigger = types.StatusTrigger + ---@class UnitFrame local UnitFrame = types.CreateClass("UnitFrame") types.UnitFrame = UnitFrame @@ -47,6 +56,8 @@ local colors = { white = {1.0, 1.0, 1.0} } +---@param unit string +---@param config table function UnitFrame:Init(unit, config) local width = config.size.width local height = config.size.height @@ -85,8 +96,8 @@ end function UnitFrame:CreateTriggers(triggers) for _, trigger in ipairs(triggers) do local kind = trigger.kind + local indicator = self:CreateIndicator(trigger.indicator) if kind == "AuraTrigger" then - local indicator = self:CreateIndicator(trigger.indicator) local at = AuraTrigger:new( trigger.spellId, trigger.own, @@ -95,6 +106,10 @@ function UnitFrame:CreateTriggers(triggers) ) at:SetTarget(indicator) self.auras:AddTrigger(at) + elseif kind == "StatusTrigger" then + local st = StatusTrigger:new(trigger.status, trigger.requiredCount, trigger.invert) + st:SetTarget(indicator) + self.auras:AddTrigger(st) end end end