Author SHA1 Message Date
Andreas 4567bea3f9 Override role as TANK based on MT assignments
This is particularly helpful in fights like High King Maulgar,
Illidari Council or Kael'Thas where a DPS player is temporarily
made into a tank.
2026-10-29 12:54:24 +01:00
Andreas 949e3686aa Update config with TBC druid settings 2026-10-29 09:52:17 +01:00
omicron 76851011fe Fix font and status bars to use new API arguments 2026-10-29 09:28:49 +01:00
omicron 7f3269949f Add multiple spell ids support to AuraTrigger
Before AuraTrigger only supported a single spell id but now multiple
spells can activate the same trigger.

Related changes:
- Change the glue between AuraList and AuraTrigger to match this new functionality.
- Update the default frame config
2026-10-29 09:28:49 +01:00
omicron b9f1bad81d Replace Trigger:SetState by Trigger:SetStateAndData
Update the use of the old API in most triggers except AuraTrigger. This
means the code isn't in a working state at this commit.
2026-10-29 09:28:48 +01:00
omicron 80859c1e44 Change the sort algorithm to use UnitExist instead of frame:IsShown
When UNIT_PET fires, pet units will exist but the UnitWatch will not yet
have shown the frame.
2026-10-29 09:28:48 +01:00
omicron 575e829025 Make UnitGroup trigger sort on UNIT_PET 2026-10-29 09:28:48 +01:00
omicron b473f7bf3d Add raid pets to the hardcoded configuration 2026-10-29 09:28:48 +01:00
omicron 14aeb2c43e Fixed typos and logic error in UnitFrame:Disable
This function is currently unused so these changes are not tested. The
Disable function now always hides the UnitFrame and calls
UnregisterUnitWatch with the correct parameters.
2026-10-29 09:28:47 +01:00
omicron 991bc5d0fe Fix type in AuraList:UpdateAura
Due to a typo AuraTrigger:UpdateAura always received nil as its first
(before) parameter. This parameter is currently unused so it did not
trigger an error.
2026-10-29 09:28:47 +01:00
omicron 2a24e64554 update config for TBC shaman play 2026-10-29 09:28:47 +01:00
8 changed files with 361 additions and 108 deletions

No files matched your search

