Page 1 of 6

CSORT - Sort items inside bags

Posted: Fri May 20, 2005 10:31 pm
by Agripa
Also see Furiousness' excellent sort routine here:

http://www.macroquest2.com/phpBB2/viewt ... light=sort

I started this one before I noticed his.

Code: Select all

|* CSORT.MAC - http://www.macroquest2.com/phpBB2/viewtopic.php?t=11404
|*
|* 1.11 - 20060324 Agripa
|*      - Changed BigBankWnd to BankWnd. *shakes fist at SOE*
|*      - Tested as working now on pre-PoR EQ.
|* 1.10 - 20060315 Agripa
|*      - Added PoR bank slots.  Set csort_PoR to TRUE to use them. 
|* 1.00 - 20050712 Agripa
|*      - Removed all ${String[]} functions.
|* 0.40 - 20050522 Agripa
|*      - Added the option Dual.
|* 0.31 - 20050521 Agripa
|*      - Added the option Stack.
|*      - Spell and Stack now handle single digit cases correctly by prefixing them with a 0.
|* 0.20 - 20050521 Agripa
|*      - Added the options Begin, Close, End, Reverse, and Spell.
|*      - An open inventory window is no longer required to sort packs.
|* 0.10 - 20050520 Agripa
|*
|* /mac csort [<start> <end>] [<options>]
|* /call csort [<start> <end>] [<options>]
|*
|* <options> include:
|*
|*    Begin   - Move empty slots to the beginning.
|*    Close   - Close bags after sorting is done.
|*    Dual    - Sort left and right slots as seperate arrays.
|*    End     - Move empty slots to the end.
|*    Reverse - Sort in reverse order.
|*    Spell   - Sort spells by level first and name second.
|*    Stack   - Sort by quantity first and name second.
|*
|* Note that the options Begin and End are exclusive and cause odd
|* behavior when used together.  I could check for this but maybe someone
|* will find a use.
|*
|* Valid start and end addresses are bank1 to bank16 (2000 to 2015), pack1
|* to pack8 (22 to 29), or sharedbank1 to sharedbank2 (2500 to 2501).  If
|* no addresses are given, then the entire bank is sorted if the bank
|* window is open or the entire inventory is sorted if the inventory window
|* is open.  Slots without bags are ignored.  Items not in bags are ignored.
|*
|* The bank window must already be open before sorting the bank or sharebank.
|*
|* Installation:
|*
|*    Save as CSORT.MAC with the first Sub named main.
|*
|*       or
|*
|*    Save as CSORT.INC with the first Sub named CSORT and use #include CSORT.INC
|*
|* PoR:
|*
|*    Either set csort_PoR to TRUE in line 95 or use the following before calling csort:
|*
|*       /declare csort_PoR bool outer TRUE
|*
|* Examples:
|*
|* /mac csort              
|*    Sort the contents of the bank or inventory as seperate sets of continuous items.
|* /mac csort end
|*    Sort the contents of the bank or inventory and place empty slots at the end.
|* /mac csort pack2 pack4 beginreverse
|*    Reverse sort the contents of inventory packs 2 through 4 and place blank spots at beginning.

|* Sub csort(string pStart, string pEnd, string pOptions)
Sub main(string pStart, string pEnd, string pOptions)

   /declare iStart int local
   /declare iEnd   int local

|* /declare aStart int local ${InvSlot[${pStart}]}
|* /declare aEnd   int local ${InvSlot[${pEnd}]}

   /declare bStart int local
   /declare bEnd   int local

   /declare I   int local
   /declare J   int local
   /declare K   int local
   /declare K1  int local
   /declare K2  int local

   /declare L bool local
   /declare M bool local
   /declare N bool local

   /if ( !${Defined[csort_index]} ) {
      /declare csort_index[240] int outer
   }

|*
|* Set the following to TRUE if using PoR
|*

   /if ( !${Defined[csort_PoR]} ) /declare csort_PoR bool outer FALSE

   /if ( !${Defined[csort_bank_max]} ) /declare csort_bank_max int outer

   /if ( ${csort_PoR} ) {
      /varset csort_bank_max 2023
   } else {
      /varset csort_bank_max 2015
   }

