local E, L, V, P, G = unpack(ElvUI) local _G = _G local pi = math.pi local utf8sub = string.utf8sub local tonumber, format = tonumber, format local tinsert, strfind, strmatch = tinsert, strfind, strmatch local next, max, wipe, gsub = next, max, wipe, gsub local GetAverageItemLevel = GetAverageItemLevel local GetInspectSpecialization = GetInspectSpecialization local GetInventoryItemTexture = GetInventoryItemTexture local GetInventoryItemLink = GetInventoryItemLink local UnitIsUnit = UnitIsUnit local UIParent = UIParent local RETRIEVING_ITEM_INFO = RETRIEVING_ITEM_INFO local ITEM_SPELL_TRIGGER_ONEQUIP = ITEM_SPELL_TRIGGER_ONEQUIP local GetSpellDescription = C_Spell.GetSpellDescription or GetSpellDescription local ESSENCE_DESCRIPTION = GetSpellDescription(277253) local GetItemInfo = C_Item.GetItemInfo local GetCVarBool = C_CVar.GetCVarBool local MATCH_ITEM_LEVEL = ITEM_LEVEL:gsub('%%d', '(%%d+)') local MATCH_ITEM_LEVEL_ALT = ITEM_LEVEL_ALT:gsub('%%d(%s?)%(%%d%)', '%%d+%1%%((%%d+)%%)') local MATCH_ENCHANT = ENCHANTED_TOOLTIP_LINE:gsub('%%s', '(.+)') local X2_INVTYPES, X2_EXCEPTIONS, ARMOR_SLOTS = { INVTYPE_2HWEAPON = true, INVTYPE_RANGEDRIGHT = true, INVTYPE_RANGED = true, }, { [2] = 19, -- wands, use INVTYPE_RANGEDRIGHT, but are 1H }, {1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} function E:InspectGearSlot(line, lineText, slotInfo) if not lineText then return end -- handle item level local itemLevel = strmatch(lineText, MATCH_ITEM_LEVEL_ALT) or strmatch(lineText, MATCH_ITEM_LEVEL) if itemLevel then slotInfo.iLvl = tonumber(itemLevel) local r1, g1, b1 = _G.ElvUI_ScanTooltipTextLeft1:GetTextColor() slotInfo.itemLevelColors[1] = r1 slotInfo.itemLevelColors[2] = g1 slotInfo.itemLevelColors[3] = b1 end -- handle encahants local enchant = strmatch(lineText, MATCH_ENCHANT) if enchant then local color1, color2 = strmatch(enchant, '(|cn.-:).-(|r)') local text = gsub(gsub(enchant, '%s?|A.-|a', ''), '|cn.-:(.-)|r', '%1') local r, g, b = line:GetTextColor() local shortStrip = gsub(text, '[&+] ?', '') local shortAbbrev = E.db.general.itemLevel.enchantAbbrev and gsub(shortStrip, '(%w%w%w)%w+', '%1') slotInfo.enchantText = format('%s%s%s', color1 or '', text, color2 or '') slotInfo.enchantTextShort = format('%s%s%s', color1 or '', utf8sub(shortAbbrev or shortStrip, 1, 20), color2 or '') slotInfo.enchantTextReal = enchant -- unchanged, contains Atlas and color slotInfo.enchantColors[1] = r slotInfo.enchantColors[2] = g slotInfo.enchantColors[3] = b end end function E:CollectEssenceInfo(index, lineText, slotInfo) local step = 1 local essence = slotInfo.essences[step] if essence and next(essence) and (ESSENCE_DESCRIPTION and strfind(lineText, ESSENCE_DESCRIPTION, nil, true) and strfind(lineText, ITEM_SPELL_TRIGGER_ONEQUIP, nil, true)) then for i = 5, 2, -1 do local line = _G['ElvUI_ScanTooltipTextLeft'..index - i] local text = line and line:GetText() if text and (not strmatch(text, '^[ +]')) and essence and next(essence) then local r, g, b = line:GetTextColor() essence[4] = E:RGBToHex(r, g, b) essence[5] = text step = step + 1 essence = slotInfo.essences[step] end end end end function E:GetGearSlotInfo(unit, slot, deepScan) local tt = E.ScanTooltip tt:SetOwner(UIParent, 'ANCHOR_NONE') local hasItem = tt:SetInventoryItem(unit, slot) tt:Show() local info = hasItem and tt:GetTooltipData() if not tt.slotInfo then tt.slotInfo = {} else wipe(tt.slotInfo) end local slotInfo = tt.slotInfo if deepScan then slotInfo.gems, slotInfo.essences = E:ScanTooltipTextures() if not tt.enchantColors then tt.enchantColors = {} else wipe(tt.enchantColors) end if not tt.itemLevelColors then tt.itemLevelColors = {} else wipe(tt.itemLevelColors) end slotInfo.enchantColors = tt.enchantColors slotInfo.itemLevelColors = tt.itemLevelColors if info then for i, line in next, info.lines do local text = line and line.leftText if i == 1 and text == RETRIEVING_ITEM_INFO then return 'tooSoon' else E:InspectGearSlot(_G['ElvUI_ScanTooltipTextLeft'..i], text, slotInfo) E:CollectEssenceInfo(i, text, slotInfo) end end end elseif info then local firstLine = info.lines[1] local firstText = firstLine and firstLine.leftText if firstText == RETRIEVING_ITEM_INFO then return 'tooSoon' end local colorblind = GetCVarBool('colorblindmode') local numLines = E.Mists and (colorblind and 21 or 20) or (colorblind and 4 or 3) for x = 2, numLines do local line = info.lines[x] if line then local text = line.leftText local itemLevel = (text and text ~= '') and (strmatch(text, MATCH_ITEM_LEVEL_ALT) or strmatch(text, MATCH_ITEM_LEVEL)) if itemLevel then slotInfo.iLvl = tonumber(itemLevel) end end end end tt:Hide() return slotInfo end --Credit ls & Acidweb function E:CalculateAverageItemLevel(iLevelDB, unit) local spec = E.Retail and GetInspectSpecialization(unit) -- fix this later? local total = 0 if E.Retail and (not spec or spec == 0) then return end -- Armor for _, id in next, ARMOR_SLOTS do local link = GetInventoryItemLink(unit, id) if link then local cur = iLevelDB[id] if cur and cur > 0 then total = total + cur end elseif GetInventoryItemTexture(unit, id) then return end end -- Main hand local mainItemLevel, mainQuality, mainEquipLoc, mainItemClass, mainItemSubClass, _ = 0 local mainLink = GetInventoryItemLink(unit, 16) if mainLink then mainItemLevel = iLevelDB[16] _, _, mainQuality, _, _, _, _, _, mainEquipLoc, _, _, mainItemClass, mainItemSubClass = GetItemInfo(mainLink) elseif GetInventoryItemTexture(unit, 16) then return end -- Off hand local offItemLevel, offEquipLoc = 0 local offLink = GetInventoryItemLink(unit, 17) if offLink then offItemLevel = iLevelDB[17] _, _, _, _, _, _, _, _, offEquipLoc = GetItemInfo(offLink) elseif GetInventoryItemTexture(unit, 17) then return end if mainItemLevel and offItemLevel then if mainQuality == 6 or (not offEquipLoc and X2_INVTYPES[mainEquipLoc] and X2_EXCEPTIONS[mainItemClass] ~= mainItemSubClass and spec ~= 72) then mainItemLevel = max(mainItemLevel, offItemLevel) total = total + mainItemLevel * 2 else total = total + mainItemLevel + offItemLevel end end -- at the beginning of an arena match no info might be available, -- so despite having equipped gear a person may appear naked if total == 0 then return end return E:Round(total / 16, 2) end function E:ColorizeItemLevel(num) if num >= 0 then return .1, 1, .1 else return E:ColorGradient(-(pi/num), 1, .1, .1, 1, 1, .1, .1, 1, .1) end end function E:GetPlayerItemLevel() local average, equipped = GetAverageItemLevel() return E:Round(average, 2), E:Round(equipped, 2) end do local iLevelDB, tryAgain = {}, {} function E:GetUnitItemLevel(unit) if UnitIsUnit(unit, 'player') then local _, equipped = E:GetPlayerItemLevel() return equipped end if next(iLevelDB) then wipe(iLevelDB) end if next(tryAgain) then wipe(tryAgain) end for i = 1, 17 do if i ~= 4 then local slotInfo = E:GetGearSlotInfo(unit, i) if slotInfo == 'tooSoon' then tinsert(tryAgain, i) else iLevelDB[i] = slotInfo.iLvl end end end if next(tryAgain) then return 'tooSoon', unit, tryAgain, iLevelDB end return E:CalculateAverageItemLevel(iLevelDB, unit) end end