Item Level

UI and Macro
How can you get the Item Level of an upgraded item? I upgraded my 463 shoulders to 471 but GetItemInfo() is still returning 463.

/dump GetInventoryItemLink('player', INVSLOT_SHOULDER);
[1]="|cff0070dd|Hitem:81287:4805:4585:0:0:0:0:-2058788992:90:126:452|h[Spaulders of Immovable Stone]|h|r"

/dump GetItemInfo(GetInventoryItemLink('player', INVSLOT_SHOULDER))
[1]="Spaulders of Immovable Stone",
[2]="|cff0070dd|Hitem:81287:4805:4585:0:0:0:0:-2058788992:90:126:452|h[Spaulders of Immovable Stone]|h|r",
You item string example maps as follows:

item : itemId : enchantId : jewelId1 : jewelId2 : jewelId3 : jewelId4 : suffixId : uniqueId : linkLevel : reforgeId : unkown
item : 81287 : 4805 : 4585 : 0 : 0 : 0 : 0 : -2058788992 : 90 : 126 : 452

So I assume it's either buried in the suffixId or in the "unknown".

BTW: We need both the ability to get the "upgraded" iLevel AND STATS of an item, but we also need the ability to query the currently used and max possible upgrades on an item. It's in the tooltips so the data's there, but official API functions instead of itemString parsing would be very, very helpful.

Its the unknown value but how it translates is still unknown. We figured this out last night in #wowuidev using a 509 Heroic Shoulder

Value Upgrade iLevel
450 none 509
451 0/1 509
452 1/1 517
453 0/2 509
454 1/2 513
455 2/2 517
456 0/1 509
457 1/1 517
458 0/4 509
459 1/4 513
Interesting stuff. I hope we can flesh this out because I'm writing an addon that checks gear and this is exactly what I need for it.

If I can help, please feel free to hit me up.
FYI: I don't think the unknown values map to an exact iLevel. For example, I upgraded my 463 Lightbreaker Greatsword from 0/1 and it got unknown 452 with 1/1 and iLevel 471.

Maybe it's more like 452 means 1/1 upgrade slots filled on Rare quality item by Justice Points causing +8 iLevel increase...

Here is some in-game testing and not using a for loop

Upgrade iLevel Value Item

0/1 463 451 81577 Lightbreaker Greatsword
1/1 471 452 81287 Spaulders of the Immovable Stone

0/2 483 445 86823 Windblade Talons
0/2 489 445 86134 Star-Stealer Waistguard
1/2 480 446 90907 Boots of Unbreakable Umbrage
1/2 493 446 89067 Links of the Lucid
1/2 500 446 86160 Mail of Screaming Secrests
2/2 484 447 79343 Inscribed Tiger Staff
2/2 504 447 87403 Chestplate of Limitless Faith

1/2 513 446 86958 Twisting Wind Bracers
A blue post or someone who is better at interpreting the ui would be great.
Yeah this is a good thing for blues to get word back from the devs.

One possible idea of getting a larger sample size across levels is looping through a tailor/smith/LW's tradeskill links. For each link do another loop with incrementing 11th item ids and create a tooltip from each and scan for an upgrade on the tooltip. Write the results to a table/savedvars and you could get a big enough sample to see any trends in bitfield or whatever. Actually I'll see what I can do tonight this is pretty simple to do.
Inelegant, but I'm pretty confident this will return the adjusted item level of an item link (or nil if it has no level):

