fix: herb bags

This commit is contained in:
Salikh Gurgenidze
2025-12-19 01:44:10 +04:00
parent 03ff8bf52e
commit 159a0a6e15
7 changed files with 496 additions and 184 deletions
+100 -22
View File
@@ -240,6 +240,41 @@ function Utils:IsAmmoQuiverBag(bagID)
return false
end
-- Check if a bag is Herb Bag
function Utils:IsHerbBag(bagID)
-- Skip backpack, bank, and keyring
if bagID == 0 or bagID == -1 or bagID == -2 then
return false
end
local invSlot = ContainerIDToInventoryID(bagID)
if not invSlot then return false end
local link = GetInventoryItemLink("player", invSlot)
if not link then return false end
-- Prefer specialized type detection
local bagType = self:GetSpecializedBagType(bagID)
if bagType == "herb" then return true end
-- Fallback: tooltip scan for "Herb Bag"
local tooltip = GetScanTooltip()
tooltip:ClearLines()
tooltip:SetInventoryItem("player", invSlot)
for i = 1, tooltip:NumLines() do
local line = getglobal("GudaBagScanTooltipTextLeft" .. i)
if line then
local text = line:GetText()
if text and string.find(string.lower(text), "herb bag") then
return true
end
end
end
return false
end
-- Check if a bag is Soul Bag
function Utils:IsSoulBag(bagID)
-- Skip backpack, bank, and keyring
@@ -289,7 +324,7 @@ function Utils:IsSoulBag(bagID)
end
-- Get specialized bag type (for sorting priority)
-- Returns: "soul", "quiver", "ammo", or nil
-- Returns: "soul", "herb", "quiver", "ammo", or nil
function Utils:GetSpecializedBagType(bagID)
-- Skip backpack, bank, and keyring
if bagID == 0 or bagID == -1 or bagID == -2 then
@@ -322,6 +357,11 @@ function Utils:GetSpecializedBagType(bagID)
return "soul"
end
-- Herb Bag
if string.find(typeLower, "herb bag") then
return "herb"
end
-- Quiver
if string.find(typeLower, "quiver") then
return "quiver"
@@ -341,6 +381,8 @@ function Utils:GetContainerPriority(bagID)
local bagType = self:GetSpecializedBagType(bagID)
if bagType == "soul" then
return 40
elseif bagType == "herb" then
return 35
elseif bagType == "quiver" then
return 30
elseif bagType == "ammo" then
@@ -381,32 +423,37 @@ function Utils:IsAmmo(itemType)
end
-- Get preferred container type for an item
-- Returns: "soul", "quiver", "ammo", or nil
-- Returns: "soul", "herb", "quiver", "ammo", or nil
function Utils:GetItemPreferredContainer(itemLink)
if not itemLink then return nil end
if not itemLink then return nil end
-- Check for soul shards first
if self:IsSoulShard(itemLink) then
return "soul"
end
-- Check for soul shards first
if self:IsSoulShard(itemLink) then
return "soul"
end
-- Get item info using utility function
local itemID = self:ExtractItemID(itemLink)
if not itemID then return nil end
-- Get item info using utility function
local itemID = self:ExtractItemID(itemLink)
if not itemID then return nil end
local itemName, _, itemRarity, itemLevel, itemCategory, itemType, itemStackCount, itemSubType = self:GetItemInfoSafe(itemID)
if not itemType then return nil end
local itemName, _, itemRarity, itemLevel, itemCategory, itemType, itemStackCount, itemSubType, itemTexture = self:GetItemInfoSafe(itemID)
if not itemType then return nil end
-- Only route PROJECTILE category items that are specifically arrows or bullets
if itemCategory == "Projectile" then
if itemType == "Arrow" then
return "quiver"
elseif itemType == "Bullet" then
return "ammo"
end
end
-- Only route PROJECTILE category items that are specifically arrows or bullets
if itemCategory == "Projectile" then
if itemType == "Arrow" then
return "quiver"
elseif itemType == "Bullet" then
return "ammo"
end
end
return nil
-- Route herbs to herb bags (robust: category/subtype OR texture pattern fallback)
if self:IsHerbItem(itemLink) then
return "herb"
end
return nil
end
-- Check if an item is equipment (armor, weapon, or other equippable)
@@ -432,5 +479,36 @@ function Utils:IsEquipment(itemLink)
end
end
return false
return false
end
-- Determine if an item is a herb (for routing to herb bags)
-- NEW rule (per request): require BOTH
-- 1) itemCategory == "Trade Goods"
-- 2) texture contains "INV_Misc_Herb" (case-insensitive; prefix tolerated)
function Utils:IsHerbItem(itemLink)
if not itemLink then return false end
local itemID = self:ExtractItemID(itemLink)
if not itemID then return false end
local name, _, quality, iLevel, itemCategory, itemType, itemStackCount, itemSubType, itemTexture = self:GetItemInfoSafe(itemID)
if itemCategory ~= "Trade Goods" then
return false
end
if not itemTexture then
return false
end
-- Normalize and check texture name
local tex = string.lower(itemTexture)
tex = string.gsub(tex, "^interface\\\\icons\\\\", "")
if string.find(tex, "inv_misc_herb") or string.find(tex, "misc_herb") then
return true
end
return false
end
+2
View File
@@ -27,6 +27,8 @@ function BagScanner:ScanBag(bagID)
local bagType = "regular"
if addon.Modules.Utils:IsSoulBag(bagID) then
bagType = "soul"
elseif addon.Modules.Utils:IsHerbBag(bagID) then
bagType = "herb"
elseif addon.Modules.Utils:IsAmmoQuiverBag(bagID) then
bagType = "ammo"
end
+2
View File
@@ -30,6 +30,8 @@ function BankScanner:ScanBankBag(bagID)
local bagType = "regular"
if addon.Modules.Utils:IsSoulBag(bagID) then
bagType = "soul"
elseif addon.Modules.Utils:IsHerbBag(bagID) then
bagType = "herb"
elseif addon.Modules.Utils:IsAmmoQuiverBag(bagID) then
bagType = "ammo"
end
+225 -85
View File
@@ -172,25 +172,28 @@ end
--===========================================================================
local function DetectSpecializedBags(bagIDs)
local containers = {
soul = {},
quiver = {},
ammo = {},
regular = {}
}
local containers = {
soul = {},
herb = {},
quiver = {},
ammo = {},
regular = {}
}
for _, bagID in ipairs(bagIDs) do
local bagType = addon.Modules.Utils:GetSpecializedBagType(bagID)
if bagType == "soul" then
table.insert(containers.soul, bagID)
elseif bagType == "quiver" then
table.insert(containers.quiver, bagID)
elseif bagType == "ammo" then
table.insert(containers.ammo, bagID)
else
table.insert(containers.regular, bagID)
end
end
if bagType == "soul" then
table.insert(containers.soul, bagID)
elseif bagType == "herb" then
table.insert(containers.herb, bagID)
elseif bagType == "quiver" then
table.insert(containers.quiver, bagID)
elseif bagType == "ammo" then
table.insert(containers.ammo, bagID)
else
table.insert(containers.regular, bagID)
end
end
return containers
end
@@ -749,13 +752,13 @@ function SortEngine:AnalyzeContainer(bagIDs, containerType)
local totalOutOfPlace = 0
local totalItems = 0
-- Analyze specialized bags separately
for _, bagType in ipairs({"soul", "quiver", "ammo"}) do
local specialBags = containers[bagType]
for _, bagID in ipairs(specialBags) do
local items = CollectItems({bagID})
if table.getn(items) > 0 then
local sortedItems = SortItems(items)
-- Analyze specialized bags separately
for _, bagType in ipairs({"soul", "herb", "quiver", "ammo"}) do
local specialBags = containers[bagType]
for _, bagID in ipairs(specialBags) do
local items = CollectItems({bagID})
if table.getn(items) > 0 then
local sortedItems = SortItems(items)
local targetPositions = BuildTargetPositions({bagID}, table.getn(items))
for i, item in ipairs(sortedItems) do
@@ -827,23 +830,27 @@ function SortEngine:AnalyzeContainer(bagIDs, containerType)
end
end
if totalOutOfPlace == 0 then
return {passes = 0, itemsOutOfPlace = 0, totalItems = totalItems, alreadySorted = true}
end
if totalOutOfPlace == 0 then
return {passes = 0, itemsOutOfPlace = 0, totalItems = totalItems, alreadySorted = true}
end
-- Estimate passes (same logic as before)
local displacementRatio = totalOutOfPlace / math.max(1, totalItems)
local estimatedPasses
-- Estimate passes (aligned to single-pass executor; cap at 6)
local displacementRatio = totalOutOfPlace / math.max(1, totalItems)
local estimatedPasses
if displacementRatio < 0.1 then
estimatedPasses = 1
elseif displacementRatio < 0.3 then
estimatedPasses = 2
elseif displacementRatio < 0.5 then
estimatedPasses = 3
else
estimatedPasses = 4
end
if displacementRatio < 0.10 then
estimatedPasses = 1
elseif displacementRatio < 0.30 then
estimatedPasses = 2
elseif displacementRatio < 0.50 then
estimatedPasses = 3
elseif displacementRatio < 0.70 then
estimatedPasses = 4
elseif displacementRatio < 0.85 then
estimatedPasses = 5
else
estimatedPasses = 6
end
return {
passes = estimatedPasses,
@@ -853,6 +860,61 @@ function SortEngine:AnalyzeContainer(bagIDs, containerType)
}
end
-- Execute exactly ONE full sorting pass over bags (used by safety wrapper)
function SortEngine:SortBagsPass()
local bagIDs = addon.Constants.BAGS
-- Phase 1: Detect specialized bags
local containers = DetectSpecializedBags(bagIDs)
-- Phase 2: Route specialized items to their bags
local routeCount = RouteSpecializedItems(bagIDs, containers)
-- Phase 3: Consolidate stacks in ALL bags (including specialized)
local consolidateCount = ConsolidateStacks(bagIDs)
-- Phase 4: Sort items WITHIN each specialized bag (soul, herb, quiver, ammo)
local specializedMoves = 0
for _, bagType in ipairs({"soul", "herb", "quiver", "ammo"}) do
local specialBags = containers[bagType]
for _, bagID in ipairs(specialBags) do
local items = CollectItems({bagID})
if table.getn(items) > 0 then
items = SortItems(items)
local targetPositions = BuildTargetPositions({bagID}, table.getn(items))
local moveCount = ApplySort({bagID}, items, targetPositions)
specializedMoves = specializedMoves + moveCount
end
end
end
-- Phase 5: Two-phase sort for regular bags in a single pass
local regularMoves = 0
local regularBagIDs = containers.regular
if table.getn(regularBagIDs) > 0 then
-- Re-collect current state from regular bags
local allItems = CollectItems(regularBagIDs)
local nonGreys, greys = SplitGreyItems(allItems)
-- 1) Non-greys: standard sort to the front positions only
if table.getn(nonGreys) > 0 then
local sortedNonGreys = SortItems(nonGreys)
local frontPositions = BuildTargetPositions(regularBagIDs, table.getn(sortedNonGreys))
regularMoves = regularMoves + (ApplySort(regularBagIDs, sortedNonGreys, frontPositions) or 0)
end
-- 2) Greys: end->start across bags
local afterItems = CollectItems(regularBagIDs)
local _, greysNow = SplitGreyItems(afterItems)
if table.getn(greysNow) > 0 then
local tailPositions = BuildGreyTailPositions(regularBagIDs, table.getn(greysNow))
regularMoves = regularMoves + (ApplySort(regularBagIDs, greysNow, tailPositions) or 0)
end
end
return routeCount + consolidateCount + specializedMoves + regularMoves
end
function SortEngine:SortBags()
local bagIDs = addon.Constants.BAGS
@@ -865,14 +927,14 @@ function SortEngine:SortBags()
-- Phase 3: Consolidate stacks in ALL bags (including specialized)
local consolidateCount = ConsolidateStacks(bagIDs)
-- Phase 4: Sort items WITHIN each specialized bag (soul, quiver, ammo)
local specializedMoves = 0
for _, bagType in ipairs({"soul", "quiver", "ammo"}) do
local specialBags = containers[bagType]
for _, bagID in ipairs(specialBags) do
-- Sort items within this single specialized bag
local items = CollectItems({bagID})
if table.getn(items) > 0 then
-- Phase 4: Sort items WITHIN each specialized bag (soul, herb, quiver, ammo)
local specializedMoves = 0
for _, bagType in ipairs({"soul", "herb", "quiver", "ammo"}) do
local specialBags = containers[bagType]
for _, bagID in ipairs(specialBags) do
-- Sort items within this single specialized bag
local items = CollectItems({bagID})
if table.getn(items) > 0 then
items = SortItems(items)
local targetPositions = BuildTargetPositions({bagID}, table.getn(items))
local moveCount = ApplySort({bagID}, items, targetPositions)
@@ -881,9 +943,7 @@ function SortEngine:SortBags()
end
end
-- Phase 5: Two-phase sort for regular bags:
-- 1) Sort non-grey items normally across all regular bags (front-compaction)
-- 2) Pack grey items (quality 0) at the end tail (last bag backwards), spilling into previous bags.
-- Phase 5: Two-phase sort for regular bags (multi-pass legacy; kept for direct calls)
local regularMoves = 0
local regularBagIDs = containers.regular
if table.getn(regularBagIDs) > 0 then
@@ -920,6 +980,63 @@ function SortEngine:SortBags()
return routeCount + consolidateCount + specializedMoves + regularMoves
end
-- Execute exactly ONE full sorting pass over bank (used by safety wrapper)
function SortEngine:SortBankPass()
if not addon.Modules.BankScanner:IsBankOpen() then
addon:Print("Bank must be open to sort!")
return 0
end
local bagIDs = addon.Constants.BANK_BAGS
-- Phase 1: Detect specialized bags
local containers = DetectSpecializedBags(bagIDs)
-- Phase 2: Route specialized items
local routeCount = RouteSpecializedItems(bagIDs, containers)
-- Phase 3: Consolidate stacks
local consolidateCount = ConsolidateStacks(bagIDs)
-- Phase 4: Sort items WITHIN each specialized bag (single pass)
local specializedMoves = 0
for _, bagType in ipairs({"soul", "herb", "quiver", "ammo"}) do
local specialBags = containers[bagType]
for _, bagID in ipairs(specialBags) do
local items = CollectItems({bagID})
if table.getn(items) > 0 then
items = SortItems(items)
local targetPositions = BuildTargetPositions({bagID}, table.getn(items))
local moved = ApplySort({bagID}, items, targetPositions)
specializedMoves = specializedMoves + moved
end
end
end
-- Phase 5: Regular bank bags — single pass
local regularBagIDs = containers.regular
local regularMoves = 0
if table.getn(regularBagIDs) > 0 then
local allItems = CollectItems(regularBagIDs)
local nonGreys, greys = SplitGreyItems(allItems)
if table.getn(nonGreys) > 0 then
local sortedNonGreys = SortItems(nonGreys)
local frontPositions = BuildTargetPositions(regularBagIDs, table.getn(sortedNonGreys))
regularMoves = regularMoves + (ApplySort(regularBagIDs, sortedNonGreys, frontPositions) or 0)
end
local afterItems = CollectItems(regularBagIDs)
local _, greysNow = SplitGreyItems(afterItems)
if table.getn(greysNow) > 0 then
local tailPositions = BuildGreyTailPositions(regularBagIDs, table.getn(greysNow))
regularMoves = regularMoves + (ApplySort(regularBagIDs, greysNow, tailPositions) or 0)
end
end
return routeCount + consolidateCount + specializedMoves + regularMoves
end
function SortEngine:SortBank()
if not addon.Modules.BankScanner:IsBankOpen() then
addon:Print("Bank must be open to sort!")
@@ -937,23 +1054,23 @@ function SortEngine:SortBank()
-- Phase 3: Consolidate stacks
local consolidateCount = ConsolidateStacks(bagIDs)
-- Phase 4: Sort items WITHIN each specialized bag (multi-pass to avoid mid-bag holes)
local specializedMoves = 0
for _, bagType in ipairs({"soul", "quiver", "ammo"}) do
local specialBags = containers[bagType]
for _, bagID in ipairs(specialBags) do
local maxPasses = 4
for pass = 1, maxPasses do
local items = CollectItems({bagID})
if table.getn(items) == 0 then break end
items = SortItems(items)
local targetPositions = BuildTargetPositions({bagID}, table.getn(items))
local moved = ApplySort({bagID}, items, targetPositions)
specializedMoves = specializedMoves + moved
if moved == 0 then break end
end
end
end
-- Phase 4: Sort items WITHIN each specialized bag (multi-pass to avoid mid-bag holes)
local specializedMoves = 0
for _, bagType in ipairs({"soul", "herb", "quiver", "ammo"}) do
local specialBags = containers[bagType]
for _, bagID in ipairs(specialBags) do
local maxPasses = 4
for pass = 1, maxPasses do
local items = CollectItems({bagID})
if table.getn(items) == 0 then break end
items = SortItems(items)
local targetPositions = BuildTargetPositions({bagID}, table.getn(items))
local moved = ApplySort({bagID}, items, targetPositions)
specializedMoves = specializedMoves + moved
if moved == 0 then break end
end
end
end
-- Phase 5: Regular bank bags — same two-phase approach (non-greys first, greys to tail)
local regularBagIDs = containers.regular
@@ -1005,26 +1122,27 @@ function SortEngine:ExecuteSort(sortFunction, analyzeFunction, updateFrame, sort
addon:Print("Sorting %s... (%d/%d items need sorting, estimated %d passes)",
sortType, analysis.itemsOutOfPlace, analysis.totalItems, analysis.passes)
local passCount = 0
local maxPasses = math.max(analysis.passes, 1) -- Use estimated passes, minimum 1
local safetyLimit = math.max(maxPasses * 2, 6) -- Reasonable upper bound
local totalMoves = 0
local passCount = 0
local maxPasses = math.max(analysis.passes, 1) -- Use estimated passes, minimum 1
local safetyLimit = math.max(maxPasses * 2, 6) -- Reasonable upper bound
local totalMoves = 0
local noProgressPasses = 0
addon:Print("Starting %s sort (estimated: %d passes, safety limit: %d)", sortType, maxPasses, safetyLimit)
local function DoSortPass()
passCount = passCount + 1
-- Perform one sort pass
local moveCount = sortFunction()
totalMoves = totalMoves + moveCount
-- Perform one sort pass
local moveCount = sortFunction()
totalMoves = totalMoves + moveCount
-- Check if sorting is complete by re-analyzing
local currentAnalysis = analyzeFunction()
if currentAnalysis.alreadySorted then
-- Sorting is complete!
addon:Print("%s sort complete! (%d passes, %d total moves)", sortType, passCount, totalMoves)
if currentAnalysis.alreadySorted then
-- Sorting is complete!
addon:Print("%s sort complete! (%d passes, %d total moves)", sortType, passCount, totalMoves)
-- Final update
local frame = CreateFrame("Frame")
@@ -1035,10 +1153,10 @@ function SortEngine:ExecuteSort(sortFunction, analyzeFunction, updateFrame, sort
updateFrame()
end
end)
elseif passCount >= safetyLimit then
-- Hit safety limit but not fully sorted
addon:Print("%s sort stopped at safety limit! (%d/%d items still need sorting after %d passes)",
sortType, currentAnalysis.itemsOutOfPlace, currentAnalysis.totalItems, passCount)
elseif passCount >= safetyLimit then
-- Hit safety limit but not fully sorted
addon:Print("%s sort stopped at safety limit! (%d/%d items still need sorting after %d passes)",
sortType, currentAnalysis.itemsOutOfPlace, currentAnalysis.totalItems, passCount)
-- Final update
local frame = CreateFrame("Frame")
@@ -1049,11 +1167,33 @@ function SortEngine:ExecuteSort(sortFunction, analyzeFunction, updateFrame, sort
updateFrame()
end
end)
else
-- More sorting needed
local remainingRatio = currentAnalysis.itemsOutOfPlace / math.max(1, currentAnalysis.totalItems)
addon:Print("%s Pass %d: %d moves, %d/%d items remaining (%.1f%%)",
sortType, passCount, moveCount, currentAnalysis.itemsOutOfPlace, currentAnalysis.totalItems, remainingRatio * 100)
else
-- No progress guard: stop if we make no moves repeatedly
if moveCount == 0 then
noProgressPasses = noProgressPasses + 1
else
noProgressPasses = 0
end
if noProgressPasses >= 3 then
addon:Print("%s sort stopped due to no progress after %d passes (items remaining: %d/%d)",
sortType, passCount, currentAnalysis.itemsOutOfPlace, currentAnalysis.totalItems)
-- Final update
local frame = CreateFrame("Frame")
local startTime = GetTime()
frame:SetScript("OnUpdate", function()
if GetTime() - startTime >= 0.7 then
frame:SetScript("OnUpdate", nil)
updateFrame()
end
end)
return
end
-- More sorting needed
local remainingRatio = currentAnalysis.itemsOutOfPlace / math.max(1, currentAnalysis.totalItems)
addon:Print("%s Pass %d: %d moves, %d/%d items remaining (%.1f%%)",
sortType, passCount, moveCount, currentAnalysis.itemsOutOfPlace, currentAnalysis.totalItems, remainingRatio * 100)
-- PROGRESSIVE DELAY: Calculate delay based on remaining complexity
local baseDelay = 0.7
+57 -45
View File
@@ -236,10 +236,11 @@ function BagFrame:DisplayItems(bagData, isOtherChar, charName)
local perRow = addon.Modules.DB:GetSetting("bagColumns") or 10
local itemContainer = getglobal("Guda_BagFrame_ItemContainer")
-- Separate bags into regular, soul, and ammo/quiver types
local regularBags = {}
local soulBags = {}
local ammoQuiverBags = {}
-- Separate bags into regular, soul, herb, and ammo/quiver types
local regularBags = {}
local soulBags = {}
local herbBags = {}
local ammoQuiverBags = {}
for _, bagID in ipairs(addon.Constants.BAGS) do
-- Skip hidden bags
@@ -251,44 +252,55 @@ function BagFrame:DisplayItems(bagData, isOtherChar, charName)
bagType = bag and bag.bagType or "regular"
else
-- For current character, detect bag type in real-time
if addon.Modules.Utils:IsSoulBag(bagID) then
bagType = "soul"
elseif addon.Modules.Utils:IsAmmoQuiverBag(bagID) then
bagType = "ammo"
else
bagType = "regular"
end
end
if addon.Modules.Utils:IsSoulBag(bagID) then
bagType = "soul"
elseif addon.Modules.Utils:IsHerbBag(bagID) then
bagType = "herb"
elseif addon.Modules.Utils:IsAmmoQuiverBag(bagID) then
bagType = "ammo"
else
bagType = "regular"
end
end
if bagType == "soul" then
table.insert(soulBags, bagID)
elseif bagType == "ammo" then
table.insert(ammoQuiverBags, bagID)
else
table.insert(regularBags, bagID)
end
end
end
if bagType == "soul" then
table.insert(soulBags, bagID)
elseif bagType == "herb" then
table.insert(herbBags, bagID)
elseif bagType == "ammo" then
table.insert(ammoQuiverBags, bagID)
else
table.insert(regularBags, bagID)
end
end
end
-- Build display order: regular bags -> soul bags -> ammo/quiver bags -> keyring
local bagsToShow = {}
for _, bagID in ipairs(regularBags) do
table.insert(bagsToShow, {bagID = bagID, needsSpacing = false})
end
-- Build display order: regular bags -> soul bags -> herb bags -> ammo/quiver bags -> keyring
local bagsToShow = {}
for _, bagID in ipairs(regularBags) do
table.insert(bagsToShow, {bagID = bagID, needsSpacing = false})
end
-- Add soul bags with spacing marker
if table.getn(soulBags) > 0 then
for i, bagID in ipairs(soulBags) do
table.insert(bagsToShow, {bagID = bagID, needsSpacing = (i == 1)})
end
end
if table.getn(soulBags) > 0 then
for i, bagID in ipairs(soulBags) do
table.insert(bagsToShow, {bagID = bagID, needsSpacing = (i == 1)})
end
end
-- Add ammo/quiver bags with spacing marker
if table.getn(ammoQuiverBags) > 0 then
for i, bagID in ipairs(ammoQuiverBags) do
table.insert(bagsToShow, {bagID = bagID, needsSpacing = (i == 1)})
end
end
-- Add herb bags with spacing marker
if table.getn(herbBags) > 0 then
for i, bagID in ipairs(herbBags) do
table.insert(bagsToShow, {bagID = bagID, needsSpacing = (i == 1)})
end
end
-- Add ammo/quiver bags with spacing marker
if table.getn(ammoQuiverBags) > 0 then
for i, bagID in ipairs(ammoQuiverBags) do
table.insert(bagsToShow, {bagID = bagID, needsSpacing = (i == 1)})
end
end
-- Add keyring at the end if toggled on and not hidden
if showKeyring and not hiddenBags[-2] then
@@ -299,8 +311,8 @@ function BagFrame:DisplayItems(bagData, isOtherChar, charName)
local bagID = bagInfo.bagID
local bag = bagData[bagID]
-- Add spacing before soul, ammo/quiver, or keyring sections
if bagInfo.needsSpacing then
-- Add spacing before soul, herb, ammo/quiver, or keyring sections
if bagInfo.needsSpacing then
if col > 0 then
-- Move to next row if not at start of row
col = 0
@@ -1167,12 +1179,12 @@ function Guda_BagFrame_Sort()
return
end
local success, message = addon.Modules.SortEngine:ExecuteSort(
function() return addon.Modules.SortEngine:SortBags() end,
function() return addon.Modules.SortEngine:AnalyzeBags() end,
function() BagFrame:Update() end,
"bags"
)
local success, message = addon.Modules.SortEngine:ExecuteSort(
function() return addon.Modules.SortEngine:SortBagsPass() end,
function() return addon.Modules.SortEngine:AnalyzeBags() end,
function() BagFrame:Update() end,
"bags"
)
if not success and message == "already sorted" then
addon:Print("Bags are already sorted!")
+85 -32
View File
@@ -196,28 +196,90 @@ function BankFrame:DisplayItems(bankData, isOtherChar, charName)
local perRow = addon.Modules.DB:GetSetting("bankColumns") or 10
local itemContainer = getglobal("Guda_BankFrame_ItemContainer")
for _, bagID in ipairs(addon.Constants.BANK_BAGS) do
-- Skip bags that are hidden
if not hiddenBankBags[bagID] then
local bag = bankData[bagID]
-- Separate bank bags into regular, soul, herb, and ammo/quiver types
local regularBags = {}
local soulBags = {}
local herbBags = {}
local ammoQuiverBags = {}
-- Get slot count for this bag
local numSlots
if isOtherChar and bag and bag.numSlots then
-- Use stored slot count for other characters
numSlots = bag.numSlots
for _, bagID in ipairs(addon.Constants.BANK_BAGS) do
if not hiddenBankBags[bagID] then
local bagType
if isOtherChar then
-- Use saved bag type for other characters
local bagSaved = bankData and bankData[bagID]
bagType = bagSaved and bagSaved.bagType or "regular"
else
-- Use current character's bag slot count
numSlots = addon.Modules.Utils:GetBagSlotCount(bagID)
-- Live detection for current character when bank is open
if addon.Modules.Utils:IsSoulBag(bagID) then
bagType = "soul"
elseif addon.Modules.Utils:IsHerbBag(bagID) then
bagType = "herb"
elseif addon.Modules.Utils:IsAmmoQuiverBag(bagID) then
bagType = "ammo"
else
bagType = "regular"
end
end
-- Only show bags that have slots
if numSlots and numSlots > 0 then
-- Iterate through ALL slots (1 to numSlots) to show empty slots too
if bagType == "soul" then
table.insert(soulBags, bagID)
elseif bagType == "herb" then
table.insert(herbBags, bagID)
elseif bagType == "ammo" then
table.insert(ammoQuiverBags, bagID)
else
table.insert(regularBags, bagID)
end
end
end
-- Build display order: regular -> soul -> herb -> ammo/quiver
local bagsToShow = {}
for _, bagID in ipairs(regularBags) do
table.insert(bagsToShow, { bagID = bagID, needsSpacing = false })
end
if table.getn(soulBags) > 0 then
for i, bagID in ipairs(soulBags) do
table.insert(bagsToShow, { bagID = bagID, needsSpacing = (i == 1) })
end
end
if table.getn(herbBags) > 0 then
for i, bagID in ipairs(herbBags) do
table.insert(bagsToShow, { bagID = bagID, needsSpacing = (i == 1) })
end
end
if table.getn(ammoQuiverBags) > 0 then
for i, bagID in ipairs(ammoQuiverBags) do
table.insert(bagsToShow, { bagID = bagID, needsSpacing = (i == 1) })
end
end
for _, bagInfo in ipairs(bagsToShow) do
local bagID = bagInfo.bagID
local bag = bankData and bankData[bagID]
-- Add spacing before first of each specialized section
if bagInfo.needsSpacing then
if col > 0 then
col = 0
row = row + 1
end
row = row + 0.5
end
-- Get slot count for this bag
local numSlots
if isOtherChar and bag and bag.numSlots then
numSlots = bag.numSlots
else
numSlots = addon.Modules.Utils:GetBagSlotCount(bagID)
end
if numSlots and numSlots > 0 then
for slot = 1, numSlots do
local itemData = bag and bag.slots and bag.slots[slot] or nil
-- Check if item matches search filter
local matchesFilter = self:PassesSearchFilter(itemData)
-- Ensure a per-bag parent frame exists and carries the bag ID
@@ -232,33 +294,24 @@ function BankFrame:DisplayItems(bankData, isOtherChar, charName)
bankBagParent = bankBagParents[bagID]
local button = Guda_GetItemButton(bankBagParent)
if button.isBagSlot then break end
-- Ensure this is NOT a bag slot button
if button.isBagSlot then
break
end
button.inUse = true
button.inUse = true -- Mark this button as actively in use
-- Position button
local xPos = x + (col * (buttonSize + spacing))
local yPos = y - (row * (buttonSize + spacing))
button:ClearAllPoints()
button:SetPoint("TOPLEFT", itemContainer, "TOPLEFT", xPos, yPos)
-- Set item data with filter match info
-- Pass isReadOnlyMode to disable interaction for saved banks
Guda_ItemButton_SetItem(button, bagID, slot, itemData, true, isOtherChar and charName or nil, matchesFilter, isReadOnlyMode)
-- Advance position
col = col + 1
if col >= perRow then
col = 0
row = row + 1
end
end
end
end
end
@@ -608,12 +661,12 @@ function Guda_BankFrame_Sort()
return
end
local success, message = addon.Modules.SortEngine:ExecuteSort(
function() return addon.Modules.SortEngine:SortBank() end,
function() return addon.Modules.SortEngine:AnalyzeBank() end,
function() BankFrame:Update() end,
"bank"
)
local success, message = addon.Modules.SortEngine:ExecuteSort(
function() return addon.Modules.SortEngine:SortBankPass() end,
function() return addon.Modules.SortEngine:AnalyzeBank() end,
function() BankFrame:Update() end,
"bank"
)
if not success and message == "already sorted" then
addon:Print("Bank is already sorted!")
+25
View File
@@ -876,6 +876,31 @@ function Guda_ItemButton_OnEnter(self)
GameTooltip:SetBagItem(self.bagID, self.slotID)
end
GameTooltip:Show()
-- Debug: print hovered item's texture path to chat
-- Uses GetItemInfo on the hovered item's ID
--if self.hasItem then
-- local link = nil
-- if self.itemData and self.itemData.link then
-- link = self.itemData.link
-- else
-- -- Fallback to live bag query
-- link = GetContainerItemLink(self.bagID, self.slotID)
-- end
-- if link and addon and addon.Modules and addon.Modules.Utils and addon.Modules.Utils.ExtractItemID then
-- local itemID = addon.Modules.Utils:ExtractItemID(link)
-- if itemID and addon.Modules.Utils.GetItemInfoSafe then
-- local name, itemLink, itemRarity, itemLevel, itemCategory, itemType, itemStackCount,
-- itemSubType, itemTexture, itemEquipLoc, itemSellPrice = addon.Modules.Utils:GetItemInfoSafe(itemID)
-- if addon and addon.Print then
-- addon:Print("itemTexture: %s", tostring(itemTexture))
-- addon:Print("itemCategory: %s", tostring(itemCategory))
-- addon:Print("itemType: %s", tostring(itemType))
-- addon:Print("itemType: %s", tostring(itemType))
-- end
-- end
-- end
--end
-- Handle merchant sell cursor (same approach as BagShui)
if MerchantFrame:IsShown() and not self.isBank and not self.otherChar and self.hasItem then
ShowContainerSellCursor(self.bagID, self.slotID)