cd9dfa5 - Move frame.dead to updateText as it sometimes was missed
[wowui.git] / OmaCD / Inspect.lua
1 -- Inspect.lua
2 local _;
3 local next, print = next, print;
4 local format = string.format;
5 local InCombatLockdown = InCombatLockdown;
6 local CTimerAfter = C_Timer.After;
7 local UnitIsDeadOrGhost = UnitIsDeadOrGhost;
8 local IsInGroup, IsInRaid = IsInGroup, IsInRaid;
9 local CheckInteractDistance = CheckInteractDistance;
10 local GetTime, UnitGUID, UnitName = GetTime, UnitGUID, UnitName;
11 local CanInspect, NotifyInspect, ClearInspectPlayer = CanInspect, NotifyInspect, ClearInspectPlayer;
12 local GetInventoryItemLink, GetInventoryItemID = GetInventoryItemLink, GetInventoryItemID;
13 local GetTalentInfo, GetInspectSpecialization = GetTalentInfo, GetInspectSpecialization;
14 local INVSLOT_MAINHAND, INVSLOT_WRIST = INVSLOT_MAINHAND, INVSLOT_WRIST;
15
16 local cache = {};
17 local pending = {};
18 local inspecting = nil;
19 local inspectui = nil;
20 local frame = CreateFrame("Frame", "OmaInspect");
21 frame:Hide();
22 OmaInspect = {};
23
24 local redoGuid = nil;
25 local function redo()
26     if redoGuid and inspecting == redoGuid then
27         print("hit redo timeout, putting back on pending");
28         pending[redoGuid] = true;
29         inspecting = nil;
30         redoGuid = nil;
31         if not inspectui then ClearInspectPlayer() end
32     end
33 end
34
35 local function inspect(id)
36     local guid = UnitGUID(id);
37     if not guid then return end
38     if InCombatLockdown() then
39         pending[guid] = true;
40     elseif not inspectui then
41         -- not necessary, but there's too many issues with inspect,
42         -- try to hope being nearby makes it more likely to work
43         -- no need to inspect people not in range before pull anyway
44         if not UnitIsDeadOrGhost("player") and
45            CheckInteractDistance(id, 1) and CanInspect(id) then
46             if not inspecting then
47                 inspecting = guid;
48                 print("Sending inspect", UnitName(id));
49                 NotifyInspect(id);
50                 redoGuid = guid;
51                 CTimerAfter(20, redo);
52             else
53                 pending[guid] = true;
54             end
55         else
56             pending[guid] = true;
57         end
58     else
59         pending[guid] = true;
60     end
61 end
62
63 hooksecurefunc("InspectUnit", function()
64     inspectui = true;
65 end);
66 hooksecurefunc("NotifyInspect", function(id)
67     if inspecting ~= UnitGUID(id) then
68         inspectui = true;
69     end
70 end);
71 hooksecurefunc("ClearInspectPlayer", function()
72     inspectui = nil;
73 end);
74
75 local function tick()
76     -- make sure pending inspects get done at some point
77     if not InCombatLockdown() then
78         local guid, _ = next(pending);
79         if guid and cache[guid] and cache[guid].id then
80             pending[guid] = nil;
81             inspect(cache[guid].id);
82         end
83     end
84     CTimerAfter(2, tick);
85 end
86
87 function OmaInspect.Request(guid, id, callback, needItems, force)
88     if not id or not CanInspect(id) then return false end
89     if not guid or UnitGUID(id) ~= guid then return false end
90
91     if not cache[guid] then cache[guid] = {} end
92     local cached = cache[guid];
93     if not cached.time then cached.time = 0 end
94     cached.id = id;
95     cached.cb = callback;
96     cached.needItems = needItems;
97     local elapsed = GetTime() - cached.time;
98     if force or (not needItems and (not cached.talent or elapsed > 60)) or
99        (needItems and (not cached.weapon or elapsed > 60)) then
100         if not pending[guid] or inspecting ~= guid then -- don't send multiple inspects
101             inspect(id);
102         end
103     else
104         cached.cb(guid, cached.spec, cached.talent, cached.weapon, cached.wrist);
105     end
106     return true;
107 end
108
109 local function inspectReady(guid)
110     if not guid or inspecting ~= guid then print("Got inspect from elsewhere"); return end
111     local cached = cache[guid];
112     if cached and cached.id and UnitGUID(cached.id) == guid then
113         local time = GetTime();
114         local id = cached.id;
115         inspecting = nil;
116         redoGuid = nil;
117         if InCombatLockdown() and not inspectui then
118             pending[guid] = true;
119             if not inspectui then ClearInspectPlayer() end
120         else
121             if CanInspect(id) then
122                 -- new inspect
123                 cached.time = time;
124                 if cached.needItems then
125                     cached.weapon = GetInventoryItemLink(id, INVSLOT_MAINHAND);
126                     cached.wrist = GetInventoryItemID(id, INVSLOT_WRIST);
127                 end
128                 cached.spec = GetInspectSpecialization(id);
129                 local _, _, _, selected = GetTalentInfo(6, 2, 1, true, id);
130                 cached.talent = selected;
131             end
132             if not inspectui then ClearInspectPlayer() end
133             if (cached.needItems and cached.weapon) or
134                (not cached.needItems and cached.talent ~= nil) then
135                 print("Got inspect done", UnitName(id));
136                 cached.cb(guid, cached.spec, cached.talent, cached.weapon, cached.wrist);
137             else
138                 pending[guid] = true;
139             end
140         end
141     end
142 end
143
144 local function updateIds()
145     local size = 0;
146     local prefix = "solo";
147     if IsInGroup() then
148         if IsInRaid() then
149             size = 40;
150             prefix = "raid";
151         else
152             size = 4;
153             prefix = "party";
154         end
155     end
156     for i = 1,size do
157         local id = format("%s%i", prefix, i);
158         local guid = UnitGUID(id);
159         if cache[guid] then cache[guid].id = id end
160     end
161 end
162
163 local function create()
164     frame:UnregisterAllEvents();
165     frame:SetScript("OnEvent", function(self, event, guid)
166         if event == "INSPECT_READY" then
167             inspectReady(guid);
168         elseif event == "GROUP_ROSTER_UPDATE" then
169             updateIds();
170         end
171     end);
172     frame:RegisterEvent("INSPECT_READY");
173     frame:RegisterEvent("GROUP_ROSTER_UPDATE");
174     tick();
175 end
176
177 frame:RegisterEvent("PLAYER_LOGIN");
178 frame:SetScript("OnEvent", function(self, event)
179     if event == "PLAYER_LOGIN" then
180         return create();
181     end
182 end);