aa489f6 - Remove unused MoveAnything compatibility code
[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                 if time - cached.time > 60 then -- refresh >1min
123                     -- new inspect
124                     cached.time = time;
125                     if cached.needItems then
126                         cached.weapon = GetInventoryItemLink(id, INVSLOT_MAINHAND);
127                         cached.wrist = GetInventoryItemID(id, INVSLOT_WRIST);
128                     end
129                     cached.spec = GetInspectSpecialization(id);
130                     local _, _, _, selected = GetTalentInfo(6, 2, 1, true, id);
131                     cached.talent = selected;
132                 end
133             end
134             if not inspectui then ClearInspectPlayer() end
135             if (cached.needItems and cached.weapon) or
136                (not cached.needItems and cached.talent ~= nil) then
137                 print("Got inspect done", UnitName(id));
138                 cached.cb(guid, cached.spec, cached.talent, cached.weapon, cached.wrist);
139             else
140                 pending[guid] = true;
141             end
142         end
143     end
144 end
145
146 local function updateIds()
147     local size = 0;
148     local prefix = "solo";
149     if IsInGroup() then
150         if IsInRaid() then
151             size = 40;
152             prefix = "raid";
153         else
154             size = 4;
155             prefix = "party";
156         end
157     end
158     for i = 1,size do
159         local id = format("%s%i", prefix, i);
160         local guid = UnitGUID(id);
161         if cache[guid] then cache[guid].id = id end
162     end
163 end
164
165 local function create()
166     frame:UnregisterAllEvents();
167     frame:SetScript("OnEvent", function(self, event, guid)
168         if event == "INSPECT_READY" then
169             inspectReady(guid);
170         elseif event == "GROUP_ROSTER_UPDATE" then
171             updateIds();
172         end
173     end);
174     frame:RegisterEvent("INSPECT_READY");
175     frame:RegisterEvent("GROUP_ROSTER_UPDATE");
176     tick();
177 end
178
179 frame:RegisterEvent("PLAYER_LOGIN");
180 frame:SetScript("OnEvent", function(self, event)
181     if event == "PLAYER_LOGIN" then
182         return create();
183     end
184 end);