-- Constants |
local CACHE_SIZE = 0 -- Max. # of characters in cache |
local CACHE_EXPIRE = 60 -- Cached entries will expire after this # of seconds |
local INSPECT_DELAY = 0.1 -- Time to hover over unit before NotifyInspect() is called |
local TXT_LOADING = "Loading items..." |
|
LoadAddOn("Blizzard_InspectUI") |
|
--[[ |
This is a workaround for a bug in blizzard's UI code, that popups |
an error when inspecting a unit when the actual inspection window |
is not open. Supposidely fixed in 4.1 |
|
Alternatively, install InspectFix: |
http://wow.curse.com/downloads/wow-addons/details/inspectfix.aspx |
]] |
local function patch() |
local oldfunc1=InspectPaperDollFrame_SetLevel; |
InspectPaperDollFrame_SetLevel=function(...) |
if InspectFrame.unit and UnitExists(InspectFrame.unit) then |
return oldfunc1(...); |
end |
end; |
|
local oldfunc2=InspectGuildFrame_Update; |
InspectGuildFrame_Update=function(...) |
if InspectFrame.unit and UnitExists(InspectFrame.unit) then |
return oldfunc2(...); |
end |
end; |
end |
|
if IsAddOnLoaded("Blizzard_InspectUI") then |
patch(); |
else |
local eframe=CreateFrame("Frame"); |
eframe:RegisterEvent("ADDON_LOADED"); |
eframe:SetScript("OnEvent",function(self,event,arg) |
if event=="ADDON_LOADED" and arg=="Blizzard_InspectUI" then |
self:UnregisterEvent(event); |
patch(); |
end |
end); |
end |
--[[ |
End of workaround. When fixed, delete this whole block. |
]] |
|
|
local Cache = {new = function() |
local self = {} |
self.data = {} |
self.remove = function(guid) |
for i=1,#self.data do |
if guid==self.data[i].guid then |
tremove(self.data,i) |
break |
end |
end |
end |
self.removeExpired = function() |
local exptime=GetTime()-CACHE_EXPIRE |
local i=1 |
while i<=#self.data do |
if self.data[i].time<exptime then |
tremove(self.data,i) |
else |
i=i+1 |
end |
end |
end |
self.limitSize = function() |
while #self.data>CACHE_SIZE do |
tremove(self.data,1) |
end |
end |
self.add = function(guid,ilvl,missing,spec1,spec2) |
-- If unit is already in cache, remove it |
self.remove(guid) |
|
-- Add unit to end of cache |
self.data[#self.data+1] = { |
["guid"] = guid, |
["ilvl"] = ilvl, |
["missing"] = missing, |
["spec1"] = spec1, |
["spec2"] = spec2, |
["time"] = GetTime() |
} |
end |
self.find = function(guid) |
self.removeExpired() |
if CACHE_SIZE > 0 then |
for i=1,#self.data do |
if guid==self.data[i].guid then |
return self.data[i].ilvl, self.data[i].missing, self.data[i].spec1, self.data[i].spec2 |
end |
end |
end |
return nil |
end |
return self |
end} |
|
|
|
local function levelColor(iLevel) |
local max=360 |
local H=1-iLevel/max |
if H<0 then |
H=0 |
end |
|
-- Now we have the hue, convert this to rgb, then convert that to hex |
|
local R,G,B=0,0,0 |
var_h=H*6 |
if var_h==6 then |
var_h=0 |
end |
var_i=math.floor(var_h) |
var_3=var_h-var_i |
|
if var_i==0 then |
R=1 |
G=var_3 |
elseif var_i==1 then |
R=1-var_3 |
G=1 |
elseif var_i==2 then |
G=1 |
B=var_3 |
elseif var_i==3 then |
G=1-var_3 |
B=1 |
elseif var_i==4 then |
R=var_3 |
B=1 |
else |
R=1 |
B=1-var_3 |
end |
return format("%02x%02x%02x", (R*255), (G*255), (B*255) ); |
end |
|
local function getItemLevel(target) |
local total=0 |
local count=0 |
local missing=0 |
for i=1,18 do |
-- Skip shirt slot |
if i~=4 then |
-- If no item is equiped in a slot, count it as ilvl 0 |
-- An exception would be offhand when a two-hander |
-- is equipped. |
|
local level=0 |
local item=GetInventoryItemLink(target,i) |
if item ~= nil then |
_,_,_,level,_,_,_,_,loc = GetItemInfo(item) |
if loc=="INVTYPE_2HWEAPON" then |
count=count-1 |
missing=missing-1 |
end |
else |
missing=missing+1 |
end |
total=total+level |
count=count+1 |
end |
end |
if count>0 then |
return math.floor(total/count,1),missing |
else |
return 0,missing |
end |
end |
|
local function specInfo(group) |
local treename = "None" |
local primary = GetPrimaryTalentTree(true,false,group) |
if primary then |
_,treename = GetTalentTabInfo(primary,true,false,group) |
end |
local _,_,_,_,p1 = GetTalentTabInfo(1,true,false,group) |
local _,_,_,_,p2 = GetTalentTabInfo(2,true,false,group) |
local _,_,_,_,p3 = GetTalentTabInfo(3,true,false,group) |
return format( "%s (%d/%d/%d)",treename or "none",p1 or 0,p2 or 0,p3 or 0 ) |
end |
|
c = CreateFrame("Frame") |
c.TimeSinceLastUpdate = 0 |
c.currentGUID = nil -- GUID of unit that triggered NotifyInspect() call |
c.currentUnit = nil |
c.currentTime = nil |
c.inspectCache = Cache:new() |
c.inspectTime = nil |
-- c:RegisterEvent("INSPECT_READY") |
|
c:SetScript("OnEvent",function(self,event,guid,...) |
if event=="INSPECT_READY" then |
self:UnregisterEvent("INSPECT_READY") |
|
-- Now, because this fires prematurely 9 out of 10 times, |
-- and itemdata is using the streaming system, we start |
-- a timer, that will keep checking if we have everything yet. |
-- Only when we do, we can inspect the unit... |
-- This is handled in the OnUpdate event! |
-- Don't you just love how useful some events are? This event |
-- should be renamed INSPECT_KINDASORTA_READY_BUTNOTREALLY |
-- It would be just as useful, but at least have an accurate |
-- name... |
|
local active = GetActiveTalentGroup(true, false) |
if active~=1 then offspec=1 else offspec=2 end |
local spec1 = specInfo(active) |
local spec2 = specInfo(offspec) |
|
GameTooltip:AddLine( "Current Spec: "..spec1 ) |
GameTooltip:AddLine( "Alt. Spec: "..spec2 ) |
GameTooltip:AddLine( TXT_LOADING ) |
GameTooltip:Show() |
|
self.inspectTime = GetTime() + 0.2 |
end |
end) |
|
c:SetScript("OnUpdate",function(self,elapsed) |
local now = GetTime() |
|
if self.inspectTime and now >= self.inspectTime then |
local _,unit = GameTooltip:GetUnit() |
if unit then |
guid = UnitGUID(unit) |
if guid==self.currentGUID then |
-- Determine if iteminfo is complete yet |
local done = true |
for i=1,18 do |
if GetInventoryItemTexture(unit, i) and not GetInventoryItemLink(unit, i) then |
-- GetTexture always return stuff but GetLink is not. |
done = false |
break |
end |
end |
|
|
if done then |
ile,missing=getItemLevel(unit) |
local offspec=2 |
local active = GetActiveTalentGroup(true, false) |
if active~=1 then offspec=1 end |
local spec1 = specInfo(active) |
local spec2 = specInfo(offspec) |
ClearInspectPlayer() |
|
self.inspectCache.add(guid,ile,missing,spec1,spec2) |
|
-- Replace the "Loading iLvls..." text with item level info |
for i=2, GameTooltip:NumLines() do |
if (_G["GameTooltipTextLeft"..i]:GetText() or "") == TXT_LOADING then |
_G["GameTooltipTextLeft"..i]:SetFormattedText("%s", getTTilevel(ile,missing) ); |
end |
end |
GameTooltip:Show() |
|
self.inspectTime = nil |
else |
-- Nope try again in 0.2 secs |
-- print( "Data still loading..." ) |
-- Would be nice if we can do some animation |
-- in the tooltip... |
self.inspectTime = now + 0.2 |
end |
|
else |
-- Current tooltip is for different unit |
-- print( "Aborting inspection: Data is for differnt unit than target" ) |
self.inspectTime = nil |
end |
else |
-- No tooltip, no unit.... |
-- print( "Aborting inspection: No unit targeted" ) |
self.inspectTime = nil |
end |
end |
|
|
if (c.currentTime == nil) or ((now - c.currentTime) < INSPECT_DELAY) then return end |
|
-- If current tooltip is still for the requested unit, |
-- fire a notify request for it |
local _,unit = GameTooltip:GetUnit() |
if unit and (unit==self.currentUnit) and UnitIsPlayer(unit) and CheckInteractDistance(unit,1) and CanInspect(unit) then |
guid = UnitGUID(unit) |
if guid==self.currentGUID then |
-- it SEEMS that calling this several times reduces |
-- missing items. Still happens though:( |
|
self:RegisterEvent("INSPECT_READY") |
NotifyInspect(unit) |
end |
else |
-- print ("Cannot inspect unit") |
end |
c.currentTime = nil |
end) |
|
function getTTilevel(ilevel,missing) |
local color=levelColor(ilevel) |
|
local s = "iLevel: |cff"..color..tostring(ilevel).."|r" |
if missing>0 then |
s = s.." (|cffff0000"..missing.."|r items missing)" |
end |
return s |
end |
|
GameTooltip:HookScript("OnTooltipSetUnit",function(self,...) |
local _,unit = self:GetUnit(); |
if (not unit) then |
local mFocus = GetMouseFocus() |
if (mFocus) and (mFocus.unit) then |
unit=mFocus.unit |
end |
end |
|
if unit and UnitIsPlayer(unit) then |
guid = UnitGUID(unit) |
ilvl,missing,spec1,spec2 = c.inspectCache.find(guid) |
if ilvl then |
GameTooltip:AddLine( "Current Spec: "..spec1 ) |
GameTooltip:AddLine( "Alt. Spec: "..spec2 ) |
GameTooltip:AddLine( getTTilevel(ilvl,missing) ) |
GameTooltip:Show() |
else |
c.currentGUID = guid |
c.currentUnit = unit |
c.currentTime = GetTime() |
end |
end |
end); |