21d4f1b - Update TOCs to 8.2.5
[wowui.git] / OmaGtfo / Gtfo.lua
1 -- Gtfo.lua
2 local _;
3 local tonumber = tonumber;
4 local format = string.format;
5 local UnitGUID = UnitGUID;
6 local UnitExists, UnitIsUnit = UnitExists, UnitIsUnit;
7 local UnitBuff, UnitDebuff = UnitBuff, UnitDebuff;
8 local PlaySoundFile = PlaySoundFile;
9 local playerGuid, guids;
10 local frame = CreateFrame("Frame");
11 frame:Hide();
12
13 local sounds = {
14     "Interface\\Addons\\OmaGtfo\\sounds\\alarmbuzzer.ogg",
15     "Interface\\Addons\\OmaGtfo\\sounds\\alarmbeep.ogg",
16     "Interface\\Addons\\OmaGtfo\\sounds\\alarmdouble.ogg",
17     "Interface\\Addons\\OmaGtfo\\sounds\\alarmbuzz.ogg",
18 };
19 local taken = OmaGTFO.DmgTaken;
20 local caused = OmaGTFO.DmgDone;
21 local environs = {
22     ["Drowning"] = sounds[1],
23     ["Fatigue"] = sounds[1],
24     ["Lava"] = sounds[2],
25     ["Fire"] = sounds[2],
26     ["Slime"] = sounds[2],
27 };
28
29 local function checkDebuff(id)
30     local i = 1;
31     while true do
32         local _, _, _, _, _, _, _, _, _, spell = UnitAura("player", i, "HARMFUL");
33         if not spell then
34             return false;
35         elseif spell == id then
36             return true;
37         end
38         i = i + 1;
39     end
40 end
41
42 local auraEvents = {
43     ["SPELL_AURA_APPLIED"] = true,
44     ["SPELL_AURA_APPLIED_DOSE"] = true,
45     ["SPELL_AURA_REFRESH"] = true,
46 };
47 local events = {
48     ["SPELL_DAMAGE"] = function(event, source, spellid, spellname, _, arg1, arg2)
49         if auraEvents[event] and arg1 ~= "DEBUFF" then
50             return;
51         elseif taken[spellid] then
52             local spell = taken[spellid];
53             local sound = spell.sound;
54
55             if spell.eventType and spell.eventType ~= event then return end
56             if spell.applicationOnly then
57                 if not auraEvents[event] then
58                     return;
59                 elseif spell.minStacks and (event ~= "SPELL_AURA_APPLIED_DOSE" or
60                     not arg2 or arg2 <= spell.minStacks) then
61                     return;
62                 end
63             end
64             if spell.minDamage then
65                 local damage = tonumber(arg1) or 0;
66                 if damage < spell.minDamage then return end
67             end
68             if spell.multipleHitsTime then -- only alarm if multiple hits within a certain time
69                 local now, prevHit = GetTime(), spell.prevHit;
70                 spell.prevHit = now;
71                 if prevHit then
72                     if now - prevHit > spell.multipleHitsTime then
73                         return;
74                     end
75                 else
76                     return;
77                 end
78             end
79             if spell.negatingDebuff and checkDebuff(spell.negatingDebuff) then return end
80
81             return PlaySoundFile(sounds[sound], "SFX");
82         end
83     end,
84     ["ENVIRONMENTAL_DAMAGE"] = function(_, _, env)
85         if environs[env] then return PlaySoundFile(environs[env], "SFX") end
86     end,
87 };
88 events["SPELL_MISSED"] = events["SPELL_DAMAGE"];
89 events["SPELL_PERIODIC_DAMAGE"] = events["SPELL_DAMAGE"];
90 events["SPELL_PERIODIC_MISSED"] = events["SPELL_DAMAGE"];
91 events["SPELL_AURA_APPLIED"] = events["SPELL_DAMAGE"];
92 events["SPELL_AURA_APPLIED_DOSE"] = events["SPELL_DAMAGE"];
93 events["SPELL_AURA_REFRESH"] = events["SPELL_DAMAGE"];
94
95 local function clog(_, event, _, sourceGuid, _, _, _, destGuid, _, _, _, ...)
96     -- TODO vehicle support?
97     if destGuid == playerGuid and events[event] then
98         return events[event](event, sourceGuid, ...);
99     elseif sourceGuid == playerGuid and event == "SPELL_DAMAGE" and guids[destGuid] then
100         local spellid = ...;
101         if caused[spellid] then return PlaySoundFile(sounds[caused[spellid]], "SFX") end
102     end
103 end
104
105 local function updateGuids()
106     guids = {};
107     if IsInGroup() then
108         if IsInRaid() then
109             for i = 1,40 do
110                 local unit = format("raid%i", i);
111                 if not UnitExists(unit) then break end
112                 if not UnitIsUnit(unit, "player") then
113                     guids[UnitGUID(unit)] = true;
114                 end
115             end
116         else
117             for i = 1,4 do
118                 local unit = format("party%i", i);
119                 if not UnitExists(unit) then break end
120                 guids[UnitGUID(unit)] = true;
121             end
122         end
123     end
124 end
125
126 local frameEvents = {
127     ["COMBAT_LOG_EVENT_UNFILTERED"] = function()
128         return clog(CombatLogGetCurrentEventInfo());
129     end,
130     ["GROUP_ROSTER_UPDATE"] = updateGuids,
131     ["MIRROR_TIMER_START"] = function(timer, _, _, scale)
132         if (timer == "EXHAUSTION" and scale < 0) then
133             return PlaySoundFile(sounds[1], "SFX");
134         end
135     end,
136 };
137
138 frame:SetScript("OnEvent", function()
139     frame:UnregisterAllEvents();
140     playerGuid = UnitGUID("player");
141     updateGuids();
142     frame:SetScript("OnEvent", function(_, event, ...)
143         frameEvents[event](...);
144     end);
145     frame:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED");
146     frame:RegisterEvent("GROUP_ROSTER_UPDATE");
147     frame:RegisterEvent("MIRROR_TIMER_START");
148 end);
149 frame:RegisterEvent("PLAYER_LOGIN");