Zerotorescue@80
|
1 local addon = select(2, ...);
|
Zerotorescue@80
|
2 local mod = addon:NewModule("Mover", "AceEvent-3.0", "AceTimer-3.0");
|
Zerotorescue@80
|
3
|
Zerotorescue@80
|
4 local Scanner;
|
Zerotorescue@80
|
5 local queuedMoves = {}; -- table storing all queued moves before BeginMove is called
|
Zerotorescue@80
|
6 local combinedMoves = {}; -- table storing all combined moves (with source and target) that is to be processed by the actual mover in the order of the index (1 to #)
|
Zerotorescue@81
|
7 local movesSource;
|
Zerotorescue@80
|
8
|
Zerotorescue@101
|
9 function mod:AddMove(itemId, amount, numMissing, numAvailable)
|
Zerotorescue@80
|
10 table.insert(queuedMoves, {
|
Zerotorescue@80
|
11 id = itemId,
|
Zerotorescue@80
|
12 num = amount,
|
Zerotorescue@101
|
13 missing = numMissing,
|
Zerotorescue@101
|
14 available = numAvailable,
|
Zerotorescue@80
|
15 });
|
Zerotorescue@80
|
16 end
|
Zerotorescue@80
|
17
|
Zerotorescue@81
|
18 function mod:HasMoves()
|
Zerotorescue@81
|
19 return (#queuedMoves ~= 0);
|
Zerotorescue@81
|
20 end
|
Zerotorescue@81
|
21
|
Zerotorescue@101
|
22 function mod:GetMoves()
|
Zerotorescue@101
|
23 return queuedMoves;
|
Zerotorescue@101
|
24 end
|
Zerotorescue@101
|
25
|
Zerotorescue@101
|
26 function mod:ResetQueue()
|
Zerotorescue@101
|
27 table.wipe(queuedMoves);
|
Zerotorescue@101
|
28 end
|
Zerotorescue@101
|
29
|
Zerotorescue@84
|
30 if not table.reverse then
|
Zerotorescue@84
|
31 table.reverse = function(orig)
|
Zerotorescue@84
|
32 local temp = {};
|
Zerotorescue@84
|
33 local origLength = #orig;
|
Zerotorescue@84
|
34 for i = 1, origLength do
|
Zerotorescue@84
|
35 temp[(origLength - i + 1)] = orig[i];
|
Zerotorescue@84
|
36 end
|
Zerotorescue@84
|
37
|
Zerotorescue@84
|
38 -- -- Update the original table (can't do orig = temp as that would change the reference-link instead of the original table)
|
Zerotorescue@84
|
39 -- for i, v in pairs(temp) do
|
Zerotorescue@84
|
40 -- orig[i] = v;
|
Zerotorescue@84
|
41 -- end
|
Zerotorescue@84
|
42 return temp; -- for speed we choose to do a return instead
|
Zerotorescue@84
|
43 end
|
Zerotorescue@84
|
44 end
|
Zerotorescue@84
|
45
|
Zerotorescue@80
|
46 function mod:BeginMove(location, onFinish)
|
Zerotorescue@81
|
47 addon:Debug("BeginMove");
|
Zerotorescue@80
|
48
|
Zerotorescue@80
|
49 -- Find the outgoing moves
|
Zerotorescue@80
|
50 -- We need the source container and slot, find all the requires sources and put them in a list which we go through later to find matching targets
|
Zerotorescue@80
|
51
|
Zerotorescue@80
|
52 -- Get a list of items in the source container
|
Zerotorescue@80
|
53 local sourceContents = Scanner:CacheLocation(location, false);
|
Zerotorescue@80
|
54
|
Zerotorescue@80
|
55 local outgoingMoves = {};
|
Zerotorescue@80
|
56
|
Zerotorescue@89
|
57 addon:Debug("%d moves were queued.", #queuedMoves);
|
Zerotorescue@82
|
58
|
Zerotorescue@81
|
59 for _, singleMove in pairs(queuedMoves) do
|
Zerotorescue@80
|
60 local sourceItem = sourceContents[singleMove.id];
|
Zerotorescue@80
|
61 if not sourceItem then
|
Zerotorescue@101
|
62 addon:Print(("Can't move %s, this doesn't exist in the source."):format(IdToItemLink(singleMove.id)), addon.Colors.Red);
|
Zerotorescue@80
|
63 else
|
Zerotorescue@82
|
64 -- We want to move the smallest stacks first to keep stuff pretty (and minimize space usage, splitting a stack takes 2 slots, moving something only 1)
|
Zerotorescue@80
|
65 table.sort(sourceItem.locations, function(a, b)
|
Zerotorescue@81
|
66 return a.count < b.count;
|
Zerotorescue@80
|
67 end);
|
Zerotorescue@80
|
68
|
Zerotorescue@81
|
69 for _, itemLocation in pairs(sourceItem.locations) do
|
Zerotorescue@80
|
70 -- if this location has more items than we need, only move what we need, otherwise move everything in this stack
|
Zerotorescue@80
|
71 local movingNum = ((itemLocation.count > singleMove.num and singleMove.num) or itemLocation.count);
|
Zerotorescue@80
|
72
|
Zerotorescue@80
|
73 table.insert(outgoingMoves, {
|
Zerotorescue@80
|
74 itemId = singleMove.id,
|
Zerotorescue@82
|
75 num = movingNum,
|
Zerotorescue@80
|
76 container = itemLocation.container,
|
Zerotorescue@80
|
77 slot = itemLocation.slot,
|
Zerotorescue@80
|
78 });
|
Zerotorescue@80
|
79
|
Zerotorescue@80
|
80 singleMove.num = (singleMove.num - movingNum);
|
Zerotorescue@80
|
81
|
Zerotorescue@80
|
82 if singleMove.num == 0 then
|
Zerotorescue@80
|
83 -- If we have prepared everything we wanted, go to the next queued move
|
Zerotorescue@81
|
84 break; -- stop the locations-loop
|
Zerotorescue@80
|
85 end
|
Zerotorescue@80
|
86 end
|
Zerotorescue@80
|
87 end
|
Zerotorescue@80
|
88 end
|
Zerotorescue@82
|
89
|
Zerotorescue@89
|
90 addon:Debug("%d outgoing moves are possible.", #outgoingMoves);
|
Zerotorescue@80
|
91
|
Zerotorescue@80
|
92 -- No longer needed
|
Zerotorescue@80
|
93 table.wipe(queuedMoves);
|
Zerotorescue@80
|
94
|
Zerotorescue@80
|
95 -- Process every single outgoing move and find fitting targets
|
Zerotorescue@80
|
96
|
Zerotorescue@80
|
97 -- Get a list of items already in the target container
|
Zerotorescue@80
|
98 local targetContents = Scanner:CacheLocation(addon.Locations.Bag, false);
|
Zerotorescue@80
|
99
|
Zerotorescue@80
|
100 -- Find all empty slots
|
Zerotorescue@80
|
101
|
Zerotorescue@80
|
102 local emptySlots = {};
|
Zerotorescue@80
|
103
|
Zerotorescue@80
|
104 local start = 0;
|
Zerotorescue@80
|
105 local stop = NUM_BAG_SLOTS;
|
Zerotorescue@80
|
106
|
Zerotorescue@80
|
107 -- Go through all our bags, including the backpack
|
Zerotorescue@80
|
108 for bagId = start, stop do
|
Zerotorescue@80
|
109 -- Go through all our slots
|
Zerotorescue@80
|
110 for slotId = 1, GetContainerNumSlots(bagId) do
|
Zerotorescue@82
|
111 local itemId = GetContainerItemID(bagId, slotId); -- we're scanning our local bags here, so no need to get messy with guild bank support
|
Zerotorescue@80
|
112
|
Zerotorescue@80
|
113 if not itemId then
|
Zerotorescue@80
|
114 table.insert(emptySlots, {
|
Zerotorescue@81
|
115 container = bagId,
|
Zerotorescue@81
|
116 slot = slotId,
|
Zerotorescue@80
|
117 });
|
Zerotorescue@80
|
118 end
|
Zerotorescue@80
|
119 end
|
Zerotorescue@80
|
120 end
|
Zerotorescue@82
|
121
|
Zerotorescue@89
|
122 addon:Debug("%d empty slots are available.", #emptySlots);
|
Zerotorescue@80
|
123
|
Zerotorescue@81
|
124 -- Remember where we're moving from
|
Zerotorescue@81
|
125 movesSource = location;
|
Zerotorescue@81
|
126
|
Zerotorescue@84
|
127 local backup = 0;
|
Zerotorescue@84
|
128
|
Zerotorescue@80
|
129 while #outgoingMoves ~= 0 do
|
Zerotorescue@80
|
130 -- A not equal-comparison should be quicker than a larger/smaller than-comparison
|
Zerotorescue@80
|
131
|
Zerotorescue@81
|
132 for _, outgoingMove in pairs(outgoingMoves) do
|
Zerotorescue@80
|
133 -- itemId will be set to nil when this outgoing move was processed - sanity check
|
Zerotorescue@80
|
134 if outgoingMove.itemId then
|
Zerotorescue@80
|
135 local targetItem = targetContents[outgoingMove.itemId];
|
Zerotorescue@80
|
136
|
Zerotorescue@80
|
137 if not targetItem then
|
Zerotorescue@80
|
138 -- grab an empty slot
|
Zerotorescue@80
|
139 -- make new instance of ItemMove
|
Zerotorescue@80
|
140 -- populate targetContents with it so future moves of this item can be put on top of it if this isn't a full stack
|
Zerotorescue@80
|
141
|
Zerotorescue@80
|
142 local firstAvailableSlot = emptySlots[1];
|
Zerotorescue@80
|
143
|
Zerotorescue@80
|
144 if not firstAvailableSlot then
|
Zerotorescue@98
|
145 addon:Print(("Bags are full. Skipping %s."):format(IdToItemLink(outgoingMove.itemId)), addon.Colors.Orange);
|
Zerotorescue@80
|
146
|
Zerotorescue@82
|
147 outgoingMove.itemId = nil; -- remove this record from the outgoingMoves-table
|
Zerotorescue@109
|
148
|
Zerotorescue@109
|
149 -- Not a single item with this item id can be moved, since we only want the bags are full announcement once, we remove all other moves with this item id
|
Zerotorescue@109
|
150 for _, otherMove in pairs(outgoingMoves) do
|
Zerotorescue@109
|
151 if otherMove.itemId and otherMove.itemId == outgoingMove.itemId then
|
Zerotorescue@109
|
152 otherMove.itemId = nil;
|
Zerotorescue@109
|
153 end
|
Zerotorescue@109
|
154 end
|
Zerotorescue@80
|
155 else
|
Zerotorescue@80
|
156 table.insert(combinedMoves, {
|
Zerotorescue@82
|
157 itemId = outgoingMove.itemId,
|
Zerotorescue@82
|
158 num = outgoingMove.num,
|
Zerotorescue@80
|
159 sourceContainer = outgoingMove.container,
|
Zerotorescue@80
|
160 sourceSlot = outgoingMove.slot,
|
Zerotorescue@80
|
161 targetContainer = firstAvailableSlot.container,
|
Zerotorescue@80
|
162 targetSlot = firstAvailableSlot.slot,
|
Zerotorescue@80
|
163 });
|
Zerotorescue@80
|
164
|
Zerotorescue@80
|
165 -- We filled an empty slot so the target contents now has one more item,
|
Zerotorescue@80
|
166 -- make a new instance of the ItemMove class so any additional items with this id can be stacked on top of it
|
Zerotorescue@81
|
167 local itemMove = addon.ContainerItem:New();
|
Zerotorescue@82
|
168 itemMove:AddLocation(firstAvailableSlot.container, firstAvailableSlot.slot, outgoingMove.num);
|
Zerotorescue@80
|
169 targetContents[outgoingMove.itemId] = itemMove;
|
Zerotorescue@80
|
170
|
Zerotorescue@81
|
171 table.remove(emptySlots, 1); -- no longer empty
|
Zerotorescue@80
|
172
|
Zerotorescue@82
|
173 outgoingMove.num = 0; -- nothing remaining - sanity check
|
Zerotorescue@80
|
174 outgoingMove.itemId = nil; -- remove this record from the outgoingMoves-table
|
Zerotorescue@80
|
175 end
|
Zerotorescue@80
|
176 else
|
Zerotorescue@80
|
177 -- Find the maximum stack size for this item
|
Zerotorescue@80
|
178 local itemStackCount = select(8, GetItemInfo(outgoingMove.itemId));
|
Zerotorescue@80
|
179
|
Zerotorescue@80
|
180 -- We want to move to the largest stacks first to keep stuff pretty
|
Zerotorescue@80
|
181 table.sort(targetItem.locations, function(a, b)
|
Zerotorescue@81
|
182 return a.count > b.count;
|
Zerotorescue@80
|
183 end);
|
Zerotorescue@80
|
184
|
Zerotorescue@81
|
185 for _, itemLocation in pairs(targetItem.locations) do
|
Zerotorescue@82
|
186 if itemLocation.count < itemStackCount and outgoingMove.num > 0 then
|
Zerotorescue@80
|
187 -- Check if this stack isn't already full (and we still need to move this item)
|
Zerotorescue@80
|
188
|
Zerotorescue@80
|
189 local remainingSpace = (itemStackCount - itemLocation.count);
|
Zerotorescue@84
|
190 if remainingSpace >= outgoingMove.num then
|
Zerotorescue@80
|
191 -- Enough room to move this entire stack
|
Zerotorescue@80
|
192 -- Deposit this item and then forget this outgoing move as everything in it was processed
|
Zerotorescue@80
|
193
|
Zerotorescue@80
|
194 table.insert(combinedMoves, {
|
Zerotorescue@82
|
195 itemId = outgoingMove.itemId,
|
Zerotorescue@82
|
196 num = outgoingMove.num,
|
Zerotorescue@80
|
197 sourceContainer = outgoingMove.container,
|
Zerotorescue@80
|
198 sourceSlot = outgoingMove.slot,
|
Zerotorescue@80
|
199 targetContainer = itemLocation.container,
|
Zerotorescue@80
|
200 targetSlot = itemLocation.slot,
|
Zerotorescue@80
|
201 });
|
Zerotorescue@80
|
202
|
Zerotorescue@82
|
203 itemLocation.count = (itemLocation.count + outgoingMove.num);
|
Zerotorescue@84
|
204 outgoingMove.num = 0; -- nothing remaining
|
Zerotorescue@80
|
205 outgoingMove.itemId = nil; -- remove this record from the outgoingMoves-table
|
Zerotorescue@80
|
206 break; -- stop the locations-loop
|
Zerotorescue@80
|
207 else
|
Zerotorescue@80
|
208 -- Deposit this item but don't remove the outgoing move as there are some items left to move
|
Zerotorescue@80
|
209
|
Zerotorescue@80
|
210 table.insert(combinedMoves, {
|
Zerotorescue@82
|
211 itemId = outgoingMove.itemId,
|
Zerotorescue@82
|
212 num = outgoingMove.num,
|
Zerotorescue@80
|
213 sourceContainer = outgoingMove.container,
|
Zerotorescue@80
|
214 sourceSlot = outgoingMove.slot,
|
Zerotorescue@80
|
215 targetContainer = itemLocation.container,
|
Zerotorescue@80
|
216 targetSlot = itemLocation.slot,
|
Zerotorescue@80
|
217 });
|
Zerotorescue@80
|
218
|
Zerotorescue@80
|
219 -- The target will be full when we complete, but the source will still have remaining items left to be moved
|
Zerotorescue@80
|
220 itemLocation.count = itemStackCount;
|
Zerotorescue@82
|
221 outgoingMove.num = (outgoingMove.num - remainingSpace);
|
Zerotorescue@80
|
222 end
|
Zerotorescue@80
|
223 end
|
Zerotorescue@80
|
224 end
|
Zerotorescue@80
|
225
|
Zerotorescue@82
|
226 if outgoingMove.num > 0 then
|
Zerotorescue@80
|
227 -- We went through all matching items and checked their stack sizes if we could move this there, no room available
|
Zerotorescue@80
|
228 -- So forget about the target item (even though it may just have full locations, these are useless anyway) and the next loop move it onto an empty slot
|
Zerotorescue@84
|
229 targetContents[outgoingMove.itemId] = nil;
|
Zerotorescue@80
|
230 end
|
Zerotorescue@80
|
231 end
|
Zerotorescue@80
|
232 end
|
Zerotorescue@80
|
233 end
|
Zerotorescue@80
|
234
|
Zerotorescue@80
|
235 -- Loop through the array to find items that should be removed, start with the last element or the loop would break
|
Zerotorescue@80
|
236 local numOutgoingMoves = #outgoingMoves; -- since LUA-tables start at an index of 1, this is actually an existing index (outgoingMoves[#outgoingMoves] would return a value)
|
Zerotorescue@80
|
237 while numOutgoingMoves ~= 0 do
|
Zerotorescue@80
|
238 -- A not equal-comparison should be quicker than a larger/smaller than-comparison
|
Zerotorescue@80
|
239
|
Zerotorescue@80
|
240 -- Check if the item id is nil, this is set to nil when this outgoing move has been processed
|
Zerotorescue@84
|
241 if not outgoingMoves[numOutgoingMoves].itemId or outgoingMoves[numOutgoingMoves].num == 0 then
|
Zerotorescue@80
|
242 -- Remove this element from the array
|
Zerotorescue@80
|
243 table.remove(outgoingMoves, numOutgoingMoves);
|
Zerotorescue@80
|
244 end
|
Zerotorescue@80
|
245
|
Zerotorescue@80
|
246 -- Proceed with the next element (or previous considering we're going from last to first)
|
Zerotorescue@80
|
247 numOutgoingMoves = (numOutgoingMoves - 1);
|
Zerotorescue@80
|
248 end
|
Zerotorescue@84
|
249
|
Zerotorescue@89
|
250 addon:Debug("%d moves remaining.", #outgoingMoves);
|
Zerotorescue@84
|
251
|
Zerotorescue@84
|
252 backup = (backup + 1);
|
Zerotorescue@84
|
253 if backup > 1000 then
|
Zerotorescue@84
|
254 dump(nil, outgoingMoves);
|
Zerotorescue@84
|
255 table.wipe(outgoingMoves);
|
Zerotorescue@84
|
256 self:Abort("mover crashed", "Error preparing moves, hit an endless loop");
|
Zerotorescue@84
|
257 onFinish();
|
Zerotorescue@84
|
258 return;
|
Zerotorescue@84
|
259 end
|
Zerotorescue@80
|
260 end
|
Zerotorescue@84
|
261
|
Zerotorescue@84
|
262 -- Reverse table, we need to go through it from last to first because we'll be removing elements, but we don't want the actions to be executed in a different order
|
Zerotorescue@84
|
263 combinedMoves = table.reverse(combinedMoves);
|
Zerotorescue@82
|
264
|
Zerotorescue@89
|
265 addon:Debug("%d moves should be possible.", #combinedMoves);
|
Zerotorescue@80
|
266
|
Zerotorescue@80
|
267 -- No longer needed
|
Zerotorescue@80
|
268 table.wipe(emptySlots);
|
Zerotorescue@80
|
269
|
Zerotorescue@81
|
270 self:ProcessMove();
|
Zerotorescue@80
|
271
|
Zerotorescue@82
|
272 -- Even though we aren't completely done yet, allow requeueing
|
Zerotorescue@81
|
273 onFinish();
|
Zerotorescue@80
|
274 end
|
Zerotorescue@80
|
275
|
Zerotorescue@109
|
276 local ContainerFunctions = {
|
Zerotorescue@109
|
277 [addon.Locations.Bag] = {
|
Zerotorescue@109
|
278 GetItemId = GetContainerItemID,
|
Zerotorescue@109
|
279 PickupItem = SplitContainerItem,
|
Zerotorescue@109
|
280 IsLocked = function(sourceContainer, sourceSlot)
|
Zerotorescue@109
|
281 return select(3, GetContainerItemInfo(sourceContainer, sourceSlot);
|
Zerotorescue@109
|
282 end,
|
Zerotorescue@109
|
283 },
|
Zerotorescue@109
|
284 [addon.Locations.Bank] = {
|
Zerotorescue@109
|
285 GetItemId = GetContainerItemID,
|
Zerotorescue@109
|
286 PickupItem = SplitContainerItem,
|
Zerotorescue@109
|
287 IsLocked = function(sourceContainer, sourceSlot)
|
Zerotorescue@109
|
288 return select(3, GetContainerItemInfo(sourceContainer, sourceSlot);
|
Zerotorescue@109
|
289 end,
|
Zerotorescue@109
|
290 },
|
Zerotorescue@109
|
291 [addon.Locations.Guild] = {
|
Zerotorescue@109
|
292 GetItemId = function(tabId, slotId)
|
Zerotorescue@109
|
293 return addon:GetItemId(GetGuildBankItemLink(tabId, slotId));
|
Zerotorescue@109
|
294 end,
|
Zerotorescue@109
|
295 PickupItem = SplitGuildBankItem,
|
Zerotorescue@109
|
296 IsLocked = function(sourceContainer, sourceSlot)
|
Zerotorescue@109
|
297 return select(3, GetGuildBankItemInfo(sourceContainer, sourceSlot);
|
Zerotorescue@109
|
298 end,
|
Zerotorescue@109
|
299 },
|
Zerotorescue@109
|
300 --[[ Even though support is possible, it will require a little more work than just this and there are currently higher priorities
|
Zerotorescue@109
|
301 [addon.Locations.Mailbox] = {
|
Zerotorescue@109
|
302 GetItemId = function(mailIndex, attachmentId)
|
Zerotorescue@109
|
303 return addon:GetItemId(GetInboxItemLink(mailIndex, attachmentId));
|
Zerotorescue@109
|
304 end,
|
Zerotorescue@109
|
305 PickupItem = TakeInboxItem,
|
Zerotorescue@109
|
306 IsLocked = function() return false; end,
|
Zerotorescue@109
|
307 DoNotDrop = true,
|
Zerotorescue@109
|
308 },]]
|
Zerotorescue@109
|
309 };
|
Zerotorescue@109
|
310
|
Zerotorescue@81
|
311 function mod:ProcessMove()
|
Zerotorescue@81
|
312 addon:Debug("ProcessMove");
|
Zerotorescue@81
|
313
|
Zerotorescue@81
|
314 if #combinedMoves == 0 then
|
Zerotorescue@98
|
315 addon:Print("Nothing to move.");
|
Zerotorescue@81
|
316
|
Zerotorescue@81
|
317 self:Abort();
|
Zerotorescue@81
|
318
|
Zerotorescue@81
|
319 return;
|
Zerotorescue@81
|
320 end
|
Zerotorescue@81
|
321
|
Zerotorescue@98
|
322 -- Make sure nothing is at the mouse
|
Zerotorescue@98
|
323 ClearCursor();
|
Zerotorescue@98
|
324
|
Zerotorescue@88
|
325 self:RegisterEvent("ITEM_LOCK_CHANGED");
|
Zerotorescue@81
|
326 self:RegisterEvent("UI_ERROR_MESSAGE");
|
Zerotorescue@81
|
327
|
Zerotorescue@80
|
328 -- combinedMoves now has all moves in it (source -> target)
|
Zerotorescue@80
|
329 -- go through list, move everything inside it
|
Zerotorescue@81
|
330 -- add source and target to lists, if either is already in this list, skip the move
|
Zerotorescue@81
|
331 -- repeat every few seconds until we're completely done
|
Zerotorescue@80
|
332
|
Zerotorescue@80
|
333 local sourceLocationsLocked = {};
|
Zerotorescue@80
|
334 local targetLocationsLocked = {};
|
Zerotorescue@80
|
335
|
Zerotorescue@82
|
336 local combinedMovesOriginalLength = #combinedMoves;
|
Zerotorescue@82
|
337 local numCurrentMove = combinedMovesOriginalLength;
|
Zerotorescue@80
|
338 while numCurrentMove ~= 0 do
|
Zerotorescue@80
|
339 local move = combinedMoves[numCurrentMove];
|
Zerotorescue@80
|
340
|
Zerotorescue@109
|
341 local isSourceLocked = ((sourceLocationsLocked[move.sourceContainer] and sourceLocationsLocked[move.sourceContainer][move.sourceSlot]) or ContainerFunctions[movesSource].IsLocked(move.sourceContainer, move.sourceSlot));
|
Zerotorescue@109
|
342 -- Target are always the local bags
|
Zerotorescue@109
|
343 local isTargetLocked = ((targetLocationsLocked[move.targetContainer] and targetLocationsLocked[move.targetContainer][move.targetSlot]) or ContainerFunctions[addon.Locations.Bag].IsLocked(move.targetContainer, move.targetSlot));
|
Zerotorescue@88
|
344
|
Zerotorescue@89
|
345 if move and not isSourceLocked and not isTargetLocked then
|
Zerotorescue@98
|
346 addon:Print(("Moving %dx%s."):format(move.num, IdToItemLink(move.itemId)));
|
Zerotorescue@80
|
347
|
Zerotorescue@89
|
348 addon:Debug("Moving %dx%s from (%d,%d) to (%d,%d)", move.num, IdToItemLink(move.itemId), move.sourceContainer, move.sourceSlot, move.targetContainer, move.targetSlot);
|
Zerotorescue@81
|
349
|
Zerotorescue@109
|
350 if ContainerFunctions[movesSource].GetItemId(move.sourceContainer, move.sourceSlot) ~= move.itemId then
|
Zerotorescue@81
|
351 self:Abort("source changed", "Source (" .. move.sourceContainer .. "," .. move.sourceSlot .. ") is not " .. IdToItemLink(move.itemId));
|
Zerotorescue@81
|
352 return;
|
Zerotorescue@81
|
353 end
|
Zerotorescue@81
|
354
|
Zerotorescue@80
|
355 -- Pickup stack
|
Zerotorescue@109
|
356 ContainerFunctions[movesSource].PickupItem(move.sourceContainer, move.sourceSlot, move.num);
|
Zerotorescue@80
|
357
|
Zerotorescue@80
|
358 -- Remember we picked this item up and thus it is now locked
|
Zerotorescue@80
|
359 if not sourceLocationsLocked[move.sourceContainer] then
|
Zerotorescue@80
|
360 sourceLocationsLocked[move.sourceContainer] = {};
|
Zerotorescue@80
|
361 end
|
Zerotorescue@80
|
362 sourceLocationsLocked[move.sourceContainer][move.sourceSlot] = true;
|
Zerotorescue@80
|
363
|
Zerotorescue@109
|
364 if movesSource ~= addon.Locations.Bank or CursorHasItem() then -- CursorHasItem only works when moving outside of the bank
|
Zerotorescue@84
|
365 -- We are moving into our local bags, so the below must check normal
|
Zerotorescue@109
|
366 local targetItemId = ContainerFunctions[movesSource].get(move.targetContainer, move.targetSlot);
|
Zerotorescue@84
|
367 if targetItemId and targetItemId ~= move.itemId then
|
Zerotorescue@81
|
368 self:Abort("target changed", "Target (" .. move.targetContainer .. "," .. move.targetSlot .. ") is not " .. IdToItemLink(move.itemId) .. " nor empty");
|
Zerotorescue@81
|
369 return;
|
Zerotorescue@81
|
370 end
|
Zerotorescue@81
|
371
|
Zerotorescue@82
|
372 -- And drop it (this is always a local bag so no need to do any guild-checks)
|
Zerotorescue@80
|
373 PickupContainerItem(move.targetContainer, move.targetSlot);
|
Zerotorescue@80
|
374
|
Zerotorescue@80
|
375 -- Remember we dropped an item here and thus this is now locked
|
Zerotorescue@81
|
376 if not targetLocationsLocked[move.targetContainer] then
|
Zerotorescue@81
|
377 targetLocationsLocked[move.targetContainer] = {};
|
Zerotorescue@80
|
378 end
|
Zerotorescue@81
|
379 targetLocationsLocked[move.targetContainer][move.targetSlot] = true;
|
Zerotorescue@80
|
380
|
Zerotorescue@80
|
381 -- This move was processed
|
Zerotorescue@80
|
382 table.remove(combinedMoves, numCurrentMove);
|
Zerotorescue@81
|
383 else
|
Zerotorescue@81
|
384 self:Abort("item disappeared from mouse", "Couldn't move " .. IdToItemLink(move.itemId) .. ", CursorHasItem() is false");
|
Zerotorescue@81
|
385 return;
|
Zerotorescue@80
|
386 end
|
Zerotorescue@80
|
387 end
|
Zerotorescue@80
|
388
|
Zerotorescue@80
|
389 -- Proceed with the next element (or previous considering we're going from last to first)
|
Zerotorescue@80
|
390 numCurrentMove = (numCurrentMove - 1);
|
Zerotorescue@80
|
391 end
|
Zerotorescue@81
|
392
|
Zerotorescue@89
|
393 addon:Debug("%d moves processed. %d moves remaining.", (combinedMovesOriginalLength - #combinedMoves), #combinedMoves);
|
Zerotorescue@82
|
394
|
Zerotorescue@81
|
395 if #combinedMoves == 0 then
|
Zerotorescue@98
|
396 addon:Print("Finished.", addon.Colors.Green);
|
Zerotorescue@81
|
397
|
Zerotorescue@81
|
398 self:Abort();
|
Zerotorescue@81
|
399
|
Zerotorescue@81
|
400 return;
|
Zerotorescue@81
|
401 end
|
Zerotorescue@80
|
402 end
|
Zerotorescue@80
|
403
|
Zerotorescue@80
|
404 local tmrProcessNext;
|
Zerotorescue@88
|
405 function mod:ITEM_LOCK_CHANGED()
|
Zerotorescue@81
|
406 self:CancelTimer(tmrProcessNext, true); -- silent
|
Zerotorescue@89
|
407 tmrProcessNext = self:ScheduleTimer("ProcessMove", .5);
|
Zerotorescue@80
|
408 end
|
Zerotorescue@80
|
409
|
Zerotorescue@81
|
410 function IdToItemLink(itemId)
|
Zerotorescue@81
|
411 local itemLink = select(2, GetItemInfo(itemId));
|
Zerotorescue@81
|
412 itemLink = itemLink or "Unknown (" .. itemId .. ")";
|
Zerotorescue@81
|
413 return itemLink;
|
Zerotorescue@81
|
414 end
|
Zerotorescue@81
|
415
|
Zerotorescue@81
|
416 function mod:UI_ERROR_MESSAGE(e, errorMessage)
|
Zerotorescue@81
|
417 if errorMessage == ERR_SPLIT_FAILED then
|
Zerotorescue@81
|
418 self:Abort("splitting failed", "Splitting failed.");
|
Zerotorescue@80
|
419 end
|
Zerotorescue@80
|
420 end
|
Zerotorescue@80
|
421
|
Zerotorescue@81
|
422 function mod:Abort(simple, debugMsg)
|
Zerotorescue@81
|
423 if debugMsg then
|
Zerotorescue@89
|
424 addon:Debug("Aborting:%s", debugMsg);
|
Zerotorescue@81
|
425 end
|
Zerotorescue@81
|
426 if simple then
|
Zerotorescue@98
|
427 addon:Print(("Aborting: %s."):format(simple), addon.Colors.Red);
|
Zerotorescue@81
|
428 end
|
Zerotorescue@81
|
429 table.wipe(combinedMoves);
|
Zerotorescue@81
|
430 movesSource = nil;
|
Zerotorescue@80
|
431
|
Zerotorescue@98
|
432 -- Make sure nothing is at the mouse
|
Zerotorescue@98
|
433 ClearCursor();
|
Zerotorescue@98
|
434
|
Zerotorescue@81
|
435 -- Stop timer
|
Zerotorescue@89
|
436 self:UnregisterEvent("ITEM_LOCK_CHANGED");
|
Zerotorescue@81
|
437 self:CancelTimer(tmrProcessNext, true); -- silent
|
Zerotorescue@80
|
438
|
Zerotorescue@81
|
439 self:UnregisterEvent("UI_ERROR_MESSAGE");
|
Zerotorescue@80
|
440 end
|
Zerotorescue@80
|
441
|
Zerotorescue@80
|
442 function mod:OnEnable()
|
Zerotorescue@80
|
443 Scanner = addon:GetModule("Scanner");
|
Zerotorescue@80
|
444 end
|
Zerotorescue@80
|
445
|
Zerotorescue@80
|
446 function mod:OnDisable()
|
Zerotorescue@80
|
447 Scanner = nil;
|
Zerotorescue@81
|
448
|
Zerotorescue@81
|
449 self:Abort();
|
Zerotorescue@80
|
450 end
|