Initial commit

This commit is contained in:
2023-03-15 17:13:01 +01:00
commit 86825dd6e5
18 changed files with 1912 additions and 0 deletions

200
src/types/auralist.lua Normal file
View File

@@ -0,0 +1,200 @@
-- Copyright 2023 <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 AuraTrigger = types.AuraTrigger
local AuraList = types.CreateClass("AuraList")
types.AuraList = AuraList
local statusLists = {
Immune = {
[642] = true, -- Divine Shield, Paladin
[186265] = true -- Aspect of the Turtle, Hunter
},
Bomb = {
[642] = true, -- Divine Shield, Paladin
[186265] = true, -- Aspect of the Turtle, Hunter
[381615] = true, -- Raszageth, Static Charge
[377467] = true -- Raszageth, Fulminating Charge
},
Burn = {
[642] = true, -- Divine Shield, Paladin
[186265] = true -- Aspect of the Turtle, Hunter
}
}
local function ForEachAuraSlots(unit, fn, continuationToken, ...)
local GetAuraDataBySlot = C_UnitAuras.GetAuraDataBySlot
local n = select('#', ...)
for i=1, n do
local slot = select(i, ...)
fn(GetAuraDataBySlot(unit, slot))
end
return continuationToken
end
local function ForEachAuraFiltered(unit, filter, fn)
local UnitAuraSlots = UnitAuraSlots
local continuationToken = nil
repeat
continuationToken = ForEachAuraSlots(unit, fn, UnitAuraSlots(unit, filter, nil, continuationToken))
until (continuationToken == nil)
end
-- Similar to what AuraUtils.ForEachAura does except the callback fn takes a
-- UnitAuraInfo structure rather than individual arguments
local function ForEachAura(unit, fn)
ForEachAuraFiltered(unit, "HELPFUL", fn)
ForEachAuraFiltered(unit, "HARMFUL", fn)
end
function AuraList:Init(unitframe)
self.unitframe = unitframe
self.unit = unitframe.unit
self.statusCount = {}
self.auras = {} -- map AuraInstanceID to UnitAuraInfo table
self.triggers = {}
self.triggersBySpell = {}
end
function AuraList:AddTrigger(trigger)
table.insert(self.triggers, trigger)
if trigger:IsInstanceOf(AuraTrigger) then
local spellId = trigger.spellId
if self.triggersBySpell[spellId] == nil then
self.triggersBySpell[spellId] = {}
end
table.insert(self.triggersBySpell[spellId], trigger)
end
end
-- Scan all the auras of the owning unit and build the aura list from scratch
-- This should only ever happen when the unit is first assigned to the frame
function AuraList:Reset()
self.auras = {}
self.statusCount = {}
for _, trigger in ipairs(self.triggers) do
trigger:Reset()
end
ForEachAura(self.unit, function(aura)
self:AddAura(aura)
end)
end
function AuraList:AddAura(aura)
local statusChanged = false
self.auras[aura.auraInstanceID] = aura
-- Update status counts associated with this aura
local count = self.statusCount
for _, status in ipairs(self:GetStatusForAura(aura)) do
if not count[status] then
count[status] = 1
statusChanged = true
else
count[status] = count[status] + 1
end
end
for _, trigger in ipairs(self.triggersBySpell[aura.spellId] or {}) do
trigger:AddAura(aura)
end
-- Update triggers associated with this aura
return statusChanged
end
-- Returns a table with every status that applies to the given aura
function AuraList:GetStatusForAura(aura)
local status = {}
if aura.dispelName and aura.isHarmful then
table.insert(status, aura.dispelName)
end
for statusName, auraIds in pairs(statusLists) do
if auraIds[aura.spellId] then
table.insert(status, statusName)
end
end
return status
end
function AuraList:UpdateAura(aura)
for _, trigger in ipairs(self.triggersBySpell[aura.spellId] or {}) do
trigger:UpdateAura(self.auras[aura.auraInstanceId], aura)
end
self.auras[aura.auraInstanceID] = aura
end
function AuraList:RemoveAura(iid)
local aura = self.auras[iid]
if aura == nil then
-- FIXME: Why does this happen? Are we actually missing important auras?
return false
end
self.auras[iid] = nil
local statusChanged = false
local count = self.statusCount
for _, status in ipairs(self:GetStatusForAura(aura)) do
if not count[status] then
print("Removed a status that we didn't already have...?", status, aura.spellId)
elseif count[status] == 1 then
count[status] = nil
statusChanged = true
else
count[status] = count[status] - 1
end
end
for _, trigger in ipairs(self.triggersBySpell[aura.spellId] or {}) do
trigger:RemoveAura(aura)
end
return statusChanged
end
function AuraList:Update(info)
local GetAuraDataByAuraInstanceID = C_UnitAuras.GetAuraDataByAuraInstanceID
local statusChanged = false
for _, aura in ipairs(info.addedAuras or {}) do
if self:AddAura(aura) then
statusChanged = true
end
end
for _, iid in ipairs(info.updatedAuraInstanceIDs or {}) do
local aura = GetAuraDataByAuraInstanceID(self.unit, iid)
-- FIXME: Why can aura be nil? Are we actually missing important auras?
if aura ~= nil then
self:UpdateAura(aura)
end
end
for _, iid in ipairs(info.removedAuraInstanceIDs or {}) do
if self:RemoveAura(iid) then
statusChanged = true
end
end
return statusChanged
end

