fix: juju powers as consumables

This commit is contained in:
Vati
2026-02-26 21:47:12 +04:00
parent 09bc895b5c
commit b07ea69994
7 changed files with 161 additions and 42 deletions
+12
View File
@@ -81,6 +81,18 @@ C.PROFESSION_TOOL_IDS = {
[20824] = true, -- Simple Grinder
}
-- Items classified as "Quest" by GetItemInfo but are actually consumables
-- These get reclassified as "Consumable" for category view and sorting
C.QUEST_CATEGORY_EXCLUSIONS = {
[12450] = true, -- Juju Flurry
[12451] = true, -- Juju Power
[12455] = true, -- Juju Ember
[12457] = true, -- Juju Chill
[12458] = true, -- Juju Guile
[12459] = true, -- Juju Escape
[12460] = true, -- Juju Might
}
-- Weapon subtypes that should NOT be marked as junk
C.PROFESSION_TOOL_SUBTYPES = {
["Fishing Pole"] = true,
+11
View File
@@ -172,6 +172,17 @@ local function DetectQuestItem(lines, itemData)
local isQuestItem = false
local isQuestStarter = false
-- Early exit: exclude known non-quest items misclassified by the API
if itemData and itemData.link and addon.Constants and addon.Constants.QUEST_CATEGORY_EXCLUSIONS then
local _, _, idStr = string.find(itemData.link, "item:(%d+)")
if idStr then
local id = tonumber(idStr)
if id and addon.Constants.QUEST_CATEGORY_EXCLUSIONS[id] then
return false, false
end
end
end
-- Check item category first
if itemData and itemData.class == "Quest" then
isQuestItem = true
+5
View File
@@ -841,6 +841,11 @@ function Utils:IsQuestItem(bagID, slotID, itemData, isOtherChar, isBank)
end
end
-- Early exit: exclude known non-quest items that the API misclassifies as "Quest"
if itemID and addon.Constants and addon.Constants.QUEST_CATEGORY_EXCLUSIONS and addon.Constants.QUEST_CATEGORY_EXCLUSIONS[itemID] then
return false, false
end
-- Check if item is equipment (should not be classified as quest unless explicitly Quest category)
local isEquipment = (itemCategory == "Weapon" or itemCategory == "Armor" or
itemType == "Weapon" or itemType == "Armor")
+8
View File
@@ -221,6 +221,14 @@ function BagScanner:ScanSlot(bagID, slot)
itemData.iLevel = iLevel
itemData.type = itemType
itemData.class = itemCategory
-- Override misclassified Quest items (e.g. Juju consumables) to Consumable
if itemCategory == "Quest" and itemLink and addon.Constants and addon.Constants.QUEST_CATEGORY_EXCLUSIONS then
local itemID = addon.Modules.Utils:ExtractItemID(itemLink)
if itemID and addon.Constants.QUEST_CATEGORY_EXCLUSIONS[itemID] then
itemData.class = "Consumable"
itemData.type = "Consumable"
end
end
itemData.subclass = itemSubType
itemData.equipSlot = itemEquipLoc
itemData.locked = locked
+11 -5
View File
@@ -800,7 +800,12 @@ local function AddSortKeys(items)
item.sortedClass = 1 -- All equippable gear gets priority class
item.equipSlotOrder = EQUIP_SLOT_ORDER[itemSubType] or 999
else
item.sortedClass = CATEGORY_ORDER[itemCategory] or 99
-- Override misclassified Quest items (e.g. Juju consumables) to Consumable
if itemCategory == "Quest" and (addon.Constants.QUEST_CATEGORY_EXCLUSIONS and addon.Constants.QUEST_CATEGORY_EXCLUSIONS[itemID]) then
item.sortedClass = CATEGORY_ORDER["Consumable"] or 2
else
item.sortedClass = CATEGORY_ORDER[itemCategory] or 99
end
-- Check if item is a permanent enchant (should NOT be Quest)
local itemProps = GetItemProperties(item.bagID, item.slot, item.data.link)
@@ -812,9 +817,10 @@ local function AddSortKeys(items)
item.sortedClass = 6 -- Same as Tools, comes before Quest (7)
-- Heuristic: Detect items that should be in the Quest category (priority 7)
-- but aren't categorized as such by the game (e.g. some "Manual" items)
elseif item.sortedClass ~= (CATEGORY_ORDER["Quest"] or 7) then
-- Skip items with a known non-Quest category (e.g. Consumable, Trade Goods)
elseif item.sortedClass ~= (CATEGORY_ORDER["Quest"] or 7) and not CATEGORY_ORDER[itemCategory] then
local nameLower = string.lower(item.itemName)
if string.find(nameLower, "manual") or string.find(nameLower, "quest") then
if string.find(nameLower, "manual") then
item.sortedClass = CATEGORY_ORDER["Quest"] or 7
elseif IsQuestItemTooltip(item.bagID, item.slot, item.data) then
item.sortedClass = CATEGORY_ORDER["Quest"] or 7
@@ -859,8 +865,8 @@ local function AddSortKeys(items)
item.isQuestUsable = false
item.isPermanentEnchant = isPermanentEnchant -- Store for potential use in sorting
local nameLower = string.lower(item.itemName)
if not isPermanentEnchant then
if itemCategory == "Quest" or string.find(nameLower, "quest") or item.data.class == "Quest" or IsQuestItemTooltip(item.bagID, item.slot, item.data) then
if not isPermanentEnchant and not (addon.Constants.QUEST_CATEGORY_EXCLUSIONS and addon.Constants.QUEST_CATEGORY_EXCLUSIONS[itemID]) then
if itemCategory == "Quest" or item.data.class == "Quest" or IsQuestItemTooltip(item.bagID, item.slot, item.data) then
item.isQuest = true
if IsQuestItemStarter(item.bagID, item.slot, item.data) then item.isQuestStarter = true end
if IsQuestItemUsable(item.bagID, item.slot, item.data) then item.isQuestUsable = true end
+114 -1
View File
@@ -84,6 +84,70 @@ local function IsQuestItem(bagID, slotID, isBank, itemData)
return false, false
end
--=====================================================
-- Inner Shadow (inset quality glow, GudaBags-inspired)
-- 4 gradient textures along edges colored by item quality
--=====================================================
local INNER_SHADOW_SIZE = 4
local INNER_SHADOW_ALPHA = 0.5
-- Create the 4-edge inner shadow textures on a button, anchored to an icon texture
local function CreateInnerShadow(button, anchorTo)
local shadow = {}
-- Top edge
shadow.top = button:CreateTexture(nil, "ARTWORK", nil, 1)
shadow.top:SetPoint("TOPLEFT", anchorTo, "TOPLEFT", 0, 0)
shadow.top:SetPoint("TOPRIGHT", anchorTo, "TOPRIGHT", 0, 0)
shadow.top:SetHeight(INNER_SHADOW_SIZE)
shadow.top:SetTexture("Interface\\ChatFrame\\ChatFrameBackground")
shadow.top:Hide()
-- Bottom edge
shadow.bottom = button:CreateTexture(nil, "ARTWORK", nil, 1)
shadow.bottom:SetPoint("BOTTOMLEFT", anchorTo, "BOTTOMLEFT", 0, 0)
shadow.bottom:SetPoint("BOTTOMRIGHT", anchorTo, "BOTTOMRIGHT", 0, 0)
shadow.bottom:SetHeight(INNER_SHADOW_SIZE)
shadow.bottom:SetTexture("Interface\\ChatFrame\\ChatFrameBackground")
shadow.bottom:Hide()
-- Left edge
shadow.left = button:CreateTexture(nil, "ARTWORK", nil, 1)
shadow.left:SetPoint("TOPLEFT", anchorTo, "TOPLEFT", 0, 0)
shadow.left:SetPoint("BOTTOMLEFT", anchorTo, "BOTTOMLEFT", 0, 0)
shadow.left:SetWidth(INNER_SHADOW_SIZE)
shadow.left:SetTexture("Interface\\ChatFrame\\ChatFrameBackground")
shadow.left:Hide()
-- Right edge
shadow.right = button:CreateTexture(nil, "ARTWORK", nil, 1)
shadow.right:SetPoint("TOPRIGHT", anchorTo, "TOPRIGHT", 0, 0)
shadow.right:SetPoint("BOTTOMRIGHT", anchorTo, "BOTTOMRIGHT", 0, 0)
shadow.right:SetWidth(INNER_SHADOW_SIZE)
shadow.right:SetTexture("Interface\\ChatFrame\\ChatFrameBackground")
shadow.right:Hide()
return shadow
end
-- Show inner shadow with a given quality color
local function ShowInnerShadow(shadow, r, g, b)
if not shadow then return end
local a = INNER_SHADOW_ALPHA
shadow.top:SetGradientAlpha("VERTICAL", r, g, b, 0, r, g, b, a)
shadow.top:Show()
shadow.bottom:SetGradientAlpha("VERTICAL", r, g, b, a, r, g, b, 0)
shadow.bottom:Show()
shadow.left:SetGradientAlpha("HORIZONTAL", r, g, b, a, r, g, b, 0)
shadow.left:Show()
shadow.right:SetGradientAlpha("HORIZONTAL", r, g, b, 0, r, g, b, a)
shadow.right:Show()
end
-- Hide inner shadow
local function HideInnerShadow(shadow)
if not shadow then return end
shadow.top:Hide()
shadow.bottom:Hide()
shadow.left:Hide()
shadow.right:Hide()
end
--=====================================================
-- Junk Icon Pool (Baganator-inspired memory optimization)
-- Uses frame pooling to avoid creating new frames per button
@@ -400,6 +464,14 @@ function Guda_ItemButton_OnLoad(self)
self.qualityBorder = backdrop
end
-- Create inner shadow for quality color glow (anchored to icon texture)
if not self.innerShadow then
local iconTex = getglobal(self:GetName() .. "IconTexture")
if iconTex then
self.innerShadow = CreateInnerShadow(self, iconTex)
end
end
-- Create quest item border (golden, higher priority than quality border)
if not self.questBorder then
local questBackdrop = CreateFrame("Frame", nil, self)
@@ -564,6 +636,7 @@ local function ResetButtonVisualState(self)
if self.questBorder then self.questBorder:Hide() end
if self.questIcon then self.questIcon:Hide() end
if self.qualityBorder then self.qualityBorder:Hide() end
HideInnerShadow(self.innerShadow)
if self.unusableOverlay then self.unusableOverlay:Hide() end
HideJunkIcon(self)
@@ -763,11 +836,13 @@ local function UpdateQualityBorder(self, itemQuality, itemLink, bagID, Utils)
-- Special border for keyring items (cyan/blue)
self.qualityBorder:SetBackdropBorderColor(0.2, 0.8, 1.0, 1)
self.qualityBorder:Show()
ShowInnerShadow(self.innerShadow, 0.2, 0.8, 1.0)
return
end
if not itemQuality then
self.qualityBorder:Hide()
HideInnerShadow(self.innerShadow)
return
end
@@ -796,8 +871,10 @@ local function UpdateQualityBorder(self, itemQuality, itemLink, bagID, Utils)
end
self.qualityBorder:SetBackdropBorderColor(r, g, b, 1)
self.qualityBorder:Show()
ShowInnerShadow(self.innerShadow, r, g, b)
else
self.qualityBorder:Hide()
HideInnerShadow(self.innerShadow)
end
end
@@ -852,8 +929,10 @@ local function ClearItemButton(self, emptySlotBg, countText, bagID)
if bagID == -2 then
self.qualityBorder:SetBackdropBorderColor(0.2, 0.8, 1.0, 0.5)
self.qualityBorder:Show()
ShowInnerShadow(self.innerShadow, 0.2, 0.8, 1.0)
else
self.qualityBorder:Hide()
HideInnerShadow(self.innerShadow)
end
end
@@ -1176,12 +1255,13 @@ function Guda_ItemButton_SetItem(self, bagID, slotID, itemData, isBank, otherCha
countText:Hide()
end
-- Set quality border
-- Set quality border and inner shadow
if self.qualityBorder then
if bagID == -2 then
-- Special border for keyring items (cyan/blue)
self.qualityBorder:SetBackdropBorderColor(0.2, 0.8, 1.0, 1)
self.qualityBorder:Show()
ShowInnerShadow(self.innerShadow, 0.2, 0.8, 1.0)
elseif itemQuality then
-- Check settings to determine if we should show borders
local showEquipmentBorder, showOtherBorder
@@ -1215,11 +1295,14 @@ function Guda_ItemButton_SetItem(self, bagID, slotID, itemData, isBank, otherCha
end
self.qualityBorder:SetBackdropBorderColor(r, g, b, 1)
self.qualityBorder:Show()
ShowInnerShadow(self.innerShadow, r, g, b)
else
self.qualityBorder:Hide()
HideInnerShadow(self.innerShadow)
end
else
self.qualityBorder:Hide()
HideInnerShadow(self.innerShadow)
end
end
@@ -1283,8 +1366,10 @@ function Guda_ItemButton_SetItem(self, bagID, slotID, itemData, isBank, otherCha
if bagID == -2 then
self.qualityBorder:SetBackdropBorderColor(0.2, 0.8, 1.0, 0.5) -- Dimmer cyan for empty slots
self.qualityBorder:Show()
ShowInnerShadow(self.innerShadow, 0.2, 0.8, 1.0)
else
self.qualityBorder:Hide()
HideInnerShadow(self.innerShadow)
end
end
@@ -1490,6 +1575,33 @@ function Guda_ItemButton_OnEnter(self)
GameTooltip:Show()
-- Debug: print item classification info to chat when debug mode is active
if addon.DEBUG and self.hasItem and self.bagID and self.slotID and not self._debugPrinted then
local link = self.itemData and self.itemData.link or GetContainerItemLink(self.bagID, self.slotID)
if link then
local itemID = addon.Modules.Utils:ExtractItemID(link)
if itemID then
local itemName, _, itemRarity, itemLevel, itemCategory, itemType, _, itemSubType = GetItemInfo(itemID)
addon:Debug("Item: %s (ID: %s)", tostring(itemName), tostring(itemID))
addon:Debug(" Category: %s | Type: %s | SubType: %s", tostring(itemCategory), tostring(itemType), tostring(itemSubType))
addon:Debug(" Quality: %s | iLvl: %s", tostring(itemRarity), tostring(itemLevel))
if addon.Modules.ItemDetection then
local props = addon.Modules.ItemDetection:GetItemProperties({link = link}, self.bagID, self.slotID)
local flags = {}
if props.isQuestItem then table.insert(flags, "Quest") end
if props.isQuestStarter then table.insert(flags, "Starter") end
if props.isQuestUsable then table.insert(flags, "Usable") end
if props.isJunk then table.insert(flags, "Junk") end
if props.isPermanentEnchant then table.insert(flags, "Enchant") end
if props.isUnusable then table.insert(flags, "Unusable") end
local flagStr = table.getn(flags) > 0 and table.concat(flags, ", ") or "none"
addon:Debug(" Flags: %s", flagStr)
end
self._debugPrinted = true
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)
@@ -1501,6 +1613,7 @@ end
-- OnLeave handler
function Guda_ItemButton_OnLeave(self)
self._debugPrinted = nil
-- Clear any viewed character hint on the tooltip when leaving
if GameTooltip then
GameTooltip.GudaViewedCharacter = nil
-36
View File
@@ -30,7 +30,6 @@ function TrackedItemBar:ScanForTrackedItems()
local itemOrder = {}
local itemIsQuest = {}
local itemIsQuestStarter = {}
local itemQualities = {}
-- Scan backpack and 4 bags
for bagID = 0, 4 do
@@ -51,9 +50,6 @@ function TrackedItemBar:ScanForTrackedItems()
local isQuest, isStarter = IsQuestItem(bagID, slotID)
itemIsQuest[id] = isQuest
itemIsQuestStarter[id] = isStarter
-- Get item quality
local _, _, itemQuality = GetItemInfo(id)
itemQualities[id] = tonumber(itemQuality)
table.insert(itemOrder, id)
end
itemCounts[id] = itemCounts[id] + count
@@ -88,7 +84,6 @@ function TrackedItemBar:ScanForTrackedItems()
isQuestStarter = itemIsQuestStarter[id],
isUnusable = isUnusable,
isJunk = isJunk,
quality = itemQualities[id],
})
end
end
@@ -112,7 +107,6 @@ function TrackedItemBar:Update()
-- Hide all buttons and their overlays initially
for _, btn in ipairs(buttons) do
btn:Hide()
if btn.qualityBorder then btn.qualityBorder:Hide() end
if btn.unusableOverlay then btn.unusableOverlay:Hide() end
if btn.junkIcon then btn.junkIcon:Hide() end
end
@@ -136,19 +130,6 @@ function TrackedItemBar:Update()
questBorder:Hide()
button.questBorder = questBorder
-- Create quality border (colored by rarity)
local qualityBorder = CreateFrame("Frame", nil, button)
qualityBorder:SetFrameLevel(button:GetFrameLevel() + 5)
qualityBorder:SetBackdrop({
bgFile = nil,
edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
edgeSize = 12,
insets = {left = 4, right = 4, top = 4, bottom = 4}
})
qualityBorder:SetBackdropBorderColor(0, 0, 0, 0)
qualityBorder:Hide()
button.qualityBorder = qualityBorder
-- Create quest icon (question mark in corner)
local questIcon = CreateFrame("Frame", nil, button)
questIcon:SetFrameLevel(button:GetFrameLevel() + 7)
@@ -258,23 +239,6 @@ function TrackedItemBar:Update()
emptyBg:SetHeight(buttonSize)
end
-- Position and show/hide quality border
if button.qualityBorder then
button.qualityBorder:ClearAllPoints()
button.qualityBorder:SetPoint("TOPLEFT", icon, "TOPLEFT", -5, 5)
button.qualityBorder:SetPoint("BOTTOMRIGHT", icon, "BOTTOMRIGHT", 5, -5)
if info.quality and info.quality >= 1 then
local r, g, b = 1, 1, 1
if addon.Modules.Utils and addon.Modules.Utils.GetQualityColor then
r, g, b = addon.Modules.Utils:GetQualityColor(info.quality)
end
button.qualityBorder:SetBackdropBorderColor(r, g, b, 1)
button.qualityBorder:Show()
else
button.qualityBorder:Hide()
end
end
-- Position and show/hide quest border
if button.questBorder then
button.questBorder:ClearAllPoints()