WoWInterface SVN kRestack

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /trunk
    from Rev 13 to Rev 14
    Reverse comparison

Rev 13 → Rev 14

kRestack/kRestack.lua
1,67 → 1,93
--[[ kRestack() is a global function and can be used in any addon or macro
Some of the functionality is based on ArkInventory's restacking function, kudos!
 
Usage: /restack [bags, bank, auto]
Devs: kRestack("bags") and kRestack("bank") can be used in your addons. ]]
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"
 
local container = { bags = { 0 }, bank = { -1 } }
--[[ pretty chat colors! ]]
local col = { w = "|cffFFFFFF", g = "|cff55FF55", r = "|cffFF5555" }
local kR = "|cff44CCFFk|cffFFFFAARestack"..col.w
 
--[[ 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
 
--[[ initiate defaults ]]
if type(AutoRestack) ~= "table" then
AutoRestack = { }
elseif AutoRestack.bags == nil then
table.insert(AutoRestack.bags, true)
elseif AutoRestack.bank == nil then
table.insert(AutoRestack.bank, true)
elseif AutoRestack.guild == nil then
table.insert(AutoRestack.guild, false)
end
 
--[[ watching some events ]]
local frame = CreateFrame("FRAME")
frame:RegisterEvent("BANKFRAME_OPENED")
frame:SetScript("OnEvent", function(_, event)
if event == "BANKFRAME_OPENED" and AutoRestack then
local events = { "BANKFRAME_OPENED", "LOOT_OPENED", "TRADE_SHOW", "GUILDBANKFRAME_OPENED" }
for _, r in pairs(events) do frame:RegisterEvent(r) end
frame:SetScript("OnEvent", function(_, e)
if AutoRestack.bank and e == events[1] then
kRestack("bank", true)
elseif AutoRestack.bags and (e == events[2] or e == events[3]) then
kRestack("bags", true)
elseif AutoRestack.guild and e == events[4] then
kRestack("guild", true)
end
end)
 
--[[ hooking auto-stacking to togglebackpack and guild bank tab switching ]]
local oToggleBackpack = ToggleBackpack
ToggleBackpack = function()
if AutoRestack and not InCombatLockdown() and (type(restacker) ~= "thread" or coroutine.status(restacker) == "dead") then
kRestack("bags", true)
end
if AutoRestack.bags then kRestack("bags", true) end
return oToggleBackpack()
end
 
local function DecodeItemId(itemlink)
return select(3, strfind(itemlink, "item:(%d+)"))
local oSetCurrentGuildBankTab = SetCurrentGuildBankTab
SetCurrentGuildBankTab = function(tab)
if AutoRestack.guild and (type(restacker) ~= "thread" or coroutine.status(restacker) == "dead") then
kRestack("guild", true, tab)
return oSetCurrentGuildBankTab(tab)
end
end
 
local function RestackFindPartial(cb, cs, id, loc)
for _, bag in pairs(container[loc]) do
for slot = GetContainerNumSlots(bag), 1, -1 do
if not (bag == cb and slot == cs) then
local item = GetContainerItemLink(bag, slot)
if item then
local itemId = DecodeItemId(item)
if itemId == id then
local _, count, locked = GetContainerItemInfo(bag, slot)
local stack = select(8, GetItemInfo(itemId))
if stack > count then return true, bag, slot end
end
end
local function coYield(loc, lb, ls, count)
--[[ yielding function; can't be stacking too fast or else bad stuff happens ]]
frame: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
return false
end)
coroutine.yield()
end
 
local function RestackFindSpecial(ct, loc)
local function getPartial(cb, cs, id, loc)
local vault = loc == "guild"
for _, bag in pairs(container[loc]) do
local _, bt = GetContainerNumFreeSlots(bag)
if bt == 0 then
for slot = 1, GetContainerNumSlots(bag) do
local item = GetContainerItemLink(bag, slot)
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 itemEquipLoc = select(8, GetItemInfo(h))
if itemEquipLoc ~= "INVTYPE_BAG" then
local it = GetItemFamily(h)
if bit.band(it, ct) > 0 then return true, bag, slot end
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
70,133 → 96,125
return false
end
 
local function RestackBags(loc)
local changed = false
for _, bag in pairs(container[loc]) do
for slot = 1, GetContainerNumSlots(bag) do
while true do
local locked = select(3, GetContainerItemInfo(bag, slot))
if locked then
coroutine.yield()
--[[ 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
break
AutoRestack[loc] = false
togl = col.r.."OFF"
end
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
 
local item = GetContainerItemLink(bag, slot)
 
if item then
local itemId = DecodeItemId(item)
local stack = select(8, GetItemInfo(itemId))
local count = select(2, GetContainerItemInfo(bag, slot))
 
if stack > count then
local locked, ok, pb, ps, pc
 
while true do
ok, pbag, pslot = RestackFindPartial(bag, slot, itemId, loc)
locked = ok and select(3, GetContainerItemInfo(pbag, pslot)) or false
 
if locked then
coroutine.yield()
else
break
end
end
 
if ok then
ClearCursor()
PickupContainerItem(pbag, pslot)
PickupContainerItem(bag, slot)
ClearCursor()
changed = true
end
end
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
end
return changed
end
 
function kRestack(loc, nowarn)
if loc ~= "bags" and loc ~= "bank" then
local col = { w = "|cffFFFFFF", g = "|cff55FF55", r = "|cffFF5555" }
local krstr = "|cff44CCFFk|cffFFFFAARestack"..col.w
if loc == "auto" then
local togl
if not AutoRestack then
AutoRestack = true
togl = col.g.."ON"
else
AutoRestack = false
togl = col.r.."OFF"
end
print(krstr, "Auto-stacking toggled", togl)
else
local status = AutoRestack and col.g.."on" or col.r.."off"
print(krstr, "Usage:")
print("- /restack [bags, bank]")
print("- /restack auto - toggles auto-stacking ("..status..col.w..")")
end
 
do return end
end
 
 
if type(restacker) ~= "thread" or coroutine.status(restacker) == "dead" then
frame:SetScript("OnUpdate", function()
if type(restacker) == "thread" then coroutine.resume(restacker) end
end)
restacker = coroutine.create(function()
--[[ core restacking function ]]
local changed = true
while changed == true do
changed = RestackBags(loc)
end
 
for _, bag in pairs(container[loc]) do
local _, bt = GetContainerNumFreeSlots(bag)
if bt ~= 0 then
for slot = 1, GetContainerNumSlots(bag) do
while true do
local locked = select( 3, GetContainerItemInfo(bag, slot))
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
 
if locked then
coroutine.yield()
else
break
--[[ 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
end
 
local item = GetContainerItemLink(bag, slot)
 
if not item then
local locked, ok, sbag, sslot
 
while true do
ok, sbag, sslot = RestackFindSpecial(bt, loc)
locked = ok and select(3, GetContainerItemInfo(sbag, sslot)) or false
 
if locked then
coroutine.yield()
else
break
 
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
 
if ok then
ClearCursor()
PickupContainerItem(sbag, sslot)
PickupContainerItem(bag, slot)
ClearCursor()
end
end
end
end
end
frame:SetScript("OnUpdate", function() end)
--[[ turn off yielding function ]]
frame:SetScript("OnUpdate", nil)
end)
coroutine.resume(restacker)
else
if not nowarn then
print("|cff33A1DEk|cffFFFFFFRestack |cffFF5555Restacking is already in progress, please wait.")
--[[ 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
end
kRestack/kRestack.toc
1,8 → 1,8
## Interface: 30100
## Title: kRestack
## Version: 0.9.wowi:revision
## SavedVariablesPerCharacter: AutoRestack
## Version: 1.0 rwowi:revision
## Author: Katae of Anvilmar
## Notes: Function for restacking inventory items.
## SavedVariablesPerCharacter: AutoRestack
 
kRestack.lua
\ No newline at end of file
kRestack/changelog.txt
1,2 → 1,9
r13 release 2009-05-13
v1.0 r14 release 2009-05-18
- Added support for restacking guild vault tabs.
- Hooked bag auto-stack to LOOT_OPEN and TRADE_SHOW, and guild bank auto-stack to GUILDBANKFRAME_OPENED and SetCurrentGuildBankTab(i).
- Extended auto-stack toggle to enable or disable bags, bank, or guild bank individually.
- Will now move items that can go into special class/profession bags into those bags if possible (soul shards, herbs, arrows, etc).
- Cleaned up and commented code.
 
v0.9 r13 release 2009-05-13
- Added option to auto-stack when opening bags or bank, off by default. Toggle with '/restack auto'
\ No newline at end of file