local addonName = ... local EquippedItemLevel = CreateFrame("Frame") _G[addonName] = EquippedItemLevel local slots = { { id = 1, frame = "CharacterHeadSlot" }, { id = 2, frame = "CharacterNeckSlot" }, { id = 3, frame = "CharacterShoulderSlot" }, { id = 5, frame = "CharacterChestSlot" }, { id = 6, frame = "CharacterWaistSlot" }, { id = 7, frame = "CharacterLegsSlot" }, { id = 8, frame = "CharacterFeetSlot" }, { id = 9, frame = "CharacterWristSlot" }, { id = 10, frame = "CharacterHandsSlot" }, { id = 11, frame = "CharacterFinger0Slot" }, { id = 12, frame = "CharacterFinger1Slot" }, { id = 13, frame = "CharacterTrinket0Slot" }, { id = 14, frame = "CharacterTrinket1Slot" }, { id = 15, frame = "CharacterBackSlot" }, { id = 16, frame = "CharacterMainHandSlot" }, { id = 17, frame = "CharacterSecondaryHandSlot" }, } local itemLevels = {} local updateQueued = false local characterFrameHooked = false local bagFrameHooks = {} local equippedLowest, equippedHighest local function GetCachedItemInfo(itemLink) if C_Item and C_Item.GetItemInfo then return C_Item.GetItemInfo(itemLink) end if GetItemInfo then return GetItemInfo(itemLink) end return nil end local function GetItemLevel(itemLink) if not itemLink then return nil end if C_Item and C_Item.GetDetailedItemLevelInfo then local level = C_Item.GetDetailedItemLevelInfo(itemLink) if level and level > 0 then return level end end local _, _, _, level = GetCachedItemInfo(itemLink) return level end local function GetGradientColor(level, lowest, highest) if lowest == highest then return 0, 1, 0 end local progress = (level - lowest) / (highest - lowest) progress = math.max(0, math.min(1, progress)) if progress <= 0.5 then return 1, progress * 2, 0 end return 2 - progress * 2, 1, 0 end local function IsGearItem(itemLink) if not itemLink then return false end local _, _, _, _, _, _, _, _, equipLocation = GetCachedItemInfo(itemLink) return equipLocation and equipLocation ~= "" and equipLocation ~= "INVTYPE_NON_EQUIP" and equipLocation ~= "INVTYPE_NON_EQUIP_IGNORE" and equipLocation ~= "INVTYPE_BAG" and equipLocation ~= "INVTYPE_TABARD" end local function CreateLabel(slot) local button = _G[slot.frame] if not button or button.EquippedItemLevelLabel then return end local label = button:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall") label:SetPoint("BOTTOMRIGHT", button, "BOTTOMRIGHT", -2, 2) label:SetFont("Fonts\\FRIZQT__.TTF", 12, "OUTLINE") label:SetJustifyH("RIGHT") label:Hide() button.EquippedItemLevelLabel = label end function EquippedItemLevel:Update() updateQueued = false local lowest, highest for _, slot in ipairs(slots) do CreateLabel(slot) local itemLink = GetInventoryItemLink("player", slot.id) local level = GetItemLevel(itemLink) itemLevels[slot.id] = level if level then lowest = not lowest and level or math.min(lowest, level) highest = not highest and level or math.max(highest, level) end end equippedLowest, equippedHighest = lowest, highest for _, slot in ipairs(slots) do local button = _G[slot.frame] local label = button and button.EquippedItemLevelLabel local level = itemLevels[slot.id] if label and level and lowest and highest then local red, green, blue = GetGradientColor(level, lowest, highest) label:SetText(string.format("%.0f", level)) label:SetTextColor(red, green, blue) label:Show() elseif label then label:Hide() end end self:UpdateBagLabels() end function EquippedItemLevel:QueueUpdate() if updateQueued then return end updateQueued = true C_Timer.After(0.1, function() EquippedItemLevel:Update() end) end function EquippedItemLevel:HookCharacterFrame() if characterFrameHooked or not CharacterFrame then return end CharacterFrame:HookScript("OnShow", function() EquippedItemLevel:QueueUpdate() end) characterFrameHooked = true end function EquippedItemLevel:UpdateBagButton(button) if not button or not button.GetBagID then return end local label = button.EquippedItemLevelBagLabel if not label then label = button:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall") label:SetPoint("BOTTOMRIGHT", button, "BOTTOMRIGHT", -2, 2) label:SetFont("Fonts\\FRIZQT__.TTF", 11, "OUTLINE") label:SetJustifyH("RIGHT") button.EquippedItemLevelBagLabel = label end local bag, slot = button:GetBagID(), button:GetID() local itemLink = bag and slot and C_Container.GetContainerItemLink(bag, slot) local level = GetItemLevel(itemLink) if not level or not IsGearItem(itemLink) or not equippedLowest or not equippedHighest then label:Hide() return end local red, green, blue = GetGradientColor(level, equippedLowest, equippedHighest) label:SetText(string.format("%.0f", level)) label:SetTextColor(red, green, blue) label:Show() end function EquippedItemLevel:UpdateContainerFrame(frame) if not frame then return end if frame.EnumerateValidItems then for _, button in frame:EnumerateValidItems() do self:UpdateBagButton(button) end elseif frame.Items then for _, button in ipairs(frame.Items) do self:UpdateBagButton(button) end end end function EquippedItemLevel:HookBagFrame(frame) if not frame or bagFrameHooks[frame] or not frame.Update then return end hooksecurefunc(frame, "Update", function(updatedFrame) EquippedItemLevel:UpdateContainerFrame(updatedFrame) end) bagFrameHooks[frame] = true end function EquippedItemLevel:UpdateBagLabels() local index = 1 local frame = _G["ContainerFrame" .. index] while frame do self:HookBagFrame(frame) self:UpdateContainerFrame(frame) index = index + 1 frame = _G["ContainerFrame" .. index] end if ContainerFrameCombinedBags then self:HookBagFrame(ContainerFrameCombinedBags) self:UpdateContainerFrame(ContainerFrameCombinedBags) end end local function AddTooltipItemLevel(tooltip, data) -- The same data is supplied for normal and comparison tooltips, including -- comparison panes that do not implement GameTooltip:GetItem(). local itemReference = data and (data.hyperlink or data.id) if not itemReference or not IsGearItem(itemReference) then return end local level = GetItemLevel(itemReference) if not level then return end local red, green, blue = GetGradientColor(level, equippedLowest or level, equippedHighest or level) tooltip:AddDoubleLine("Item level", string.format("%.0f", level), 1, 0.82, 0, red, green, blue) tooltip:Show() end function EquippedItemLevel:OnEvent(event) if event == "PLAYER_LOGIN" then TooltipDataProcessor.AddTooltipPostCall(Enum.TooltipDataType.Item, AddTooltipItemLevel) end self:HookCharacterFrame() self:QueueUpdate() end EquippedItemLevel:RegisterEvent("PLAYER_LOGIN") EquippedItemLevel:RegisterEvent("PLAYER_EQUIPMENT_CHANGED") EquippedItemLevel:RegisterEvent("GET_ITEM_INFO_RECEIVED") EquippedItemLevel:RegisterEvent("PLAYER_ENTERING_WORLD") EquippedItemLevel:RegisterEvent("ADDON_LOADED") EquippedItemLevel:RegisterEvent("BAG_UPDATE_DELAYED") EquippedItemLevel:SetScript("OnEvent", EquippedItemLevel.OnEvent)