User:Cogswobble/Addon Tutorial/Slash Commands

So, we know what we want to do. But, how to get started?

Examining the API
Since both of my addons are very "inventory item"-centric, I should probably look at the available API functions and data types for dealing with inventory items, and see what is available for getting the data I'll need. Below is a list of functions grouped by area. The list was shamelessly stolen from the API page and cut down to a set of "interesting" functions for my addons (or my own education).

Bank Functions

 * BankButtonIDToInvSlotID(buttonID, isBag)  - Returns the ID number of a bank button or bag in terms of inventory slot ID.
 * GetNumBankSlots  - Returns total purchased bank bag slots, and a flag indicating if it's full.

Container/Bag Functions

 * ContainerIDToInventoryID(bagID)
 * GetBagName(bagID)  - Get the name of one of the player's bags.
 * GetContainerItemInfo(bagID, slot)  - Get the info for an item in one of the player's bags.
 * GetContainerNumSlots(bagID)  - Returns the total number of slots in the bag specified by the index.
 * PROTECTED (Situational) UseContainerItem(bagID, slot[, onSelf])  - Uses an item located in bag# and slot#.  (Warning: If a vendor window is open, using items in your pack may sell them!)   - 'onSelf' added in 1.12

Inventory Functions

 * ContainerIDToInventoryID(bagID)
 * GetInventoryItemCount("unit",invSlot)  - Determine the quantity of an item in an inventory slot.
 * GetInventoryItemQuality("unit",invSlot)  - Return the quality of an inventory item.
 * GetInventoryItemTexture("unit",invSlot)  - Return the texture for an inventory item.
 * GetInventorySlotInfo(invSlotName)  - Get the info for a named inventory slot (slot ID and texture)
 * PROTECTED UseInventoryItem(invSlot)  - Use an item in a specific inventory slot.

Item Functions

 * GetItemCount(itemId or "itemName" or "itemLink"[, includeBank])  - returns how many of specified item you have in your inventory
 * GetItemFamily(itemId or "itemName" or "itemLink")  - Returns the bag type that an item can go into, or for bags the type of items that it can contain. (New in Patch 2.4)
 * GetItemIcon(itemId or "itemString" or "itemName" or "itemLink")  - Returns the icon for the item. Works for any valid item even if it's not in the cache. (New in Patch 2.4)
 * GetItemInfo(itemId or "itemString" or "itemName" or "itemLink")  - Returns information about an item.
 * IsUsableItem(item)  - Returns usable, noMana.
 * IsConsumableItem(item)  -

Now What?
Now, I know what some of the above functions do. I have an idea what some of them do. And the rest...well, I have no idea. So, what I need to do now is play around with them and see what I can learn. There are a few ways to do this. First, you can use the slash command /script to execute a Lua function. This has the advantage of being really, really easy. The downside is that is just one function and we have a few that we want to play around with and see how they work together. Second, we can create an addon to perform certain operations as we press buttons, etc. So, this allows us to have complex behavior, but at the cost of building all the UI components and such. That is really overkill for a learning exercise. Third, we can create a new slash command. Arguments sent with the command can trigger complex behavior, but we don't have to waste the time creating UIs we are just going to throw out later.

We are going to go with the third option.

Setting Up the Addon Structure
Since I'm lazy, I'm going to name this addon MagicBox. Later, I can delete the files under it and reuse it for the real addon. So, that means creating a directory under \Interface\Addon named MagicBox.

MagicBox.toc
Next, I need to create a TOC file. You might want to do this last so you know what files to list in it, but I already know I'm going to have two files, MagicBox.lua and MagicBox.xml. The Lua file will contain the script for our desired behavior, and the XML file is needed to trigger the Lua script with a OnLoad event (more on this later).

Text of MagicBox.toc: MagicBox.xml MagicBox.lua Your interface version number may be different, as this changes with each UI update. You'll know when this happens, all of the addons will show up as out of date. To find the latest interface version number, see Getting the current interface number.
 * 1) Title: MagicBox
 * 2) Version: 0.1
 * 3) Author: Cogswobble of Malygos
 * 4) Interface: 30000

MagicBox.xml
Now we need a simple XML file that will allow us to trap the OnLoad event and send it to our Lua script. The frame we generate doesn't need to be fancy. In fact, we don't even want to have it displayed. Text of MagicBox.xml:      MagicBox_OnLoad;     The Script element identifies our Lua file. And the OnLoad element identifies MagicBox_OnLoad as the function to call when the frame is loaded.

MagicBox.lua
Now it's time to write our Lua script. We need a function, MagicBox_OnLoad, which will be called when the frame is loaded. This function needs to setup the slash command (we are going to use /magicbox, and for example purposes, /mb) and declare the handler function for when this slash command is used, MagicBox_SlashCommandHandler( msg ). Because Lua uses a one-pass parser, functions must be defined before being used. Therefore, MagicBox_SlashCommandHandler( msg ) must be defined before MagicBox_OnLoad which will use it. Text for MagicBox.lua: function MagicBox_SlashCommandHandler( msg ) DEFAULT_CHAT_FRAME:AddMessage( "Command: " .. msg ); -- Output the message to the default chat window end function MagicBox_OnLoad SlashCmdList["MAGICBOX"] = MagicBox_SlashCommandHandler; -- Add our slash command handler to the list of slash commands SLASH_MAGICBOX1 = "/magicbox"; -- Associate /magicbox with the slash command list entry for MAGICBOX SLASH_MAGICBOX2 = "/mb"; -- Associate /mb with the slash command list entry for MAGICBOX end This code really begs some explaination. The MagicBox_SlashCommandHandler function is pretty straightforward, the arguement msg will be output to the chat window. We'll modify this later to actually do some work. The MagicBox_OnLoad function is a little more mystical. The SlashCmdList is an array of handlers for different slash commands. The index string for our handler is "MAGICBOX". The following lines associate our slash commands with this index by creating the variables SLASH_MAGICBOX1 and SLASH_MAGICBOX2. Notice the use of the index string in the variables' names? That completes the association from the slash command string "/magicbox" to MagicBox_SlashCommandHandler.

Note, the MAGICBOX used as the index string is unrelated to the name of the addon or this function name. To make this point, here is the file again, except we implement the slash commands /beavis and /butthead: function MagicBox_SlashCommandHandler( msg ) DEFAULT_CHAT_FRAME:AddMessage( "Command: " .. msg ); -- Output the message to the default chat window end function MagicBox_OnLoad SlashCmdList["TRICK"] = MagicBox_SlashCommandHandler; -- Add our slash command handler to the list of slash commands SLASH_TRICK1 = "/beavis"; -- Associate /beavis with the slash command list entry for TRICK SLASH_TRICK2 = "/butthead"; -- Associate /butthead with the slash command list entry for TRICK end This is very important to note, as this syntax is neither obvious or intuitive. A much better mechanism would have been something more like: function MagicBox_OnLoad AssociateSlashCommandToHandler( "/magicbox", MagicBox_SlashCommandHandler ); AssociateSlashCommandToHandler( "/mb", MagicBox_SlashCommandHandler ); end However, Blizzard stuck us with this kludgy code instead.

Test MagicBox
After saving your files, it's time to take it for a spin. Login and ensure that the addon is set to load with your character. Enter WoW with that character and type: /magicbox Test. You should see in your chat window: Command: Test. If not, or if you get an error, go back, fix your files and try again. Congratulations, you have just written an addon!