function GetActualItemLevel(link)
local levelAdjust={ -- 11th item:id field and level adjustment
local baseLevel = select(4,GetItemInfo(link))
local upgrade = link:match(":(%d+)\124h%[")
if baseLevel and upgrade then
return baseLevel + levelAdjust[upgrade]
return baseLevel

If you're curious about the testing method, you can read on.

StartupSavedVars.levels = {} -- savedvar
local upgrade,link,level,id,name
for trade=1,GetNumTradeSkills() do
link = GetTradeSkillItemLink(trade)
if link then
if name then
id = link:match("item:(%d+)")
table.insert(StartupSavedVars.levels,format("name:%s ilvl:%s id:%s",name,level,id))
for i=0,512 do -- this will lock up client for a while, be patient!
upgrade = GameTooltipTextLeft3:GetText()
if upgrade:match("^Upgrade Level: ") then
table.insert(StartupSavedVars.levels,format("11th:%s up:%s",i,upgrade))

The above showed that over 235 items on my tailor (and double checked with my LW), on every item level, from a Green Workman's Shirt (ilevel 1) to a Spelltwister's Grand Robe (ilevel 476), they all reacted the same when trying to use a value from 0 to 512 in the 11th item:id field:

001 Upgrade Level: 1/1
373 Upgrade Level: 1/2
374 Upgrade Level: 2/2
375 Upgrade Level: 1/3
376 Upgrade Level: 2/3
377 Upgrade Level: 3/3
379 Upgrade Level: 1/2
380 Upgrade Level: 2/2
445 Upgrade Level: 0/2
446 Upgrade Level: 1/2
447 Upgrade Level: 2/2
451 Upgrade Level: 0/1
452 Upgrade Level: 1/1
453 Upgrade Level: 0/2
454 Upgrade Level: 1/2
455 Upgrade Level: 2/2
456 Upgrade Level: 0/1
457 Upgrade Level: 1/1
458 Upgrade Level: 0/4
459 Upgrade Level: 1/4
460 Upgrade Level: 2/4
461 Upgrade Level: 3/4
462 Upgrade Level: 4/4

Once that was establish, a level comparison test was done limiting the 11th fields to the 23 valid values (the above test locked up client for a while as is):

local ups = {1,373,374,375,376,377,379,380,445,446,447,451,452,453,454,455,456,457,458,459,460,461,462 }
StartupSavedVars.levels = {} -- savedvar
local upgrade,link,level,id,name,newlevel
for trade=1,GetNumTradeSkills() do
link = GetTradeSkillItemLink(trade)
if link then
if name then
id = link:match("item:(%d+)")
table.insert(StartupSavedVars.levels,format("name:%s ilvl:%s id:%s",name,level,id))
link = link:gsub(":%d+\124h%[",":%%s\124h%[")
for _,i in pairs(ups) do
upgrade = GameTooltipTextLeft3:GetText()
if upgrade and upgrade:match("^Upgrade Level: ") then
newlevel = GameTooltipTextLeft2:GetText():match("Item Level (%d+)") - level
table.insert(StartupSavedVars.levels,format("11th:%s up:%s +lvl:%s",i,upgrade,newlevel))

And spot checking a bunch of items this looked to be consistent:

001 up:Upgrade Level: 1/1 +lvl:8
373 up:Upgrade Level: 1/2 +lvl:4
374 up:Upgrade Level: 2/2 +lvl:8
375 up:Upgrade Level: 1/3 +lvl:4
376 up:Upgrade Level: 2/3 +lvl:4
377 up:Upgrade Level: 3/3 +lvl:4
379 up:Upgrade Level: 1/2 +lvl:4
380 up:Upgrade Level: 2/2 +lvl:4
445 up:Upgrade Level: 0/2 +lvl:0
446 up:Upgrade Level: 1/2 +lvl:4
447 up:Upgrade Level: 2/2 +lvl:8
451 up:Upgrade Level: 0/1 +lvl:0
452 up:Upgrade Level: 1/1 +lvl:8
453 up:Upgrade Level: 0/2 +lvl:0
454 up:Upgrade Level: 1/2 +lvl:4
455 up:Upgrade Level: 2/2 +lvl:8
456 up:Upgrade Level: 0/1 +lvl:0
457 up:Upgrade Level: 1/1 +lvl:8
458 up:Upgrade Level: 0/4 +lvl:0
459 up:Upgrade Level: 1/4 +lvl:4
460 up:Upgrade Level: 2/4 +lvl:8
461 up:Upgrade Level: 3/4 +lvl:12
462 up:Upgrade Level: 4/4 +lvl:16

With the run of 4's in the 375-380 range, I don't think there's any mathematical pattern. These looks like arbitrary values (but I could be wrong)

So you can use those values in a table to know how much to adjust item level by. Doesn't help a whole lot with actual stats. I think we're still stuck scanning tooltips for that.
Thanks Ro, I added it to my addon, Simple iLevel with some debug code and it looks spot on, grab 3.2.1-alpha and then run /sil debug to enable it.
Doesn't help a whole lot with actual stats. I think we're still stuck scanning tooltips for that.

Fairly new to addon development, how would one go about scanning said tooltip for stats? As far as I can tell, GetItemStats() returns the stats of the base item only, regardless of upgrades.
To scan a tooltip you create a GameTooltip (the code above uses the default's GameTooltip) that inherits GameTooltipTemplate, use one of the :SetSomething widgets to the tooltip (like :SetInventoryItem) and then GetText the lines from the tooltip the client creates. Then parse the string text for info you're interested in.

This is a relatively computationally expensive process. It's fine for totaling up stats on an INSPECT_READY or something equally infrequent, but avoid using it in anything related to a BAG_UPDATE or UNIT_AURAS or anything frequent unless you're very careful/extensively caching.

For dealing with items you'll be using SetInventoryItem, SetBagItem and SetHyperlink mostly. Make sure you poke at the tooltips thoroughly and never blindly believe what you expect them to contain. There's a lot of subtle variations. For instance on the surface these seem to be identical:
local g=MyTooltipScan or CreateFrame("GameTooltip","MyTooltipScan",UIParent,"GameTooltipTemplate")
for i=1,g:NumLines() do

local g=MyTooltipScan or CreateFrame("GameTooltip","MyTooltipScan",UIParent,"GameTooltipTemplate")
for i=1,g:NumLines() do

But they're not. The SetHyperlink won't include the lines for transmog changes. SetInventoryItem will. Lines can appear from all sorts of things so be prepared to not make any assumptions.

That said, the 5.1 tooltip change has made it a little easier to lift stats. We no longer have to create regular expressions to lift out stats from "english" text. Almost every stat increase is in the format "+number Stat". But we still have to account for greyed out stats (GetTextColor), some stats aren't a single word ("PvP Power") and there will always be exceptions ("+80 All Stats") to account for. So some massaging of the text is still needed.

Here's example code that adds up all the stats on worn gear. Note it doesn't handle "All Stats" well and there may be other examples I'm missing. But it's a start:
-- adds the stats from the passed link to the passed table (which can be empty but not nil)
function AddTooltipItemStats(link,rtable)
if not link then return end
if not AddTooltipItemStatsTooltip then
local tooltip = AddTooltipItemStatsTooltip
for line = 1,tooltip:NumLines() do
local tooltipLine = _G["AddTooltipItemStatsTooltipTextLeft"..line]
local r,g,b = tooltipLine:GetTextColor()
if r>.6 or g>.6 or b>.6 then -- only lines that aren't greyed out
local txt=tooltipLine:GetText()
-- I suck at regexes so the following is brute forcing some substitutions
txt=txt:gsub(",","") -- remove commas on values like +1,234 Stamina
txt=txt:gsub("PvP Power","PvPPower") -- so %w+ captures this stat
txt=txt:gsub("PvP Resilience","PvPResilience") -- so %w+ captures this stat
txt=txt:gsub("All Stats","AllStats") -- not going to bother, call it its own stat
for value,stat in txt:gmatch("%+(%d+) (%w+)") do
rtable[stat] = rtable[stat] and rtable[stat]+value or value

wornStats = {}
for i=1,17 do

-- wornStats is now a table indexed by stat name with total stats
print("Total stats on worn gear:")
for stat,value in pairs(wornStats) do

Join the Conversation

Return to Forum