Compare commits

..

21 Commits

Author SHA1 Message Date
763bf0bdae Remove old unused textures for squares 2025-08-24 12:37:22 +02:00
f181c0022c Apply stylua to the entire codebase 2025-08-24 12:28:06 +02:00
0cced419a6 Make devloop do an initial install on first run 2025-08-24 12:28:06 +02:00
5bbbde3ca7 Update default configuration
This comprises many different configuration changes over a longer time
for multiple classes.
2025-08-24 12:28:06 +02:00
6f954b9d15 Add more immunity and burn spells to auralist 2025-08-24 12:28:06 +02:00
c56b847710 Add IconIndicator
Similar functionality to a SquareIndicator but uses an icon instead of a
solid color.
2025-08-24 12:28:06 +02:00
dc62b031a9 Update UnitAuraSlots API for TWW 2025-08-24 12:28:06 +02:00
ec7e2c74ff Update range check API to for TWW 2025-08-24 12:28:06 +02:00
b1dca1639d Properly update unit frames on GROUP_ROSTER_UPDATE 2025-08-24 12:28:06 +02:00
47542c7147 Expand config with more auras 2025-08-24 12:28:06 +02:00
1fce6017bd Add bar overlays for absorb and heal absorb 2025-08-24 12:27:56 +02:00
ff9d8b2289 Add/change monk and priest keybinds and auras 2023-11-05 19:20:16 +01:00
24c571658c Apply auto formatting to all source files 2023-09-10 12:37:25 +02:00
e20887d46b Implement fade and flash behavior for square indicators 2023-07-28 14:15:50 +02:00
877560cb58 Rework profiler for 10.1.0
Since GetFunctionCPUUsage was removed in 10.1.0 the entire profler
stopped working. This has been replaced by wrapping the functions in a
closure that runs GetTimePreciseSec before and after and keeps track of
the total runtime per function.
2023-07-27 15:29:08 +02:00
b201ef789a Partially fix unicode name truncation.
This fix ensures that name truncation always happens on codepoint
boundaries and that a name has exactly 5 visible codepoints. This should
cover all possible cases unless names can have grapheme clusters, afaik
this is not the case.
2023-07-26 03:15:13 +02:00
30d8248832 Expand spell ids for default AuraList statuses 2023-05-12 16:51:39 +02:00
5668a5b4db Fix a bug where AuraList wasn't processing a full update
This fixes issue #8
2023-05-12 15:50:34 +02:00
263b3f1330 Update default configuration indicators/keybinds/layout 2023-05-12 15:45:54 +02:00
45129a8635 Square- and BorderIndicator now use trigger data for changing color
If the field color is supplied from trigger data, these indicators will
now change their color. Currently this change is permanent and not bound to the
trigger.
2023-04-14 15:40:39 +02:00
1f95899781 Make Trigger responsible for default data
Trigger now has a new method Trigger:SetData and two new fields
Trigger.defaultData and Trigger.data

Whenever SetData is used it ensures that all the keys and values from
defaultData are present in the new data.

The data argument from Trigger:SetState has been removed and it will now
always use the Trigger.Data field for notifying indicators
2023-04-14 15:37:57 +02:00
25 changed files with 1332 additions and 334 deletions

1
.stylua.toml Normal file
View File

@@ -0,0 +1 @@
indent_type = "Spaces"

View File

@@ -11,6 +11,10 @@ if [[ ! -d "${WOW_ADDON_DIR}" ]]; then
exit 1 exit 1
fi fi
# Initial build / install
make -s build
rsync -q -a ./build/OmicronFrames "${WOW_ADDON_DIR}/" --delete
# Every time the source or texture directory tree is changed, wait 1 second and # Every time the source or texture directory tree is changed, wait 1 second and
# build the addon, then install it to the directory passed on the command line # build the addon, then install it to the directory passed on the command line
while true; do while true; do

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -17,6 +17,7 @@ types/statusbar.lua
types/auralist.lua types/auralist.lua
types/indicators/indicator.lua types/indicators/indicator.lua
types/indicators/squareindicator.lua types/indicators/squareindicator.lua
types/indicators/iconindicator.lua
types/indicators/borderindicator.lua types/indicators/borderindicator.lua
types/unitgroup.lua types/unitgroup.lua
types/unitframe.lua types/unitframe.lua

View File

