diff --git a/modules/DispellableDebuffs.lua b/modules/DispellableDebuffs.lua index 47ee443..0f62c9a 100644 --- a/modules/DispellableDebuffs.lua +++ b/modules/DispellableDebuffs.lua @@ -1,118 +1,243 @@ --[[-------------------------------------------------------------------- - oUF_DispelHighlight - Highlights oUF frames by dispellable debuff type. - Originally based on Ammo's oUF_DebuffHighlight. + Credit to Phanx for this Dispel Highlight Module + + Copyright (c) 2008-2013 Phanx <addons@phanx.net>. All rights reserved. + http://www.wowinterface.com/downloads/info13993-oUF_Phanx.html + http://www.curse.com/addons/wow/ouf-phanx +------------------------------------------------------------------------ + Element to highlight oUF frames by dispellable debuff type. + Originally based on oUF_DebuffHighlight by Ammo. + Some code adapted from LibDispellable-1.0 by Adirelle. You may embed this module in your own layout, but please do not distribute it as a standalone plugin. - To have your frame's health bar highlighted: - frame.DispelHighlight = true + Usage: + frame.DispelHighlight = frame.Health:CreateTexture(nil, "OVERLAY") + frame.DispelHighlight:SetAllPoints(frame.Health:GetStatusBarTexture()) - To use your own highlighting function: - frame.DispelHighlight = function(frame, event, unit, debuffType, canDispel) - -- debuffType : string or nil : type of the highest priority debuff, nil if no debuffs - -- canDispel : boolean : indicates whether the player can dispel the debuff + Options: + frame.DispelHighlight.filter = true + frame.DispelHighlight.PreUpdate = function(element) end + frame.DispelHighlight.PostUpdate = function(element, debuffType, canDispel) + frame.DispelHighlight.Override = function(element, debuffType, canDispel) +----------------------------------------------------------------------]] + +if select(4, GetAddOnInfo("oUF_DebuffHighlight")) then return end + +local _, ns = ... +local oUF = ns.oUF or oUF +assert(oUF, "DispelHighlight element requires oUF") + +local _, playerClass = UnitClass("player") + +local colors = { -- these are nicer than DebuffTypeColor + ["Curse"] = { 0.8, 0, 1 }, + ["Disease"] = { 0.8, 0.6, 0 }, + ["Enrage"] = { 1.0, 0.2, 0.6 }, + ["Invulnerability"] = { 1, 1, 0.4 }, + ["Magic"] = { 0, 0.8, 1 }, + ["Poison"] = { 0, 0.8, 0 }, +} +oUF.colors.debuff = colors + +local INVULNERABILITY_EFFECTS = { + [642] = true, -- Divine Shield + [1022] = true, -- Hand of Protection + [45438] = true, -- Ice Block +} + +local DefaultDispelPriority = { Curse = 2, Disease = 4, Magic = 1, Poison = 3 } +local ClassDispelPriority = { Curse = 3, Disease = 1, Magic = 4, Poison = 2 } + +local canDispel, canPurge, canShatter, canSteal, canTranq, noDispels = {} +local debuffTypeCache = {} + +local Update, ForceUpdate, Enable, Disable + +function Update(self, event, unit) + if unit ~= self.unit then return end + local element = self.DispelHighlight + -- print("DispelHighlight Update", event, unit) + + local debuffType, dispellable + + if not noDispels and UnitCanAssist("player", unit) then + for i = 1, 40 do + local name, _, _, _, type = UnitDebuff(unit, i) + if not name then break end + -- print("UnitDebuff", unit, i, tostring(name), tostring(type)) + if type and (not debuffType or ClassDispelPriority[type] > ClassDispelPriority[debuffType]) then + -- print("debuffType", type) + debuffType = type + dispellable = canDispel[type] + end + end + elseif (canSteal or canPurge or canTranq) and UnitCanAttack("player", unit) then + for i = 1, 40 do + local name, _, _, _, type, _, _, _, stealable, _, id = UnitBuff(unit, i) + if not name then break end + + if canShatter and INVULNERABILITY_EFFECTS[id] then + type = "Invulnerability" + elseif type == "" then + type = "Enrage" + end + + if (canSteal and stealable) or (canPurge and type == "Magic") or (canTranq and type == "Enrage") or (type == "Invulnerability") then + -- print("debuffType", type) + debuffType = type + dispellable = true + break + end end + end - To highlight only debuffs you can dispel: - frame.DispelHighlightFilter = true -----------------------------------------------------------------------]] + if debuffTypeCache[unit] == debuffType then return end -if not oUF then return end -if select(4, GetAddOnInfo('oUF_DispelHighlight')) then return end - -local _, playerClass = UnitClass('player') - -local canDispel -if playerClass == 'DRUID' then - canDispel = { Curse = true, Poison = true } -elseif playerClass == 'MAGE' then - canDispel = { Curse = true } -elseif playerClass == 'PALADIN' then - canDispel = { Disease = true, Magic = true, Poison = true } -elseif playerClass == 'PRIEST' then - canDispel = { Disease = true, Magic = true } -elseif playerClass == 'SHAMAN' then - canDispel = { Curse = true, Disease = true, Poison = true } -end + -- print("UpdateDispelHighlight", unit, tostring(debuffTypeCache[unit]), "==>", tostring(debuffType)) + debuffTypeCache[unit] = debuffType + + if element.Override then + element:Override(debuffType, dispellable) + return + end -local DebuffPriority = { } -for type, priority in pairs({ Curse = 2, Disease = 4, Magic = 1, Poison = 3 }) do - table.insert(DebuffPriority, type) - DebuffPriority[type] = ((canDispel and canDispel[type]) and 10 or 5) - priority + if element.PreUpdate then + element:PreUpdate() + end + + if debuffType and (dispellable or not element.filter) then + element:SetVertexColor(unpack(colors[debuffType])) + element:Show() + else + element:Hide() + end + + if element.PostUpdate then + element:PostUpdate(debuffType, dispellable) + end end -table.sort(DebuffPriority, function(a, b) return DebuffPriority[a] > DebuffPriority[b] end) -local DebuffTypeColor = { } -for type, color in pairs(_G.DebuffTypeColor) do - DebuffTypeColor[type] = { color.r, color.g, color.b } +function ForceUpdate(element) + return Update(element.__owner, "ForceUpdate", element.__owner.unit) end ------------------------------------------------------------------------- +local function Enable(self) + local element = self.DispelHighlight + if not element then return end -local unitDebuffType = { } + element.__owner = self + element.ForceUpdate = ForceUpdate -local function applyDispelHighlight(self, event, unit, bar) - local debuffType = unitDebuffType[unit] - if debuffType then - bar:SetStatusBarColor(unpack(DebuffTypeColor[debuffType])) + self:RegisterEvent("UNIT_AURA", Update) + + if element.GetTexture and not element:GetTexture() then + element:SetTexture([[Interface\QuestFrame\UI-QuestTitleHighlight]]) end -end -local function Update(self, event, unit) - if self.unit ~= unit then return end - -- print('Update', unit) + return true +end - if not UnitCanAssist('player', unit) then return end - -- print('not UnitCanAssist') +local function Disable(self) + local element = self.DispelHighlight + if not element then return end - local debuffType + self:UnregisterEvent("UNIT_AURA", Update) - local i = 1 - while true do - local name, _, _, _, type = UnitAura(unit, i, 'HARMFUL') - if not name then break end - -- print('UnitAura', unit, i, name or 'NONE', type or 'NONE') - if type and (not debuffType or DebuffPriority[type] > DebuffPriority[debuffType]) then - -- print('debuffType', type) - debuffType = type - end - i = i + 1 - end + element:Hide() +end - if unitDebuffType[unit] ~= debuffType then - -- print('unitDebuffType', unitDebuffType[unit] or 'NONE', 'debuffType', debuffType or 'NONE') +oUF:AddElement("DispelHighlight", Update, Enable, Disable) - unitDebuffType[unit] = debuffType +------------------------------------------------------------------------ - if type(self.DispelHighlight) == 'function' then - self:DispelHighlight(event, unit, debuffType, canDispel and canDispel[debuffType]) - else - if debuffType and self.DispelHighlightFilter and not (canDispel and canDispel[debuffType]) then return end - applyDispelHighlight(self, event, unit, self.Health) - end - end +local function SortByPriority(a, b) + return ClassDispelPriority[a] > ClassDispelPriority[b] end -local function Enable(self) - if not self.DispelHighlight or (self.DispelHighlightFilter and not canDispel) then return end +local f = CreateFrame("Frame") +f:RegisterEvent("SPELLS_CHANGED") +f:SetScript("OnEvent", function(self, event) + wipe(canDispel) - self:RegisterEvent('UNIT_AURA', Update) + -- print("DispelHighlight", event, "Checking capabilities...") - if type(self.DispelHighlight) ~= 'function' then - local o = self.PostUpdateHealth - self.PostUpdateHealth = function(...) - if o then o(...) end - applyDispelHighlight(...) + if playerClass == "DEATHKNIGHT" then + for i = 1, GetNumGlyphSockets() do + local enabled, _, _, id = GetGlyphSocketInfo(i) + if id == 58631 then + canPurge = true -- Glyph of Icy Touch + break + end end - end -end -local function Disable(self) - if not self.DispelHighlight or not canDispel then return end + elseif playerClass == "DRUID" then + canDispel.Curse = IsPlayerSpell(88423) or IsPlayerSpell(2782) -- Remove Corruption + canDispel.Magic = IsPlayerSpell(88423) -- Nature's Cure + canDispel.Poison = canDispel.Curse + canTranq = IsPlayerSpell(2908) -- Soothe + + elseif playerClass == "HUNTER" then + canPurge = IsPlayerSpell(19801) -- Tranquilizing Shot + canTranq = canPurge + + elseif playerClass == "MAGE" then + canDispel.Curse = IsPlayerSpell(475) -- Remove Curse + canSteal = IsPlayerSpell(30449) -- Spellsteal + + elseif playerClass == "MONK" then + canDispel.Disease = IsPlayerSpell(115450) -- Detox + canDispel.Magic = IsPlayerSpell(115451) -- Internal Medicine + canDispel.Poison = canDispel.Disease + + elseif playerClass == "PALADIN" then + canDispel.Disease = IsPlayerSpell(4987) -- Cleanse + canDispel.Magic = IsPlayerSpell(53551) -- Sacred Cleansing + canDispel.Poison = canDispel.Disease + + elseif playerClass == "PRIEST" then + canDispel.Disease = IsPlayerSpell(527) -- Purify + canDispel.Magic = IsPlayerSpell(527) or IsPlayerSpell(32375) -- Mass Dispel + canPurge = IsPlayerSpell(528) -- Dispel Magic + + elseif playerClass == "ROGUE" then + canTranq = IsPlayerSpell(5938) -- Shiv + + elseif playerClass == "SHAMAN" then + canDispel.Curse = IsPlayerSpell(51886) -- Cleanse Spirit (upgrades to Purify Spirit) + canDispel.Magic = IsPlayerSpell(77130) -- Purify Spirit + canPurge = IsPlayerSpell(370) -- Purge + + elseif playerClass == "WARLOCK" then + canDispel.Magic = IsPlayerSpell(115276, true) or IsPlayerSpell(89808, true) -- Sear Magic (Fel Imp) or Singe Magic (Imp) + canPurge = IsPlayerSpell(19505, true) -- Devour Magic (Felhunter) + + elseif playerClass == "WARRIOR" then + canPurge = IsPlayerSpell(23922) -- Shield Slam + canShatter = IsPlayerSpell(64382) -- Shattering Throw + end - self:UnregisterEvent('UNIT_AURA', Update) -end + wipe(ClassDispelPriority) + for type, priority in pairs(DefaultDispelPriority) do + ClassDispelPriority[1 + #ClassDispelPriority] = type + ClassDispelPriority[type] = (canDispel[type] and 10 or 5) - priority + end + table.sort(ClassDispelPriority, SortByPriority) -oUF:AddElement('DispelHighlight', Update, Enable, Disable) + noDispels = not next(canDispel) +--[[ + for i, v in ipairs(ClassDispelPriority) do + print("Can dispel " .. v .. "?", canDispel[v] and "YES" or "NO") + end + print("Can purge?", canPurge and "YES" or "NO") + print("Can shatter?", canShatter and "YES" or "NO") + print("Can steal?", canSteal and "YES" or "NO") + print("Can tranquilize?", canTranq and "YES" or "NO") +]] + for i, object in ipairs(oUF.objects) do + if object.DispelHighlight and object:IsShown() then + Update(object, event, object.unit) + end + end +end) \ No newline at end of file diff --git a/modules/Threat.lua b/modules/Threat.lua index 6c0b28b..0ca3e15 100644 --- a/modules/Threat.lua +++ b/modules/Threat.lua @@ -1,67 +1,75 @@ --[[-------------------------------------------------------------------- - oUF_ThreatHighlight - Highlights oUF frames by threat level. + Credit to Phanx for this threat highlighting module + + Copyright (c) 2008-2013 Phanx <addons@phanx.net>. All rights reserved. + http://www.wowinterface.com/downloads/info13993-oUF_Phanx.html + http://www.curse.com/addons/wow/ouf-phanx +------------------------------------------------------------------------ + Element to highlight oUF frames by threat level. - Simple usage: - self.ThreatHighlight = true + You may embed this module in your own layout, but please do not + distribute it as a standalone module. - Advanced usage: - self.ThreatHighlight = function(self, unit, status) end + Usage: + frame.ThreatHighlight = frame.Health:CreateTexture(nil, "OVERLAY") + frame.ThreatHighlight:SetAllPoints(true) + + Supports Override. Does not support PreUpdate/PostUpdate. ----------------------------------------------------------------------]] local _, ns = ... local oUF = ns.oUF or oUF -if not oUF then return end +assert(oUF, "ThreatHighlight element requires oUF") -local unitThreatStatus = { } +local Update, ForceUpdate, Enable, Disable -local function applyThreatHighlight(self, unit) - local status = unitThreatStatus[unit] - if status then - local r, g, b = GetThreatStatusColor(status) - self:SetStatusBarColor(r, g, b) - end -end +function Update(self, event, unit) + if not unit or self.unit ~= unit then return end + local element = self.ThreatHighlight -local function Update(self, event, unit) - if self.unit ~= unit then return end + local ok, status = pcall(UnitThreatSituation, unit) + if not ok then return end -- WTF??? + -- print("ThreatHighlight Update", event, unit, status) - local status = UnitThreatSituation(unit) - -- local status = UnitIsFriend(unit, 'player') and UnitThreatSituation(unit) or UnitThreatSituation('player', unit) - -- print('ThreatHighlight Update', event, unit, status) + if element.Override then + return element:Override(status) + end if status and status > 0 then - if type(self.ThreatHighlight) == 'function' then - self.ThreatHighlight(self, unit, status) - else - unitThreatStatus[unit] = status - applyThreatHighlight(self.Health, unit) - end - elseif type(self.ThreatHighlight) == 'function' then - self.ThreatHighlight(self, unit, 0) + element:SetVertexColor(GetThreatStatusColor(status)) + element:Show() + else + element:Hide() end end -local function Enable(self) - if not self.ThreatHighlight then return end +function ForceUpdate(element) + return Update(element.__owner, "ForceUpdate", element.__owner.unit) +end + +function Enable(self) + local element = self.ThreatHighlight + if not element then return end - self:RegisterEvent('UNIT_THREAT_SITUATION_UPDATE', Update) + element.__owner = self + element.ForceUpdate = ForceUpdate - if type(self.ThreatHighlight) ~= 'function' then - local o = self.Health.PostUpdate - self.Health.PostUpdate = function(...) - if o then o(...) end - applyThreatHighlight(...) - end + self:RegisterEvent("UNIT_THREAT_SITUATION_UPDATE", Update) + + if element.GetTexture and not element:GetTexture() then + element:SetTexture([[Interface\QuestFrame\UI-QuestTitleHighlight]]) end return true end -local function Disable(self) - if not self.ThreatHighlight then return end +function Disable(self) + local element = self.ThreatHighlight + if not element then return end + + self:UnregisterEvent("UNIT_THREAT_SITUATION_UPDATE", Update) - self:UnregisterEvent('UNIT_THREAT_SITUATION_UPDATE', Update) + element:Hide() end -oUF:AddElement('ThreatHighlight', Update, Enable, Disable) +oUF:AddElement("ThreatHighlight", Update, Enable, Disable) diff --git a/oUF_Lanerra.lua b/oUF_Lanerra.lua index 1af87a8..009d185 100644 --- a/oUF_Lanerra.lua +++ b/oUF_Lanerra.lua @@ -84,20 +84,12 @@ PowerBarColor['ENERGY'] = { r = 1, g = 1, b = 35/255 } PowerBarColor['RUNIC_POWER'] = { r = 0.45, g = 0.85, b = 1 } -- Threat color handling -oUF.colors.threat = {} +colors.threat = {} for i = 1, 3 do local r, g, b = GetThreatStatusColor(i) oUF.colors.threat[i] = { r, g, b } end --- Debuff color handling -colors.debuff = {} -for type, color in pairs(DebuffTypeColor) do - if (type ~= 'none') then - colors.debuff[type] = { color.r, color.g, color.b } - end -end - -- Color conversion function function hex(r, g, b) if(type(r) == 'table') then @@ -112,23 +104,21 @@ end local function UpdateBorder(self) local threat, debuff, dispellable = self.threatLevel, self.debuffType, self.debuffDispellable - local color, glow + local color if debuff and dispellable then color = colors.debuff[debuff] - glow = true elseif threat and threat > 1 then color = colors.threat[threat] - glow = true - elseif debuff then + elseif debuff and not ns.config.dispelFilter then color = colors.debuff[debuff] elseif threat and threat > 0 then color = colors.threat[threat] end if color then - self:SetBackdropBorderColor(color[1], color[2], color[3], 1) + SetBorderColor(self.Overlay, color[1], color[2], color[3]) else - self:SetBackdropBorderColor(0, 0, 0, 0) + SetBorderColor(self.Overlay, unpack(Settings.Media.BorderColor)) end end @@ -433,7 +423,7 @@ local AuraIconOverlay_SetBorderColor = function(overlay, r, g, b) local over = overlay:GetParent() - over.border:SetBorderColor(r, g, b) + SetBorderColor(over.border, r, g, b) end -- Aura Icon Creation Function @@ -502,27 +492,29 @@ local function PostUpdateAuraIcon(iconframe, unit, button, index, offset) end -- Dispel highlighting function -local function UpdateDispelHighlight(self, event, unit, debuffType, canDispel) - if (self.unit ~= unit) then - return - end - - if (self.debuffType == debuffType) then - return - end +local function UpdateDispelHighlight(element, debuffType, canDispel) + local frame = element.__owner - self.debuffType = debuffType - self.debuffDispellable = canDispel - - self:UpdateBorder() + if frame.debuffType == debuffType then return end + + frame.debuffType = debuffType + frame.debuffDispellable = canDispel + + frame:UpdateBorder() end -- Threat highlighting function -local function UpdateThreatHighlight(self, unit, status) - if self.threatLevel == status then return end +local function UpdateThreatHighlight(element, status) + if not status then + status = 0 + end + + local frame = element.__owner + if frame.threatLevel == status then return end + + frame.threatLevel = status - self.threatLevel = status - self:UpdateBorder() + frame:UpdateBorder() end -- Time to give our solo unit frames some style! @@ -959,7 +951,7 @@ local Stylish = function(self, unit, isSingle) self.Buffs['initialAnchor'] = 'BOTTOMRIGHT' self.Buffs['num'] = buffs self.Buffs['showType'] = false - self.Buffs['size'] = Settings.Units.Target.Height + self.Buffs['size'] = Settings.Units.Target.Height - 6 self.Buffs['spacing-x'] = GAP self.Buffs['spacing-y'] = GAP * 2 @@ -972,10 +964,6 @@ local Stylish = function(self, unit, isSingle) self.Buffs.parent = self end - -- DebuffHighlight Support - self.DebuffHighlightBackdrop = false - self.DebuffHighlightFilter = true - -- Various oUF plugins support if (unit == 'player') then -- oUF_RuneBar support @@ -1137,17 +1125,21 @@ local Stylish = function(self, unit, isSingle) end -- Hardcore border action! - AddBorder(self, Settings.Media.BorderSize, Settings.Media.BorderPadding + 2) - self:SetBorderParent(self.Overlay) + AddBorder(self.Overlay, Settings.Media.BorderSize, Settings.Media.BorderPadding + 2) self.UpdateBorder = UpdateBorder -- Dispel highlight support - self.DispelHighlight = UpdateDispelHighlight + self.DispelHighlight = { + Override = UpdateDispelHighlight, + filter = true, + } -- Threat highlight support self.threatLevel = 0 - self.ThreatHighlight = UpdateThreatHighlight + self.ThreatHighlight = { + Override = UpdateThreatHighlight, + } return self end @@ -1323,17 +1315,21 @@ local function StylishGroup(self, unit) self.SpellRange = true -- Hardcore border action! - AddBorder(self, Settings.Media.BorderSize, Settings.Media.BorderPadding + 2) - self:SetBorderParent(self.Overlay) + AddBorder(self.Overlay, Settings.Media.BorderSize, Settings.Media.BorderPadding + 2) self.UpdateBorder = UpdateBorder - -- Dispel highlight support - self.DispelHighlight = UpdateDispelHighlight + -- Dispel highlight support + self.DispelHighlight = { + Override = UpdateDispelHighlight, + filter = true, + } -- Threat highlight support self.threatLevel = 0 - self.ThreatHighlight = UpdateThreatHighlight + self.ThreatHighlight = { + Override = UpdateThreatHighlight, + } return self end @@ -1490,17 +1486,21 @@ local function StylishRaid(self, unit) self.SpellRange = true -- Hardcore border action! - AddBorder(self, Settings.Media.BorderSize, Settings.Media.BorderPadding + 2) - self:SetBorderParent(self.Overlay) + AddBorder(self.Overlay, Settings.Media.BorderSize, Settings.Media.BorderPadding + 2) self.UpdateBorder = UpdateBorder -- Dispel highlight support - self.DispelHighlight = UpdateDispelHighlight + self.DispelHighlight = { + Override = UpdateDispelHighlight, + filter = true, + } -- Threat highlight support self.threatLevel = 0 - self.ThreatHighlight = UpdateThreatHighlight + self.ThreatHighlight = { + Override = UpdateThreatHighlight, + } return self end diff --git a/oUF_Lanerra.toc b/oUF_Lanerra.toc index 1fc3888..e77564a 100644 --- a/oUF_Lanerra.toc +++ b/oUF_Lanerra.toc @@ -1,5 +1,5 @@ ## Interface: 50400 -## Version: 1.4.2 +## Version: 1.5.1 ## Title: oUF_Lanerra ## Notes: oUF layout by Lanerra