--[[ ########################################################## S V U I By: Failcoder ########################################################## LOCALIZED LUA FUNCTIONS ########################################################## ]]-- --[[ GLOBALS ]]-- local _G = _G; local unpack = _G.unpack; local select = _G.select; local pairs = _G.pairs; local string = _G.string; local math = _G.math; --[[ STRING METHODS ]]-- local find, format, match, split, join = string.find, string.format, string.match, string.split, string.join; local sub, byte = string.sub, string.byte; --[[ MATH METHODS ]]-- local ceil, floor, round = math.ceil, math.floor, math.round; --[[ TABLE METHODS ]]-- local tremove, tcopy, twipe, tsort, tcat = table.remove, table.copy, table.wipe, table.sort, table.concat; --[[ ########################################################## GET ADDON DATA ########################################################## ]]-- local SV = select(2, ...) local L = SV.L local LIUI = LibStub("LibItemUpgradeInfo-1.0"); --[[ ########################################################## LOCAL VARS ########################################################## ]]-- local NewHook = hooksecurefunc; local ParseItemLevel, ParseGearSlots; local GEAR_CACHE, GEARSET_LISTING = {}, {}; local EquipmentSlots = { ["HeadSlot"] = {true,true}, ["NeckSlot"] = {true,false}, ["ShoulderSlot"] = {true,true}, ["BackSlot"] = {true,false}, ["ChestSlot"] = {true,true}, ["WristSlot"] = {true,true}, ["MainHandSlot"] = {true,true,true}, ["SecondaryHandSlot"] = {true,true}, ["HandsSlot"] = {true,true,true}, ["WaistSlot"] = {true,true,true}, ["LegsSlot"] = {true,true,true}, ["FeetSlot"] = {true,true,true}, ["Finger0Slot"] = {true,false,true}, ["Finger1Slot"] = {true,false,true}, ["Trinket0Slot"] = {true,false,true}, ["Trinket1Slot"] = {true,false,true} } --[[ Quick explaination of what Im doing with all of these locals... Unlike many of the other modules, Inventory has to continuously reference config settings which can start to get sluggish. What I have done is set local variables for every database value that the module can read efficiently. The function "UpdateLocals" is used to refresh these any time a change is made to configs and once when the mod is loaded. ]]-- local COLOR_KEYS = { [0] = "|cffff0000", [1] = "|cff00ff00", [2] = "|cffffff88" }; local LIVESET, LASTSET, BG_SET, SPEC_SET, SHOW_DURABILITY, ONLY_DAMAGED, AVG_LEVEL, MAX_LEVEL; local SPEC_SWAP, BG_SWAP; local SHOW_CHAR_LEVEL, SHOW_BAG_LEVEL, SHOW_CHAR_SET, SHOW_BAG_SET; local iLevelFilter = ITEM_LEVEL:gsub( "%%d", "(%%d+)" ) --[[ ########################################################## LOCAL FUNCTIONS ########################################################## ]]-- local GearHandler = CreateFrame("Frame", nil); local function encodeSub(i, j, k) local l = j; while((k > 0) and (l <= #i)) do local m = byte(i, l) if(m > 240) then l = l + 4; elseif(m > 225) then l = l + 3; elseif(m > 192) then l = l + 2; else l = l + 1; end k = k - 1; end return i:sub(j, (l - 1)) end do local _heirlooms80 = { 44102,42944,44096,42943,42950,48677,42946,42948,42947,42992, 50255,44103,44107,44095,44098,44097,44105,42951,48683,48685, 42949,48687,42984,44100,44101,44092,48718,44091,42952,48689, 44099,42991,42985,48691,44094,44093,42945,48716 } local _heirlooms90h = {105689,105683,105686,105687,105688,105685,105690,105691,105684,105692,105693} local _heirlooms90n = {104399,104400,104401,104402,104403,104404,104405,104406,104407,104408,104409} local _heirlooms90f = {105675,105670,105672,105671,105674,105673,105676,105677,105678,105679,105680} -- DEPRECATED -- local _heirloom_regex = "|?c?f?f?(%x*)|?H?([^:]*):?(%d+):?(%d*):?(%d*):?(%d*):?(%d*):?(%d*):?(%-?%d*):?(%-?%d*):?(%d*):?(%d*)|?h?%[?([^%[%]]*)%]?|?h?|?r?"; local _slots = { ["HeadSlot"] = {true, true}, ["NeckSlot"] = {true, false}, ["ShoulderSlot"] = {true, true}, ["BackSlot"] = {true, false}, ["ChestSlot"] = {true, true}, ["WristSlot"] = {true, true}, ["MainHandSlot"] = {true, true, true}, ["SecondaryHandSlot"] = {true, true}, ["HandsSlot"] = {true, true, true}, ["WaistSlot"] = {true, true, true}, ["LegsSlot"] = {true, true, true}, ["FeetSlot"] = {true, true, true}, ["Finger0Slot"] = {true, false, true}, ["Finger1Slot"] = {true, false, true}, ["Trinket0Slot"] = {true, false, true}, ["Trinket1Slot"] = {true, false, true} } local function _justthetip() for i=1, #GameTooltip.shoppingTooltips do if(not GameTooltip.shoppingTooltips[i]:IsShown()) then return GameTooltip.shoppingTooltips[i] end end end local function _getHeirloomLevel(unit, itemId) if(not itemId) then return; end local baseLevel = UnitLevel(unit) if baseLevel > 85 then for i=1, #_heirlooms90h do if(_heirlooms90h[i] == itemId) then baseLevel = 582 break end end for i=1, #_heirlooms90n do if(_heirlooms90n[i] == itemId) then baseLevel = 569 break end end for i=1, #_heirlooms90f do if(_heirlooms90f[i] == itemId) then baseLevel = 548 break end end return baseLevel elseif baseLevel > 80 then for i=1, #_heirlooms80 do if(_heirlooms80[i] == itemId) then baseLevel = 80; break end end end if(baseLevel > 80) then return (((baseLevel - 81) * 12.2) + 272) elseif(baseLevel > 67) then return (((baseLevel - 68) * 6) + 130) elseif(baseLevel > 59) then return (((baseLevel - 60) * 3) + 85) end return baseLevel end function ParseItemLevel(unit, itemLink) -- local name, link, quality; -- local iLevel = 0; -- if(itemLink and type(itemLink) == "string") then -- name, link, quality, iLevel = GetItemInfo(itemLink) -- local itemId = tonumber(itemLink:match("item:%d+:%d+:%d+:%d+:%d+:%d+:%-?%d+:%-?%d+:%d+:%d+:(%d+)")) -- if iLevel and itemId then -- if(quality == 7) then -- iLevel = _getHeirloomLevel(unit, itemId) -- end -- end -- end -- return iLevel or 0 return LIUI:GetUpgradedItemLevel(itemLink) or 0 end local function _getEquippedItemLevel(unit, itemLink) -- local tooltip = _justthetip(); -- if(not tooltip) then return ParseItemLevel(unit, itemLink) end -- tooltip:SetOwner(UIParent, "ANCHOR_NONE"); -- tooltip:SetHyperlink(itemLink); -- tooltip:Show(); -- local iLevel = 0; -- local tname = tooltip:GetName().."TextLeft%s"; -- for i = 2, tooltip:NumLines() do -- local text = _G[tname:format(i)]:GetText(); -- if(text and text ~= "") then -- local value = tonumber(text:match(iLevelFilter)); -- if(value) then -- iLevel = value; -- end -- end -- end -- tooltip:Hide(); -- return iLevel return LIUI:GetUpgradedItemLevel(itemLink) or 0 end local function _setLevelDisplay(frame, iLevel) if(not frame or (not frame.ItemLevel)) then return; end frame.ItemLevel:SetText('') if(SHOW_CHAR_LEVEL and iLevel) then local key = (iLevel < (AVG_LEVEL - 10)) and 0 or (iLevel > (AVG_LEVEL + 10)) and 1 or 2; frame.ItemLevel:SetFormattedText("%s%d|r", COLOR_KEYS[key], iLevel) end end local function _setDurabilityDisplay(frame, slotId) if(not frame or (not frame.DurabilityInfo)) then return; end if(SHOW_DURABILITY) then local current,total,actual,perc,r,g,b; current,total = GetInventoryItemDurability(slotId) if(current and total) then frame.DurabilityInfo.bar:SetMinMaxValues(0, 100) if(current == total and ONLY_DAMAGED) then frame.DurabilityInfo:Hide() else if(current ~= total) then actual = current / total; perc = actual * 100; r,g,b = SV:ColorGradient(actual,1,0,0,1,1,0,0,1,0) frame.DurabilityInfo.bar:SetValue(perc) frame.DurabilityInfo.bar:SetStatusBarColor(r,g,b) if not frame.DurabilityInfo:IsShown() then frame.DurabilityInfo:Show() end else frame.DurabilityInfo.bar:SetValue(100) frame.DurabilityInfo.bar:SetStatusBarColor(0, 1, 0) end end else frame.DurabilityInfo:Hide() end else frame.DurabilityInfo:Hide() end end function ParseGearSlots(unit, category, setLevel, setDurability) local averageLevel,totalSlots = 0,0; for slotName, flags in pairs(_slots) do local slotId = GetInventorySlotInfo(slotName); local iLink = GetInventoryItemLink(unit, slotId) local iLevel; if(iLink and type(iLink) == "string") then iLevel = _getEquippedItemLevel(unit, iLink) if(iLevel and iLevel > 0) then totalSlots = totalSlots + 1; averageLevel = averageLevel + iLevel end end if(setLevel and flags[1]) then _setLevelDisplay(_G[category .. slotName], iLevel) end if(setDurability and (slotId ~= nil) and (not inspecting) and flags[2]) then _setDurabilityDisplay(_G[category .. slotName], slotId) end end return averageLevel,totalSlots end end function SV:ParseGearSlots(unit, inspecting, setLevel, setDurability) local category = (inspecting) and "Inspect" or "Character"; local averageLevel,totalSlots = ParseGearSlots(unit, category, setLevel, setDurability); if(averageLevel < 1 or totalSlots < 15) then return end return floor(averageLevel / totalSlots) end function SV:SetGearLabels(frame, bagID, slotID, itemLink, quality, equipSlot) quality = quality or 0; equipSlot = equipSlot or ''; if(frame.GearInfo) then local loc = format("%d_%d", bagID, slotID); if((not SHOW_BAG_SET) or (not GEARSET_LISTING[loc])) then frame.GearInfo:SetText('') else local setNumber = #GEARSET_LISTING[loc] < 4 and #GEARSET_LISTING[loc] or 3; if(setNumber == 1) then frame.GearInfo:SetFormattedText("|cffffffaa%s|r", encodeSub(GEARSET_LISTING[loc][1], 1, 4)) elseif(setNumber == 2) then frame.GearInfo:SetFormattedText("|cffffffaa%s %s|r", encodeSub(GEARSET_LISTING[loc][1], 1, 4), encodeSub(GEARSET_LISTING[loc][2], 1, 4)) elseif(setNumber == 3) then frame.GearInfo:SetFormattedText("|cffffffaa%s %s %s|r", encodeSub(GEARSET_LISTING[loc][1], 1, 4), encodeSub(GEARSET_LISTING[loc][2], 1, 4), encodeSub(GEARSET_LISTING[loc][3], 1, 4)) else frame.GearInfo:SetText('') end end end if(frame.ItemLevel) then local iLevel = ParseItemLevel('player', itemLink) if((not SHOW_BAG_LEVEL) or (iLevel <= 1) or (quality == 7) or (not equipSlot:find('INVTYPE'))) then frame.ItemLevel:SetText('') else local key = (iLevel < (AVG_LEVEL - 10)) and 0 or (iLevel > (AVG_LEVEL + 10)) and 1 or 2; frame.ItemLevel:SetFormattedText("%s%d|r", COLOR_KEYS[key], iLevel) end end end local function GetActiveGear() local count = GetNumEquipmentSets() local resultSpec = GetSpecialization() local _, sname = GetSpecializationInfo(resultSpec) local resultSet BG_SET = SV.db.Gear.battleground.equipmentset SPEC_SET = "none" if(sname) then SPEC_SET = SV.db.Gear.specialization[sname] or SPEC_SET end if(count == 0) then return resultSpec,false end for i=1, count do local setName,_,_,setUsed = GetEquipmentSetInfo(i) if setUsed then resultSet = setName break end end return resultSpec,resultSet end local function SetDisplayStats(arg) for slotName, flags in pairs(EquipmentSlots) do local globalName = format("%s%s", arg, slotName) local frame = _G[globalName] if(flags[1]) then frame.ItemLevel = frame:CreateFontString(nil, "OVERLAY") frame.ItemLevel:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", 2, 1) frame.ItemLevel:SetFontObject(SVUI_Font_Default) end if(arg == "Character" and flags[2]) then frame.DurabilityInfo = CreateFrame("Frame", nil, frame) frame.DurabilityInfo:SetWidth(7) if flags[3] then frame.DurabilityInfo:SetPoint("TOPRIGHT", frame, "TOPLEFT", -1, 1) frame.DurabilityInfo:SetPoint("BOTTOMRIGHT", frame, "BOTTOMLEFT", -1, -1) else frame.DurabilityInfo:SetPoint("TOPLEFT", frame, "TOPRIGHT", 1, 1) frame.DurabilityInfo:SetPoint("BOTTOMLEFT", frame, "BOTTOMRIGHT", 1, -1) end frame.DurabilityInfo:SetFrameLevel(frame:GetFrameLevel()-1) frame.DurabilityInfo:SetBackdrop(SV.media.backdrop.glow) frame.DurabilityInfo:SetBackdropColor(0, 0, 0, 0.5) frame.DurabilityInfo:SetBackdropBorderColor(0, 0, 0, 0.8) frame.DurabilityInfo.bar = CreateFrame("StatusBar", nil, frame.DurabilityInfo) frame.DurabilityInfo.bar:InsetPoints(frame.DurabilityInfo, 2, 2) frame.DurabilityInfo.bar:SetStatusBarTexture(SV.media.statusbar.default) frame.DurabilityInfo.bar:SetOrientation("VERTICAL") frame.DurabilityInfo.bg = frame.DurabilityInfo:CreateTexture(nil, "BORDER") frame.DurabilityInfo.bg:InsetPoints(frame.DurabilityInfo, 2, 2) frame.DurabilityInfo.bg:SetTexture([[Interface\BUTTONS\WHITE8X8]]) frame.DurabilityInfo.bg:SetVertexColor("VERTICAL", 0.5, 0.53, 0.55, 0.8, 0.8, 1) end end end --[[ ########################################################## CORE FUNCTIONS ########################################################## ]]-- local function RefreshInspectedGear() if(not SV.GearBuildComplete) then return end if(InCombatLockdown()) then GearHandler:RegisterEvent("PLAYER_REGEN_ENABLED", RefreshInspectedGear) return else GearHandler.WaitingOnInspect = nil end local unit = InspectFrame and InspectFrame.unit or "player"; if(not unit or (unit and not CanInspect(unit,false))) then return end SV:ParseGearSlots(unit, true, true) end local function UpdateLocals() SPEC_SWAP = SV.db.Gear.specialization.enable BG_SWAP = SV.db.Gear.battleground.enable SHOW_CHAR_LEVEL = SV.db.Gear.labels.characterItemLevel SHOW_BAG_LEVEL = SV.db.Gear.labels.inventoryItemLevel SHOW_CHAR_SET = SV.db.Gear.labels.characterGearSet SHOW_BAG_SET = SV.db.Gear.labels.inventoryGearSet SHOW_DURABILITY = SV.db.Gear.durability.enable ONLY_DAMAGED = SV.db.Gear.durability.onlydamaged MAX_LEVEL, AVG_LEVEL = GetAverageItemLevel() end function SV:BuildEquipmentMap() UpdateLocals() for key, gearData in pairs(GEARSET_LISTING) do twipe(gearData); end local set, player, bank, bags, slotIndex, bagIndex, loc, _; for i = 1, GetNumEquipmentSets() do set = GetEquipmentSetInfo(i); GEAR_CACHE = GetEquipmentSetLocations(set); if(GEAR_CACHE) then for key, location in pairs(GEAR_CACHE) do if(type(location) ~= "string") then player, bank, bags, _, slotIndex, bagIndex = EquipmentManager_UnpackLocation(location); if((bank or bags) and (slotIndex and bagIndex)) then loc = format("%d_%d", bagIndex, slotIndex); GEARSET_LISTING[loc] = GEARSET_LISTING[loc] or {}; local gslCount = #GEARSET_LISTING[loc] + 1 GEARSET_LISTING[loc][gslCount] = set; end end end end end end function SV:UpdateGearInfo() if(not SV.GearBuildComplete) then return end if(InCombatLockdown()) then GearHandler:RegisterEvent("PLAYER_REGEN_ENABLED") return end UpdateLocals() SV:ParseGearSlots("player", false, true, true) end local Gear_UpdateTabs = function() GearHandler.WaitingOnInspect = true SV.Timers:ExecuteTimer(RefreshInspectedGear, 0.2) end function SV:GearSwap() if(InCombatLockdown()) then return; end local gearSpec, gearSet = GetActiveGear() if(not gearSet) then return; end if(BG_SWAP and (BG_SET ~= "none" and BG_SET ~= gearSet)) then local inDungeon,dungeonType = IsInInstance() if(inDungeon and dungeonType == "pvp" or dungeonType == "arena") then if BG_SET ~= "none" and BG_SET ~= gearSet then LIVESET = BG_SET; UseEquipmentSet(BG_SET) end return end end if(SPEC_SWAP and (SPEC_SET ~= "none" and SPEC_SET ~= gearSet)) then LIVESET = SPEC_SET; UseEquipmentSet(SPEC_SET) end end local MSG_PREFIX = "You have equipped equipment set: " local GearHandler_OnEvent = function(self, event, ...) if(event == "PLAYER_REGEN_ENABLED") then self:UnregisterEvent("PLAYER_REGEN_ENABLED") if(self.WaitingOnInspect) then SV.Timers:ExecuteTimer(RefreshInspectedGear, 0.2) else SV:UpdateGearInfo() end elseif(event == "EQUIPMENT_SWAP_FINISHED") then if LIVESET then local strMsg = ("%s%s"):format(MSG_PREFIX, LIVESET) SV:AddonMessage(strMsg) LIVESET = nil end else SV:UpdateGearInfo() end end local function InitializeGearInfo() MSG_PREFIX = L["You have equipped equipment set: "] SHOW_CHAR_LEVEL = SV.db.Gear.labels.characterItemLevel SHOW_BAG_LEVEL = SV.db.Gear.labels.inventoryItemLevel SHOW_CHAR_SET = SV.db.Gear.labels.characterGearSet SHOW_BAG_SET = SV.db.Gear.labels.inventoryGearSet SHOW_DURABILITY = SV.db.Gear.durability.enable ONLY_DAMAGED = SV.db.Gear.durability.onlydamaged MAX_LEVEL, AVG_LEVEL = GetAverageItemLevel() LoadAddOn("Blizzard_InspectUI") SetDisplayStats("Character") SetDisplayStats("Inspect") GearHandler:RegisterEvent("PLAYER_ENTERING_WORLD") GearHandler:RegisterEvent("UPDATE_INVENTORY_DURABILITY") GearHandler:RegisterEvent("PLAYER_EQUIPMENT_CHANGED") GearHandler:RegisterEvent("SOCKET_INFO_UPDATE") GearHandler:RegisterEvent("COMBAT_RATING_UPDATE") GearHandler:RegisterEvent("MASTERY_UPDATE") GearHandler:RegisterEvent("EQUIPMENT_SWAP_FINISHED") GearHandler:SetScript("OnEvent", GearHandler_OnEvent) NewHook('InspectFrame_UpdateTabs', Gear_UpdateTabs) SV.Timers:ExecuteTimer(SV.UpdateGearInfo, 10) SV:GearSwap() SV.GearBuildComplete = true end SV:NewScript(InitializeGearInfo)