@@ -17,29 +17,36 @@
local omif = select(2, ...) local omif = select(2, ...)
local colors = { local colors = {
cyan = {0.0, 0.8, 0.8}, cyan = { 0.0, 0.8, 0.8 },
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 },
magic = { 0.4, 0.4, 1.0 },
disease = { 0.4, 0.2, 0.0 },
poison = { 0.0, 0.7, 0.7 },
curse = { 0.7, 0.0, 0.7 },
red = { 1, 0, 0 },
blue = { 0.4, 0.4, 1 },
light_blue = { 0.7, 0.7, 1 },
} }
local function RangeConfig() local function RangeConfig()
local _, class = UnitClass("player") local _, class = UnitClass("player")
if class == "SHAMAN" then if class == "SHAMAN" then
return { return {
friendly = "Healing Surge", friendly = "Healing Wave",
enemy = "Lightning Bolt", enemy = "Lightning Bolt",
fade = 0.2 fade = 0.2,
} }
elseif class == "PRIEST" then elseif class == "PRIEST" then
return { return {
friendly = "Flash Heal", friendly = "Flash Heal",
enemy = "Smite", enemy = "Smite",
fade = 0.2 fade = 0.2,
} }
else else
return { return {
fade = 0.2 fade = 0.2,
} }
end end
end end
@@ -49,142 +56,618 @@ local function MouseConfig()
if class == "SHAMAN" then if class == "SHAMAN" then
return { return {
-- No modifier -- No modifier
{button="mouse1", mods={}, kind="target"}, { button = "mouse1", mods = {}, kind = "target" },
{button="mouse2", mods={}, kind="macro", data="/use [@UNIT,dead,help]Ancestral Vision; [@UNIT,help]Chain Heal"}, {
{button="mouse3", mods={}, kind="macro", data="/use [@UNIT,dead,help]Ancestral Spirit; [@UNIT,help]Purify Spirit"}, button = "mouse2",
{button="wheel-up", mods={}, kind="macro", data="/use [@UNIT,help]Healing Surge"}, mods = {},
{button="wheel-down", mods={}, kind="macro", data="/use [@UNIT,help]Riptide"}, kind = "macro",
data = "/use [@UNIT,dead,help]Ancestral Vision; [@UNIT,help]Chain Heal",
},
{
button = "mouse3",
mods = {},
kind = "macro",
data = "/use [@UNIT,dead,help]Ancestral Spirit; [@UNIT,help]Purify Spirit",
},
{
button = "wheel-up",
mods = {},
kind = "macro",
data = "/use [@UNIT,help]Healing Surge",
},
{ 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-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" },
-- Shift -- Shift
{button="mouse2", mods={shift=true}, kind="togglemenu"}, { button = "mouse2", mods = { shift = true }, kind = "togglemenu" },
{
button = "wheel-up",
mods = { shift = true },
kind = "macro",
data = "/cast [@UNIT,help]Water Walking;\n/stopspelltarget",
},
} }
elseif class == "PRIEST" then elseif class == "PRIEST" then
return { return {
-- No modifier -- No modifier
{button="mouse1", mods={}, kind="target"}, { button = "mouse1", mods = {}, kind = "target" },
{button="mouse2", mods={}, kind="macro", data="/use [@UNIT,dead,help]Mass Resurrection; [@UNIT,help]Power Word: Radiance"}, {
{button="mouse3", mods={}, kind="macro", data="/use [@UNIT,dead,help]Resurrection; [@UNIT,help]Purify"}, button = "mouse2",
{button="mouse4", mods={}, kind="spell", data="Shadow Covenant"}, mods = {},
{button="wheel-up", mods={}, kind="macro", data="/use [@UNIT,help]Flash Heal"}, kind = "macro",
{button="wheel-down", mods={}, kind="macro", data="/use [@UNIT,help]Renew"}, data = "/use [@UNIT,dead,help]Mass Resurrection; [@UNIT,help]Power Word: Radiance",
},
{
button = "mouse3",
mods = {},
kind = "macro",
data = "/use [@UNIT,dead,help]Resurrection; [@UNIT,help]Purify",
},
{ button = "mouse4", mods = {}, kind = "spell", data = "Shadow Covenant" },
{
button = "wheel-up",
mods = {},
kind = "macro",
data = "/use [@UNIT,help]Flash Heal",
},
{ button = "wheel-down", mods = {}, kind = "macro", data = "/use [@UNIT,help]Renew" },
-- alt -- alt
{button="mouse2", mods={alt=true}, kind="spell", data="Pain Suppression"}, { button = "mouse1", mods = { alt = true }, kind = "spell", data = "Power Word: Life" },
{button="mouse3", mods={alt=true}, kind="spell", data="Power Infusion"}, { button = "mouse2", mods = { alt = true }, kind = "spell", data = "Pain Suppression" },
{button="wheel-up", mods={alt=true}, kind="spell", data="Rapture"}, { button = "mouse3", mods = { alt = true }, kind = "spell", data = "Power Infusion" },
{button="wheel-down", mods={alt=true}, kind="spell", data="Power Word: Shield"}, { button = "wheel-up", mods = { alt = true }, kind = "spell", data = "Rapture" },
{ button = "wheel-down", mods = { alt = true }, kind = "spell", data = "Power Word: Shield" },
-- Shift -- Shift
{button="mouse2", mods={shift=true}, kind="togglemenu"}, { button = "mouse2", mods = { shift = true }, kind = "togglemenu" },
{button="wheel-up", mods={shift=true}, kind="macro", data="/cast [@UNIT,help]Levitate;\n/stopspelltarget"}, {
{button="wheel-down", mods={shift=true}, kind="macro", data="/cast [@UNIT,help]Leap of Faith;\n/stopspelltarget"}, button = "wheel-up",
mods = { shift = true },
kind = "macro",
data = "/cast [@UNIT,help]Levitate;\n/stopspelltarget",
},
{
button = "wheel-down",
mods = { shift = true },
kind = "macro",
data = "/cast [@UNIT,help]Leap of Faith;\n/stopspelltarget",
},
}
elseif class == "MONK" then
return {
-- No modifier
{ button = "mouse1", mods = {}, kind = "target" },
{
button = "mouse2",
mods = {},
kind = "macro",
data = (
"/use [@UNIT,known:Reawaken,dead,help]Reawaken; "
.. "[@UNIT,dead,help]Resuscitate; "
.. "[@UNIT,help]Tiger's Lust"
),
},
{
button = "mouse3",
mods = {},
kind = "macro",
data = "/use [@UNIT,dead,help]Resuscitate; [@UNIT,help]Detox",
},
{ button = "mouse4", mods = {}, kind = "spell", data = "Shadow Covenant" },
{ button = "wheel-up", mods = {}, kind = "macro", data = "/use [@UNIT,help]Vivify" },
{
button = "wheel-down",
mods = {},
kind = "macro",
data = "/use [@UNIT,help]Soothing Mist",
},
-- alt
{ button = "mouse1", mods = { alt = true }, kind = "spell", data = "Power Word: Life" },
{ button = "mouse2", mods = { alt = true }, kind = "spell", data = "Pain Suppression" },
{ button = "mouse3", mods = { alt = true }, kind = "spell", data = "Power Infusion" },
{ button = "wheel-up", mods = { alt = true }, kind = "spell", data = "Rapture" },
{ button = "wheel-down", mods = { alt = true }, kind = "spell", data = "Power Word: Shield" },
-- Shift
{ button = "mouse2", mods = { shift = true }, kind = "togglemenu" },
{
button = "wheel-up",
mods = { shift = true },
kind = "macro",
data = "/cast [@UNIT,help]Levitate;\n/stopspelltarget",
},
{
button = "wheel-down",
mods = { shift = true },
kind = "macro",
data = "/cast [@UNIT,help]Leap of Faith;\n/stopspelltarget",
},
}
elseif class == "PALADIN" then
return {
-- No modifier
{ button = "mouse1", mods = {}, kind = "target" },
{
button = "mouse2",
mods = {},
kind = "macro",
data = (
"/use [@UNIT,combat,dead,help]Intercession; "
.. "[@UNIT,known:Absolution,dead,help]Absolution; "
.. "[@UNIT,dead,help]Redemption; "
.. "[@UNIT,help]Blessing of Freedom"
),
},
{
button = "mouse3",
mods = {},
kind = "macro",
data = "/use [@UNIT,dead,help]Redemption; [@UNIT,help]Cleanse Toxins",
},
{
button = "mouse4",
mods = {},
kind = "spell",
data = "Word of Glory",
},
{
button = "mouse5",
mods = {},
kind = "spell",
data = "Blessing of Summer",
},
{
button = "wheel-up",
mods = {},
kind = "macro",
data = "/use [@UNIT,help]Flash of Light",
},
{
button = "wheel-down",
mods = {},
kind = "macro",
data = "/use [@UNIT,help,known:Holy Shock]Holy Shock; [@UNIT,help]Word of Glory",
},
-- Shift
{ button = "mouse2", mods = { shift = true }, kind = "togglemenu" },
-- alt
{ button = "mouse1", mods = { alt = true }, kind = "spell", data = "Blessing of Sacrifice" },
{ button = "mouse2", mods = { alt = true }, kind = "spell", data = "Blessing of Protection" },
{ button = "mouse3", mods = { alt = true }, kind = "spell", data = "Blessing of Spellwarding" },
{ button = "wheel-up", mods = { alt = true }, kind = "spell", data = "Holy Light" },
{ button = "wheel-down", mods = { alt = true }, kind = "spell", data = "Lay on Hands" },
} }
else else
return { return {
-- Super basic defaults -- Super basic defaults
{button="mouse1", mods={}, kind="target"}, { button = "mouse1", mods = {}, kind = "target" },
{button="mouse2", mods={shift=true}, kind="togglemenu"}, { button = "mouse2", mods = { shift = true }, kind = "togglemenu" },
} }
end end
end end
local function TriggerConfig() local function TriggerClassConfig()
local _, class = UnitClass("player") local _, class = UnitClass("player")
if class == "SHAMAN" then if class == "SHAMAN" then
return { return {
{ {
kind="AuraTrigger", spellId=383648, own=true, -- Second Earth Shield on yourself kind = "AuraTrigger",
indicator={ spellId = 383648,
kind="SquareIndicator", own = true, -- Second Earth Shield on yourself
size=14, indicator = {
point="TOPLEFT", kind = "SquareIndicator",
x=2, y=-2, size = 17,
color=colors.white, point = "TOPLEFT",
} x = 3,
y = -3,
color = colors.white,
showStacks = true,
},
}, },
{ {
kind="AuraTrigger", spellId=974, own=true, -- Second Earth Shield on yourself kind = "AuraTrigger",
indicator={ spellId = 974,
kind="SquareIndicator", own = true, -- Second Earth Shield on yourself
size=14, indicator = {
point="TOPLEFT", kind = "SquareIndicator",
x=2, y=-2, size = 17,
color=colors.white, point = "TOPLEFT",
} x = 3,
y = -3,
color = colors.white,
showStacks = true,
},
}, },
{ {
kind="AuraTrigger", spellId=61295, own=true, -- Riptide kind = "AuraTrigger",
indicator={ spellId = 61295,
kind="SquareIndicator", own = true, -- Riptide
size=14, indicator = {
point="BOTTOMLEFT", kind = "IconIndicator",
x=2, y=2, size = 17,
color=colors.cyan, point = "BOTTOMLEFT",
} x = 3,
y = 3,
fadeTime = 10.0,
},
},
{
kind = "StatusTrigger",
status = "Burn",
invert = false,
indicator = {
kind = "BorderIndicator",
thickness = 3.0,
color = colors.red,
level = 0,
},
}, },
} }
elseif class == "PRIEST" then elseif class == "PRIEST" then
return { return {
{ {
kind="AuraTrigger", spellId=17, own=true, -- Power Word: Shield kind = "AuraTrigger",
indicator={ spellId = 17,
kind="SquareIndicator", own = true, -- Power Word: Shield
size=14, indicator = {
point="TOPLEFT", kind = "SquareIndicator",
x=2, y=-2, size = 17,
color=colors.white, point = "TOPLEFT",
} x = 3,
y = -3,
color = colors.white,
fadeTime = 10.0,
},
}, },
{ {
kind="AuraTrigger", spellId=33206, own=true, -- Pain Suppression kind = "AuraTrigger",
indicator={ spellId = 33206,
kind="SquareIndicator", own = true, -- Pain Suppression
size=14, indicator = {
point="TOPLEFT", kind = "SquareIndicator",
x=18, y=-2, size = 17,
color=colors.orange, point = "TOPLEFT",
} x = 22,
y = -3,
color = colors.orange,
fadeTime = 10.0,
flashTime = 1.3,
},
}, },
{ {
kind="AuraTrigger", spellId=139, own=true, -- Renew kind = "AuraTrigger",
indicator={ spellId = 41635,
kind="SquareIndicator", own = true, -- Prayer of Mending
size=14, indicator = {
point="BOTTOMLEFT", kind = "SquareIndicator",
x=2, y=2, size = 17,
color=colors.cyan, point = "TOPLEFT",
} x = 41,
y = -3,
color = { 0.7, 0.9, 1 },
showStacks = true,
},
}, },
{ {
kind="AuraTrigger", spellId=194384, own=true, -- Renew kind = "AuraTrigger",
indicator={ spellId = 139,
kind="SquareIndicator", own = true, -- Renew
size=14, indicator = {
point="BOTTOMLEFT", kind = "SquareIndicator",
x=18, y=2, size = 17,
color=colors.white, point = "BOTTOMLEFT",
} x = 3,
y = 3,
color = colors.cyan,
fadeTime = 10.0,
},
}, },
{ {
kind="AuraTrigger", spellId=10060, own=true, -- Renew kind = "AuraTrigger",
indicator={ spellId = 194384,
kind="SquareIndicator", own = true, -- Atonement
size=14, indicator = {
point="BOTTOMLEFT", kind = "SquareIndicator",
x=34, y=2, size = 17,
color=colors.violet, point = "BOTTOMLEFT",
} x = 22,
y = 3,
color = colors.white,
fadeTime = 10.0,
flashTime = 1.3,
},
},
{
kind = "AuraTrigger",
spellId = 10060,
own = true, -- Power Infusion
indicator = {
kind = "SquareIndicator",
size = 17,
point = "BOTTOMLEFT",
x = 41,
y = 3,
color = colors.violet,
fadeTime = 10.0,
},
},
{
kind = "StatusTrigger",
status = "Burn",
invert = false,
indicator = {
kind = "BorderIndicator",
thickness = 3.0,
color = colors.red,
level = 0,
},
},
}
elseif class == "PALADIN" then
return {
{
kind = "AuraTrigger",
spellId = 287280, -- Glimmer of Light
own = true,
indicator = {
kind = "SquareIndicator",
size = 17,
point = "TOPLEFT",
x = 3,
y = -3,
color = colors.white,
fadeTime = 10.0,
flashTime = 1.3,
},
},
{
kind = "AuraTrigger",
spellId = 25771, -- Forbearance
indicator = {
kind = "SquareIndicator",
size = 17,
point = "TOPLEFT",
x = 22,
y = -3,
color = colors.red,
fadeTime = 10.0,
flashTime = 1.3,
},
},
{
kind = "AuraTrigger",
spellId = 53563, -- Beacon of Light
own = true,
indicator = {
kind = "SquareIndicator",
size = 17,
point = "TOPLEFT",
x = 41,
y = -3,
color = colors.white,
},
},
{
kind = "AuraTrigger",
spellId = 156910, -- Beacon of Faith
own = true,
indicator = {
kind = "SquareIndicator",
size = 17,
point = "TOPLEFT",
x = 41,
y = -3,
color = colors.light_blue,
},
},
{
kind = "AuraTrigger",
spellId = 200025, -- Beacon of Virtue
own = true,
indicator = {
kind = "SquareIndicator",
size = 17,
point = "TOPLEFT",
x = 41,
y = -3,
color = colors.white,
},
},
{
kind = "AuraTrigger",
spellId = 1044, -- Blessing of Freedom
own = true,
indicator = {
kind = "SquareIndicator",
size = 17,
point = "BOTTOMLEFT",
x = 3,
y = 3,
color = colors.orange,
flashTime = 1.3,
},
},
{
kind = "AuraTrigger",
spellId = 1111, -- Blessing of Spellwarding
own = true,
indicator = {
kind = "SquareIndicator",
size = 17,
point = "BOTTOMLEFT",
x = 41,
y = 3,
color = colors.cyan,
flashTime = 1.3,
},
},
{
kind = "AuraTrigger",
spellId = 1022, -- Blessing of Protection
own = true,
indicator = {
kind = "SquareIndicator",
size = 17,
point = "BOTTOMLEFT",
x = 41,
y = 3,
color = colors.cyan,
flashTime = 1.3,
},
},
{
kind = "AuraTrigger",
spellId = 6940, -- Blessing of Saccrifice
own = true,
indicator = {
kind = "SquareIndicator",
size = 17,
point = "BOTTOMLEFT",
x = 61,
y = 3,
color = colors.red,
flashTime = 1.3,
},
},
{
kind = "StatusTrigger",
status = "Burn",
invert = false,
indicator = {
kind = "BorderIndicator",
thickness = 3.0,
color = colors.red,
level = 0,
},
}, },
} }
else else
return {} return {
{
kind = "StatusTrigger",
status = "Burn",
invert = false,
indicator = {
kind = "BorderIndicator",
thickness = 3.0,
color = colors.red,
level = 0,
},
},
}
end end
end end
-- Quick helper function to create a config for debuff triggers
local function MakeDebuffTrigger(slot, spellid, color, stacks)
if stacks == nil then
stacks = false
end
return {
kind = "AuraTrigger",
spellId = spellid,
indicator = {
kind = "SquareIndicator",
size = 15,
point = "TOPRIGHT",
x = -17 * slot,
y = -3,
color = color,
showStacks = stacks,
},
}
end
local function TriggerConfig()
local triggers = TriggerClassConfig()
print("Class triggers:", #triggers)
-- slot, spellid, color, stacks
local debuffs = {
-- Kezzara, Aberrus
{ 1, 406525, colors.orange }, -- Dread Rift
{ 2, 402253, colors.red }, -- Ray of Anguish
{ 3, 404743, colors.violet, true }, -- Terror Claws
-- Forgotten Experiment, Aberrus
{ 1, 406365, colors.red, true }, -- Rending Charge (p1)
{ 1, 407327, colors.cyan, true }, -- Unstable Essence (p2/p3)
{ 3, 407313, colors.violet, true }, -- Infused Strikes
-- Uldaman: Legacy of Tyr
{ 1, 377510, colors.cyan, true }, -- Stolen Time
-- Brackenhide Hollow
{ 1, 367521, colors.cyan, true }, -- Bone Bolt
-- The Underrot
--{1, 273226, colors.green, true}, -- Decaying Spores
-- Sarkareth, Aberrus
{ 3, 401330, colors.violet }, -- Burning Claws (P1 tank)
{ 3, 411241, colors.violet }, -- Void Claws (P2 tank)
{ 3, 408429, colors.violet }, -- Void Slash (P3 tank)
{ 2, 404218, colors.blue }, -- Void Fracture (carry bomb)
{ 1, 401951, colors.cyan, true }, -- Oblivion
-- Darkheart Thicket
{ 3, 225484, colors.violet }, -- Grievous Rip
{ 3, 196376, colors.violet }, -- Grievous Tear
-- Throne of the Tides
{ 1, 426660, colors.red, true }, -- Razor Jaws
-- Nymue, Amirdrassil
{ 1, 429785, colors.red }, -- Loom (line stun)
{ 1, 417807, colors.red, true }, -- Fyrakk
-- Algeth'ar Academy
{ 1, 389033, colors.poison, true },
{ 1, 388912, colors.red, true },
{ 2, 391977, colors.cyan, true },
{ 2, 389011, colors.cyan, true },
-- Nokhud Offensive
{ 1, 381692, colors.red, true },
-- Tazavesh
{ 1, 1240102, colors.orange, true },
-- Priory of the Sacred Flame
{ 1, 424414, colors.violet, true },
}
for _, debuff in ipairs(debuffs) do
table.insert(triggers, MakeDebuffTrigger(debuff[1], debuff[2], debuff[3], debuff[4]))
end
print("All triggers:", #triggers)
-- Some more debuffs in the bottom row
table.insert(triggers, {
kind = "AuraTrigger",
spellId = 240443, -- Bursting
indicator = {
kind = "SquareIndicator",
size = 17,
point = "BOTTOMRIGHT",
x = -3,
y = 3,
color = colors.red,
fadeTime = 3.0,
showStacks = true,
},
})
return triggers
end
local types = omif.GetModule("types") local types = omif.GetModule("types")
local UnitFrame = types.UnitFrame local UnitFrame = types.UnitFrame
local UnitGroup = types.UnitGroup local UnitGroup = types.UnitGroup
@@ -198,7 +681,7 @@ function HideBlizzardFrames()
TargetFrame, TargetFrame,
FocusFrame, FocusFrame,
PartyFrame, PartyFrame,
CompactRaidFrameContainer CompactRaidFrameContainer,
} }
for _, frame in ipairs(blizzardFrames) do for _, frame in ipairs(blizzardFrames) do
@@ -212,9 +695,9 @@ function CreateRaidFrames(left, top, config)
local width = config.size.width local width = config.size.width
local height = config.size.height local height = config.size.height
local group = UnitGroup:new(left, top, width, height) local group = UnitGroup:new(left, top, width, height)
for i=0,5 do for i = 0, 5 do
for j=0,4 do for j = 0, 4 do
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)
end end
@@ -227,7 +710,7 @@ 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)
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)
end end
@@ -241,16 +724,16 @@ function CreateTargetFrames(left, top, config)
focus:SetPosition(left, top) focus:SetPosition(left, top)
local target = UnitFrame:new("target", config) local target = UnitFrame:new("target", config)
target:SetPosition(left, top - height) target:SetPosition(left, top - height)
for i=1,4 do for i = 1, 4 do
local boss = UnitFrame:new("boss" .. i, config) local boss = UnitFrame:new("boss" .. i, config)
boss:SetPosition(left, top-(i+1)*height) boss:SetPosition(left, top - (i + 1) * height)
end end
end end
function CreateFrames() function CreateFrames()
config = { local config = {
size = { size = {
width = 110, width = 111,
height = 45, height = 45,
}, },
range = RangeConfig(), range = RangeConfig(),
@@ -259,10 +742,11 @@ function CreateFrames()
triggers = TriggerConfig(), triggers = TriggerConfig(),
} }
CreatePartyFrames(0, -290, config) CreatePartyFrames(-0.05, -290.05, config)
config.hideInRaid = false config.hideInRaid = false
CreateRaidFrames(0, -290, config) CreateRaidFrames(-0.05, -290.05, config)
CreateTargetFrames(110*3+50, -245, config) CreateTargetFrames(110 * 3 + 50 - 0.05, -245.05, config)
HideBlizzardFrames() HideBlizzardFrames()
end end
omif.SetEventHandler("OMICRON_LOADING", CreateFrames) omif.SetEventHandler("OMICRON_LOADING", CreateFrames)

