-- TellMeWhen.lua local _; local pairs = pairs; local GetSpecialization = GetSpecialization; local UnitExists = UnitExists; local UnitAura = UnitAura; local GetTotemInfo = GetTotemInfo; -- character specific frames -- TODO try with auraFilter, remove characters, change to classes --[[local classes = { ["PALADIN"] = { ["PLAYER HELPFUL"] = { { unit = "player", auras = {["Divine Shield"]=1, ""}, frames = { [1] = { x = 0, y = 0, width = 1, height = 1, }, }, }, }, }, }; local specs = { [retSpecid] = { ["PLAYER HELPFUL"] = { { unit = "player", auras = {["Judgment"]=1}, frames = { [1] = { }, }, }, }, ["PLAYER HARMFUL"] = { { }, }, }, }; --]] local chars = { ["Sylvanas"] = { ["Vildana"] = { { unit = "target", spec = 3, -- Retribution auras = {"Judgment"}, auraFilter = "PLAYER HARMFUL", x = 570, -- placed over Innervate frame y = 440, width = 80, height = 80, }, { unit = "player", spec = 3, -- Retribution auras = {"Divine Purpose"}, auraFilter = "PLAYER HELPFUL", x = 570, y = 530, width = 80, height = 80, }, { unit = "player", spec = 2, -- Protection auras = {"Shield of the Righteous"}, auraFilter = "PLAYER HELPFUL", x = 570, y = 440, width = 80, height = 80, }, { unit = "player", auras = {"Divine Shield"}, auraFilter = "PLAYER HELPFUL", x = 660, y = 440, width = 80, height = 80, }, }, }, ["Stormreaver"] = { ["Vildan"] = { { unit = "target", spec = 3, -- Retribution auras = {"Judgment"}, auraFilter = "PLAYER HARMFUL", x = 570, -- placed over Innervate frame y = 440, width = 80, height = 80, }, { unit = "player", auras = {"Divine Purpose"}, auraFilter = "PLAYER HELPFUL", x = 570, y = 530, width = 80, height = 80, }, { unit = "player", spec = 2, -- Protection auras = {"Shield of the Righteous"}, auraFilter = "PLAYER HELPFUL", x = 570, y = 440, width = 80, height = 80, }, { unit = "player", auras = {"Divine Shield"}, auraFilter = "PLAYER HELPFUL", x = 660, y = 440, width = 80, height = 80, }, }, ["Gilden"] = { { unit = "target", auras = {"Shadow Word: Pain", "Purge the Wicked"}, auraFilter = "PLAYER HARMFUL", x = 660, y = 440, width = 60, height = 60, }, { unit = "player", auras = {"Power Word: Fortitude"}, auraFilter = "HELPFUL", invert = true, x = 720, y = 440, width = 60, height = 60, }, { unit = "player", auras = {"Overcharge Mana"}, auraFilter = "PLAYER HELPFUL", x = 720, y = 440, width = 60, height = 60, }, }, ["Gedren"] = { { totems = {1}, -- Efflorescence x = 660, y = 440, width = 80, height = 80, }, }, ["Gazden"] = { { unit = "player", auras = {"Tidal Waves"}, auraFilter = "PLAYER HELPFUL", x = 660, y = 440, width = 40, height = 40, }, { unit = "player", auras = {"Healing Rain"}, auraFilter = "PLAYER HELPFUL", x = 700, y = 440, width = 40, height = 40, }, { unit = "player", auras = {"Unleash Life"}, auraFilter = "PLAYER HELPFUL", x = 740, y = 440, width = 40, height = 40, }, }, ["Gran"] = { { unit = "player", auras = {"Tidal Waves"}, auraFilter = "PLAYER HELPFUL", x = 660, y = 440, width = 40, height = 40, }, { unit = "player", auras = {"Healing Rain"}, auraFilter = "PLAYER HELPFUL", x = 700, y = 440, width = 40, height = 40, }, { unit = "player", auras = {"Unleash Life"}, auraFilter = "PLAYER HELPFUL", x = 740, y = 440, width = 40, height = 40, }, }, ["Gedrin"] = { { unit = "pet", auras = {"Frenzy"}, auraFilter = "HELPFUL", x = 660, y = 440, width = 40, height = 40, }, }, }, }; -- settings entry: -- unit = unitID where to check auras, not required for totem checkers -- spec = player spec index to show frame, if nil show always -- auras = list of auras to track, in priority order -- auraFilter = filter for UnitAura -- totems = list of totem slots to track, in priority order, only checked if auras is nil -- x = x position relative to UIParent bottom left -- y = y position relative to UIParent bottom left -- width = width -- height = height -- global frames' settings local settings = { { unit = "player", auras = {"Innervate", "Gift of the Titans"}, auraFilter = "HELPFUL", x = 570, y = 440, width = 80, height = 80, }, { unit = "player", auras = {"Ineffable Truth"}, auraFilter = "HELPFUL", x = 570, y = 440, width = 40, height = 40, }, { unit = "player", auras = { "Delusions", "Entropic Blast", "Necrotic Embrace", "Flametouched", "Shadowtouched", "Blazing Eruption", "Shattering Scream", "Consuming Hunger", "Unstable Soul", "Time Bomb", "Broken Shard", "Demolished", "Fetid Rot", "Roiling Deceit", "Putrid Blood", "Endemic Virus", "Lingering Infection", "Gigavolt Charge", "Crackling Lightning", "Storm's Wail", "Death's Door", "Deathly Withering", "Chilling Touch", "Volatile Charge", "Liquid Gold", "Drained Soul", "Evoke Anguish", "Ancient Curse", "Corrosion", "Debilitating Spit", "Tasty Morsel", "Encroaching Shadows", "Corrupted Existence", "Madness Bomb" }, auraFilter = "HARMFUL", x = 660, y = 530, width = 80, height = 80, }, { unit = "player", auras = { "Adaptive Membrane" }, auraFilter = "HARMFUL", x = 660, y = 780, width = 160, height = 160, }, }; local frames = {}; local units = {}; -- mapping from unitID to frames local totems = {}; -- mapping to frames with totems local bosses = {}; for i = 1, MAX_BOSS_FRAMES do bosses[i] = "boss"..i; end local currentSpec = 0; -- 0 is invalid local Indicators = CreateFrame("Frame", "OmaTMW", UIParent); local function updateAuraFrame(frame) local unit = frame.unit; if UnitExists(unit) and (not frame.spec or frame.spec == currentSpec) then local name, icon, count, duration, expires; local auraFilter = frame.auraFilter; local i = 1; while true do name, icon, count, _, duration, expires = UnitAura(unit, i, auraFilter); if not name then break end -- possible improvement to add spellID as an option if frame.auras[name] and not frame.invert then if count > 1 then frame.stack:SetText(count); frame.stack:Show(); else frame.stack:Hide(); end if expires > 0 then frame.cd:SetCooldown(expires - duration, duration); frame.cd:Show(); else frame.cd:Hide(); end frame.icon:SetTexture(icon); frame:Show(); return; elseif frame.auras[name] and frame.invert then frame.icon:SetTexture(icon); frame:Hide(); return; end i = i + 1; end if frame.invert then frame:Show(); -- not functional without first hiding once to get SetTexture return; end end frame:Hide(); end local function updateAuras(unit) if units[unit] then for _, i in pairs(units[unit]) do updateAuraFrame(frames[i]); end end end local function updateTotemFrame(frame, slot) local _, name, start, duration, icon = GetTotemInfo(slot); if name ~= "" then frame.cd:SetCooldown(start, duration); frame.cd:Show(); frame.icon:SetTexture(icon); frame:Show(); else frame:Hide(); end end local function updateTotems(slot) if totems[slot] then for _, i in pairs(totems[slot]) do updateTotemFrame(frames[i], slot); end end end local function createTMW(name, config, parent) local frame = CreateFrame("Frame", name, parent); frame:SetPoint("TOPLEFT", parent, "BOTTOMLEFT", config.x, config.y+config.height); frame:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", config.x+config.width, config.y); frame.unit = config.unit; frame.spec = config.spec; if config.auras then frame.auras = {}; for _, v in pairs(config.auras) do frame.auras[v] = true; end end frame.auraFilter = config.auraFilter; frame.totems = config.totems; frame.invert = config.invert; frame:Hide(); frame.base = frame:CreateTexture(nil, "BACKGROUND"); frame.base:SetAllPoints(); frame.base:SetColorTexture(0, 0, 0, 0.6); frame.icon = frame:CreateTexture(nil, "ARTWORK"); frame.icon:SetPoint("TOPLEFT", frame.base, "TOPLEFT", 1, -1); frame.icon:SetPoint("BOTTOMRIGHT", frame.base, "BOTTOMRIGHT", -1, 1); frame.icon:SetTexCoord(0.07, 0.93, 0.07, 0.93); frame.stack = frame:CreateFontString(nil, "OVERLAY", "NumberFontNormalLarge"); frame.stack:SetPoint("TOPLEFT"); frame.stack:Hide(); frame.cd = CreateFrame("Cooldown", name.."CD", frame, "CooldownFrameTemplate"); frame.cd:SetReverse(true); frame.cd:SetAllPoints(); return frame; end local function initialize() Indicators:SetFrameStrata("LOW"); Indicators:SetPoint("BOTTOMLEFT"); Indicators:SetWidth(1); Indicators:SetHeight(1); currentSpec = GetSpecialization(); local name, realm = UnitFullName("player"); if chars[realm] and chars[realm][name] then for _, config in pairs(chars[realm][name]) do table.insert(settings, config) end end for i, config in pairs(settings) do if config.unit then if not units[config.unit] then units[config.unit] = {} end table.insert(units[config.unit], i); end if config.totems then for _, slot in pairs(config.totems) do if not totems[slot] then totems[slot] = {} end table.insert(totems[slot], i); end end frames[i] = createTMW("OmaTMW"..i, config, Indicators); end for _, frame in pairs(frames) do if frame.auras then updateAuraFrame(frame) end if frame.totems then for _, slot in pairs(frame.totems) do updateTotemFrame(frame, slot) end end end end Indicators:RegisterEvent("UNIT_AURA"); Indicators:RegisterEvent("PLAYER_TARGET_CHANGED"); Indicators:RegisterEvent("PLAYER_TOTEM_UPDATE"); Indicators:RegisterEvent("INSTANCE_ENCOUNTER_ENGAGE_UNIT"); Indicators:RegisterEvent("PLAYER_SPECIALIZATION_CHANGED"); Indicators:RegisterEvent("PLAYER_LOGIN"); Indicators:SetScript("OnEvent", function(self, event, arg1) if event == "UNIT_AURA" then updateAuras(arg1); elseif event == "PLAYER_TARGET_CHANGED" then updateAuras("target"); elseif event == "PLAYER_TOTEM_UPDATE" then updateTotems(arg1); elseif event == "INSTANCE_ENCOUNTER_ENGAGE_UNIT" then for _, boss in pairs(bosses) do updateAuras(boss); end elseif event == "PLAYER_SPECIALIZATION_CHANGED" then currentSpec = GetSpecialization(); for _, frame in pairs(frames) do if frame.auras then updateAuraFrame(frame) end if frame.totems then for _, slot in pairs(frame.totems) do updateTotemFrame(frame, slot) end end end elseif event == "PLAYER_LOGIN" then initialize(); end end);