|* ${FindItem[${spellName}].InvSlot.ID}
|*
|* item FindItem[ [=]name]
|*
|* int    Container Number of slots, if this is a container 
|* int    Items Number of items, if this is a container 
|* item   Item[n] nth contained item, if this is a container 
|*
|* invslot InvSlot[name]
|*
|* int ID         Number of this item slot (usable directly by /itemnotify) 
|* item Item      Item contained by this item slot 
|* invslot Pack   Container that must be opened to access the slot with /itemnotify 
|* int Slot       Slot number inside the pack which holds the item 
|* string Name    For inventory slots not inside packs, the slot name 
|* To String      Same as ID 
|*
|* .Item
|*
|* int Container Number of slots, if this is a container 
|*
|* bank1  2000 2031-2040   pack1 22 251-260   sharedbank1 2500 2531-2540
|* bank2  2001 2041-2050   pack2 23 261-270   sharedbank2 2501 2541-2550
|* bank3  2002 2051-2060   pack3 24 271-280
|* bank4  2003 2061-2070   pack4 25 281-290
|* bank5  2004 2071-2080   pack5 26 291-300
|* bank6  2005 2081-2090   pack6 27 301-310
|* bank7  2006 2091-2100   pack7 28 311-320
|* bank8  2007 2101-2110   pack8 29 321-330
|* bank9  2008 2111-2120
|* bank10 2009 2121-2130
|* bank11 2010 2131-2140
|* bank12 2011 2141-2150
|* bank13 2012 2151-2160
|* bank14 2013 2161-2170
|* bank15 2014 2171-2180
|* bank16 2015 2181-2190

|* New PoR Bank Slots?     2016-2023 and 2191-2260 

|* bank17 2016 2191-2200
|* bank18 2017 2201-2210
|* bank19 2018 2211-2220
|* bank20 2019 2221-2230
|* bank21 2020 2231-2240
|* bank22 2021 2241-2250
|* bank23 2022 2251-2260
|* bank24 2023 2261-2270

   /if ( ${Macro.Params}==1 ) {
      /declare pOptions string local ${pStart}
      /deletevar pStart
   }

   /echo CSORT: (${pStart},${pEnd},${pOptions})

   /if ( !${Defined[pStart]} || !${Defined[pEnd]} ) {
      /if ( !${Defined[pStart]} ) /declare pStart string local
      /if ( !${Defined[pEnd]}   ) /declare pEnd   string local
      /if ( ${Window[BankWnd].Open} ) {
         /if ( ${csort_PoR} ) {
            /varset pStart bank1
            /varset pEnd   bank24
         } else {
            /varset pStart bank1
            /varset pEnd   bank16
         }
      } else /if ( ${Window[InventoryWindow].Open} ) {
         /varset pStart pack1
         /varset pEnd   pack8
      }
   }

   /declare aStart int local ${InvSlot[${pStart}]}
   /declare aEnd   int local ${InvSlot[${pEnd}]}

   /varset L TRUE
   /if ( ${aStart}>=22 && ${aStart}<=29 && ${aEnd}>=22 && ${aEnd}<=29 && ${aStart}<=${aEnd} ) {
      /varset L FALSE
   }
   /if ( ${aStart}>=2000 && ${aStart}<=${csort_bank_max} && ${aEnd}>=2000 && ${aEnd}<=${csort_bank_max} && ${aStart}<=${aEnd} && ${Window[BankWnd].Open} ) {
      /varset L FALSE
   }
   /if ( ${aStart}>=2500 && ${aStart}<=2501 && ${aEnd}>=2500 && ${aEnd}<=2501 && ${aStart}<=${aEnd} && ${Window[BankWnd].Open} ) {
      /varset L FALSE
   }
   /if ( ${L} ) {
      /echo CSORT: Parameter Error (${pStart},${pEnd},${pOptions}) ${aStart} to ${aEnd}
      /return
   }

   /echo CSORT: (${pStart},${pEnd}) ${aStart} ${aEnd}
   
   /varset J 1

   /for I ${aStart} to ${aEnd}

      /call CSORT_BagSlot_Start ${I}
      /varset K1 ${Macro.Return}
      /call CSORT_BagSlot_End   ${I}
      /varset K2 ${Macro.Return}