View File

@@ -19,7 +19,7 @@ omif.events = {} -- event (str) to list of handlers
omif.db = nil omif.db = nil
OmicronFrames = {} OmicronFrames = {}
omif.modules = {public=OmicronFrames} omif.modules = { public = OmicronFrames }
-- Simple function that creates or returns a local module table -- Simple function that creates or returns a local module table
function omif.GetModule(name) function omif.GetModule(name)
if omif.modules[name] == nil then if omif.modules[name] == nil then
@@ -66,6 +66,7 @@ function omif.OnAddonLoaded(name)
omif.MainEventHandler(nil, "OMICRON_LOADING") omif.MainEventHandler(nil, "OMICRON_LOADING")
print("Loaded", AddonName) print("Loaded", AddonName)
end end
omif.SetEventHandler("ADDON_LOADED", omif.OnAddonLoaded) omif.SetEventHandler("ADDON_LOADED", omif.OnAddonLoaded)
-- Fire custom event OMICRON_FULLY_LOADED. This event is fired when the player -- Fire custom event OMICRON_FULLY_LOADED. This event is fired when the player
@@ -75,6 +76,7 @@ function omif.FireFullyLoadedEvent(initialLogin, reloadUI)
omif.MainEventHandler(nil, "OMICRON_FULLY_LOADED") omif.MainEventHandler(nil, "OMICRON_FULLY_LOADED")
end end
end end
omif.SetEventHandler("PLAYER_ENTERING_WORLD", omif.FireFullyLoadedEvent) omif.SetEventHandler("PLAYER_ENTERING_WORLD", omif.FireFullyLoadedEvent)
function omif.SlashCommand(args) function omif.SlashCommand(args)

