-- Gtfo.lua local _; local tonumber = tonumber; local format = string.format; local UnitGUID = UnitGUID; local UnitExists, UnitIsUnit = UnitExists, UnitIsUnit; local UnitBuff, UnitDebuff = UnitBuff, UnitDebuff; local PlaySoundFile = PlaySoundFile; local playerGuid, guids; local frame = CreateFrame("Frame"); frame:Hide(); local sounds = { "Interface\\Addons\\OmaGtfo\\sounds\\alarmbuzzer.ogg", "Interface\\Addons\\OmaGtfo\\sounds\\alarmbeep.ogg", "Interface\\Addons\\OmaGtfo\\sounds\\alarmdouble.ogg", "Interface\\Addons\\OmaGtfo\\sounds\\alarmbuzz.ogg", }; local taken = OmaGTFO.DmgTaken; local caused = OmaGTFO.DmgDone; local environs = { ["Drowning"] = sounds[1], ["Fatigue"] = sounds[1], ["Lava"] = sounds[2], ["Fire"] = sounds[2], ["Slime"] = sounds[2], }; local function checkDebuff(id) local i = 1; while true do local _, _, _, _, _, _, _, _, _, spell = UnitAura("player", i, "HARMFUL"); if not spell then return false; elseif spell == id then return true; end i = i + 1; end end local auraEvents = { ["SPELL_AURA_APPLIED"] = true, ["SPELL_AURA_APPLIED_DOSE"] = true, ["SPELL_AURA_REFRESH"] = true, }; local events = { ["SPELL_DAMAGE"] = function(event, source, spellid, spellname, _, arg1, arg2) if auraEvents[event] and arg1 ~= "DEBUFF" then return; elseif taken[spellid] then local spell = taken[spellid]; local sound = spell.sound; if spell.eventType and spell.eventType ~= event then return end if spell.applicationOnly then if not auraEvents[event] then return; elseif spell.minStacks and (event ~= "SPELL_AURA_APPLIED_DOSE" or not arg2 or arg2 <= spell.minStacks) then return; end end if spell.minDamage then local damage = tonumber(arg1) or 0; if damage < spell.minDamage then return end end if spell.multipleHitsTime then -- only alarm if multiple hits within a certain time local now, prevHit = GetTime(), spell.prevHit; spell.prevHit = now; if prevHit then if now - prevHit > spell.multipleHitsTime then return; end else return; end end if spell.negatingDebuff and checkDebuff(spell.negatingDebuff) then return end return PlaySoundFile(sounds[sound], "SFX"); end end, ["ENVIRONMENTAL_DAMAGE"] = function(_, _, env) if environs[env] then return PlaySoundFile(environs[env], "SFX") end end, }; events["SPELL_MISSED"] = events["SPELL_DAMAGE"]; events["SPELL_PERIODIC_DAMAGE"] = events["SPELL_DAMAGE"]; events["SPELL_PERIODIC_MISSED"] = events["SPELL_DAMAGE"]; events["SPELL_AURA_APPLIED"] = events["SPELL_DAMAGE"]; events["SPELL_AURA_APPLIED_DOSE"] = events["SPELL_DAMAGE"]; events["SPELL_AURA_REFRESH"] = events["SPELL_DAMAGE"]; local function clog(_, event, _, sourceGuid, _, _, _, destGuid, _, _, _, ...) -- TODO vehicle support? if destGuid == playerGuid and events[event] then return events[event](event, sourceGuid, ...); elseif sourceGuid == playerGuid and event == "SPELL_DAMAGE" and guids[destGuid] then local spellid = ...; if caused[spellid] then return PlaySoundFile(sounds[caused[spellid]], "SFX") end end end local function updateGuids() guids = {}; if IsInGroup() then if IsInRaid() then for i = 1,40 do local unit = format("raid%i", i); if not UnitExists(unit) then break end if not UnitIsUnit(unit, "player") then guids[UnitGUID(unit)] = true; end end else for i = 1,4 do local unit = format("party%i", i); if not UnitExists(unit) then break end guids[UnitGUID(unit)] = true; end end end end local frameEvents = { ["COMBAT_LOG_EVENT_UNFILTERED"] = function() return clog(CombatLogGetCurrentEventInfo()); end, ["GROUP_ROSTER_UPDATE"] = updateGuids, ["MIRROR_TIMER_START"] = function(timer, _, _, scale) if (timer == "EXHAUSTION" and scale < 0) then return PlaySoundFile(sounds[1], "SFX"); end end, }; frame:SetScript("OnEvent", function() frame:UnregisterAllEvents(); playerGuid = UnitGUID("player"); updateGuids(); frame:SetScript("OnEvent", function(_, event, ...) frameEvents[event](...); end); frame:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED"); frame:RegisterEvent("GROUP_ROSTER_UPDATE"); frame:RegisterEvent("MIRROR_TIMER_START"); end); frame:RegisterEvent("PLAYER_LOGIN");