Files
coa-omen/Omen.lua
T
florian.berthold b6d42dfe5d Add OmenSync: addon-channel fallback for Vol'jin party threat
The CoA Vol'jin core does not push UnitDetailedThreatSituation data
for party-member units, so vanilla Omen draws only the local
player's bar in 5-mans. The same install on Bronzebeard/classic+
shows the whole party because that core does push the data. The gap
is server-side, not client-side, and there is no Omen flag that
fixes it.

OmenSync layers a tiny SendAddonMessage("OMSYNC", …, "PARTY"|"RAID")
relay on top:
- Each player's Omen broadcasts its own player+pet threat values
  (throttled, ~0.4s + 5% delta) every time updatethreat() succeeds
  via the API path.
- Receivers store incoming values keyed by senderGUID/mobGUID and
  serve them as a fallback in updatethreat() whenever
  UnitDetailedThreatSituation returns nil.

When the API does push data (Bronzebeard) the existing path still
wins; sync values are simply unused, so this is a no-op on healthy
realms. Both peers must run a fork that emits the OMSYNC prefix.

Wire format keeps each message under the 255-byte AddonMessage cap:
    <subjectGUID>|<mobGUID>|<threatValue>|<isTanking 0|1>
Sender's name comes from CHAT_MSG_ADDON's sender arg. Subject GUID
distinguishes the player and pet broadcasts each Omen instance
emits.

Hook in Omen.lua's local updatethreat():
- After UnitDetailedThreatSituation returns nil for any unit, try
  Omen:SyncGetThreat(guid, mobGUID).
- After it returns a value for "player" or "pet", call
  Omen:SyncBroadcastThreat to relay it to peers.
2026-05-08 23:40:17 +02:00

3179 lines
102 KiB
Lua