View File

@@ -26,56 +26,117 @@ local Printf = Commander.Printf
local types = omi.GetModule("types") local types = omi.GetModule("types")
local data = {} local data = {}
local startTime
local stopTime
local functionTimers = {}
local functionNames = {}
Commander.RegisterCommand("omi-pstart", { -- Permanently wrap all functions to do profiling
description="Start/reset the OmicronFrames profiler", local function EnableFunctionProfiler()
command=function() if #functionTimers ~= 0 then
local profiler = C_CVar.GetCVar("scriptProfile") return
if profiler ~= "1" then
PrintLn("scriptProfiler is off")
PrintLn("set it to on with `/console scriptProfile 1`, then reload the UI.")
return
end
PrintLn("OmicronFrames: start profiling")
ResetCPUUsage()
end end
}) local GetTimePreciseSec = GetTimePreciseSec
local counter = 1
Commander.RegisterCommand("omi-pstop", { for typeName, T in pairs(types) do
description="Stop the OmicronFrames profiler", if type(T) == "table" then
command=function() PrintLn("Type:", typeName, T)
PrintLn("OmicronFrames: stop profiling") for fnName, fn in pairs(T) do
UpdateAddOnCPUUsage() if type(fn) == "function" then
local total = GetAddOnCPUUsage(addonName) local fnIdx = counter
data = {{ counter = counter + 1
name = "Total OmicronFrames time", local name = string.format("%s:%s", typeName, fnName)
time = total, functionTimers[fnIdx] = 0
pct = 1.0 functionNames[fnIdx] = name
}} local wrapped = function(...)
local start = GetTimePreciseSec()
for typeName, T in pairs(types) do local a, b, c, d, e, f, g, h = fn(...)
if type(T) == "table" then local elapsed = GetTimePreciseSec() - start
for fnName, fn in pairs(T) do functionTimers[fnIdx] = functionTimers[fnIdx] + elapsed
if type(fn) == "function" then return a, b, c, d, e, f, g, h
local time = GetFunctionCPUUsage(fn, true)
table.insert(data, {
name = string.format("%s:%s", typeName, fnName),
time = time,
pct = time/total
})
end end
T[fnName] = wrapped
end end
end end
end end
table.sort(data, function(a, b) return a.time > b.time end) end
end
-- Set all function timers back to 0
local function ResetFunctionProfiler()
for i, _ in ipairs(functionTimers) do
functionTimers[i] = 0
end
end
Commander.RegisterCommand("omi-pstart", {
description = "Start/reset the OmicronFrames profiler",
command = function()
local profiler = C_CVar.GetCVar("scriptProfile")
PrintLn("OmicronFrames: start profiling")
EnableFunctionProfiler()
ResetFunctionProfiler()
startTime = GetTimePreciseSec()
stopTime = nil
if profiler == "1" then
ResetCPUUsage()
else
PrintLn("WoW scriptProfiler is off. Addon totals will not be shown,")
PrintLn("only individual functions.The profiler will not show total")
PrintLn("addon time, only function profiler.")
PrintLn("")
PrintLn("To enable the script profiler run `/console scriptProfile 1`, then reload the UI.")
return
end
end,
})
Commander.RegisterCommand("omi-pstop", {
description = "Stop the OmicronFrames profiler",
command = function()
if not startTime then
PrintLn("Profiling not started. Run omi-pstart first.")
return
end
PrintLn("OmicronFrames: stop profiling")
local profiler = C_CVar.GetCVar("scriptProfile") == "1"
data = {}
stopTime = GetTimePreciseSec()
if profiler then
UpdateAddOnCPUUsage()
local total = GetAddOnCPUUsage(addonName)
table.insert(data, {
name = "Total OmicronFrames time",
time = total,
})
end
for i, time in ipairs(functionTimers) do
local name = functionNames[i]
table.insert(data, {
name = name,
time = time * 1000,
})
end
table.sort(data, function(a, b)
return a.time < b.time
end)
end, end,
}) })
Commander.RegisterCommand("omi-pprint", { Commander.RegisterCommand("omi-pprint", {
description="Print the collected OmicronFrames profiling data", description = "Print the collected OmicronFrames profiling data",
command=function() command = function()
for _, item in ipairs(data) do if not stopTime then
Printf("% 5.1f%% % 5fms %s\n", item.pct*100, item.time, item.name) PrintLn("Profiling data not collected yet. Run omi-pstop first.")
return
end end
end local top = data[#data].time
local total = stopTime - startTime
for _, item in ipairs(data) do
local time = item.time
local pct = time / top * 100
local ms_per_sec = time / total
Printf("% 6.1f%% % 7.2fms %7.2fms/s %s\n", pct, time, ms_per_sec, item.name)
end
end,
}) })

View File

@@ -24,27 +24,119 @@ types.AuraList = AuraList
local statusLists = { local statusLists = {
Immune = { Immune = {
[642] = true, -- Divine Shield, Paladin [642] = true, -- Divine Shield, Paladin
[186265] = true -- Aspect of the Turtle, Hunter [186265] = true, -- Aspect of the Turtle, Hunter
[45438] = true, -- Ice Block
[31224] = true, -- Cloak of Shadows
[196555] = true, -- Netherwalk
}, },
Bomb = { Bomb = {
[642] = true, -- Divine Shield, Paladin [381615] = true, -- Raszageth, Static Charge
[186265] = true, -- Aspect of the Turtle, Hunter [377467] = true, -- Raszageth, Fulminating Charge
[381615] = true, -- Raszageth, Static Charge [399713] = true, -- Raszageth, Magnetic Charge
[377467] = true -- Raszageth, Fulminating Charge [397797] = true, -- Corrupted Vortex, Jade Serpent Temple
[387843] = true, -- Astral Bomb, Algeth'ar Academy
[386181] = true, -- Mana Bomb, Algeth'ar Academy
[401330] = true, -- Sarkareth, Burning Claws (p1 tank)
[411241] = true, -- Sarkareth, Void Claws (p2 tank)
[408429] = true, -- Sarkareth, Void Slash (p3 tank)
[404218] = true, -- Sarkareth, Void fracture (bombs)
[427722] = true, -- Nymue, Weaver's Burden (hehe jk it's private because reasons)
}, },
Burn = { Burn = {
[642] = true, -- Divine Shield, Paladin -- Jade Serpent Temple
[186265] = true -- Aspect of the Turtle, Hunter [114803] = true, -- Throw Torch
} [397914] = true, -- Defiling Mist
[106114] = true, -- Touch of Nothingness
-- Shadow moon Burial Ground
[152819] = true, -- Shadow Word: Frailty
[153524] = true, -- Plague Spit
-- Court of Stars
[397907] = true, -- Impending Doom
[209516] = true, -- Mana Fang
[207980] = true, -- Disintegration Beam
[211464] = true, -- Fel Detonation
-- Algeth'ar Academy
[376997] = true, -- Savage Peck, Algeth'ar Academy
[388912] = true, -- Severing Slash, Algeth'ar Academy
[388866] = true, -- Mana Void, Algeth'ar Academy
-- Vault of the Incarnates
[390911] = true, -- Raszageth, Lingering Charge
-- Atal'Dazar
[255582] = true, -- Priestess Alun'za, Molten Gold
[250096] = true, -- Yazma, Wracking pain
[255434] = true, -- Rezan, Serrated Teeth
-- The MOTHERLODE!!
[259853] = true, -- Rixxa Fluxflame, Chemical Burn
-- Halls of Infusion
-- Uldaman: Legacy of Tyr
[372718] = true, -- Earthen Shards
-- Brackenhide Hollow
[367521] = true, -- Bone Bolt
[367484] = true, -- Vicious Clawmangle
[378020] = true, -- Gash Frenzy
[385058] = true, -- Withering Poison
[384575] = true, -- Crippling Bite
-- Neltharus
[373735] = true, -- Dragon Strike
[372224] = true, -- Draogonbone Axe
[377018] = true, -- Molten Gold
[372570] = true, -- Bold Ambush
-- Neltharion's Lair
-- Freehold
[413131] = true, -- Whirling Dagger
-- The Underrot
[265019] = true, -- Savage Cleave
[265568] = true, -- Dark Omen
[273226] = true, -- Decaying Spores
-- Vortex Pinnacle
-- Aberrus
[404010] = true, -- Zkarn, ???
[405462] = true, -- Zkarn, ???
-- Dawn of the infinite: Galakrond's fall
[407406] = true,
-- Darkheart Thicket
-- Amirdrassil
[427721] = true, -- Nymue, Weaver's burden (dot part)
-- Waycrest Manor
[263943] = true, -- Etch
[264378] = true, -- Fragment Soul
-- Ruby Lifepools
[381862] = true, -- Kyrakka, Infernocore
-- Nokhud Offensive
[381692] = true, -- Swift Stab
-- Priory of the Sacred Flame
[447439] = true, -- Savage Mauling
},
} }
-- helper function that goes over several aura slots for a unit. Runs a -- helper function that goes over several aura slots for a unit. Runs a
-- callback function with UnitAuraInfo table as argument -- callback function with UnitAuraInfo table as argument
local function ForEachAuraSlots(unit, fn, continuationToken, ...) local function ForEachAuraSlots(unit, fn, continuationToken, ...)
local GetAuraDataBySlot = C_UnitAuras.GetAuraDataBySlot local GetAuraDataBySlot = C_UnitAuras.GetAuraDataBySlot
local n = select('#', ...) local n = select("#", ...)
for i=1, n do for i = 1, n do
local slot = select(i, ...) local slot = select(i, ...)
fn(GetAuraDataBySlot(unit, slot)) fn(GetAuraDataBySlot(unit, slot))
end end
@@ -53,11 +145,11 @@ end
-- Helper function that goes over all aura slots for a given filter -- Helper function that goes over all aura slots for a given filter
local function ForEachAuraFiltered(unit, filter, fn) local function ForEachAuraFiltered(unit, filter, fn)
local UnitAuraSlots = UnitAuraSlots local UnitAuraSlots = C_UnitAuras.GetAuraSlots
local continuationToken = nil local continuationToken = nil
repeat repeat
continuationToken = ForEachAuraSlots(unit, fn, UnitAuraSlots(unit, filter, nil, continuationToken)) continuationToken = ForEachAuraSlots(unit, fn, UnitAuraSlots(unit, filter, nil, continuationToken))
until (continuationToken == nil) until continuationToken == nil
end end
-- Similar to what AuraUtils.ForEachAura does except the callback fn takes a -- Similar to what AuraUtils.ForEachAura does except the callback fn takes a
@@ -67,7 +159,6 @@ local function ForEachAura(unit, fn)
ForEachAuraFiltered(unit, "HARMFUL", fn) ForEachAuraFiltered(unit, "HARMFUL", fn)
end end
---@return AuraList ---@return AuraList
function AuraList.new(cls, ...) function AuraList.new(cls, ...)
--- I really dislike duplicating this everywhere but it makes --- I really dislike duplicating this everywhere but it makes
@@ -84,7 +175,6 @@ function AuraList:Init(unitframe)
self.statusCount = {} self.statusCount = {}
self.auras = {} -- map AuraInstanceID to UnitAuraInfo table self.auras = {} -- map AuraInstanceID to UnitAuraInfo table
self.triggers = {} self.triggers = {}
self.triggersBySpell = {} self.triggersBySpell = {}
self.triggersByStatus = {} self.triggersByStatus = {}
@@ -213,8 +303,15 @@ function AuraList:RemoveAura(iid)
return statusChanged return statusChanged
end end
-- FIXME: param wrong
---@param info UnitAuraInfo ---@param info UnitAuraInfo
function AuraList:Update(info) function AuraList:Update(info)
if info.isFullUpdate then
self:Reset()
-- FIXME: return value might not reflect truth but true is the more prudent choice
return true
end
local GetAuraDataByAuraInstanceID = C_UnitAuras.GetAuraDataByAuraInstanceID local GetAuraDataByAuraInstanceID = C_UnitAuras.GetAuraDataByAuraInstanceID
local statusChanged = false local statusChanged = false
for _, aura in ipairs(info.addedAuras or {}) do for _, aura in ipairs(info.addedAuras or {}) do

