Merge pull request #85 from BanditTech/main

Add Deconstruct mode to the bags
This commit is contained in:
Andrew
2025-11-09 10:47:06 -07:00
committed by GitHub
13 changed files with 655 additions and 4 deletions
+3
View File
@@ -69,6 +69,9 @@ L["Confused.. Try Again!"] = "Verwirrt.. Versuche es erneut!"
L["Continue"] = "Fortfahren" L["Continue"] = "Fortfahren"
L["Coords"] = "Koordinaten" L["Coords"] = "Koordinaten"
L["Count"] = "Zähler" L["Count"] = "Zähler"
L["Current state: %s."] = "Klicken zum Umschalten.\nAktueller Status: %s."
L["Deconstruct Mode"] = "Zerlegen Modus"
L["Deconstruct Mode Desc"] = "Ermöglicht das Entzaubern, Mahlen, Sondieren und Öffnen von Gegenständen."
L["DND"] = "DND" L["DND"] = "DND"
L["DPS"] = "DPS" L["DPS"] = "DPS"
L["Dark"] = "Dunkel" L["Dark"] = "Dunkel"
+3
View File
@@ -72,6 +72,9 @@ L["Confused.. Try Again!"] = true
L["Continue"] = true L["Continue"] = true
L["Coords"] = true L["Coords"] = true
L["Count"] = true L["Count"] = true
L["Current state: %s."] = "Click to toggle.\nCurrent state: %s."
L["Deconstruct Mode"] = true
L["Deconstruct Mode Desc"] = "Allow you to disenchant/mill/prospect/unlock items."
L["DND"] = true L["DND"] = true
L["DPS"] = true L["DPS"] = true
L["Dark"] = true L["Dark"] = true
+3
View File
@@ -69,6 +69,9 @@ L["Confused.. Try Again!"] = "Confundido... ¡Intenta de Nuevo!"
L["Continue"] = "Continuar" L["Continue"] = "Continuar"
L["Coords"] = true L["Coords"] = true
L["Count"] = "Contador" L["Count"] = "Contador"
L["Current state: %s."] = "Haz clic para alternar.\nEstado actual: %s."
L["Deconstruct Mode"] = "Modo Deconstruir"
L["Deconstruct Mode Desc"] = "Permite desencantar, moler, prospectar y abrir objetos."
L["DND"] = "Oc" L["DND"] = "Oc"
L["DPS"] = "DPS" L["DPS"] = "DPS"
L["Dark"] = "Oscuro" L["Dark"] = "Oscuro"
+3
View File
@@ -69,6 +69,9 @@ L["Confused.. Try Again!"] = "Confus... Essayez à nouveau !"
L["Continue"] = true L["Continue"] = true
L["Coords"] = "Coordonnées" L["Coords"] = "Coordonnées"
L["Count"] = "Nombre" L["Count"] = "Nombre"
L["Current state: %s."] = "Cliquez pour basculer.\nÉtat actuel : %s."
L["Deconstruct Mode"] = "Mode Déconstruction"
L["Deconstruct Mode Desc"] = "Permet de désenchanter, moudre, prospecter et déverrouiller des objets."
L["DND"] = "OQP" L["DND"] = "OQP"
L["DPS"] = "DPS" L["DPS"] = "DPS"
L["Dark"] = "Sombre" L["Dark"] = "Sombre"
+3
View File
@@ -69,6 +69,9 @@ L["Confused.. Try Again!"] = "작업에 혼선이 있었습니다. 다시 시도
L["Continue"] = true L["Continue"] = true
L["Coords"] = "좌표" L["Coords"] = "좌표"
L["Count"] = "갯수" L["Count"] = "갯수"
L["Current state: %s."] = "클릭하여 전환합니다.\n현재 상태: %s."
L["Deconstruct Mode"] = "분해 모드"
L["Deconstruct Mode Desc"] = "마법 부여 분해, 가루로 만들기, 세공 및 잠금 해제를 할 수 있습니다."
L["DND"] = "다른 용무 중" L["DND"] = "다른 용무 중"
L["DPS"] = "DPS" L["DPS"] = "DPS"
L["Dark"] = "어두운 느낌" L["Dark"] = "어두운 느낌"
+3
View File
@@ -69,6 +69,9 @@ L["Confused.. Try Again!"] = "Confuso... Tente novamente!"
L["Continue"] = true L["Continue"] = true
L["Coords"] = true L["Coords"] = true
L["Count"] = "Contar" L["Count"] = "Contar"
L["Current state: %s."] = "Clique para alternar.\nEstado atual: %s."
L["Deconstruct Mode"] = "Modo Desconstruir"
L["Deconstruct Mode Desc"] = "Permite desencantar, moer, prospectar e desbloquear itens."
L["DND"] = "NP" L["DND"] = "NP"
L["DPS"] = "DPS" L["DPS"] = "DPS"
L["Dark"] = "Escuro" L["Dark"] = "Escuro"
+3
View File
@@ -69,6 +69,9 @@ L["Confused.. Try Again!"] = "Что за?.. Попробуйте еще раз!
L["Continue"] = "Продолжить" L["Continue"] = "Продолжить"
L["Coords"] = "Коорд." L["Coords"] = "Коорд."
L["Count"] = "Кол-во" L["Count"] = "Кол-во"
L["Current state: %s."] = "Нажмите для переключения.\nТекущее состояние: %s."
L["Deconstruct Mode"] = "Режим разборки"
L["Deconstruct Mode Desc"] = "Позволяет распылять, измельчать, обрабатывать и вскрывать предметы."
L["DND"] = "ДНД" L["DND"] = "ДНД"
L["DPS"] = "УВС" L["DPS"] = "УВС"
L["Dark"] = "Темная" L["Dark"] = "Темная"
+3
View File
@@ -69,6 +69,9 @@ L["Confused.. Try Again!"] = "请再试一次!"
L["Continue"] = "下一步" L["Continue"] = "下一步"
L["Coords"] = "坐标" L["Coords"] = "坐标"
L["Count"] = "计数" L["Count"] = "计数"
L["Current state: %s."] = "点击切换。\n当前状态: %s。"
L["Deconstruct Mode"] = "分解模式"
L["Deconstruct Mode Desc"] = "允许你分解、碾磨、勘探和解锁物品。"
L["DND"] = "忙碌" L["DND"] = "忙碌"
L["DPS"] = "伤害输出" L["DPS"] = "伤害输出"
L["Dark"] = "黑暗" L["Dark"] = "黑暗"
+3
View File
@@ -69,6 +69,9 @@ L["Confused.. Try Again!"] = "請再試一次!"
L["Continue"] = "下一步" L["Continue"] = "下一步"
L["Coords"] = "坐標" L["Coords"] = "坐標"
L["Count"] = "計數" L["Count"] = "計數"
L["Current state: %s."] = "點擊切換。\n當前狀態: %s。"
L["Deconstruct Mode"] = "分解模式"
L["Deconstruct Mode Desc"] = "允許你分解、碾磨、勘探和解鎖物品。"
L["DND"] = "忙碌" L["DND"] = "忙碌"
L["DPS"] = "傷害輸出" L["DPS"] = "傷害輸出"
L["Dark"] = "黑暗" L["Dark"] = "黑暗"
+615
View File
@@ -0,0 +1,615 @@
--[[
Deconstruct Module for ElvUI (WoW 3.3.5a / Ascension)
Adapted from ElvUI_SLE retail version
This module provides functionality to disenchant, mill, prospect, and unlock items
directly from bags by creating an overlay button when mousing over compatible items.
]] --
local E, L, V, P, G = unpack(select(2, ...))
local B = E:GetModule("Bags")
local D = B:NewModule("Deconstruct", "AceHook-3.0", "AceEvent-3.0")
-- Lua functions
local _G = _G
local format, strfind, type, tostring = format, strfind, type, tostring
local pairs, select, unpack = pairs, select, unpack
-- WoW API
local GetTradeTargetItemLink = GetTradeTargetItemLink
local InCombatLockdown = InCombatLockdown
local GetContainerItemLink = GetContainerItemLink
local GetSpellInfo = GetSpellInfo
local GetItemInfo = GetItemInfo
local GetItemCount = GetItemCount
local CreateFrame = CreateFrame
local GameTooltip = GameTooltip
-- Constants (with fallbacks in case they're not loaded yet)
local LOCKED = LOCKED or "Locked"
local VIDEO_OPTIONS_ENABLED = VIDEO_OPTIONS_ENABLED or "Enabled"
local VIDEO_OPTIONS_DISABLED = VIDEO_OPTIONS_DISABLED or "Disabled"
-- Module variables
D.DeconstructMode = false
D.ItemTable = {
['DoNotDE'] = {
['49715'] = true, -- Rose helm
['44731'] = true, -- Rose offhand
['21524'] = true, -- Red winter hat
['51525'] = true, -- Green winter hat
['70923'] = true, -- Sweater
['34486'] = true, -- Orgrimmar achievement fish
['11287'] = true, -- Lesser Magic Wand
['11288'] = true -- Greater Magic Wand
},
['Cooking'] = {
['46349'] = true -- Chef's Hat
},
['Fishing'] = {
['19022'] = true, -- Nat Pagle's Extreme Angler FC-5000
['19970'] = true, -- Arcanite Fishing Pole
['25978'] = true, -- Seth's Graphite Fishing Pole
['44050'] = true, -- Mastercraft Kalu'ak Fishing Pole
['45858'] = true, -- Nat's Lucky Fishing Pole
['45991'] = true, -- Bone Fishing Pole
['45992'] = true -- Jeweled Fishing Pole
}
}
D.Keys = {}
D.BlacklistDE = {}
D.BlacklistLOCK = {}
-- Profession spell names
D.DEname = GetSpellInfo(13262) -- Disenchant
D.MILLname = GetSpellInfo(51005) -- Milling
D.PROSPECTname = GetSpellInfo(31252) -- Prospecting
D.LOCKname = GetSpellInfo(1804) -- Pick Lock
-- Check if player has any relevant professions
function D:HasRelevantProfession()
if D.HasEnchanting then return true end
if D.HasInscription then return true end
if D.HasJewelcrafting then return true end
if D.HasPickLock then return true end
return false
end
-- Update button state (enabled/disabled)
function D:UpdateButtonState()
if not D.DeconstructButton then return end
local hasProf = D:HasRelevantProfession()
if hasProf then
D.DeconstructButton:Enable()
D.DeconstructButton:SetAlpha(1)
else
D.DeconstructButton:Disable()
D.DeconstructButton:SetAlpha(0.5)
end
end
-- Check which professions the player has
function D:UpdateProfessions()
D.HasEnchanting = false
D.HasInscription = false
D.HasJewelcrafting = false
D.HasPickLock = false
if D.DEname and GetSpellInfo(D.DEname) then D.HasEnchanting = true end
if D.MILLname and GetSpellInfo(D.MILLname) then D.HasInscription = true end
if D.PROSPECTname and GetSpellInfo(D.PROSPECTname) then D.HasJewelcrafting = true end
if D.LOCKname and GetSpellInfo(D.LOCKname) then D.HasPickLock = true end
end
-- Helper function to check if player has a skeleton key
local function HaveKey() for key in pairs(D.Keys) do if GetItemCount(key) > 0 then return key end end end
-- Build blacklist from settings
function D:Blacklisting(skill) D['BuildBlacklist' .. skill](self) end
function D:BuildBlacklistDE(...)
wipe(D.BlacklistDE)
for index = 1, select('#', ...) do
local name = select(index, ...)
if name and name ~= "" then
local itemName = GetItemInfo(name)
if itemName then D.BlacklistDE[itemName] = true end
end
end
end
function D:BuildBlacklistLOCK(...)
wipe(D.BlacklistLOCK)
for index = 1, select('#', ...) do
local name = select(index, ...)
if name and name ~= "" then
local itemName = GetItemInfo(name)
if itemName then D.BlacklistLOCK[itemName] = true end
end
end
end
-- Check if item can be disenchanted
function D:IsBreakable(itemId, itemName, itemQuality, equipSlot)
if not itemId then return false end
if type(itemId) == "number" then itemId = tostring(itemId) end
-- Check blacklists
if D.ItemTable['DoNotDE'][itemId] then return false end
if D.ItemTable['Cooking'][itemId] then return false end
if D.ItemTable['Fishing'][itemId] then return false end
if D.BlacklistDE[itemName] then return false end
return true
end
-- Check if item is disenchantable
function D:IsDisenchantable(itemId)
if not itemId then return false end
local itemName, itemLink, itemRarity, itemLevel, itemMinLevel, itemType, itemSubType, itemStackCount, itemEquipLoc = GetItemInfo(itemId)
if not itemName then return false end
-- Quality: 2=Uncommon, 3=Rare, 4=Epic
if not itemRarity or itemRarity < 2 or itemRarity > 4 then return false end
if itemType ~= "Armor" and itemType ~= "Weapon" then return false end
if not itemEquipLoc or itemEquipLoc == "" then return false end
if not D.HasEnchanting then return false end
return true
end
-- Check if item can be prospected
function D:IsProspectable(itemId)
if not itemId or not D.HasJewelcrafting then return false end
-- Prospectable ores in WotLK (3.3.5a)
local prospectableOres = {
[2770] = true, -- Copper Ore
[2771] = true, -- Tin Ore
[2772] = true, -- Iron Ore
[3858] = true, -- Mithril Ore
[10620] = true, -- Thorium Ore
[23424] = true, -- Fel Iron Ore
[23425] = true, -- Adamantite Ore
[36909] = true, -- Cobalt Ore
[36912] = true, -- Saronite Ore
[36910] = true -- Titanium Ore
}
return prospectableOres[tonumber(itemId)] or false
end
-- Check if item can be milled
function D:IsMillable(itemId)
if not itemId or not D.HasInscription then return false end
-- Millable herbs in WotLK (3.3.5a)
local millableHerbs = {
[765] = true, -- Silverleaf
[2447] = true, -- Peacebloom
[2449] = true, -- Earthroot
[785] = true, -- Mageroyal
[2450] = true, -- Briarthorn
[2452] = true, -- Swiftthistle
[2453] = true, -- Bruiseweed
[3820] = true, -- Stranglekelp
[3369] = true, -- Grave Moss
[3356] = true, -- Kingsblood
[3357] = true, -- Liferoot
[3818] = true, -- Fadeleaf
[3821] = true, -- Goldthorn
[3358] = true, -- Khadgar's Whisker
[3819] = true, -- Dragon's Teeth (Wintersbite)
[8836] = true, -- Arthas' Tears
[8838] = true, -- Sungrass
[8839] = true, -- Blindweed
[8845] = true, -- Ghost Mushroom
[8846] = true, -- Gromsblood
[13464] = true, -- Golden Sansam
[13463] = true, -- Dreamfoil
[13465] = true, -- Mountain Silversage
[13466] = true, -- Plaguebloom
[13467] = true, -- Icecap
[22785] = true, -- Felweed
[22786] = true, -- Dreaming Glory
[22787] = true, -- Ragveil
[22789] = true, -- Terocone
[22790] = true, -- Ancient Lichen
[22791] = true, -- Netherbloom
[22792] = true, -- Nightmare Vine
[22793] = true, -- Mana Thistle
[36901] = true, -- Goldclover
[36903] = true, -- Adder's Tongue
[36904] = true, -- Tiger Lily
[36905] = true, -- Lichbloom
[36906] = true, -- Icethorn
[36907] = true, -- Talandra's Rose
[37921] = true, -- Deadnettle
[39970] = true -- Fire Leaf
}
return millableHerbs[tonumber(itemId)] or false
end
-- Check if item is currently locked (scan tooltip)
function D:IsUnlockable(itemLink)
if not itemLink then return false end
-- Scan tooltip for "Locked" text
GameTooltip:SetOwner(UIParent, "ANCHOR_NONE")
GameTooltip:SetHyperlink(itemLink)
for i = 2, GameTooltip:NumLines() do
local line = _G["GameTooltipTextLeft" .. i]
if line then
local text = line:GetText()
if text and strfind(text, LOCKED) then
GameTooltip:Hide()
return true
end
end
end
GameTooltip:Hide()
return false
end
-- Apply the deconstruct overlay to a bag slot
function D:ApplyDeconstruct(itemLink, itemId, spell, spellType, r, g, b, slot)
if not slot then return end
if slot == D.DeconstructionReal then return end
local bag = slot:GetParent():GetID()
-- Verify the bag and slot exist in ElvUI's bag or bank structure
local validBag = (B.BagFrame and B.BagFrame.Bags and B.BagFrame.Bags[bag]) or (B.BankFrame and B.BankFrame.Bags and B.BankFrame.Bags[bag])
if not validBag then return end
D.DeconstructionReal.Bag = bag
D.DeconstructionReal.Slot = slot:GetID()
-- Check if in trade window
if GetTradeTargetItemLink and GetTradeTargetItemLink(7) == itemLink then
return
elseif GetContainerItemLink(bag, slot:GetID()) == itemLink then
D.DeconstructionReal.ID = itemId
D.DeconstructionReal:SetAttribute('type1', spellType)
D.DeconstructionReal:SetAttribute(spellType, spell)
D.DeconstructionReal:SetAttribute('target-bag', D.DeconstructionReal.Bag)
D.DeconstructionReal:SetAttribute('target-slot', D.DeconstructionReal.Slot)
D.DeconstructionReal:SetAllPoints(slot)
D.DeconstructionReal:Show()
-- Apply visual effect (ActionButton_ShowOverlayGlow confirmed on Ascension)
ActionButton_ShowOverlayGlow(D.DeconstructionReal)
end
end
-- Get deconstruct mode status text
function D:GetDeconMode()
local text
if D.DeconstructMode then
text = '|cff00FF00 ' .. VIDEO_OPTIONS_ENABLED .. '|r'
else
text = '|cffFF0000 ' .. VIDEO_OPTIONS_DISABLED .. '|r'
end
return text
end
-- Toggle deconstruct mode (called from button click)
function D:ToggleMode()
-- Don't toggle if player doesn't have required professions
if not D:HasRelevantProfession() then return end
D.DeconstructMode = not D.DeconstructMode
if D.DeconstructButton then
local normalTex = D.DeconstructButton:GetNormalTexture()
if normalTex then
if D.DeconstructMode then
normalTex:SetTexture([[Interface\ICONS\INV_Enchant_EssenceCosmicGreater]])
ActionButton_ShowOverlayGlow(D.DeconstructButton)
else
normalTex:SetTexture([[Interface\ICONS\INV_Rod_Enchantedcobalt]])
ActionButton_HideOverlayGlow(D.DeconstructButton)
end
end
D.DeconstructButton.ttText2 = format(L["Deconstruct Mode Desc"] .. "\n" .. L["Current state: %s."], D:GetDeconMode())
if GameTooltip:IsOwned(D.DeconstructButton) then B.Tooltip_Show(D.DeconstructButton) end
end
-- Update both bag and bank slots
if B.BagFrame then D:UpdateBagSlots(B.BagFrame, D.DeconstructMode) end
if B.BankFrame then D:UpdateBagSlots(B.BankFrame, D.DeconstructMode) end
end
-- Create the actual deconstruct button overlay
function D:ConstructRealDecButton()
D.DeconstructionReal = CreateFrame('Button', 'ElvUI_DeconReal', E.UIParent, 'SecureActionButtonTemplate')
D.DeconstructionReal:SetScript('OnEvent', function(obj, event, ...) obj[event](obj, ...) end)
D.DeconstructionReal:RegisterForClicks('AnyUp', 'AnyDown')
D.DeconstructionReal:SetFrameStrata('TOOLTIP')
D.DeconstructionReal.OnLeave = function(frame)
if InCombatLockdown() then
frame:SetAlpha(0)
frame:RegisterEvent('PLAYER_REGEN_ENABLED')
else
frame:ClearAllPoints()
frame:SetAlpha(1)
if GameTooltip then GameTooltip:Hide() end
-- Stop visual effects
ActionButton_HideOverlayGlow(frame)
frame:Hide()
end
end
D.DeconstructionReal.SetTip = function(f)
GameTooltip:SetOwner(f, 'ANCHOR_LEFT', 0, 4)
GameTooltip:ClearLines()
GameTooltip:SetBagItem(f.Bag, f.Slot)
end
D.DeconstructionReal:SetScript('OnEnter', D.DeconstructionReal.SetTip)
D.DeconstructionReal:SetScript('OnLeave', function() D.DeconstructionReal:OnLeave() end)
D.DeconstructionReal:Hide()
function D.DeconstructionReal:PLAYER_REGEN_ENABLED()
self:UnregisterEvent('PLAYER_REGEN_ENABLED')
D.DeconstructionReal:OnLeave()
end
end
-- Parse tooltip to determine if item should show deconstruct button
function D:DeconstructParser()
if not D.DeconstructMode then return end
if not GameTooltip:IsVisible() then return end
local owner = GameTooltip:GetOwner()
if not owner then return end
local ownerName = owner.GetName and owner:GetName()
if not ownerName then return end
-- Only process ElvUI bag and bank slots
if not (strfind(ownerName, 'ElvUI_ContainerFrameBag') or strfind(ownerName, 'ElvUI_BankContainerFrameBag')) then return end
-- Get the bag and slot from the owner
local bag, slot
if owner.GetParent then
local parent = owner:GetParent()
if parent.GetID then bag = parent:GetID() end
end
if owner.GetID then slot = owner:GetID() end
if not bag or not slot then return end
local itemLink = GetContainerItemLink(bag, slot)
if not itemLink then return end
local itemId = tonumber(itemLink:match("item:(%d+)"))
if not itemId then return end
if InCombatLockdown() then return end
-- Check what can be done with this item
local r, g, b
-- Check for lockboxes
local hasKey = HaveKey()
if (D.HasPickLock or hasKey) and D:IsUnlockable(itemLink) then
r, g, b = 0, 1, 1
if D.HasPickLock then
D:ApplyDeconstruct(itemLink, itemId, D.LOCKname, 'spell', r, g, b, owner)
elseif hasKey then
D:ApplyDeconstruct(itemLink, itemId, hasKey, 'item', r, g, b, owner)
end
return
end
-- Check for prospectable ores (Jewelcrafting only)
if D.HasJewelcrafting and D:IsProspectable(itemId) then
r, g, b = 1, 0.5, 0
D:ApplyDeconstruct(itemLink, itemId, D.PROSPECTname, 'spell', r, g, b, owner)
return
end
-- Check for millable herbs (Inscription only)
if D.HasInscription and D:IsMillable(itemId) then
r, g, b = 0, 1, 0
D:ApplyDeconstruct(itemLink, itemId, D.MILLname, 'spell', r, g, b, owner)
return
end
-- Check for disenchantable items (Enchanting only)
if D.HasEnchanting and D:IsDisenchantable(itemId) then
local itemName, _, itemQuality, _, _, _, _, _, equipSlot = GetItemInfo(itemId)
if D:IsBreakable(itemId, itemName, itemQuality, equipSlot) then
r, g, b = 0.5, 0, 1
D:ApplyDeconstruct(itemLink, itemId, D.DEname, 'spell', r, g, b, owner)
return
end
end
end
-- Check if an item can be processed (disenchant/mill/prospect/unlock)
function D:CanProcessItem(itemLink, hasKey)
if not itemLink then return false end
local itemId = tonumber(itemLink:match("item:(%d+)"))
if not itemId then return false end
-- Check lockboxes (Rogues only)
if (D.HasPickLock or hasKey) and D:IsUnlockable(itemLink) then return true end
-- Check prospectable (Jewelcrafting only)
if D.HasJewelcrafting and D:IsProspectable(itemId) then return true end
-- Check millable (Inscription only)
if D.HasInscription and D:IsMillable(itemId) then return true end
-- Check disenchantable (Enchanting only)
if D.HasEnchanting and D:IsDisenchantable(itemId) then
local itemName, _, itemQuality, _, _, _, _, _, equipSlot = GetItemInfo(itemId)
if D:IsBreakable(itemId, itemName, itemQuality, equipSlot) then return true end
end
return false
end
-- Update all bag/bank slots to dim non-processable items
function D:UpdateBagSlots(frame, isActive)
if not frame or not frame.Bags then return end
local hasKey = HaveKey()
for _, bagID in ipairs(frame.BagIDs) do
if frame.Bags[bagID] then
for slotID = 1, GetContainerNumSlots(bagID) do
local slot = frame.Bags[bagID][slotID]
if slot then
if isActive then
-- Dim items that can't be processed
local itemLink = GetContainerItemLink(bagID, slotID)
if itemLink and D:CanProcessItem(itemLink, hasKey) then
slot:SetAlpha(1)
else
slot:SetAlpha(0.3)
end
else
-- Restore normal alpha
slot:SetAlpha(1)
end
end
end
end
end
end
-- Helper function to create and setup the deconstruct button
local function CreateDeconstructButton(bagFrame)
if not bagFrame or not bagFrame.holderFrame then return end
if bagFrame.deconstructButton then return end -- Already created
-- Create the button
local button = CreateFrame("Button", nil, bagFrame.holderFrame)
button:Size(16 + E.Border)
button:SetTemplate()
button:Point("RIGHT", bagFrame.vendorGraysButton, "LEFT", -5, 0)
button:SetNormalTexture("Interface\\ICONS\\INV_Rod_Enchantedcobalt")
button:GetNormalTexture():SetTexCoord(unpack(E.TexCoords))
button:GetNormalTexture():SetInside()
button:SetPushedTexture("Interface\\ICONS\\INV_Rod_Enchantedcobalt")
button:GetPushedTexture():SetTexCoord(unpack(E.TexCoords))
button:GetPushedTexture():SetInside()
button:StyleButton(nil, true)
button.ttText = L["Deconstruct Mode"]
button.ttText2 = format(L["Deconstruct Mode Desc"] .. "\n" .. L["Current state: %s."], D:GetDeconMode())
button:SetScript("OnEnter", B.Tooltip_Show)
button:SetScript("OnLeave", GameTooltip_Hide)
button:SetScript("OnClick", function() D:ToggleMode() end)
bagFrame.deconstructButton = button
D.DeconstructButton = button
-- Re-anchor the search box to the deconstruct button
if bagFrame.editBox then
bagFrame.editBox:ClearAllPoints()
bagFrame.editBox:Point("BOTTOMLEFT", bagFrame.holderFrame, "TOPLEFT", (E.Border * 2) + 18, E.Border * 2 + 2)
bagFrame.editBox:Point("RIGHT", bagFrame.deconstructButton, "LEFT", -5, 0)
end
end
-- Helper function to setup button and hooks (called once when bags are first opened)
local function SetupDeconstructButton()
if D.DeconstructButton then return end
-- Update professions first
D:UpdateProfessions()
if not B.BagFrame then return end
-- Create the button (always show if module is enabled)
CreateDeconstructButton(B.BagFrame)
-- Update button state (enabled/disabled)
D:UpdateButtonState()
-- Only create the real deconstruct button and hooks once
if not D.DeconstructionReal then
D:ConstructRealDecButton()
-- Hook GameTooltip to detect when mousing over items
GameTooltip:HookScript('OnShow', function() D:DeconstructParser() end)
GameTooltip:HookScript('OnUpdate', function() D:DeconstructParser() end)
end
-- Hide deconstruct mode when bags close
B.BagFrame:HookScript('OnHide', function()
D.DeconstructMode = false
if D.DeconstructButton then
local normalTex = D.DeconstructButton:GetNormalTexture()
if normalTex then normalTex:SetTexture([[Interface\ICONS\INV_Rod_Enchantedcobalt]]) end
ActionButton_HideOverlayGlow(D.DeconstructButton)
end
if B.BagFrame then D:UpdateBagSlots(B.BagFrame, false) end
if B.BankFrame then D:UpdateBagSlots(B.BankFrame, false) end
if D.DeconstructionReal then D.DeconstructionReal:OnLeave() end
end)
end
-- Initialize the module
function D:Initialize()
if not E.private.bags.enable then return end
if not E.db.bags.deconstruct then return end -- Check if deconstruct is enabled
-- Hook into Layout to setup button for bags and reapply dimming
hooksecurefunc(B, "Layout", function(_, isBank)
if not isBank then if B.BagFrame and not D.DeconstructButton then E:Delay(0.1, function() SetupDeconstructButton() end) end end
-- Reapply dimming after layout (layout resets slot alpha)
if D.DeconstructMode then
E:Delay(0.05, function()
if B.BagFrame then D:UpdateBagSlots(B.BagFrame, true) end
if B.BankFrame then D:UpdateBagSlots(B.BankFrame, true) end
end)
end
end)
-- Build blacklists
D:Blacklisting('DE')
D:Blacklisting('LOCK')
-- Register events
D:RegisterEvent('BAG_UPDATE')
D:RegisterEvent('SKILL_LINES_CHANGED')
-- If bag frame already exists, setup button now
if B.BagFrame and not D.DeconstructButton then E:Delay(0.1, function() SetupDeconstructButton() end) end
end
-- Handle SKILL_LINES_CHANGED event
function D:SKILL_LINES_CHANGED()
D:UpdateProfessions()
-- Update button state (enabled/disabled) based on professions
D:UpdateButtonState()
end
-- Handle BAG_UPDATE event
function D:BAG_UPDATE()
if D.DeconstructMode then
if B.BagFrame then D:UpdateBagSlots(B.BagFrame, true) end
if B.BankFrame then D:UpdateBagSlots(B.BankFrame, true) end
end
end
-- Wait for ElvUI to fully load before initializing
hooksecurefunc(B, "Initialize", function() D:Initialize() end)
+1
View File
@@ -2,4 +2,5 @@
<Script file="Bags.lua"/> <Script file="Bags.lua"/>
<Script file="BagBar.lua"/> <Script file="BagBar.lua"/>
<Script file="Sort.lua"/> <Script file="Sort.lua"/>
<Script file="Deconstruct.lua"/>
</Ui> </Ui>
+1
View File
@@ -165,6 +165,7 @@ P.bags = {
moneyCoins = true, moneyCoins = true,
junkIcon = false, junkIcon = false,
junkDesaturate = true, junkDesaturate = true,
deconstruct = true,
unlearnedVanityIcon = false, unlearnedVanityIcon = false,
unlearnedWardrobeIcon = false, unlearnedWardrobeIcon = false,
ignoredItems = {}, ignoredItems = {},
+11 -4
View File
@@ -149,22 +149,29 @@ E.Options.args.bags = {
name = L["Disable Bank Sort"], name = L["Disable Bank Sort"],
set = function(info, value) E.db.bags[info[#info]] = value B:ToggleSortButtonState(true) end set = function(info, value) E.db.bags[info[#info]] = value B:ToggleSortButtonState(true) end
}, },
unlearnedVanityIcon = { deconstruct = {
order = 16, order = 16,
type = "toggle", type = "toggle",
name = L["Deconstruct Mode"],
desc = L["Deconstruct Mode Desc"],
set = function(info, value) E.db.bags[info[#info]] = value E:StaticPopup_Show("PRIVATE_RL") end
},
unlearnedVanityIcon = {
order = 17,
type = "toggle",
name = L["Unlearned Vanity"], name = L["Unlearned Vanity"],
desc = L["Unlearned Vanity Desc"], desc = L["Unlearned Vanity Desc"],
set = function(info, value) E.db.bags[info[#info]] = value B:UpdateAllBagSlots() end set = function(info, value) E.db.bags[info[#info]] = value B:UpdateAllBagSlots() end
}, },
unlearnedWardrobeIcon = { unlearnedWardrobeIcon = {
order = 17, order = 18,
type = "toggle", type = "toggle",
name = L["Unlearned Wardrobe"], name = L["Unlearned Wardrobe"],
desc = L["Unlearned Wardrobe Desc"], desc = L["Unlearned Wardrobe Desc"],
set = function(info, value) E.db.bags[info[#info]] = value B:UpdateAllBagSlots() end set = function(info, value) E.db.bags[info[#info]] = value B:UpdateAllBagSlots() end
}, },
countGroup = { countGroup = {
order = 18, order = 19,
type = "group", type = "group",
name = L["Item Count Font"], name = L["Item Count Font"],
guiInline = true, guiInline = true,
@@ -209,7 +216,7 @@ E.Options.args.bags = {
} }
}, },
itemLevelGroup = { itemLevelGroup = {
order = 19, order = 20,
type = "group", type = "group",
name = L["Item Level"], name = L["Item Level"],
guiInline = true, guiInline = true,