Compare with Previous | Blame | View Log
-- 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);