View File

@@ -70,17 +70,26 @@ end
--- Show the square indicator. --- Show the square indicator.
---@param data table ---@param data table
function BorderIndicator:Show(data) function BorderIndicator:Show(data)
if data.color then
self.color = data.color
end
local frame, stacks = self:GetFrame() local frame, stacks = self:GetFrame()
frame:Show() frame:Show()
end end
function BorderIndicator:Update(data)
if data.color then
self:SetColor(data.color)
end
end
function BorderIndicator:GetFrame() function BorderIndicator:GetFrame()
local frame, new = borderPool:Acquire() local frame, new = borderPool:Acquire()
if new then if new then
frame.backdropInfo = { frame.backdropInfo = {
edgeFile = "Interface\\Addons\\OmicronFrames\\media\\textures\\pixel_edge", edgeFile = "Interface\\Addons\\OmicronFrames\\media\\textures\\pixel_edge",
edgeSize = 1, edgeSize = 1,
insets = {left=0, right=0, top=0, bottom=0}, insets = { left = 0, right = 0, top = 0, bottom = 0 },
} }
end end
@@ -99,4 +108,3 @@ function BorderIndicator:Hide()
self.frame = nil self.frame = nil
borderPool:Release(frame) borderPool:Release(frame)
end end

View File

@@ -0,0 +1,173 @@
-- Copyright 2025 <omicron.me@protonmail.com>
--
-- 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 <https://www.gnu.org/licenses/>.
local omi = select(2, ...)
local types = omi.GetModule("types")
local iconPool = CreateFramePool("Frame", nil, "BackdropTemplate")
---IconIndicator is an indicator that displays an icon with border
---@class IconIndicator: Indicator
local IconIndicator = types.CreateClass("IconIndicator", Indicator)
types.IconIndicator = IconIndicator
---@return IconIndicator
function IconIndicator.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 IconIndicator
-- 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
---@param unitframe UnitFrame
---@param size number
---@param point string
---@param x number
---@param y number
---@param showStacks boolean
---@param doFade nil|number
---@param doFlash nil|number
function IconIndicator:Init(unitframe, size, point, x, y, showStacks, fadeTime, flashTime)
self.unitframe = unitframe
self.frameParent = unitframe.overlays
self.size = size
self.point = point
self.x = x
self.y = y
self.icon = 134400
self.showStacks = showStacks
self.fadeTime = fadeTime
self.flashTime = flashTime
end
--- Show the square indicator
---@param data table
function IconIndicator:Show(data)
local frame, stacks = self:GetFrame()
local numStacks = data.stacks or 0
self.frame = frame
self.stacks = stacks
if self.showStacks and numStacks > 0 then
stacks:SetText(numStacks)
stacks:Show()
end
if self.flashTime or self.fadeTime then
self.frame:SetScript("OnUpdate", function(frame, dt)
self:OnUpdate(dt)
end)
self.expirationTime = data.expirationTime
self.updateThrottle = 0
end
if data.icon then
self:SetIcon(data.icon)
else
self:SetIcon(self.icon)
end
frame:Show()
end
--- Set the icon of the Icon Indicator
function IconIndicator:SetIcon(icon)
self.icon = icon
local frame = self.frame
if frame then
frame.iconTexture:SetTexture(icon)
end
end
function IconIndicator:GetFrame()
local frame, new = iconPool:Acquire()
local stacks
if new then
local iconTexture = frame:CreateTexture(nil, "BACKGROUND")
iconTexture:SetAllPoints()
frame.iconTexture = iconTexture
frame.backdropInfo = {
bgFile = nil,
edgeFile = "Interface\\Addons\\OmicronFrames\\media\\textures\\pixel_edge",
edgeSize = 2,
insets = { left = 0, right = 0, top = 0, bottom = 0 },
}
frame:ApplyBackdrop()
stacks = frame:CreateFontString(nil, "OVERLAY")
frame.stacks = stacks
stacks:SetFont("Interface\\AddOns\\OmicronFrames\\media\\fonts\\roboto\\Roboto-Medium.ttf", 12, "OUTLINE")
stacks:SetPoint("CENTER")
stacks:SetTextColor(1, 1, 1)
end
frame:SetSize(self.size, self.size)
frame:SetParent(self.frameParent)
frame:SetPoint(self.point, self.x, self.y)
frame:SetBackdropBorderColor(0, 0, 0, 1)
frame:SetAlpha(1)
stacks = frame.stacks
return frame, stacks
end
---@param data table
function IconIndicator:Update(data)
if data.icon then
self:SetIcon(data.icon)
end
local numStacks = data.stacks or 0
if numStacks > 0 then
self.stacks:SetText(numStacks)
self.stacks:Show()
end
self.expirationTime = data.expirationTime
self.frame:SetAlpha(1)
end
function IconIndicator:OnUpdate(dt)
dt = self.updateThrottle + dt
if dt < 0.04 then
self.updateThrottle = dt
return
else
self.updateThrottle = 0
end
local timeLeft = self.expirationTime - GetTime()
local fadeTime = self.fadeTime or 0
local flashTime = self.flashTime or 0
if timeLeft < flashTime then
local alpha = ((timeLeft * 4) % 1)
self.frame:SetAlpha(alpha)
elseif timeLeft < fadeTime then
local alpha = timeLeft / fadeTime
self.frame:SetAlpha(alpha)
end
end
--- Hide the square indicator.
function IconIndicator:Hide()
local frame = self.frame
self.stacks:Hide()
self.frame = nil
self.stacks = nil
frame:SetScript("OnUpdate", nil)
iconPool:Release(frame)
end

View File

@@ -26,14 +26,10 @@ local Indicator = types.CreateClass("Indicator")
types.Indicator = Indicator types.Indicator = Indicator
--- Show the indicator and supply it with data --- Show the indicator and supply it with data
function Indicator:Show(data) function Indicator:Show(data) end
end
--- Update the indicator with new data --- Update the indicator with new data
function Indicator:Update(data) function Indicator:Update(data) end
end
--- Hide the indicator --- Hide the indicator
function Indicator:Hide() function Indicator:Hide() end
end

View File

