WoWInterface

WoWInterface (https://www.wowinterface.com/forums/index.php)
-   Lua/XML Help (https://www.wowinterface.com/forums/forumdisplay.php?f=16)
-   -   Unequip all items (https://www.wowinterface.com/forums/showthread.php?t=59132)

Walkerbo 05-24-22 10:01 PM

Unequip all items
 
Hi all

I am trying to unequip all items into any empty bag slot.

The problem is that I can unequip all items into my bags or into my backpack but not all into any empty slot in both.

This is the code I am trying to run;
Lua Code:
  1. for k, v in pairs(EquipmentSlots) do
  2.    PickupInventoryItem(v)
  3.    for bag = 0, 4 do
  4.       for slot = 0, GetContainerNumSlots(bag) do
  5.          local itemID = GetContainerItemID(bag, slot)
  6.          if not itemID then
  7.             PutItemInBag(slot)
  8.          end
  9.       end
  10.    end
  11.    if CursorHasItem() then
  12.     PutItemInBackpack()
  13.    end
  14. end

If I have enough bagspace the items move into the bags, but if I do not have enough space the leftover items do not drop into the backpack.

I have tried splitting it into 2 separate chunks runnig one after the other with the same results.

It is the backpack one that seems to break it, it will fill the backpack then say "not enough space" and then stop altogether.

Does anyone have any advice/help for me?

Cheers

Kanegasi 05-24-22 10:41 PM

PutItemInBag wants an InventorySlotId, not a slot in a bag. 20, 21, 22, and 23 are the bag slots. You should also break out of the inner loops once you put the item in a bag.

Lua Code:
  1. local ignore,foundspot={[0]={},[1]={},[2]={},[3]={},[4]={},}
  2. for k, v in pairs(EquipmentSlots) do
  3.    PickupInventoryItem(v)
  4.    foundspot = false
  5.    if CursorHasItem() then
  6.       for bag = 4, 0, -1 do
  7.          for slot = 1, GetContainerNumSlots(bag) do
  8.             if not ignore[bag][slot] and not GetContainerItemID(bag, slot) then
  9.                if bag == 0 then
  10.                   PutItemInBackpack()
  11.                else
  12.                   PutItemInBag(bag+19)
  13.                end
  14.                ignore[bag][slot] = true
  15.                foundspot = true
  16.                break
  17.             end
  18.          end
  19.          if foundspot then
  20.             break
  21.          end
  22.       end
  23.    end
  24. end


Edit: Fizzlemizz makes a good point. Based on your wording, it does look like you would rather fill other bags with the unequipped gear before your backpack. I reversed the bag loop so your backpack is searched last.

Edit2: Added CursorHasItem and an ignore table to keep track of spots filled by the code.

Fizzlemizz 05-24-22 11:25 PM

Bag 0 is the backpack so checking there first for empty slots is probably not what you're looking for.

Code:

for bag = 1, 4 do
Edit:
In a tight loop, the bag inventory doesn't update in time so you the get the "That bag is full" notification which can cause the process to break. Best to wait for the bag update event before processing the next item:
Lua Code:
  1. local LastBag, LastSlot, Remove
  2. local function SaveToBags()
  3.     while Remove do
  4.         PickupInventoryItem(Remove)
  5.         Remove = Remove+1
  6.         if Remove > INVSLOT_LAST_EQUIPPED then
  7.             Remove = nil
  8.             return
  9.         end
  10.         if CursorHasItem() then -- only process picked up items
  11.             local Placed
  12.             for bag = LastBag, 4 do -- bag 0 is the backpack
  13.                 local slots = GetContainerNumSlots(bag)
  14.                 for LastSlot = LastSlot, slots do
  15.                     local itemID = GetContainerItemID(bag, LastSlot)
  16.                     if not itemID then
  17.                         PutItemInBag(bag+19)
  18.                         Placed = true -- so scram
  19.                         break
  20.                     end
  21.                 end
  22.                 if bag > LastBag then
  23.                     LastBag = bag
  24.                     LastSlot = 1
  25.                 end
  26.                 if Placed then break end
  27.             end
  28.             if not Placed then -- no empty slots in bags
  29.                 local GotSpace
  30.                 for i=1, GetContainerNumSlots(0) do -- make sure the backpack isn't full as well
  31.                     if not GetContainerItemID(0, i) then
  32.                         GotSpace = true
  33.                         break
  34.                     end
  35.                 end
  36.                 if not GotSpace then  -- No more slots in backpack to put stuff either
  37.                     print("Not enough backpack space!")
  38.                     Remove = nil
  39.                     return
  40.                 end
  41.                 PutItemInBackpack()
  42.             end
  43.             break
  44.         end
  45.     end
  46. end
  47.  
  48. local f = CreateFrame("Frame")
  49. f:RegisterEvent("BAG_UPDATE")
  50. f:SetScript("OnEvent", function(self, event, ...)
  51.     if event == "BAG_UPDATE" then -- if you are using the handler for more than this event
  52.         if Remove then
  53.             SaveToBags()
  54.             return -- maybe, if you are doing other things with this event as well
  55.         end
  56. --  elseif event == "SOME_EVENT" then
  57.     end
  58. end)
  59.  
  60. SLASH_XXX1 = "/xx"
  61. SlashCmdList.XXX = function()
  62.     LastBag = 1
  63.     LastSlot = 1
  64.     Remove = INVSLOT_FIRST_EQUIPPED
  65.     SaveToBags()
  66. end

Edit: I didn't notice Kanegasi had made changes before doing this...

Walkerbo 05-26-22 02:14 AM

Hi Kanegasi and Fizzlemizz

Thanks for your answers.

Fizzlemizz, I can see the wait makes a lot of sense, it is something I should have picked up myself :(

I do have a couple of questions about your solutions.

You both used;
Lua Code:
  1. PutItemInBag(bag+19)
I dont understand where the 19 comes into it?

And Kanegasi you set up a table to record all placed items;
Lua Code:
  1. local ignore={[0]={},[1]={},[2]={},[3]={},[4]={},}
Is it necassary to record where items were placed, or is this just good practise?

Fizzlemizz 05-26-22 09:43 AM

Kanegasi mentioned that PutItemInBag requires a bag id. (InventorySlotId) not a bag number and these start at 20 (bag 1+19 = 20).

Using the table keeps track of where you put the last item instead of using the event method. Checking GetContainerItemID in a tight loop can return nil for a slot that has only just been filled in the previous loop(s) until the system catches up and sends the event which could cause a "Bag is full" message.

Kanegasi 05-26-22 01:40 PM

Fizzlemizz, I left this thread open on my phone's browser just after your post, so I didn't catch your edits either lol.

Anyways, to expand on InventorySlotId: https://wowpedia.fandom.com/wiki/InventorySlotId
And PutItemInBag: https://wowpedia.fandom.com/wiki/API_PutItemInBag

Basically, your character's entire "inventory" is actually your equipped items, your equipped bags (where items are saved elsewhere), your 28 base bank slots, and then your equipped bank bags. On retail, this counts all the way to 86. 0 is the old unused ammo slot, 1 is your head, 2 is your neck, 19 is your tabard, 20 is the first bag next to your backback, 21-23 is the next three. I'm honestly not sure what 24-51 is, then 52-79 is your base bank, and finally 80-86 is your bank bags.

Also, Fizzlemizz nailed the table explanation. It's a temporary table that starts off blank every time you use this code and is a quick solution to track slots where your unequipped items get dropped into. The slots may actually not line up depending on how you have new items enter your bags, but it still works in the end because the loop will find the, say for example, four empty slots and the table will treat those spots filled in the eyes of this loop when it dumps four of your pieces in.

Walkerbo 05-26-22 04:30 PM

Hi Kanegasi and Fizzlemizz

Thanks for the further explainations, I do really appreciate your help.

You two absolutely rock :banana:

Cheers

briskman3000 05-26-22 06:55 PM

Quote:

Originally Posted by Kanegasi (Post 340653)
I'm honestly not sure what 24-51 is

If I had to guess, they probably have something to do with the old Keyring system. It was dynamically sized with up to 32 slots.

IIRC when the added the 4 extra backpack slots for having an authenticator, they repurposed they keyring system for those slots. Counting up the number of slots in spots 24 - 51 gives you 28, which would be the 28 unassigned numbers you see there.

I'm completely pulling this out of my ass and my be completely wrong, but it all makes sense to me.

Walkerbo 02-09-23 06:12 PM

Hi all

I didn't want to create a new thread for this issue, instead, I have resurrected this post; (Yes, I am a necromancer).

Using Kanegasi's code did correctly remove all items and placed them in my bags/backpack;
Lua Code:
  1. local EquipmentSlots = {
  2.    AMMOSLOT = 0,
  3.    HEADSLOT = 1,
  4.    NECKSLOT = 2,
  5.    SHOULDERSLOT = 3,
  6.    SHIRTSLOT = 4,
  7.    CHESTSLOT = 5,
  8.    WAISTSLOT = 6,
  9.    LEGSSLOT = 7,
  10.    FEETSLOT = 8,
  11.    WRISTSLOT = 9,
  12.    HANDSSLOT = 10,
  13.    FINGER0SLOT = 11,
  14.    FINGER1SLOT = 12,
  15.    TRINKET0SLOT = 13,
  16.    TRINKET1SLOT = 14,
  17.    BACKSLOT = 15,
  18.    MAINHANDSLOT = 16,
  19.    SECONDHANDSLOT = 17,
  20.    RANGEDSLOT = 18,
  21.    TABARDSLOT = 19
  22. }
  23.  
  24. local ignore,foundspot={[0]={},[1]={},[2]={},[3]={},[4]={},}
  25. for k, v in pairs(EquipmentSlots) do
  26.    PickupInventoryItem(v)
  27.    foundspot = false
  28.    if CursorHasItem() then
  29.       for bag = 4, 0, -1 do
  30.          for slot = 1, C_Container.GetContainerNumSlots(bag) do
  31.             if not ignore[bag][slot] and not C_Container.GetContainerItemID(bag, slot) then
  32.                if bag == 0 then
  33.                   C_Container.PutItemInBackpack()
  34.                else
  35.                   C_Container.PutItemInBag(bag+19)
  36.                end
  37.                ignore[bag][slot] = true
  38.                foundspot = true
  39.                break
  40.             end
  41.          end
  42.          if foundspot then
  43.             break
  44.          end
  45.       end
  46.    end
  47. end

Since the launch of Wrath and Dragonflight 10.05 the code has stopped working, (even after adding the C_Container. where required), and it throws no errors at all.

The code still works in flawlessly Classic.

How do I get this running again?

SDPhantom 02-10-23 02:55 AM

I wrote my own script to do this a long time ago and decided to dust it off and make some improvements. It should work with Classic Era, Wrath Classic, and Dragon Flight.

Lua Code:
  1. local function UnequipAll()
  2.     local invslot,lastslot=EQUIPPED_FIRST or INVSLOT_FIRST_EQUIPPED,EQUIPPED_LAST or INVSLOT_LAST_EQUIPPED;
  3.  
  4.     ClearCursor();
  5.     for bag=NUM_BAG_SLOTS or NUM_TOTAL_EQUIPPED_BAG_SLOTS,0,-1 do
  6.         local free,type=(C_Container or _G).GetContainerNumFreeSlots(bag);
  7.         free=(type==0 and free or 0);
  8.  
  9.         for _=1,free do
  10.             PickupInventoryItem(invslot);
  11.             (bag==0 and PutItemInBackpack or PutItemInBag)((C_Container or _G).ContainerIDToInventoryID(bag));
  12.  
  13.             invslot=invslot+1;
  14.             if invslot>lastslot then return; end
  15.         end
  16.     end
  17. end

Walkerbo 02-10-23 05:28 PM

Hi SDPhantom

Thaks fopr your chunk, it absolutley works in Wrath and Retail.

I should have mentioned that I ended up using Kanegasi's chunk as I could skip items just by removing specific items from the EquipmentSlots table.

Is there a way to skip/ignore items using your code?

SDPhantom 02-11-23 11:58 AM

It can with a few tweaks. I added notes for educational purposes and fixed skipping free container slots if it encounters an empty inventory slot.

Lua Code:
  1. local InventorySlots={--    Comment or remove whichever slots you don't want to process, these enums exist in all clients
  2.     INVSLOT_AMMO;
  3.     INVSLOT_HEAD;
  4.     INVSLOT_NECK;
  5.     INVSLOT_SHOULDER;
  6.     INVSLOT_BODY;
  7.     INVSLOT_CHEST;
  8.     INVSLOT_WAIST;
  9.     INVSLOT_LEGS;
  10.     INVSLOT_FEET;
  11.     INVSLOT_WRIST;
  12.     INVSLOT_HAND;
  13.     INVSLOT_FINGER1;
  14.     INVSLOT_FINGER2;
  15.     INVSLOT_TRINKET1;
  16.     INVSLOT_TRINKET2;
  17.     INVSLOT_BACK;
  18.     INVSLOT_MAINHAND;
  19.     INVSLOT_OFFHAND;
  20.     INVSLOT_RANGED;
  21.     INVSLOT_TABARD;
  22. };
  23.  
  24. local function UnequipAll()
  25.     if #InventorySlots<=0 then return; end--    Sanity check
  26.     local slotindex=1;
  27.  
  28.     ClearCursor();--    Make sure the cursor isn't holding anything, otherwise we might accidentally issue an item swap instead of an unequip
  29.     for bag=NUM_BAG_SLOTS or NUM_TOTAL_EQUIPPED_BAG_SLOTS,0,-1 do-- CE and Wrath use NUM_BAG_SLOTS, DF uses NUM_TOTAL_EQUIPPED_BAG_SLOTS
  30.         local free,type=(C_Container or _G).GetContainerNumFreeSlots(bag);--    C_Container is used in Wrath and DF, CE still has this in _G
  31.         free=(type==0 and free or 0);-- Uses a quirk with this style of condition, only process bags with no item type restriction with fallback to zero if no bag is there (if free is nil, it'll fallback to zero even if the condition is true)
  32.  
  33.         for _=1,free do--   Variable is unused, we just need to loop for every free slot we see
  34.             local invslot=InventorySlots[slotindex];--  Cache slot mapped to current index
  35.             while not GetInventoryItemID("player",invslot) do-- Loop if no item in slot and until we find one
  36.                 if slotindex<#InventorySlots then slotindex=slotindex+1; else return; end-- Increment to next index or stop when we have no more inventory slots to process
  37.                 invslot=InventorySlots[slotindex];--    Update to new slot
  38.             end
  39.  
  40. --          This pair is a complete operation, cursor is expected to be clear by the time both of these lines have run
  41.             PickupInventoryItem(invslot);
  42.             (bag==0 and PutItemInBackpack or PutItemInBag)((C_Container or _G).ContainerIDToInventoryID(bag));--    First set of parenthesis chooses function to run before calling it, PutItemInBackpack() doesn't accept any args, so ContainerIDToInventoryID() is safe to run regardless
  43.  
  44.             if slotindex<#InventorySlots then slotindex=slotindex+1; else return; end-- Increment to next index or stop when we have no more inventory slots to process
  45.         end
  46.     end
  47. end

Walkerbo 02-11-23 04:30 PM

Hi SDPhantom

Thanks for your code, it works as intended; and the comments are very much appreciated as I am still learning and the comments really help me.

I do have a question regarding line 41.

I thought in lua there was no requirement to end a line with ; yet if I remove the line close the function breaks.

Why does this happen?

SDPhantom 02-11-23 08:23 PM

Lua can have ambiguity errors where the compiler gets confused about what part of a line is supposed to do. Since the next line starts with a set of parenthesis, the compiler wouldn't know if it's a set of parameters for a function call continuing from the previous line or a new expression. Remember, Lua is whitespace agnostic and whitespace is allowed between a function reference and the argument list. Newlines don't explicitly define new statements, that's the semicolon's job.

Most times, the compiler is smart and can determine this on its own, but there are a few edge cases where this can happen. In this case, we want it to be recognized as an expression because it fetches the function we want for the next set of parenthesis to call.



Lua 5.1 Reference Manual §2.5.8
Quote:

As an exception to the free-format syntax of Lua, you cannot put a line break before the '(' in a function call. This restriction avoids some ambiguities in the language. If you write
Code:

a = f
(g).x(a)

Lua would see that as a single statement, a = f(g).x(a). So, if you want two statements, you must add a semi-colon between them. If you actually want to call f, you must remove the line break before (g).

Walkerbo 02-11-23 10:08 PM

Hi SDPhantom

Thanks for your explanation, it is really appreciated.:)


All times are GMT -6. The time now is 07:47 AM.

vBulletin © 2024, Jelsoft Enterprises Ltd
© 2004 - 2022 MMOUI