annotate Modules/Mover.lua @ 98:252292b703ce

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