-- InnerFireWatch (Turtle WoW / 1.12.1) -- Tracks key self-buffs and alerts when they fall off: -- - Priest: Inner Fire -- - Warrior: Battle Shout -- - Shaman: Lightning Shield / Water Shield / Earth Shield InnerFireWatchDB = InnerFireWatchDB or {} local f = CreateFrame("Frame") local DEFAULTS = { enabled = true, soundEnabled = true, gainedMessage = false, largeMessageEnabled = true, useCustomSound = true, customSoundPath = "Interface\\AddOns\\InnerFireWatch\\sounds\\expire.wav", fallbackSound = "igQuestFailed", } local function ApplyDefaults() for k, v in pairs(DEFAULTS) do if InnerFireWatchDB[k] == nil then InnerFireWatchDB[k] = v end end end -- Big center-screen text (independent of UIErrorsFrame) local CenterAlert = CreateFrame("Frame", "InnerFireWatchCenterAlert", UIParent) CenterAlert:SetPoint("CENTER", UIParent, "CENTER", 0, 120) CenterAlert:SetWidth(600) CenterAlert:SetHeight(80) CenterAlert:Hide() CenterAlert.text = CenterAlert:CreateFontString(nil, "OVERLAY") CenterAlert.text:SetAllPoints(CenterAlert) CenterAlert.text:SetFont("Fonts\\FRIZQT__.TTF", 32, "OUTLINE") CenterAlert.text:SetJustifyH("CENTER") CenterAlert.text:SetJustifyV("MIDDLE") local function ShowCenterAlert(msg, r, g, b) CenterAlert.text:SetText(msg or "") CenterAlert.text:SetTextColor(r or 1, g or 0.1, b or 0.1) CenterAlert:Show() CenterAlert.startTime = GetTime() end -- Fade out over ~1.6s CenterAlert:SetScript("OnUpdate", function() if not CenterAlert:IsShown() then return end local t = GetTime() - (CenterAlert.startTime or 0) if t >= 1.6 then CenterAlert:Hide() return end local alpha = 1 - (t / 1.6) CenterAlert:SetAlpha(alpha) end) -- Returns true if player currently has a buff whose texture contains textureNeedle (lowercase compare). local function HasBuffByTexture(textureNeedle) local i = 1 while true do local texture = UnitBuff("player", i) if not texture then break end texture = string.lower(texture) if string.find(texture, textureNeedle) then return true end i = i + 1 end return false end local function PlayExpireSound() if not InnerFireWatchDB.soundEnabled then return end if InnerFireWatchDB.useCustomSound and PlaySoundFile then PlaySoundFile(InnerFireWatchDB.customSoundPath) return end if PlaySound then PlaySound(InnerFireWatchDB.fallbackSound) end end local function NotifyExpired(buffLabel) local msg = buffLabel .. " has expired!" DEFAULT_CHAT_FRAME:AddMessage("|cffff3333" .. msg .. "|r") if InnerFireWatchDB.largeMessageEnabled then ShowCenterAlert(string.upper(buffLabel) .. " EXPIRED!") end if UIErrorsFrame and UIErrorsFrame.AddMessage then UIErrorsFrame:AddMessage(msg, 1.0, 0.1, 0.1, 1.0, 5) end PlayExpireSound() end local function NotifyGained(buffLabel) if not InnerFireWatchDB.gainedMessage then return end DEFAULT_CHAT_FRAME:AddMessage("|cff33ff33" .. buffLabel .. " active.|r") end -- Build trackers based on class local trackers = {} local function BuildTrackers() trackers = {} local _, classToken = UnitClass("player") if classToken == "PRIEST" then table.insert(trackers, { label = "Inner Fire", needle = "spell_holy_innerfire", active = false, }) elseif classToken == "WARRIOR" then table.insert(trackers, { label = "Battle Shout", needle = "ability_warrior_battleshout", active = false, }) elseif classToken == "SHAMAN" then -- Texture needles are based on the icon file names. -- Lightning Shield: Spell_Nature_LightningShield -- Water Shield: Ability_Shaman_WaterShield -- Earth Shield: Spell_Nature_SkinOfEarth (commonly used in TBC/clients that add it) table.insert(trackers, { label = "Lightning Shield", needle = "spell_nature_lightningshield", active = false }) table.insert(trackers, { label = "Water Shield", needle = "ability_shaman_watershield", active = false }) table.insert(trackers, { label = "Earth Shield", needle = "spell_nature_skinofearth", active = false }) end for _, t in ipairs(trackers) do t.active = HasBuffByTexture(t.needle) end end local function Check() if not InnerFireWatchDB.enabled then return end if not trackers or table.getn(trackers) == 0 then return end for _, t in ipairs(trackers) do local nowActive = HasBuffByTexture(t.needle) if t.active and (not nowActive) then NotifyExpired(t.label) elseif (not t.active) and nowActive then NotifyGained(t.label) end t.active = nowActive end end f:RegisterEvent("PLAYER_LOGIN") f:RegisterEvent("PLAYER_AURAS_CHANGED") f:SetScript("OnEvent", function() Check() end) -- Init after saved vars load f:SetScript("OnUpdate", function() f:SetScript("OnUpdate", nil) ApplyDefaults() BuildTrackers() end) -- Slash commands SLASH_INNERFIREWATCH1 = "/ifw" SlashCmdList["INNERFIREWATCH"] = function(msg) msg = msg and string.lower(msg) or "" if msg == "on" then InnerFireWatchDB.enabled = true DEFAULT_CHAT_FRAME:AddMessage("InnerFireWatch: enabled") elseif msg == "off" then InnerFireWatchDB.enabled = false DEFAULT_CHAT_FRAME:AddMessage("InnerFireWatch: disabled") elseif msg == "sound on" then InnerFireWatchDB.soundEnabled = true DEFAULT_CHAT_FRAME:AddMessage("InnerFireWatch: sound enabled") elseif msg == "sound off" then InnerFireWatchDB.soundEnabled = false DEFAULT_CHAT_FRAME:AddMessage("InnerFireWatch: sound disabled") elseif msg == "custom on" then InnerFireWatchDB.useCustomSound = true DEFAULT_CHAT_FRAME:AddMessage("InnerFireWatch: custom sound enabled") elseif msg == "custom off" then InnerFireWatchDB.useCustomSound = false DEFAULT_CHAT_FRAME:AddMessage("InnerFireWatch: custom sound disabled") elseif msg == "gained on" then InnerFireWatchDB.gainedMessage = true DEFAULT_CHAT_FRAME:AddMessage("InnerFireWatch: gained message enabled") elseif msg == "gained off" then InnerFireWatchDB.gainedMessage = false DEFAULT_CHAT_FRAME:AddMessage("InnerFireWatch: gained message disabled") elseif msg == "large on" then InnerFireWatchDB.largeMessageEnabled = true DEFAULT_CHAT_FRAME:AddMessage("InnerFireWatch: large message enabled") elseif msg == "large off" then InnerFireWatchDB.largeMessageEnabled = false DEFAULT_CHAT_FRAME:AddMessage("InnerFireWatch: large message disabled") else DEFAULT_CHAT_FRAME:AddMessage("InnerFireWatch commands:") DEFAULT_CHAT_FRAME:AddMessage(" /ifw on|off") DEFAULT_CHAT_FRAME:AddMessage(" /ifw sound on|sound off") DEFAULT_CHAT_FRAME:AddMessage(" /ifw custom on|custom off") DEFAULT_CHAT_FRAME:AddMessage(" /ifw gained on|gained off") DEFAULT_CHAT_FRAME:AddMessage(" /ifw large on|large off") end end