Guest User

BankStack TBC (removed Gbank to fix errors)

a guest
May 21st, 2021
221
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 24.55 KB | None | 0 0
  1. BankStack = LibStub("AceAddon-3.0"):NewAddon("BankStack", "AceEvent-3.0")
  2. local core = BankStack
  3. local L = LibStub("AceLocale-3.0"):GetLocale("BankStack")
  4. core.L = L
  5. core.events = LibStub("CallbackHandler-1.0"):New(core)
  6.  
  7. local debugf = tekDebug and tekDebug:GetFrame("BankStack")
  8. local function Debug(...) if debugf then debugf:AddMessage(string.join(", ", tostringall(...))) end end
  9. core.Debug = Debug
  10.  
  11. local version, build, date, tocversion = GetBuildInfo()
  12. core.has_guild_bank = tocversion >= 20300
  13.  
  14. --Bindings locales:
  15. BINDING_HEADER_BANKSTACK_HEAD = L['BINDING_HEADER_BANKSTACK_HEAD']
  16. BINDING_NAME_BANKSTACK = L['BINDING_NAME_BANKSTACK']
  17. BINDING_NAME_COMPRESS = L['BINDING_NAME_COMPRESS']
  18. BINDING_NAME_BAGSORT = L['BINDING_NAME_BAGSORT']
  19.  
  20. function core:OnInitialize()
  21. local oldDB
  22. if BankStackDB and not BankStackDB.profileKeys then
  23. -- upgrade the database!
  24. oldDB = BankStackDB
  25. BankStackDB = nil
  26. end
  27.  
  28. self.db_object = LibStub("AceDB-3.0"):New("BankStackDB", {
  29. profile = {
  30. verbosity = 1,
  31. junk = 2, -- 0: no special treatment, 1: end of sort, 2: back of bags
  32. conjured = false,
  33. soulbound = true,
  34. reverse = false,
  35. backfill = false,
  36. ignore = {},
  37. ignore_bags = {},
  38. ignore_blizzard = true,
  39. groups = {},
  40. fubar_keybinds={
  41. ['BUTTON1'] = 'sortbags',
  42. ['ALT-BUTTON1'] = 'sortbank',
  43. ['CTRL-BUTTON1'] = 'compressbags',
  44. ['ALT-CTRL-BUTTON1'] = 'compressbank',
  45. ['SHIFT-BUTTON1'] = 'stackbank',
  46. ['ALT-SHIFT-BUTTON1'] = 'stackbags',
  47. ['CTRL-SHIFT-BUTTON1'] = false,
  48. ['ALT-CTRL-SHIFT-BUTTON1'] = false,
  49. },
  50. conservative_guild = true,
  51. stutter_duration = 0.05,
  52. stutter_delay = 0,
  53. processing_delay = 0.1,
  54. processing_delay_guild = 0.4,
  55. },
  56. }, "Default")
  57. self.db = self.db_object.profile
  58. self.db_object.RegisterCallback(self, "OnProfileChanged", function()
  59. self.db = self.db_object.profile
  60. end)
  61.  
  62. if oldDB then
  63. local copy = function(from, to)
  64. for k,v in pairs(from) do
  65. if type(v) == 'table' then
  66. to[k] = copy(v, type(to[k]) == 'table' and to[k] or {})
  67. else
  68. to[k] = v
  69. end
  70. end
  71. return to
  72. end
  73. copy(oldDB, self.db)
  74. end
  75.  
  76. if type(self.db.junk) == "boolean" then
  77. self.db.junk = self.db.junk and 1 or 0
  78. end
  79.  
  80. if self.setup_config then
  81. self.setup_config()
  82. end
  83.  
  84. self:RegisterEvent("BANKFRAME_OPENED")
  85. self:RegisterEvent("BANKFRAME_CLOSED")
  86. --if self.has_guild_bank then
  87. -- self:RegisterEvent("GUILDBANKFRAME_OPENED")
  88. -- self:RegisterEvent("GUILDBANKFRAME_CLOSED")
  89. --end
  90. end
  91.  
  92. local frame = CreateFrame("Frame")
  93. local t, WAIT_TIME, MAX_MOVE_TIME = 0, 0.05, 3
  94. frame:SetScript("OnUpdate", function(self, time_since_last)
  95. --if (core.bankrequired and not core.bank_open) or (core.guildbankrequired and not core.guild_bank_open) then
  96. -- Debug(core.bankrequired and "bank required" or "guild bank required")
  97. -- core.StopStacking(L.at_bank)
  98. --end
  99. t = t + (time_since_last or 0.01)
  100. if t > WAIT_TIME then
  101. t = 0
  102. core.DoMoves()
  103. end
  104. end)
  105. frame:Hide() -- stops OnUpdate from running
  106.  
  107. core.frame = frame
  108.  
  109. --Inner workings:
  110. function core.announce(level, message, r, g, b)
  111. if level > core.db.verbosity then return end
  112. DEFAULT_CHAT_FRAME:AddMessage(message, r, g, b)
  113. end
  114.  
  115. -- http://wowwiki.com/API_TYPE_bagID
  116. local bank_bags = {REAGENTBANK_CONTAINER, BANK_CONTAINER}
  117. for i = NUM_BAG_SLOTS+1, NUM_BAG_SLOTS+NUM_BANKBAGSLOTS do
  118. table.insert(bank_bags, i)
  119. end
  120. core.bank_bags = bank_bags
  121. local player_bags = {}
  122. for i = 0, NUM_BAG_SLOTS do
  123. table.insert(player_bags, i)
  124. end
  125. core.player_bags = player_bags
  126. local all_bags = {}
  127. for _,i in ipairs(player_bags) do
  128. table.insert(all_bags, i)
  129. end
  130. for _,i in ipairs(bank_bags) do
  131. table.insert(all_bags, i)
  132. end
  133. core.all_bags = all_bags
  134. local guild = {51,52,53,54,55,56,57,58}
  135. core.guild = guild
  136. local all_bags_with_guild = {}
  137. for _,bag in ipairs(all_bags) do table.insert(all_bags_with_guild, bag) end
  138. for _,bag in ipairs(guild) do table.insert(all_bags_with_guild, bag) end
  139. core.all_bags_with_guild = all_bags_with_guild
  140.  
  141. local function is_valid_bag(bagid)
  142. return (bagid == BANK_CONTAINER or ((bagid >= 0) and bagid <= NUM_BAG_SLOTS+NUM_BANKBAGSLOTS))
  143. end
  144. core.is_valid_bag = is_valid_bag
  145. local function is_bank_bag(bagid)
  146. return (bagid == BANK_CONTAINER or bagid == REAGENTBANK_CONTAINER or (bagid > NUM_BAG_SLOTS and bagid <= NUM_BANKBAGSLOTS))
  147. end
  148. core.is_bank_bag = is_bank_bag
  149. local function is_guild_bank_bag(bagid)
  150. -- Note that this is an artificial slot id, which we're using internally to trigger usage of guild bank functions.
  151. -- Guild bank slots are: 51, 52, 53, 54, 55, 56, 57, 58.
  152. -- I couldn't find a constant for the maximum number of guild bank tabs; it's currently 8.
  153. return (bagid > 50 and bagid <= 58)
  154. end
  155. core.is_guild_bank_bag = is_guild_bank_bag
  156.  
  157. local core_groups = {
  158. bank = bank_bags,
  159. bags = player_bags,
  160. all = all_bags,
  161. reagents = {REAGENTBANK_CONTAINER},
  162. bank_without_reagents = {select(2, unpack(bank_bags))},
  163. guild = guild,
  164. guild1 = {51,},
  165. guild2 = {52,},
  166. guild3 = {53,},
  167. guild4 = {54,},
  168. guild5 = {55,},
  169. guild6 = {56,},
  170. guild7 = {57,},
  171. guild8 = {58,},
  172. }
  173. core.groups = core_groups
  174. function core.get_group(id)
  175. Debug ("get_group", id)
  176. --if id == "bank" and core.guild_bank_open then
  177. -- local tab = GetCurrentGuildBankTab()
  178. -- if tab then
  179. -- return core_groups["guild" .. tab]
  180. -- end
  181. --end
  182. if not core.db.groups[id] and string.match(id, "^[-%d,]+$") then
  183. Debug("Looks like a bag list", id)
  184. local bags = {}
  185. for b in string.gmatch(id, "-?%d+") do
  186. table.insert(bags, tonumber(b))
  187. end
  188. Debug("Parsed out", #bags)
  189. return bags
  190. end
  191. return core_groups[id] or core.db.groups[id]
  192. end
  193. function core.contains_bank_bag(group)
  194. for _,bag in ipairs(group) do
  195. if is_bank_bag(bag) then return true end
  196. end
  197. end
  198. function core.contains_guild_bank_bag(group)
  199. for _,bag in ipairs(group) do
  200. if is_guild_bank_bag(bag) then return true end
  201. end
  202. end
  203.  
  204. function core.check_for_banks(bags)
  205. --Check {bags} to see if any of them are in the bank / guild bank. Print a warning if they are.
  206. if core.contains_bank_bag(bags) then
  207. if not core.bank_open then
  208. core.announce(0, L.at_bank, 1, 0, 0)
  209. return true
  210. end
  211. core.bankrequired = true
  212. end
  213. --if core.contains_guild_bank_bag(bags) then
  214. -- if not core.guild_bank_open then
  215. -- core.announce(0, L.at_bank, 1, 0, 0)
  216. -- return true
  217. -- end
  218. -- core.guildbankrequired = true
  219. --end
  220. end
  221.  
  222. do
  223. local tooltip
  224. function core.CheckTooltipFor(bag, slot, text)
  225. if not tooltip then
  226. tooltip = CreateFrame("GameTooltip", "BankStackTooltip", nil, "GameTooltipTemplate")
  227. tooltip:SetOwner(WorldFrame, "ANCHOR_NONE")
  228. end
  229. tooltip:ClearLines()
  230. if slot and not bag then
  231. -- just showing tooltip for an itemid
  232. -- uses rather innocent checking so that slot can be a link or an itemid
  233. local link = tostring(slot) -- so that ":match" is guaranteed to be okay
  234. if not link:match("item:") then
  235. link = "item:"..link
  236. end
  237. tooltip:SetHyperlink(link)
  238. --elseif is_guild_bank_bag(bag) then
  239. -- tooltip:SetGuildBankItem(bag-50, slot)
  240. else
  241. -- This is just ridiculous... since 3.3, SetBagItem doesn't work in the base
  242. -- bank slot or the keyring since they're not real bags.
  243. if bag == BANK_CONTAINER then
  244. tooltip:SetInventoryItem("player", BankButtonIDToInvSlotID(slot, nil))
  245. elseif bag == REAGENTBANK_CONTAINER then
  246. tooltip:SetInventoryItem("player", ReagentBankButtonIDToInvSlotID(slot))
  247. else
  248. tooltip:SetBagItem(bag, slot)
  249. end
  250. end
  251. for i=2, tooltip:NumLines() do
  252. local left = _G["BankStackTooltipTextLeft"..i]
  253. --local right = _G["BankStackTooltipTextRight"..i]
  254. if left and left:IsShown() and string.match(left:GetText(), text) then return true end
  255. --if right and right:IsShown() and string.match(right:GetText(), text) then return true end
  256. end
  257. return false
  258. end
  259. end
  260.  
  261. local function encode_bagslot(bag, slot) return (bag*100) + slot end
  262. local function decode_bagslot(int) return math.floor(int/100), int % 100 end
  263. local function encode_move(source, target) return (source*10000)+target end
  264. local function decode_move(move)
  265. local source = math.floor(move/10000)
  266. local target = move%10000
  267. source = (target>9000) and (source+1) or source
  268. target = (target>9000) and (target-10000) or target
  269. return source, target
  270. end
  271. core.encode_bagslot = encode_bagslot
  272. core.decode_bagslot = decode_bagslot
  273. core.encode_move = encode_move
  274. core.decode_move = decode_move
  275.  
  276. do
  277. local bag_role, bagiter_forwards, bagiter_backwards
  278. function bagiter_forwards(baglist, i)
  279. i = i + 1
  280. local step = 1
  281. for _,bag in ipairs(baglist) do
  282. local slots = core.GetNumSlots(bag, bag_role)
  283. if i > slots + step then
  284. step = step + slots
  285. else
  286. for slot=1, slots do
  287. if step == i then
  288. return i, bag, slot
  289. end
  290. step = step + 1
  291. end
  292. end
  293. end
  294. bag_role = nil
  295. end
  296. function bagiter_backwards(baglist, i)
  297. i = i + 1
  298. local step = 1
  299. for ii=#baglist, 1, -1 do
  300. local bag = baglist[ii]
  301. local slots = core.GetNumSlots(bag, bag_role)
  302. if i > slots + step then
  303. step = step + slots
  304. else
  305. for slot=slots, 1, -1 do
  306. if step == i then
  307. return i, bag, slot
  308. end
  309. step = step + 1
  310. end
  311. end
  312. end
  313. bag_role = nil
  314. end
  315.  
  316. -- Iterate over bags and slots
  317. -- e.g. for _, bag, slot in core.IterateBags({1,2,3}) do ... end
  318. function core.IterateBags(baglist, reverse, role)
  319. bag_role = role
  320. return (reverse and bagiter_backwards or bagiter_forwards), baglist, 0
  321. end
  322. end
  323.  
  324. local already_queried = {}
  325. --local function QueryGuildBankTabIfNeeded(tab)
  326. -- if not already_queried[tab] then
  327. -- QueryGuildBankTab(tab)
  328. -- already_queried[tab] = true
  329. -- end
  330. --end
  331.  
  332. -- Wrapper functions to allow for pretending that the guild bank and bags are the same.
  333. function core.GetNumSlots(bag, role)
  334. -- role: "withdraw", "deposit", "both"; defaults to "both", as that is the most restrictive
  335. -- (Whether you intend to put things into or take things out of this bag. Only affects guild bank slots.)
  336. -- The main complication here is the guild bank.
  337. -- if is_guild_bank_bag(bag) then
  338. -- if not role then role = "deposit" end
  339. -- local tab = bag - 50
  340. -- QueryGuildBankTabIfNeeded(tab)
  341. -- local name, icon, canView, canDeposit, numWithdrawals = GetGuildBankTabInfo(tab)
  342. -- --(numWithdrawals is negative if you have unlimited withdrawals available.)
  343. -- if name and canView and ((role == "withdraw" and numWithdrawals ~= 0) or (role == "deposit" and canDeposit) or (role == "both" and numWithdrawals ~= 0 and canDeposit)) then
  344. -- return 98 -- MAX_GUILDBANK_SLOTS_PER_TAB (some bag addons stop Blizzard_GuildBankUI from loading, making the constant unavailable)
  345. -- end
  346. -- else
  347. return GetContainerNumSlots(bag)
  348. -- end
  349. -- return 0
  350. end
  351.  
  352. function core.GetItemInfo(bag, slot)
  353. -- if is_guild_bank_bag(bag) then
  354. -- local tab = bag - 50
  355. -- QueryGuildBankTabIfNeeded(tab)
  356. -- return GetGuildBankItemInfo(tab, slot)
  357. -- else
  358. return GetContainerItemInfo(bag, slot)
  359. -- end
  360. end
  361.  
  362. function core.GetItemLink(bag, slot)
  363. -- if is_guild_bank_bag(bag) then
  364. -- local tab = bag - 50
  365. -- QueryGuildBankTabIfNeeded(tab)
  366. -- return GetGuildBankItemLink(tab, slot)
  367. -- else
  368. return GetContainerItemLink(bag, slot)
  369. -- end
  370. end
  371.  
  372. function core.GetItemID(bag, slot)
  373. if is_guild_bank_bag(bag) then
  374. local link = core.GetItemLink(bag, slot)
  375. return link and tonumber(string.match(link, "item:(%d+)"))
  376. else
  377. return GetContainerItemID(bag, slot)
  378. end
  379. end
  380.  
  381. function core.PickupItem(bag, slot)
  382. --if is_guild_bank_bag(bag) then
  383. -- local tab = bag - 50
  384. -- return PickupGuildBankItem(tab, slot)
  385. --else
  386. return PickupContainerItem(bag, slot)
  387. --end
  388. end
  389.  
  390. function core.SplitItem(bag, slot, amount)
  391. --if is_guild_bank_bag(bag) then
  392. -- local tab = bag - 50
  393. -- return SplitGuildBankItem(tab, slot, amount)
  394. --else
  395. return SplitContainerItem(bag, slot, amount)
  396. --end
  397. end
  398.  
  399. do
  400. local safe = {
  401. [BANK_CONTAINER]=true,
  402. [0]=true,
  403. }
  404. function core.IsSpecialtyBag(bagid)
  405. if safe[bagid] or is_guild_bank_bag(bagid) then return false end
  406. if bagid == REAGENTBANK_CONTAINER then return true end
  407. local invslot = ContainerIDToInventoryID(bagid)
  408. if not invslot then return false end
  409. local bag = GetInventoryItemLink("player", invslot)
  410. if not bag then return false end
  411. local family = GetItemFamily(bag)
  412. if family == 0 then return false end
  413. return family
  414. end
  415. end
  416.  
  417. function core.CanItemGoInBag(bag, slot, target_bag)
  418. if is_guild_bank_bag(target_bag) then
  419. -- almost anything can go in a guild bank... apart from:
  420. if
  421. core.CheckTooltipFor(bag, slot, ITEM_SOULBOUND)
  422. or
  423. core.CheckTooltipFor(bag, slot, ITEM_CONJURED)
  424. or
  425. core.CheckTooltipFor(bag, slot, ITEM_BIND_QUEST)
  426. then
  427. return false
  428. end
  429. return true
  430. end
  431. local item = core.bag_ids[encode_bagslot(bag, slot)]
  432. -- since we now know this isn't a guild bank we can just use the bag id provided
  433. local item_family = GetItemFamily(item)
  434. if not item_family then
  435. Debug("Item without family", item, bag, slot)
  436. return false
  437. end
  438. if item_family > 0 then
  439. -- if the item is a profession bag, this will actually be the bag_family, and it should be zero
  440. if select(4, GetItemInfoInstant(item)) == "INVTYPE_BAG" then
  441. item_family = 0
  442. end
  443. end
  444. if target_bag == REAGENTBANK_CONTAINER then
  445. if not IsReagentBankUnlocked() then
  446. return false
  447. end
  448. -- 7.1.5 finally added an "is crafting reagent" return
  449. return select(17, GetItemInfo(item))
  450. end
  451.  
  452. local bag_family = select(2, GetContainerNumFreeSlots(target_bag))
  453. return bag_family == 0 or bit.band(item_family, bag_family) > 0
  454. end
  455.  
  456. function core.IsIgnored(bag, slot)
  457. if core.db.ignore_bags[bag] then
  458. return true
  459. end
  460. if core.db.ignore[encode_bagslot(bag, slot)] then
  461. return true
  462. end
  463. if core.db.ignore_blizzard then
  464. if (bag == -1) then
  465. return GetBankAutosortDisabled and GetBankAutosortDisabled() or false
  466. elseif (bag == 0) then
  467. return GetBackpackAutosortDisabled and GetBackpackAutosortDisabled() or false
  468. elseif is_bank_bag(bag) then
  469. return GetBankBagSlotFlag(bag - NUM_BAG_SLOTS, LE_BAG_FILTER_FLAG_IGNORE_CLEANUP)
  470. elseif not is_guild_bank_bag(bag) then
  471. return GetBagSlotFlag(bag, LE_BAG_FILTER_FLAG_IGNORE_CLEANUP)
  472. end
  473. end
  474. end
  475.  
  476. function core.CommandDecorator(func, groups_defaults, required_count)
  477. local bag_groups = {}
  478. return function(groups)
  479. Debug("command wrapper", groups, groups_defaults, required_count)
  480. if core.running then
  481. Debug("abort", "already running")
  482. return core.announce(0, L.already_running, 1, 0, 0)
  483. end
  484. wipe(bag_groups)
  485. if not groups or #groups == 0 then
  486. groups = groups_defaults
  487. end
  488. for bags in (groups or ""):gmatch("[^%s]+") do
  489. bags = core.get_group(bags)
  490. if bags then
  491. if core.check_for_banks(bags) then
  492. Debug("abort", "bank needed", bags)
  493. return
  494. end
  495. table.insert(bag_groups, bags)
  496. end
  497. end
  498. required_count = required_count or 1
  499. if #bag_groups < required_count then
  500. Debug("abort", "less groups than required", #bag_groups, required_count)
  501. return core.announce(0, L.confused, 1, 0, 0)
  502. end
  503.  
  504. core.ScanBags()
  505. if func(unpack(bag_groups)) == false then
  506. return
  507. end
  508. wipe(bag_groups)
  509. core.StartStacking()
  510. end
  511. end
  512.  
  513. --Respond to events:
  514. function core:BANKFRAME_OPENED()
  515. self.bank_open = true
  516. self.events:Fire("Bank_Open")
  517. end
  518. function core:BANKFRAME_CLOSED()
  519. self.bank_open = false
  520. self.events:Fire("Bank_Close")
  521. end
  522. --function core:GUILDBANKFRAME_OPENED()
  523. -- self.guild_bank_open = true
  524. -- self.events:Fire("GuildBank_Open")
  525. --end
  526. --function core:GUILDBANKFRAME_CLOSED()
  527. -- self.guild_bank_open = false
  528. -- self.events:Fire("GuildBank_Close")
  529. --end
  530.  
  531. local moves = {--[[encode_move(encode_bagslot(),encode_bagslot(target)),. ..--]]}
  532. core.moves = moves
  533.  
  534. local bag_ids = {}
  535. local bag_stacks = {}
  536. local bag_maxstacks = {}
  537. core.bag_ids, core.bag_stacks, core.bag_maxstacks = bag_ids, bag_stacks, bag_maxstacks
  538. local function update_location(from, to)
  539. -- When I move something from (3,12) to (0,1), the contents of (0,1) are now in (3,12).
  540. -- Therefore if I find later that I need to move something from (0,1), I actually need to move whatever wound up in (3,12).
  541. -- This function updates the various cache tables to reflect current locations.
  542. -- Debug("update_location", from, to)
  543. if (bag_ids[from] == bag_ids[to]) and (bag_stacks[to] < bag_maxstacks[to]) then
  544. -- If they're the same type we might have to deal with stacking.
  545. local stack_size = bag_maxstacks[to]
  546. if (bag_stacks[to] + bag_stacks[from]) > stack_size then
  547. -- only some of the items have been moved, since the total is greater than the stack size
  548. bag_stacks[from] = bag_stacks[from] - (stack_size - bag_stacks[to])
  549. bag_stacks[to] = stack_size
  550. else
  551. -- from is empty, since everything in it has been moved
  552. bag_stacks[to] = bag_stacks[to] + bag_stacks[from]
  553. bag_stacks[from] = nil
  554. bag_ids[from] = nil
  555. bag_maxstacks[from] = nil
  556. end
  557. else
  558. bag_ids[from], bag_ids[to] = bag_ids[to], bag_ids[from]
  559. bag_stacks[from], bag_stacks[to] = bag_stacks[to], bag_stacks[from]
  560. bag_maxstacks[from], bag_maxstacks[to] = bag_maxstacks[to], bag_maxstacks[from]
  561. end
  562. end
  563. function core.ScanBags()
  564. for _, bag, slot in core.IterateBags(core.has_guild_bank and all_bags_with_guild or all_bags) do
  565. local bagslot = encode_bagslot(bag, slot)
  566. local itemid = core.GetItemID(bag, slot)
  567. if itemid then
  568. bag_ids[bagslot] = itemid
  569. bag_stacks[bagslot] = select(2, core.GetItemInfo(bag, slot))
  570. bag_maxstacks[bagslot] = select(8, GetItemInfo(itemid))
  571. end
  572. end
  573. end
  574. function core.AddMove(source, destination)
  575. update_location(source, destination)
  576. table.insert(moves, 1, encode_move(source, destination))
  577. end
  578.  
  579. local moves_underway, last_itemid, last_destination, lock_stop, last_move, move_retries
  580. local move_tracker = {}
  581.  
  582. local function debugtime(start, ...) Debug("took", GetTime() - start, ...) end
  583. function core.DoMoves()
  584. Debug("DoMoves", #moves)
  585. if InCombatLockdown() then
  586. Debug("Aborted because of combat")
  587. return core.StopStacking(L.confused)
  588. end
  589. wipe(already_queried)
  590. local cursortype, cursor_itemid = GetCursorInfo()
  591. if cursortype == "item" and cursor_itemid then
  592. if last_itemid ~= cursor_itemid then
  593. -- We didn't pick up whatever is on the cursor; things could get really screwed up if we carry on. Abort!
  594. Debug("Aborted because", last_itemid or 'nil', '~=', cursor_itemid or 'nil')
  595. return core.StopStacking(L.confused)
  596. end
  597. if move_retries < 10 then
  598. local target_bag, target_slot = decode_bagslot(last_destination)
  599. local _, _, target_locked = core.GetItemInfo(target_bag, target_slot)
  600. if not target_locked then
  601. Debug("Attempting to repeat move drop", last_itemid, target_bag, target_slot)
  602. core.PickupItem(target_bag, target_slot)
  603. WAIT_TIME = core.db.processing_delay
  604. lock_stop = GetTime()
  605. move_retries = move_retries + 1
  606. return
  607. end
  608. end
  609. end
  610.  
  611. if lock_stop then
  612. Debug("Checking whether it's safe to move again")
  613. for slot, itemid in pairs(move_tracker) do
  614. local actual_slot_itemid = core.GetItemID(decode_bagslot(slot))
  615. Debug("checking whether", slot, "contains", itemid, actual_slot_itemid)
  616. if actual_slot_itemid ~= itemid then
  617. Debug("Stopping DoMoves because last move hasn't happened yet.", slot, itemid, actual_slot_itemid)
  618. WAIT_TIME = core.db.processing_delay
  619. if (GetTime() - lock_stop) > MAX_MOVE_TIME then
  620. if last_move and move_retries < 4 then
  621. local success, move_id = core.DoMove(last_move, true)
  622. Debug("Attempting to repeat entire move", last_move, success, move_id, move_retries)
  623. WAIT_TIME = core.db.processing_delay
  624. lock_stop = GetTime()
  625. move_retries = move_retries + 1
  626. return -- take a break!
  627. end
  628. -- Abandon it, since we've taken far too long on this move
  629. return core.StopStacking(L.confused)
  630. end
  631. return --give processing time to happen
  632. end
  633. move_tracker[slot] = nil
  634. end
  635. end
  636.  
  637. move_retries, last_itemid, last_destination, last_move, lock_stop = 0, nil, nil, nil, nil
  638. wipe(move_tracker)
  639.  
  640. core.events:Fire("Doing_Moves", #moves, moves)
  641.  
  642. local start, success, move_id, target_id, move_source, move_target, was_guild
  643. start = GetTime()
  644. if #moves > 0 then for i=#moves, 1, -1 do
  645. success, move_id, move_source, target_id, move_target, was_guild = core.DoMove(moves[i])
  646. if not success then
  647. debugtime(start, move_id or 'unspecified') -- repurposing for debugging
  648. WAIT_TIME = core.db.processing_delay
  649. lock_stop = GetTime()
  650. return -- take a break!
  651. end
  652. move_tracker[move_source] = target_id
  653. move_tracker[move_target] = move_id
  654. last_itemid = move_id
  655. last_destination = move_target
  656. last_move = moves[i]
  657. table.remove(moves, i)
  658. if moves[i-1] then
  659. -- Guild bank CursorHasItem/CursorItemInfo isn't working, so slow down for it.
  660. if was_guild then
  661. local next_source, next_target = decode_move(moves[i-1])
  662. if core.db.conservative_guild or move_tracker[next_source] or move_tracker[next_target] then
  663. Debug("fake-guild-locking is in effect", core.db.conservative_guild and "conservative" or "locking")
  664. WAIT_TIME = core.db.processing_delay_guild
  665. lock_stop = GetTime()
  666. debugtime(start, 'guild bank sucks')
  667. return
  668. end
  669. end
  670. if (GetTime() - start) > core.db.stutter_duration then
  671. -- avoiding the lags
  672. WAIT_TIME = core.db.stutter_delay
  673. debugtime(start, "stutter-avoider")
  674. return
  675. end
  676. end
  677. end end
  678. debugtime(start, 'done')
  679. core.announce(1, L.complete, 1, 1, 1)
  680. core.StopStacking()
  681. end
  682.  
  683. function core.DoMove(move)
  684. if GetCursorInfo() == "item" then
  685. return false, 'cursorhasitem'
  686. end
  687. local source, target = decode_move(move)
  688. local source_bag, source_slot = decode_bagslot(source)
  689. local target_bag, target_slot = decode_bagslot(target)
  690. local _, source_count, source_locked = core.GetItemInfo(source_bag, source_slot)
  691. local _, target_count, target_locked = core.GetItemInfo(target_bag, target_slot)
  692.  
  693. if source_locked or target_locked then
  694. return false, 'source/target_locked'
  695. end
  696.  
  697. local source_link = core.GetItemLink(source_bag, source_slot)
  698. local source_itemid = core.GetItemID(source_bag, source_slot)
  699. local target_itemid = core.GetItemID(target_bag, target_slot)
  700. if not source_itemid then
  701. if move_tracker[source] then
  702. return false, 'move incomplete'
  703. else
  704. Debug("Aborted because not source_itemid", source_bag, source_slot, source_link, source_itemid or 'nil')
  705. return core.StopStacking(L.confused)
  706. end
  707. end
  708. local stack_size = select(8, GetItemInfo(source_itemid))
  709.  
  710. core.announce(2, string.format(L.moving, source_link), 1,1,1)
  711.  
  712. if
  713. (source_itemid == target_itemid)
  714. and
  715. (target_count ~= stack_size)
  716. and
  717. ((target_count + source_count) > stack_size)
  718. then
  719. core.SplitItem(source_bag, source_slot, stack_size - target_count)
  720. else
  721. core.PickupItem(source_bag, source_slot)
  722. end
  723. -- local source_guildbank = is_guild_bank_bag(source_bag)
  724. -- local target_guildbank = is_guild_bank_bag(target_bag)
  725. if GetCursorInfo() == "item" then
  726. -- CursorHasItem doesn't work on the guild bank
  727. core.PickupItem(target_bag, target_slot)
  728. end
  729.  
  730. -- if source_guildbank then
  731. -- QueryGuildBankTabIfNeeded(source_bag - 50)
  732. -- end
  733. -- if target_guildbank then
  734. -- QueryGuildBankTabIfNeeded(target_bag - 50)
  735. -- end
  736.  
  737. if (source_itemid == target_itemid)
  738. and
  739. (target_count ~= stack_size)
  740. and
  741. ((target_count + source_count) <= stack_size)
  742. then
  743. -- we're doing a merge, so we pass back that we're not moving anything from the target slot to the source slot
  744. target_itemid = nil
  745. end
  746.  
  747. Debug("Moved", source, source_itemid, target, target_itemid) --, source_guildbank or target_guildbank)
  748. return true, source_itemid, source, target_itemid, target --, source_guildbank or target_guildbank
  749. end
  750.  
  751. function core.StartStacking()
  752. wipe(bag_maxstacks)
  753. wipe(bag_stacks)
  754. wipe(bag_ids)
  755. wipe(move_tracker)
  756.  
  757. if #moves > 0 then
  758. core.running = true
  759. core.announce(1, string.format(L.to_move, #moves), 1, 1, 1)
  760. frame:Show()
  761. core.events:Fire("Stacking_Started", #moves)
  762. else
  763. core.announce(1, L.perfect, 1, 1, 1)
  764. core.StopStacking()
  765. end
  766. end
  767.  
  768. function core.StopStacking(message, r, g, b)
  769. core.running = false
  770. core.bankrequired = false
  771. --core.guildbankrequired = false
  772. wipe(moves)
  773. wipe(move_tracker)
  774. move_retries, last_itemid, lock_stop, last_destination, last_move = 0, nil, nil, nil, nil
  775. frame:Hide()
  776. if message then
  777. core.announce(1, message, r or 1, g or 0, b or 0)
  778. end
  779. core.events:Fire("Stacking_Stopped", message)
  780. end
  781.  
Add Comment
Please, Sign In to add comment