-----------------------------------------------------------------------------
-- Addon declaration
local Omen = LibStub("AceAddon-3.0"):NewAddon("Omen", "AceConsole-3.0", "AceEvent-3.0", "AceTimer-3.0", "LibSink-2.0")
local L = LibStub("AceLocale-3.0"):GetLocale("Omen", false)
local LSM = LibStub("LibSharedMedia-3.0")
local LDB = LibStub("LibDataBroker-1.1", true)
local LDBIcon = LDB and LibStub("LibDBIcon-1.0", true)
Omen.version = GetAddOnMetadata("Omen", "Version")
Omen.versionstring = "Omen v"..GetAddOnMetadata("Omen", "Version")
_G["Omen"] = Omen
-----------------------------------------------------------------------------
-- Keybinding globals
BINDING_HEADER_OMEN = Omen.versionstring
BINDING_NAME_OMENTOGGLE = L["Toggle Omen"]
BINDING_NAME_OMENTOGGLEFOCUS = L["Toggle Focus"]
-----------------------------------------------------------------------------
-- Register some media
LSM:Register("sound", "Rubber Ducky", [[Sound\Doodad\Goblin_Lottery_Open01.wav]])
LSM:Register("sound", "Cartoon FX", [[Sound\Doodad\Goblin_Lottery_Open03.wav]])
LSM:Register("sound", "Explosion", [[Sound\Doodad\Hellfire_Raid_FX_Explosion05.wav]])
LSM:Register("sound", "Shing!", [[Sound\Doodad\PortcullisActive_Closed.wav]])
LSM:Register("sound", "Wham!", [[Sound\Doodad\PVP_Lordaeron_Door_Open.wav]])
LSM:Register("sound", "Simon Chime", [[Sound\Doodad\SimonGame_LargeBlueTree.wav]])
LSM:Register("sound", "War Drums", [[Sound\Event Sounds\Event_wardrum_ogre.wav]])
LSM:Register("sound", "Cheer", [[Sound\Event Sounds\OgreEventCheerUnique.wav]])
LSM:Register("sound", "Humm", [[Sound\Spells\SimonGame_Visual_GameStart.wav]])
LSM:Register("sound", "Short Circuit", [[Sound\Spells\SimonGame_Visual_BadPress.wav]])
LSM:Register("sound", "Fel Portal", [[Sound\Spells\Sunwell_Fel_PortalStand.wav]])
LSM:Register("sound", "Fel Nova", [[Sound\Spells\SeepingGaseous_Fel_Nova.wav]])
LSM:Register("sound", "You Will Die!", [[Sound\Creature\CThun\CThunYouWillDIe.wav]])
LSM:Register("sound", "Omen: Aoogah!", [[Interface\AddOns\Omen\aoogah.ogg]])
-----------------------------------------------------------------------------
-- Localize some global functions
local floor, format, random, pairs, type = floor, format, random, pairs, type
local tinsert, tremove, next, sort, wipe = tinsert, tremove, next, sort, wipe
local RAID_CLASS_COLORS = RAID_CLASS_COLORS
local UnitDetailedThreatSituation = UnitDetailedThreatSituation
local UnitExists, UnitGUID, UnitName, UnitClass, UnitHealth = UnitExists, UnitGUID, UnitName, UnitClass, UnitHealth
local UnitIsPlayer, UnitPlayerControlled, UnitCanAttack = UnitIsPlayer, UnitPlayerControlled, UnitCanAttack
local GetNumRaidMembers, GetNumPartyMembers = GetNumRaidMembers, GetNumPartyMembers
-----------------------------------------------------------------------------
-- Local variables used
local db
local defaults = {
profile = {
Alpha = 1,
Scale = 1,
GrowUp = false,
Autocollapse = false,
NumBars = 10,
CollapseHide = false,
Locked = false,
PositionW = 200,
PositionH = 82,
VGrip1 = 85,
VGrip2 = 115,
UseFocus = false,
IgnorePlayerPets = true,
FrameStrata = "3-MEDIUM",
ClampToScreen = true,
ClickThrough = false,
Background = {
Texture = "Blizzard Parchment",
BorderTexture = "Blizzard Dialog",
Color = {r = 1, g = 1, b = 1, a = 1,},
BorderColor = {r = 0.8, g = 0.6, b = 0, a = 1,},
Tile = false,
TileSize = 32,
EdgeSize = 8,
BarInset = 3,
},
TitleBar = {
Height = 16,
Font = "Friz Quadrata TT",
FontOutline = "",
FontColor = {r = 1, g = 1, b = 1, a = 1,},
FontSize = 10,
ShowTitleBar = true,
UseSameBG = true,
Texture = "Blizzard Parchment",
BorderTexture = "Blizzard Dialog",
Color = {r = 1, g = 1, b = 1, a = 1,},
BorderColor = {r = 0.8, g = 0.6, b = 0, a = 1,},
Tile = false,
TileSize = 32,
EdgeSize = 8,
},
Bar = {
Texture = "Blizzard",
Height = 12,
Spacing = 0,
AnimateBars = true,
ShortNumbers = true,
Font = "Friz Quadrata TT",
FontOutline = "",
FontColor = {r = 1, g = 1, b = 1, a = 1,},
FontSize = 10,
Classes = {
DEATHKNIGHT = true,
DRUID = true,
HUNTER = true,
MAGE = true,
PALADIN = true,
PET = true,
PRIEST = true,
ROGUE = true,
SHAMAN = true,
WARLOCK = true,
WARRIOR = true,
HERO = true,
["*NOTINPARTY*"] = true,
},
ShowTPS = true,
TPSWindow = 10,
ShowHeadings = true,
HeadingBGColor = {r = 0, g = 0, b = 0, a = 0,},
UseMyBarColor = false,
MyBarColor = {r = 1, g = 0, b = 0, a = 1,},
ShowPercent = true,
ShowValue = true,
UseClassColors = true,
BarColor = {r = 1, g = 0, b = 0, a = 1,},
UseTankBarColor = false,
TankBarColor = {r = 1, g = 0, b = 0, a = 1,},
AlwaysShowSelf = true,
ShowAggroBar = true,
AggroBarColor = {r = 1, g = 0, b = 0, a = 1,},
PetBarColor = {r = 0.77, g = 0, b = 1, a = 1},
FadeBarColor = {r = 0.5, g = 0.5, b = 0.5, a = 1},
UseCustomClassColors = true,
InvertColors = false,
},
ShowWith = {
UseShowWith = true,
Pet = true,
Alone = false,
Party = true,
Raid = true,
-- Deprecated SV values
-- Resting = false, PVP = false, Dungeon = true, ShowOnlyInCombat = false,
HideWhileResting = true,
HideInPVP = true,
HideWhenOOC = false,
},
FuBar = {
HideMinimapButton = true,
AttachMinimap = false,
},
Warnings = {
Sound = true,
Flash = true,
Shake = false,
Message = false,
SinkOptions = {},
Threshold = 90,
SoundFile = "Fel Nova",
DisableWhileTanking = true,
},
MinimapIcon = {
hide = false,
minimapPos = 220,
radius = 80,
},
},
}
local guidNameLookup = {} -- Format: guidNameLookup[guid] = "Unit Name"
local guidClassLookup = {} -- Format: guidClassLookup[guid] = "CLASS"
local timers = {} -- Format: timers.timerName = timer returned from AceTimer-3.0
local bars = {} -- Format: bars[i] = frame containing the i-th bar from the top of Omen
local inRaid, inParty -- boolean variables indicating if the player is in a raid and/or party
local testMode = false -- boolean: Are we in test mode?
local manualToggle = false -- boolean: Did we manually toggle Omen?
local moduleOptions = {} -- Table for LoD module options registration
Omen.GuidNameLookup = guidNameLookup
Omen.GuidClassLookup = guidClassLookup
Omen.Timers = timers
Omen.Bars = bars
setmetatable(guidNameLookup, {__index = function(self, guid) return L["<Unknown>"] end})
-- For speedups. Rather than concantenating every time we need a unitID, we just look
-- it up instead. That is rID[i] is much faster than format("raid%d", i) or "raid"..i
local pID = {}
local ptID = {}
local ppID = {}
local pptID = {}
local rID = {}
local rtID = {}
local rpID = {}
local rptID = {}
for i = 1, 4 do
pID[i] = format("party%d", i)
ptID[i] = format("party%dtarget", i)
ppID[i] = format("partypet%d", i)
pptID[i] = format("partypet%dtarget", i)
end
for i = 1, 40 do
rID[i] = format("raid%d", i)
rtID[i] = format("raid%dtarget", i)
rpID[i] = format("raidpet%d", i)
rptID[i] = format("raidpet%dtarget", i)
end
local showClassesOptionTable = {
DEATHKNIGHT = L["DEATHKNIGHT"],
DRUID = L["DRUID"],
HUNTER = L["HUNTER"],
MAGE = L["MAGE"],
PALADIN = L["PALADIN"],
PET = L["PET"],
PRIEST = L["PRIEST"],
ROGUE = L["ROGUE"],
SHAMAN = L["SHAMAN"],
WARLOCK = L["WARLOCK"],
WARRIOR = L["WARRIOR"],
HERO = L["HERO"],
["*NOTINPARTY*"] = L["*Not in Party*"],
}
----------------------------------------------------------------------------------------
-- Use a common frame and setup some common functions for the Omen dropdown menus
local Omen_DropDownMenu = CreateFrame("Frame", "Omen_DropDownMenu")
Omen_DropDownMenu.displayMode = "MENU"
Omen_DropDownMenu.info = {}
Omen_DropDownMenu.HideMenu = function()
if UIDROPDOWNMENU_OPEN_MENU == Omen_DropDownMenu then
CloseDropDownMenus()
end
end
Omen_DropDownMenu.OnClick = function(frame, button, down)
if Omen_DropDownMenu.initialize ~= frame.initMenuFunc then
CloseDropDownMenus()
Omen_DropDownMenu.initialize = frame.initMenuFunc
end
ToggleDropDownMenu(1, nil, Omen_DropDownMenu, frame, 0, 0)
end
-----------------------------------------------------------------------------
-- Table Pool for recycling tables
local tablePool = {}
setmetatable(tablePool, {__mode = "kv"}) -- Weak table
-- Get a new table
local function newTable()
local t = next(tablePool) or {}
tablePool[t] = nil
return t
end
-- Delete table and return to pool -- Recursive!! -- Use with care!!
local function delTable(t)
if type(t) == "table" then
for k, v in pairs(t) do
if type(v) == "table" then
delTable(v) -- child tables get put into the pool
end
t[k] = nil
end
t[true] = true -- resize table to 1 item
t[true] = nil
setmetatable(t, nil)
tablePool[t] = true
end
return nil -- return nil to assign input reference
end
-----------------------------------------------------------------------------
-- Omen initialization and frame functions
local function startmoving(self)
if not db.Locked then
Omen.Anchor.IsMovingOrSizing = 1
Omen.Anchor:StartMoving()
end
end
local function stopmoving(self)
if Omen.Anchor.IsMovingOrSizing then
Omen.Anchor:StopMovingOrSizing()
Omen:SetAnchors()
Omen:UpdateBars()
Omen.Anchor.IsMovingOrSizing = nil
end
if self == Omen.Anchor then db.Shown = self:IsShown() end
end
local function sizing(self)
local w = Omen.Anchor:GetWidth()
db.VGrip1 = w * Omen.Anchor.VGrip1Ratio
db.VGrip2 = w * Omen.Anchor.VGrip2Ratio
if db.VGrip1 < 10 then db.VGrip1 = 10 end
if db.VGrip1 > w - 10 then db.VGrip1 = w - 10 end
if db.Bar.ShowTPS then
if db.VGrip2 < db.VGrip1 + 10 then db.VGrip2 = db.VGrip1 + 10 end
if db.VGrip1 > w - 20 then
db.VGrip1 = w - 20
db.VGrip2 = w - 10
end
Omen.VGrip2:ClearAllPoints()
Omen.VGrip2:SetPoint("TOPLEFT", Omen.BarList, "TOPLEFT", db.VGrip2, 0)
Omen.VGrip2:SetPoint("BOTTOMLEFT", Omen.BarList, "BOTTOMLEFT", db.VGrip2, 0)
end
Omen.VGrip1:ClearAllPoints()
Omen.VGrip1:SetPoint("TOPLEFT", Omen.BarList, "TOPLEFT", db.VGrip1, 0)
Omen.VGrip1:SetPoint("BOTTOMLEFT", Omen.BarList, "BOTTOMLEFT", db.VGrip1, 0)
Omen:ResizeBars()
Omen:ReAnchorLabels()
Omen:UpdateBars()
end
local function movegrip1(self)
local x = GetCursorPosition() / UIParent:GetEffectiveScale() / Omen.Anchor:GetScale()
local x1 = Omen.Anchor:GetLeft() + 10
local x2 = db.Bar.ShowTPS and Omen.Anchor:GetLeft() + db.VGrip2 - 10 or Omen.Anchor:GetRight() - 10
if x > x1 and x < x2 then
db.VGrip1 = x - x1 + 10
Omen.VGrip1:ClearAllPoints()
Omen.VGrip1:SetPoint("TOPLEFT", Omen.BarList, "TOPLEFT", db.VGrip1, 0)
Omen.VGrip1:SetPoint("BOTTOMLEFT", Omen.BarList, "BOTTOMLEFT", db.VGrip1, 0)
end
Omen:ReAnchorLabels()
end
local function movegrip2(self)
local x = GetCursorPosition() / UIParent:GetEffectiveScale() / Omen.Anchor:GetScale()
local x1 = Omen.Anchor:GetLeft() + db.VGrip1 + 10
local x2 = Omen.Anchor:GetRight() - 10
if x > x1 and x < x2 then
db.VGrip2 = x - x1 + db.VGrip1 + 10
Omen.VGrip2:ClearAllPoints()
Omen.VGrip2:SetPoint("TOPLEFT", Omen.BarList, "TOPLEFT", db.VGrip2, 0)
Omen.VGrip2:SetPoint("BOTTOMLEFT", Omen.BarList, "BOTTOMLEFT", db.VGrip2, 0)
end
Omen:ReAnchorLabels()
end
function Omen:CreateFrames()
-- Create anchor
self.Anchor = CreateFrame("Frame", "OmenAnchor", UIParent)
self.Anchor:SetResizable(true)
self.Anchor:SetMinResize(90, db.Background.EdgeSize * 2)
self.Anchor:SetMovable(true)
self.Anchor:SetPoint("CENTER", UIParent, "CENTER")
self.Anchor:SetWidth(225)
self.Anchor:SetHeight(150)
self.Anchor:SetScript("OnHide", stopmoving)
self.Anchor:SetScript("OnShow", function(self) db.Shown = true Omen:UpdateBars() end)
-- Create Title
self.Title = CreateFrame("Button", "OmenTitle", self.Anchor)
self.Title:SetPoint("TOPLEFT", self.Anchor, "TOPLEFT")
self.Title:SetPoint("TOPRIGHT", self.Anchor, "TOPRIGHT")
self.Title:SetHeight(16)
self.Title:SetMinResize(90, db.Background.EdgeSize * 2)
self.Title:EnableMouse(true)
self.Title:SetScript("OnMouseDown", startmoving)
self.Title:SetScript("OnMouseUp", stopmoving)
self.Title:SetScript("OnClick", Omen_DropDownMenu.OnClick)
self.Title.initMenuFunc = self.TitleQuickMenu
self.Title:RegisterForClicks("RightButtonUp")
-- Create Title text
self.TitleText = self.Title:CreateFontString(nil, nil, "GameFontNormal")
self.TitleText:SetPoint("LEFT", self.Title, "LEFT", 8, 1)
self.TitleText:SetJustifyH("LEFT")
self.TitleText:SetTextColor(1, 1, 1, 1)
self.defaultTitle = "Omen|cffffcc003|r"
self.TitleText:SetText(self.defaultTitle)
-- Create Bar List
self.BarList = CreateFrame("Frame", "OmenBarList", self.Anchor)
self.BarList:SetResizable(true)
self.BarList:EnableMouse(true)
self.BarList:SetPoint("TOPLEFT", self.Title, "BOTTOMLEFT")
self.BarList:SetPoint("BOTTOMRIGHT", self.Anchor, "BOTTOMRIGHT")
self.BarList:SetScript("OnMouseDown", startmoving)
self.BarList:SetScript("OnMouseUp", stopmoving)
self.BarList:SetScript("OnHide", stopmoving)
self.BarList.barsShown = 0
-- Create resizing corner grip
self.Grip = CreateFrame("Button", "OmenResizeGrip", self.BarList)
self.Grip:SetNormalTexture("Interface\\AddOns\\Omen\\ResizeGrip")
self.Grip:SetHighlightTexture("Interface\\AddOns\\Omen\\ResizeGrip")
self.Grip:SetWidth(16)
self.Grip:SetHeight(16)
self.Grip:SetPoint("BOTTOMRIGHT", self.BarList, "BOTTOMRIGHT", 0, 1)
self.Grip:SetScript("OnMouseDown", function(self, button)
if not db.Locked then
Omen.Anchor.IsMovingOrSizing = 2
Omen.Anchor.VGrip1Ratio = db.VGrip1 / Omen.Anchor:GetWidth()
Omen.Anchor.VGrip2Ratio = db.VGrip2 / Omen.Anchor:GetWidth()
Omen.Anchor:SetScript("OnSizeChanged", sizing)
Omen.Anchor:StartSizing()
end
end)
self.Grip:SetScript("OnMouseUp", function(self)
if Omen.Anchor.IsMovingOrSizing == 2 then
Omen.Anchor:SetScript("OnSizeChanged", nil)
Omen.Anchor:StopMovingOrSizing()
sizing()
Omen:SetAnchors()
Omen.Anchor.IsMovingOrSizing = nil
Omen.Anchor.VGrip1Ratio = nil
end
end)
self.Grip:SetScript("OnHide", self.Grip:GetScript("OnMouseUp"))
-- Create label resizing vertical grip 1
self.VGrip1 = CreateFrame("Button", "OmenVResizeGrip1", self.BarList)
self.VGrip1:SetWidth(1)
self.VGrip1:SetPoint("TOPLEFT", self.BarList, "TOPLEFT", db.VGrip1, 0)
self.VGrip1:SetPoint("BOTTOMLEFT", self.BarList, "BOTTOMLEFT", db.VGrip1, 0)
self.VGrip1:SetNormalTexture("Interface\\Tooltips\\UI-Tooltip-Background")
self.VGrip1:SetHighlightTexture("Interface\\Tooltips\\UI-Tooltip-Background")
self.VGrip1:GetNormalTexture():SetVertexColor(1, 1, 1, 0.5)
self.VGrip1:GetHighlightTexture():SetVertexColor(1, 1, 1, 0.5)
self.VGrip1:SetScript("OnMouseDown", function(self)
if not db.Locked then self:SetScript("OnUpdate", movegrip1) end
end)
self.VGrip1:SetScript("OnMouseUp", function(self) self:SetScript("OnUpdate", nil) end)
self.VGrip1:SetScript("OnHide", self.VGrip1:GetScript("OnMouseUp"))
self.VGrip1:SetFrameLevel(self.BarList:GetFrameLevel() + 2)
-- Create label resizing vertical grip 2
self.VGrip2 = CreateFrame("Button", "OmenVResizeGrip2", self.BarList)
self.VGrip2:SetWidth(1)
self.VGrip2:SetPoint("TOPLEFT", self.BarList, "TOPLEFT", db.VGrip2, 0)
self.VGrip2:SetPoint("BOTTOMLEFT", self.BarList, "BOTTOMLEFT", db.VGrip2, 0)
self.VGrip2:SetNormalTexture("Interface\\Tooltips\\UI-Tooltip-Background")
self.VGrip2:SetHighlightTexture("Interface\\Tooltips\\UI-Tooltip-Background")
self.VGrip2:GetNormalTexture():SetVertexColor(1, 1, 1, 0.5)
self.VGrip2:GetHighlightTexture():SetVertexColor(1, 1, 1, 0.5)
self.VGrip2:SetScript("OnMouseDown", function(self)
if not db.Locked then self:SetScript("OnUpdate", movegrip2) end
end)
self.VGrip2:SetScript("OnMouseUp", self.VGrip1:GetScript("OnMouseUp"))
self.VGrip2:SetScript("OnHide", self.VGrip1:GetScript("OnMouseUp"))
self.VGrip2:SetFrameLevel(self.BarList:GetFrameLevel() + 2)
--[[self.FocusButton = CreateFrame("Button", "OmenFocusButton", self.Title, "OptionsButtonTemplate")
self.FocusButton:SetWidth(16)
self.FocusButton:SetHeight(16)
self.FocusButton:SetPoint("TOPRIGHT")
self.FocusButton:SetText("F")
self.FocusButton:SetScript("OnClick", function(self, button, down)
db.UseFocus = not db.UseFocus
if db.UseFocus then
self:GetFontString():SetTextColor(1, 0.82, 0, 1)
else
self:GetFontString():SetTextColor(0.5, 0.5, 0.5, 1)
end
Omen:UpdateBars()
end)
if db.UseFocus then
self.FocusButton:GetFontString():SetTextColor(1, 0.82, 0, 1)
else
self.FocusButton:GetFontString():SetTextColor(0.5, 0.5, 0.5, 1)
end]]
self.CreateFrames = nil
end
function Omen:OnInitialize()
-- Create savedvariables
self.db = LibStub("AceDB-3.0"):New("Omen3DB", defaults)
self.db.RegisterCallback(self, "OnProfileChanged", "OnProfileChanged")
self.db.RegisterCallback(self, "OnProfileCopied", "OnProfileChanged")
self.db.RegisterCallback(self, "OnProfileReset", "OnProfileChanged")
db = self.db.profile
self:SetSinkStorage(db.Warnings.SinkOptions)
LSM.RegisterCallback(self, "LibSharedMedia_Registered", "UpdateUsedMedia")
-- These 2 functions self GC after running
self:CreateFrames()
self:SetupOptions()
self:RegisterEvent("PLAYER_LOGIN")
self.OnInitialize = nil
end
function Omen:PLAYER_LOGIN()
-- We set up anchors here because we only want to do it once on
-- PLAYER_LOGIN, hence we don't do it in OnEnable() which triggers on
-- the same event as well as on every subsequent Enable()/Disable() calls.
-- It cannot be earlier than PLAYER_LOGIN because layout-cache.txt
-- is loaded just before this event fires.
self:SetAnchors(true)
self.Anchor:SetAlpha(db.Alpha)
self.Anchor:SetFrameStrata(strsub(db.FrameStrata, 3))
self.Anchor:SetClampedToScreen(db.ClampToScreen)
self:UpdateBackdrop()
self:UpdateTitleBar()
self:UpdateGrips()
self:UpdateClickThrough()
self:UpdateRaidClassColors()
self:ClearAll()
self:UnregisterEvent("PLAYER_LOGIN")
if not db.Shown then self.Anchor:Hide() end -- Auto-show/hide will override this later if enabled
-- Optional !ClassColors addon support
if CUSTOM_CLASS_COLORS then
CUSTOM_CLASS_COLORS:RegisterCallback("UpdateBars", self)
end
-- ConfigMode support
do
CONFIGMODE_CALLBACKS = CONFIGMODE_CALLBACKS or {}
local oldTestMode = testMode
local oldLocked = db.Locked
function CONFIGMODE_CALLBACKS.Omen(action)
if action == "ON" then
oldTestMode = testMode
oldLocked = db.Locked
testMode = true
db.Locked = false
Omen:Toggle(true)
elseif action == "OFF" then
testMode = oldTestMode
db.Locked = oldLocked
manualToggle = false
Omen:UpdateVisible()
end
Omen:UpdateGrips()
Omen:UpdateBars()
LibStub("AceConfigRegistry-3.0"):NotifyChange("Omen")
end
end
-- LDB launcher
if LDB then
OmenLauncher = LDB:NewDataObject("Omen", {
type = "launcher",
icon = "Interface\\AddOns\\Omen\\icon",
OnClick = function(clickedframe, button)
if button == "RightButton" then Omen:ShowConfig() else Omen:Toggle() end
end,
OnTooltipShow = function(tt)
tt:AddLine(self.defaultTitle)
tt:AddLine("|cffffff00" .. L["Click|r to toggle the Omen window"])
tt:AddLine("|cffffff00" .. L["Right-click|r to open the options menu"])
end,
})
if LDBIcon and not IsAddOnLoaded("Broker2FuBar") and not IsAddOnLoaded("FuBar") then
LDBIcon:Register("Omen", OmenLauncher, db.MinimapIcon)
end
end
-- Optional launcher support for LFBP-3.0 if present, this code is placed here so
-- that it runs after all other addons have loaded since we don't embed LFBP-3.0
-- Yes, this is one big hack since LFBP-3.0 is a Rock library, and we embed it
-- via Ace3. OnEmbedInitialize() needs to be called manually.
if LibStub:GetLibrary("LibFuBarPlugin-3.0", true) and not IsAddOnLoaded("FuBar2Broker") then
local LFBP = LibStub:GetLibrary("LibFuBarPlugin-3.0")
LibStub("AceAddon-3.0"):EmbedLibrary(self, "LibFuBarPlugin-3.0")
self:SetFuBarOption("tooltipType", "GameTooltip")
self:SetFuBarOption("hasNoColor", true)
self:SetFuBarOption("cannotDetachTooltip", true)
self:SetFuBarOption("hideWithoutStandby", true)
self:SetFuBarOption("iconPath", [[Interface\AddOns\Omen\icon]])
self:SetFuBarOption("hasIcon", true)
self:SetFuBarOption("defaultPosition", "RIGHT")
self:SetFuBarOption("tooltipHiddenWhenEmpty", true)
self:SetFuBarOption("configType", "None")
LFBP:OnEmbedInitialize(self)
function Omen:OnUpdateFuBarTooltip()
GameTooltip:AddLine(self.defaultTitle)
GameTooltip:AddLine("|cffffff00" .. L["Click|r to toggle the Omen window"])
GameTooltip:AddLine("|cffffff00" .. L["Right-click|r to open the options menu"])
end
function Omen:OnFuBarClick(button)
if button == "RightButton" then self:ShowConfig() else self:Toggle() end
end
self.optionsFrames["FuBar"] = LibStub("AceConfigDialog-3.0"):AddToBlizOptions("Omen", L["FuBar Options"], self.versionstring, "FuBar")
self:UpdateFuBarSettings()
end
self.PLAYER_LOGIN = nil
end
function Omen:OnEnable()
self:RegisterEvent("UNIT_THREAT_LIST_UPDATE")
self:RegisterEvent("UNIT_THREAT_SITUATION_UPDATE")
self:RegisterEvent("PLAYER_TARGET_CHANGED")
self:RegisterEvent("PARTY_MEMBERS_CHANGED")
self:RegisterEvent("UNIT_PET", "PARTY_MEMBERS_CHANGED")
self:RegisterEvent("UNIT_NAME_UPDATE", "PARTY_MEMBERS_CHANGED")
self:RegisterEvent("PLAYER_PET_CHANGED", "PARTY_MEMBERS_CHANGED")
--self:RegisterEvent("RAID_ROSTER_UPDATE", "PARTY_MEMBERS_CHANGED") -- Is this needed?
self:RegisterEvent("PLAYER_UPDATE_RESTING", "UpdateVisible")
self:RegisterEvent("PLAYER_ENTERING_WORLD")
if db.ShowWith.HideWhenOOC then
self:RegisterEvent("PLAYER_REGEN_DISABLED", "UpdateVisible")
self:RegisterEvent("PLAYER_REGEN_ENABLED", "UpdateVisible")
end
if db.UseFocus then
self:RegisterEvent("UNIT_TARGET")
end
self:PARTY_MEMBERS_CHANGED()
self:PLAYER_TARGET_CHANGED()
end
function Omen:OnDisable()
-- Cancel all timers (well at least nil them all
-- out in timers[], since AceTimer-3.0 cancels
-- them all OnDisable anyway).
for k, v in pairs(timers) do
self:CancelTimer(v, true)
timers[k] = nil
end
self:_toggle(false)
end
function Omen:OnProfileChanged(event, database, newProfileKey)
db = database.profile
self:SetAnchors(true)
self.Anchor:SetAlpha(db.Alpha)
self.Anchor:SetFrameStrata(strsub(db.FrameStrata, 3))
self.Anchor:SetClampedToScreen(db.ClampToScreen)
self:UpdateBackdrop()
self:UpdateTitleBar()
self:UpdateGrips()
self:ResizeBars()
self:ReAnchorBars()
self:ReAnchorLabels()
self:UpdateBarLabelSettings()
self:UpdateBarTextureSettings()
self:UpdateClickThrough()
self:UpdateRaidClassColors()
self:UpdateFuBarSettings()
-- These remainder settings were not placed in functions
-- and were just updated directly from the config code.
if LDBIcon and not IsAddOnLoaded("Broker2FuBar") and not IsAddOnLoaded("FuBar") then
LDBIcon:Refresh("Omen", db.MinimapIcon)
end
if db.ShowWith.HideWhenOOC then
self:RegisterEvent("PLAYER_REGEN_DISABLED", "UpdateVisible")
self:RegisterEvent("PLAYER_REGEN_ENABLED", "UpdateVisible")
else
self:UnregisterEvent("PLAYER_REGEN_DISABLED")
self:UnregisterEvent("PLAYER_REGEN_ENABLED")
end
if db.UseFocus then
self:RegisterEvent("UNIT_TARGET")
else
self:UnregisterEvent("UNIT_TARGET")
end
local f = self.TPSUpdateFrame
if f then
if db.Bar.ShowTPS then f:Show() else f:Hide() end
end
if db.Bar.ShowValue and db.Bar.ShowPercent then
bars[0].Text2:SetText(L["Threat [%]"])
else
bars[0].Text2:SetText(L["Threat"])
end
self:UpdateVisible()
self:UpdateBars()
end
function Omen:UpdateUsedMedia(event, mediatype, key)
if mediatype == "statusbar" then
if key == db.Bar.Texture then self:UpdateBarTextureSettings() end
elseif mediatype == "font" then
if key == db.TitleBar.Font then self:UpdateTitleBar() end
if key == db.Bar.Font then self:UpdateBarLabelSettings() self:UpdateBars() end
elseif mediatype == "background" then
if key == db.Background.Texture then self:UpdateBackdrop() end
elseif mediatype == "border" then
if key == db.Background.BorderTexture then self:UpdateBackdrop() end
--elseif mediatype == "sound" then
-- Do nothing
end
end
function Omen:SetAnchors(useDB)
local x, y, w, h
-- Set the scale, since the scaling affects the position
self.Anchor:SetScale(db.Scale)
self.VGrip1:SetWidth(1 / self.VGrip1:GetEffectiveScale())
self.VGrip2:SetWidth(1 / self.VGrip2:GetEffectiveScale())
-- Get position
if useDB then
x, y = db.PositionX, db.PositionY
if not x or not y then
self.Anchor:ClearAllPoints()
self.Anchor:SetPoint("CENTER", UIParent, "CENTER", 0, 0)
x, y = self.Anchor:GetLeft(), db.GrowUp and self.Anchor:GetBottom() or self.Anchor:GetTop()
end
else
x, y = self.Anchor:GetLeft(), db.GrowUp and self.Anchor:GetBottom() or self.Anchor:GetTop()
end
-- Get width/height
w = useDB and db.PositionW or self.Anchor:GetWidth()
h = useDB and db.PositionH or self.Anchor:GetHeight()
-- Set the anchors and size
self.Anchor:ClearAllPoints()
self.Anchor:SetPoint(db.GrowUp and "BOTTOMLEFT" or "TOPLEFT", UIParent, "BOTTOMLEFT", x, y)
self.Anchor:SetWidth(w)
self.Anchor:SetHeight(h)
self.Anchor:SetUserPlaced(nil)
-- Save the data
db.PositionX, db.PositionY = x, y
db.PositionW, db.PositionH = w, h
end
-- For public use
function Omen:Toggle(setting)
-- Don't set the manualToggle flag if "Hide Omen on 0 bars" option is active
if not (db.Autocollapse and db.CollapseHide) then
manualToggle = true
end
return self:_toggle(setting)
end
-- For internal use
function Omen:_toggle(setting)
if setting == nil then
setting = not self.Anchor:IsShown()
end
if setting then
self.Anchor:Show()
else
self.Anchor:Hide()
end
end
function Omen:UpdateVisible(event)
local t = db.ShowWith
if not t.UseShowWith or manualToggle then return end
-- Hide if HideWhenOOC option is on, we're not in combat, and the triggering event is not
-- "PLAYER_REGEN_DISABLED" (we're out of combat during this event just before entering combat)
if t.HideWhenOOC and not InCombatLockdown() and event ~= "PLAYER_REGEN_DISABLED" then
self:_toggle(false)
return
end
-- Check for pet|party|raid|alone
local show = (t.Pet and UnitExists("pet")) or
(t.Party and inParty) or
(t.Raid and inRaid) or
(t.Alone and not inParty and not inRaid and not UnitExists("pet"))
-- Then hide override if necessary for resting|pvp
local inInstance, instanceType = IsInInstance()
if (t.HideWhileResting and IsResting()) or (t.HideInPVP and (instanceType == "pvp" or instanceType == "arena")) then
show = false
end
-- Hide if Autocollapse and Hide Omen on 0 Bars are both active and there are 0 bars.
if db.Autocollapse and db.CollapseHide and self.BarList.barsShown == 0 then
show = false
end
self:_toggle(show)
end
local bgFrame = {insets = {}}
function Omen:UpdateBackdrop()
bgFrame.bgFile = LSM:Fetch("background", db.Background.Texture)
bgFrame.edgeFile = LSM:Fetch("border", db.Background.BorderTexture)
bgFrame.tile = db.Background.Tile
bgFrame.tileSize = db.Background.TileSize
bgFrame.edgeSize = db.Background.EdgeSize
local inset = floor(db.Background.EdgeSize / 4)
bgFrame.insets.left = inset
bgFrame.insets.right = inset
bgFrame.insets.top = inset
bgFrame.insets.bottom = inset
self.BarList:SetBackdrop(bgFrame)
if not db.TitleBar.UseSameBG then
bgFrame.bgFile = LSM:Fetch("background", db.TitleBar.Texture)
bgFrame.edgeFile = LSM:Fetch("border", db.TitleBar.BorderTexture)
bgFrame.tile = db.TitleBar.Tile
bgFrame.tileSize = db.TitleBar.TileSize
bgFrame.edgeSize = db.TitleBar.EdgeSize
local inset = floor(db.TitleBar.EdgeSize / 4)
bgFrame.insets.left = inset
bgFrame.insets.right = inset
bgFrame.insets.top = inset
bgFrame.insets.bottom = inset
end
self.Title:SetBackdrop(bgFrame)
local c = db.Background.Color
self.BarList:SetBackdropColor(c.r, c.g, c.b, c.a)
if not db.TitleBar.UseSameBG then c = db.TitleBar.Color end
self.Title:SetBackdropColor(c.r, c.g, c.b, c.a)
c = db.Background.BorderColor
self.BarList:SetBackdropBorderColor(c.r, c.g, c.b, c.a)
if not db.TitleBar.UseSameBG then c = db.TitleBar.BorderColor end
self.Title:SetBackdropBorderColor(c.r, c.g, c.b, c.a)
local h = db.Background.EdgeSize * 2
if not db.TitleBar.UseSameBG then h = db.TitleBar.EdgeSize * 2 end
self.Anchor:SetMinResize(90, h)
self.Title:SetMinResize(90, h)
if not db.TitleBar.ShowTitleBar then
self.Title:SetHeight(1e-6) -- See comment in Omen:UpdateTitleBar()
elseif h > db.TitleBar.Height then
self.Title:SetHeight(h)
else
self.Title:SetHeight(db.TitleBar.Height)
end
if self.Options then
self.Options.args.TitleBar.args.Height.min = h
end
--self.FocusButton:SetPoint("TOPRIGHT", -inset, -inset)
self.BarList:ClearAllPoints() -- See comment in Omen:UpdateTitleBar()
self.BarList:SetPoint("TOPLEFT", self.Title, "BOTTOMLEFT")
self.BarList:SetPoint("BOTTOMRIGHT", self.Anchor, "BOTTOMRIGHT")
self:ResizeBars()
self:ReAnchorBars()
self:UpdateBars()
end
function Omen:UpdateTitleBar()
local font = LSM:Fetch("font", db.TitleBar.Font)
local size = db.TitleBar.FontSize
local flags = db.TitleBar.FontOutline
local color = db.TitleBar.FontColor
self.TitleText:SetFont(font, size, flags)
self.TitleText:SetTextColor(color.r, color.g, color.b, color.a)
local h = db.Background.EdgeSize * 2
if not db.TitleBar.UseSameBG then h = db.TitleBar.EdgeSize * 2 end
if not db.TitleBar.ShowTitleBar then
-- Yes, its a hack, since it can't be set to 0
self.Title:SetHeight(1e-6)
self.Title:Hide()
elseif h > db.TitleBar.Height then
self.Title:SetHeight(h)
self.Title:Show()
else
self.Title:SetHeight(db.TitleBar.Height)
self.Title:Show()
end
-- This forces the UI to redraw it, I couldn't find a better way. Although it is
-- anchored to the Title, it doesn't update automatically on the height change.
self.BarList:ClearAllPoints()
self.BarList:SetPoint("TOPLEFT", self.Title, "BOTTOMLEFT")
self.BarList:SetPoint("BOTTOMRIGHT", self.Anchor, "BOTTOMRIGHT")
end
function Omen:UpdateFuBarSettings()
if LibStub:GetLibrary("LibFuBarPlugin-3.0", true) then
if db.FuBar.HideMinimapButton then
self:Hide()
else
self:Show()
if self:IsFuBarMinimapAttached() ~= db.FuBar.AttachMinimap then
self:ToggleFuBarMinimapAttached()
end
end
end
end
function Omen:UpdateGrips()
self.VGrip1:ClearAllPoints()
self.VGrip1:SetPoint("TOPLEFT", self.BarList, "TOPLEFT", db.VGrip1, 0)
self.VGrip1:SetPoint("BOTTOMLEFT", self.BarList, "BOTTOMLEFT", db.VGrip1, 0)
self.VGrip2:ClearAllPoints()
self.VGrip2:SetPoint("TOPLEFT", self.BarList, "TOPLEFT", db.VGrip2, 0)
self.VGrip2:SetPoint("BOTTOMLEFT", self.BarList, "BOTTOMLEFT", db.VGrip2, 0)
if db.Locked then
self.Grip:Hide()
self.VGrip1:Hide()
self.VGrip2:Hide()
else
self.Grip:Show()
self.VGrip1:Show()
if db.Bar.ShowTPS then
self.VGrip2:Show()
else
self.VGrip2:Hide()
end
end
end
function Omen:ToggleFocus()
db.UseFocus = not db.UseFocus
if db.UseFocus then
Omen:RegisterEvent("UNIT_TARGET")
else
Omen:UnregisterEvent("UNIT_TARGET")
end
Omen:UpdateBars()
end
function Omen:UpdateRaidClassColors()
if CUSTOM_CLASS_COLORS and db.Bar.UseCustomClassColors then
RAID_CLASS_COLORS = CUSTOM_CLASS_COLORS
else
RAID_CLASS_COLORS = _G.RAID_CLASS_COLORS
end
Omen:UpdateBars()
end
-----------------------------------------------------------------------------
-- Omen warnings
function Omen:Flash()
if not self.FlashFrame then
local flasher = CreateFrame("Frame", "OmenFlashFrame")
flasher:SetToplevel(true)
flasher:SetFrameStrata("FULLSCREEN_DIALOG")
flasher:SetAllPoints(UIParent)
flasher:EnableMouse(false)
flasher:Hide()
flasher.texture = flasher:CreateTexture(nil, "BACKGROUND")
flasher.texture:SetTexture("Interface\\FullScreenTextures\\LowHealth")
flasher.texture:SetAllPoints(UIParent)
flasher.texture:SetBlendMode("ADD")
flasher:SetScript("OnShow", function(self)
self.elapsed = 0
self:SetAlpha(0)
end)
flasher:SetScript("OnUpdate", function(self, elapsed)
elapsed = self.elapsed + elapsed
if elapsed < 2.6 then
local alpha = elapsed % 1.3
if alpha < 0.15 then
self:SetAlpha(alpha / 0.15)
elseif alpha < 0.9 then
self:SetAlpha(1 - (alpha - 0.15) / 0.6)
else
self:SetAlpha(0)
end
else
self:Hide()
end
self.elapsed = elapsed
end)
self.FlashFrame = flasher
end
self.FlashFrame:Show()
end
-- This function is adapted from Omen2 to be self-contained,
-- which was initially taken from BigWigs
function Omen:Shake()
local shaker = self.ShakerFrame
if not shaker then
shaker = CreateFrame("Frame", "OmenShaker", UIParent)
shaker:Hide()
shaker:SetScript("OnUpdate", function(self, elapsed)
elapsed = self.elapsed + elapsed
local x, y = 0, 0 -- Resets to original position if we're supposed to stop.
if elapsed >= 0.8 then
self:Hide()
else
x, y = random(-8, 8), random(-8, 8)
end
if WorldFrame:IsProtected() and InCombatLockdown() then
if not shaker.fail then
Omen:Print(L["|cffff0000Error:|r Omen cannot use shake warning if you have turned on nameplates at least once since logging in."])
shaker.fail = true
end
self:Hide()
else
WorldFrame:ClearAllPoints()
for i = 1, #self.originalPoints do
local v = self.originalPoints[i]
WorldFrame:SetPoint(v[1], v[2], v[3], v[4] + x, v[5] + y)
end
end
self.elapsed = elapsed
end)
shaker:SetScript("OnShow", function(self)
-- Store old worldframe positions, we need them all, people have frame modifiers for it
if not self.originalPoints then
self.originalPoints = {}
for i = 1, WorldFrame:GetNumPoints() do
tinsert(self.originalPoints, {WorldFrame:GetPoint(i)})
end
end
self.elapsed = 0
end)
self.ShakerFrame = shaker
end
shaker:Show()
end
function Omen:Warn(sound, flash, shake, message)
if sound then PlaySoundFile(LSM:Fetch("sound", db.Warnings.SoundFile)) end
if flash then self:Flash() end
if shake then self:Shake() end
if message then self:Pour(message, 1, 0, 0, nil, 24, "OUTLINE", true) end
end
-----------------------------------------------------------------------------
-- Omen bar stuff
do
-- OnUpdate function for bar animation, lasts 0.25 seconds
local function animate(self, elapsed)
local t = self.animationCursor + elapsed
local animData = self.animData
if t >= 0.25 then
self.texture:SetWidth(animData[1])
animData[3] = nil
animData[2] = nil
animData[1] = nil
t = 0
self:SetScript("OnUpdate", nil)
else
self.texture:SetWidth(animData[2] + animData[3] * t / 0.25)
end
self.animationCursor = t
end
-- function to start bar animations
local function AnimateTo(self, val)
if val == 1/0 or val == -1/0 then return end -- infinity, do nothing
if val == 0 then val = 1 end -- at least 1 pixel width
local animData = self.animData
if animData[1] == val then return end -- there is already an animation to the target width
local currentWidth = self.texture:GetWidth()
--if currentWidth > self:GetWidth() then currentWidth = self:GetWidth() end
if val == currentWidth then return end -- the current width is already the target width
animData[1] = val
animData[2] = currentWidth
animData[3] = val - currentWidth
self.animationCursor = 0
self:SetScript("OnUpdate", animate)
end
-- Create bars on demand
setmetatable(bars, {__index = function(self, barID)
local bar = CreateFrame("Frame", nil, Omen.BarList)
self[barID] = bar
local inset = db.Background.BarInset
local inset2 = db.Background.BarInset * 2
local color = db.Bar.InvertColors and db.Bar.BarColor or db.Bar.FontColor
bar:SetWidth(Omen.Anchor:GetWidth() - inset2)
bar:SetHeight(db.Bar.Height)
if db.Bar.ShowHeadings then
bar:SetPoint("TOPLEFT", Omen.BarList, "TOPLEFT", inset, -inset + (barID) * -(db.Bar.Height + db.Bar.Spacing))
else
bar:SetPoint("TOPLEFT", Omen.BarList, "TOPLEFT", inset, -inset + (barID-1) * -(db.Bar.Height + db.Bar.Spacing))
end
bar.Text1 = bar:CreateFontString(nil, nil, "GameFontNormalSmall")
bar.Text1:SetPoint("LEFT", bar, "LEFT", 5, 1)
bar.Text1:SetJustifyH("LEFT")
bar.Text1:SetFont(LSM:Fetch("font", db.Bar.Font), db.Bar.FontSize, db.Bar.FontOutline)
bar.Text1:SetTextColor(color.r, color.g, color.b, color.a)
bar.Text1:SetWidth(db.VGrip1 - 5)
bar.Text1:SetHeight(db.Bar.FontSize)
bar.Text1:SetNonSpaceWrap(false)
bar.Text2 = bar:CreateFontString(nil, nil, "GameFontNormalSmall")
bar.Text2:SetPoint("RIGHT", bar, "RIGHT", -5, 1)
bar.Text2:SetJustifyH("RIGHT")
bar.Text2:SetFont(LSM:Fetch("font", db.Bar.Font), db.Bar.FontSize, db.Bar.FontOutline)
bar.Text2:SetTextColor(color.r, color.g, color.b, color.a)
if db.Bar.ShowTPS then
bar.Text2:SetWidth(Omen.BarList:GetWidth() - db.VGrip2 - 5)
else
bar.Text2:SetWidth(Omen.BarList:GetWidth() - db.VGrip1 - 5)
end
bar.Text2:SetHeight(db.Bar.FontSize)
bar.Text2:SetNonSpaceWrap(false)
bar.Text3 = bar:CreateFontString(nil, nil, "GameFontNormalSmall")
bar.Text3:SetPoint("LEFT", bar.Text1, "RIGHT", 0, 0)
bar.Text3:SetJustifyH("RIGHT")
bar.Text3:SetFont(LSM:Fetch("font", db.Bar.Font), db.Bar.FontSize, db.Bar.FontOutline)
bar.Text3:SetTextColor(color.r, color.g, color.b, color.a)
bar.Text3:SetWidth(db.VGrip2 - db.VGrip1 - 5)
bar.Text3:SetHeight(db.Bar.FontSize)
bar.Text3:SetNonSpaceWrap(false)
if not db.Bar.ShowTPS then bar.Text3:Hide() end
bar.texture = bar:CreateTexture()
bar.texture:SetTexture(LSM:Fetch("statusbar", db.Bar.Texture))
bar.texture:SetPoint("TOPLEFT", bar, "TOPLEFT")
bar.texture:SetPoint("BOTTOMLEFT", bar, "BOTTOMLEFT")
color = db.Bar.InvertColors and db.Bar.FontColor or db.Bar.BarColor
bar.texture:SetVertexColor(color.r, color.g, color.b, color.a)
bar.animData = {}
bar.animationCursor = 0
bar.AnimateTo = AnimateTo
if barID == 0 then
bar.Text1:SetText(L["Name"])
if db.Bar.ShowValue and db.Bar.ShowPercent then
bar.Text2:SetText(L["Threat [%]"])
else
bar.Text2:SetText(L["Threat"])
end
bar.Text3:SetText(L["TPS"])
color = db.Bar.InvertColors and db.Bar.FontColor or db.Bar.HeadingBGColor
bar.texture:SetVertexColor(color.r, color.g, color.b, color.a)
bar:Hide()
elseif barID == 1 then
-- Parent our TPS update frame to the first bar, so that TPS updates
-- updates happen when at least 1 bar (the first bar) is shown.
Omen.TPSUpdateFrame = CreateFrame("Frame", nil, bar)
Omen.TPSUpdateFrame:SetScript("OnUpdate", function(self, elapsed) Omen:UpdateTPS() end)
if not db.Bar.ShowTPS then Omen.TPSUpdateFrame:Hide() end
end
return bar
end})
end
function Omen:ResizeBars()
local inset = db.Background.BarInset * 2
local w = Omen.Anchor:GetWidth() - inset
for i = 0, #bars do
bars[i]:SetWidth(w)
bars[i]:SetHeight(db.Bar.Height)
end
end
function Omen:ReAnchorBars()
local inset = db.Background.BarInset
if db.Bar.ShowHeadings then
for i = 0, #bars do
bars[i]:SetPoint("TOPLEFT", self.BarList, "TOPLEFT", inset, -inset + (i) * -(db.Bar.Height + db.Bar.Spacing))
end
else
for i = 1, #bars do
bars[i]:SetPoint("TOPLEFT", self.BarList, "TOPLEFT", inset, -inset + (i-1) * -(db.Bar.Height + db.Bar.Spacing))
end
bars[0]:Hide()
end
end
function Omen:UpdateBarLabelSettings()
local font = LSM:Fetch("font", db.Bar.Font)
local size = db.Bar.FontSize
local flags = db.Bar.FontOutline
local color = db.Bar.InvertColors and db.Bar.BarColor or db.Bar.FontColor
local color2 = db.Bar.InvertColors and db.Bar.FontColor or db.Bar.BarColor
for i = 0, #bars do
bars[i].Text1:SetFont(font, size, flags)
bars[i].Text2:SetFont(font, size, flags)
bars[i].Text3:SetFont(font, size, flags)
bars[i].Text1:SetTextColor(color.r, color.g, color.b, color.a)
bars[i].Text2:SetTextColor(color.r, color.g, color.b, color.a)
bars[i].Text3:SetTextColor(color.r, color.g, color.b, color.a)
bars[i].Text1:SetHeight(size)
bars[i].Text2:SetHeight(size)
bars[i].Text3:SetHeight(size)
bars[i].texture:SetVertexColor(color2.r, color2.g, color2.b, color2.a)
end
color = db.Bar.InvertColors and db.Bar.FontColor or db.Bar.HeadingBGColor
color2 = db.Bar.InvertColors and db.Bar.HeadingBGColor or db.Bar.FontColor
bars[0].texture:SetVertexColor(color.r, color.g, color.b, color.a)
bars[0].Text1:SetTextColor(color2.r, color2.g, color2.b, color2.a)
bars[0].Text2:SetTextColor(color2.r, color2.g, color2.b, color2.a)
bars[0].Text3:SetTextColor(color2.r, color2.g, color2.b, color2.a)
end
function Omen:ReAnchorLabels()
local w = db.VGrip1
local w2 = db.Bar.ShowTPS and Omen.BarList:GetWidth() - db.VGrip2 or Omen.BarList:GetWidth() - w
local w3 = db.VGrip2 - db.VGrip1
for i = 0, #bars do
bars[i].Text1:SetWidth(w - 5)
bars[i].Text2:SetWidth(w2 - 5)
if db.Bar.ShowTPS then
bars[i].Text3:SetWidth(w3 - 5)
bars[i].Text3:Show()
else
bars[i].Text3:Hide()
end
end
end
function Omen:UpdateBarTextureSettings()
local texturepath = LSM:Fetch("statusbar", db.Bar.Texture)
for i = 0, #bars do
bars[i].texture:SetTexture(texturepath)
end
end
function Omen:UpdateClickThrough()
self.Title:EnableMouse(not db.ClickThrough)
self.BarList:EnableMouse(not db.ClickThrough)
end
-----------------------------------------------------------------------------
-- Omen event functions
-- Fired when a mob has its threat list updated. The mob that
-- had its list updated is the first parameter of the event.
function Omen:UNIT_THREAT_LIST_UPDATE(event, unitID)
-- It appears that unitID can only be "target" or "focus"
self:UpdateBars()
end
-- Fired when a unit's threat situation changes. The unit that
-- had a change in threat situation is the first parameter of
-- the event. Note that this only triggers when major state
-- changes, not when the raw threat values change.
function Omen:UNIT_THREAT_SITUATION_UPDATE(...)
self:UpdateBars()
end
function Omen:PLAYER_TARGET_CHANGED()
-- Stop our unit update timer for updating threat on "targettarget"
if timers.UpdateBars then
self:CancelTimer(timers.UpdateBars, true)
timers.UpdateBars = nil
end
self:UpdateBars()
end
function Omen:UNIT_TARGET(event, unitID)
if unitID == "focus" and db.UseFocus and self.unitID == "focustarget" then
self:UpdateBars()
end
end
local lastPartyUpdateTime = GetTime()
function Omen:PARTY_MEMBERS_CHANGED()
local oldInParty, oldInRaid = inParty, inRaid
inParty = GetNumPartyMembers() > 0
inRaid = GetNumRaidMembers() > 0
if oldInParty ~= inParty or oldInRaid ~= inRaid then manualToggle = false end
self:UpdateVisible()
-- Run the update if the last call is more than 0.5 seconds ago else
-- schedule an update 0.5 seconds later if one isn't already scheduled
if GetTime() - lastPartyUpdateTime > 0.5 then
self:UpdatePartyGUIDs()
elseif not timers.UpdatePartyGUIDs then
timers.UpdatePartyGUIDs = self:ScheduleTimer("UpdatePartyGUIDs", 0.5)
end
end
-- This function updates the name and class guid lookup tables of the raid
function Omen:UpdatePartyGUIDs()
lastPartyUpdateTime = GetTime()
if timers.UpdatePartyGUIDs then
self:CancelTimer(timers.UpdatePartyGUIDs, true)
timers.UpdatePartyGUIDs = nil
end
local _
local me = UnitGUID("player")
wipe(guidClassLookup)
if me then -- Because it sometimes is nil on zoning/logging in.
guidNameLookup[me] = UnitName("player")
_, guidClassLookup[me] = UnitClass("player")
else
timers.UpdatePartyGUIDs = self:ScheduleTimer("UpdatePartyGUIDs", 0.5)
end
if UnitExists("pet") then
local petGUID = UnitGUID("pet")
guidClassLookup[petGUID] = "PET"
guidNameLookup[petGUID] = UnitName("pet")--.." ["..UnitName("player").."]"
end
if inParty or inRaid then
local playerFmt = inRaid and rID or pID
local petFmt = inRaid and rpID or ppID
local currentPartySize = inRaid and GetNumRaidMembers() or GetNumPartyMembers()
for i = 1, currentPartySize do
local unitID = playerFmt[i]
local pGUID = UnitGUID(unitID)
if pGUID then
guidNameLookup[pGUID] = UnitName(unitID)
_, guidClassLookup[pGUID] = UnitClass(unitID)
-- lookup pet (if existing)
local petID = petFmt[i]
local petGUID = UnitGUID(petID)
if petGUID then
guidNameLookup[petGUID] = UnitName(petID)--.." ["..UnitName(unitID).."]"
guidClassLookup[petGUID] = "PET"
end
end
end
end
guidNameLookup["AGGRO"] = L["> Pull Aggro <"]
guidClassLookup["AGGRO"] = "AGGRO"
end
function Omen:PLAYER_ENTERING_WORLD()
manualToggle = false
wipe(guidNameLookup)
self:PARTY_MEMBERS_CHANGED()
end
-----------------------------------------------------------------------------
-- Omen update functions
--[[
First, some definitions:
* mob - enemy creature
* threat list - a mob's list of possible targets, along with each possible target's current threat value
* threat situation - the situation that a unit is currently in (either globally, or with respect to a certain mob)
* scaled percentage - a threat percentage, where 100% means you will pull aggro (become the primary target of the mob), and thus this % cannot be higher than 100% under normal circumstances
* raw threat percentage - the percentage of the units threat when divided by the threat of the mob's current primary target, this % CAN be over 100%
---------
state = UnitThreatSituation(unit, mob)
Returns the unit's threat situation with respect to the given mob. The state can be one of the following values:
nil = the unit is not on the mob's threat list
0 = 0-99% raw threat percentage (no indicator shown)
1 = 100% or more raw threat percentage (yellow warning indicator shown)
2 = tanking, other has 100% or more raw threat percentage (orange indicator shown)
3 = tanking, all others have less than 100% raw percentage threat (red indicator shown)
---------
state = UnitThreatSituation(unit)
Returns the unit's maximum threat state on any mob's threat list.
---------
isTanking, state, scaledPercent, rawPercent, threatValue = UnitDetailedThreatSituation(unit, mob)
Returns detailed information about the unit's state on the mob's threat list.
isTanking is true if the unit the primary target of the mob (and by definition has 100% threat)
state is the unit's threat situation, as listed above.
scaledPercent is the current percent threat of the unit, scaled in the 0-100% range based on distance from target.
rawPercent is the current percent threat of the unit relative to the primary target of the mob.
threatValue is the amount of threat that the unit has on the mob's threat list. This is roughly approximate to the amount of damage and healing the unit has done.
---------
r, g, b = GetThreatStatusColor(state)
Returns the colors used in the UI to represent each major threat state.
]]
local threatTable -- Format: threatTable[guid] = threatValue
local sortTable = {} -- Format: threatTable[i] = guid -- used for sorting by sortfunction()
local tankGUID -- Used to store which unit is tanking and hence has 100% threat by definition
local topthreat -- Used to store the top threat value
local lastWarn = { -- Used to store information for threat warnings
threatpercent = 0,
}
local threatStore = {} -- Format: threatStore[i] = threatTable[guid] -- used for storing past threatTables
local threatStoreTime = {} -- Format: threatStoreTime[i] = GetTime()
local negativeTable = {} -- Format: negativeTable[guid] = true -- stores if someone is under the effects of Fade or Mirror Image
local function sortfunction(a, b)
return threatTable[a] > threatTable[b]
end
local function updatethreat(unitid, mobunitid)
local guid = UnitGUID(unitid)
if guid and not threatTable[guid] then
local isTanking, state, scaledPercent, rawPercent, threatValue = UnitDetailedThreatSituation(unitid, mobunitid)
-- CoA: the Vol'jin/CoA core does not push party-member threat to the
-- client, so the API call above returns nil for everyone but us. Fall
-- back to values broadcast by peers running OmenSync.
if not threatValue and Omen.SyncGetThreat then
local mobGUID = UnitGUID(mobunitid)
if mobGUID then
local syncVal, syncTanking = Omen:SyncGetThreat(guid, mobGUID)
if syncVal then
threatValue = syncVal
isTanking = syncTanking
end
end
end
if threatValue then
-- Threat can be negative due to temporary threat reduction effects such as Fade and Mirror Image (-410065408).
if threatValue < 0 then
threatValue = threatValue + 410065408
negativeTable[guid] = true
end
if threatValue > topthreat then topthreat = threatValue end
if isTanking then tankGUID = guid end
threatTable[guid] = threatValue
-- CoA: broadcast our own player/pet threat so peers' OmenSync can
-- fill the gap left by their nil UnitDetailedThreatSituation call.
if (unitid == "player" or unitid == "pet") and Omen.SyncBroadcastThreat then
local mobGUID = UnitGUID(mobunitid)
if mobGUID then
Omen:SyncBroadcastThreat(guid, mobGUID, threatValue, isTanking)
end
end
else
-- We use the special value -1 to indicate nil here.
threatTable[guid] = -1
end
end
end
local threatUnitIDFindList = {"target", "targettarget"}
local threatUnitIDFindList2 = {"focus", "focustarget", "target", "targettarget"}
function Omen:FindThreatMob()
-- Figure out which mob to show threat on.
-- It has to be attackable and not human controlled.
local t = db.UseFocus and threatUnitIDFindList2 or threatUnitIDFindList
local name, name2
for i = 1, #t do
local mob = t[i]
if UnitExists(mob) then
name2 = UnitName(mob)
guidNameLookup[UnitGUID(mob)] = name2
if not name then name = name2 end
if not UnitIsPlayer(mob) and UnitCanAttack("player", mob) and UnitHealth(mob) > 0 then
if not db.IgnorePlayerPets or not UnitPlayerControlled(mob) then
self.TitleText:SetText(name2)
self.unitID = mob
return mob
end
end
end
end
self.TitleText:SetText(name)
self.unitID = nil
end
-- Frame for throtling updates
local OmenUpdateBarsThrotleFrame = CreateFrame("Frame")
OmenUpdateBarsThrotleFrame:Hide()
OmenUpdateBarsThrotleFrame:SetScript("OnUpdate", function(self, elapsed)
self:Hide()
Omen:UpdateBarsReal()
end)
function Omen:UpdateBars()
OmenUpdateBarsThrotleFrame:Show()
end
local queried = false
function Omen:UpdateBarsReal()
if db.Autocollapse and db.CollapseHide then
-- Update the visibility because it could have been hidden on 0 bars
self.BarList.barsShown = 1 -- Dummy value
self:UpdateVisible()
end
if not self.Anchor:IsShown() then
self.BarList.barsShown = 0
return
end
local myGUID = UnitGUID("player")
local dbBar = db.Bar
local mob, mobGUID, mobTargetGUID
topthreat = -1
if testMode then
threatTable = newTable()
local key = next(showClassesOptionTable)
for i = 1, 25 do
if i == 22 and myGUID then -- Because I've got myGUID == nil before
threatTable[myGUID] = i*5000
else
threatTable[i] = i*5000
guidNameLookup[i] = showClassesOptionTable[key]
if key ~= "*NOTINPARTY*" then guidClassLookup[i] = key end
key = next(showClassesOptionTable, key) or next(showClassesOptionTable)
end
end
tankGUID = 25
topthreat = 25*5000
mob = ""
self.TitleText:SetText(L["Test Mode"])
else
mob = self:FindThreatMob()
if not mob then
self:ClearAll()
return
end
mobGUID = UnitGUID(mob)
-- Schedule a repeating timer for updating threat on "targettarget"
-- since we get no events on a targettarget change.
if mob == "targettarget" and not timers.UpdateBars then
timers.UpdateBars = self:ScheduleRepeatingTimer("UpdateBars", 0.5)
end
-- We want the mob's target just in case the tank isn't
-- in our raid (say an NPC or some other player)
local mobTarget = mob.."target"
local mobTargetGUID = UnitGUID(mobTarget)
if mobTargetGUID then
guidNameLookup[mobTargetGUID] = UnitName(mobTarget)
end
threatTable = newTable()
threatTable[mobGUID] = -1
tankGUID = nil
wipe(negativeTable)
-- Get data for threat on mob by scanning the whole raid
if inParty or inRaid then
if inRaid then
for i = 1, GetNumRaidMembers() do
updatethreat(rID[i], mob)
updatethreat(rpID[i], mob)
updatethreat(rtID[i], mob)
updatethreat(rptID[i], mob)
end
else
for i = 1, GetNumPartyMembers() do
updatethreat(pID[i], mob)
updatethreat(ppID[i], mob)
updatethreat(ptID[i], mob)
updatethreat(pptID[i], mob)
end
end
end
if not inRaid then
updatethreat("player", mob)
updatethreat("pet", mob)
updatethreat("target", mob)
updatethreat("pettarget", mob)
end
updatethreat("target", mob)
updatethreat("targettarget", mob)
updatethreat("focus", mob)
updatethreat("focustarget", mob)
updatethreat(mobTarget, mob)
updatethreat("mouseover", mob)
updatethreat("mouseovertarget", mob)
end
local tankThreat = tankGUID and threatTable[tankGUID] or mobTargetGUID and threatTable[mobTargetGUID] or topthreat
if dbBar.ShowAggroBar and tankThreat > 0 then
if GetItemInfo(37727) then -- 5 yards (Ruby Acorn - http://www.wowhead.com/?item=37727)
threatTable["AGGRO"] = tankThreat * (IsItemInRange(37727, mob) == 1 and 1.1 or 1.3)
else -- 9 yards compromise
threatTable["AGGRO"] = tankThreat * (CheckInteractDistance(mob, 3) and 1.1 or 1.3)
if not queried and not ItemRefTooltip:IsVisible() then
ItemRefTooltip:SetHyperlink("item:37727")
queried = true -- Only query once per session
end
end
end
-- Sort the threatTable
local i = 1
for k, v in pairs(threatTable) do
if v ~= -1 then
sortTable[i] = k
i = i + 1
end
end
for j = i, #sortTable do
sortTable[j] = nil
end
if #sortTable == 0 then
self:ClearAll()
self.TitleText:SetText(guidNameLookup[mobGUID])
return
end
sort(sortTable, sortfunction)
-- Now update the bars on screen
local inset = db.Background.BarInset * 2
local w = self.BarList:GetWidth() - inset
local h = self.BarList:GetHeight() - inset
topthreat = threatTable[sortTable[1]]
if topthreat == 0 then topthreat = 1 end -- To avoid 0/0 division
local showSelfYet = true
if dbBar.AlwaysShowSelf then
-- Check if we're one of the bars to be displayed
for j = 1, #sortTable do
if sortTable[j] == myGUID then
showSelfYet = false -- Yes, so flag it false
break
end
end
end
-- Check how many bars of space we have
local numBars = db.Autocollapse and db.NumBars or floor((h - dbBar.Height) / (dbBar.Height + dbBar.Spacing) + 1.01)
i = 1 -- Counts one higher than number of bars used
if dbBar.ShowHeadings then
if i <= numBars then
i = i + 1
bars[0].texture:SetWidth(w)
bars[0]:Show()
end
else
bars[0]:Hide()
end
for j = 1, #sortTable do
if i > numBars then break end
local guid = sortTable[j]
local class = guidClassLookup[guid]
local show = class == nil and dbBar.Classes["*NOTINPARTY*"] or class == "AGGRO" and dbBar.ShowAggroBar or dbBar.Classes[class]
if dbBar.AlwaysShowSelf and i == numBars and not showSelfYet and guid ~= myGUID then
show = false
end
if dbBar.AlwaysShowSelf and guid == myGUID then
show = true
showSelfYet = true
end
if show then
local bar = bars[dbBar.ShowHeadings and i-1 or i]
local threat = threatTable[guid]
-- Update the text on the bar
bar.Text1:SetText(guidNameLookup[guid])
if dbBar.ShowPercent and dbBar.ShowValue then
if dbBar.ShortNumbers and threat >= 100000 then
bar.Text2:SetFormattedText("%2.1fk [%d%%]", threat / 100000, tankThreat == 0 and 0 or threat / tankThreat * 100)
else
bar.Text2:SetFormattedText("%d [%d%%]", threat / 100, tankThreat == 0 and 0 or threat / tankThreat * 100)
end
elseif dbBar.ShowValue then
if dbBar.ShortNumbers and threat >= 100000 then
bar.Text2:SetFormattedText("%2.1fk", threat / 100000)
else
bar.Text2:SetFormattedText("%d", threat / 100)
end
else
bar.Text2:SetFormattedText("%d%%", tankThreat == 0 and 0 or threat / tankThreat * 100)
end
-- Update the color of the bar
local c = (negativeTable[guid] and dbBar.FadeBarColor) or
(guid == myGUID and dbBar.UseMyBarColor and dbBar.MyBarColor) or
(guid == tankGUID and dbBar.UseTankBarColor and dbBar.TankBarColor) or
(guid == "AGGRO" and dbBar.AggroBarColor) or
(dbBar.UseClassColors and (RAID_CLASS_COLORS[class] or (class == "PET" and dbBar.PetBarColor))) or
dbBar.BarColor
if dbBar.InvertColors then
bar.Text1:SetTextColor(c.r, c.g, c.b, c.a or 1)
bar.Text2:SetTextColor(c.r, c.g, c.b, c.a or 1)
bar.Text3:SetTextColor(c.r, c.g, c.b, c.a or 1)
else
bar.texture:SetVertexColor(c.r, c.g, c.b, c.a or 1)
end
-- Update the width of the bar, and animate if necessary
local width = w * threat / topthreat
if width <= 0 then width = 1 end
if dbBar.AnimateBars and self.Anchor.IsMovingOrSizing ~= 2 then
bar:AnimateTo(width)
else
bar.texture:SetWidth(width)
end
bar.guid = guid -- For TPS calcs
bar:Show()
i = i + 1
end
end
-- And hide the rest
for j = dbBar.ShowHeadings and i-1 or i, #bars do
bars[j]:Hide()
end
if db.Autocollapse then
self.Anchor:SetHeight((i-1)*dbBar.Height + (i-2)*dbBar.Spacing + self.Title:GetHeight() + inset)
end
self.BarList:Show()
self.BarList.barsShown = dbBar.ShowHeadings and i-2 or i-1
-- Threat warnings
if testMode then
threatTable = delTable(threatTable)
elseif myGUID then
local myClass = guidClassLookup[myGUID]
local myThreatPercent = threatTable[myGUID] / tankThreat * 100
local t = db.Warnings
if lastWarn.mobGUID == mobGUID and myThreatPercent >= t.Threshold and t.Threshold > lastWarn.threatpercent then
local shapeShiftForm = GetShapeshiftForm()
if not t.DisableWhileTanking or not (
myClass == "WARRIOR" and GetBonusBarOffset() == 2
or myClass == "DRUID" and GetBonusBarOffset() == 3
or myClass == "HERO" and GetBonusBarOffset() == 3
or UnitAura("player", GetSpellInfo(25780)) -- Righteous Fury
or UnitAura("player", GetSpellInfo(701463)) -- Mana-forged Barrier
or shapeShiftForm ~= 0 and (
GetShapeshiftFormInfo(shapeShiftForm) == "Interface\\Icons\\Ability_Warrior_DefensiveStance"
or GetShapeshiftFormInfo(shapeShiftForm) == "Interface\\Icons\\Spell_Deathknight_FrostPresence"
))
then
self:Warn(t.Sound, t.Flash, t.Shake, t.Message and L["Passed %s%% of %s's threat!"]:format(t.Threshold, guidNameLookup[lastWarn.tankGUID]))
end
end
-- Remove TPS data if the last scanned mob is different
if lastWarn.mobGUID ~= mobGUID then
delTable(threatStore)
threatStore = newTable()
wipe(threatStoreTime)
end
tinsert(threatStore, threatTable)
tinsert(threatStoreTime, GetTime())
-- Store last scanned mob GUID
local u = tankGUID or mobTargetGUID or (dbBar.ShowAggroBar and sortTable[2] or sortTable[1])
if u ~= "AGGRO" then
lastWarn.mobGUID = mobGUID
lastWarn.tankGUID = u
lastWarn.threatpercent = myThreatPercent
end
threatTable = nil
end
end
function Omen:ClearAll()
for i = 0, #bars do
bars[i]:Hide()
end
self.TitleText:SetText(self.defaultTitle)
if db.Autocollapse then
self.Anchor:SetHeight(self.Title:GetHeight())
self.BarList:Hide()
if db.CollapseHide and not self.Anchor.IsMovingOrSizing and not manualToggle then
self.Anchor:Hide()
end
end
self.BarList.barsShown = 0
-- Store last scanned mob GUID
lastWarn.mobGUID = nil
lastWarn.tankGUID = nil
lastWarn.threatpercent = 0
-- Remove TPS data
delTable(threatStore)
threatStore = newTable()
wipe(threatStoreTime)
threatTable = nil
end
function Omen:UpdateTPS()
local numBars = #bars
if testMode then
if db.Bar.ShowAggroBar then
bars[1].Text3:SetText("--")
for i = 2, numBars do
bars[i].Text3:SetText(1300 - 50*(i-1))
end
else
for i = 1, numBars do
bars[i].Text3:SetText(1300 - 50*i)
end
end
return
end
-- Remove data that is too old
local TPSWindow = db.Bar.TPSWindow
local startTime = GetTime() - TPSWindow
while threatStoreTime[2] and startTime > threatStoreTime[2] do
delTable(tremove(threatStore, 1))
tremove(threatStoreTime, 1)
end
-- Now check that we still have enough data
local dataSize = #threatStoreTime
if dataSize == 0 or startTime <= threatStoreTime[1] then
-- We do not have enough data, TPSWindow seconds has not passed
for i = 1, numBars do
bars[i].Text3:SetText("??")
end
return
end
-- Check for special case with just 1 data point past TPSWindow seconds
if dataSize == 1 then
-- Threat generated is 0
for i = 1, numBars do
bars[i].Text3:SetText("0")
end
return
end
-- We have at least 2 data points
for i = 1, numBars do
local bar = bars[i]
if not bar:IsShown() then return end
local guid = bar.guid
if guid == "AGGRO" then
bar.Text3:SetText("--")
else
local baseThreat = threatStore[1][guid]
local secondThreat = threatStore[2][guid]
local finalThreat = threatStore[dataSize][guid]
if baseThreat and secondThreat and finalThreat then
-- Calculate TPS
local ratio = (startTime - threatStoreTime[1]) / (threatStoreTime[2] - threatStoreTime[1])
local startThreat = (secondThreat - baseThreat) * ratio + baseThreat
bar.Text3:SetFormattedText("%d", (finalThreat - startThreat) / TPSWindow / 100)
else
-- We don't have enough data for this unit
bar.Text3:SetText("??")
end
end
end
end
-----------------------------------------------------------------------------
-- Title Right Click menu
do
-- Upvalue the functions in the menu
local function updateGrip()
db.Locked = not db.Locked
Omen:UpdateGrips()
LibStub("AceConfigRegistry-3.0"):NotifyChange("Omen")
end
local function toggleFocus() Omen:ToggleFocus() end
local function toggleTestMode()
testMode = not testMode
Omen:UpdateBars()
LibStub("AceConfigRegistry-3.0"):NotifyChange("Omen")
end
local function showConfig() Omen:ShowConfig() end
local function toggle() Omen:Toggle() end
function Omen.TitleQuickMenu(self, level)
if not level then return end
local info = self.info
wipe(info)
if level == 1 then
-- Create the title of the menu
info.isTitle = 1
info.text = L["Omen Quick Menu"]
info.notCheckable = 1
UIDropDownMenu_AddButton(info, level)
info.disabled = nil
info.isTitle = nil
info.notCheckable = nil
info.text = L["Lock Omen"]
info.func = updateGrip
info.checked = db.Locked
info.tooltipTitle = L["Lock Omen"]
info.tooltipText = L["Locks Omen in place and prevents it from being dragged or resized."]
UIDropDownMenu_AddButton(info, level)
info.text = L["Use Focus Target"]
info.func = toggleFocus
info.checked = db.UseFocus
info.tooltipTitle = L["Use Focus Target"]
info.tooltipText = L["Tells Omen to additionally check your 'focus' and 'focustarget' before your 'target' and 'targettarget' in that order for threat display."]
UIDropDownMenu_AddButton(info, level)
info.text = L["Test Mode"]
info.func = toggleTestMode
info.checked = testMode
info.tooltipTitle = L["Test Mode"]
info.tooltipText = L["Tells Omen to enter Test Mode so that you can configure Omen's display much more easily."]
UIDropDownMenu_AddButton(info, level)
info.text = L["Open Config"]
info.func = showConfig
info.checked = nil
info.tooltipTitle = L["Open Config"]
info.tooltipText = L["Open Omen's configuration panel"]
UIDropDownMenu_AddButton(info, level)
info.text = L["Hide Omen"]
info.func = toggle
info.tooltipTitle = L["Hide Omen"]
info.tooltipText = nil
UIDropDownMenu_AddButton(info, level)
-- Close menu item
info.text = CLOSE
info.func = self.HideMenu
info.checked = nil
info.arg1 = nil
info.notCheckable = 1
info.tooltipTitle = CLOSE
UIDropDownMenu_AddButton(info, level)
end
end
end
-----------------------------------------------------------------------------
-- Omen config stuff
function Omen:SetupOptions()
LibStub("AceConfigRegistry-3.0"):RegisterOptionsTable("Omen", self.GenerateOptions)
LibStub("AceConfig-3.0"):RegisterOptionsTable("OmenSlashCommand", self.OptionsSlash, "omen")
-- The ordering here matters, it determines the order in the Blizzard Interface Options
local ACD3 = LibStub("AceConfigDialog-3.0")
self.optionsFrames = {}
self.optionsFrames.Omen = ACD3:AddToBlizOptions("Omen", self.versionstring, nil, "General")
self.optionsFrames.ShowWhen = ACD3:AddToBlizOptions("Omen", L["Show When..."], self.versionstring, "ShowWhen")
self.optionsFrames.ShowClasses = ACD3:AddToBlizOptions("Omen", L["Show Classes..."], self.versionstring, "ShowClasses")
self.optionsFrames.TitleBar = ACD3:AddToBlizOptions("Omen", L["Title Bar Settings"], self.versionstring, "TitleBar")
self.optionsFrames.Bars = ACD3:AddToBlizOptions("Omen", L["Bar Settings"], self.versionstring, "Bars")
self.optionsFrames.Warnings = ACD3:AddToBlizOptions("Omen", L["Warning Settings"], self.versionstring, "Warnings")
self:RegisterModuleOptions("OmenSlashCommand", self.OptionsSlash, L["Slash Command"])
self:RegisterModuleOptions("Profiles", function() return LibStub("AceDBOptions-3.0"):GetOptionsTable(self.db) end, L["Profiles"])
self.optionsFrames.Help = ACD3:AddToBlizOptions("Omen", L["Help File"], self.versionstring, "Help")
self.SetupOptions = nil
end
function Omen:RegisterModuleOptions(name, optionTbl, displayName)
if moduleOptions then
moduleOptions[name] = optionTbl
else
self.Options.args[name] = (type(optionTbl) == "function") and optionTbl() or optionTbl
end
self.optionsFrames[name] = LibStub("AceConfigDialog-3.0"):AddToBlizOptions("Omen", displayName, self.versionstring, name)
end
function Omen:ShowConfig()
-- Open the profiles tab before, so the menu expands
InterfaceOptionsFrame_OpenToCategory(self.optionsFrames.Profiles)
InterfaceOptionsFrame_OpenToCategory(self.optionsFrames.Omen)
end
function Omen.GenerateOptions()
if Omen.noconfig then assert(false, Omen.noconfig) end
if not Omen.Options then
Omen.GenerateOptionsInternal()
Omen.GenerateOptionsInternal = nil
moduleOptions = nil
end
return Omen.Options
end
-----------------------------------------------------------------------------
-- Omen config tables
-- Option table for the slash command only
Omen.OptionsSlash = {
type = "group",
name = L["Slash Command"],
order = -3,
args = {
intro = {
order = 1,
type = "description",
name = L["OMEN_SLASH_DESC"],
cmdHidden = true,
},
toggle = {
type = "execute",
name = L["Toggle Omen"],
desc = L["Toggle Omen"].." ( /omen toggle )",
func = function() Omen:Toggle() end,
},
center = {
type = "execute",
name = L["Center Omen"],
desc = L["Center Omen"].." ( /omen center )",
func = function()
Omen.Anchor:ClearAllPoints()
Omen.Anchor:SetPoint("CENTER", UIParent, "CENTER")
Omen:SetAnchors()
end,
},
config = {
type = "execute",
name = L["Configure"],
desc = L["Open the configuration dialog"].." ( /omen config )",
func = function() Omen:ShowConfig() end,
guiHidden = true,
},
show = {
type = "execute",
name = L["Show Omen"],
desc = L["Show Omen"].." ( /omen show )",
func = function() Omen:Toggle(true) end,
},
hide = {
type = "execute",
name = L["Hide Omen"],
desc = L["Hide Omen"].." ( /omen hide )",
func = function() Omen:Toggle(false) end,
},
},
}
-- This is to provide better error reporting feedback, and stop loading the rest of the file.
if not AceGUIWidgetLSMlists then
Omen.noconfig = 'Cannot find a library instance of "AceGUI-3.0-SharedMediaWidgets". Omen configuration will not be available.'
assert(AceGUIWidgetLSMlists, Omen.noconfig)
end
function Omen.GenerateOptionsInternal()
local outlines = {
[""] = L["None"],
["OUTLINE"] = L["Outline"],
["THICKOUTLINE"] = L["Thick Outline"],
}
local function GetFuBarMinimapAttachedStatus(info)
return Omen:IsFuBarMinimapAttached() or db.FuBar.HideMinimapButton
end
-- Option table for the AceGUI config only
Omen.Options = {
type = "group",
name = "Omen",
get = function(info) return db[ info[#info] ] end,
set = function(info, value) db[ info[#info] ] = value end,
args = {
General = {
order = 1,
type = "group",
name = L["General Settings"],
desc = L["General Settings"],
args = {
intro = {
order = 1,
type = "description",
name = L["OMEN_DESC"],
},
Alpha = {
order = 3,
name = L["Alpha"],
desc = L["Controls the transparency of the main Omen window."],
type = "range",
min = 0, max = 1, step = 0.01,
isPercent = true,
set = function(info, value)
db.Alpha = value
Omen.Anchor:SetAlpha(value)
end,
},
Scale = {
order = 4,
name = L["Scale"],
desc = L["Controls the scaling of the main Omen window."],
type = "range",
min = 0.50, max = 1.50, step = 0.01,
isPercent = true,
set = function(info, value)
db.Scale = value
Omen:SetAnchors()
end,
},
FrameStrata = {
type = "select",
order = 5,
name = L["Frame Strata"],
desc = L["Controls the frame strata of the main Omen window. Default: MEDIUM"],
values = { -- A hack to sort them in the menu
["1-BACKGROUND"] = "BACKGROUND",
["2-LOW"] = "LOW",
["3-MEDIUM"] = "MEDIUM",
["4-HIGH"] = "HIGH",
["5-DIALOG"] = "DIALOG",
["6-FULLSCREEN"] = "FULLSCREEN",
["7-FULLSCREEN_DIALOG"] = "FULLSCREEN_DIALOG",
["8-TOOLTIP"] = "TOOLTIP",
},
set = function(info, value)
db.FrameStrata = value
Omen.Anchor:SetFrameStrata(strsub(value, 3))
end,
},
ClampToScreen = {
type = "toggle",
name = L["Clamp To Screen"],
desc = L["Controls whether the main Omen window can be dragged offscreen"],
order = 6,
set = function(info, value)
db.ClampToScreen = value
Omen.Anchor:SetClampedToScreen(value)
end,
},
Locked = {
type = "toggle",
name = L["Lock Omen"],
desc = L["Locks Omen in place and prevents it from being dragged or resized."],
order = 7,
set = function(info, value)
db.Locked = value
Omen:UpdateGrips()
end,
},
UseFocus = {
type = "toggle",
name = L["Use Focus Target"],
desc = L["Tells Omen to additionally check your 'focus' and 'focustarget' before your 'target' and 'targettarget' in that order for threat display."],
order = 8,
set = function(info, value)
Omen:ToggleFocus()
end,
},
TestMode = {
type = "toggle",
name = L["Test Mode"],
desc = L["Tells Omen to enter Test Mode so that you can configure Omen's display much more easily."],
order = 9,
get = function(info) return testMode end,
set = function(info, value)
testMode = value
Omen:UpdateBars()
end,
},
MinimapIcon = {
type = "toggle",
name = L["Show minimap button"],
desc = L["Show the Omen minimap button"],
order = 10,
get = function(info) return not db.MinimapIcon.hide end,
set = function(info, value)
db.MinimapIcon.hide = not value
if value then LDBIcon:Show("Omen") else LDBIcon:Hide("Omen") end
end,
hidden = function() return not LDBIcon or IsAddOnLoaded("Broker2FuBar") or IsAddOnLoaded("FuBar") end,
},
IgnorePlayerPets = {
type = "toggle",
name = L["Ignore Player Pets"],
desc = L["IGNORE_PLAYER_PETS_DESC"],
order = 11,
set = function(info, value)
db.IgnorePlayerPets = value
Omen:UpdateBars()
end,
},
ClickThrough = {
type = "toggle",
name = L["Click Through"],
desc = L["Makes the Omen window non-interactive"],
order = 12,
set = function(info, value)
db.ClickThrough = value
Omen:UpdateClickThrough()
end,
},
AutocollapseGroup = {
type = "group",
name = L["Autocollapse Options"],
guiInline = true,
order = 21,
disabled = function() return not db.Autocollapse end,
set = function(info, value)
db[ info[#info] ] = value
Omen:UpdateVisible()
Omen:UpdateBars()
end,
args = {
Autocollapse = {
type = "toggle",
name = L["Autocollapse"],
desc = L["Collapse to show a minimum number of bars"],
order = 1,
set = function(info, value)
db.Autocollapse = value
Omen.Anchor:SetHeight(6*db.Bar.Height + 5*db.Bar.Spacing + Omen.Title:GetHeight() + 2*db.Background.BarInset)
Omen:SetAnchors()
Omen.BarList:Show()
Omen:UpdateVisible()
Omen:UpdateBars()
end,
disabled = false,
},
GrowUp = {
order = 2,
type = "toggle",
name = L["Grow bars upwards"],
desc = L["Grow bars upwards"],
set = function(info, value)
db.GrowUp = value
Omen:SetAnchors()
end,
},
CollapseHide = {
order = 3,
type = "toggle",
name = L["Hide Omen on 0 bars"],
desc = L["Hide Omen entirely if it collapses to show 0 bars"],
set = function(info, value)
db.CollapseHide = value
if value then manualToggle = false end
Omen:UpdateVisible()
Omen:UpdateBars()
end,
},
NumBars = {
order = 4,
name = L["Max bars to show"],
desc = L["Max number of bars to show"],
type = "range",
min = 1, max = 40, step = 1,
},
},
},
Background = {
type = "group",
name = L["Background Options"],
guiInline = true,
order = 31,
get = function(info) return db.Background[ info[#info] ] end,
set = function(info, value)
db.Background[ info[#info] ] = value
Omen:UpdateBackdrop()
end,
args = {
Texture = {
type = "select", dialogControl = 'LSM30_Background',
order = 1,
name = L["Background Texture"],
desc = L["Texture to use for the frame's background"],
values = AceGUIWidgetLSMlists.background,
},
BorderTexture = {
type = "select", dialogControl = 'LSM30_Border',
order = 2,
name = L["Border Texture"],
desc = L["Texture to use for the frame's border"],
values = AceGUIWidgetLSMlists.border,
},
Color = {
type = "color",
order = 3,
name = L["Background Color"],
desc = L["Frame's background color"],
hasAlpha = true,
get = function(info)
local t = db.Background.Color
return t.r, t.g, t.b, t.a
end,
set = function(info, r, g, b, a)
local t = db.Background.Color
t.r, t.g, t.b, t.a = r, g, b, a
Omen:UpdateBackdrop()
end,
},
BorderColor = {
type = "color",
order = 4,
name = L["Border Color"],
desc = L["Frame's border color"],
hasAlpha = true,
get = function(info)
local t = db.Background.BorderColor
return t.r, t.g, t.b, t.a
end,
set = function(info, r, g, b, a)
local t = db.Background.BorderColor
t.r, t.g, t.b, t.a = r, g, b, a
Omen:UpdateBackdrop()
end,
},
Tile = {
type = "toggle",
order = 5,
name = L["Tile Background"],
desc = L["Tile the background texture"],
},
TileSize = {
type = "range",
order = 6,
name = L["Background Tile Size"],
desc = L["The size used to tile the background texture"],
min = 16, max = 256, step = 1,
disabled = function() return not db.Background.Tile end,
},
EdgeSize = {
type = "range",
order = 7,
name = L["Border Thickness"],
desc = L["The thickness of the border"],
min = 1, max = 16, step = 1,
},
BarInset = {
type = "range",
order = 8,
name = L["Bar Inset"],
desc = L["Sets how far inside the frame the threat bars will display from the 4 borders of the frame"],
min = 1, max = 16, step = 1,
},
},
},
},
},
ShowWhen = {
order = 2,
type = "group",
name = L["Show When..."],
desc = L["Show Omen when..."],
get = function(info) return db.ShowWith[ info[#info] ] end,
set = function(info, value)
db.ShowWith[ info[#info] ] = value
manualToggle = false
Omen:UpdateVisible()
Omen:UpdateBars()
end,
args = {
intro = {
order = 1,
type = "description",
name = L["This section controls when Omen is automatically shown or hidden."],
disabled = false,
},
UseShowWith = {
type = "toggle",
order = 2,
name = L["Use Auto Show/Hide"],
desc = L["Use Auto Show/Hide"],
disabled = false,
},
ShowWithGroup = {
type = "group",
order = 3,
guiInline = true,
name = L["Use Auto Show/Hide"],
desc = L["Use Auto Show/Hide"],
disabled = function(info) return not db.ShowWith.UseShowWith end,
args = {
intro2 = {
order = 10,
type = "description",
name = L["Show Omen when any of the following are true"],
},
Alone = {
type = "toggle",
order = 11,
name = L["You are alone"],
desc = L["Show Omen when you are alone"],
},
Party = {
type = "toggle",
order = 12,
name = L["You are in a party"],
desc = L["Show Omen when you are in a 5-man party"],
},
Raid = {
type = "toggle",
order = 13,
name = L["You are in a raid"],
desc = L["Show Omen when you are in a raid"],
},
Pet = {
type = "toggle",
order = 14,
name = L["You have a pet"],
desc = L["Show Omen when you have a pet out"],
},
intro3 = {
order = 20,
type = "description",
name = L["However, hide Omen if any of the following are true (higher priority than the above)."],
},
HideInPVP = {
type = "toggle",
order = 21,
width = "double",
name = L["You are in a battleground"],
desc = L["Turning this on will cause Omen to hide whenever you are in a battleground or arena."],
},
HideWhileResting = {
type = "toggle",
order = 22,
width = "double",
name = L["You are resting"],
desc = L["Turning this on will cause Omen to hide whenever you are in a city or inn."],
},
HideWhenOOC = {
type = "toggle",
order = 23,
width = "double",
name = L["You are not in combat"],
desc = L["Turning this on will cause Omen to hide whenever you are not in combat."],
set = function(info, value)
db.ShowWith.HideWhenOOC = value
manualToggle = false
if value then
Omen:RegisterEvent("PLAYER_REGEN_DISABLED", "UpdateVisible")
Omen:RegisterEvent("PLAYER_REGEN_ENABLED", "UpdateVisible")
else
Omen:UnregisterEvent("PLAYER_REGEN_DISABLED")
Omen:UnregisterEvent("PLAYER_REGEN_ENABLED")
end
Omen:UpdateVisible()
Omen:UpdateBars()
end,
},
intro4 = {
order = 30,
type = "description",
name = L["AUTO_SHOW/HIDE_NOTE"],
},
},
},
},
},
ShowClasses = {
order = 3,
type = "group",
name = L["Show Classes..."],
desc = L["Show Classes..."],
args = {
intro = {
order = 1,
type = "description",
name = L["SHOW_CLASSES_DESC"],
},
Classes = {
type = "multiselect",
order = 30,
name = L["Show bars for these classes"],
values = showClassesOptionTable,
get = function(info, k) return db.Bar.Classes[k] end,
set = function(info, k, v)
db.Bar.Classes[k] = v
Omen:UpdateBars()
end,
},
},
},
TitleBar = {
order = 4,
type = "group",
name = L["Title Bar Settings"],
desc = L["Title Bar Settings"],
get = function(info) return db.TitleBar[ info[#info] ] end,
set = function(info, value)
db.TitleBar[ info[#info] ] = value
Omen:UpdateTitleBar()
Omen:UpdateBars()
end,
args = {
intro = {
order = 1,
type = "description",
name = L["Configure title bar settings."],
},
ShowTitleBar = {
type = "toggle",
order = 2,
name = L["Show Title Bar"],
desc = L["Show the Omen Title Bar"],
},
Height = {
type = "range",
order = 5,
name = L["Title Bar Height"],
desc = L["Height of the title bar. The minimum height allowed is twice the background border thickness."],
min = 2, max = 32, step = 1,
disabled = function() return not db.TitleBar.ShowTitleBar end,
},
TitleText = {
type = "group",
name = L["Title Text Options"],
guiInline = true,
order = 20,
set = function(info, value)
db.TitleBar[ info[#info] ] = value
Omen:UpdateTitleBar()
end,
disabled = function() return not db.TitleBar.ShowTitleBar end,
args = {
Font = {
type = "select", dialogControl = 'LSM30_Font',
order = 1,
name = L["Font"],
desc = L["The font that the title text will use"],
values = AceGUIWidgetLSMlists.font,
},
FontOutline = {
type = "select",
order = 2,
name = L["Font Outline"],
desc = L["The outline that the title text will use"],
values = outlines,
},
FontColor = {
type = "color",
order = 3,
name = L["Font Color"],
desc = L["The color of the title text"],
hasAlpha = true,
get = function(info)
local t = db.TitleBar.FontColor
return t.r, t.g, t.b, t.a
end,
set = function(info, r, g, b, a)
local t = db.TitleBar.FontColor
t.r, t.g, t.b, t.a = r, g, b, a
Omen:UpdateTitleBar()
end,
},
FontSize = {
type = "range",
order = 4,
name = L["Font Size"],
desc = L["Control the font size of the title text"],
min = 4, max = 30, step = 1,
},
},
},
UseSameBG = {
type = "toggle",
order = 30,
width = "double",
name = L["Use Same Background"],
desc = L["Use the same background settings for the title bar as the main window's background"],
set = function(info, value)
db.TitleBar.UseSameBG = value
Omen:UpdateBackdrop()
end,
disabled = function() return not db.TitleBar.ShowTitleBar end,
},
Background = {
type = "group",
name = L["Title Bar Background Options"],
guiInline = true,
order = 31,
get = function(info) return db.TitleBar[ info[#info] ] end,
set = function(info, value)
db.TitleBar[ info[#info] ] = value
Omen:UpdateBackdrop()
end,
disabled = function() return not db.TitleBar.ShowTitleBar or db.TitleBar.UseSameBG end,
args = {
Texture = {
type = "select", dialogControl = 'LSM30_Background',
order = 1,
name = L["Background Texture"],
desc = L["Texture to use for the frame's background"],
values = AceGUIWidgetLSMlists.background,
},
BorderTexture = {
type = "select", dialogControl = 'LSM30_Border',
order = 2,
name = L["Border Texture"],
desc = L["Texture to use for the frame's border"],
values = AceGUIWidgetLSMlists.border,
},
Color = {
type = "color",
order = 3,
name = L["Background Color"],
desc = L["Frame's background color"],
hasAlpha = true,
get = function(info)
local t = db.TitleBar.Color
return t.r, t.g, t.b, t.a
end,
set = function(info, r, g, b, a)
local t = db.TitleBar.Color
t.r, t.g, t.b, t.a = r, g, b, a
Omen:UpdateBackdrop()
end,
},
BorderColor = {
type = "color",
order = 4,
name = L["Border Color"],
desc = L["Frame's border color"],
hasAlpha = true,
get = function(info)
local t = db.TitleBar.BorderColor
return t.r, t.g, t.b, t.a
end,
set = function(info, r, g, b, a)
local t = db.TitleBar.BorderColor
t.r, t.g, t.b, t.a = r, g, b, a
Omen:UpdateBackdrop()
end,
},
Tile = {
type = "toggle",
order = 5,
name = L["Tile Background"],
desc = L["Tile the background texture"],
},
TileSize = {
type = "range",
order = 6,
name = L["Background Tile Size"],
desc = L["The size used to tile the background texture"],
min = 16, max = 256, step = 1,
disabled = function() return not db.TitleBar.ShowTitleBar or db.TitleBar.UseSameBG or not db.TitleBar.Tile end,
},
EdgeSize = {
type = "range",
order = 7,
name = L["Border Thickness"],
desc = L["The thickness of the border"],
min = 1, max = 16, step = 1,
},
},
},
},
},
Bars = {
order = 5,
type = "group",
name = L["Bar Settings"],
desc = L["Bar Settings"],
get = function(info) return db.Bar[ info[#info] ] end,
set = function(info, value)
db.Bar[ info[#info] ] = value
Omen:UpdateBars()
end,
args = {
intro = {
order = 1,
type = "description",
name = L["Configure bar settings."],
},
AnimateBars = {
type = "toggle",
order = 2,
name = L["Animate Bars"],
desc = L["Smoothly animate bar changes"],
},
ShortNumbers = {
type = "toggle",
order = 3,
name = L["Short Numbers"],
desc = L["Display large numbers in Ks"],
disabled = function() return not db.Bar.ShowValue end
},
Height = {
type = "range",
order = 4,
name = L["Bar Height"],
desc = L["Height of each bar"],
min = 5, max = 50, step = 1, bigStep = 1,
set = function(info, value)
db.Bar.Height = value
Omen:ReAnchorBars()
Omen:ResizeBars()
Omen:UpdateBars()
end,
},
Spacing = {
type = "range",
order = 5,
name = L["Bar Spacing"],
desc = L["Spacing between each bar"],
min = 0, max = 20, step = 1, bigStep = 1,
set = function(info, value)
db.Bar.Spacing = value
Omen:ReAnchorBars()
Omen:UpdateBars()
end,
},
ShowTPS = {
type = "toggle",
order = 6,
name = L["Show TPS"],
desc = L["Show threat per second values"],
set = function(info, value)
db.Bar.ShowTPS = value
if db.VGrip1 > db.VGrip2 then
db.VGrip1, db.VGrip2 = db.VGrip2, db.VGrip1
end
movegrip1()
movegrip2()
Omen:UpdateGrips()
local f = Omen.TPSUpdateFrame
if f then
if value then f:Show() else f:Hide() end
end
end,
},
TPSWindow = {
type = "range",
order = 7,
name = L["TPS Window"],
desc = L["TPS_WINDOW_DESC"],
min = 3, max = 15, step = 0.1,
disabled = function() return not db.Bar.ShowTPS end,
},
ShowValue = {
type = "toggle",
order = 8,
name = L["Show Threat Values"],
desc = L["Show Threat Values"],
set = function(info, value)
db.Bar.ShowValue = value
if not value then
db.Bar.ShowPercent = true
bars[0].Text2:SetText(L["Threat"])
elseif db.Bar.ShowPercent then
bars[0].Text2:SetText(L["Threat [%]"])
end
Omen:UpdateBars()
end,
},
ShowPercent = {
type = "toggle",
order = 9,
name = L["Show Threat %"],
desc = L["Show Threat %"],
set = function(info, value)
db.Bar.ShowPercent = value
if not value then
db.Bar.ShowValue = true
bars[0].Text2:SetText(L["Threat"])
elseif db.Bar.ShowValue then
bars[0].Text2:SetText(L["Threat [%]"])
end
Omen:UpdateBars()
end,
},
ShowHeadings = {
type = "toggle",
order = 11,
name = L["Show Headings"],
desc = L["Show column headings"],
set = function(info, value)
db.Bar.ShowHeadings = value
Omen:ReAnchorBars()
Omen:UpdateBars()
end,
},
HeadingBGColor = {
type = "color",
order = 12,
name = L["Heading BG Color"],
desc = L["Heading background color"],
hasAlpha = true,
get = function(info)
local t = db.Bar.HeadingBGColor
return t.r, t.g, t.b, t.a
end,
set = function(info, r, g, b, a)
local t = db.Bar.HeadingBGColor
t.r, t.g, t.b, t.a = r, g, b, a
Omen:UpdateBarLabelSettings()
Omen:UpdateBars()
end,
disabled = function() return not db.Bar.ShowHeadings end,
},
UseMyBarColor = {
type = "toggle",
order = 13,
name = L["Use 'My Bar' color"],
desc = L["Use a different colored background for your threat bar in Omen"],
},
MyBarColor = {
type = "color",
order = 14,
name = L["'My Bar' BG Color"],
desc = L["The background color for your threat bar"],
hasAlpha = true,
get = function(info)
local t = db.Bar.MyBarColor
return t.r, t.g, t.b, t.a
end,
set = function(info, r, g, b, a)
local t = db.Bar.MyBarColor
t.r, t.g, t.b, t.a = r, g, b, a
Omen:UpdateBars()
end,
disabled = function() return not db.Bar.UseMyBarColor end,
},
UseTankBarColor = {
type = "toggle",
order = 15,
name = L["Use Tank Bar color"],
desc = L["Use a different colored background for the tank's threat bar in Omen"],
},
TankBarColor = {
type = "color",
order = 16,
name = L["Tank Bar Color"],
desc = L["The background color for your tank's threat bar"],
hasAlpha = true,
get = function(info)
local t = db.Bar.TankBarColor
return t.r, t.g, t.b, t.a
end,
set = function(info, r, g, b, a)
local t = db.Bar.TankBarColor
t.r, t.g, t.b, t.a = r, g, b, a
Omen:UpdateBars()
end,
disabled = function() return not db.Bar.UseTankBarColor end,
},
ShowAggroBar = {
type = "toggle",
order = 17,
name = L["Show Pull Aggro Bar"],
desc = L["Show a bar for the amount of threat you will need to reach in order to pull aggro."],
},
AggroBarColor = {
type = "color",
order = 18,
name = L["Pull Aggro Bar Color"],
desc = L["The background color for your Pull Aggro bar"],
hasAlpha = true,
get = function(info)
local t = db.Bar.AggroBarColor
return t.r, t.g, t.b, t.a
end,
set = function(info, r, g, b, a)
local t = db.Bar.AggroBarColor
t.r, t.g, t.b, t.a = r, g, b, a
Omen:UpdateBars()
end,
disabled = function() return not db.Bar.ShowAggroBar end,
},
UseClassColors = {
type = "toggle",
order = 21,
name = L["Use Class Colors"],
desc = L["Use standard class colors for the background color of threat bars"],
},
PetBarColor = {
type = "color",
order = 22,
name = L["Pet Bar Color"],
desc = L["The background color for pets"],
hasAlpha = true,
get = function(info)
local t = db.Bar.PetBarColor
return t.r, t.g, t.b, t.a
end,
set = function(info, r, g, b, a)
local t = db.Bar.PetBarColor
t.r, t.g, t.b, t.a = r, g, b, a
Omen:UpdateBars()
end,
disabled = function() return not db.Bar.UseClassColors end,
},
UseCustomClassColors = {
type = "toggle",
order = 23,
name = L["Use !ClassColors"],
desc = L["Use !ClassColors addon for class colors for the background color of threat bars"],
set = function(info, v)
db.Bar.UseCustomClassColors = v
Omen:UpdateRaidClassColors()
end,
disabled = function() return not db.Bar.UseClassColors or not CUSTOM_CLASS_COLORS end,
},
FadeBarColor = {
type = "color",
order = 24,
name = L["Fade/MI Bar Color"],
desc = L["The background color for players under the effects of Fade and Mirror Image (they will be at negative 4 million threat)"],
hasAlpha = true,
get = function(info)
local t = db.Bar.FadeBarColor
return t.r, t.g, t.b, t.a
end,
set = function(info, r, g, b, a)
local t = db.Bar.FadeBarColor
t.r, t.g, t.b, t.a = r, g, b, a
Omen:UpdateBars()
end,
},
BarColor = {
type = "color",
order = 25,
name = L["Bar BG Color"],
desc = L["The background color for all threat bars"],
hasAlpha = true,
get = function(info)
local t = db.Bar.BarColor
return t.r, t.g, t.b, t.a
end,
set = function(info, r, g, b, a)
local t = db.Bar.BarColor
t.r, t.g, t.b, t.a = r, g, b, a
Omen:UpdateBars()
end,
disabled = function() return db.Bar.UseClassColors end,
},
AlwaysShowSelf = {
type = "toggle",
order = 26,
name = L["Always Show Self"],
desc = L["Always show your threat bar on Omen (ignores class filter settings), showing your bar on the last row if necessary"],
},
InvertColors = {
type = "toggle",
order = 27,
name = L["Invert Bar/Text Colors"],
desc = L["Switch the colors so that the bar background colors and the text colors are swapped."],
set = function(info, v)
db.Bar.InvertColors = v
Omen:UpdateBarLabelSettings()
Omen:UpdateBars()
end,
},
Texture = {
type = "select", dialogControl = 'LSM30_Statusbar',
order = 29,
name = L["Bar Texture"],
desc = L["The texture that the bar will use"],
values = AceGUIWidgetLSMlists.statusbar,
set = function(info, v)
db.Bar.Texture = v
Omen:UpdateBarTextureSettings()
end,
},
BarLabelsGroup = {
type = "group",
name = L["Bar Label Options"],
guiInline = true,
order = 30,
set = function(info, v)
db.Bar[ info[#info] ] = v
Omen:UpdateBarLabelSettings()
Omen:UpdateBars()
end,
args = {
Font = {
type = "select", dialogControl = 'LSM30_Font',
order = 1,
name = L["Font"],
desc = L["The font that the labels will use"],
values = AceGUIWidgetLSMlists.font,
},
FontOutline = {
type = "select",
order = 2,
name = L["Font Outline"],
desc = L["The outline that the labels will use"],
values = outlines,
},
FontColor = {
type = "color",
order = 3,
name = L["Font Color"],
desc = L["The color of the labels"],
hasAlpha = true,
get = function(info)
local t = db.Bar.FontColor
return t.r, t.g, t.b, t.a
end,
set = function(info, r, g, b, a)
local t = db.Bar.FontColor
t.r, t.g, t.b, t.a = r, g, b, a
Omen:UpdateBarLabelSettings()
Omen:UpdateBars()
end,
},
FontSize = {
type = "range",
order = 4,
name = L["Font Size"],
desc = L["Control the font size of the labels"],
min = 4, max = 30, step = 1,
},
},
},
},
},
Warnings = {
order = 6,
type = "group",
name = L["Warning Settings"],
desc = L["Warning Settings"],
get = function(info) return db.Warnings[ info[#info] ] end,
set = function(info, value)
db.Warnings[ info[#info] ] = value
end,
args = {
intro = {
order = 1,
type = "description",
name = L["OMEN_WARNINGS_DESC"],
},
Sound = {
type = "toggle",
order = 2,
name = L["Enable Sound"],
desc = L["Causes Omen to play a chosen sound effect"],
},
Flash = {
type = "toggle",
order = 3,
name = L["Enable Screen Flash"],
desc = L["Causes the entire screen to flash red momentarily"],
},
Shake = {
type = "toggle",
order = 4,
name = L["Enable Screen Shake"],
desc = L["Causes the entire game world to shake momentarily. This option only works if nameplates are turned off."],
},
Message = {
type = "toggle",
order = 5,
name = L["Enable Warning Message"],
desc = L["Print a message to screen when you accumulate too much threat"],
},
Output = Omen:GetSinkAce3OptionsDataTable(),
Threshold = {
type = "range",
order = 7,
name = L["Warning Threshold %"],
desc = L["Warning Threshold %"],
min = 60, max = 130, step = 1,
},
SoundFile = {
type = "select", dialogControl = 'LSM30_Sound',
order = 8,
name = L["Sound to play"],
desc = L["Sound to play"],
values = AceGUIWidgetLSMlists.sound,
disabled = function() return not db.Warnings.Sound end,
},
DisableWhileTanking = {
type = "toggle",
order = 9,
name = L["Disable while tanking"],
desc = L["DISABLE_WHILE_TANKING_DESC"],
},
test = {
type = "execute",
order = -1,
name = L["Test warnings"],
desc = L["Test warnings"],
func = function()
local t = db.Warnings
Omen:Warn(t.Sound, t.Flash, t.Shake, t.Message and L["Test warnings"])
end,
},
},
},
FuBar = {
order = -4,
type = "group",
name = L["FuBar Options"],
desc = L["FuBar Options"],
hidden = function() return Omen.IsFuBarMinimapAttached == nil end,
args = {
hideIcon = {
type = "toggle",
order = 1,
name = L["Hide minimap/FuBar icon"],
desc = L["Hide minimap/FuBar icon"],
get = function(info) return db.FuBar.HideMinimapButton end,
set = function(info, v)
db.FuBar.HideMinimapButton = v
Omen:UpdateFuBarSettings()
end,
},
attachMinimap = {
type = "toggle",
order = 2,
name = L["Attach to minimap"],
desc = L["Attach to minimap"],
get = function(info) return Omen:IsFuBarMinimapAttached() end,
set = function(info, v)
Omen:ToggleFuBarMinimapAttached()
db.FuBar.AttachMinimap = Omen:IsFuBarMinimapAttached()
end,
disabled = function() return db.FuBar.HideMinimapButton end,
},
showIcon = {
type = "toggle",
order = 3,
name = L["Show icon"],
desc = L["Show icon"],
get = function(info) return Omen:IsFuBarIconShown() end,
set = function(info, v) Omen:ToggleFuBarIconShown() end,
disabled = GetFuBarMinimapAttachedStatus,
},
showText = {
type = "toggle",
order = 4,
name = L["Show text"],
desc = L["Show text"],
get = function(info) return Omen:IsFuBarTextShown() end,
set = function(info, v) Omen:ToggleFuBarTextShown() end,
disabled = GetFuBarMinimapAttachedStatus,
},
position = {
type = "select",
order = 5,
name = L["Position"],
desc = L["Position"],
values = {LEFT = L["Left"], CENTER = L["Center"], RIGHT = L["Right"]},
get = function() return Omen:GetPanel() and Omen:GetPanel():GetPluginSide(Omen) end,
set = function(info, val)
if Omen:GetPanel() and Omen:GetPanel().SetPluginSide then
Omen:GetPanel():SetPluginSide(Omen, val)
end
end,
disabled = GetFuBarMinimapAttachedStatus,
}
}
},
Help = {
type = "group",
order = -1,
name = L["Help File"],
desc = L["A collection of help pages"],
childGroups = "select",
args = {
FAQ1 = {
type = "group",
order = 1,
name = L["FAQ Part 1"],
args = {
header = {
type = "header",
name = L["Frequently Asked Questions"],
order = 0,
},
text = {
order = 1,
type = "description",
name = L["GENERAL_FAQ"],
},
},
},
FAQ2 = {
type = "group",
order = 2,
name = L["FAQ Part 2"],
args = {
header = {
type = "header",
name = L["Frequently Asked Questions"],
order = 0,
},
text = {
order = 1,
type = "description",
name = L["GENERAL_FAQ2"],
},
},
},
WARRIOR = {
type = "group",
name = L["Warrior"],
args = {
header = {
type = "header",
name = L["Warrior"],
order = 0,
},
text = {
order = 1,
type = "description",
name = L["WARRIOR_FAQ"],
},
},
},
},
},
},
}
Omen.Options.args.Warnings.args.Output.order = 6
Omen.Options.args.Warnings.args.Output.inline = true
Omen.Options.args.Warnings.args.Output.disabled = function() return not db.Warnings.Message end
for k, v in pairs(moduleOptions) do
Omen.Options.args[k] = (type(v) == "function") and v() or v
end
-- Add ordering data to the option table generated by AceDBOptions-3.0
Omen.Options.args.Profiles.order = -2
local h = db.Background.EdgeSize * 2
if not db.TitleBar.UseSameBG then h = db.TitleBar.EdgeSize * 2 end
Omen.Options.args.TitleBar.args.Height.min = h
end