-- Gtfo.lua local _; local print, tonumber, pairs = print, tonumber, pairs; local format = string.format; local strsplit = strsplit; local UnitGUID = UnitGUID; local UnitExists, UnitIsUnit = UnitExists, UnitIsUnit; local UnitBuff, UnitDebuff = UnitBuff, UnitDebuff; local UnitGroupRolesAssigned = UnitGroupRolesAssigned; local PlaySoundFile = PlaySoundFile; local playerGuid, guids; local playerTank; local printAll = false; 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 mobId(guid) local mob, _, _, _, _, id = strsplit("-", guid); if mob and (mob == "Creature" or mob == "Vehicle" or mob == "Pet") then return tonumber(id); end return nil; end -- negatingIgnoreTime-like functionality not implemented local events = { ["SPELL_DAMAGE"] = function(event, source, spellid, spellname, _, arg1, arg2) if (event == "SPELL_AURA_APPLIED" or event == "SPELL_AURA_APPLIED_DOSE" or event == "SPELL_AURA_REFRESH") and arg1 ~= "DEBUFF" then return; elseif taken[spellid] then -- TODO uncomment checks when they're in use local spell = taken[spellid]; local sound = spell.sound; if spell.eventType and spell.eventType ~= event then return end --if (event == "SPELL_MISSED" or event == "SPELL_PERIODIC_MISSED") and not spell.always then return end if spell.negatingDebuff and UnitDebuff("player", spell.negatingDebuff) then return end --if spell.negatingBuff and UnitBuff("player", spell.negatingBuff) then return end --if spell.affirmingDebuff and not UnitDebuff("player", spell.affirmingDebuff) then return end --if spell.mobs and source and not spell.mobs[mobId(source)] then return end --if spell.ignoreSelf and source == playerGuid then return end if spell.tankMechanic and playerTank then if spell.tankMechanic == true then return end sound = spell.tankMechanic; end if spell.applicationOnly then if event ~= "SPELL_AURA_APPLIED" and event ~= "SPELL_AURA_APPLIED_DOSE" and event ~= "SPELL_AURA_REFRESH" 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 return PlaySoundFile(sounds[sound], "SFX"); --elseif printAll then -- TODO uncomment when wanting to print all non-tracked events -- return print(event, spellid, spellname); 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_ENERGIZE"] = events["SPELL_DAMAGE"]; events["SPELL_INSTAKILL"] = 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 then if events[event] then return events[event](event, sourceGuid, ...) end elseif sourceGuid == playerGuid and event == "SPELL_DAMAGE" then local spellid = ...; if guids[destGuid] and 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 function updateRole() playerTank = UnitGroupRolesAssigned("player") == "TANK"; end local realEvents = { ["COMBAT_LOG_EVENT_UNFILTERED"] = clog, ["GROUP_ROSTER_UPDATE"] = updateGuids, ["PLAYER_ROLES_ASSIGNED"] = updateRole, ["MIRROR_TIMER_START"] = function(timer, _, _, scale) if (timer == "EXHAUSTION" and scale < 0) then return PlaySoundFile(sounds[1], "SFX"); end end, }; local function handleEvent(frame, event, ...) realEvents[event](...); end frame:SetScript("OnEvent", function() frame:UnregisterAllEvents(); playerGuid = UnitGUID("player"); updateGuids(); updateRole(); frame:SetScript("OnEvent", handleEvent); frame:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED"); frame:RegisterEvent("GROUP_ROSTER_UPDATE"); frame:RegisterEvent("PLAYER_ROLES_ASSIGNED"); frame:RegisterEvent("MIRROR_TIMER_START"); end); frame:RegisterEvent("PLAYER_LOGIN"); SLASH_OMAGTFO1 = "/omag"; function SlashCmdList.OMAGTFO(msg, editBox) printAll = not printAll; print("printAll", printAll) end