comparison Mover.lua @ 82:f885805da5d6

Added options to toggle the automatic refilling. This defaults to true. Normalized property amount names; a move has a ?num? that must be moved and a location has a ?count? indicating the amount of items at that slot. Target/source item verification should now be working properly for guilds. When ?bank? is included in the local item count, we will skip trying to auto refill from this.
author Zerotorescue
date Thu, 06 Jan 2011 10:48:56 +0100
parents 58617c7827fa
children
comparison
equal deleted inserted replaced
81:58617c7827fa 82:f885805da5d6
26 -- Get a list of items in the source container 26 -- Get a list of items in the source container
27 local sourceContents = Scanner:CacheLocation(location, false); 27 local sourceContents = Scanner:CacheLocation(location, false);
28 28
29 local outgoingMoves = {}; 29 local outgoingMoves = {};
30 30
31 addon:Debug(#queuedMoves .. " moves were queued.");
32
31 for _, singleMove in pairs(queuedMoves) do 33 for _, singleMove in pairs(queuedMoves) do
32 local sourceItem = sourceContents[singleMove.id]; 34 local sourceItem = sourceContents[singleMove.id];
33 if not sourceItem then 35 if not sourceItem then
34 print("Can't move " .. IdToItemLink(singleMove.id) .. ", non-existant in source"); 36 print("Can't move " .. IdToItemLink(singleMove.id) .. ", non-existant in source");
35 else 37 else
36 -- We want to move the smallest stacks first to keep stuff pretty 38 -- 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)
37 table.sort(sourceItem.locations, function(a, b) 39 table.sort(sourceItem.locations, function(a, b)
38 return a.count < b.count; 40 return a.count < b.count;
39 end); 41 end);
40 42
41 for _, itemLocation in pairs(sourceItem.locations) do 43 for _, itemLocation in pairs(sourceItem.locations) do
42 -- if this location has more items than we need, only move what we need, otherwise move everything in this stack 44 -- if this location has more items than we need, only move what we need, otherwise move everything in this stack
43 local movingNum = ((itemLocation.count > singleMove.num and singleMove.num) or itemLocation.count); 45 local movingNum = ((itemLocation.count > singleMove.num and singleMove.num) or itemLocation.count);
44 46
45 table.insert(outgoingMoves, { 47 table.insert(outgoingMoves, {
46 itemId = singleMove.id, 48 itemId = singleMove.id,
49 num = movingNum,
47 container = itemLocation.container, 50 container = itemLocation.container,
48 slot = itemLocation.slot, 51 slot = itemLocation.slot,
49 count = movingNum,
50 }); 52 });
51 53
52 singleMove.num = (singleMove.num - movingNum); 54 singleMove.num = (singleMove.num - movingNum);
53 55
54 if singleMove.num == 0 then 56 if singleMove.num == 0 then
56 break; -- stop the locations-loop 58 break; -- stop the locations-loop
57 end 59 end
58 end 60 end
59 end 61 end
60 end 62 end
63
64 addon:Debug(#outgoingMoves .. " outgoing moves are possible.");
61 65
62 -- No longer needed 66 -- No longer needed
63 table.wipe(queuedMoves); 67 table.wipe(queuedMoves);
64 68
65 -- Process every single outgoing move and find fitting targets 69 -- Process every single outgoing move and find fitting targets
76 80
77 -- Go through all our bags, including the backpack 81 -- Go through all our bags, including the backpack
78 for bagId = start, stop do 82 for bagId = start, stop do
79 -- Go through all our slots 83 -- Go through all our slots
80 for slotId = 1, GetContainerNumSlots(bagId) do 84 for slotId = 1, GetContainerNumSlots(bagId) do
81 local itemId = GetContainerItemID(bagId, slotId); 85 local itemId = GetContainerItemID(bagId, slotId); -- we're scanning our local bags here, so no need to get messy with guild bank support
82 86
83 if not itemId then 87 if not itemId then
84 table.insert(emptySlots, { 88 table.insert(emptySlots, {
85 container = bagId, 89 container = bagId,
86 slot = slotId, 90 slot = slotId,
87 }); 91 });
88 end 92 end
89 end 93 end
90 end 94 end
95
96 addon:Debug(#emptySlots .. " empty slots are available.");
91 97
92 -- Remember where we're moving from 98 -- Remember where we're moving from
93 movesSource = location; 99 movesSource = location;
94 100
95 while #outgoingMoves ~= 0 do 101 while #outgoingMoves ~= 0 do
108 local firstAvailableSlot = emptySlots[1]; 114 local firstAvailableSlot = emptySlots[1];
109 115
110 if not firstAvailableSlot then 116 if not firstAvailableSlot then
111 print("Bags are full. Skipping " .. IdToItemLink(outgoingMove.itemId) .. "."); 117 print("Bags are full. Skipping " .. IdToItemLink(outgoingMove.itemId) .. ".");
112 118
113 outgoingMove.itemId = nil; 119 outgoingMove.itemId = nil; -- remove this record from the outgoingMoves-table
114 else 120 else
115 table.insert(combinedMoves, { 121 table.insert(combinedMoves, {
122 itemId = outgoingMove.itemId,
123 num = outgoingMove.num,
116 sourceContainer = outgoingMove.container, 124 sourceContainer = outgoingMove.container,
117 sourceSlot = outgoingMove.slot, 125 sourceSlot = outgoingMove.slot,
118 targetContainer = firstAvailableSlot.container, 126 targetContainer = firstAvailableSlot.container,
119 targetSlot = firstAvailableSlot.slot, 127 targetSlot = firstAvailableSlot.slot,
120 itemId = outgoingMove.itemId,
121 num = outgoingMove.count,
122 }); 128 });
123 129
124 -- We filled an empty slot so the target contents now has one more item, 130 -- We filled an empty slot so the target contents now has one more item,
125 -- make a new instance of the ItemMove class so any additional items with this id can be stacked on top of it 131 -- make a new instance of the ItemMove class so any additional items with this id can be stacked on top of it
126 local itemMove = addon.ContainerItem:New(); 132 local itemMove = addon.ContainerItem:New();
127 itemMove:AddLocation(firstAvailableSlot.container, firstAvailableSlot.slot, outgoingMove.count); 133 itemMove:AddLocation(firstAvailableSlot.container, firstAvailableSlot.slot, outgoingMove.num);
128 targetContents[outgoingMove.itemId] = itemMove; 134 targetContents[outgoingMove.itemId] = itemMove;
129 135
130 table.remove(emptySlots, 1); -- no longer empty 136 table.remove(emptySlots, 1); -- no longer empty
131 137
132 outgoingMove.count = 0; -- nothing remaining - sanity check 138 outgoingMove.num = 0; -- nothing remaining - sanity check
133 outgoingMove.itemId = nil; -- remove this record from the outgoingMoves-table 139 outgoingMove.itemId = nil; -- remove this record from the outgoingMoves-table
134 end 140 end
135 else 141 else
136 -- Find the maximum stack size for this item 142 -- Find the maximum stack size for this item
137 local itemStackCount = select(8, GetItemInfo(outgoingMove.itemId)); 143 local itemStackCount = select(8, GetItemInfo(outgoingMove.itemId));
140 table.sort(targetItem.locations, function(a, b) 146 table.sort(targetItem.locations, function(a, b)
141 return a.count > b.count; 147 return a.count > b.count;
142 end); 148 end);
143 149
144 for _, itemLocation in pairs(targetItem.locations) do 150 for _, itemLocation in pairs(targetItem.locations) do
145 if itemLocation.count < itemStackCount and outgoingMove.count > 0 then 151 if itemLocation.count < itemStackCount and outgoingMove.num > 0 then
146 -- Check if this stack isn't already full (and we still need to move this item) 152 -- Check if this stack isn't already full (and we still need to move this item)
147 153
148 local remainingSpace = (itemStackCount - itemLocation.count); 154 local remainingSpace = (itemStackCount - itemLocation.count);
149 if remainingSpace > outgoingMove.count then 155 if remainingSpace > outgoingMove.num then
150 -- Enough room to move this entire stack 156 -- Enough room to move this entire stack
151 -- Deposit this item and then forget this outgoing move as everything in it was processed 157 -- Deposit this item and then forget this outgoing move as everything in it was processed
152 158
153 table.insert(combinedMoves, { 159 table.insert(combinedMoves, {
160 itemId = outgoingMove.itemId,
161 num = outgoingMove.num,
154 sourceContainer = outgoingMove.container, 162 sourceContainer = outgoingMove.container,
155 sourceSlot = outgoingMove.slot, 163 sourceSlot = outgoingMove.slot,
156 targetContainer = itemLocation.container, 164 targetContainer = itemLocation.container,
157 targetSlot = itemLocation.slot, 165 targetSlot = itemLocation.slot,
158 itemId = outgoingMove.itemId,
159 num = outgoingMove.count,
160 }); 166 });
161 167
162 itemLocation.count = (itemLocation.count + outgoingMove.count); 168 itemLocation.count = (itemLocation.count + outgoingMove.num);
163 outgoingMove.count = 0; -- nothing remaining 169 outgoingMove.count = 0; -- nothing remaining
164 outgoingMove.itemId = nil; -- remove this record from the outgoingMoves-table 170 outgoingMove.itemId = nil; -- remove this record from the outgoingMoves-table
165 break; -- stop the locations-loop 171 break; -- stop the locations-loop
166 else 172 else
167 -- Deposit this item but don't remove the outgoing move as there are some items left to move 173 -- Deposit this item but don't remove the outgoing move as there are some items left to move
168 174
169 table.insert(combinedMoves, { 175 table.insert(combinedMoves, {
176 itemId = outgoingMove.itemId,
177 num = outgoingMove.num,
170 sourceContainer = outgoingMove.container, 178 sourceContainer = outgoingMove.container,
171 sourceSlot = outgoingMove.slot, 179 sourceSlot = outgoingMove.slot,
172 targetContainer = itemLocation.container, 180 targetContainer = itemLocation.container,
173 targetSlot = itemLocation.slot, 181 targetSlot = itemLocation.slot,
174 itemId = outgoingMove.itemId,
175 num = outgoingMove.count,
176 }); 182 });
177 183
178 -- The target will be full when we complete, but the source will still have remaining items left to be moved 184 -- The target will be full when we complete, but the source will still have remaining items left to be moved
179 itemLocation.count = itemStackCount; 185 itemLocation.count = itemStackCount;
180 outgoingMove.count = (outgoingMove.count - remainingSpace); 186 outgoingMove.num = (outgoingMove.num - remainingSpace);
181 end 187 end
182 end 188 end
183 end 189 end
184 190
185 if outgoingMove.count > 0 then 191 if outgoingMove.num > 0 then
186 -- We went through all matching items and checked their stack sizes if we could move this there, no room available 192 -- We went through all matching items and checked their stack sizes if we could move this there, no room available
187 -- 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 193 -- 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
188 targetItem = nil; 194 targetItem = nil;
189 end 195 end
190 end 196 end
204 210
205 -- Proceed with the next element (or previous considering we're going from last to first) 211 -- Proceed with the next element (or previous considering we're going from last to first)
206 numOutgoingMoves = (numOutgoingMoves - 1); 212 numOutgoingMoves = (numOutgoingMoves - 1);
207 end 213 end
208 end 214 end
215
216 addon:Debug(#combinedMoves .. " moves should be possible.");
209 217
210 -- No longer needed 218 -- No longer needed
211 table.wipe(emptySlots); 219 table.wipe(emptySlots);
212 220
213 self:ProcessMove(); 221 self:ProcessMove();
214 222
215 self:RegisterEvent("BAG_UPDATE"); 223 -- Even though we aren't completely done yet, allow requeueing
216
217 onFinish(); 224 onFinish();
218 end 225 end
219 226
220 if not table.reverse then 227 if not table.reverse then
221 -- table.reverse = function(orig) 228 -- table.reverse = function(orig)
249 self:Abort(); 256 self:Abort();
250 257
251 return; 258 return;
252 end 259 end
253 260
261 self:RegisterEvent("BAG_UPDATE");
254 self:RegisterEvent("UI_ERROR_MESSAGE"); 262 self:RegisterEvent("UI_ERROR_MESSAGE");
255 263
256 -- combinedMoves now has all moves in it (source -> target) 264 -- combinedMoves now has all moves in it (source -> target)
257 -- go through list, move everything inside it 265 -- go through list, move everything inside it
258 -- add source and target to lists, if either is already in this list, skip the move 266 -- add source and target to lists, if either is already in this list, skip the move
260 268
261 local sourceLocationsLocked = {}; 269 local sourceLocationsLocked = {};
262 local targetLocationsLocked = {}; 270 local targetLocationsLocked = {};
263 271
264 -- 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 272 -- 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
265 combinedMoves = table.reverse(combinedMoves); 273 combinedMoves = table.reverse(combinedMoves);
266 274
267 local numCurrentMove = #combinedMoves; 275 local GetContainerItemID;
276 if movesSource == addon.Locations.Guild then
277 GetContainerItemID = GetGuildBankItemLink;
278 else
279 GetContainerItemID = GetContainerItemID;
280 end
281
282 local combinedMovesOriginalLength = #combinedMoves;
283 local numCurrentMove = combinedMovesOriginalLength;
268 while numCurrentMove ~= 0 do 284 while numCurrentMove ~= 0 do
269 local move = combinedMoves[numCurrentMove]; 285 local move = combinedMoves[numCurrentMove];
270 286
271 -- sourceContainer, sourceSlot, targetContainer, targetSlot, itemId, num 287 -- sourceContainer, sourceSlot, targetContainer, targetSlot, itemId, num
272 if move and (not sourceLocationsLocked[move.sourceContainer] or not sourceLocationsLocked[move.sourceContainer][move.sourceSlot]) and 288 if move and (not sourceLocationsLocked[move.sourceContainer] or not sourceLocationsLocked[move.sourceContainer][move.sourceSlot]) and
276 292
277 addon:Debug(("Moving %dx%s from (%d,%d) to (%d,%d)"):format(move.num, IdToItemLink(move.itemId), move.sourceContainer, move.sourceSlot, move.targetContainer, move.targetSlot)); 293 addon:Debug(("Moving %dx%s from (%d,%d) to (%d,%d)"):format(move.num, IdToItemLink(move.itemId), move.sourceContainer, move.sourceSlot, move.targetContainer, move.targetSlot));
278 294
279 if GetContainerItemID(move.sourceContainer, move.sourceSlot) ~= move.itemId then 295 if GetContainerItemID(move.sourceContainer, move.sourceSlot) ~= move.itemId then
280 self:Abort("source changed", "Source (" .. move.sourceContainer .. "," .. move.sourceSlot .. ") is not " .. IdToItemLink(move.itemId)); 296 self:Abort("source changed", "Source (" .. move.sourceContainer .. "," .. move.sourceSlot .. ") is not " .. IdToItemLink(move.itemId));
281
282 return; 297 return;
283 end 298 end
284 299
285 -- Pickup stack 300 -- Pickup stack
286 if movesSource == addon.Locations.Bank then 301 if movesSource == addon.Locations.Bank then
299 if GetContainerItemID(move.targetContainer, move.targetSlot) and GetContainerItemID(move.targetContainer, move.targetSlot) ~= move.itemId then 314 if GetContainerItemID(move.targetContainer, move.targetSlot) and GetContainerItemID(move.targetContainer, move.targetSlot) ~= move.itemId then
300 self:Abort("target changed", "Target (" .. move.targetContainer .. "," .. move.targetSlot .. ") is not " .. IdToItemLink(move.itemId) .. " nor empty"); 315 self:Abort("target changed", "Target (" .. move.targetContainer .. "," .. move.targetSlot .. ") is not " .. IdToItemLink(move.itemId) .. " nor empty");
301 return; 316 return;
302 end 317 end
303 318
304 -- And drop it 319 -- And drop it (this is always a local bag so no need to do any guild-checks)
305 PickupContainerItem(move.targetContainer, move.targetSlot); 320 PickupContainerItem(move.targetContainer, move.targetSlot);
306 321
307 -- Remember we dropped an item here and thus this is now locked 322 -- Remember we dropped an item here and thus this is now locked
308 if not targetLocationsLocked[move.targetContainer] then 323 if not targetLocationsLocked[move.targetContainer] then
309 targetLocationsLocked[move.targetContainer] = {}; 324 targetLocationsLocked[move.targetContainer] = {};
320 335
321 -- Proceed with the next element (or previous considering we're going from last to first) 336 -- Proceed with the next element (or previous considering we're going from last to first)
322 numCurrentMove = (numCurrentMove - 1); 337 numCurrentMove = (numCurrentMove - 1);
323 end 338 end
324 339
340 addon:Debug((combinedMovesOriginalLength - #combinedMoves) .. " moves processed. " .. #combinedMoves .. " moves remaining.");
341
325 if #combinedMoves == 0 then 342 if #combinedMoves == 0 then
326 print("Finished."); 343 print("Finished.");
327 344
328 self:Abort(); 345 self:Abort();
329 346