@@ -45,7 +45,9 @@ end
---@param y number ---@param y number
---@param color number[] ---@param color number[]
---@param showStacks boolean ---@param showStacks boolean
function SquareIndicator:Init(unitframe, size, point, x, y, color, showStacks) ---@param doFade nil|number
---@param doFlash nil|number
function SquareIndicator:Init(unitframe, size, point, x, y, color, showStacks, fadeTime, flashTime)
self.unitframe = unitframe self.unitframe = unitframe
self.frameParent = unitframe.overlays self.frameParent = unitframe.overlays
self.size = size self.size = size
@@ -54,6 +56,8 @@ function SquareIndicator:Init(unitframe, size, point, x, y, color, showStacks)
self.y = y self.y = y
self.color = color self.color = color
self.showStacks = showStacks self.showStacks = showStacks
self.fadeTime = fadeTime
self.flashTime = flashTime
end end
--- Set the color of the Square Indicator --- Set the color of the Square Indicator
@@ -61,7 +65,7 @@ end
function SquareIndicator:SetColor(color) function SquareIndicator:SetColor(color)
self.color = color self.color = color
local frame = self.frame local frame = self.frame
if frame then if frame then
frame:SetBackdropColor(unpack(color)) frame:SetBackdropColor(unpack(color))
end end
end end
@@ -77,7 +81,18 @@ function SquareIndicator:Show(data)
stacks:SetText(numStacks) stacks:SetText(numStacks)
stacks:Show() stacks:Show()
end end
frame:SetBackdropColor(unpack(self.color)) if self.flashTime or self.fadeTime then
self.frame:SetScript("OnUpdate", function(frame, dt)
self:OnUpdate(dt)
end)
self.expirationTime = data.expirationTime
self.updateThrottle = 0
end
if data.color then
self:SetColor(data.color)
else
frame:SetBackdropColor(unpack(self.color))
end
frame:Show() frame:Show()
end end
@@ -89,7 +104,7 @@ function SquareIndicator:GetFrame()
bgFile = "Interface\\Addons\\OmicronFrames\\media\\textures\\square_white", bgFile = "Interface\\Addons\\OmicronFrames\\media\\textures\\square_white",
edgeFile = "Interface\\Addons\\OmicronFrames\\media\\textures\\pixel_edge", edgeFile = "Interface\\Addons\\OmicronFrames\\media\\textures\\pixel_edge",
edgeSize = 2, edgeSize = 2,
insets = {left=0, right=0, top=0, bottom=0}, insets = { left = 0, right = 0, top = 0, bottom = 0 },
} }
frame:ApplyBackdrop() frame:ApplyBackdrop()
@@ -104,17 +119,45 @@ function SquareIndicator:GetFrame()
frame:SetParent(self.frameParent) frame:SetParent(self.frameParent)
frame:SetPoint(self.point, self.x, self.y) frame:SetPoint(self.point, self.x, self.y)
frame:SetBackdropBorderColor(0, 0, 0, 1) frame:SetBackdropBorderColor(0, 0, 0, 1)
frame:SetAlpha(1)
stacks = frame.stacks stacks = frame.stacks
return frame, stacks return frame, stacks
end end
---@param data table ---@param data table
function SquareIndicator:Update(data) function SquareIndicator:Update(data)
if data.color then
self:SetColor(data.color)
end
local numStacks = data.stacks or 0 local numStacks = data.stacks or 0
if numStacks > 0 then if numStacks > 0 then
self.stacks:SetText(numStacks) self.stacks:SetText(numStacks)
self.stacks:Show() self.stacks:Show()
end end
self.expirationTime = data.expirationTime
self.frame:SetAlpha(1)
end
function SquareIndicator:OnUpdate(dt)
dt = self.updateThrottle + dt
if dt < 0.04 then
self.updateThrottle = dt
return
else
self.updateThrottle = 0
end
local timeLeft = self.expirationTime - GetTime()
local fadeTime = self.fadeTime or 0
local flashTime = self.flashTime or 0
if timeLeft < flashTime then
local alpha = ((timeLeft * 4) % 1)
self.frame:SetAlpha(alpha)
elseif timeLeft < fadeTime then
local alpha = timeLeft / fadeTime
self.frame:SetAlpha(alpha)
end
end end
--- Hide the square indicator. --- Hide the square indicator.
@@ -123,5 +166,6 @@ function SquareIndicator:Hide()
self.stacks:Hide() self.stacks:Hide()
self.frame = nil self.frame = nil
self.stacks = nil self.stacks = nil
frame:SetScript("OnUpdate", nil)
squarePool:Release(frame) squarePool:Release(frame)
end end

View File

@@ -20,8 +20,10 @@ local types = omi.GetModule("types")
types.StatusBar = types.CreateClass("StatusBar") types.StatusBar = types.CreateClass("StatusBar")
local StatusBar = types.StatusBar local StatusBar = types.StatusBar
function StatusBar:Init(parent, width, height, level, top) function StatusBar:Init(parent, width, height, level, top, texture, bgtexture)
if top == nil then top = true end if top == nil then
top = true
end
level = level or 0 level = level or 0
-- parent: the parent frame -- parent: the parent frame
self.parent = parent self.parent = parent
@@ -38,15 +40,17 @@ function StatusBar:Init(parent, width, height, level, top)
end end
bar:SetSize(width, height) bar:SetSize(width, height)
bar:SetStatusBarTexture("Interface\\Addons\\OmicronFrames\\media\\textures\\bar_subtle_diagonal") bar:SetStatusBarTexture(texture)
bar:GetStatusBarTexture():SetHorizTile(false) bar:GetStatusBarTexture():SetHorizTile(false)
bar:GetStatusBarTexture():SetVertTile(false) bar:GetStatusBarTexture():SetVertTile(false)
self.bar = bar self.bar = bar
local bg = bar:CreateTexture(nil, "BACKGROUND") if bgtexture ~= nil then
bg:SetTexture("Interface\\Addons\\OmicronFrames\\media\\textures\\bar_subtle_diagonal") local bg = bar:CreateTexture(nil, "BACKGROUND")
bg:SetAllPoints(true) bg:SetTexture(bgtexture)
self.bg = bg bg:SetAllPoints(true)
self.bg = bg
end
self:SetRange(0, 1) self:SetRange(0, 1)
self:SetValue(1) self:SetValue(1)
@@ -61,6 +65,10 @@ function StatusBar:SetValue(value)
self.bar:SetValue(value) self.bar:SetValue(value)
end end
function StatusBar:SetFillStyle(style)
self.bar:SetFillStyle(style)
end
function StatusBar:Show() function StatusBar:Show()
self.bar:Show() self.bar:Show()
end end
@@ -70,13 +78,15 @@ function StatusBar:Hide()
end end
function StatusBar:SetInterpolatedColor(start, stop, progress) function StatusBar:SetInterpolatedColor(start, stop, progress)
local r = start[1] + (stop[1] - start[1])*progress local r = start[1] + (stop[1] - start[1]) * progress
local g = start[2] + (stop[2] - start[2])*progress local g = start[2] + (stop[2] - start[2]) * progress
local b = start[3] + (stop[3] - start[3])*progress local b = start[3] + (stop[3] - start[3]) * progress
self:SetColor(r, g, b) self:SetColor(r, g, b)
end end
function StatusBar:SetColor(r, g, b) function StatusBar:SetColor(r, g, b)
self.bar:SetStatusBarColor(r, g, b) self.bar:SetStatusBarColor(r, g, b)
self.bg:SetVertexColor(0.2*r, 0.2*g, 0.2*b) if self.bg ~= nil then
self.bg:SetVertexColor(0.2 * r, 0.2 * g, 0.2 * b)
end
end end

View File

@@ -27,19 +27,13 @@ local Trigger = types.Trigger
local AuraTrigger = types.CreateClass("AuraTrigger", Trigger) local AuraTrigger = types.CreateClass("AuraTrigger", Trigger)
types.AuraTrigger = AuraTrigger types.AuraTrigger = AuraTrigger
---Creates a new AuraTrigger from a config description and attaches it to the ---Creates a new AuraTrigger from a config description and attaches it to the
---correct data source ---correct data source
---@param unit UnitFrame ---@param unit UnitFrame
---@param config table ---@param config table
---@return AuraTrigger ---@return AuraTrigger
function AuraTrigger.CreateFromConfig(unit, config) function AuraTrigger.CreateFromConfig(unit, config)
local trigger = AuraTrigger:new( local trigger = AuraTrigger:new(config.spellId, config.own, config.requiredCount, config.invert, config.defaultData)
config.spellId,
config.own,
config.requiredCount,
config.invert
)
unit.auras:AddTrigger(trigger) unit.auras:AddTrigger(trigger)
return trigger return trigger
end end
@@ -57,8 +51,9 @@ end
---@param own boolean ---@param own boolean
---@param requiredCount number | nil ---@param requiredCount number | nil
---@param invert boolean | nil ---@param invert boolean | nil
function AuraTrigger:Init(spellId, own, requiredCount, invert) ---@param defaultData table | nil
Trigger.Init(self, invert) function AuraTrigger:Init(spellId, own, requiredCount, invert, defaultData)
Trigger.Init(self, invert, defaultData)
self.spellId = spellId self.spellId = spellId
self.requiredCount = requiredCount or 1 self.requiredCount = requiredCount or 1
self.own = own self.own = own
@@ -68,7 +63,7 @@ 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, nil, false) self:SetState(self.count >= self.requiredCount, false)
end end
---Check if a given aura matches this AuraTrigger ---Check if a given aura matches this AuraTrigger
@@ -90,15 +85,27 @@ function AuraTrigger:AddAura(aura)
return return
end end
self.count = self.count + 1 self.count = self.count + 1
self:SetState(self.count >= self.requiredCount, {stacks=aura.applications}, false) self:SetData({
stacks = aura.applications,
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({
stacks = after.applications,
duration = after.duration,
expirationTime = after.expirationTime,
icon = after.icon,
})
if self.active then if self.active then
self.indicator:Update({stacks=after.applications}) self.indicator:Update(self.data)
end end
end end
@@ -109,5 +116,6 @@ function AuraTrigger:RemoveAura(aura)
return return
end end
self.count = self.count - 1 self.count = self.count - 1
self:SetState(self.count >= self.requiredCount, nil, false) self:SetData({})
self:SetState(self.count >= self.requiredCount, false)
end end

View File

@@ -73,7 +73,7 @@ function MultiTrigger:AddTrigger(trigger)
end, end,
Hide = function(_, data) Hide = function(_, data)
self:OnChildDeactivate(idx, trigger, data) self:OnChildDeactivate(idx, trigger, data)
end end,
}) })
end end
@@ -92,7 +92,8 @@ 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:SetState(true, data) self:SetData(data)
self:SetState(true, true)
end end
end end
@@ -113,8 +114,15 @@ function MultiTrigger:OnChildDeactivate(idx, trigger, data)
end end
end end
table.remove(activeChildren, found) table.remove(activeChildren, found)
if activeChild ~= activeChildren[1] then local newActiveChild = activeChildren[1]
self:SetState(activeChildren[1] ~= nil, childrenData[1], true) if activeChild ~= newActiveChild then
if activeChildren[1] ~= nil then
self:SetData(childrenData[newActiveChild])
self:SetState(true, true)
else
self:SetData({})
self:SetState(false, false)
end
end end
end end
@@ -133,4 +141,3 @@ end
function MultiTrigger:Reset() function MultiTrigger:Reset()
self:SetState(false) self:SetState(false)
end end

