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 [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 -- Weapon subtypes that should NOT be marked as junk
C.PROFESSION_TOOL_SUBTYPES = { C.PROFESSION_TOOL_SUBTYPES = {
["Fishing Pole"] = true, ["Fishing Pole"] = true,
+11
View File
@@ -172,6 +172,17 @@ local function DetectQuestItem(lines, itemData)
local isQuestItem = false local isQuestItem = false
local isQuestStarter = 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 -- Check item category first
if itemData and itemData.class == "Quest" then if itemData and itemData.class == "Quest" then
isQuestItem = true isQuestItem = true
+5
View File
@@ -841,6 +841,11 @@ function Utils:IsQuestItem(bagID, slotID, itemData, isOtherChar, isBank)
end end
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) -- Check if item is equipment (should not be classified as quest unless explicitly Quest category)
local isEquipment = (itemCategory == "Weapon" or itemCategory == "Armor" or local isEquipment = (itemCategory == "Weapon" or itemCategory == "Armor" or
itemType == "Weapon" or itemType == "Armor") itemType == "Weapon" or itemType == "Armor")
+8
View File
@@ -221,6 +221,14 @@ function BagScanner:ScanSlot(bagID, slot)
itemData.iLevel = iLevel itemData.iLevel = iLevel
itemData.type = itemType itemData.type = itemType
itemData.class = itemCategory 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.subclass = itemSubType
itemData.equipSlot = itemEquipLoc itemData.equipSlot = itemEquipLoc
itemData.locked = locked 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.sortedClass = 1 -- All equippable gear gets priority class
item.equipSlotOrder = EQUIP_SLOT_ORDER[itemSubType] or 999 item.equipSlotOrder = EQUIP_SLOT_ORDER[itemSubType] or 999
else 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) -- Check if item is a permanent enchant (should NOT be Quest)
local itemProps = GetItemProperties(item.bagID, item.slot, item.data.link) 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) item.sortedClass = 6 -- Same as Tools, comes before Quest (7)
-- Heuristic: Detect items that should be in the Quest category (priority 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) -- 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) 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 item.sortedClass = CATEGORY_ORDER["Quest"] or 7
elseif IsQuestItemTooltip(item.bagID, item.slot, item.data) then elseif IsQuestItemTooltip(item.bagID, item.slot, item.data) then
item.sortedClass = CATEGORY_ORDER["Quest"] or 7 item.sortedClass = CATEGORY_ORDER["Quest"] or 7
@@ -859,8 +865,8 @@ local function AddSortKeys(items)
item.isQuestUsable = false item.isQuestUsable = false
item.isPermanentEnchant = isPermanentEnchant -- Store for potential use in sorting item.isPermanentEnchant = isPermanentEnchant -- Store for potential use in sorting
local nameLower = string.lower(item.itemName) local nameLower = string.lower(item.itemName)
if not isPermanentEnchant then if not isPermanentEnchant and not (addon.Constants.QUEST_CATEGORY_EXCLUSIONS and addon.Constants.QUEST_CATEGORY_EXCLUSIONS[itemID]) then
if itemCategory == "Quest" or string.find(nameLower, "quest") or item.data.class == "Quest" or IsQuestItemTooltip(item.bagID, item.slot, item.data) then if itemCategory == "Quest" or item.data.class == "Quest" or IsQuestItemTooltip(item.bagID, item.slot, item.data) then
item.isQuest = true item.isQuest = true
if IsQuestItemStarter(item.bagID, item.slot, item.data) then item.isQuestStarter = true end 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 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 return false, false
end 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) -- Junk Icon Pool (Baganator-inspired memory optimization)
-- Uses frame pooling to avoid creating new frames per button -- Uses frame pooling to avoid creating new frames per button
@@ -400,6 +464,14 @@ function Guda_ItemButton_OnLoad(self)
self.qualityBorder = backdrop self.qualityBorder = backdrop
end 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) -- Create quest item border (golden, higher priority than quality border)
if not self.questBorder then if not self.questBorder then
local questBackdrop = CreateFrame("Frame", nil, self) local questBackdrop = CreateFrame("Frame", nil, self)
@@ -564,6 +636,7 @@ local function ResetButtonVisualState(self)
if self.questBorder then self.questBorder:Hide() end if self.questBorder then self.questBorder:Hide() end
if self.questIcon then self.questIcon:Hide() end if self.questIcon then self.questIcon:Hide() end
if self.qualityBorder then self.qualityBorder:Hide() end if self.qualityBorder then self.qualityBorder:Hide() end
HideInnerShadow(self.innerShadow)
if self.unusableOverlay then self.unusableOverlay:Hide() end if self.unusableOverlay then self.unusableOverlay:Hide() end
HideJunkIcon(self) HideJunkIcon(self)
@@ -763,11 +836,13 @@ local function UpdateQualityBorder(self, itemQuality, itemLink, bagID, Utils)
-- Special border for keyring items (cyan/blue) -- Special border for keyring items (cyan/blue)
self.qualityBorder:SetBackdropBorderColor(0.2, 0.8, 1.0, 1) self.qualityBorder:SetBackdropBorderColor(0.2, 0.8, 1.0, 1)
self.qualityBorder:Show() self.qualityBorder:Show()
ShowInnerShadow(self.innerShadow, 0.2, 0.8, 1.0)
return return
end end
if not itemQuality then if not itemQuality then
self.qualityBorder:Hide() self.qualityBorder:Hide()
HideInnerShadow(self.innerShadow)
return return
end end
@@ -796,8 +871,10 @@ local function UpdateQualityBorder(self, itemQuality, itemLink, bagID, Utils)
end end
self.qualityBorder:SetBackdropBorderColor(r, g, b, 1) self.qualityBorder:SetBackdropBorderColor(r, g, b, 1)
self.qualityBorder:Show() self.qualityBorder:Show()
ShowInnerShadow(self.innerShadow, r, g, b)
else else
self.qualityBorder:Hide() self.qualityBorder:Hide()
HideInnerShadow(self.innerShadow)
end end
end end
@@ -852,8 +929,10 @@ local function ClearItemButton(self, emptySlotBg, countText, bagID)
if bagID == -2 then if bagID == -2 then
self.qualityBorder:SetBackdropBorderColor(0.2, 0.8, 1.0, 0.5) self.qualityBorder:SetBackdropBorderColor(0.2, 0.8, 1.0, 0.5)
self.qualityBorder:Show() self.qualityBorder:Show()
ShowInnerShadow(self.innerShadow, 0.2, 0.8, 1.0)
else else
self.qualityBorder:Hide() self.qualityBorder:Hide()
HideInnerShadow(self.innerShadow)
end end
end end
@@ -1176,12 +1255,13 @@ function Guda_ItemButton_SetItem(self, bagID, slotID, itemData, isBank, otherCha
countText:Hide() countText:Hide()
end end
-- Set quality border -- Set quality border and inner shadow
if self.qualityBorder then if self.qualityBorder then
if bagID == -2 then if bagID == -2 then
-- Special border for keyring items (cyan/blue) -- Special border for keyring items (cyan/blue)
self.qualityBorder:SetBackdropBorderColor(0.2, 0.8, 1.0, 1) self.qualityBorder:SetBackdropBorderColor(0.2, 0.8, 1.0, 1)
self.qualityBorder:Show() self.qualityBorder:Show()
ShowInnerShadow(self.innerShadow, 0.2, 0.8, 1.0)
elseif itemQuality then elseif itemQuality then
-- Check settings to determine if we should show borders -- Check settings to determine if we should show borders
local showEquipmentBorder, showOtherBorder local showEquipmentBorder, showOtherBorder
@@ -1215,11 +1295,14 @@ function Guda_ItemButton_SetItem(self, bagID, slotID, itemData, isBank, otherCha
end end
self.qualityBorder:SetBackdropBorderColor(r, g, b, 1) self.qualityBorder:SetBackdropBorderColor(r, g, b, 1)
self.qualityBorder:Show() self.qualityBorder:Show()
ShowInnerShadow(self.innerShadow, r, g, b)
else else
self.qualityBorder:Hide() self.qualityBorder:Hide()
HideInnerShadow(self.innerShadow)
end end
else else
self.qualityBorder:Hide() self.qualityBorder:Hide()
HideInnerShadow(self.innerShadow)
end end
end end
@@ -1283,8 +1366,10 @@ function Guda_ItemButton_SetItem(self, bagID, slotID, itemData, isBank, otherCha
if bagID == -2 then if bagID == -2 then
self.qualityBorder:SetBackdropBorderColor(0.2, 0.8, 1.0, 0.5) -- Dimmer cyan for empty slots self.qualityBorder:SetBackdropBorderColor(0.2, 0.8, 1.0, 0.5) -- Dimmer cyan for empty slots
self.qualityBorder:Show() self.qualityBorder:Show()
ShowInnerShadow(self.innerShadow, 0.2, 0.8, 1.0)
else else
self.qualityBorder:Hide() self.qualityBorder:Hide()
HideInnerShadow(self.innerShadow)
end end
end end
@@ -1490,6 +1575,33 @@ function Guda_ItemButton_OnEnter(self)
GameTooltip:Show() 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) -- Handle merchant sell cursor (same approach as BagShui)
if MerchantFrame:IsShown() and not self.isBank and not self.otherChar and self.hasItem then if MerchantFrame:IsShown() and not self.isBank and not self.otherChar and self.hasItem then
ShowContainerSellCursor(self.bagID, self.slotID) ShowContainerSellCursor(self.bagID, self.slotID)
@@ -1501,6 +1613,7 @@ end
-- OnLeave handler -- OnLeave handler
function Guda_ItemButton_OnLeave(self) function Guda_ItemButton_OnLeave(self)
self._debugPrinted = nil
-- Clear any viewed character hint on the tooltip when leaving -- Clear any viewed character hint on the tooltip when leaving
if GameTooltip then if GameTooltip then
GameTooltip.GudaViewedCharacter = nil GameTooltip.GudaViewedCharacter = nil
-36
View File
@@ -30,7 +30,6 @@ function TrackedItemBar:ScanForTrackedItems()
local itemOrder = {} local itemOrder = {}
local itemIsQuest = {} local itemIsQuest = {}
local itemIsQuestStarter = {} local itemIsQuestStarter = {}
local itemQualities = {}
-- Scan backpack and 4 bags -- Scan backpack and 4 bags
for bagID = 0, 4 do for bagID = 0, 4 do
@@ -51,9 +50,6 @@ function TrackedItemBar:ScanForTrackedItems()
local isQuest, isStarter = IsQuestItem(bagID, slotID) local isQuest, isStarter = IsQuestItem(bagID, slotID)
itemIsQuest[id] = isQuest itemIsQuest[id] = isQuest
itemIsQuestStarter[id] = isStarter itemIsQuestStarter[id] = isStarter
-- Get item quality
local _, _, itemQuality = GetItemInfo(id)
itemQualities[id] = tonumber(itemQuality)
table.insert(itemOrder, id) table.insert(itemOrder, id)
end end
itemCounts[id] = itemCounts[id] + count itemCounts[id] = itemCounts[id] + count
@@ -88,7 +84,6 @@ function TrackedItemBar:ScanForTrackedItems()
isQuestStarter = itemIsQuestStarter[id], isQuestStarter = itemIsQuestStarter[id],
isUnusable = isUnusable, isUnusable = isUnusable,
isJunk = isJunk, isJunk = isJunk,
quality = itemQualities[id],
}) })
end end
end end
@@ -112,7 +107,6 @@ function TrackedItemBar:Update()
-- Hide all buttons and their overlays initially -- Hide all buttons and their overlays initially
for _, btn in ipairs(buttons) do for _, btn in ipairs(buttons) do
btn:Hide() btn:Hide()
if btn.qualityBorder then btn.qualityBorder:Hide() end
if btn.unusableOverlay then btn.unusableOverlay:Hide() end if btn.unusableOverlay then btn.unusableOverlay:Hide() end
if btn.junkIcon then btn.junkIcon:Hide() end if btn.junkIcon then btn.junkIcon:Hide() end
end end
@@ -136,19 +130,6 @@ function TrackedItemBar:Update()
questBorder:Hide() questBorder:Hide()
button.questBorder = questBorder 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) -- Create quest icon (question mark in corner)
local questIcon = CreateFrame("Frame", nil, button) local questIcon = CreateFrame("Frame", nil, button)
questIcon:SetFrameLevel(button:GetFrameLevel() + 7) questIcon:SetFrameLevel(button:GetFrameLevel() + 7)
@@ -258,23 +239,6 @@ function TrackedItemBar:Update()
emptyBg:SetHeight(buttonSize) emptyBg:SetHeight(buttonSize)
end 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 -- Position and show/hide quest border
if button.questBorder then if button.questBorder then
button.questBorder:ClearAllPoints() button.questBorder:ClearAllPoints()