|     /echo CSORT: ${I} ${InvSlot[${I}].Item} ${InvSlot[${I}].Item.Container} ${K1} ${K2}

      /if ( ${InvSlot[${I}].Item.Container}>0 ) {
         /for K ${K1} to ${K2}
            /varcalc csort_index[${J}] ${K}
            /varcalc J ${J}+1
         /next K
      }

   /next I

   /varcalc iStart 1
   /varcalc iEnd   ${J}-1

|  /echo CSORT: ${iStart} ${iEnd}

|  /for I ${iStart} to ${iEnd}
|     /echo CSORT: ${I} ${csort_index[${I}]}
|  /next I
   
   /varset I ${iStart}

   :findstart

   |* 
   |* Open pack if it is not already open and wait for slot to fill.
   |*

   /if ( ${InvSlot[${csort_index[${I}]}].Pack} && !${Window[${InvSlot[${csort_index[${I}]}].Pack.Name}].Open} ) {
      /nomodkey /itemnotify ${InvSlot[${csort_index[${I}]}].Pack} rightmouseup
      /delay 1s ${Window[${InvSlot[${csort_index[${I}]}].Pack.Name}].Open}
      /delay 1s ${InvSlot[${csort_index[${I}]}].Item.ID}
   }

   |* 
   |* Look for the beginning of an array.
   |*

   /if ( ${InvSlot[${csort_index[${I}]}].Item.ID} || ${pOptions.Find[Begin]} || ${pOptions.Find[End]} ) {
      /varcalc bStart ${I}
   } else {
      /varcalc I ${I} + 1
      /if ( ${I}<${iEnd} ) {
         /goto :findstart
      } else {
         /return
      }
   }

   :findend

   |* 
   |* Open pack if it is not already open and wait for slot to fill.
   |*

   /if ( ${InvSlot[${csort_index[${I}]}].Pack} && !${Window[${InvSlot[${csort_index[${I}]}].Pack.Name}].Open} ) {
      /nomodkey /itemnotify ${InvSlot[${csort_index[${I}]}].Pack} rightmouseup
      /delay 1s ${Window[${InvSlot[${csort_index[${I}]}].Pack.Name}].Open}
      /delay 1s ${InvSlot[${csort_index[${I}]}].Item.ID}
   }

   |* 
   |* Look for the end of an array.
   |*

   /if ( ( !${InvSlot[${csort_index[${I}]}].Item.ID} && !( ${pOptions.Find[Begin]} || ${pOptions.Find[End]} ) ) || ${I}>${iEnd}) {
      /varcalc bEnd   ${I} - 1
   } else {
      /varcalc I ${I} + 1
      /goto :findend
   }

   |* 
   |* Sort the current array and if we are not done go look for another one.
   |*

   /echo CSORT: ${InvSlot[${csort_index[${bStart}]}].Item.Name}(${bStart}index) to ${InvSlot[${csort_index[${bEnd}]}].Item.Name}(${bEnd}index) ${pOptions}

   /call CSORT_Array ${bStart} ${bEnd} ${pOptions}
   
   /varcalc I ${bEnd} + 1

   /if ( ${I}<${iEnd} ) {
      /goto :findstart
   }

   |*
   |* Close all containers if needed.
   |*

   /if ( ${pOptions.Find[Close]} ) {
      /for I ${iStart} to ${iEnd}
         /if ( ${InvSlot[${csort_index[${I}]}].Pack} && ${Window[${InvSlot[${csort_index[${I}]}].Pack.Name}].Open} ) {
            /nomodkey /itemnotify ${InvSlot[${csort_index[${I}]}].Pack} rightmouseup
            /delay 1s !${Window[${InvSlot[${csort_index[${I}]}].Pack.Name}].Open}
         }
      /next I
   }

