-- ************************************************************************** -- * TitanBag.lua -- * -- * By: The Titan Panel Development Team -- ************************************************************************** -- ******************************** Constants ******************************* local _G = getfenv(0); local TITAN_BAG_ID = "Bag"; local TITAN_BUTTON = "TitanPanel"..TITAN_BAG_ID.."Button" local TITAN_BAG_THRESHOLD_TABLE = { Values = { 0.5, 0.75, 0.9 }, Colors = { HIGHLIGHT_FONT_COLOR, NORMAL_FONT_COLOR, ORANGE_FONT_COLOR, RED_FONT_COLOR }, } local updateTable = {TITAN_BAG_ID, TITAN_PANEL_UPDATE_BUTTON}; -- ******************************** Variables ******************************* local AceTimer = LibStub("AceTimer-3.0") local L = LibStub("AceLocale-3.0"):GetLocale(TITAN_ID, true) local BagTimer local bag_info = { -- itemType : warcraft.wiki.gg/wiki/itemType [1] = -- Soul bag { color = {r=0.96,g=0.55,b=0.73}}, -- PINK [2] = -- HERBALISM = { color = {r=0,g=1,b=0}}, -- GREEN [3] = -- ENCHANTING = { color = {r=0,g=0,b=1}}, -- BLUE [4] = -- ENGINEERING = { color = {r=1,g=0.49,b=0.04}}, -- ORANGE [5] = -- JEWELCRAFTING = { color = {r=1,g=0,b=0}}, -- RED [6] = -- MINING = { color = {r=1,g=1,b=1}}, -- WHITE [7] = -- LEATHERWORKING = { color = {r=0.78,g=0.61,b=0.43}}, -- TAN [8] = -- INSCRIPTION = { color = {r=0.58,g=0.51,b=0.79}}, -- PURPLE [9] = -- FISHING = { color = {r=0.41,g=0.8,b=0.94}}, -- LIGHT_BLUE [10] = -- COOKING = { color = {r=0.96,g=0.55,b=0.73}}, -- PINK -- These are Classic arrow or bullet bags [22] = -- Classic arrow { color = {r=1,g=.4,b=0}}, -- copper [23] = -- Classic bullet { color = {r=0.8,g=0.8,b=0.8}}, -- silver } local trace = false local MIN_BAGS = 0 local MAX_BAGS = Constants.InventoryConstants.NumBagSlots local bag_data = {} -- to hold the user bag data -- ******************************** Functions ******************************* local function IsProfessionBagID(slot) -- The info needed is available using GetItemInfoInstant; only the bag / item id is required -- itemType : warcraft.wiki.gg/wiki/itemType local res = false local style = 0 local info, itemId, itemType, itemSubType, itemEquipLoc, itemTexture, classID, subclassID local inv_id = C_Container.ContainerIDToInventoryID(slot) if inv_id == nil then -- Only works on bag and bank bags NOT backpack! else info = GetInventoryItemLink("player", inv_id) itemId, itemType, itemSubType, itemEquipLoc, itemTexture, classID, subclassID = GetItemInfoInstant(info) style = subclassID --[[ TitanDebug("T isP 0:" .." "..tostring(slot).."" .." "..tostring(itemId).."" .." '"..tostring(itemType).."'" .." '"..tostring(itemSubType).."'" .." "..tostring(itemEquipLoc).."" .." '"..tostring(itemTexture).."'" .." "..tostring(classID).."" .." "..tostring(subclassID).."" ) --]] if classID == 1 then -- is a container / bag if subclassID >= 1 then -- profession bag of some type [2 - 10] Jan 2024 (DragonFlight / Wrath / Classic Era) -- OR soul bag [1] res = true else -- is a arrow or bullet; only two options end elseif classID == 6 then -- is a 'projectile' holder res = true -- is a ammo bag or quiver; only two options elseif classID == 11 then -- is a 'quiver'; Wrath and CE res = true -- is a ammo pouch or quiver; only two options style = subclassID + 20 -- change to get local color for name else -- not a bag end end if trace then TitanDebug("T isP:" .." "..tostring(res).."" .." "..tostring(style).."" .." "..tostring(itemId).."" .." "..tostring(classID).."" .." "..tostring(subclassID).."" .." "..tostring(inv_id).."" ) end return res, style end local function ToggleBags() if TitanGetVar(TITAN_BAG_ID, "OpenBags") then ToggleAllBags() else end end local function GetBagData(id) --[[ The bag name is not always available when player entering world Grabbing the total slots is available though to determine if a bag exists. The user may see bag name as <unknown> until an event triggers a bag check AND the name is available. --]] local total_slots = 0 local total_free = 0 local total_used = 0 local count_prof = TitanGetVar(TITAN_BAG_ID, "CountProfBagSlots") for bag_slot = MIN_BAGS, MAX_BAGS do -- assuming 0 (Backpack) will not be a profession bag local slots = C_Container.GetContainerNumSlots(bag_slot) -- Ensure a blank structure exists bag_data[bag_slot] = { has_bag = false, name = "", maxi_slots = 0, free_slots = 0, used_slots = 0, style = "", color = "", } if slots > 0 then bag_data[bag_slot].has_bag = true local bag_name = (C_Container.GetBagName(bag_slot) or UNKNOWN) bag_data[bag_slot].name = bag_name bag_data[bag_slot].maxi_slots = slots local free = C_Container.GetContainerNumFreeSlots(bag_slot) local used = slots - free bag_data[bag_slot].free_slots = free bag_data[bag_slot].used_slots = used --[[ TitanDebug("T Bag:" .." "..tostring(bag_slot).."" .." "..tostring(slots).."" .." "..tostring(free).."" .." '"..tostring(bag_name).."'" ) --]] -- some info is not known until the name is available... -- The API requires name to get the bag ID. local bag_type = "none" local color = {r=0,g=0,b=0} -- black (should never be used...) if bag_name == UNKNOWN then -- name not available yet else end -- Jan 2024 : Moved away from named based to an id based. Allows name to come later from server local is_prof_bag, style = IsProfessionBagID(bag_slot) --[[ if trace then TitanDebug("T Bag...:" .." "..tostring(bag_slot).."" .." "..tostring(is_prof_bag).."" .." '"..tostring(style).."'" .." "..tostring(itemClassID).."" .." "..tostring(itemSubClassID).."" ) end --]] if is_prof_bag then color = bag_info[style].color bag_type = "profession" else bag_type = "normal" end bag_data[bag_slot].style = bag_type bag_data[bag_slot].color = color -- add to total if bag_data[bag_slot].style == "profession" then if count_prof then total_slots = total_slots + slots total_free = total_free + free total_used = total_used + used else -- ignore in totals end else total_slots = total_slots + slots total_free = total_free + free total_used = total_used + used end else bag_data[bag_slot].has_bag = false end if trace then TitanDebug("T info" .." "..tostring(bag_slot).."" .." ?:"..tostring(bag_data[bag_slot].has_bag).."" .." max: "..tostring(bag_data[bag_slot].maxi_slots).."" .." used: "..tostring(bag_data[bag_slot].used_slots).."" .." free: "..tostring(bag_data[bag_slot].free_slots).."" .." type: "..tostring(bag_data[bag_slot].style).."" .." count: "..tostring(count_prof).."" .." '"..tostring(bag_data[bag_slot].name).."'" ) end end bag_data.total_slots = total_slots bag_data.total_free = total_free bag_data.total_used = total_used local bagText = "" if (TitanGetVar(TITAN_BAG_ID, "ShowUsedSlots")) then bagText = format(L["TITAN_BAG_FORMAT"], total_used, total_slots); else bagText = format(L["TITAN_BAG_FORMAT"], total_free, total_slots); end local bagRichText = "" if ( TitanGetVar(TITAN_BAG_ID, "ShowColoredText") ) then local color = "" color = TitanUtils_GetThresholdColor(TITAN_BAG_THRESHOLD_TABLE, total_used / total_slots); bagRichText = TitanUtils_GetColoredText(bagText, color); else bagRichText = TitanUtils_GetHighlightText(bagText); end bagRichText = bagRichText --..bagRichTextProf[1]..bagRichTextProf[2]..bagRichTextProf[3]..bagRichTextProf[4]..bagRichTextProf[5]; return L["TITAN_BAG_BUTTON_LABEL"], bagRichText end --[[ plugin -- ************************************************************************** -- NAME : TitanPanelBagButton_OnLoad() -- DESC : Registers the plugin upon it loading -- ************************************************************************** --]] function TitanPanelBagButton_OnLoad(self) local notes = "" .."Adds bag and free slot information to Titan Panel.\n" -- .."- xxx.\n" self.registry = { id = TITAN_BAG_ID, category = "Built-ins", version = TITAN_VERSION, menuText = L["TITAN_BAG_MENU_TEXT"], buttonTextFunction = "TitanPanelBagButton_GetButtonText", tooltipTitle = L["TITAN_BAG_TOOLTIP"], tooltipTextFunction = "TitanPanelBagButton_GetTooltipText", icon = "Interface\\AddOns\\TitanBag\\TitanBag", iconWidth = 16, notes = notes, controlVariables = { ShowIcon = true, ShowLabelText = true, ShowColoredText = true, DisplayOnRightSide = true, }, savedVariables = { ShowUsedSlots = 1, ShowDetailedInfo = false, CountProfBagSlots = false, ShowIcon = 1, ShowLabelText = 1, ShowColoredText = 1, DisplayOnRightSide = false, OpenBags = false, OpenBagsClassic = "new_install", } }; if TITAN_ID == "Titan" then -- 10.* / Retail -- for taint issue self.registry.savedVariables.OpenBags = false else -- does not taint so default to open bags on click self.registry.savedVariables.OpenBags = true end self:RegisterEvent("PLAYER_ENTERING_WORLD"); end --[[ plugin -- ************************************************************************** -- NAME : TitanPanelBagButton_OnEvent() -- DESC : Parse events registered to plugin and act on them -- ************************************************************************** --]] function TitanPanelBagButton_OnEvent(self, event, a1, a2, ...) if event == "PLAYER_ENTERING_WORLD" then --[===[ local inv_id = C_Container.ContainerIDToInventoryID(1) local info = GetInventoryItemLink("player", inv_id) local name, _, Color, Ltype, Id, Enchant, Gem1, Gem2, Gem3, Gem4, Suffix, Unique, LinkLvl, reforging, Name = string.find(info, "|?c?f?f?(%x*)|?H?([^:]*):?(%d+):?(%d*):?(%d*):?(%d*):?(%d*):?(%d*):?(%-?%d*):?(%-?%d*):?(%d*):?(%d*)|?h?%[?([^%[%]]*)%]?|?h?|?r?") local itemName, itemLink, itemQuality, itemLevel, itemMinLevel, itemType, itemSubType, itemStackCount, itemEquipLoc, itemTexture, sellPrice, classID, subclassID, bindType, expacID, setID, isCraftingReagent = GetItemInfo(Id) local iitemId, iitemType, iitemSubType, iitemEquipLoc, iitemTexture, iclassID, isubclassID = GetItemInfoInstant(info) print("======") print("bag" .." "..tostring(inv_id).."" ) print("inv" .." "..tostring(name).."" .." "..tostring(Id).."" .." "..tostring(classID).."" .." "..tostring(subclassID).."" ) print("iinv" .." "..tostring(iitemId).."" .." "..tostring(Id).."" .." "..tostring(iclassID).."" .." "..tostring(isubclassID).."" ) print("======") --]===] if a1 == true and TITAN_ID == "Titan" then -- 10.* / Retail -- initial login TitanPrint(L["TITAN_BAG_TAINT_TEXT"], "warning") else -- either Classic version local open = TitanGetVar(TITAN_BAG_ID, "OpenBagsClassic") if open == "new_install" then -- -- set to default behavior of opening bag on left click TitanSetVar(TITAN_BAG_ID, "OpenBags", true) TitanSetVar(TITAN_BAG_ID, "OpenBagsClassic", "processed") -- don't do again else -- already processed... end end end if event == "BAG_UPDATE" then -- update the plugin text TitanPanelButton_UpdateButton(TITAN_BAG_ID); end --[[ print("_OnEvent" .." "..tostring(event).."" ) --]] end --[[ plugin -- ************************************************************************** -- NAME : TitanPanelBagButton_OnClick(button) -- DESC : Opens all bags on a LeftClick -- VARS : button = value of action -- ************************************************************************** --]] function TitanPanelBagButton_OnClick(self, button) if (button == "LeftButton") then ToggleBags(); end end -- plugin function TitanPanelBagButton_GetButtonText(id) local strA, strB = GetBagData(id) return strA, strB end --[[ plugin -- ************************************************************************** -- NAME : TitanPanelBagButton_GetTooltipText() -- DESC : Display tooltip text -- ************************************************************************** --]] function TitanPanelBagButton_GetTooltipText() local totalSlots, usedSlots, availableSlots; local returnstring = ""; if TitanGetVar(TITAN_BAG_ID, "ShowDetailedInfo") then returnstring = "\n"; if TitanGetVar(TITAN_BAG_ID, "ShowUsedSlots") then returnstring = returnstring..TitanUtils_GetNormalText(L["TITAN_BAG_MENU_TEXT"]) ..":\t"..TitanUtils_GetNormalText(L["TITAN_BAG_USED_SLOTS"])..":\n"; else returnstring = returnstring..TitanUtils_GetNormalText(L["TITAN_BAG_MENU_TEXT"]) ..":\t"..TitanUtils_GetNormalText(L["TITAN_BAG_FREE_SLOTS"])..":\n"; end for bag = MIN_BAGS, MAX_BAGS do local bagText, bagRichText, color; --[[ TitanDebug("T Bag: TT" .." "..tostring(bag).."" .." "..tostring(bag_data[bag].has_bag).."" .." "..tostring(bag_data[bag].name).."" .." "..tostring(bag_data[bag].maxi_slots).."" .." "..tostring(bag_data[bag].used_slots).."" .." "..tostring(bag_data[bag].free_slots).."" ) --]] if bag_data[bag] and bag_data[bag].has_bag then if (TitanGetVar(TITAN_BAG_ID, "ShowUsedSlots")) then bagText = format(L["TITAN_BAG_FORMAT"], bag_data[bag].used_slots, bag_data[bag].maxi_slots); else bagText = format(L["TITAN_BAG_FORMAT"], bag_data[bag].free_slots, bag_data[bag].maxi_slots); end if bag_data[bag].style == "profession" and not TitanGetVar(TITAN_BAG_ID, "CountProfBagSlots") then bagRichText = "|cffa0a0a0"..bagText.."|r" -- show as gray elseif ( TitanGetVar(TITAN_BAG_ID, "ShowColoredText") ) then if bag_data[bag].maxi_slots == 0 then color = TitanUtils_GetThresholdColor(TITAN_BAG_THRESHOLD_TABLE, 1 ); else color = TitanUtils_GetThresholdColor(TITAN_BAG_THRESHOLD_TABLE, bag_data[bag].used_slots / bag_data[bag].maxi_slots); end bagRichText = TitanUtils_GetColoredText(bagText, color); else -- use without color bagRichText = TitanUtils_GetHighlightText(bagText); end local name_text = bag_data[bag].name if bag_data[bag].style == "profession" then name_text = TitanUtils_GetColoredText(name_text, bag_data[bag].color) else -- use without color end returnstring = returnstring..name_text.."\t"..bagRichText.."\n"; else returnstring = returnstring..NONE.."\n"; end end returnstring = returnstring.."\n"; end if TitanGetVar(TITAN_BAG_ID, "ShowUsedSlots") then local xofy = ""..tostring(bag_data.total_used) .."/"..tostring(bag_data.total_slots).."\n" returnstring = returnstring..TitanUtils_GetNormalText(L["TITAN_BAG_USED_SLOTS"]) ..":\t"..xofy else local xofy = ""..tostring(bag_data.total_free) .."/"..tostring(bag_data.total_slots).."\n" returnstring = returnstring..TitanUtils_GetNormalText(L["TITAN_BAG_USED_SLOTS"]) ..":\t"..xofy end -- Add Hint if TitanGetVar(TITAN_BAG_ID, "OpenBags") then returnstring = returnstring..TitanUtils_GetGreenText(L["TITAN_BAG_TOOLTIP_HINTS"]) else -- nop end return returnstring end --[[ plugin -- ************************************************************************** -- NAME : TitanPanelRightClickMenu_PrepareBagMenu() -- DESC : Display rightclick menu options -- NOTE : Titan builds this name to call on right click -- ************************************************************************** --]] function TitanPanelRightClickMenu_PrepareBagMenu() local info -- level 2 if TitanPanelRightClickMenu_GetDropdownLevel() == 2 then if TitanPanelRightClickMenu_GetDropdMenuValue() == "Options" then TitanPanelRightClickMenu_AddTitle(L["TITAN_PANEL_OPTIONS"], TitanPanelRightClickMenu_GetDropdownLevel()) info = {}; info.text = L["TITAN_BAG_MENU_SHOW_USED_SLOTS"]; info.func = TitanPanelBagButton_ShowUsedSlots; info.checked = TitanGetVar(TITAN_BAG_ID, "ShowUsedSlots"); TitanPanelRightClickMenu_AddButton(info, TitanPanelRightClickMenu_GetDropdownLevel()); info = {}; info.text = L["TITAN_BAG_MENU_SHOW_AVAILABLE_SLOTS"]; info.func = TitanPanelBagButton_ShowAvailableSlots; info.checked = TitanUtils_Toggle(TitanGetVar(TITAN_BAG_ID, "ShowUsedSlots")); TitanPanelRightClickMenu_AddButton(info, TitanPanelRightClickMenu_GetDropdownLevel()); info = {}; info.text = L["TITAN_BAG_MENU_SHOW_DETAILED"]; info.func = TitanPanelBagButton_ShowDetailedInfo; info.checked = TitanGetVar(TITAN_BAG_ID, "ShowDetailedInfo"); TitanPanelRightClickMenu_AddButton(info, TitanPanelRightClickMenu_GetDropdownLevel()); info = {}; info.text = L["TITAN_BAG_MENU_OPEN_BAGS"] info.func = function() TitanToggleVar(TITAN_BAG_ID, "OpenBags") end info.checked = TitanGetVar(TITAN_BAG_ID, "OpenBags"); TitanPanelRightClickMenu_AddButton(info, TitanPanelRightClickMenu_GetDropdownLevel()); end return end -- level 1 TitanPanelRightClickMenu_AddTitle(TitanPlugins[TITAN_BAG_ID].menuText); info = {}; info.notCheckable = true info.text = L["TITAN_PANEL_OPTIONS"]; info.value = "Options" info.hasArrow = 1; TitanPanelRightClickMenu_AddButton(info, TitanPanelRightClickMenu_GetDropdownLevel()); TitanPanelRightClickMenu_AddSpacer(); info = {}; info.text = L["TITAN_BAG_MENU_IGNORE_PROF_BAGS_SLOTS"]; info.func = TitanPanelBagButton_ToggleIgnoreProfBagSlots; info.checked = not TitanGetVar(TITAN_BAG_ID, "CountProfBagSlots") TitanPanelRightClickMenu_AddButton(info, TitanPanelRightClickMenu_GetDropdownLevel()); TitanPanelRightClickMenu_AddControlVars(TITAN_BAG_ID) end --[[ -- ************************************************************************** -- NAME : TitanPanelBagButton_ShowUsedSlots() -- DESC : Set option to show used slots -- ************************************************************************** --]] function TitanPanelBagButton_ShowUsedSlots() TitanSetVar(TITAN_BAG_ID, "ShowUsedSlots", 1); TitanPanelButton_UpdateButton(TITAN_BAG_ID); end --[[ -- ************************************************************************** -- NAME : TitanPanelBagButton_ShowAvailableSlots() -- DESC : Set option to show available slots -- ************************************************************************** --]] function TitanPanelBagButton_ShowAvailableSlots() TitanSetVar(TITAN_BAG_ID, "ShowUsedSlots", nil); TitanPanelButton_UpdateButton(TITAN_BAG_ID); end --[[ -- ************************************************************************** -- NAME : TitanPanelBagButton_ToggleIgnoreProfBagSlots() -- DESC : Set option to count profession bag slots -- ************************************************************************** --]] function TitanPanelBagButton_ToggleIgnoreProfBagSlots() TitanToggleVar(TITAN_BAG_ID, "CountProfBagSlots"); TitanPanelButton_UpdateButton(TITAN_BAG_ID); end function TitanPanelBagButton_ShowDetailedInfo() TitanToggleVar(TITAN_BAG_ID, "ShowDetailedInfo"); end function TitanPanelBagButton_OnShow(self) -- Register for bag updates and update the plugin text self:RegisterEvent("BAG_UPDATE") TitanPanelButton_UpdateButton(TITAN_BAG_ID); end function TitanPanelBagButton_OnHide(self) self:UnregisterEvent("BAG_UPDATE") end -- ====== Create needed frames local function Create_Frames() if _G[TITAN_BUTTON] then return -- if already created end -- general container frame local f = CreateFrame("Frame", nil, UIParent) -- f:Hide() -- Titan plugin button local window = CreateFrame("Button", TITAN_BUTTON, f, "TitanPanelComboTemplate") window:SetFrameStrata("FULLSCREEN") -- Using SetScript("OnLoad", does not work TitanPanelBagButton_OnLoad(window); -- TitanPanelButton_OnLoad(window); -- Titan XML template calls this... window:SetScript("OnShow", function(self) TitanPanelBagButton_OnShow(self); TitanPanelButton_OnShow(self); end) window:SetScript("OnHide", function(self) TitanPanelBagButton_OnHide(self) end) window:SetScript("OnEvent", function(self, event, ...) TitanPanelBagButton_OnEvent(self, event, ...) end) window:SetScript("OnClick", function(self, button) TitanPanelBagButton_OnClick(self, button); TitanPanelButton_OnClick(self, button); end) end Create_Frames() -- do the work