61
src/types/indicator.lua Normal file
View File

@@ -0,0 +1,61 @@
-- Copyright 2023 <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 AuraTrigger = types.AuraTrigger
local Indicator = types.CreateClass("Indicator")
types.Indicator = Indicator
-- TODO: make different indicators, such as texture, text, border
-- TODO: spellid feels out of place but I wanna quickly get something for now.
-- Should rethink this when Trigger is its own class
function Indicator:Init(unitframe, auralist, size, point, x, y, color, spellId)
local frame = unitframe.overlays
local texture = frame:CreateTexture(nil, "ARTWORK")
self.texture = texture
texture:Hide()
texture:SetTexture("Interface\\Addons\\OmicronFrames\\media\\textures\\square_b")
texture:SetSize(size, size)
texture:SetPoint(point, x, y)
self:SetColor(color)
texture:SetVertexColor(unpack(color))
texture:SetDrawLayer("ARTWORK")
local fn = function(activate)
if activate then
self:Show()
else
self:Hide()
end
end
local trigger = AuraTrigger:new(fn, spellId, true)
auralist:AddTrigger(trigger)
end
function Indicator:SetColor(color)
self.texture:SetVertexColor(unpack(color))
end
function Indicator:Show()
self.texture:Show()
end
function Indicator:Hide()
self.texture:Hide()
end

53
src/types/object.lua Normal file
View File

@@ -0,0 +1,53 @@
-- Copyright 2023 <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 Object = omi.GetModule("types").Object
local IsDerivedFrom = omi.GetModule("types").IsDerivedFrom
-- Create a new instance of Object or (more likely) any inheriting class
function Object.new(class, ...)
local o = {}
setmetatable(o, class)
if o.Init ~= nil then
o:Init(...)
end
return o
end
-- Returns true if the Object is a class, false if it is an instance object
function Object.IsClassObject(self)
return self.__typeInfo.class == self
end
-- Returns true if the Object is an instance, false if it is a class
function Object.IsInstanceObject(self)
return self.__typeInfo.class ~= self
end
-- return true if this object is an instance of the given class
function Object:IsInstanceOf(class)
if not self:IsInstanceObject() or not class:IsClassObject() then
return false
end
return IsDerivedFrom(self:GetClass(), class)
end
-- Return the class of any object
function Object.GetClass(self)
return self.__typeInfo.class
end

71
src/types/statusbar.lua Normal file
View File