/return

|*
|* Combsort an array of indexed items.
|*

Sub CSORT_Array(int start, int end, string pOptions)

   /declare I   int local
   /declare I1  int local
   /declare I2  int local
   /declare J   int local
   /declare K   int local

   /declare L  bool local
   /declare L1 bool local
   /declare L2 bool local
   /declare M  bool local
   /declare N  bool local

   /declare gap   int local
   /declare gap_i int local
   /declare swapped bool local

   /declare I_ID     int    local
   /declare J_ID     int    local
   /declare I_Forage string local
   /declare J_Forage string local
   /declare I_Name   string local
   /declare J_Name   string local

   /varcalc gap_i ${end}-${start}

   /if ( ${pOptions.Find[Dual]} ) {
      /varcalc gap_i ${gap_i}/2
   }

   /if ( ${gap_i}<1 ) {
      /return
   }

   /echo CSORT_Array: ${InvSlot[${csort_index[${start}]}].Item.Name}(${start}index) to ${InvSlot[${csort_index[${end}]}].Item.Name}(${end}index) ${pOptions}

   :resort

   /varset swapped FALSE

   |* 1/e   (e-1)/e
   /varcalc gap_i (${gap_i}*10)/13
   /if ( ${gap_i}==9 || ${gap_i}==10 ) {
      /varcalc gap_i 11
   }

   /if ( ${pOptions.Find[Dual]} ) {
      /varcalc gap ${gap_i}*2
   } else {
      /varcalc gap ${gap_i}
   }

   /echo CSORT_Array: Gap = ${gap}   gap_i = ${gap_i}

   /for I ${start} to ${Math.Calc[${end}-${gap}]}

      /varcalc J ${I} + ${gap}

      /varset I_ID ${InvSlot[${csort_index[${I}]}].Item.ID}
      /if ( ${InvSlot[${csort_index[${I}]}].Item.Type.Equal[Scroll]} && ${pOptions.Find[Spell]} )  {
         /varset I_Name ${InvSlot[${csort_index[${I}]}].Item.Spell.Level}
         /if ( ${I_Name.Length}==1 ) /varset I_Name 0${I_Name}
      } else /if ( ${pOptions.Find[Stack]} ) {
         /varset I_Name ${InvSlot[${csort_index[${I}]}].Item.Stack}
         /if ( ${I_Name.Length}==1 ) /varset I_Name 0${I_Name}
      } else {
         /varset I_Name
      }
      /varset I_Name ${I_Name}${InvSlot[${csort_index[${I}]}].Item.Name}

      /varset J_ID ${InvSlot[${csort_index[${J}]}].Item.ID}
      /if ( ${InvSlot[${csort_index[${J}]}].Item.Type.Equal[Scroll]} && ${pOptions.Find[Spell]} )  {
         /varset J_Name ${InvSlot[${csort_index[${J}]}].Item.Spell.Level}
         /if ( ${J_Name.Length}==1 ) /varset J_Name 0${J_Name}
      } else /if ( ${pOptions.Find[Stack]} ) {
         /varset J_Name ${InvSlot[${csort_index[${J}]}].Item.Stack}
         /if ( ${J_Name.Length}==1 ) /varset J_Name 0${J_Name}
      } else {
         /varset J_Name
      }
      /varset J_Name ${J_Name}${InvSlot[${csort_index[${J}]}].Item.Name}

      /varcalc L ${I_ID} && ${J_ID} && ${I_Name.Compare[${J_Name}]}==${If[${pOptions.Find[Reverse]},-1,1]}
      /varcalc M ( ${pOptions.Find[Begin]} && ${I_ID} && !${J_ID} ) || ( ${pOptions.Find[End]} && !${I_ID} && ${J_ID} )

      /if ( ${L} || ${M} ) {
|        /echo CSORT_Array: Exchange ${I_Name}(${I_ID}id)(${csort_index[${I}]}slot) with ${J_Name}(${J_ID}id)(${csort_index[${J}]}slot)
         /varset swapped TRUE

         /if ( ${I_ID} ) {
            /nomodkey /shiftkey /itemnotify ${csort_index[${I}]} leftmouseup
            /delay 1s (  ${Cursor.ID}==${I_ID} )
         }

         /if ( ${I_ID} || ${J_ID} ) {
            /nomodkey /shiftkey /itemnotify ${csort_index[${J}]} leftmouseup
            /delay 1s (  ${Cursor.ID}==${J_ID} && ${InvSlot[${csort_index[${J}]}].Item.ID}==${I_ID} )
         }

         /if ( ${J_ID} ) {
            /nomodkey /shiftkey /itemnotify ${csort_index[${I}]} leftmouseup
            /delay 1s ( ${InvSlot[${csort_index[${I}]}].Item.ID}==${J_ID} )
         }

         /if ( ${Cursor.ID} ) {
            /echo CSORT_Array: Error: ${Cursor.Name}
         }
      }
   
   /next I

   /if ( ${gap_i}>1 || ${swapped} ) /goto :resort