View File

@@ -29,8 +29,7 @@ types.StatusTrigger = StatusTrigger
---@param unit UnitFrame ---@param unit UnitFrame
---@param config table ---@param config table
function StatusTrigger.CreateFromConfig(unit, config) function StatusTrigger.CreateFromConfig(unit, config)
local trigger = StatusTrigger:new(config.status, config.requiredCount, local trigger = StatusTrigger:new(config.status, config.requiredCount, config.invert, config.defaultData)
config.invert)
unit.auras:AddTrigger(trigger) unit.auras:AddTrigger(trigger)
return trigger return trigger
end end
@@ -47,8 +46,8 @@ end
---@param status string The kind of status to trigger on ---@param status string The kind of status to trigger on
---@param requiredCount number | nil ---@param requiredCount number | nil
---@param invert boolean | nil ---@param invert boolean | nil
function StatusTrigger:Init(status, requiredCount, invert) function StatusTrigger:Init(status, requiredCount, invert, defaultData)
Trigger.Init(self, invert) Trigger.Init(self, invert, defaultData)
self.status = status self.status = status
self.requiredCount = requiredCount or 1 self.requiredCount = requiredCount or 1
self.invert = invert or false self.invert = invert or false
@@ -59,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, nil, false) self:SetState(count >= self.requiredCount, false)
end end

View File

@@ -23,10 +23,11 @@ local types = omi.GetModule("types")
---@class Trigger: Object ---@class Trigger: Object
---@field active boolean ---@field active boolean
---@field invert boolean ---@field invert boolean
---@field indicator Indicator
---@field data table The most recent data updated by the data source
local Trigger = types.CreateClass("Trigger") local Trigger = types.CreateClass("Trigger")
types.Trigger = Trigger types.Trigger = Trigger
---@param unit UnitFrame ---@param unit UnitFrame
---@param config table ---@param config table
---@return Trigger ---@return Trigger
@@ -36,10 +37,25 @@ end
--- Initialize a new Trigger object --- Initialize a new Trigger object
---@param invert boolean|nil ---@param invert boolean|nil
function Trigger:Init(invert) ---@param defaultData table|nil default data that is always present when this trigger updates an indicator
function Trigger:Init(invert, defaultData)
invert = invert or false invert = invert or false
self.invert = invert self.invert = invert
self.active = invert self.active = invert
self.defaultData = defaultData
self:SetData({})
end
---Save new data from the datasource into the trigger. This method will make
---sure the default data is always present
---@param data table
function Trigger:SetData(data)
if self.defaultData then
for k, v in pairs(self.defaultData) do
data[k] = v
end
end
self.data = data
end end
--- Set the target of the Trigger. --- Set the target of the Trigger.
@@ -49,30 +65,28 @@ end
function Trigger:SetTarget(target) function Trigger:SetTarget(target)
self.indicator = target self.indicator = target
if self.active then if self.active then
target:Show() target:Show(self.data)
end end
end end
---Set the state of the trigger. Will activate the indicator if needed. ---Set the state of the trigger. Will activate the indicator if needed.
---@param data table<string,any> | nil
---@param state boolean ---@param state boolean
function Trigger:SetState(state, data, doUpdate) function Trigger:SetState(state, doUpdate)
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
self.indicator:Show(data) self.indicator:Show(self.data)
else else
self.indicator:Hide() self.indicator:Hide()
end end
self.active = state self.active = state
elseif doUpdate and self.active then elseif doUpdate and self.active then
self.indicator:Update(data) self.indicator:Update(self.data)
end end
end 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, nil, false) self:SetState(false, false)
end end

View File

@@ -24,7 +24,7 @@ local function CreateClassRaw(name, parent)
c.__typeInfo = { c.__typeInfo = {
name = name, name = name,
class = c, class = c,
parent = parent parent = parent,
} }
c.__index = c c.__index = c
if parent ~= nil then if parent ~= nil then
@@ -48,6 +48,6 @@ function types.IsDerivedFrom(a, b)
return true return true
end end
current = current.__typeInfo.parent current = current.__typeInfo.parent
until current == nil; until current == nil
return false return false
end end

View File