@@ -0,0 +1,71 @@
-- Copyright 2023 <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")
types.StatusBar = types.CreateClass("StatusBar")
local StatusBar = types.StatusBar
function StatusBar:Init(parent, width, height)
-- parent: the parent frame
-- pct: nil if no percent value is shown, otherwise "left", "right" or "center"
-- value: nil if no value is shown, otherwise "left", "right" or "center"
-- text: nil if no text is shown, otherwise "left", "right" or "center"
-- stack: another StatusBar we will stack under
self.parent = parent
local parentFrame = parent.secureFrame
local bar = CreateFrame("StatusBar", nil, parentFrame)
bar:SetFrameStrata("MEDIUM")
bar:SetFrameLevel(10)
bar:SetPoint("TOPLEFT", parentFrame, "TOPLEFT", 0, 0)
bar:SetSize(width, height)
bar:SetStatusBarTexture("Interface\\Addons\\OmicronFrames\\media\\textures\\bar_subtle_diagonal")
bar:GetStatusBarTexture():SetHorizTile(false)
bar:GetStatusBarTexture():SetVertTile(false)
self.bar = bar
local bg = bar:CreateTexture(nil, "BACKGROUND")
bg:SetTexture("Interface\\Addons\\OmicronFrames\\media\\textures\\bar_subtle_diagonal")
bg:SetAllPoints(true)
self.bg = bg
self:SetRange(0, 1)
self:SetValue(1)
bar:Show()
end
function StatusBar:SetRange(min, max)
self.bar:SetMinMaxValues(min, max)
end
function StatusBar:SetValue(value)
self.bar:SetValue(value)
end
function StatusBar:SetInterpolatedColor(start, stop, progress)
local r = start[1] + (stop[1] - start[1])*progress
local g = start[2] + (stop[2] - start[2])*progress
local b = start[3] + (stop[3] - start[3])*progress
self:SetColor(r, g, b)
end
function StatusBar:SetColor(r, g, b)
self.bar:SetStatusBarColor(r, g, b)
self.bg:SetVertexColor(0.2*r, 0.2*g, 0.2*b)
end

136
src/types/trigger.lua Normal file
View File

@@ -0,0 +1,136 @@
-- Copyright 2023 <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")
types.Trigger = types.CreateClass("Trigger")
local Trigger = types.Trigger
-- Constructor for Trigger.
-- fn:
-- The callback function that gets called every time this trigger changes
-- states between active and inactive. Function takes one boolean argument.
function Trigger:Init(fn)
self.fn = fn
end
-- Returns whether the trigger is active
function Trigger:IsActive()
return false
end
-- Reset the trigger to the default state. Does run the untrigger callback if
-- the trigger is active when Reset is called.
function Trigger:Reset()
end
types.AuraTrigger = types.CreateClass("AuraTrigger", Trigger)
local AuraTrigger = types.AuraTrigger
-- Constructor for AuraTrigger
-- fn:
-- The callback function that gets called every time this trigger changes
-- states between active and inactive. Function takes one boolean argument.
--
-- requiredCount = 1:
-- The minimum number of conditions that must be met before the trigger
-- activates. What exactly this means depends on the trigger, examples are
-- # of matching auras, # of stacks.
--
-- invert = false:
-- If the trigger is inverted it will activate when count < requiredCount.
-- If the trigger is not inverted it will activate when count >= requiredCount.
function AuraTrigger:Init(fn, spellId, own, requiredCount, invert)
Trigger.Init(self, fn)
self.spellId = spellId
self.requiredCount = requiredCount or 1
self.own = own
self.count = 0
self.invert = invert or false
end
-- Reset the trigger to the default state. Does run the untrigger callback if
-- the trigger is active when it is called
function AuraTrigger:Reset()
local before = self:IsActive()
self.count = 0
local after = self:IsActive()
if before ~= after then
self.fn(after)
end
end
-- Return true if the aura matches the trigger
-- aura:
-- Must be a valid UnitAuraInfo structure.
function AuraTrigger:IsMatching(aura)
if aura.spellId ~= aura.spellId then
return false
end
if self.own and aura.sourceUnit ~= "player" then
return false
end
return true
end
-- Inform the trigger about an added aura
-- aura:
-- Must be a valid UnitAuraInfo
function AuraTrigger:AddAura(aura)
if not self:IsMatching(aura) then
return
end
self.count = self.count + 1
-- Be mindful, this works only if count always changes by 1.
if self.count == self.requiredCount then
self.fn(not self.invert)
end
end
-- Inform the trigger about an updated aura
-- before:
-- Must be a valid UnitAuraInfo for the aura before the update
-- after:
-- Must be a valid UnitAuraInfo for the aura after the update
function AuraTrigger:UpdateAura(before, after)
--
end
-- Inform the trigger about an aura that got removed
-- Must be a valid UnitAuraInfo for the aura before it got removed
function AuraTrigger:RemoveAura(aura)
if not self:IsMatching(aura) then
return
end
self.count = self.count - 1
-- Be mindful, this works only if count always changes by 1.
if self.count == self.requiredCount - 1 then
self.fn(self.invert)
end
end
-- Returns true if the trigger is active, false otherwise
function AuraTrigger:IsActive()
if self.invert then
return self.count < self.requiredCount
else
return self.count >= self.requiredCount
end
end