/return

|*
|* Return respectively the first or last address inside a container when 
|* when given a bank, sharedbank, or pack address.  If the item is not a container, 
|* then the original address is returned.
|*

Sub CSORT_BagSlot_Start(int bagslot)

   /declare I int local 0

   /if ( ${bagslot}>=22 && ${bagslot}<=29 ) {
      /if ( ${InvSlot[${bagslot}].Item.Container}>0 ) {
         /varcalc I ${bagslot}*10+31
      } else {
         /varcalc I ${bagslot}
      }
      /return ${I}
   }      
   /if ( ${bagslot}>=2000 && ${bagslot}<=${csort_bank_max} ) {
      /if ( ${InvSlot[${bagslot}].Item.Container}>0 ) {
         /varcalc I ${bagslot}*10-17969
      } else {
         /varcalc I ${bagslot}
      }
      /return ${I}
   }
   /if ( ${bagslot}>=2500 && ${bagslot}<=2501 ) {
      /if ( ${InvSlot[${bagslot}].Item.Container}>0 ) {
         /varcalc I ${bagslot}*10-22469
      } else {
         /varcalc I ${bagslot}
      }
   }

/return ${I}
                                           
Sub CSORT_BagSlot_End(int bagslot)

   /declare I int local 0

   /if ( ${bagslot}>=22 && ${bagslot}<=29 ) {
      /if ( ${InvSlot[${bagslot}].Item.Container}>0 ) {
         /varcalc I ${bagslot}*10+31+(${InvSlot[${bagslot}].Item.Container}-1)
      } else {
         /varcalc I ${bagslot}
      }
      /return ${I}
   }      
   /if ( ${bagslot}>=2000 && ${bagslot}<=${csort_bank_max} ) {
      /if ( ${InvSlot[${bagslot}].Item.Container}>0 ) {
         /varcalc I ${bagslot}*10-17969+(${InvSlot[${bagslot}].Item.Container}-1)
      } else {
         /varcalc I ${bagslot}
      }
      /return ${I}
   }
   /if ( ${bagslot}>=2500 && ${bagslot}<=2501 ) {
      /if ( ${InvSlot[${bagslot}].Item.Container}>0 ) {
         /varcalc I ${bagslot}*10-22469+(${InvSlot[${bagslot}].Item.Container}-1)
      } else {
         /varcalc I ${bagslot}
      }
   }

/return ${I}

Posted: Tue Jul 12, 2005 1:11 pm
by AEbard
any update to this for the new string issue?

Posted: Tue Jul 12, 2005 1:34 pm
by skyler
many places. open up that search function and have at it

Posted: Wed Mar 08, 2006 4:02 pm
by Agripa
If someone could verify the new bank slot IDs in PoR for me I can update this to handle them.

Code: Select all

