local L = LibStub("AceLocale-3.0"):GetLocale("Skada", false) local Skada = Skada local media = LibStub("LibSharedMedia-3.0") -- This mode is a bit special. local mod = Skada:NewModule(L["Threat"]) local opts = { options = { type="group", name=L["Threat"], args={ warnings = { type="group", name=L["Threat warning"], inline=true, order=1, args={ flash = { type="toggle", name=L["Flash screen"], desc=L["This will cause the screen to flash as a threat warning."], get=function() return Skada.db.profile.modules.threatflash end, set=function(self, val) Skada.db.profile.modules.threatflash = val end, order=2, }, shake = { type="toggle", name=L["Shake screen"], desc=L["This will cause the screen to shake as a threat warning."], get=function() return Skada.db.profile.modules.threatshake end, set=function(self, val) Skada.db.profile.modules.threatshake = not Skada.db.profile.modules.threatshake end, order=3, }, playsound = { type="toggle", name=L["Play sound"], desc=L["This will play a sound as a threat warning."], get=function() return Skada.db.profile.modules.threatsound end, set=function(self, val) Skada.db.profile.modules.threatsound = not Skada.db.profile.modules.threatsound end, order=4, }, sound = { type = 'select', dialogControl = 'LSM30_Sound', name = L["Threat sound"], desc = L["The sound that will be played when your threat percentage reaches a certain point."], values = AceGUIWidgetLSMlists.sound, get = function() return Skada.db.profile.modules.threatsoundname end, set = function(self,val) Skada.db.profile.modules.threatsoundname = val end, order=5, }, treshold = { type = 'range', name = L["Threat threshold"], desc = L["When your threat reaches this level, relative to tank, warnings are shown."], min=0, max=130, step=1, get = function() return Skada.db.profile.modules.threattreshold end, set = function(self,val) Skada.db.profile.modules.threattreshold = val end, order=6, }, notankwarnings = { type = "toggle", name = L["Do not warn while tanking"], get = function() return Skada.db.profile.modules.notankwarnings end, set = function() Skada.db.profile.modules.notankwarnings = not Skada.db.profile.modules.notankwarnings end, order=2, }, }, }, rawthreat = { type = "toggle", name = L["Show raw threat"], desc = L["Shows raw threat percentage relative to tank instead of modified for range."], get = function() return Skada.db.profile.modules.threatraw end, set = function() Skada.db.profile.modules.threatraw = not Skada.db.profile.modules.threatraw end, order=2, }, focustarget = { type = "toggle", name = L["Use focus target"], desc = L["Shows threat on focus target, or focus target's target, when available."], get = function() return Skada.db.profile.modules.threatfocustarget end, set = function() Skada.db.profile.modules.threatfocustarget = not Skada.db.profile.modules.threatfocustarget end, order=2, }, }, } } function mod:OnInitialize() -- Add our options. table.insert(Skada.options.plugins, opts) end function mod:OnEnable() mod.metadata = {showspots = 1, wipestale = 1, columns = {Threat = true, TPS = false, Percent = true}} -- Add our feed. Skada:AddFeed(L["Threat: Personal Threat"], function() if Skada.current and UnitExists("target") then local isTanking, status, threatpct, rawthreatpct, threatvalue = UnitDetailedThreatSituation("player", "target") if threatpct then return ("%02.1f%%"):format(threatpct) end end end) -- Enable us Skada:AddMode(self) end function mod:OnDisable() Skada:RemoveMode(self) end local maxthreat = 0 -- Used as index for dataset. local nr = 1 -- Max threat value. local max = 0 local function add_to_threattable(win, name, target) if name and UnitExists(name) then local isTanking, status, threatpct, rawthreatpct, threatvalue = UnitDetailedThreatSituation(name, target) if Skada.db.profile.modules.threatraw then if threatvalue then local d = win.dataset[nr] or {} win.dataset[nr] = d d.label = name d.class = select(2, UnitClass(name)) d.id = name d.threat = threatvalue d.isTanking = isTanking if threatvalue < 0 then -- Show real threat. d.value = threatvalue + 410065408 d.threat = threatvalue + 410065408 else d.value = threatvalue end if threatvalue > maxthreat then maxthreat = threatvalue end end else if threatpct then local d = win.dataset[nr] or {} win.dataset[nr] = d d.label = name d.class = select(2, UnitClass(name)) d.id = name d.value = threatpct d.isTanking = isTanking d.threat = threatvalue end end nr = nr + 1 end end local function format_threatvalue(value) if value == nil then return "0" elseif value >= 100000 then return ("%2.1fk"):format(value / 100000) else return ("%d"):format(value / 100) end end local function getTPS(threatvalue) if Skada.current then local totaltime = time() - Skada.current.starttime return format_threatvalue(threatvalue / math.max(1,totaltime)) else -- If we are not in combat and have no active set, we are screwed, since we have no time reference. return "0" end end local last_warn = time() function mod:Update(win, set) local target = nil if UnitExists("target") and not UnitIsFriend("player", "target") then target = "target" elseif Skada.db.profile.modules.threatfocustarget and UnitExists("focus") and not UnitIsFriend("player", "focus") then target = "focus" elseif Skada.db.profile.modules.threatfocustarget and UnitExists("focustarget") and not UnitIsFriend("player", "focustarget") then target = "focustarget" elseif UnitExists("target") and UnitIsFriend("player", "target") and UnitExists("targettarget") and not UnitIsFriend("player", "targettarget") then target = "targettarget" end if target then -- Set window title. win.metadata.title = UnitName(target) -- Reset our counter which we use to keep track of current index in the dataset. nr = 1 -- Reset out max threat value. maxthreat = 0 if GetNumRaidMembers() > 0 then -- We are in a raid. for i = 1, 40, 1 do local name, rank, subgroup, level, class, fileName, zone, online, isDead, role, isML = GetRaidRosterInfo(i); if name then add_to_threattable(win, name, target) if UnitExists("raid"..i.."pet") then add_to_threattable(win, select(1, UnitName("raid"..i.."pet")), target) end end end elseif GetNumPartyMembers() > 0 then -- We are in a party. for i = 1, 5, 1 do local name = (UnitName("party"..tostring(i))) if name then add_to_threattable(win, name, target) if UnitExists("party"..i.."pet") then add_to_threattable(win, select(1, UnitName("party"..i.."pet")), target) end end end -- Don't forget ourselves. add_to_threattable(win, UnitName("player"), target) -- Maybe we have a pet? if UnitExists("pet") then add_to_threattable(win, UnitName("pet"), target) end else -- We are all alone. add_to_threattable(win, UnitName("player"), target) -- Maybe we have a pet? if UnitExists("pet") then add_to_threattable(win, UnitName("pet"), target) end end -- If we are going by raw threat we got the max threat from above; otherwise it's always 100. if not Skada.db.profile.modules.threatraw then maxthreat = 100 end win.metadata.maxvalue = maxthreat local we_should_warn = false -- We now have a a complete threat table. -- Now we need to add valuetext. for i, data in ipairs(win.dataset) do if data.id then if data.threat and data.threat > 0 then -- Warn if this is ourselves and we are over the treshold. local percent = data.value / maxthreat * 100 if data.label == UnitName("player") then if Skada.db.profile.modules.threattreshold and Skada.db.profile.modules.threattreshold < percent and (not data.isTanking or not Skada.db.profile.modules.notankwarnings) then we_should_warn = true end end data.valuetext = Skada:FormatValueText( format_threatvalue(data.threat), self.metadata.columns.Threat, getTPS(data.threat), self.metadata.columns.TPS, string.format("%02.1f%%", percent), self.metadata.columns.Percent ) else data.id = nil end end end -- Warn if we_should_warn and time() - last_warn > 2 then if Skada.db.profile.modules.threatflash then self:Flash() end if Skada.db.profile.modules.threatshake then self:Shake() end if Skada.db.profile.modules.threatsound then PlaySoundFile(media:Fetch("sound", Skada.db.profile.modules.threatsoundname)) end last_warn = time() end else win.metadata.title = self:GetName() end end -- Shamelessly copied from Omen - thanks! function mod:Flash() if not self.FlashFrame then local flasher = CreateFrame("Frame", "SkadaThreatFlashFrame") 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 -- Shamelessly copied from Omen (which copied from BigWigs) - thanks! function mod:Shake() local shaker = self.ShakerFrame if not shaker then shaker = CreateFrame("Frame", "SkadaThreatShaker", 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 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