diff --git a/src/types/auralist.lua b/src/types/auralist.lua index e385588..67ac884 100644 --- a/src/types/auralist.lua +++ b/src/types/auralist.lua @@ -18,6 +18,7 @@ local omi = select(2, ...) local types = omi.GetModule("types") local AuraTrigger = types.AuraTrigger +--- AuraList keeps track of all the auras attached to a unitframe local AuraList = types.CreateClass("AuraList") types.AuraList = AuraList @@ -38,6 +39,8 @@ local statusLists = { } } +-- helper function that goes over several aura slots for a unit. Runs a +-- callback function with UnitAuraInfo table as argument local function ForEachAuraSlots(unit, fn, continuationToken, ...) local GetAuraDataBySlot = C_UnitAuras.GetAuraDataBySlot local n = select('#', ...) @@ -48,6 +51,7 @@ local function ForEachAuraSlots(unit, fn, continuationToken, ...) return continuationToken end +-- Helper function that goes over all aura slots for a given filter local function ForEachAuraFiltered(unit, filter, fn) local UnitAuraSlots = UnitAuraSlots local continuationToken = nil @@ -63,6 +67,9 @@ local function ForEachAura(unit, fn) ForEachAuraFiltered(unit, "HARMFUL", fn) end +--- Initialize AuraList +-- unitframe +-- The unitframe this list belongs to function AuraList:Init(unitframe) self.unitframe = unitframe self.unit = unitframe.unit @@ -70,30 +77,30 @@ function AuraList:Init(unitframe) self.statusCount = {} self.auras = {} -- map AuraInstanceID to UnitAuraInfo table - + self.triggers = {} self.triggersBySpell = {} end - +--- Add an AuraTrigger to this AuraList +-- trigger +-- an AuraTrigger object function AuraList:AddTrigger(trigger) table.insert(self.triggers, trigger) - if trigger:IsInstanceOf(AuraTrigger) then - local spellId = trigger.spellId - if self.triggersBySpell[spellId] == nil then - self.triggersBySpell[spellId] = {} - end - table.insert(self.triggersBySpell[spellId], trigger) + local spellId = trigger.spellId + if self.triggersBySpell[spellId] == nil then + self.triggersBySpell[spellId] = {} end + table.insert(self.triggersBySpell[spellId], trigger) end --- Scan all the auras of the owning unit and build the aura list from scratch --- This should only ever happen when the unit is first assigned to the frame +--- 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 = {} self.statusCount = {} - + for _, trigger in ipairs(self.triggers) do trigger:Reset() end @@ -103,6 +110,9 @@ function AuraList:Reset() end) end +--- Add an aura to the AuraList +-- aura +-- A UnitAuraInfo table for a newly added aura function AuraList:AddAura(aura) local statusChanged = false self.auras[aura.auraInstanceID] = aura @@ -117,7 +127,7 @@ function AuraList:AddAura(aura) count[status] = count[status] + 1 end end - + for _, trigger in ipairs(self.triggersBySpell[aura.spellId] or {}) do trigger:AddAura(aura) end @@ -126,7 +136,9 @@ function AuraList:AddAura(aura) return statusChanged end --- Returns a table with every status that applies to the given aura +--- Return a sequence table with all status names that match the given aura +-- aura +-- A UnitAuraInfo table function AuraList:GetStatusForAura(aura) local status = {} if aura.dispelName and aura.isHarmful then @@ -140,6 +152,9 @@ function AuraList:GetStatusForAura(aura) return status end +--- Add an aura to the AuraList +-- aura +-- A UnitAuraInfo table for a newly added aura function AuraList:UpdateAura(aura) for _, trigger in ipairs(self.triggersBySpell[aura.spellId] or {}) do trigger:UpdateAura(self.auras[aura.auraInstanceId], aura) @@ -147,6 +162,9 @@ function AuraList:UpdateAura(aura) self.auras[aura.auraInstanceID] = aura end +--- Remove an aura from the AuraList +-- iid +-- The instance id for a removed aura function AuraList:RemoveAura(iid) local aura = self.auras[iid] if aura == nil then @@ -167,13 +185,16 @@ function AuraList:RemoveAura(iid) count[status] = count[status] - 1 end end - + for _, trigger in ipairs(self.triggersBySpell[aura.spellId] or {}) do trigger:RemoveAura(aura) end return statusChanged end +--- Update an aura in the AuraList +-- info +-- The new UnitAuraInfo structure function AuraList:Update(info) local GetAuraDataByAuraInstanceID = C_UnitAuras.GetAuraDataByAuraInstanceID local statusChanged = false @@ -190,7 +211,7 @@ function AuraList:Update(info) self:UpdateAura(aura) end end - + for _, iid in ipairs(info.removedAuraInstanceIDs or {}) do if self:RemoveAura(iid) then statusChanged = true diff --git a/src/types/indicator.lua b/src/types/indicator.lua index 107299f..223843f 100644 --- a/src/types/indicator.lua +++ b/src/types/indicator.lua @@ -18,13 +18,35 @@ local omi = select(2, ...) local types = omi.GetModule("types") local AuraTrigger = types.AuraTrigger +--- Indicator is a type for any kind of visual indicator. This type has no +-- function and should not be created. All functional indicators derive from +-- this type. local Indicator = types.CreateClass("Indicator") types.Indicator = Indicator --- TODO: make different indicators, such as texture, text, border --- TODO: spellid feels out of place but I wanna quickly get something for now. --- Should rethink this when Trigger is its own class -function Indicator:Init(unitframe, auralist, size, point, x, y, color, spellId) +--- Show the indicator and supply it with data +function Indicator:Show(data) +end + +--- Update the indicator with new data +function Indicator:Update(data) +end + +--- Hide the indicator +function Indicator:Hide() +end + +--- SquareIndicator is an indicator that displays a colored square texture +local SquareIndicator = types.CreateClass("SquareIndicator", Indicator) +types.SquareIndicator = SquareIndicator + +--- Initialize a new SquareIndicator +-- unitframe Unitframe it is attached to +-- size Size of the indicator square +-- point Attachment point to the unitframe's overlay frame +-- x, y x and y offset for the attachment point +-- color Color of the square +function SquareIndicator:Init(unitframe, size, point, x, y, color) local frame = unitframe.overlays local texture = frame:CreateTexture(nil, "ARTWORK") @@ -36,26 +58,21 @@ function Indicator:Init(unitframe, auralist, size, point, x, y, color, spellId) self:SetColor(color) texture:SetVertexColor(unpack(color)) texture:SetDrawLayer("ARTWORK") - - local fn = function(activate) - if activate then - self:Show() - else - self:Hide() - end - end - local trigger = AuraTrigger:new(fn, spellId, true) - auralist:AddTrigger(trigger) end -function Indicator:SetColor(color) +--- Set the color of the Square Indicator +-- color: a sequence table with 3 color channels {r, g, b} +function SquareIndicator:SetColor(color) self.texture:SetVertexColor(unpack(color)) end -function Indicator:Show() +--- Show the square indicator. +-- data: ignored for now +function SquareIndicator:Show(data) self.texture:Show() end -function Indicator:Hide() +--- Hide the square indicator. +function SquareIndicator:Hide() self.texture:Hide() end diff --git a/src/types/trigger.lua b/src/types/trigger.lua index 72c39df..3aebfd4 100644 --- a/src/types/trigger.lua +++ b/src/types/trigger.lua @@ -17,47 +17,52 @@ local omi = select(2, ...) local types = omi.GetModule("types") +--- +-- Trigger objects provide a link between indicators and some data source. They +-- can pass data from the data source into the trigger. This is just a +-- supertype for all indicators and should not be constructed on its own. It +-- has no functionality other than providing default implementations that do +-- nothing. types.Trigger = types.CreateClass("Trigger") local Trigger = types.Trigger --- Constructor for Trigger. --- fn: --- The callback function that gets called every time this trigger changes --- states between active and inactive. Function takes one boolean argument. -function Trigger:Init(fn) - self.fn = fn +-- Initialize a new Trigger object +-- indicator: +-- The indicator that gets activated by this trigger. +function Trigger:Init(indicator) + self.indicator = indicator end --- Returns whether the trigger is active +-- Returns whether or not the trigger is active function Trigger:IsActive() return false end --- Reset the trigger to the default state. Does run the untrigger callback if --- the trigger is active when Reset is called. +-- Reset the trigger to the default state. Deactivates the indicator if it is +-- active when Reset is called. function Trigger:Reset() end +--- +-- AuraTrigger is a trigger that can be attached to AuraList as datasource types.AuraTrigger = types.CreateClass("AuraTrigger", Trigger) local AuraTrigger = types.AuraTrigger --- Constructor for AuraTrigger --- fn: --- The callback function that gets called every time this trigger changes --- states between active and inactive. Function takes one boolean argument. --- --- requiredCount = 1: --- The minimum number of conditions that must be met before the trigger --- activates. What exactly this means depends on the trigger, examples are --- # of matching auras, # of stacks. --- --- invert = false: --- If the trigger is inverted it will activate when count < requiredCount. --- If the trigger is not inverted it will activate when count >= requiredCount. -function AuraTrigger:Init(fn, spellId, own, requiredCount, invert) - Trigger.Init(self, fn) +--- Initialize a new AuraTrigger object +-- indicator +-- Indicator that gets controlled by this trigger. +-- spellId +-- Spell id to trigger on +-- own +-- Only trigger on auras by the player +-- requiredCount=1 +-- Number of aura applications to activate trigger +-- invert=false +-- Whether to invert trigger activation +function AuraTrigger:Init(indicator, spellId, own, requiredCount, invert) + Trigger.Init(self, indicator) self.spellId = spellId self.requiredCount = requiredCount or 1 self.own = own @@ -65,18 +70,19 @@ function AuraTrigger:Init(fn, spellId, own, requiredCount, invert) self.invert = invert or false end --- Reset the trigger to the default state. Does run the untrigger callback if --- the trigger is active when it is called +--- See Trigger:Reset function AuraTrigger:Reset() local before = self:IsActive() self.count = 0 local after = self:IsActive() - if before ~= after then - self.fn(after) + if not before and after then + self.indicator:Show() + elseif before and not after then + self.indicator:Hide() end end --- Return true if the aura matches the trigger +--- Return true if the aura matches the trigger -- aura: -- Must be a valid UnitAuraInfo structure. function AuraTrigger:IsMatching(aura) @@ -86,10 +92,10 @@ function AuraTrigger:IsMatching(aura) if self.own and aura.sourceUnit ~= "player" then return false end - return true + return true end --- Inform the trigger about an added aura +--- Inform the trigger about an added aura -- aura: -- Must be a valid UnitAuraInfo function AuraTrigger:AddAura(aura) @@ -98,13 +104,17 @@ function AuraTrigger:AddAura(aura) end self.count = self.count + 1 - -- Be mindful, this works only if count always changes by 1. + -- Be mindful, this works only if count always changes by 1. if self.count == self.requiredCount then - self.fn(not self.invert) + if self.invert then + self.indicator:Hide() + else + self.indicator:Show() + end end end --- Inform the trigger about an updated aura +--- Inform the trigger about an updated aura -- before: -- Must be a valid UnitAuraInfo for the aura before the update -- after: @@ -113,20 +123,25 @@ function AuraTrigger:UpdateAura(before, after) -- end --- Inform the trigger about an aura that got removed +--- Inform the trigger about an aura that got removed +-- aura: -- Must be a valid UnitAuraInfo for the aura before it got removed function AuraTrigger:RemoveAura(aura) if not self:IsMatching(aura) then return end - self.count = self.count - 1 - -- Be mindful, this works only if count always changes by 1. + self.count = self.count - 1 + -- Be mindful, this works only if count always changes by 1. if self.count == self.requiredCount - 1 then - self.fn(self.invert) + if self.invert then + self.indicator:Show() + else + self.indicator:Hide() + end end end --- Returns true if the trigger is active, false otherwise +--- Returns true if the trigger is active, false otherwise function AuraTrigger:IsActive() if self.invert then return self.count < self.requiredCount diff --git a/src/types/unitframe.lua b/src/types/unitframe.lua index 01ff008..659992d 100644 --- a/src/types/unitframe.lua +++ b/src/types/unitframe.lua @@ -18,7 +18,8 @@ local omif = select(2, ...) local types = omif.GetModule("types") local StatusBar = types.StatusBar local AuraList = types.AuraList -local Indicator = types.Indicator +local SquareIndicator = types.SquareIndicator +local AuraTrigger = types.AuraTrigger types.UnitFrame = types.CreateClass("UnitFrame") local UnitFrame = types.UnitFrame @@ -59,11 +60,29 @@ function UnitFrame:Init(unit, width, height, hideInRaid) overlays:Show() self.overlays = overlays self:CreateName() - self.indicators = { - Indicator:new(self, self.auras, 14, "TOPLEFT", 2, -2, colors.white, 383648), - Indicator:new(self, self.auras, 14, "TOPLEFT", 2, -2, colors.white, 974), - Indicator:new(self, self.auras, 14, "BOTTOMLEFT", 2, 2, colors.cyan, 61295) - } + + self.auras:AddTrigger( + AuraTrigger:new( + SquareIndicator:new(self, 14, "TOPLEFT", 2, -2, colors.white), + 383648, -- Second Earthshield on self + true + ) + ) + self.auras:AddTrigger( + AuraTrigger:new( + SquareIndicator:new(self, 14, "TOPLEFT", 2, -2, colors.white), + 974, -- Earthshield + true + ) + ) + self.auras:AddTrigger( + AuraTrigger:new( + SquareIndicator:new(self, 14, "BOTTOMLEFT", 2, 2, colors.cyan), + 61295, -- Riptide + true + ) + ) + self:RegisterEvents() self:Enable() end @@ -143,7 +162,7 @@ function UnitFrame:PrepareWheelBinds() self:SetBindingClick(false, "ALT-MOUSEWHEELUP", "BUTTONNAME", "alt-wheel-up") self:SetBindingClick(false, "ALT-MOUSEWHEELDOWN", "BUTTONNAME", "alt-wheel-down") ]]):gsub("BUTTONNAME", "OmicronSecureFrame" .. self.unit) - + local removeBindScript = [[ self:ClearBindings() ]] @@ -297,7 +316,7 @@ function UnitFrame:UNIT_HEALTH() self:UpdateAll(true) return end - self:UpdateHealth() + self:UpdateHealth() self:UpdateHealthColor() end @@ -306,7 +325,7 @@ function UnitFrame:UNIT_MAXHEALTH() self:UpdateAll(true) return end - self:UpdateHealth() + self:UpdateHealth() self:UpdateHealthColor() end