Compare with Previous | Blame | View Log
--[[ Usage: /restack [bags, bank, guild] - manual run /restack auto [bags, bank, guild] - toggles auto mode ]] SlashCmdList["RESTACK"] = function(s) kRestack(s) end SLASH_RESTACK1 = "/restack" --[[ pretty chat colors! ]] local col = { w = "|cffFFFFFF", g = "|cff55FF55", r = "|cffFF5555" } local kR = "|cff44CCFFk|cffFFFFAARestack"..col.w --[[ ldb plugin ]] local menu = { { text = "= Restack =", isTitle = true }, { text = "Backpack", func = function() kRestack("bags") end }, { text = "Bank", disabled = true, func = function() kRestack("bank") end }, { text = "Guild Vault", disabled = true, func = function() kRestack("guild") end }, { disabled = true }, { text = "= Set Auto =", isTitle = true }, { text = "Backpack", checked = function() return (AutoRestack.bags and true or false) end, func = function() kRestack("auto bags") end }, { text = "Bank", checked = function() return (AutoRestack.bank and true or false) end, func = function() kRestack("auto bank") end }, { text = "Guild Vault", checked = function() return (AutoRestack.guild and true or false) end, func = function() kRestack("auto guild") end }, } local drop = CreateFrame("frame", "kRestack", nil, "UIDropDownMenuTemplate") LibStub:GetLibrary("LibDataBroker-1.1"):NewDataObject("kRestack", { type = "data source", label = "kRestack", icon = "Interface\\Icons\\INV_Crate_09", OnClick = function(self, button) if button == "RightButton" then GameTooltip:Hide() UIDropDownMenu_Initialize(drop, function() for _, opt in pairs(menu) do UIDropDownMenu_AddButton(opt, 1) end end, "MENU") return ToggleDropDownMenu(1, nil, drop, self, 0, 0) elseif button == "LeftButton" then kRestack("bags") end end, }) --[[ set user's container identifers ]] local container = { bags = { 0 }, bank = { -1 }, guild = { 42 } } for i = 1, NUM_BAG_SLOTS do table.insert(container.bags, i) end for i = NUM_BAG_SLOTS + 1, NUM_BAG_SLOTS + NUM_BANKBAGSLOTS do table.insert(container.bank, i) end --[[ watching some events ]] local atBank, atVault local f = CreateFrame("frame") local events = { "ADDON_LOADED", "BANKFRAME_OPENED", "BANKFRAME_CLOSED", "LOOT_OPENED", "GUILDBANKFRAME_OPENED", "GUILDBANKFRAME_CLOSED" } for _, r in pairs(events) do f:RegisterEvent(r) end f:SetScript("OnEvent", function(_, e) --[[ ldb stuff ]] if e == events[2] then menu[3].disabled = false elseif e == events[3] then menu[3].disabled = true elseif e == events[5] then local _, _, isViewable, canDeposit = GetGuildBankTabInfo(GetCurrentGuildBankTab()) if IsGuildLeader() or (isViewable and canDeposit) then menu[4].disabled = false end elseif e == events[6] then menu[4].disabled = true end if e == events[1] then --[[ initialize saved variables ]] if type(AutoRestack) ~= "table" then AutoRestack = { } end if AutoRestack.bags == nil then AutoRestack.bags = true end if AutoRestack.bank == nil then AutoRestack.bank = true end if AutoRestack.guild == nil then AutoRestack.guild = false end elseif AutoRestack.bank and e == events[2] then kRestack("bank", true) elseif AutoRestack.bags and e == events[4] then kRestack("bags", true) elseif AutoRestack.guild and e == events[5] then kRestack("guild", true) end end) --[[ hooking auto-stacking to ToggleBackpack and guild vault tab switching ]] local oToggleBackpack = ToggleBackpack ToggleBackpack = function() if AutoRestack.bags then kRestack("bags", true) end return oToggleBackpack() end local oSetCurrentGuildBankTab = SetCurrentGuildBankTab SetCurrentGuildBankTab = function(tab) if type(restacker) ~= "thread" or coroutine.status(restacker) == "dead" then if AutoRestack.guild then kRestack("guild", true, tab) end return oSetCurrentGuildBankTab(tab) end end local function coYield(loc, lb, ls, count) --[[ yielding function; can't be stacking too fast or else bad stuff happens ]] f:SetScript("OnUpdate", function() if coroutine.status(restacker) == "suspended" then local locked = true if loc == "guild" then locked = select(2, GetGuildBankItemInfo(lb, ls)) == count and true or false else locked = select(3, GetContainerItemInfo(lb, ls)) end if not locked then coroutine.resume(restacker) end end end) coroutine.yield() end local function getPartial(cb, cs, id, loc) local vault = loc == "guild" for _, bag in pairs(container[loc]) do local slots = vault and MAX_GUILDBANK_SLOTS_PER_TAB or GetContainerNumSlots(bag) for slot = slots, 1, -1 do bag = vault and cb or bag if not (bag == cb and slot == cs) then local item = vault and GetGuildBankItemLink(bag, slot) or GetContainerItemLink(bag, slot) if item then local itemid = select(3, strfind(item, "item:(%d+)")) if itemid == id then local stack = select(8, GetItemInfo(itemid)) local count = vault and select(2, GetGuildBankItemInfo(bag, slot)) or select(2, GetContainerItemInfo(bag, slot)) if stack > count then return true, bag, slot end end end end end end return false end --[[ main function ]] function kRestack(loc, nowarn, tab) if loc ~= "bags" and loc ~= "bank" and loc ~= "guild" then --[[ more slash commands ]] if loc == "resume" then if coroutine.status(restacker) == "suspended" then print(kR..col.w, "Resuming suspended thread.") coroutine.resume(restacker) else print(kR..col.w, "No suspended threads to resume.") end else loc = select(3, strfind(loc, "auto (%a+)")) if loc == "bags" or loc == "bank" or loc == "guild" then local togl if not AutoRestack[loc] then AutoRestack[loc] = true togl = col.g.."ON" else AutoRestack[loc] = false togl = col.r.."OFF" end loc = loc == "bags" and "your backpack" or loc loc = loc == "bank" and "your bank" or loc loc = loc == "guild" and "the guild vault" or loc print(kR, "Auto-stacking for", loc, "toggled", togl) else local bags = AutoRestack.bags and col.g or col.r local bank = AutoRestack.bank and col.g or col.r local guild = AutoRestack.guild and col.g or col.r print(kR, "Usage:") print(col.w.."- /restack [bags, bank, guild] - Run restacker manually") print(col.w.."- /restack auto ["..bags.."bags"..col.w..",", bank.."bank"..col.w..",", guild.."guild"..col.w.."] - Toggle auto-stacking") end end do return end end if type(restacker) ~= "thread" or coroutine.status(restacker) == "dead" then restacker = coroutine.create(function() --[[ core restacking function ]] local changed = true while changed do changed = false vault = loc == "guild" if vault then vbag = tab or GetCurrentGuildBankTab() local _, _, isViewable, canDeposit = GetGuildBankTabInfo(vbag) if not (IsGuildLeader() or (isViewable and canDeposit)) then break end end for _, bag in pairs(container[loc]) do bag = vault and vbag or bag for slot = 1, (vault and MAX_GUILDBANK_SLOTS_PER_TAB or GetContainerNumSlots(bag)) do while true and not vault do local locked = select(3, GetContainerItemInfo(bag, slot)) if locked then coYield(loc, bag, slot) else break end end local item = vault and GetGuildBankItemLink(bag, slot) or GetContainerItemLink(bag, slot) if item then local itemid = select(3, strfind(item, "item:(%d+)")) local stack = select(8, GetItemInfo(itemid)) local count = vault and select(2, GetGuildBankItemInfo(bag, slot)) or select(2, GetContainerItemInfo(bag, slot)) local moved = false --[[ do "special" things with "special" items by moving them to "special" bags ]] if not vault then for _, sbag in pairs(container[loc]) do if sbag > 0 and GetContainerNumSlots(sbag) > 0 then local bagID = ContainerIDToInventoryID(sbag) local bagType = GetItemFamily(GetInventoryItemLink("player", bagID)) local itemType = GetItemFamily(item) if bagType > 0 and bagType == itemType and bag ~= sbag then PickupContainerItem(bag, slot) PutItemInBag(bagID) moved = true end end end end if count < stack and not moved then --[[ found a partial stack ]] local locked, found, pbag, pslot while true do --[[ look for another partial stack ]] found, pbag, pslot = getPartial(bag, slot, itemid, loc) if vault then break end locked = found and select(3, GetContainerItemInfo(pbag, pslot)) or false if locked then coYield(loc, pbag, pslot) else break end end if found then --[[ stack 'em up ]] ClearCursor() if vault then PickupGuildBankItem(pbag, pslot) PickupGuildBankItem(bag, slot) ClearCursor() coYield(loc, bag, slot, count) else PickupContainerItem(pbag, pslot) PickupContainerItem(bag, slot) end changed = true end end end end end end --[[ turn off yielding function ]] f:SetScript("OnUpdate", nil) end) coroutine.resume(restacker) else if not nowarn then --[[ user is impatient or there is a stall, tell them so ]] print(kR..col.r, "Restacking is already in progress. (use '/restack resume' if stuck)") end end end