diff --git a/.pkgmeta b/.pkgmeta index c3b4190..9f52a48 100644 --- a/.pkgmeta +++ b/.pkgmeta @@ -14,3 +14,4 @@ externals: Libs/AceTimer-3.0: svn://svn.wowace.com/wow/ace3/mainline/trunk/AceTimer-3.0 Libs/LibSharedMedia-3.0: svn://svn.wowace.com/wow/libsharedmedia-3-0/mainline/trunk/LibSharedMedia-3.0 Libs/AceGUI-3.0-SharedMediaWidgets: svn://svn.wowace.com/wow/ace-gui-3-0-shared-media-widgets/mainline/trunk/AceGUI-3.0-SharedMediaWidgets + Libs/LibSink-2.0: svn://svn.wowace.com/wow/libsink-2-0/mainline/trunk/LibSink-2.0 diff --git a/Localization/enUS.lua b/Localization/enUS.lua index 06aad5a..3adb115 100644 --- a/Localization/enUS.lua +++ b/Localization/enUS.lua @@ -4,6 +4,10 @@ if not L then return end -- Main Omen window L[""] = true +L["Test Mode"] = true + +-- Warnings +L["|cffff0000Error:|r Omen cannot use shake warning if you have turned on nameplates at least once since logging in."] = true -- Config module titles L["General Settings"] = true @@ -120,7 +124,18 @@ L["Center Omen"] = true L["Configure"] = true L["Open the configuration dialog"] = true --- For Fubar +-- Config strings, warning settings section +L["Warning Settings"] = true +L["OMEN_WARNINGS_DESC"] = "This section allows you to customize when and how Omen notifies you if you are about to pull aggro." +L["Enable Warning Message"] = true +L["Print a message to screen when you accumulate too much threat"] = true +L["Warning Threshold %"] = true +L["Sound to play"] = true +L["Disable while tanking"] = true +L["DISABLE_WHILE_TANKING_DESC"] = "Do not give out any warnings if Defensive Stance, Bear Form, Righteous Fury or Frost Presence is active." +L["Test warnings"] = true + +-- Config strings, for Fubar L["Click|r to toggle the Omen window"] = true L["Right-click|r to open the options menu"] = true L["FuBar Options"] = true @@ -211,9 +226,3 @@ Vigilance ____________ 10% of target's generated threat (stance modifier is not You do not gain threat for refecting spells targetted at allies with Improved Spell Reflect. When you reflect a spell for an ally, your ally gains the threat for the damage dealt by the reflected spell. ]] --- Slash command - -BINDING_HEADER_OMEN = "Omen" -BINDING_NAME_OMENTOGGLE = "Toggle Omen" - - diff --git a/Omen.lua b/Omen.lua index 03039b2..408bd5f 100644 --- a/Omen.lua +++ b/Omen.lua @@ -9,22 +9,27 @@ LoadAddOn("Ace3") LoadAddOn("LibSharedMedia-3.0") LoadAddOn("AceGUI-3.0-SharedMediaWidgets") +LoadAddOn("LibSink-2.0") ----------------------------------------------------------------------------- -- Addon declaration -local Omen = LibStub("AceAddon-3.0"):NewAddon("Omen", "AceConsole-3.0", "AceEvent-3.0", "AceTimer-3.0") +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") _G["Omen"] = Omen -- TODO: Add TPS calculations --- TODO: Add visible/audible warnings --- TODO: Add Sink/SharedMedia stuff -- TODO: Code optimizations +----------------------------------------------------------------------------- +-- Keybinding globals +BINDING_HEADER_OMEN = "Omen" +BINDING_NAME_OMENTOGGLE = L["Toggle Omen"] + + ----------------------------------------------------------------------------- -- Register some media LSM:Register("sound", "Rubber Ducky", [[Sound\Doodad\Goblin_Lottery_Open01.wav]]) @@ -122,6 +127,16 @@ local defaults = { HideMinimapButton = true, AttachMinimap = false, }, + Warnings = { + Sound = true, + Flash = true, + Shake = false, + Message = false, + SinkOptions = {}, + Threshold = 90, + SoundFile = "Fel Nova", + DisableWhileTanking = true, + }, }, } local guidNameLookup = {} -- Format: guidNameLookup[guid] = "Unit Name" @@ -129,11 +144,13 @@ 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? Omen.GuidNameLookup = guidNameLookup Omen.GuidClassLookup = guidClassLookup Omen.Timers = timers Omen.Bars = bars +setmetatable(guidNameLookup, {__index = function(self, guid) return L[""] end}) local default_color = { -- Default bar color for units not in the player's raid/party r = 1, @@ -271,6 +288,7 @@ function Omen:OnInitialize() self.db.RegisterCallback(self, "OnProfileCopied", "OnProfileChanged") self.db.RegisterCallback(self, "OnProfileReset", "OnProfileChanged") db = self.db.profile + self:SetSinkStorage(db.Warnings.SinkOptions) self:CreateFrames() self:SetupOptions() @@ -278,9 +296,7 @@ function Omen:OnInitialize() self:UpdateBackdrop() self:UpdateTitleBar() - -- Register events that are "always on". The rest are in :OnEnable() self:RegisterEvent("PLAYER_LOGIN") - self:RegisterEvent("PLAYER_ENTERING_WORLD") end function Omen:PLAYER_LOGIN() @@ -294,9 +310,9 @@ function Omen:PLAYER_LOGIN() -- Optional launcher support for LDB-1.1 if present, this code is placed here so -- that it runs after all other addons have loaded since we don't embed LDB-1.1 - local DataBroker = LibStub("LibDataBroker-1.1", true) - if DataBroker then - local launcher = DataBroker:NewDataObject("Omen", { + if LibStub("LibDataBroker-1.1", true) and not IsAddOnLoaded("Broker2FuBar") then + local LDB = LibStub("LibDataBroker-1.1", true) + local launcher = LDB:NewDataObject("Omen", { type = "launcher", icon = "Interface\\AddOns\\Omen\\icon", OnClick = function(clickedframe, button) @@ -309,14 +325,14 @@ function Omen:PLAYER_LOGIN() -- 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) then + 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("iconPath", [[Interface\AddOns\Omen\icon]]) self:SetFuBarOption("hasIcon", true) self:SetFuBarOption("defaultPosition", "RIGHT") self:SetFuBarOption("tooltipHiddenWhenEmpty", true) @@ -338,20 +354,21 @@ function Omen:OnEnable() self:RegisterEvent("UNIT_THREAT_LIST_UPDATE") self:RegisterEvent("UNIT_THREAT_SITUATION_UPDATE") self:RegisterEvent("PLAYER_TARGET_CHANGED") - self:RegisterEvent("UNIT_PET") + 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", "UpdateVisible") self:PARTY_MEMBERS_CHANGED() self:PLAYER_TARGET_CHANGED() end -function Omen:Disable() - self:UnregisterEvent("UNIT_THREAT_LIST_UPDATE") - self:UnregisterEvent("UNIT_THREAT_SITUATION_UPDATE") - self:UnregisterEvent("PLAYER_TARGET_CHANGED") - self:UnregisterEvent("UNIT_PET") - self:UnregisterEvent("PARTY_MEMBERS_CHANGED") - +function Omen:OnDisable() -- Cancel all timers (well at least nil them all -- out in timers[], since AceTimer-3.0 cancels -- them all OnDisable anyway). @@ -456,7 +473,7 @@ function Omen:UpdateBackdrop() bgFrame.insets.bottom = inset self.Title:SetBackdrop(bgFrame) self.BarList:SetBackdrop(bgFrame) - + local c = db.Background.Color self.Title:SetBackdropColor(c.r, c.g, c.b, c.a) self.BarList:SetBackdropColor(c.r, c.g, c.b, c.a) @@ -495,14 +512,113 @@ end function Omen:UpdateFuBarSettings() if LibStub:GetLibrary("LibFuBarPlugin-3.0", true) then - if self:IsFuBarMinimapAttached() ~= db.FuBar.AttachMinimap then - self:ToggleFuBarMinimapAttached() + if db.FuBar.HideMinimapButton then + self:Hide() + else + self:Show() + if self:IsFuBarMinimapAttached() ~= db.FuBar.AttachMinimap then + self:ToggleFuBarMinimapAttached() + end end - if db.FuBar.HideMinimapButton then self:Hide() else self:Show() end end 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 @@ -539,7 +655,7 @@ do self:SetScript("OnUpdate", animate) end - -- Create bars on demand + -- Create bars on demand setmetatable(bars, {__index = function(self, barID) local bar = CreateFrame("Frame", nil, Omen.BarList) self[barID] = bar @@ -640,17 +756,6 @@ function Omen:PLAYER_TARGET_CHANGED() end end -function Omen:UNIT_PET() - self:PARTY_MEMBERS_CHANGED() -end - -function Omen:PLAYER_ENTERING_WORLD() - if UnitGUID("player") then - guidNameLookup[UnitGUID("player")] = UnitName("player") - end - self:UpdateVisible() -end - local lastPartyUpdateTime = GetTime() function Omen:PARTY_MEMBERS_CHANGED() @@ -679,7 +784,10 @@ function Omen:UpdatePartyGUIDs() for k, v in pairs(guidClassLookup) do guidClassLookup[k] = nil end - _, guidClassLookup[UnitGUID("player")] = UnitClass("player") + if UnitGUID("player") then + guidNameLookup[UnitGUID("player")] = UnitName("player") + _, guidClassLookup[UnitGUID("player")] = UnitClass("player") + end if UnitExists("pet") then guidClassLookup[UnitGUID("pet")] = "PET" guidNameLookup[UnitGUID("pet")] = UnitName("pet")--.." ["..UnitName("player").."]" @@ -689,15 +797,15 @@ function Omen:UpdatePartyGUIDs() 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) @@ -746,12 +854,15 @@ threatValue is the amount of threat that the unit has on the mob's threat list. --------- r, g, b = GetThreatStatusColor(state) -Returns the colors used in the UI to represent each major threat 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 lastWarn = { -- Used to store information for threat warnings + threatpercent = 0, +} local function sortfunction(a, b) return threatTable[a] > threatTable[b] @@ -768,84 +879,88 @@ end function Omen:UpdateBars() if not self.Anchor:IsShown() and not db.CollapseHide then return end - + -- TODO: Put a update throtle on this function - -- Figure out which mob to show threat on, either "target" or "targettarget" - -- It has to be attackable and not human controlled, otherwise return - local mob = "target" - if UnitExists(mob) and (UnitIsPlayer(mob) or UnitPlayerControlled(mob) or not UnitCanAttack("player", mob)) then - guidNameLookup[UnitGUID(mob)] = UnitName(mob) - mob = "targettarget" - end - if not UnitExists(mob) or UnitIsPlayer(mob) or UnitPlayerControlled(mob) or not UnitCanAttack("player", mob) then - self:ClearAll() - return - end - local mobGUID = UnitGUID(mob) - guidNameLookup[mobGUID] = UnitName(mob) - self.TitleText:SetText(guidNameLookup[mobGUID]) + local mobGUID, mobTargetGUID - -- 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 and not guidNameLookup[mobTargetGUID] then - guidNameLookup[mobTargetGUID] = UnitName(mobTarget) - end - - -- Clear the threat table - for k, v in pairs(threatTable) do - threatTable[k] = nil - end - threatTable[mobGUID] = -1 - tankGUID = nil - - -- 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 + if testMode then + for k, v in pairs(threatTable) do + threatTable[k] = nil end - - end - if not inRaid then - updatethreat("player", mob) - updatethreat("pet", mob) - updatethreat("target", mob) - updatethreat("pettarget", mob) - end - updatethreat("focus", mob) - updatethreat("focustarget", mob) - updatethreat(mobTarget, mob) - updatethreat("mouseover", mob) - updatethreat("mouseovertarget", mob) + for i = 1, 25 do + threatTable[i] = i*5000 + end + tankGUID = 25 + self.TitleText:SetText(L["Test Mode"]) + else + -- Figure out which mob to show threat on, either "target" or "targettarget" + -- It has to be attackable and not human controlled, otherwise return + local mob = "target" + if UnitExists(mob) and (UnitIsPlayer(mob) or UnitPlayerControlled(mob) or not UnitCanAttack("player", mob)) then + guidNameLookup[UnitGUID(mob)] = UnitName(mob) + mob = "targettarget" + end + if not UnitExists(mob) or UnitIsPlayer(mob) or UnitPlayerControlled(mob) or not UnitCanAttack("player", mob) then + self:ClearAll() + return + end + mobGUID = UnitGUID(mob) + guidNameLookup[mobGUID] = UnitName(mob) + self.TitleText:SetText(guidNameLookup[mobGUID]) - -- This is for testing purposes - --[[for k, v in pairs(threatTable) do - threatTable[k] = nil + -- 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 and not guidNameLookup[mobTargetGUID] then + guidNameLookup[mobTargetGUID] = UnitName(mobTarget) + end + + -- Clear the threat table + for k, v in pairs(threatTable) do + threatTable[k] = nil + end + threatTable[mobGUID] = -1 + tankGUID = nil + + -- 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("focus", mob) + updatethreat("focustarget", mob) + updatethreat(mobTarget, mob) + updatethreat("mouseover", mob) + updatethreat("mouseovertarget", mob) end - for i = 1, 25 do - threatTable[i] = i*5000 - end - tankGUID = 25]] -- Sort the threatTable local i = 1 @@ -884,7 +999,7 @@ function Omen:UpdateBars() end local bar = bars[j] local threat = threatTable[guid] - bar.Text1:SetText(guidNameLookup[guid] or L[""]) + bar.Text1:SetText(guidNameLookup[guid]) if db.Bar.ShortNumbers and threat > 100000 then bar.Text2:SetFormattedText("%2.1fk [%d%%]", threat / 100000, tankThreat == 0 and 0 or threat / tankThreat * 100) else @@ -912,6 +1027,22 @@ function Omen:UpdateBars() end self.Anchor:Show() self.BarList:Show() + + -- Threat warnings + local pGUID = UnitGUID("player") + local pClass = guidClassLookup[pGUID] + local myThreatPercent = threatTable[pGUID] / tankThreat * 100 + local t = db.Warnings + if lastWarn.mobGUID == mobGUID and myThreatPercent >= t.Threshold and t.Threshold > lastWarn.threatpercent then + if not t.DisableWhileTanking or not (pClass == "WARRIOR" and GetBonusBarOffset() == 2 or + pClass == "DRUID" and GetBonusBarOffset() == 3 or + pClass == "PALADIN" and UnitAura("player", GetSpellInfo(25780)) or + pClass == "DEATHKNIGHT" and GetShapeshiftFormInfo(GetShapeshiftForm()) == "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[tankGUID or mobTargetGUID or sortTable[1]])) + end + end + lastWarn.mobGUID = mobGUID + lastWarn.threatpercent = myThreatPercent end function Omen:ClearAll() @@ -926,6 +1057,8 @@ function Omen:ClearAll() self.Anchor:Hide() end end + lastWarn.mobGUID = nil + lastWarn.threatpercent = 0 end @@ -942,16 +1075,18 @@ local function GetFuBarMinimapAttachedStatus(info) return Omen:IsFuBarMinimapAttached() or db.FuBar.HideMinimapButton end +-- Option table for the AceGUI config only local options = { type = "group", name = "Omen", get = function(info) return db[ info[#info] ] end, set = function(info, value) db[ info[#info] ] = value end, args = { - general = { + General = { order = 1, type = "group", name = L["General Settings"], + desc = L["General Settings"], args = { intro = { order = 1, @@ -992,11 +1127,6 @@ local options = { if value then Omen.Grip:Hide() else Omen.Grip:Show() end end, }, - linebreak = { - order = 9, - type = "description", - name = "", - }, Autocollapse = { type = "toggle", name = L["Autocollapse"], @@ -1136,6 +1266,7 @@ local options = { }, }, ShowWhen = { + order = 2, type = "group", name = L["Show When..."], desc = L["Show Omen when..."], @@ -1189,6 +1320,7 @@ local options = { }, }, TitleBar = { + order = 3, type = "group", name = L["Title Bar Settings"], desc = L["Title Bar Settings"], @@ -1258,6 +1390,7 @@ local options = { }, }, Bars = { + order = 4, type = "group", name = L["Bar Settings"], desc = L["Bar Settings"], @@ -1374,15 +1507,100 @@ local options = { }, }, }, + Warnings = { + order = 5, + 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 = "Enable Sound", + desc = "Enable Sound", + }, + Flash = { + type = "toggle", + order = 3, + name = "Enable Screen Flash", + desc = "Enable Screen Flash", + }, + Shake = { + type = "toggle", + order = 4, + name = "Enable Screen Shake", + desc = "Enable Screen Shake", + }, + 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 = { - attachMinimap = { + 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, @@ -1390,17 +1608,7 @@ local options = { Omen:ToggleFuBarMinimapAttached() db.FuBar.AttachMinimap = Omen:IsFuBarMinimapAttached() end, - }, - hideIcon = { - type = "toggle", - order = 2, - 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 - if v then Omen:Hide() else Omen:Show() end - end, + disabled = function() return db.FuBar.HideMinimapButton end, }, showIcon = { type = "toggle", @@ -1438,6 +1646,7 @@ local options = { }, Help = { type = "group", + order = -1, name = L["Help File"], desc = L["A collection of help pages"], childGroups = "select", @@ -1479,10 +1688,15 @@ local options = { }, } Omen.Options = options +options.args.Warnings.args.Output.order = 6 +options.args.Warnings.args.Output.inline = true +options.args.Warnings.args.Output.disabled = function() return not db.Warnings.Message end +-- Option table for the slash command only local optionsSlash = { type = "group", name = L["Slash Command"], + order = -3, args = { intro = { order = 1, @@ -1521,20 +1735,26 @@ local optionsSlash = { } Omen.OptionsSlash = optionsSlash - function Omen:SetupOptions() self.optionsFrames = {} - + -- setup options table LibStub("AceConfigRegistry-3.0"):RegisterOptionsTable("Omen", options) LibStub("AceConfig-3.0"):RegisterOptionsTable("OmenSlashCommand", optionsSlash, "omen") - self.optionsFrames.Omen = LibStub("AceConfigDialog-3.0"):AddToBlizOptions("Omen", nil, nil, "general") - self.optionsFrames.Help = LibStub("AceConfigDialog-3.0"):AddToBlizOptions("Omen", L["Help File"], "Omen", "Help") - self.optionsFrames.ShowWhen = LibStub("AceConfigDialog-3.0"):AddToBlizOptions("Omen", L["Show When..."], "Omen", "ShowWhen") - self.optionsFrames.Bars = LibStub("AceConfigDialog-3.0"):AddToBlizOptions("Omen", L["Bar Settings"], "Omen", "Bars") - self.optionsFrames.TitleBar = LibStub("AceConfigDialog-3.0"):AddToBlizOptions("Omen", L["Title Bar Settings"], "Omen", "TitleBar") - self:RegisterModuleOptions("Profiles", LibStub("AceDBOptions-3.0"):GetOptionsTable(self.db), L["Profiles"]) + local ACD3 = LibStub("AceConfigDialog-3.0") + + -- The ordering here matters, it determines the order in the Blizzard Interface Options + self.optionsFrames.Omen = ACD3:AddToBlizOptions("Omen", nil, nil, "General") + self.optionsFrames.ShowWhen = ACD3:AddToBlizOptions("Omen", L["Show When..."], "Omen", "ShowWhen") + self.optionsFrames.TitleBar = ACD3:AddToBlizOptions("Omen", L["Title Bar Settings"], "Omen", "TitleBar") + self.optionsFrames.Bars = ACD3:AddToBlizOptions("Omen", L["Bar Settings"], "Omen", "Bars") + self.optionsFrames.Warnings = ACD3:AddToBlizOptions("Omen", L["Warning Settings"], "Omen", "Warnings") self:RegisterModuleOptions("OmenSlashCommand", optionsSlash, L["Slash Command"]) + self:RegisterModuleOptions("Profiles", LibStub("AceDBOptions-3.0"):GetOptionsTable(self.db), L["Profiles"]) + self.optionsFrames.Help = ACD3:AddToBlizOptions("Omen", L["Help File"], "Omen", "Help") + + -- Add ordering data to the option table generated by AceDBOptions-3.0 + options.args.Profiles.order = -2 end function Omen:RegisterModuleOptions(name, optionTbl, displayName) diff --git a/Omen.toc b/Omen.toc index cb9b5d4..eb62b2b 100644 --- a/Omen.toc +++ b/Omen.toc @@ -8,7 +8,7 @@ ## Notes-zhTW: 一個輕量級、有彈性、可監視多個目標的仇恨統計插件。 ## Notes-koKR: 다중-대상에 대한 위협수준 미터기로 보여줍니다. ## Author: Xinhuan -## OptionalDeps: Ace3, LibSharedMedia-3.0, AceGUI-3.0-SharedMediaWidgets +## OptionalDeps: Ace3, LibSharedMedia-3.0, AceGUI-3.0-SharedMediaWidgets, LibSink-2.0 ## X-Category: Combat ## SavedVariables: Omen3DB @@ -26,6 +26,7 @@ Libs\AceTimer-3.0\AceTimer-3.0.xml Libs\AceDBOptions-3.0\AceDBOptions-3.0.xml Libs\LibSharedMedia-3.0\lib.xml Libs\AceGUI-3.0-SharedMediaWidgets\widget.xml +Libs\LibSink-2.0\lib.xml #@end-no-lib-strip@ Localization\enUS.lua