|* bank1  2000 2031-2040 
|* bank2  2001 2041-2050   
|* bank3  2002 2051-2060   
|* bank4  2003 2061-2070   
|* bank5  2004 2071-2080   
|* bank6  2005 2081-2090   
|* bank7  2006 2091-2100   
|* bank8  2007 2101-2110   
|* bank9  2008 2111-2120
|* bank10 2009 2121-2130
|* bank11 2010 2131-2140
|* bank12 2011 2141-2150
|* bank13 2012 2151-2160
|* bank14 2013 2161-2170
|* bank15 2014 2171-2180
|* bank16 2015 2181-2190
|* ?
|* ?

Posted: Thu Mar 09, 2006 12:15 pm
by Hydryad
new bank slots are 2016-2023 and 2191-2260 (the first part I am pretty sure and the second part I don't know how to check.) I will test it out for you to see if those work. Would appriciate someone double-checking that second part. (And pointing me to where this is in the manual/wiki so I can figure it out myself preferably!)

Posted: Sun Mar 12, 2006 8:30 pm
by dewey2461
Any luck getting this to work? I'd love to be able to sort my traders cra^H^H^H valuable inventory.

Posted: Tue Mar 14, 2006 1:00 am
by notadruid
What, no recursive Quick Sort algorithm?

Posted: Tue Mar 14, 2006 1:10 am
by Hydryad
No luck getting it working here, I suck at making macros so far but the meaningless variable names for some of it compounds things. Great fun watching the macro go but damn if I understand it.

Posted: Tue Mar 14, 2006 8:21 am
by AEbard
Hydryad wrote:new bank slots are 2016-2023 and 2191-2260 (the first part I am pretty sure and the second part I don't know how to check.) I will test it out for you to see if those work. Would appriciate someone double-checking that second part. (And pointing me to where this is in the manual/wiki so I can figure it out myself preferably!)
Assuming this is true, look at the following code where you see 2015 and change it to 2023.

Posted: Tue Mar 14, 2006 11:15 am
by Hydryad
I had already tried that, didn't work. I had fiddled with the macro for a bit trying to fix it but no luck.

Posted: Wed Mar 15, 2006 2:20 am
by Agripa
I used a comb sort because it is more predictable and it is easy to prevent pathological sort times. I am going over the changes now but I need to figure out how to detect if a player has PoR or not. If I do not find a way, I will add a user settable bool.

It has been a while since I have had to make any major changes in the code. My MQ2 style has improved but this was the first thing I posted for general use and as has been observed, it is not pretty.

The code first creates an indexing array of ONLY the slots inside the bags. This array is used as an index during the actual sort because if a bag is missing in a specified range or the bag holds fewer then 10 items, the actually inventory slot list will be discontinuous.

Posted: Fri Mar 24, 2006 12:18 pm
by Bigguy70
not working :cry:
do /mac csort get following output in MQ2 window
[MQ2] CSORT:(bank1,bank24,end)
[MQ2] CSORT:Parameter Error (bank1,bank24,end) 20000 to 0
The current macro has ended.
No actions are performed on bank inventory only effect macro is having is displaying the output above.

Posted: Fri Mar 24, 2006 2:25 pm
by Agripa
I am going over this today.

Looks like BigBankWnd was replaced with BankWnd.

I tested it on pre-PoR but someone else will have to verify it works with PoR installed.

Posted: Fri Mar 24, 2006 6:53 pm
by Hydryad
When I try "/mac csort bank1 bank16" it does not work, but it says Parameter error (bank1,bank16,NULL) 2000 to 2015. However when I try "/mac csort bank1 bank24" I get Parameter error (bank1,bank24,NULL) 2000 to 0. So I don't really know what that means but that is what I get.

I set "/if ( !${Defined[csort_PoR]} ) /declare csort_PoR bool outer FALSE" to TRUE before testing this. Hopefully that helped heh.

Posted: Fri Mar 24, 2006 7:07 pm
by Agripa
That looks like the problem I fixed today when I posted version 1.11. BigBankWnd got changed to BankWnd. What version was that on?