53
src/types/types.lua Normal file
View File

@@ -0,0 +1,53 @@
-- Copyright 2023 <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 omif = select(2, ...)
local types = omif.GetModule("types")
-- Create any class, possibly top level
local function CreateClassRaw(name, parent)
local c = {}
c.__typeInfo = {
name = name,
class = c,
parent = parent
}
c.__index = c
if parent ~= nil then
setmetatable(c, parent)
end
return c
end
types.Object = CreateClassRaw("Object")
-- Create a new class, eventually rooted at Object
function types.CreateClass(name, parent)
return CreateClassRaw(name, parent or types.Object)
end
-- Return true if a is derived from b or if a is b
function types.IsDerivedFrom(a, b)
local current = a
repeat
if current == b then
return true
end
current = current.__typeInfo.parent
until current == nil;
return false
end

396
src/types/unitframe.lua Normal file
View File

@@ -0,0 +1,396 @@
-- Copyright 2023 <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 omif = select(2, ...)
local types = omif.GetModule("types")
local StatusBar = types.StatusBar
local AuraList = types.AuraList
local Indicator = types.Indicator
types.UnitFrame = types.CreateClass("UnitFrame")
local UnitFrame = types.UnitFrame
local colors = {
hostile = {0.5, 0.0, 0.0},
neutral = {0.7, 0.7, 0.0},
healthy = {0, 0.1, 0},
high = {0, 1.0, 0},
mid = {1.0, 1.0, 0},
low = {1.0, 0.0, 0},
offline = {0.7, 0.7, 0.7},
dead = {0.7, 0.7, 0.7},
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},
immune = {0.0, 0.2, 0.4},
bomb = {1.0, 0.7, 0.7},
cyan = {0.0, 0.8, 0.8},
white = {1.0, 1.0, 1.0}
}
function UnitFrame:Init(unit, width, height)
self.unit = unit
local secure = self:CreateSecureFrame(width, height)
secure:Hide()
self.hp = StatusBar:new(self, width, height)
self.auras = AuraList:new(self)
local overlays = CreateFrame("Frame", nil, secure)
overlays:SetFrameStrata("MEDIUM")
overlays:SetFrameLevel(100)
overlays:SetAllPoints(true)
overlays:Show()
self.overlays = overlays
self.indicators = {
Indicator:new(self, self.auras, 14, "TOPLEFT", 2, -2, colors.white, 383648),
Indicator:new(self, self.auras, 14, "TOPLEFT", 2, -2, colors.white, 974),
Indicator:new(self, self.auras, 14, "BOTTOMLEFT", 2, 2, colors.cyan, 61295)
}
self:RegisterEvents()
self:Enable()
end
function UnitFrame:StartRangeTicker()
if self.rangeTicker then
return
end
local delta = 0.45 + (fastrandom(0, 100)/1000)
self.rangeTicker = C_Timer.NewTicker(delta, function()
self:UpdateRange()
end)
end
function UnitFrame:StopRangeTicker()
if self.rangeTicker then
self.rangeTicker:Cancel()
self.rangeTicker = nil
end
end
function UnitFrame:UpdateRange()
local unit = self.unit
if not UnitIsFriend("player", unit) and IsSpellInRange("Lightning Bolt", unit) ~= 1 then
self.secureFrame:SetAlpha(0.2)
elseif UnitIsFriend("player", unit) and IsSpellInRange("Healing Surge", unit) ~= 1 then
self.secureFrame:SetAlpha(0.2)
else
self.secureFrame:SetAlpha(1.0)
end
end
function UnitFrame:SetSpellAction(button, spell)
local secure = self.secureFrame
local attributeName = button:gsub("type", "spell")
secure:SetAttribute(button, "spell")
secure:SetAttribute(attributeName, spell)
end
function UnitFrame:SetMacroAction(button, macro)
local secure = self.secureFrame
local attributeName = button:gsub("type", "macrotext")
secure:SetAttribute(button, "macro")
secure:SetAttribute(attributeName, macro:gsub("@UNIT", "@" .. self.unit))
end
function UnitFrame:PrepareWheelBinds()
-- By default you can't use the SecureUnitButtonTemplate to handle scroll
-- wheel "clicks". We solve this by using SecureHandler*Template to bind
-- scroll wheel to the current unit frame button when the mouse enters and
-- to unbind it when the mouse leaves. When the keybind is triggered the
-- button will receive a click with a custom button name
local secure = self.secureFrame
local bindScript = ([[
self:ClearBindings()
self:SetBindingClick(false, "MOUSEWHEELUP", "BUTTONNAME", "wheel-up")
self:SetBindingClick(false, "MOUSEWHEELDOWN", "BUTTONNAME", "wheel-down")
self:SetBindingClick(false, "ALT-MOUSEWHEELUP", "BUTTONNAME", "alt-wheel-up")
self:SetBindingClick(false, "ALT-MOUSEWHEELDOWN", "BUTTONNAME", "alt-wheel-down")
]]):gsub("BUTTONNAME", "OmicronSecureFrame" .. self.unit)
local removeBindScript = [[
self:ClearBindings()
]]
secure:SetAttribute("_onenter", bindScript)
secure:SetAttribute("_onleave", removeBindScript)
secure:SetAttribute("_onshow", removeBindScript)
secure:SetAttribute("_onhide", removeBindScript)
end
function UnitFrame:CreateSecureFrame(width, height)
local name = "OmicronSecureFrame" .. self.unit
local templates = table.concat({
"SecureUnitButtonTemplate",
"SecureHandlerEnterLeaveTemplate",
"SecureHandlerShowHideTemplate",
}, ",")
local secure = CreateFrame("Button", name, UIParent, templates)
self.secureFrame = secure
secure:SetFrameStrata("MEDIUM")
secure:SetFrameLevel(0)
secure:SetAttribute("unit", self.unit)
secure:SetSize(width, height)
secure:RegisterForClicks("AnyDown")
self:PrepareWheelBinds()
-- No modifiers
secure:SetAttribute("type1", "target")
self:SetMacroAction("type2", "/use [@UNIT,dead,help]Ancestral Vision; [@UNIT]Chain Heal")
self:SetMacroAction("type3", "/use [@UNIT,dead,help]Ancestral Spirit; [@UNIT]Purify Spirit")
self:SetMacroAction("type-wheel-up", "/use [@UNIT]Healing Surge")
self:SetMacroAction("type-wheel-down", "/use [@UNIT,help]Riptide")
-- alt
self:SetSpellAction("type-alt-wheel-up", "Healing Wave")
self:SetSpellAction("type-alt-wheel-down", "Earth Shield")
-- Shift
secure:SetAttribute("SHIFT-type2", "menu")
if self.unit == "player" then
secure.menu = function(self)
ToggleDropDownMenu(1, nil, PlayerFrameDropDown, "cursor", 0 ,0)
end
elseif self.unit == "target" then
secure.menu = function(self)
ToggleDropDownMenu(1, nil, TargetFrameDropDown, "cursor", 0 ,0)
end
elseif self.unit == "focus" then
secure.menu = function(self)
ToggleDropDownMenu(1, nil, FocusFrameDropDown, "cursor", 0 ,0)
end
elseif self.unit:match("party%d") == self.unit then
--secure.menu = function(self)
-- ToggleDropDownMenu(1, nil, FriendsFrameDropDown, "cursor", 0 ,0)
--end
end
return secure
end
function UnitFrame:Enable()
if self.unit ~= "player" then
RegisterUnitWatch(self.secureFrame)
else
self.secureFrame:Show()
end
if UnitExists(self.unit) then
self:UpdateAll(self:HasUnitChanged())
end
end
function UnitFrame:Disable()
if self.unit ~= "player" then
UnregisterUnitWatch(self.secure_frame)
else
self.secureFrame:Hide()
end
end
-- returns true if this unit is a target unit
function UnitFrame:IsTargetFrame()
return self.unit:match(".*target") == self.unit
end
-- returns the target owner
function UnitFrame:GetTargetOwner()
if self.unit == "target" then
return "player"
else
return self.unit:sub(1, -7)
end
end
-- Set position from the center of the UIParent
function UnitFrame:SetPosition(x, y)
self.secureFrame:SetPoint("CENTER", UIParent, x, y)
end
function UnitFrame:RegisterEvents()
local unit = self.unit
local secure = self.secureFrame
secure:SetScript("OnShow", function(frame, event, ...)
self:OnShow()
end)
secure:SetScript("OnHide", function(frame, event, ...)
self:OnHide()
end)
secure:SetScript("OnEvent", function(frame, event, ...)
self[event](self, ...)
end)
if self:IsTargetFrame() then
local owner = self:GetTargetOwner()
if owner == "player" then
secure:RegisterEvent("PLAYER_TARGET_CHANGED")
else
secure:RegisterUnitEvent("UNIT_TARGET", self.parent:GetTargetOwner())
end
end
secure:RegisterUnitEvent("UNIT_AURA", unit)
secure:RegisterUnitEvent("UNIT_HEALTH", unit)
secure:RegisterUnitEvent("UNIT_MAXHEALTH", unit)
end
-- returns whether or not the unit guid has changed since the last call to this
-- function. Always returns false if the current unit does not exist.
function UnitFrame:HasUnitChanged()
local unit = self.unit
if not UnitExists(unit) then
self.guid = nil
return false
end
local guid = UnitGUID(unit)
if self.guid == guid then
return false
else
self.guid = guid
return true
end
end
function UnitFrame:UNIT_AURA(unit, info)
if self:HasUnitChanged() then
self:UpdateAll(true)
return
end
if self.auras:Update(info) then
self:UpdateHealthColor()
end
end
function UnitFrame:UNIT_HEALTH()
if self:HasUnitChanged() then
self:UpdateAll(true)
return
end
self:UpdateHealth()
self:UpdateHealthColor()
end
function UnitFrame:UNIT_MAXHEALTH()
if self:HasUnitChanged() then
self:UpdateAll(true)
return
end
self:UpdateHealth()
self:UpdateHealthColor()
end
function UnitFrame:UNIT_TARGET()
self:UpdateAll(self:HasUnitChanged())
end
function UnitFrame:PLAYER_TARGET_CHANGED()
self:UpdateAll(self:HasUnitChanged())
end
function UnitFrame:OnShow()
self:StartRangeTicker()
self:UpdateAll(self:HasUnitChanged())
end
function UnitFrame:OnHide()
self.guid = nil
self:StopRangeTicker()
end
function UnitFrame:UpdateAll(unitChanged)
if not UnitExists(self.unit) then
return
end
if unitChanged then
self.auras:Reset()
end
self:UpdateHealth()
self:UpdateHealthColor()
self:UpdateRange()
end
function UnitFrame:UpdateHealth()
local unit = self.unit
local val = UnitHealth(unit)
local max = UnitHealthMax(unit)
self.hp:SetRange(0, max)
self.hp:SetValue(val)
end
function UnitFrame:UpdateHealthColor()
local unit = self.unit
local val = UnitHealth(unit)
local max = UnitHealthMax(unit)
if max == 0 then
return
end
local pct = val / max
local isFriend = UnitIsFriend("player", unit)
if not isFriend then
self.hp:SetColor(unpack(colors.hostile))
elseif self.auras.statusCount["Immune"] then
self.hp:SetColor(unpack(colors.immune))
elseif self.auras.statusCount["Bomb"] then
self.hp:SetColor(unpack(colors.bomb))
elseif self.auras.statusCount["Magic"] then
self.hp:SetColor(unpack(colors.magic))
elseif self.auras.statusCount["Curse"] then
self.hp:SetColor(unpack(colors.curse))
elseif self.auras.statusCount["Poison"] then
self.hp:SetColor(unpack(colors.poison))
elseif self.auras.statusCount["Disease"] then
self.hp:SetColor(unpack(colors.disease))
elseif isFriend and UnitIsDead(unit) then
self.hp:SetColor(unpack(colors.dead))
elseif isFriend and pct >= 0.90 then
self.hp:SetColor(unpack(colors.healthy))
elseif isFriend and pct >= 0.75 then
local progress = (pct - 0.75) / (0.90-0.75)
self.hp:SetInterpolatedColor(colors.mid, colors.high, progress)
else
local progress = pct / 0.75
-- Quadratic progress so we get to the dangerous colors faster as hp
-- goes lower
progress = progress * progress
self.hp:SetInterpolatedColor(colors.low, colors.mid, progress)
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
]]--