+212 -41
View File
@@ -21,6 +21,7 @@ local colors = {
white = { 1.0, 1.0, 1.0 }, white = { 1.0, 1.0, 1.0 },
orange = { 1.0, 0.5, 0 }, orange = { 1.0, 0.5, 0 },
violet = { 1.0, 0, 1.0 }, violet = { 1.0, 0, 1.0 },
yellow = { 1.0, 1.0, 0 },
magic = { 0.4, 0.4, 1.0 }, magic = { 0.4, 0.4, 1.0 },
disease = { 0.4, 0.2, 0.0 }, disease = { 0.4, 0.2, 0.0 },
poison = { 0.0, 0.7, 0.7 }, poison = { 0.0, 0.7, 0.7 },
@@ -28,8 +29,25 @@ local colors = {
red = { 1, 0, 0 }, red = { 1, 0, 0 },
blue = { 0.4, 0.4, 1 }, blue = { 0.4, 0.4, 1 },
light_blue = { 0.7, 0.7, 1 }, light_blue = { 0.7, 0.7, 1 },
green = { 0.2, 0.9, 0.2 },
} }
---@param list number[]
---@return table<number, true>
local function set(list)
local s = {}
for _, v in ipairs(list) do
s[v] = true
end
return s
end
local AURAS_PRIEST_RENEW = set({ 139, 6074, 6075, 6076, 6077, 6078, 10927, 10928, 10929, 25315, 25221, 25222 })
local AURAS_PRIEST_PWS = set({ 17, 592, 600, 3747, 6065, 6066, 10898, 10899, 10900, 10901, 25217, 25218 })
local AURAS_DRUID_LIFEBLOOM = set({ 33763 })
local AURAS_DRUID_REJUV = set({ 774, 1058, 1430, 2090, 2091, 3627, 8910, 9839, 9840, 9841, 25299, 26981, 26982 })
local AURAS_DRUID_REGROWTH = set({ 8936, 8938, 8939, 8940, 8941, 9750, 9856, 9857, 9858, 26980 })
local function RangeConfig() local function RangeConfig()
local _, class = UnitClass("player") local _, class = UnitClass("player")
if class == "SHAMAN" then if class == "SHAMAN" then
@@ -40,10 +58,16 @@ local function RangeConfig()
} }
elseif class == "PRIEST" then elseif class == "PRIEST" then
return { return {
friendly = "Flash Heal", friendly = "Heal",
enemy = "Smite", enemy = "Smite",
fade = 0.2, fade = 0.2,
} }
elseif class == "DRUID" then
return {
friendly = "Rejuvenation",
enemy = "Wrath",
fade = 0.2,
}
else else
return { return {
fade = 0.2, fade = 0.2,
@@ -61,25 +85,41 @@ local function MouseConfig()
button = "mouse2", button = "mouse2",
mods = {}, mods = {},
kind = "macro", kind = "macro",
data = "/use [@UNIT,dead,help]Ancestral Vision; [@UNIT,help]Chain Heal", data = "/use [@UNIT,dead,help]Ancestral Spirit; [@UNIT,help]Chain Heal",
}, },
{ {
button = "mouse3", button = "mouse3",
mods = {}, mods = {},
kind = "macro", kind = "macro",
data = "/use [@UNIT,dead,help]Ancestral Spirit; [@UNIT,help]Purify Spirit", data = "/use [@UNIT,help]Cure Poison",
}, },
{ {
button = "wheel-up", button = "wheel-up",
mods = {}, mods = {},
kind = "macro", kind = "macro",
data = "/use [@UNIT,help]Healing Surge", data = "/use [@UNIT,help]Lesser Healing Wave",
},
{
button = "wheel-down",
mods = {},
kind = "macro",
data = "/use [@UNIT,help]Healing Wave",
}, },
{ button = "wheel-down", mods = {}, kind = "macro", data = "/use [@UNIT,help]Riptide" },
-- alt -- alt
{ button = "wheel-up", mods = { alt = true }, kind = "spell", data = "Healing Wave" },
{ button = "wheel-down", mods = { alt = true }, kind = "spell", data = "Earth Shield" }, { button = "wheel-down", mods = { alt = true }, kind = "spell", data = "Earth Shield" },
{
button = "wheel-up",
mods = { alt = true },
kind = "macro",
data = "/use [@UNIT,help,nodead]Nature's Swiftness\n/use [@UNIT,help]Healing Wave",
},
{
button = "mouse3",
mods = { alt = true },
kind = "macro",
data = "/use [@UNIT,help]Cure Disease",
},
-- Shift -- Shift
{ button = "mouse2", mods = { shift = true }, kind = "togglemenu" }, { button = "mouse2", mods = { shift = true }, kind = "togglemenu" },
@@ -89,6 +129,12 @@ local function MouseConfig()
kind = "macro", kind = "macro",
data = "/cast [@UNIT,help]Water Walking;\n/stopspelltarget", data = "/cast [@UNIT,help]Water Walking;\n/stopspelltarget",
}, },
{
button = "wheel-down",
mods = { shift = true },
kind = "macro",
data = "/use [@UNIT,help]Healing Wave(rank 1)",
},
} }
elseif class == "PRIEST" then elseif class == "PRIEST" then
return { return {
@@ -111,15 +157,15 @@ local function MouseConfig()
button = "wheel-up", button = "wheel-up",
mods = {}, mods = {},
kind = "macro", kind = "macro",
data = "/use [@UNIT,help]Flash Heal", data = "/use [@UNIT,help]Lesser Heal",
}, },
{ button = "wheel-down", mods = {}, kind = "macro", data = "/use [@UNIT,help]Renew" }, { button = "wheel-down", mods = {}, kind = "macro", data = "/use [@UNIT,help]Heal" },
-- alt -- alt
{ button = "mouse1", mods = { alt = true }, kind = "spell", data = "Power Word: Life" }, { button = "mouse1", mods = { alt = true }, kind = "spell", data = "Power Word: Life" },
{ button = "mouse2", mods = { alt = true }, kind = "spell", data = "Pain Suppression" }, { button = "mouse2", mods = { alt = true }, kind = "spell", data = "Pain Suppression" },
{ button = "mouse3", mods = { alt = true }, kind = "spell", data = "Power Infusion" }, { button = "mouse3", mods = { alt = true }, kind = "spell", data = "Power Infusion" },
{ button = "wheel-up", mods = { alt = true }, kind = "spell", data = "Rapture" }, { button = "wheel-up", mods = { alt = true }, kind = "spell", data = "Renew" },
{ button = "wheel-down", mods = { alt = true }, kind = "spell", data = "Power Word: Shield" }, { button = "wheel-down", mods = { alt = true }, kind = "spell", data = "Power Word: Shield" },
-- Shift -- Shift
@@ -137,6 +183,66 @@ local function MouseConfig()
data = "/cast [@UNIT,help]Leap of Faith;\n/stopspelltarget", data = "/cast [@UNIT,help]Leap of Faith;\n/stopspelltarget",
}, },
} }
elseif class == "DRUID" then
return {
-- No modifier
{ button = "mouse1", mods = {}, kind = "target" },
{
button = "mouse2",
mods = {},
kind = "macro",
data = "/use [@UNIT,help]Rejuvenation",
},
{
button = "wheel-up",
mods = {},
kind = "macro",
data = "/use [@UNIT,help]Lifebloom",
},
{
button = "wheel-down",
mods = {},
kind = "macro",
data = "/use [@UNIT,help]Regrowth",
},
-- ctrl
{
button = "wheel-up",
mods = { ctrl = true },
kind = "macro",
data = "/use [@UNIT,help]Abolish Poison"
},
{
button = "wheel-down",
mods = { ctrl = true },
kind = "macro",
data = "/use [@UNIT,help]Remove Curse"
},
-- alt
{
button = "mouse1",
mods = { alt = true },
kind = "macro",
data = "/use [@UNIT,help]Innervate",
},
{
button = "mouse2",
mods = { alt = true },
kind = "macro",
data = "/use [@UNIT,dead,help]Rebirth",
},
-- Shift
{
button = "wheel-down",
mods = { shift = true },
kind = "macro",
data = "/use [@UNIT,help]Swiftmend",
},
{ button = "mouse2", mods = { shift = true }, kind = "togglemenu" },
}
elseif class == "MONK" then elseif class == "MONK" then
return { return {
-- No modifier -- No modifier
@@ -259,7 +365,7 @@ local function TriggerClassConfig()
return { return {
{ {
kind = "AuraTrigger", kind = "AuraTrigger",
spellId = 383648, spellIds = set({ 32594 }),
own = true, -- Second Earth Shield on yourself own = true, -- Second Earth Shield on yourself
indicator = { indicator = {
kind = "SquareIndicator", kind = "SquareIndicator",
@@ -273,29 +379,30 @@ local function TriggerClassConfig()
}, },
{ {
kind = "AuraTrigger", kind = "AuraTrigger",
spellId = 974, spellIds = set({ 29203 }),
own = true, -- Second Earth Shield on yourself own = true, -- Healing Way
indicator = { indicator = {
kind = "SquareIndicator", kind = "SquareIndicator",
size = 17, size = 17,
point = "TOPLEFT", point = "TOPLEFT",
x = 3, x = 20,
y = -3, y = -3,
color = colors.white, color = colors.yellow,
showStacks = true, showStacks = true,
}, },
}, },
{ {
kind = "AuraTrigger", kind = "AuraTrigger",
spellId = 61295, spellIds = set({ 16237 }),
own = true, -- Riptide own = true, -- Ancestral Fortitude
indicator = { indicator = {
kind = "IconIndicator", kind = "SquareIndicator",
size = 17, size = 17,
point = "BOTTOMLEFT", point = "TOPLEFT",
x = 3, x = 40,
y = 3, y = -3,
fadeTime = 10.0, color = colors.orange,
showStacks = false,
}, },
}, },
{ {
@@ -314,7 +421,7 @@ local function TriggerClassConfig()
return { return {
{ {
kind = "AuraTrigger", kind = "AuraTrigger",
spellId = 17, spellIds = AURAS_PRIEST_PWS,
own = true, -- Power Word: Shield own = true, -- Power Word: Shield
indicator = { indicator = {
kind = "SquareIndicator", kind = "SquareIndicator",
@@ -328,7 +435,7 @@ local function TriggerClassConfig()
}, },
{ {
kind = "AuraTrigger", kind = "AuraTrigger",
spellId = 33206, spellIds = set({ 33206 }),
own = true, -- Pain Suppression own = true, -- Pain Suppression
indicator = { indicator = {
kind = "SquareIndicator", kind = "SquareIndicator",
@@ -343,7 +450,7 @@ local function TriggerClassConfig()
}, },
{ {
kind = "AuraTrigger", kind = "AuraTrigger",
spellId = 41635, spellIds = set({ 41635 }),
own = true, -- Prayer of Mending own = true, -- Prayer of Mending
indicator = { indicator = {
kind = "SquareIndicator", kind = "SquareIndicator",
@@ -357,7 +464,7 @@ local function TriggerClassConfig()
}, },
{ {
kind = "AuraTrigger", kind = "AuraTrigger",
spellId = 139, spellIds = AURAS_PRIEST_RENEW,
own = true, -- Renew own = true, -- Renew
indicator = { indicator = {
kind = "SquareIndicator", kind = "SquareIndicator",
@@ -371,7 +478,7 @@ local function TriggerClassConfig()
}, },
{ {
kind = "AuraTrigger", kind = "AuraTrigger",
spellId = 194384, spellIds = set({ 194384 }),
own = true, -- Atonement own = true, -- Atonement
indicator = { indicator = {
kind = "SquareIndicator", kind = "SquareIndicator",
@@ -386,7 +493,7 @@ local function TriggerClassConfig()
}, },
{ {
kind = "AuraTrigger", kind = "AuraTrigger",
spellId = 10060, spellIds = set({ 10060 }),
own = true, -- Power Infusion own = true, -- Power Infusion
indicator = { indicator = {
kind = "SquareIndicator", kind = "SquareIndicator",
@@ -410,11 +517,69 @@ local function TriggerClassConfig()
}, },
}, },
} }
elseif class == "DRUID" then
return {
{
kind = "AuraTrigger",
spellIds = AURAS_DRUID_LIFEBLOOM,
own = true, -- Lifebloom
indicator = {
kind = "SquareIndicator",
size = 17,
point = "BOTTOMLEFT",
x = 3,
y = 3,
color = colors.green,
showStacks = true,
fadeTime = 7.0,
flashTime = 2,
},
},
{
kind = "AuraTrigger",
spellIds = AURAS_DRUID_REGROWTH,
own = true, -- Regrowth
indicator = {
kind = "SquareIndicator",
size = 17,
point = "BOTTOMLEFT",
x = 22,
y = 3,
color = colors.yellow,
fadeTime = 21.0,
},
},
{
kind = "AuraTrigger",
spellIds = AURAS_DRUID_REJUV,
own = true, -- Rejuvenation
indicator = {
kind = "SquareIndicator",
size = 17,
point = "BOTTOMLEFT",
x = 41,
y = 3,
color = colors.violet,
fadeTime = 12.0,
},
},
{
kind = "StatusTrigger",
status = "Burn",
invert = false,
indicator = {
kind = "BorderIndicator",
thickness = 3.0,
color = colors.red,
level = 0,
},
},
}
elseif class == "PALADIN" then elseif class == "PALADIN" then
return { return {
{ {
kind = "AuraTrigger", kind = "AuraTrigger",
spellId = 287280, -- Glimmer of Light spellIds = set({ 287280 }), -- Glimmer of Light
own = true, own = true,
indicator = { indicator = {
kind = "SquareIndicator", kind = "SquareIndicator",
@@ -429,7 +594,7 @@ local function TriggerClassConfig()
}, },
{ {
kind = "AuraTrigger", kind = "AuraTrigger",
spellId = 25771, -- Forbearance spellIds = set({ 25771 }), -- Forbearance
indicator = { indicator = {
kind = "SquareIndicator", kind = "SquareIndicator",
size = 17, size = 17,
@@ -443,7 +608,7 @@ local function TriggerClassConfig()
}, },
{ {
kind = "AuraTrigger", kind = "AuraTrigger",
spellId = 53563, -- Beacon of Light spellIds = set({ 53563 }), -- Beacon of Light
own = true, own = true,
indicator = { indicator = {
kind = "SquareIndicator", kind = "SquareIndicator",
@@ -456,7 +621,7 @@ local function TriggerClassConfig()
}, },
{ {
kind = "AuraTrigger", kind = "AuraTrigger",
spellId = 156910, -- Beacon of Faith spellIds = set({ 156910 }), -- Beacon of Faith
own = true, own = true,
indicator = { indicator = {
kind = "SquareIndicator", kind = "SquareIndicator",
@@ -469,7 +634,7 @@ local function TriggerClassConfig()
}, },
{ {
kind = "AuraTrigger", kind = "AuraTrigger",
spellId = 200025, -- Beacon of Virtue spellIds = set({ 200025 }), -- Beacon of Virtue
own = true, own = true,
indicator = { indicator = {
kind = "SquareIndicator", kind = "SquareIndicator",
@@ -482,7 +647,7 @@ local function TriggerClassConfig()
}, },
{ {
kind = "AuraTrigger", kind = "AuraTrigger",
spellId = 1044, -- Blessing of Freedom spellIds = set({ 1044 }), -- Blessing of Freedom
own = true, own = true,
indicator = { indicator = {
kind = "SquareIndicator", kind = "SquareIndicator",
@@ -496,7 +661,7 @@ local function TriggerClassConfig()
}, },
{ {
kind = "AuraTrigger", kind = "AuraTrigger",
spellId = 1111, -- Blessing of Spellwarding spellIds = set({ 1111 }), -- Blessing of Spellwarding
own = true, own = true,
indicator = { indicator = {
kind = "SquareIndicator", kind = "SquareIndicator",
@@ -510,7 +675,7 @@ local function TriggerClassConfig()
}, },
{ {
kind = "AuraTrigger", kind = "AuraTrigger",
spellId = 1022, -- Blessing of Protection spellIds = set({ 1022 }), -- Blessing of Protection
own = true, own = true,
indicator = { indicator = {
kind = "SquareIndicator", kind = "SquareIndicator",
@@ -524,7 +689,7 @@ local function TriggerClassConfig()
}, },
{ {
kind = "AuraTrigger", kind = "AuraTrigger",
spellId = 6940, -- Blessing of Saccrifice spellIds = set({ 6940 }), -- Blessing of Saccrifice
own = true, own = true,
indicator = { indicator = {
kind = "SquareIndicator", kind = "SquareIndicator",
@@ -572,7 +737,7 @@ local function MakeDebuffTrigger(slot, spellid, color, stacks)
end end
return { return {
kind = "AuraTrigger", kind = "AuraTrigger",
spellId = spellid, spellIds = set({ spellid }),
indicator = { indicator = {
kind = "SquareIndicator", kind = "SquareIndicator",
size = 15, size = 15,
@@ -652,7 +817,7 @@ local function TriggerConfig()
-- Some more debuffs in the bottom row -- Some more debuffs in the bottom row
table.insert(triggers, { table.insert(triggers, {
kind = "AuraTrigger", kind = "AuraTrigger",
spellId = 240443, -- Bursting spellIds = set({ 240443 }), -- Bursting
indicator = { indicator = {
kind = "SquareIndicator", kind = "SquareIndicator",
size = 17, size = 17,
@@ -700,6 +865,8 @@ function CreateRaidFrames(left, top, config)
local num = i * 5 + j + 1 local num = i * 5 + j + 1
local frame = UnitFrame:new("raid" .. num, config) local frame = UnitFrame:new("raid" .. num, config)
group:AddUnitFrame(frame) group:AddUnitFrame(frame)
local raidpet = UnitFrame:new("raidpet" .. num, config)
group:AddUnitFrame(raidpet)
end end
end end
end end
@@ -710,9 +877,13 @@ function CreatePartyFrames(left, top, config)
local group = UnitGroup:new(left, top, width, height) local group = UnitGroup:new(left, top, width, height)
local player = UnitFrame:new("player", config) local player = UnitFrame:new("player", config)
group:AddUnitFrame(player) group:AddUnitFrame(player)
local pet = UnitFrame:new("pet", config)
group:AddUnitFrame(pet)
for i = 1, 4 do for i = 1, 4 do
local frame = UnitFrame:new("party" .. i, config) local frame = UnitFrame:new("party" .. i, config)
group:AddUnitFrame(frame) group:AddUnitFrame(frame)
local partypet = UnitFrame:new("partypet" .. i, config)
group:AddUnitFrame(partypet)
end end
group:Sort() group:Sort()
end end
@@ -742,10 +913,10 @@ function CreateFrames()
triggers = TriggerConfig(), triggers = TriggerConfig(),
} }
CreatePartyFrames(-0.05, -290.05, config) CreatePartyFrames(-0.05, -240.05, config)
config.hideInRaid = false config.hideInRaid = false
CreateRaidFrames(-0.05, -290.05, config) CreateRaidFrames(-0.05, -240.05, config)
CreateTargetFrames(110 * 3 + 50 - 0.05, -245.05, config) CreateTargetFrames(110 * 3 + 50 - 0.05, -240.05, config)
HideBlizzardFrames() HideBlizzardFrames()
end end
+26 -10
View File
@@ -16,6 +16,8 @@
-- Omicron Frames. If not, see <https://www.gnu.org/licenses/>. -- Omicron Frames. If not, see <https://www.gnu.org/licenses/>.
local omi = select(2, ...) local omi = select(2, ...)
local types = omi.GetModule("types") local types = omi.GetModule("types")
local AuraTrigger = types.AuraTrigger
local StatusTrigger = types.StatusTrigger
--- AuraList keeps track of all the auras attached to a unitframe --- AuraList keeps track of all the auras attached to a unitframe
---@class AuraList: Object ---@class AuraList: Object
@@ -180,21 +182,35 @@ function AuraList:Init(unitframe)
self.triggersByStatus = {} self.triggersByStatus = {}
end end
---@param trigger AuraTrigger | StatusTrigger ---@param trigger StatusTrigger
function AuraList:AddTrigger(trigger) function AuraList:AddStatusTrigger(trigger)
table.insert(self.triggers, trigger) table.insert(self.triggers, trigger)
local spellId = trigger.spellId
local status = trigger.status 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 if self.triggersByStatus[status] == nil then
self.triggersByStatus[status] = {} self.triggersByStatus[status] = {}
end end
table.insert(self.triggersByStatus[status], trigger) table.insert(self.triggersByStatus[status], trigger)
end
---@param trigger AuraTrigger
function AuraList:AddAuraTrigger(trigger)
table.insert(self.triggers, trigger)
for spellId in pairs(trigger.spellIds) do
if self.triggersBySpell[spellId] == nil then
self.triggersBySpell[spellId] = {}
end
table.insert(self.triggersBySpell[spellId], trigger)
end
end
---@param trigger AuraTrigger | StatusTrigger
function AuraList:AddTrigger(trigger)
if trigger:IsInstanceOf(AuraTrigger) then
self:AddAuraTrigger(trigger)
elseif trigger:IsInstanceOf(StatusTrigger) then
self:AddStatusTrigger(trigger)
else
error("AddTrigger: trigger is neither an AuraTrigger nor a StatusTrigger")
end end
end end
@@ -269,7 +285,7 @@ end
---@param aura UnitAuraInfo ---@param aura UnitAuraInfo
function AuraList:UpdateAura(aura) function AuraList:UpdateAura(aura)
for _, trigger in ipairs(self.triggersBySpell[aura.spellId] or {}) do for _, trigger in ipairs(self.triggersBySpell[aura.spellId] or {}) do
trigger:UpdateAura(self.auras[aura.auraInstanceId], aura) trigger:UpdateAura(self.auras[aura.auraInstanceID], aura)
end end
self.auras[aura.auraInstanceID] = aura self.auras[aura.auraInstanceID] = aura
end end
+66 -24
View File
@@ -21,7 +21,7 @@ local Trigger = types.Trigger
---AuraTrigger is a Trigger that can be attached to AuraList as datasource ---AuraTrigger is a Trigger that can be attached to AuraList as datasource
---@class AuraTrigger: Trigger ---@class AuraTrigger: Trigger
---@field spellId number ---@field spellIds table<number, true>
---@field count number ---@field count number
---@field requiredCount number ---@field requiredCount number
local AuraTrigger = types.CreateClass("AuraTrigger", Trigger) local AuraTrigger = types.CreateClass("AuraTrigger", Trigger)
@@ -33,7 +33,8 @@ types.AuraTrigger = AuraTrigger
---@param config table ---@param config table
---@return AuraTrigger ---@return AuraTrigger
function AuraTrigger.CreateFromConfig(unit, config) function AuraTrigger.CreateFromConfig(unit, config)
local trigger = AuraTrigger:new(config.spellId, config.own, config.requiredCount, config.invert, config.defaultData) local trigger =
AuraTrigger:new(config.spellIds, config.own, config.requiredCount, config.invert, config.defaultData)
unit.auras:AddTrigger(trigger) unit.auras:AddTrigger(trigger)
return trigger return trigger
end end
@@ -47,29 +48,33 @@ function AuraTrigger.new(cls, ...)
end end
--- Initialize a new AuraTrigger object --- Initialize a new AuraTrigger object
---@param spellId number ---@param spellIds table<number, true>
---@param own boolean ---@param own boolean
---@param requiredCount number | nil ---@param requiredCount number | nil
---@param invert boolean | nil ---@param invert boolean | nil
---@param defaultData table | nil ---@param defaultData table | nil
function AuraTrigger:Init(spellId, own, requiredCount, invert, defaultData) function AuraTrigger:Init(spellIds, own, requiredCount, invert, defaultData)
Trigger.Init(self, invert, defaultData) Trigger.Init(self, invert, defaultData)
self.spellId = spellId self.spellIds = spellIds
self.instanceData = {}
self.requiredCount = requiredCount or 1 self.requiredCount = requiredCount or 1
self.own = own self.own = own
self.count = 0 self.count = 0
self.bestAuraID = nil
end end
--- Reset the AuraTrigger to the default state --- Reset the AuraTrigger to the default state
function AuraTrigger:Reset() function AuraTrigger:Reset()
self.count = 0 self.count = 0
self:SetState(self.count >= self.requiredCount, false) self.bestAuraID = nil
table.wipe(self.instanceData)
self:SetStateAndData(self.count >= self.requiredCount, {})
end end
---Check if a given aura matches this AuraTrigger ---Check if a given aura matches this AuraTrigger
---@param aura UnitAuraInfo ---@param aura UnitAuraInfo
function AuraTrigger:IsMatching(aura) function AuraTrigger:IsMatching(aura)
if aura.spellId ~= aura.spellId then if not self.spellIds[aura.spellId] then
return false return false
end end
if self.own and aura.sourceUnit ~= "player" then if self.own and aura.sourceUnit ~= "player" then
@@ -78,35 +83,68 @@ function AuraTrigger:IsMatching(aura)
return true return true
end end
-- Get the ID of the current best matching aura in AuraTrigger.instanceData
function AuraTrigger:BestAuraID()
local found = nil
for k, v in pairs(self.instanceData) do
if not found then
found = k
elseif v.expirationTime > self.instanceData[found].expirationTime then
found = k
end
end
return found
end
---Grab the best aura data and update the current recorded best aura
---It returns data if the current best aura is different from the previous
---@param updatedInstanceId number|nil the aura id that was recently updated
function AuraTrigger:BestAuraData(updatedInstanceId)
local bid = self:BestAuraID()
if bid == nil then
self.bestAuraID = nil
return nil
end
local data = nil
if bid ~= self.bestAuraID or (updatedInstanceId and bid == updatedInstanceId) then
local aura = self.instanceData[bid]
data = {
stacks = aura.applications,
duration = aura.duration,
expirationTime = aura.expirationTime,
icon = aura.icon,
}
self.bestAuraID = bid
end
return data
end
---Inform the trigger about an added aura ---Inform the trigger about an added aura
---@param aura UnitAuraInfo ---@param aura UnitAuraInfo
function AuraTrigger:AddAura(aura) function AuraTrigger:AddAura(aura)
if not self:IsMatching(aura) then if not self:IsMatching(aura) then
return return
end end
local aid = aura.auraInstanceID
self.instanceData[aid] = aura
self.count = self.count + 1 self.count = self.count + 1
self:SetData({ local newData = self:BestAuraData(nil)
stacks = aura.applications, self:SetStateAndData(self.count >= self.requiredCount, newData)
duration = aura.duration,
expirationTime = aura.expirationTime,
icon = aura.icon,
})
self:SetState(self.count >= self.requiredCount, false)
end end
---Inform the trigger about an updated aura ---Inform the trigger about an updated aura
---@param before UnitAuraInfo ---@param before UnitAuraInfo
---@param after UnitAuraInfo ---@param after UnitAuraInfo
function AuraTrigger:UpdateAura(before, after) function AuraTrigger:UpdateAura(before, after)
self:SetData({ if not self:IsMatching(after) then
stacks = after.applications, return
duration = after.duration,
expirationTime = after.expirationTime,
icon = after.icon,
})
if self.active then
self.indicator:Update(self.data)
end end
local aid = after.auraInstanceID
self.instanceData[aid] = after
local newData = self:BestAuraData(aid)
self:SetStateAndData(self.count >= self.requiredCount, newData)
end end
---Inform the trigger about an aura that got removed ---Inform the trigger about an aura that got removed
@@ -115,7 +153,11 @@ function AuraTrigger:RemoveAura(aura)
if not self:IsMatching(aura) then if not self:IsMatching(aura) then
return return
end end
local aid = aura.auraInstanceID
self.instanceData[aid] = nil
self.count = self.count - 1 self.count = self.count - 1
self:SetData({})
self:SetState(self.count >= self.requiredCount, false) local newData = self:BestAuraData(nil)
self:SetStateAndData(self.count >= self.requiredCount, newData)
end end
+4 -7
View File
@@ -92,8 +92,7 @@ function MultiTrigger:OnChildActivate(idx, trigger, data)
table.sort(activeChildren) table.sort(activeChildren)
-- The highest priority active trigger has changed -- The highest priority active trigger has changed
if activeChild ~= activeChildren[1] then if activeChild ~= activeChildren[1] then
self:SetData(data) self:SetStateAndData(true, data)
self:SetState(true, true)
end end
end end
@@ -117,11 +116,9 @@ function MultiTrigger:OnChildDeactivate(idx, trigger, data)
local newActiveChild = activeChildren[1] local newActiveChild = activeChildren[1]
if activeChild ~= newActiveChild then if activeChild ~= newActiveChild then
if activeChildren[1] ~= nil then if activeChildren[1] ~= nil then
self:SetData(childrenData[newActiveChild]) self:SetStateAndData(true, childrenData[newActiveChild])
self:SetState(true, true)
else else
self:SetData({}) self:SetStateAndData(false, {})
self:SetState(false, false)
end end
end end
end end
@@ -139,5 +136,5 @@ end
-- Reset the trigger to the default state. If this changes the activation of the -- Reset the trigger to the default state. If this changes the activation of the
-- trigger then the target will be notified. -- trigger then the target will be notified.
function MultiTrigger:Reset() function MultiTrigger:Reset()
self:SetState(false) self:SetStateAndData(false, {})
end end
+1 -1
View File
@@ -58,5 +58,5 @@ end
-- status: -- status:
-- Must be a valid UnitAuraInfo -- Must be a valid UnitAuraInfo
function StatusTrigger:UpdateStatus(count) function StatusTrigger:UpdateStatus(count)
self:SetState(count >= self.requiredCount, false) self:SetStateAndData(count >= self.requiredCount, nil)
end end
+18 -4
View File
@@ -47,7 +47,9 @@ function Trigger:Init(invert, defaultData)
end end
---Save new data from the datasource into the trigger. This method will make ---Save new data from the datasource into the trigger. This method will make
---sure the default data is always present ---sure the default data is always present. This method will not ensure the
---target gets notified of new state or new data. Subclasses of Trigger should
---use Trigger:SetStateAndData instead.
---@param data table ---@param data table
function Trigger:SetData(data) function Trigger:SetData(data)
if self.defaultData then if self.defaultData then
@@ -69,9 +71,21 @@ function Trigger:SetTarget(target)
end end
end end
---Set the state of the trigger. Will activate the indicator if needed. ---Set the data and state of the trigger. Will update the trigger as needed.
---
--- If the state changes this function will call Show or Hide on the indicator.
--- If the state remains the same and the data is not nil, it will call Update
--- on the indicator.
---
---@param state boolean ---@param state boolean
function Trigger:SetState(state, doUpdate) ---@param data table|nil
function Trigger:SetStateAndData(state, data)
local doUpdate = false
if data then
doUpdate = true
self:SetData(data)
end
state = state ~= self.invert -- state xor inverted state = state ~= self.invert -- state xor inverted
if self.active ~= state then if self.active ~= state then
if state then if state then
@@ -88,5 +102,5 @@ end
-- Reset the trigger to the default state. If this changes the activation of the -- Reset the trigger to the default state. If this changes the activation of the
-- trigger then the target will be notified. -- trigger then the target will be notified.
function Trigger:Reset() function Trigger:Reset()
self:SetState(false, false) self:SetStateAndData(false, nil)
end end
+21 -9
View File
@@ -17,6 +17,11 @@
local omif = select(2, ...) local omif = select(2, ...)
local types = omif.GetModule("types") local types = omif.GetModule("types")
local NameFont = CreateFont("OicronFrames_NameFont")
NameFont:SetFont("Interface\\AddOns\\OmicronFrames\\media\\fonts\\roboto\\Roboto-Bold.ttf", 13, "")
NameFont:SetShadowColor(0, 0, 0)
NameFont:SetShadowOffset(1, -1)
---@class StatusBar ---@class StatusBar
local StatusBar = types.StatusBar local StatusBar = types.StatusBar
@@ -101,13 +106,13 @@ function UnitFrame:Init(unit, config)
self.absorb = StatusBar:new(self, width, height, 1, true, texture_top) self.absorb = StatusBar:new(self, width, height, 1, true, texture_top)
self.absorb:SetColor(unpack(colors.absorb)) self.absorb:SetColor(unpack(colors.absorb))
self.absorb:SetFillStyle("REVERSE") self.absorb:SetFillStyle(Enum.StatusBarFillStyle.Reverse)
self.shield = StatusBar:new(self, width, height, 1, true, texture_bot) self.shield = StatusBar:new(self, width, height, 1, true, texture_bot)
self.shield:SetColor(unpack(colors.shield)) self.shield:SetColor(unpack(colors.shield))
self.shield:SetRange(0, 1) self.shield:SetRange(0, 1)
self.shield:SetValue(0.6) self.shield:SetValue(0.6)
self.shield:SetFillStyle("REVERSE") self.shield:SetFillStyle(Enum.StatusBarFillStyle.Reverse)
self.auras = AuraList:new(self) self.auras = AuraList:new(self)
@@ -182,10 +187,8 @@ function UnitFrame:CreateName()
local name = self.overlays:CreateFontString(nil, "BACKGROUND") local name = self.overlays:CreateFontString(nil, "BACKGROUND")
self.name = name self.name = name
name:SetFont("Interface\\AddOns\\OmicronFrames\\media\\fonts\\roboto\\Roboto-Bold.ttf", 13, "") name:SetFontObject(NameFont)
name:SetTextColor(0.8, 0.6, 0.1) name:SetTextColor(0.8, 0.6, 0.1)
name:SetShadowColor(0, 0, 0)
name:SetShadowOffset(1, -1)
name:SetPoint("CENTER") name:SetPoint("CENTER")
name:SetText("") name:SetText("")
name:Show() name:Show()
@@ -389,10 +392,9 @@ function UnitFrame:Disable()
if self.hideInRaid then if self.hideInRaid then
UnregisterAttributeDriver(self.secureFrame, "state-visibility") UnregisterAttributeDriver(self.secureFrame, "state-visibility")
elseif self.unit ~= "player" then elseif self.unit ~= "player" then
UnregisterUnitWatch(self.secure_frame, self.condition) UnregisterUnitWatch(self.secureFrame, false)
else
self.secureFrame:Hide()
end end
self.secureFrame:Hide()
end end
-- returns true if this unit is a target unit -- returns true if this unit is a target unit
@@ -539,10 +541,20 @@ function UnitFrame:UNIT_POWER_UPDATE()
self:UpdatePower() self:UpdatePower()
end end
function UnitFrame:UpdateRole(role) function UnitFrame:GetRole(role)
if role == nil then if role == nil then
role = UnitGroupRolesAssigned(self.unit) role = UnitGroupRolesAssigned(self.unit)
end end
if GetPartyAssignment("MAINTANK", self.unit) then
role = "TANK"
end
return role
end
function UnitFrame:UpdateRole(role)
role = self:GetRole(role)
if role == "HEALER" then if role == "HEALER" then
self:EnablePower(Enum.PowerType.Mana) self:EnablePower(Enum.PowerType.Mana)
elseif role == "TANK" and select(3, UnitClass(self.unit)) == 6 then elseif role == "TANK" and select(3, UnitClass(self.unit)) == 6 then
+13 -12
View File
@@ -32,9 +32,10 @@ local function RoleValue(role)
end end
local function UnitFrameDefaultCompare(lhs, rhs) local function UnitFrameDefaultCompare(lhs, rhs)
-- visible < invisible -- exists < not exists
if lhs.secureFrame:IsShown() ~= rhs.secureFrame:IsShown() then local lexists, rexists = UnitExists(lhs.unit), UnitExists(rhs.unit)
return lhs.secureFrame:IsShown() if lexists ~= rexists then
return lexists
end end
local lunit, runit = lhs.unit, rhs.unit local lunit, runit = lhs.unit, rhs.unit
@@ -52,8 +53,8 @@ local function UnitFrameDefaultCompare(lhs, rhs)
end end
-- tank < healer < damage < ? -- tank < healer < damage < ?
local lrole = RoleValue(UnitGroupRolesAssigned(lunit)) local lrole = RoleValue(lhs:GetRole())
local rrole = RoleValue(UnitGroupRolesAssigned(runit)) local rrole = RoleValue(rhs:GetRole())
if lrole ~= rrole then if lrole ~= rrole then
return lrole < rrole return lrole < rrole
@@ -69,7 +70,6 @@ function UnitGroup:Init(left, top, width, height)
self.top = top self.top = top
self.left = left self.left = left
self.units = {} self.units = {}
self.sortAfterCombat = false
self:RegisterEvents() self:RegisterEvents()
end end
@@ -84,6 +84,7 @@ function UnitGroup:RegisterEvents()
frame:RegisterEvent("GROUP_ROSTER_UPDATE") frame:RegisterEvent("GROUP_ROSTER_UPDATE")
frame:RegisterEvent("PLAYER_REGEN_ENABLED") frame:RegisterEvent("PLAYER_REGEN_ENABLED")
frame:RegisterEvent("PLAYER_ENTERING_WORLD") frame:RegisterEvent("PLAYER_ENTERING_WORLD")
frame:RegisterEvent("UNIT_PET")
end end
function UnitGroup:GROUP_ROSTER_UPDATE() function UnitGroup:GROUP_ROSTER_UPDATE()
@@ -94,23 +95,23 @@ function UnitGroup:PLAYER_ENTERING_WORLD()
self:OnRosterUpdate() self:OnRosterUpdate()
end end
function UnitGroup:UNIT_PET()
self:OnRosterUpdate()
end
function UnitGroup:PLAYER_REGEN_ENABLED() function UnitGroup:PLAYER_REGEN_ENABLED()
self:OnLeaveCombat() self:OnLeaveCombat()
end end
function UnitGroup:OnLeaveCombat() function UnitGroup:OnLeaveCombat()
if self.sortAfterCombat then
self:Sort() self:Sort()
self.sortAfterCombat = false
end
end end
function UnitGroup:OnRosterUpdate() function UnitGroup:OnRosterUpdate()
if InCombatLockdown() then if InCombatLockdown() then
self.sortAfterCombat = true return
else
self:Sort()
end end
self:Sort()
end end
function UnitGroup:AddUnitFrame(unit) function UnitGroup:AddUnitFrame(unit)