If you ever felt inclined to make a post detailing your experience making something that generated .ini files I would certainly read it. When I was making macros for emu servers more regularly I was very interested in the user friendliness of ini files being generated for a macro. Simply open the ini and make the edits in clearly defined areas, instead of sifting through good/bad macro and making changes all over the place and hoping you didn't goof a change somewhere you'll never find again.
Most servers I play on now are RoF supported, and KA or CWTN plugins do most of the brunt work. I would still like to continue learning from people more skilled than I.
I can break down my build function for you:
/if (!${Window[InventoryWindow].Open}) {
/windowstate InventoryWindow open
}
/echo Grabbing our containers...
/delay 10
/for slot 23 to 30
/varset itemName ${Me.Inventory[${slot}].Name}
/if (${InvSlot[${slot}].Item.Container}) {
/varset containers[${slot}] ${itemName}
/echo ${containers[${slot}]}
} else {
/echo ${itemName} is not a container, skipping...
}
/next slot
/windowstate InventoryWindow close
/ini AutoVendor.ini "Instructions" "Instructions" "Set items on the list to either Sell or Ignore."
/varset slot -1
/if (!${Window[FindItemWnd].Open}) {
/windowstate FindItemWnd open
}
The beginning of the function is just a for loop that iterates over inventory slot 23-30 (as those are your primary inventory slots you'd put bags and such in) to grab our containers since we don't want our vendor attempting to sell our bags, we can skip past that.
/echo Grabbing our items...
/delay 10
/for slot 0 to ${totalSlots}
/if (${Window[FindItemWnd].Child[FIW_ItemList].List[${slot},4].Compare[General]} == 32) {
/nomodkey /notify FindItemWnd FIW_ItemList listselect ${slot}
/varset itemName ${Window[FindItemWnd].Child[FIW_ItemList].List[${slot},2]}
/if (!${Ini[AutoVendor.ini,"Items",${itemName}].Length}) {
/if (${FindItem[${itemName}].Value} <= 0) {
/echo ${itemName} has no value, skipping...
/next slot
}
/if (${containers[23].Equal[${itemName}]} || ${containers[24].Equal[${itemName}]} || ${containers[25].Equal[${itemName}]} || ${containers[26].Equal[${itemName}]} || ${containers[27].Equal[${itemName}]} || ${containers[28].Equal[${itemName}]} || ${containers[29].Equal[${itemName}]} || ${containers[30].Equal[${itemName}]}) {
/echo ${itemName} is a container and we don't want to sell our bags, skipping...
/next slot
}
/if (${FindItem[${itemName}].NoDrop}) {
/echo ${itemName} is not vendorable, skipping...
/next slot
}
/echo Creating entry for ${itemName}.
/ini AutoVendor.ini "Items" "${itemName}" "Sell"
}
}
/next slot
/windowstate FindItemWnd close
/ini AutoVendor.ini "TotalItems" "TotalItems" ${totalSlots}
This is the real meat of the builder, so what this does is it iterates over your find item window using a for loop that is limited by the second parameter (total # of items). The first if statement is checking if the item is within the "General" section, as those are the items within our personal inventory, if it is we take the item name and set it to our designated string. The second if checks it against value, if it has no value then it skips to the next iteration in the loop, the third if checks for if it is one of our containers and if it is it skips that item and the fourth if checks if the item is no trade/no drop and if it is it skips as well. If the item passes all of these checks, it calls the function for building our INI on said item: /ini AutoVendor.ini "Items" "${itemName}" "Sell" this function essentially checks if AutoVendor.ini exists, if not it creates the file then the first variable passed in to the constructor is the category, second variable is the sub so the item itself and the third variable is the status of that item (Sell or Ignore). One we've iterated our total amount of times, we write our second parameter, total # of items, to the ini file that way it can be called upon once we restart our macro.
So what calls this is our initial functionality in our main:
/if (${Defined[Param0]}) {
/if (${Defined[Param1]}) {
/varset totalSlots ${Param1}
/if (${Param0.Equal[buildini]}) {
/echo Building our INI...
/call BuildINI
/echo Finished creating INI, please edit the INI file accordingly then restart your macro without any parameters.
/echo ex. /mac AutoVendor
/endmac
} else {
/echo You have declared your parameters incorrectly.
/echo Try again but do it like this: /mac autovendor buildini #ofitemshere
/echo You can find the number of items in the bottom right of your find item window.
/endmac
}
} else {
/echo You need to declare how many items you have total.
/echo Try again but do it like this: /mac autovendor buildini #ofitemshere
/echo You can find the number of items in the bottom right of your find item window.
/endmac
}
}
The first if checks if there is a parameter entered, this is the buildini part of /mac autovendor buildini #, if that gets a hit we set our totalSlots (total # of items variable) to the second parameter then we do a syntax check to make sure everything was entered correctly, if it was we call our BuildINI function and end the macro after running. You can then edit the ini then restart the macro WITHOUT any parameters (ex. /mac autovendor) and it will run the main functionality which is this:
/varset totalSlots ${Ini[AutoVendor.ini,"TotalItems",TotalItems]}
/call FindVendor
/delay 20
/if (!${Window[FindItemWnd].Open}) {
/windowstate FindItemWnd open
}
/for looper 0 to ${totalSlots}
/if (${Window[FindItemWnd].Child[FIW_ItemList].List[${looper},4].Compare[General]} == 32) {
/for looperTwo 0 to ${totalSlots}
/nomodkey /notify FindItemWnd FIW_ItemList listselect ${looper}
/varset itemName ${Window[FindItemWnd].Child[FIW_ItemList].List[${looper},2]}
/varset itemQuantity ${Window[FindItemWnd].Child[FIW_ItemList].List[${looper},3]}
/varset itemValue ${Int[${Math.Calc[${FindItem[=${itemName}].Value}/1000]}]}
/if (${Ini[AutoVendor.ini,"Items",${itemName}].Equal[Sell]}) {
/delay 10
/nomodkey /notify MerchantWnd MW_Sell_Button leftmouseup
/delay 20
/if (${Window[QuantityWnd].Open}) {
/nomodkey /notify QuantityWnd QTYW_Accept_Button leftmouseup
/delay 20
}
/varcalc saleTotal ${itemQuantity}*${itemValue}
/echo We sold ${itemQuantity} ${itemName} for a total of ${saleTotal}!
/varcalc totalMoney ${saleTotal}+${totalMoney}
/varcalc totalSold ${itemQuantity}+${totalSold}
/nomodkey /notify FindItemWnd FIW_ItemList listselect ${looper}
} else {
/break
}
/next looperTwo
}
/next looper
/if (${Window[FindItemWnd].Open}) {
/windowstate FindItemWnd close
}
/if (${Window[MerchantWnd].Open}) {
/windowstate MerchantWnd close
}
/echo We are finished vendoring!
/echo We vendored ${totalSold} items for a rough estimate of ${totalMoney}pp!
Which will first call our function for finding a vendor, then it will loop over our find item window and use a system of checks to decide whether or not an item should be sold. This check is /if (${Ini[AutoVendor.ini,"Items",${itemName}].Equal[Sell]}) which essentially says if the item we are highlighted on is set to Sell in our INI, then sell the item. There's just a flat else catch in there, so technically you can set it to anything BUT Sell and it will still not sell the item, it doesn't HAVE to be Ignore, I just tell people to set it to Ignore because it made sense and is less confusing than saying "Set it to anything because the else will catch the exception so it doesn't matter" sort of deal.
There's a bunch of squish in there, mainly because I personally like to see the stats of what I sold, how much, how much I gained etc. to make it easier to gauge a camps value based on the vendor trash but as well I like my applications to be as transparent as possible as it not only helps with debugging but also helps others understand exactly what the macro is doing and why.
If you have any questions, feel free to ask!
Edit: I forgot to mention, for the main functionality, the reason the main loop has another loop within it is because sometimes you'll have items one after another that need to be sold, if this is the case the main loop will actually skip the item right after it as it's moving on to the next in the list via the ${looper} variable BUT, because we sold an item, the next in the list is now the current iteration so when it increments it skips. A second loop that iterates over the functionality until it hits something that ISN'T on the INI then breaks fixes this and that's why it is there.