9d3198c - Fix castbar delays
[wowui.git] / OmaGtfo / Gtfo.lua
1 -- Gtfo.lua
2 local _;
3 local print, tonumber, pairs = print, tonumber, pairs;
4 local format = string.format;
5 local strsplit = strsplit;
6 local UnitGUID = UnitGUID;
7 local UnitExists, UnitIsUnit = UnitExists, UnitIsUnit;
8 local UnitBuff, UnitDebuff = UnitBuff, UnitDebuff;
9 local UnitGroupRolesAssigned = UnitGroupRolesAssigned;
10 local PlaySoundFile = PlaySoundFile;
11 local playerGuid, guids;
12 local playerTank;
13 local printAll = false;
14 local frame = CreateFrame("Frame");
15 frame:Hide();
16
17 local sounds = {
18     "Interface\\Addons\\OmaGtfo\\sounds\\alarmbuzzer.ogg",
19     "Interface\\Addons\\OmaGtfo\\sounds\\alarmbeep.ogg",
20     "Interface\\Addons\\OmaGtfo\\sounds\\alarmdouble.ogg",
21     "Interface\\Addons\\OmaGtfo\\sounds\\alarmbuzz.ogg",
22 };
23 local taken = OmaGTFO.DmgTaken;
24 local caused = OmaGTFO.DmgDone;
25 local environs = {
26     ["Drowning"] = sounds[1],
27     ["Fatigue"] = sounds[1],
28     ["Lava"] = sounds[2],
29     ["Fire"] = sounds[2],
30     ["Slime"] = sounds[2],
31 };
32
33 local function mobId(guid)
34     local mob, _, _, _, _, id = strsplit("-", guid);
35     if mob and (mob == "Creature" or mob == "Vehicle" or mob == "Pet") then
36         return tonumber(id);
37     end
38     return nil;
39 end
40
41 local function checkDebuff(id)
42     local i = 1;
43     while true do
44         local _, _, _, _, _, _, _, _, _, spell = UnitAura("player", i, "HARMFUL");
45         if not spell then
46             return false;
47         elseif spell == id then
48             return true;
49         end
50         i = i + 1;
51     end
52 end
53
54 -- negatingIgnoreTime-like functionality not implemented
55 local events = {
56     ["SPELL_DAMAGE"] = function(event, source, spellid, spellname, _, arg1, arg2)
57         if (event == "SPELL_AURA_APPLIED" or event == "SPELL_AURA_APPLIED_DOSE" or
58             event == "SPELL_AURA_REFRESH") and arg1 ~= "DEBUFF" then
59             return;
60         elseif taken[spellid] then
61             -- TODO uncomment checks when they're in use
62             local spell = taken[spellid];
63             local sound = spell.sound;
64             if spell.eventType and spell.eventType ~= event then return end
65             --if (event == "SPELL_MISSED" or event == "SPELL_PERIODIC_MISSED") and not spell.always then return end
66             if spell.negatingDebuff and checkDebuff(spell.negatingDebuff) then return end
67             --if spell.negatingBuff and UnitBuff("player", spell.negatingBuff) then return end
68             --if spell.affirmingDebuff and not UnitDebuff("player", spell.affirmingDebuff) then return end
69             --if spell.mobs and source and not spell.mobs[mobId(source)] then return end
70             --if spell.ignoreSelf and source == playerGuid then return end
71             if spell.tankMechanic and playerTank then
72                 if spell.tankMechanic == true then return end
73                 sound = spell.tankMechanic;
74             end
75             if spell.applicationOnly then
76                 if event ~= "SPELL_AURA_APPLIED" and event ~= "SPELL_AURA_APPLIED_DOSE" and
77                     event ~= "SPELL_AURA_REFRESH" then
78                     return;
79                 elseif spell.minStacks and (event ~= "SPELL_AURA_APPLIED_DOSE" or
80                     not arg2 or arg2 <= spell.minStacks) then
81                     return;
82                 end
83             end
84             if spell.minDamage then
85                 local damage = tonumber(arg1) or 0;
86                 if damage < spell.minDamage then return end
87             end
88             if spell.multipleHitsTime then -- only alarm if multiple hits within a certain time
89                 local now, prevHit = GetTime(), spell.prevHit;
90                 spell.prevHit = now;
91                 if prevHit then
92                     if now - prevHit > spell.multipleHitsTime then
93                         return;
94                     end
95                 else
96                     return;
97                 end
98             end
99
100             return PlaySoundFile(sounds[sound], "SFX");
101         --elseif printAll then -- TODO uncomment when wanting to print all non-tracked events
102         --    return print(event, spellid, spellname);
103         end
104     end,
105     ["ENVIRONMENTAL_DAMAGE"] = function(_, _, env)
106         if environs[env] then return PlaySoundFile(environs[env], "SFX") end
107     end,
108 };
109 events["SPELL_MISSED"] = events["SPELL_DAMAGE"];
110 events["SPELL_PERIODIC_DAMAGE"] = events["SPELL_DAMAGE"];
111 events["SPELL_PERIODIC_MISSED"] = events["SPELL_DAMAGE"];
112 events["SPELL_ENERGIZE"] = events["SPELL_DAMAGE"];
113 events["SPELL_INSTAKILL"] = events["SPELL_DAMAGE"];
114 events["SPELL_AURA_APPLIED"] = events["SPELL_DAMAGE"];
115 events["SPELL_AURA_APPLIED_DOSE"] = events["SPELL_DAMAGE"];
116 events["SPELL_AURA_REFRESH"] = events["SPELL_DAMAGE"];
117
118 local function clog(_, event, _, sourceGuid, _, _, _, destGuid, _, _, _, ...)
119     -- TODO vehicle support?
120     if destGuid == playerGuid then
121         if events[event] then return events[event](event, sourceGuid, ...) end
122     elseif sourceGuid == playerGuid and event == "SPELL_DAMAGE" then
123         local spellid = ...;
124         if guids[destGuid] and caused[spellid] then
125             return PlaySoundFile(sounds[caused[spellid]], "SFX");
126         end
127     end
128 end
129
130 local function updateGuids()
131     guids = {};
132     if IsInGroup() then
133         if IsInRaid() then
134             for i = 1,40 do
135                 local unit = format("raid%i", i);
136                 if not UnitExists(unit) then break end
137                 if not UnitIsUnit(unit, "player") then
138                     guids[UnitGUID(unit)] = true;
139                 end
140             end
141         else
142             for i = 1,4 do
143                 local unit = format("party%i", i);
144                 if not UnitExists(unit) then break end
145                 guids[UnitGUID(unit)] = true;
146             end
147         end
148     end
149 end
150
151 local function updateRole()
152     playerTank = UnitGroupRolesAssigned("player") == "TANK";
153 end
154
155 local realEvents = {
156     ["COMBAT_LOG_EVENT_UNFILTERED"] = function()
157         return clog(CombatLogGetCurrentEventInfo());
158     end,
159     ["GROUP_ROSTER_UPDATE"] = updateGuids,
160     ["PLAYER_ROLES_ASSIGNED"] = updateRole,
161     ["MIRROR_TIMER_START"] = function(timer, _, _, scale)
162         if (timer == "EXHAUSTION" and scale < 0) then
163             return PlaySoundFile(sounds[1], "SFX");
164         end
165     end,
166 };
167 local function handleEvent(frame, event, ...)
168     realEvents[event](...);
169 end
170
171 frame:SetScript("OnEvent", function()
172     frame:UnregisterAllEvents();
173     playerGuid = UnitGUID("player");
174     updateGuids();
175     updateRole();
176     frame:SetScript("OnEvent", handleEvent);
177     frame:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED");
178     frame:RegisterEvent("GROUP_ROSTER_UPDATE");
179     frame:RegisterEvent("PLAYER_ROLES_ASSIGNED");
180     frame:RegisterEvent("MIRROR_TIMER_START");
181 end);
182 frame:RegisterEvent("PLAYER_LOGIN");
183
184 SLASH_OMAGTFO1 = "/omag";
185 function SlashCmdList.OMAGTFO(msg, editBox)
186     printAll = not printAll;
187     print("printAll", printAll)
188 end