@@ -26,6 +26,9 @@ local AuraList = types.AuraList
---@class SquareIndicator ---@class SquareIndicator
local SquareIndicator = types.SquareIndicator local SquareIndicator = types.SquareIndicator
---@class IconIndicator
local IconIndicator = types.IconIndicator
---@class SquareIndicator ---@class SquareIndicator
local BorderIndicator = types.BorderIndicator local BorderIndicator = types.BorderIndicator
@@ -33,26 +36,42 @@ local BorderIndicator = types.BorderIndicator
local UnitFrame = types.CreateClass("UnitFrame") local UnitFrame = types.CreateClass("UnitFrame")
types.UnitFrame = UnitFrame types.UnitFrame = UnitFrame
local colors = { local colors = {
hostile = {0.5, 0.0, 0.0}, hostile = { 0.5, 0.0, 0.0 },
neutral = {0.7, 0.7, 0.0}, neutral = { 0.7, 0.7, 0.0 },
healthy = {0, 0.1, 0}, healthy = { 0, 0.1, 0 },
high = {0, 1.0, 0}, high = { 0, 1.0, 0 },
mid = {1.0, 1.0, 0}, mid = { 1.0, 1.0, 0 },
low = {1.0, 0.0, 0}, low = { 1.0, 0.0, 0 },
offline = {0.7, 0.7, 0.7}, offline = { 0.7, 0.7, 0.7 },
dead = {0.7, 0.7, 0.7}, dead = { 0.7, 0.7, 0.7 },
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 },
curse = {0.7, 0.0, 0.7}, curse = { 0.7, 0.0, 0.7 },
immune = {0.0, 0.2, 0.4}, immune = { 0.0, 0.2, 0.4 },
bomb = {1.0, 0.7, 0.7}, bomb = { 1.0, 0.7, 0.7 },
cyan = {0.0, 0.8, 0.8}, cyan = { 0.0, 0.8, 0.8 },
white = {1.0, 1.0, 1.0} white = { 1.0, 1.0, 1.0 },
shield = { 0.85, 0.95, 1.0 },
absorb = { 0.5, 0.4, 0.75 },
} }
-- This trucates _codepoints_ not graphemes. If combination codepoints are
-- contained in the string, it will not properly truncate and may return
-- incorrect graphemes
local function utf8_truncate(s, n)
local init = 0
for _ = 1, n do
local _, last = string.find(s, ".[\128-\191]*", init + 1)
if not last then
return s
end
init = last
end
return string.sub(s, 1, init)
end
---@param unit string ---@param unit string
---@param config table ---@param config table
function UnitFrame:Init(unit, config) function UnitFrame:Init(unit, config)
@@ -71,9 +90,25 @@ function UnitFrame:Init(unit, config)
self:SetMouseBinds(config.mouse) self:SetMouseBinds(config.mouse)
self.hp = StatusBar:new(self, width, height, 0, true) local texture = "Interface\\Addons\\OmicronFrames\\media\\textures\\bar_subtle_diagonal"
self.power = StatusBar:new(self, width, 6, 2, false) local texture_top = "Interface\\Addons\\OmicronFrames\\media\\textures\\bar_subtle_diagonal_top"
local texture_bot = "Interface\\Addons\\OmicronFrames\\media\\textures\\bar_subtle_diagonal_bottom"
self.hp = StatusBar:new(self, width, height, 0, true, texture, texture)
self.power = StatusBar:new(self, width, 6, 2, false, texture, texture)
self.power:Hide() self.power:Hide()
self.absorb = StatusBar:new(self, width, height, 1, true, texture_top)
self.absorb:SetColor(unpack(colors.absorb))
self.absorb:SetFillStyle("REVERSE")
self.shield = StatusBar:new(self, width, height, 1, true, texture_bot)
self.shield:SetColor(unpack(colors.shield))
self.shield:SetRange(0, 1)
self.shield:SetValue(0.6)
self.shield:SetFillStyle("REVERSE")
self.auras = AuraList:new(self) self.auras = AuraList:new(self)
local overlays = CreateFrame("Frame", nil, secure) local overlays = CreateFrame("Frame", nil, secure)
@@ -110,14 +145,23 @@ function UnitFrame:CreateIndicator(indicator)
indicator.x, indicator.x,
indicator.y, indicator.y,
indicator.color, indicator.color,
indicator.showStacks indicator.showStacks,
indicator.fadeTime,
indicator.flashTime
)
elseif kind == "IconIndicator" then
return IconIndicator:new(
self,
indicator.size,
indicator.point,
indicator.x,
indicator.y,
indicator.showStacks,
indicator.fadeTime,
indicator.flashTime
) )
elseif kind == "BorderIndicator" then elseif kind == "BorderIndicator" then
return BorderIndicator:new( return BorderIndicator:new(self, indicator.thickness, indicator.color)
self,
indicator.thickness,
indicator.color
)
else else
error(string.format("Invalid Indicator kind `%s` requested", indicator.kind)) error(string.format("Invalid Indicator kind `%s` requested", indicator.kind))
end end
@@ -127,7 +171,7 @@ function UnitFrame:StartRangeTicker()
if self.rangeTicker then if self.rangeTicker then
return return
end end
local delta = 0.45 + (fastrandom(0, 100)/1000) local delta = 0.45 + (fastrandom(0, 100) / 1000)
self.rangeTicker = C_Timer.NewTicker(delta, function() self.rangeTicker = C_Timer.NewTicker(delta, function()
self:UpdateRange() self:UpdateRange()
end) end)
@@ -165,9 +209,9 @@ function UnitFrame:IsInRange()
-- Prefer to use configured spells -- Prefer to use configured spells
if friendlySpell and UnitCanAssist("player", unit) then if friendlySpell and UnitCanAssist("player", unit) then
return IsSpellInRange(friendlySpell, unit) == 1 return C_Spell.IsSpellInRange(friendlySpell, unit) == true
elseif enemySpell and UnitCanAttack("player", unit) then elseif enemySpell and UnitCanAttack("player", unit) then
return IsSpellInRange(enemySpell, unit) == 1 return C_Spell.IsSpellInRange(enemySpell, unit) == true
end end
-- Fall back to raid/party only range check -- Fall back to raid/party only range check
@@ -246,9 +290,15 @@ function UnitFrame:PrepareWheelBinds(bindings)
if bind.button == "wheel-up" or bind.button == "wheel-down" then if bind.button == "wheel-up" or bind.button == "wheel-down" then
local prefix = ModifiersToPrefix(bind.mods) local prefix = ModifiersToPrefix(bind.mods)
local button = bind.button == "wheel-up" and "MOUSEWHEELUP" or "MOUSEWHEELDOWN" local button = bind.button == "wheel-up" and "MOUSEWHEELUP" or "MOUSEWHEELDOWN"
table.insert(bindScript, table.insert(
string.format([[self:SetBindingClick(false, "%s%s", "OmicronSecureFrame%s", "%s%s")]], bindScript,
prefix, button, unit, prefix, bind.button string.format(
[[self:SetBindingClick(false, "%s%s", "OmicronSecureFrame%s", "%s%s")]],
prefix,
button,
unit,
prefix,
bind.button
) )
) )
end end
@@ -389,10 +439,13 @@ function UnitFrame:RegisterEvents()
end end
end end
secure:RegisterEvent("GROUP_ROSTER_UPDATE")
secure:RegisterUnitEvent("UNIT_AURA", unit) secure:RegisterUnitEvent("UNIT_AURA", unit)
secure:RegisterUnitEvent("UNIT_HEALTH", unit) secure:RegisterUnitEvent("UNIT_HEALTH", unit)
secure:RegisterUnitEvent("UNIT_MAXHEALTH", unit) secure:RegisterUnitEvent("UNIT_MAXHEALTH", unit)
secure:RegisterUnitEvent("UNIT_NAME_UPDATE", unit) secure:RegisterUnitEvent("UNIT_NAME_UPDATE", unit)
secure:RegisterUnitEvent("UNIT_ABSORB_AMOUNT_CHANGED", unit)
secure:RegisterUnitEvent("UNIT_HEAL_ABSORB_AMOUNT_CHANGED", unit)
end end
-- returns whether or not the unit guid has changed since the last call to this -- returns whether or not the unit guid has changed since the last call to this
@@ -413,6 +466,29 @@ function UnitFrame:HasUnitChanged()
end end
end end
function UnitFrame:UNIT_HEAL_ABSORB_AMOUNT_CHANGED()
if self:HasUnitChanged() then
self:UpdateAll(true)
return
end
self:UpdateAbsorb()
end
function UnitFrame:UNIT_ABSORB_AMOUNT_CHANGED()
if self:HasUnitChanged() then
self:UpdateAll(true)
return
end
self:UpdateShield()
end
function UnitFrame:GROUP_ROSTER_UPDATE()
if self:HasUnitChanged() then
self:UpdateAll(true)
return
end
end
function UnitFrame:UNIT_AURA(unit, info) function UnitFrame:UNIT_AURA(unit, info)
if self:HasUnitChanged() then if self:HasUnitChanged() then
self:UpdateAll(true) self:UpdateAll(true)
@@ -455,7 +531,7 @@ end
function UnitFrame:ROLE_CHANGED_INFORM(name, changer, old, new) function UnitFrame:ROLE_CHANGED_INFORM(name, changer, old, new)
if UnitName(self.unit) == name then if UnitName(self.unit) == name then
self:UpdateRole(new) self:UpdateRole(new)
end end
end end
@@ -519,6 +595,8 @@ function UnitFrame:UpdateAll(unitChanged)
end end
self:UpdateHealth() self:UpdateHealth()
self:UpdateHealthColor() self:UpdateHealthColor()
self:UpdateAbsorb()
self:UpdateShield()
self:UpdateRange() self:UpdateRange()
self:UpdateName() self:UpdateName()
self:UpdateRole() -- Also calls UpdatePower if power is visible self:UpdateRole() -- Also calls UpdatePower if power is visible
@@ -533,6 +611,32 @@ function UnitFrame:UpdateHealth()
self.hp:SetValue(val) self.hp:SetValue(val)
end end
function UnitFrame:UpdateShield()
local unit = self.unit
local val = UnitGetTotalAbsorbs(unit)
local max = UnitHealthMax(unit)
if val <= 0 then
self.shield:Hide()
else
self.shield:SetRange(0, max)
self.shield:SetValue(val)
self.shield:Show()
end
end
function UnitFrame:UpdateAbsorb()
local unit = self.unit
local val = UnitGetTotalHealAbsorbs(unit)
local max = UnitHealthMax(unit)
if val <= 0 then
self.absorb:Hide()
else
self.absorb:SetRange(0, max)
self.absorb:SetValue(val)
self.absorb:Show()
end
end
function UnitFrame:UpdateHealthColor() function UnitFrame:UpdateHealthColor()
local unit = self.unit local unit = self.unit
local val = UnitHealth(unit) local val = UnitHealth(unit)
@@ -563,7 +667,7 @@ function UnitFrame:UpdateHealthColor()
elseif isFriend and pct >= 0.90 then elseif isFriend and pct >= 0.90 then
self.hp:SetColor(unpack(colors.healthy)) self.hp:SetColor(unpack(colors.healthy))
elseif isFriend and pct >= 0.75 then elseif isFriend and pct >= 0.75 then
local progress = (pct - 0.75) / (0.90-0.75) local progress = (pct - 0.75) / (0.90 - 0.75)
self.hp:SetInterpolatedColor(colors.mid, colors.high, progress) self.hp:SetInterpolatedColor(colors.mid, colors.high, progress)
else else
local progress = pct / 0.75 local progress = pct / 0.75
@@ -580,25 +684,10 @@ function UnitFrame:UpdateName()
-- TODO: UnitClass can return Unknown and the color can be nil. Having -- TODO: UnitClass can return Unknown and the color can be nil. Having
-- the unit exist but not fully loaded is possibly a state we want to -- the unit exist but not fully loaded is possibly a state we want to
-- handle more generally -- handle more generally
local color = RAID_CLASS_COLORS[class] or {r=1, g=1, b=1} local color = RAID_CLASS_COLORS[class] or { r = 1, g = 1, b = 1 }
self.name:SetTextColor(color.r, color.g, color.b) self.name:SetTextColor(color.r, color.g, color.b)
else else
self.name:SetTextColor(1, 1, 1) self.name:SetTextColor(1, 1, 1)
end end
self.name:SetText(UnitName(self.unit):sub(1, 5)) self.name:SetText(utf8_truncate((UnitName(self.unit)), 5))
end end
--[[
-- UNIT_AURA
-- UNIT_CLASSIFICATION_CHANGED
-- UNIT_COMBAT
-- UNIT_CONNECTION
-- UNIT_DISPLAYPOWER
-- UNIT_FACTION
-- UNIT_FLAGS
-- UNIT_LEVEL
-- UNIT_MANA
-- UNIT_HEALTH_PREDICTION
-- UNIT_PHASE
]]--

View File

@@ -121,14 +121,14 @@ function UnitGroup:Sort()
table.sort(self.units, UnitFrameDefaultCompare) table.sort(self.units, UnitFrameDefaultCompare)
local left, top, width, height = self.left, self.top, self.width, self.height local left, top, width, height = self.left, self.top, self.width, self.height
local maxFrameIndex = #self.units local maxFrameIndex = #self.units
for y=0,5 do for y = 0, 5 do
for x=0,4 do for x = 0, 4 do
local num = y*5 + x + 1 local num = y * 5 + x + 1
if num > maxFrameIndex then if num > maxFrameIndex then
return return
end end
local frame = self.units[num] local frame = self.units[num]
frame:SetPosition(left + (x-2)*width, top - y*height) frame:SetPosition(left + (x - 2) * width, top - y * height)
end end
end end
end end