Browse Source

Initial commit

Sergio Álvarez 2 years ago
commit
84c00cac94

+ 9 - 0
Gio_Flyout.toc

@@ -0,0 +1,9 @@
+## Interface: 80000
+## Title: Gio |cff00ffffFlyout|r
+## Author: Gio
+## Version: 1.0
+## Notes: ilvl en el flyout del pj
+## X-eMail: xergio@gmail.com
+
+LibItemUpgradeInfo-1.0\LibItemUpgradeInfo-1.0.xml
+main.lua

+ 12 - 0
LibItemUpgradeInfo-1.0/CHANGES.txt

@@ -0,0 +1,12 @@
+tag 74a4893b4dd1008c1702a98bebcf0080dd1231b3 Release-80000-30
+Author:	Alar of Runetotem <alar@aspide.it>
+Date:	Thu Jul 19 22:46:27 2018 +0200
+
+BFA
+
+commit bb6dcff130a8f4298c177ef5eb5c055c905eca34
+Author: Alar of Runetotem <alar@aspide.it>
+Date:   Thu Jul 19 22:39:53 2018 +0200
+
+    TOC bump
+

+ 725 - 0
LibItemUpgradeInfo-1.0/Core.lua

@@ -0,0 +1,725 @@
+local MAJOR, MINOR = "LibItemUpgradeInfo-1.0", 30
+local type,tonumber,select,strsplit,GetItemInfoFromHyperlink=type,tonumber,select,strsplit,GetItemInfoFromHyperlink
+local unpack,GetDetailedItemLevelInfo=unpack,GetDetailedItemLevelInfo
+local library,previous = _G.LibStub:NewLibrary(MAJOR, MINOR)
+local lib=library --#lib Needed to keep Eclipse LDT happy
+if not lib then return end
+local pp=print
+--[===[@debug@
+LoadAddOn("Blizzard_DebugTools")
+LoadAddOn("LibDebug")
+if LibDebug then LibDebug() end
+--@end-debug@]===]
+--@non-debug@
+local print=function() end
+--@end-non-debug@
+--[[
+Caching system
+1	itemName	String	The name of the item.
+2	itemLink	String	The item link of the item.
+3	itemRarity	Number	The quality of the item. The value is 0 to 7, which represents Poor to Heirloom. This appears to include gains from upgrades/bonuses.
+4	itemLevel	Number	The item level of this item, not including item levels gained from upgrades. There is currently no API to get the item level including upgrades/bonuses.
+5	itemMinLevel	Number	The minimum level required to use the item, 0 meaning no level requirement.
+6	itemType	String	The type of the item: Armor, Weapon, Quest, Key, etc.
+7	itemSubType	String	The sub-type of the item: Enchanting, Cloth, Sword, etc. See itemType.
+8	itemStackCount	Number	How many of the item per stack: 20 for Runecloth, 1 for weapon, 100 for Alterac Ram Hide, etc.
+9	itemEquipLoc	String	The type of inventory equipment location in which the item may be equipped, or "" if it can't be equippable. The string returned is also the name of a global string variable e.g. if "INVTYPE_WEAPONMAINHAND" is returned, _G["INVTYPE_WEAPONMAINHAND"] will be the localized, displayable name of the location.
+10	iconFileDataID	Number	The FileDataID for the icon texture for the item.
+11	itemSellPrice	Number	The price, in copper, a vendor is willing to pay for this item, 0 for items that cannot be sold.
+12	itemClassID	Number	This is the numerical value that determines the string to display for 'itemType'.
+13	itemSubClassID	Number	This is the numerical value that determines the string to display for 'itemSubType'
+14	bindType	Number	Item binding type: 0 - none; 1 - on pickup; 2 - on equip; 3 - on use; 4 - quest.
+15	expacID	Number
+16	itemSetID	Number
+17	isCraftingReagent bool
+--]]
+-- ItemLink Constants
+local i_Name=1
+local i_Link=2
+local i_Rarity=3
+local i_Quality=3
+local i_Level=4
+local i_MinLevel =5
+local i_ClassName=6
+local i_SubClassName=7
+local i_StackCount=8
+local i_EquipLoc=9
+local i_TextureId=10
+local i_SellPrice=11
+local i_ClassID=12
+local i_SubClass_ID=13
+local i_unk1=14
+local i_unk2=15
+local i_unk3=16
+local i_unk4=17
+
+
+do
+local oGetItemInfo=GetItemInfo
+lib.itemcache=lib.itemcache or
+	setmetatable({miss=0,tot=0},{
+		__index=function(table,key)
+			if (not key) then return "" end
+			if (key=="miss") then return 0 end
+			if (key=="tot") then return 0 end
+			local cached={oGetItemInfo(key)}
+			if #cached==0 then return nil end
+			local itemLink=cached[2]
+			if not itemLink then return nil end
+			local itemID=lib:GetItemID(itemLink)
+			local quality=cached[3]
+			local cacheIt=true
+			if quality==LE_ITEM_QUALITY_ARTIFACT then 
+				local relic1, relic2, relic3 = select(4,strsplit(':', itemLink))
+				if relic1 and relic1 ~= '' and not oGetItemInfo(relic1) then cacheIt = false end
+				if relic2 and relic2 ~= '' and not oGetItemInfo(relic2) then cacheIt = false end
+				if relic3 and relic3 ~= '' and not oGetItemInfo(relic3) then cacheIt = false end
+			end
+			cached.englishClass=GetItemClassInfo(cached[12])
+			cached.englishSubClass=GetItemSubClassInfo(cached[12],cached[13])
+			if cacheIt then
+				rawset(table,key,cached)
+			end
+			table.miss=table.miss+1
+			return cached
+		end
+
+	})
+end
+local cache=lib.itemcache
+local	function CachedGetItemInfo(key,index)
+	if not key then return nil end
+	index=index or 1
+	cache.tot=cache.tot+1
+	local cached=cache[key]
+	if cached and type(cached)=='table' then
+		return select(index,unpack(cached))
+	else
+		rawset(cache,key,nil) -- voiding broken cache entry
+	end
+end
+
+local upgradeTable = {
+	[  1] = { upgrade = 1, max = 1, ilevel = 8 },
+	[373] = { upgrade = 1, max = 3, ilevel = 4 },
+	[374] = { upgrade = 2, max = 3, ilevel = 8 },
+	[375] = { upgrade = 1, max = 3, ilevel = 4 },
+	[376] = { upgrade = 2, max = 3, ilevel = 4 },
+	[377] = { upgrade = 3, max = 3, ilevel = 4 },
+	[378] = {                       ilevel = 7 },
+	[379] = { upgrade = 1, max = 2, ilevel = 4 },
+	[380] = { upgrade = 2, max = 2, ilevel = 4 },
+	[445] = { upgrade = 0, max = 2, ilevel = 0 },
+	[446] = { upgrade = 1, max = 2, ilevel = 4 },
+	[447] = { upgrade = 2, max = 2, ilevel = 8 },
+	[451] = { upgrade = 0, max = 1, ilevel = 0 },
+	[452] = { upgrade = 1, max = 1, ilevel = 8 },
+	[453] = { upgrade = 0, max = 2, ilevel = 0 },
+	[454] = { upgrade = 1, max = 2, ilevel = 4 },
+	[455] = { upgrade = 2, max = 2, ilevel = 8 },
+	[456] = { upgrade = 0, max = 1, ilevel = 0 },
+	[457] = { upgrade = 1, max = 1, ilevel = 8 },
+	[458] = { upgrade = 0, max = 4, ilevel = 0 },
+	[459] = { upgrade = 1, max = 4, ilevel = 4 },
+	[460] = { upgrade = 2, max = 4, ilevel = 8 },
+	[461] = { upgrade = 3, max = 4, ilevel = 12 },
+	[462] = { upgrade = 4, max = 4, ilevel = 16 },
+	[465] = { upgrade = 0, max = 2, ilevel = 0 },
+	[466] = { upgrade = 1, max = 2, ilevel = 4 },
+	[467] = { upgrade = 2, max = 2, ilevel = 8 },
+	[468] = { upgrade = 0, max = 4, ilevel = 0 },
+	[469] = { upgrade = 1, max = 4, ilevel = 4 },
+	[470] = { upgrade = 2, max = 4, ilevel = 8 },
+	[471] = { upgrade = 3, max = 4, ilevel = 12 },
+	[472] = { upgrade = 4, max = 4, ilevel = 16 },
+	[491] = { upgrade = 0, max = 4, ilevel = 0 },
+	[492] = { upgrade = 1, max = 4, ilevel = 4 },
+	[493] = { upgrade = 2, max = 4, ilevel = 8 },
+	[494] = { upgrade = 0, max = 6, ilevel = 0 },
+	[495] = { upgrade = 1, max = 6, ilevel = 4 },
+	[496] = { upgrade = 2, max = 6, ilevel = 8 },
+	[497] = { upgrade = 3, max = 6, ilevel = 12 },
+	[498] = { upgrade = 4, max = 6, ilevel = 16 },
+	[503] = { upgrade = 3, max = 3, ilevel = 1 },
+	[504] = { upgrade = 3, max = 4, ilevel = 12 },
+	[505] = { upgrade = 4, max = 4, ilevel = 16 },
+	[506] = { upgrade = 5, max = 6, ilevel = 20 },
+	[507] = { upgrade = 6, max = 6, ilevel = 24 },
+	[529] = { upgrade = 0, max = 2, ilevel = 0 },
+	[530] = { upgrade = 1, max = 2, ilevel = 5 },
+	[531] = { upgrade = 2, max = 2, ilevel = 10 },
+	[535] = { upgrade = 1, max = 3, ilevel = 15 },
+	[536] = { upgrade = 2, max = 3, ilevel = 30 },
+	[537] = { upgrade = 3, max = 3, ilevel = 45 },
+	[538] = { upgrade = 0, max = 3, ilevel = 0 },
+
+}
+do
+	local stub = { ilevel = 0 }
+	setmetatable(upgradeTable, { __index = function(t, key)
+		return stub
+	end})
+end
+-- Tooltip Scanning stuff
+local itemLevelPattern = _G.ITEM_LEVEL:gsub("%%d", "(%%d+)")
+local soulboundPattern = _G.ITEM_SOULBOUND
+local boePattern=_G.ITEM_BIND_ON_EQUIP
+local bopPattern=_G.ITEM_BIND_ON_PICKUP
+local boaPattern1=_G.ITEM_BIND_TO_BNETACCOUNT
+local boaPattern2=_G.ITEM_BNETACCOUNTBOUND
+local patterns={
+  [soulboundPattern]="soulbound",
+  [boePattern]="boe",
+  [bopPattern]="bop",
+  [boaPattern1]="boa",
+  [boaPattern2]="boa",
+}
+
+local scanningTooltip
+local anchor
+lib.tipCache = lib.tipCache or setmetatable({},{__index=function(table,key) return {} end})
+local tipCache = lib.tipCache
+local emptytable={}
+
+local function ScanTip(itemLink,itemLevel,show)
+	if type(itemLink)=="number" then
+		itemLink=CachedGetItemInfo(itemLink,2)
+		if not itemLink then return emptytable end
+	end
+	if type(tipCache[itemLink].ilevel)=="nil"then -- or not tipCache[itemLink].cached then
+		local cacheIt=true
+		if not scanningTooltip then
+			anchor=CreateFrame("Frame")
+			anchor:Hide()
+			scanningTooltip = _G.CreateFrame("GameTooltip", "LibItemUpgradeInfoTooltip", nil, "GameTooltipTemplate")
+		end
+		--scanningTooltip:ClearLines()
+		GameTooltip_SetDefaultAnchor(scanningTooltip,anchor)
+		local itemString=itemLink:match("|H(.-)|h")
+		local rc,message=pcall(scanningTooltip.SetHyperlink,scanningTooltip,itemString)
+		if (not rc) then
+			return emptytable
+		end
+		scanningTooltip:Show()
+		local quality,_,_,class,subclass,_,_,_,_,classIndex,subclassIndex=CachedGetItemInfo(itemLink,3)
+		
+		-- line 1 is the item name
+		-- line 2 may be the item level, or it may be a modifier like "Heroic"
+		-- check up to line 6 just in case
+		local ilevel,soulbound,bop,boe,boa,heirloom
+		if quality==LE_ITEM_QUALITY_ARTIFACT and itemLevel then 
+			local relic1, relic2, relic3 = select(4,strsplit(':', itemLink))
+			if relic1 and relic1 ~= '' and not CachedGetItemInfo(relic1) then cacheIt = false end
+			if relic2 and relic2 ~= '' and not CachedGetItemInfo(relic2) then cacheIt = false end
+			if relic3 and relic3 ~= '' and not CachedGetItemInfo(relic3) then cacheIt = false end
+			ilevel=itemLevel 
+		end
+		if show then
+			for i=1,12 do
+				local l, ltext = _G["LibItemUpgradeInfoTooltipTextLeft"..i], nil		
+				local r, rtext  = _G["LibItemUpgradeInfoTooltipTextRight"..i], nil
+				if l then
+  				ltext=l:GetText()
+  				rtext=r:GetText()
+  				_G.print(i,ltext,' - ',rtext)
+				end		
+			end
+		end
+    tipCache[itemLink]={
+      ilevel=nil,
+      soulbound=nil,
+      bop=nil,
+      boe=nil,
+      boa=nil,
+      cached=cacheIt
+    }
+    local c=tipCache[itemLink]
+		for i = 2, 6 do
+			local label, text = _G["LibItemUpgradeInfoTooltipTextLeft"..i], nil
+			if label then text=label:GetText() end
+			if text then
+        if show then _G.print("|cFFFFFF00".. text .. "|r") end
+				if c.ilevel==nil then c.ilevel = tonumber(text:match(itemLevelPattern)) end
+				for pattern,key in pairs(patterns) do
+          if type(c[key])=="nil" then
+            if text:find(pattern) then
+              if show then _G.print(text , "matched",pattern) end
+ 				      c[key]=true
+            end
+          end
+        end
+			end
+		end
+		c.ilevel=c.ilevel or itemLevel
+		itemLevel=GetDetailedItemLevelInfo(itemLink)
+		if type(c.ilevel)=="number" then
+		  c.ilevel=math.max(c.ilevel,itemLevel)
+		else
+		  c.ilevel=itemLevel
+	  end
+		
+		scanningTooltip:Hide()
+	end
+	return tipCache[itemLink]
+end
+
+
+-- GetUpgradeID(itemString)
+--
+-- Arguments:
+--   itemString - String - An itemLink or itemString denoting the item
+--
+-- Returns:
+--   Number - The upgrade ID (possibly 0), or nil if the input is invalid or
+--            does not contain upgrade info
+function lib:GetUpgradeID(itemString)
+	if type(itemString)~="string" then return end
+	local itemString = itemString:match("item[%-?%d:]+") or ""-- Standardize itemlink to itemstring
+	local instaid, _, numBonuses, affixes = select(12, strsplit(":", itemString, 15))
+	instaid=tonumber(instaid) or 7
+	numBonuses=tonumber(numBonuses) or 0
+	if instaid >0 and (instaid-4)%8==0 then
+		return tonumber((select(numBonuses + 1, strsplit(":", affixes))))
+	end
+end
+
+-- GetCurrentUpgrade(id)
+--
+-- Returns the current upgrade level of the item, e.g. 1 for a 1/2 item.
+--
+-- Arguments:
+--   id - Number - The upgrade ID of the item (obtained via GetUpgradeID())
+--
+-- Returns:
+--   Number - The current upgrade level of the item. Returns nil if the item
+--            cannot be upgraded
+function lib:GetCurrentUpgrade(id)
+	return upgradeTable[id].upgrade
+end
+
+-- GetMaximumUpgrade(id)
+--
+-- Returns the maximum upgrade level of the item, e.g. 2 for a 1/2 item.
+--
+-- Arguments:
+--   id - Number - The upgrade ID of the item (obtained via GetUpgradeID())
+--
+-- Returns:
+--   Number - The maximum upgrade level of the item. Returns nil if the item
+--            cannot be upgraded
+function lib:GetMaximumUpgrade(id)
+	return upgradeTable[id].max
+end
+
+-- GetItemLevelUpgrade(id)
+--
+-- Returns the item level increase that this upgrade is worth, e.g. 4 for a
+-- 1/2 item or 8 for a 2/2 item.
+--
+-- Arguments:
+--   id - Number - The upgrade ID of the item (obtained via GetUpgradeID())
+--
+-- Returns:
+--   Number - The item level increase of the item. Returns 0 if the item
+--            cannot be or has not been upgraded
+function lib:GetItemLevelUpgrade(id)
+	return upgradeTable[id].ilevel
+end
+
+-- GetItemUpgradeInfo(itemString)
+--
+-- Returns the current upgrade level, maximum upgrade level, and item level
+-- increase for an item.
+--
+-- Arguments:
+--   itemString - String - An itemLink or itemString denoting the item
+--
+-- Returns if the item can be upgraded:
+--   Number - The current upgrade level of the item
+--   Number - The maximum upgrade level of the item
+--   Number - The item level increase of the item
+-- or if the item cannot be upgraded:
+--   nil
+--   nil
+--   0
+-- or if the item is invalid or does not contain upgrade info:
+--   nil
+function lib:GetItemUpgradeInfo(itemString)
+	local id = self:GetUpgradeID(itemString)
+	if id then
+		local cur = self:GetCurrentUpgrade(id)
+		local max = self:GetMaximumUpgrade(id)
+		local delta = self:GetItemLevelUpgrade(id)
+		return cur, max, delta
+	end
+	return nil
+end
+
+-- GetHeirloomTrueLevel(itemString)
+--
+-- Returns the true item level for an heirloom (actually, returns the true level for any adapting item)
+--
+-- Arguments:
+--   itemString - String - An itemLink or itemString denoting the item
+--
+-- Returns:
+--   Number, Boolean - The true item level of the item. If the item is not
+--                     an heirloom, or an error occurs when trying to scan the
+--                     item tooltip, the second return value is false. Otherwise
+--                     the second return value is true. If the input is invalid,
+--                     (nil, false) is returned.
+-- Convert the ITEM_LEVEL constant into a pattern for our use
+function lib:GetHeirloomTrueLevel(itemString)
+	if type(itemString) ~= "string" then return nil,false end
+	local _, itemLink, rarity, itemLevel = CachedGetItemInfo(itemString)
+	if (not itemLink) then
+		return nil,false
+	end
+	local rc=ScanTip(itemLink,itemLevel)
+	if rc.ilevel then
+		return rc.ilevel,true
+	end
+	return itemLevel, false
+end
+
+-- GetUpgradedItemLevel(itemString)
+--
+-- Returns the true item level of the item, including upgrades and heirlooms.
+--
+-- Arguments:
+--   itemString - String - An itemLink or itemString denoting the item
+--
+-- Returns:
+--   Number - The true item level of the item, or nil if the input is invalid
+function lib:GetUpgradedItemLevel(itemString)
+	-- check for heirlooms first
+	local ilvl, isTrue = self:GetHeirloomTrueLevel(itemString)
+	if isTrue then
+		return ilvl
+	end
+	-- not an heirloom? fall back to the regular item logic
+	local id = self:GetUpgradeID(itemString)
+	if ilvl and id then
+		ilvl = ilvl + self:GetItemLevelUpgrade(id)
+	end
+	return ilvl
+end
+
+-- IsBop(itemString)
+--
+-- Check an item for  Bind On Pickup.
+--
+-- Arguments:
+--   itemString - String - An itemLink or itemString denoting the item
+--
+-- Returns:
+--   Boolean - True if Bind On Pickup
+
+function lib:IsBop(itemString)
+	local rc=ScanTip(itemString)
+	return rc.bop
+end
+-- IsBoe(itemString)
+--
+-- Check an item for  Bind On Equip.
+--
+-- Arguments:
+--   itemString - String - An itemLink or itemString denoting the item
+--
+-- Returns:
+--   Boolean - True if Bind On Equip
+
+function lib:IsBoe(itemString)
+	local rc=ScanTip(itemString)
+	return rc.boe
+end
+-- IsBoa(itemString)
+--
+-- Check an item for  Bind On Aaccount
+--
+-- Arguments:
+--   itemString - String - An itemLink or itemString denoting the item
+--
+-- Returns:
+--   Boolean - True if Bind On Equip
+
+function lib:IsBoa(itemString)
+	local rc=ScanTip(itemString)
+	return rc.boa
+end
+
+-- IsArtifact(itemString)
+--
+-- Check an item for  Heirloom
+--
+-- Arguments:
+--   itemString - String - An itemLink or itemString denoting the item
+--
+-- Returns:
+--   Boolean - True if Artifact
+
+function lib:IsArtifact(itemString)
+	return CachedGetItemInfo(itemString,i_Quality)==LE_ITEM_QUALITY_ARTIFACT
+end
+
+-- GetClassInfoIsHeirloom(itemString)
+--
+-- Retrieve class and subclass
+--
+-- Arguments:
+--   itemString - String - An itemLink or itemString denoting the item
+--
+-- Returns:
+--   class,subclass
+
+
+function lib:GetClassInfo(itemString)
+	local rc=ScantTip(itemString)
+	return rc.class,rc.subclass
+end
+
+
+-- IsHeirloom(itemString)
+--
+-- Check an item for  Heirloom
+--
+-- Arguments:
+--   itemString - String - An itemLink or itemString denoting the item
+--
+-- Returns:
+--   Boolean - True if Heirloom
+
+function lib:IsHeirloom(itemString)
+	return CachedGetItemInfo(itemString,i_Quality) ==LE_ITEM_QUALITY_HEIRLOOM
+end
+---
+-- Parses an itemlink and returns itemId without calling API again
+-- @param #lib self
+-- @param #string itemlink
+-- @return #number itemId or 0
+function lib:GetItemID(itemlink)
+	if (type(itemlink)=="string") then
+			local itemid,context=GetItemInfoFromHyperlink(itemlink)
+			return tonumber(itemid) or 0
+			--return tonumber(itemlink:match("Hitem:(%d+):")) or 0
+	else
+			return 0
+	end
+end
+
+---
+--
+-- Returns a caching version of GetItemInfo. Can be used to override the original one.
+-- Adds a second parameter to directly retrieving a specific value
+-- (Note: internally uses select so it's actually like calling select(n,GetItemInfo(itemID))
+--
+-- Arguments:
+--   self #lib self
+--
+-- Returns:
+--   #function The new function
+
+--@do-not-package--
+local slots={
+INVSLOT_AMMO    = INVSLOT_AMMO,
+INVSLOT_HEAD    = INVSLOT_HEAD,
+INVSLOT_NECK    = INVSLOT_NECK,
+INVSLOT_SHOULDER  = INVSLOT_SHOULDER,
+INVSLOT_BODY    = INVSLOT_BODY,
+INVSLOT_CHEST   = INVSLOT_CHEST,
+INVSLOT_WAIST   = INVSLOT_WAIST,
+INVSLOT_LEGS    = INVSLOT_LEGS,
+INVSLOT_FEET    = INVSLOT_FEET,
+INVSLOT_WRIST   = INVSLOT_WRIST,
+INVSLOT_HAND    = INVSLOT_HAND,
+INVSLOT_FINGER1 = INVSLOT_FINGER1,
+INVSLOT_FINGER2 = INVSLOT_FINGER2,
+INVSLOT_TRINKET1  = INVSLOT_TRINKET1,
+INVSLOT_TRINKET2  = INVSLOT_TRINKET2,
+INVSLOT_BACK    = INVSLOT_BACK,
+INVSLOT_MAINHAND  = INVSLOT_MAINHAND,
+INVSLOT_OFFHAND = INVSLOT_OFFHAND,
+INVSLOT_RANGED    = INVSLOT_RANGED,
+INVSLOT_TABARD    = INVSLOT_TABARD,
+}
+local INVSLOT_FIRST_EQUIPPED = INVSLOT_FIRST_EQUIPPED;
+local INVSLOT_LAST_EQUIPPED = INVSLOT_LAST_EQUIPPED
+_G.SLASH_CHECKSLOT1="/checkslot"
+SlashCmdList['CHECKSLOT'] = function(args,chatframe)
+  _G.print(args)
+  local slot=strsplit(' ',args)
+  if not slot or slot=="" then
+    DevTools_Dump(slots)
+    return
+  end
+  slot=tonumber(slot)
+  local itemlink=GetInventoryItemLink("player",slot)
+  if itemlink then
+    for k,v in pairs(slots) do
+      if slot==v then _G.print("Item in " , k) break end
+    end
+    _G.print(itemlink)
+    DevTools_Dump({GetDetailedItemLevelInfo(itemlink)})
+    print(itemlink)
+    _G.print(lib:ScanTip(itemlink))
+  end
+end
+function lib:ScanTip(itemLink)
+  --self.itemcache[itemLink]=nil
+  self.tipCache[itemLink]=nil
+	local GameTooltip=_G.LibItemUpgradeInfoTooltip
+	if GameTooltip then
+		GameTooltip_SetDefaultAnchor(GameTooltip, UIParent)
+		GameTooltip:SetHyperlink(itemLink)
+		GameTooltip:Show()
+	end
+	return ScanTip(itemLink,100,true)
+end
+function lib:GetCachingGetItemInfo()
+	return CachedGetItemInfo
+end
+function lib:GetCacheStats()
+	local c=lib.itemcache
+	local h=c.tot-c.miss
+	local perc=( h>0) and h/c.tot*100 or 0
+	return c.miss,h,perc
+end
+function lib:GetCache()
+	return lib.itemcache
+end
+function lib:CleanCache()
+	return wipe(lib.itemcache)
+end
+
+--[===========[ ]===========]
+--[===[ Debug utilities ]===]
+--[===========[ ]===========]
+
+local function compareTables(t1, t2)
+	local seen = {}
+	for k, v1 in pairs(t1) do
+		seen[k] = true
+		local v2 = rawget(t2, k)
+		if not v2 then return false end
+		if type(v1) ~= type(v2) then return false end
+		if type(v1) == "table" then
+			if not compareTables(v1, v2) then return false end
+		elseif v1 ~= v2 then return false end
+	end
+	for k in pairs(t2) do
+		if not seen[k] then return false end
+	end
+	return true
+end
+
+-- prints the table rows in red and green
+-- omits the lead { and the trailing }
+local function printDiffTable(t1, t2)
+	local keys, seen = {}, {}
+	for k in pairs(t1) do
+		keys[#keys+1] = k
+		seen[k] = true
+	end
+	for k in pairs(t2) do
+		if not seen[k] then
+			keys[#keys+1] = k
+		end
+	end
+	table.sort(keys)
+	local function formatTable(t)
+		local comps = {}
+		for k, v in pairs(t) do
+			comps[#comps+1] = ("%s = %d"):format(k, v)
+		end
+		return "{ " .. table.concat(comps, ", ") .. " }"
+	end
+	for _, k in ipairs(keys) do
+		local v1, v2 = rawget(t1, k), rawget(t2, k)
+		local equal
+		if type(v1) == "table" and type(v2) == "table" then equal = compareTables(v1, v2)
+		else equal = v1 == v2 end
+		if not equal then
+			if v1 then
+				pp(("|cffff0000    [%d] = %s,|r"):format(k, formatTable(v1)))
+			end
+			if v2 then
+				pp(("|cff00ff00    [%d] = %s,|r"):format(k, formatTable(v2)))
+			end
+		end
+	end
+end
+
+-- Scans the first 10000 upgrade IDs
+-- Run this with /run LibStub:GetLibrary("LibItemUpgradeInfo-1.0"):_CheckUpgradeTable()
+-- If you don't have Aspirant's Staff of Harmony cached it may error out, just try again.
+do
+	local debugFrame
+	local worker
+	local newTable
+	local debugTooltip
+	function lib:_CheckUpgradeTable(itemLink)
+		if worker then
+			pp("|cffff0000LibItemUpgradeInfo-1.0: upgrade check already in progress")
+			return
+		end
+		if not debugFrame then
+			debugFrame = _G.CreateFrame("frame")
+			debugFrame:Hide()
+			debugFrame:SetScript("OnUpdate", function()
+				local ok, result, count, max = pcall(worker)
+				if not ok or result then
+					debugFrame:Hide()
+					worker = nil
+				end
+				if not ok then
+					pp("|cffff0000LibItemUpgradeInfo-1.0 error: " .. result .. "|r")
+				elseif result then
+					pp("LibItemUpgradeInfo-1.0: scan complete")
+					if compareTables(upgradeTable, newTable) then
+						pp("LibItemUpgradeInfo-1.0: |cff00ff00No changes|r")
+					else
+						pp("LibItemUpgradeInfo-1.0: |cffff0000New table:|r {")
+						printDiffTable(upgradeTable, newTable)
+						pp("}")
+					end
+				else
+					pp("LibItemUpgradeInfo-1.0: scanning " .. count .. "/" .. max)
+				end
+			end)
+		end
+		if not debugTooltip then
+			debugTooltip = _G.CreateFrame("GameTooltip", "LibItemUpgradeInfoDebugTooltip", nil, "GameTooltipTemplate")
+			debugTooltip:SetOwner(_G.WorldFrame, "ANCHOR_NONE")
+		end
+		newTable = {}
+		--local itemLink = "|cff0070dd|Hitem:89551:0:0:0:0:0:0:0:90:253:0:0:1:0|h[Aspirant's Staff of Harmony]|h|r"
+		local itemLink = itemLink or "|cff0070dd|Hitem:89551:0:0:0:0:0:0:0:100:253:4:0:0:0|h[Aspirant's Staff of Harmony]|h|r"
+-- Livello è il 9,upgradeid il 14. Al decimo posto, un valore che deve essere 4 o 4+n *8) per far scattare l'uso dell'upgradeid
+		local itemLevel = select(4, _G.GetItemInfo(itemLink))
+		assert(itemLevel, "Can't find item level for itemLink")
+		local count, max, batchsize = 0, 10000, 200
+		worker = function()
+			for i = count, math.min(max, count+batchsize) do
+				local link = itemLink:gsub("%d+|h", i.."|h")
+				debugTooltip:ClearLines()
+				debugTooltip:SetHyperlink(link)
+				local upgrade, max
+				local curLevel, maxLevel = _G.LibItemUpgradeInfoDebugTooltipTextLeft3:GetText():match("^Upgrade Level: (%d+)/(%d+)")
+				local ilvl = tonumber(_G.LibItemUpgradeInfoDebugTooltipTextLeft2:GetText():match("Item Level (%d+)"))
+				if not ilvl then
+					ilvl = tonumber(_G.LibItemUpgradeInfoDebugTooltipTextLeft3:GetText():match("Item Level (%d+)"))
+				end
+				assert(ilvl ~= nil, "Can't find ItemLevel in tooltip: " .. _G.LibItemUpgradeInfoDebugTooltipTextLeft2:GetText())
+				if curLevel or maxLevel or ilvl ~= itemLevel then
+					newTable[i] = { upgrade = tonumber(curLevel), max = tonumber(maxLevel), ilevel = ilvl - itemLevel }
+				end
+			end
+			count = count + batchsize
+			return (count > max), count, max
+		end
+		debugFrame:Show()
+	end
+end
+--@end-do-not-package--
+
+-- vim: set noet sw=4 ts=4:

+ 9 - 0
LibItemUpgradeInfo-1.0/LibItemUpgradeInfo-1.0.toc

@@ -0,0 +1,9 @@
+## Interface: 80000
+## Title: Lib: ItemUpgradeInfo-1.0
+## Notes: Database of item upgrade IDs
+## Author: eridius
+## Version: Release-80000-30 70200
+## X-Revision: bb6dcff
+## X-Category: Library
+
+LibItemUpgradeInfo-1.0.xml

+ 4 - 0
LibItemUpgradeInfo-1.0/LibItemUpgradeInfo-1.0.xml

@@ -0,0 +1,4 @@
+<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/..\FrameXML\UI.xsd">
+	<Script file="LibStub\LibStub.lua"/>
+	<Script file="Core.lua"/>
+</Ui>

+ 51 - 0
LibItemUpgradeInfo-1.0/LibStub/LibStub.lua

@@ -0,0 +1,51 @@
+-- $Id: LibStub.lua 76 2007-09-03 01:50:17Z mikk $
+-- LibStub is a simple versioning stub meant for use in Libraries.  http://www.wowace.com/wiki/LibStub for more info
+-- LibStub is hereby placed in the Public Domain
+-- Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel, joshborke
+local LIBSTUB_MAJOR, LIBSTUB_MINOR = "LibStub", 2  -- NEVER MAKE THIS AN SVN REVISION! IT NEEDS TO BE USABLE IN ALL REPOS!
+local LibStub = _G[LIBSTUB_MAJOR]
+
+-- Check to see is this version of the stub is obsolete
+if not LibStub or LibStub.minor < LIBSTUB_MINOR then
+	LibStub = LibStub or {libs = {}, minors = {} }
+	_G[LIBSTUB_MAJOR] = LibStub
+	LibStub.minor = LIBSTUB_MINOR
+	
+	-- LibStub:NewLibrary(major, minor)
+	-- major (string) - the major version of the library
+	-- minor (string or number ) - the minor version of the library
+	-- 
+	-- returns nil if a newer or same version of the lib is already present
+	-- returns empty library object or old library object if upgrade is needed
+	function LibStub:NewLibrary(major, minor)
+		assert(type(major) == "string", "Bad argument #2 to `NewLibrary' (string expected)")
+		minor = assert(tonumber(strmatch(minor, "%d+")), "Minor version must either be a number or contain a number.")
+		
+		local oldminor = self.minors[major]
+		if oldminor and oldminor >= minor then return nil end
+		self.minors[major], self.libs[major] = minor, self.libs[major] or {}
+		return self.libs[major], oldminor
+	end
+	
+	-- LibStub:GetLibrary(major, [silent])
+	-- major (string) - the major version of the library
+	-- silent (boolean) - if true, library is optional, silently return nil if its not found
+	--
+	-- throws an error if the library can not be found (except silent is set)
+	-- returns the library object if found
+	function LibStub:GetLibrary(major, silent)
+		if not self.libs[major] and not silent then
+			error(("Cannot find a library instance of %q."):format(tostring(major)), 2)
+		end
+		return self.libs[major], self.minors[major]
+	end
+	
+	-- LibStub:IterateLibraries()
+	-- 
+	-- Returns an iterator for the currently registered libraries
+	function LibStub:IterateLibraries() 
+		return pairs(self.libs) 
+	end
+	
+	setmetatable(LibStub, { __call = LibStub.GetLibrary })
+end

+ 9 - 0
LibItemUpgradeInfo-1.0/LibStub/LibStub.toc

@@ -0,0 +1,9 @@
+## Interface: 70200
+## Title: Lib: LibStub
+## Notes: Universal Library Stub
+## Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel
+## X-Website: http://www.wowace.com/addons/libstub/
+## X-Category: Library
+## X-License: Public Domain	
+
+LibStub.lua

+ 41 - 0
LibItemUpgradeInfo-1.0/LibStub/tests/test.lua

@@ -0,0 +1,41 @@
+debugstack = debug.traceback
+strmatch = string.match
+
+loadfile("../LibStub.lua")()
+
+local lib, oldMinor = LibStub:NewLibrary("Pants", 1) -- make a new thingy
+assert(lib) -- should return the library table
+assert(not oldMinor) -- should not return the old minor, since it didn't exist
+
+-- the following is to create data and then be able to check if the same data exists after the fact
+function lib:MyMethod()
+end
+local MyMethod = lib.MyMethod
+lib.MyTable = {}
+local MyTable = lib.MyTable
+
+local newLib, newOldMinor = LibStub:NewLibrary("Pants", 1) -- try to register a library with the same version, should silently fail
+assert(not newLib) -- should not return since out of date
+
+local newLib, newOldMinor = LibStub:NewLibrary("Pants", 0) -- try to register a library with a previous, should silently fail
+assert(not newLib) -- should not return since out of date
+
+local newLib, newOldMinor = LibStub:NewLibrary("Pants", 2) -- register a new version
+assert(newLib) -- library table
+assert(rawequal(newLib, lib)) -- should be the same reference as the previous
+assert(newOldMinor == 1) -- should return the minor version of the previous version
+
+assert(rawequal(lib.MyMethod, MyMethod)) -- verify that values were saved
+assert(rawequal(lib.MyTable, MyTable)) -- verify that values were saved
+
+local newLib, newOldMinor = LibStub:NewLibrary("Pants", "Blah 3 Blah") -- register a new version with a string minor version (instead of a number)
+assert(newLib) -- library table
+assert(newOldMinor == 2) -- previous version was 2
+
+local newLib, newOldMinor = LibStub:NewLibrary("Pants", "Blah 4 and please ignore 15 Blah") -- register a new version with a string minor version (instead of a number)
+assert(newLib)
+assert(newOldMinor == 3) -- previous version was 3 (even though it gave a string)
+
+local newLib, newOldMinor = LibStub:NewLibrary("Pants", 5) -- register a new library, using a normal number instead of a string
+assert(newLib)
+assert(newOldMinor == 4) -- previous version was 4 (even though it gave a string)

+ 27 - 0
LibItemUpgradeInfo-1.0/LibStub/tests/test2.lua

@@ -0,0 +1,27 @@
+debugstack = debug.traceback
+strmatch = string.match
+
+loadfile("../LibStub.lua")()
+
+for major, library in LibStub:IterateLibraries() do
+	-- check that MyLib doesn't exist yet, by iterating through all the libraries
+	assert(major ~= "MyLib")
+end
+
+assert(not LibStub:GetLibrary("MyLib", true)) -- check that MyLib doesn't exist yet by direct checking
+assert(not pcall(LibStub.GetLibrary, LibStub, "MyLib")) -- don't silently fail, thus it should raise an error.
+local lib = LibStub:NewLibrary("MyLib", 1) -- create the lib
+assert(lib) -- check it exists
+assert(rawequal(LibStub:GetLibrary("MyLib"), lib)) -- verify that :GetLibrary("MyLib") properly equals the lib reference
+
+assert(LibStub:NewLibrary("MyLib", 2))	-- create a new version
+
+local count=0
+for major, library in LibStub:IterateLibraries() do
+	-- check that MyLib exists somewhere in the libraries, by iterating through all the libraries
+	if major == "MyLib" then -- we found it!
+		count = count +1
+		assert(rawequal(library, lib)) -- verify that the references are equal
+	end
+end
+assert(count == 1) -- verify that we actually found it, and only once

+ 14 - 0
LibItemUpgradeInfo-1.0/LibStub/tests/test3.lua

@@ -0,0 +1,14 @@
+debugstack = debug.traceback
+strmatch = string.match
+
+loadfile("../LibStub.lua")()
+
+local proxy = newproxy() -- non-string
+
+assert(not pcall(LibStub.NewLibrary, LibStub, proxy, 1)) -- should error, proxy is not a string, it's userdata
+local success, ret = pcall(LibStub.GetLibrary, proxy, true)
+assert(not success or not ret) -- either error because proxy is not a string or because it's not actually registered.
+
+assert(not pcall(LibStub.NewLibrary, LibStub, "Something", "No number in here")) -- should error, minor has no string in it.
+
+assert(not LibStub:GetLibrary("Something", true)) -- shouldn't've created it from the above statement

+ 41 - 0
LibItemUpgradeInfo-1.0/LibStub/tests/test4.lua

@@ -0,0 +1,41 @@
+debugstack = debug.traceback
+strmatch = string.match
+
+loadfile("../LibStub.lua")()
+
+
+-- Pretend like loaded libstub is old and doesn't have :IterateLibraries
+assert(LibStub.minor)
+LibStub.minor = LibStub.minor - 0.0001
+LibStub.IterateLibraries = nil
+
+loadfile("../LibStub.lua")()
+
+assert(type(LibStub.IterateLibraries)=="function")
+
+
+-- Now pretend that we're the same version -- :IterateLibraries should NOT be re-created
+LibStub.IterateLibraries = 123
+
+loadfile("../LibStub.lua")()
+
+assert(LibStub.IterateLibraries == 123)
+
+
+-- Now pretend that a newer version is loaded -- :IterateLibraries should NOT be re-created
+LibStub.minor = LibStub.minor + 0.0001
+
+loadfile("../LibStub.lua")()
+
+assert(LibStub.IterateLibraries == 123)
+
+
+-- Again with a huge number
+LibStub.minor = LibStub.minor + 1234567890
+
+loadfile("../LibStub.lua")()
+
+assert(LibStub.IterateLibraries == 123)
+
+
+print("OK")

+ 4 - 0
README.md

@@ -0,0 +1,4 @@
+
+- Item Level in character flyouts
+
+![example](https://i.imgur.com/WG3SYRW.png)

+ 68 - 0
main.lua

@@ -0,0 +1,68 @@
+
+local IUI = LibStub("LibItemUpgradeInfo-1.0")
+
+local GREY = {0.55, 0.55, 0.55}
+local GREEN = {0, 1, 0}
+local WHITE = {1, 1, 1}
+
+-- thank you SyLevel!
+local function getItemLink(location)
+    -- https://www.townlong-yak.com/framexml/27219/EquipmentManager.lua#276
+    local player, bank, bags, voidStorage, slot, bag, tab, voidSlot = EquipmentManager_UnpackLocation(location)
+
+    if ( not player and not bank and not bags and not voidStorage ) then
+        return
+    end
+
+    if not bags then -- player or bank
+        return GetInventoryItemLink('player', slot)
+    else -- bags
+        return GetContainerItemLink(bag, slot)
+    end
+end
+
+local createText = function(button)
+    local label = button.GioFlyout
+
+    if (not label) then
+        label = button:CreateFontString(nil,"OVERLAY")
+        label:SetFont("Fonts\\FRIZQT__.TTF", 14, "OUTLINE")
+        label:SetPoint("CENTER", button, "CENTER", 0, 0)
+        button.GioFlyout = label
+    end
+
+    return label
+end
+
+local function RelativeColor(ilvl)
+    --[[local avgItemLevel, avgItemLevelEquipped = GetAverageItemLevel()
+    local e = math.floor(avgItemLevelEquipped)
+
+    if ilvl < e then
+        return unpack(GREY)
+    elseif ilvl > e then
+        return unpack(GREEN)
+    else
+        return unpack(WHITE)
+    end]]
+    return unpack(WHITE)
+end
+
+local function hook_EquipmentFlyout_DisplayButton(button)
+    -- https://www.townlong-yak.com/framexml/27219/EquipmentFlyout.lua#370
+    local location = button.location
+
+    if (location and location < EQUIPMENTFLYOUT_FIRST_SPECIAL_LOCATION) then
+        local link = getItemLink(location)
+        local ilvl = IUI:GetUpgradedItemLevel(link)
+
+        local label = createText(button)
+        label:SetTextColor(RelativeColor(ilvl))
+        label:SetText(ilvl)
+        label:Show()
+    end
+
+end
+
+hooksecurefunc('EquipmentFlyout_DisplayButton', hook_EquipmentFlyout_DisplayButton)
+--IUI:GetUpgradedItemLevel(location)