Addon Tutorial

Well, you've decided to start an AddOn for Runes of Magic. Or at least you're contemplating it.

Making the folder
You start out by choosing a folder name for your AddOn. It should be something simple, and no funny characters (just letters, numbers, dashes, underscores, periods, basically).

For this exercise, we're going to make the cliché HelloWorld AddOn.

Assuming you installed RoM to, you'll want to verify that   and   exist, otherwise you should create them, case-sensitive.

You'll then want to create the  folder (or whatever you want to call it), which will house all your AddOn's files.

Don't name your AddOn "test"... it won't work.

Laying the groundwork
There are three kinds of files used for AddOns (outside of image and sound files):


 * .toc file
 * Each AddOn should have one .toc file, it will match the name of your AddOn's folder. In our example, this will be  and will be placed as  . This will provide metadata about your AddOn as well as providing information on what files to load.


 * .lua files
 * This is where the bulk of your code lies, all the actual business logic should take place here.


 * .xml files
 * XML files can load Lua files and well as define frames. (At least until a way is provided to create frames in Lua.) Try not to put any actual logic into your XML files, but rather delegate it to a function or method inside your Lua.

We need to start with your TOC file. It should look something along the lines of this:

As you can see, you specify your AddOn's name, what version number it is , a one-line description , and your author handle. You can specify other information, but if you do, prefix with, so that there are no conflicts in the future.

For right now, we're only loading one file,, which will contain some simple code.

Let's get our code on
Here's what we'll stick in

At this point, if you start up RoM, you'll get the message "Hello, World!" in your chat frame.

You can also run  at any time from the in-game command line to print out the text again.

Addendum
For performance reasons, according the lua documentation and lua developer community it is a good practice to:
 * make use of code modules and package calls through namespaces;
 * use as many local function calls as possible;

How to implement this? Assume you created an addon called MyRomAddOn. It's possible to have more than one lua coded files within your addon.Each file then represents a separate module within your addon-package. So, you'd have your addon's folder , containing your lua table of contents (MyRomAddOn.toc) file which describes the internal file structure and any other lua files. Suppose your addon has 2 lua files, MyRomAddOn.lua and Tools.lua.

The file MyRomAddOn.lua could look like this:

To test, type /script MyRomAddOn.Load; in the game's chatwindow.

Event fun
Code which can't react to the game isn't very useful, which is why we need to start messing with some events.

To do this, we have to unintuitively make a frame, which is how we can listen in on events.

So, let's add  to our .toc file (before the   file). It would look like this:

And create the  file:

Now we need to define an OnEvent method as well as register any events, so let's return to our lua.

Now let's explain what  does. It allocates the events to each function corresponding to the  variable, without having to use structures like

Alright, now instead of printing  when the Lua loads, it will do it when   is fired.

Timers
Unlike in a single-threaded environment, you can't just run a  command to wait to execute something, you need to use timers.

If you were to manually sleep, then you'd freeze up the entire UI, which nobody wants.

is a script that runs every frame tick, similar to an event firing every tick.

In the following, we'll run a command every 5 seconds:

For your XML:

And in the Lua:

You can stop  from firing by calling   and starting it again with.

This code will generate an error in the current release. The error may come from the XML OnUpdate(elapsedTime) or from the function HelloWorld:OnUpdate(elapsed) needs investigation

Slash Commands
We will now learn how to register   commands. Lets start out by doing a simple slash command, with no other parameters. The only changes will be in the .Lua file.

Now, to declare a slash command name, we need to use the SLASH prefix to a variable, then the name of the slash variable, and a number after it. Note that the number has to be an integer. Examples of slash names:

A more complex slash command, in which you have extra parameters, but still keeping it simple. frame:Hide DEFAULT_CHAT_FRAME:AddMessage("OnUpdate now stopped.") elseif string.lower(msg) == "show" then frame:Show DEFAULT_CHAT_FRAME:AddMessage("OnUpdate now started.") elseif string.lower(msg) == "print" then HelloWorld.Print else DEFAULT_CHAT_FRAME:AddMessage("Not a viable command") end end

--- Print out "Hello, World!" to the chat frame -- @usage HelloWorld.Print function HelloWorld.Print DEFAULT_CHAT_FRAME:AddMessage("Hello, World!") end

frame:RegisterEvent("VARIABLES_LOADED")

function HelloWorld:OnEvent(event, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) -- this is a fun trick that will call a method named the event, passing in all the relevant args. self[event](self, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) end

function HelloWorld:VARIABLES_LOADED self.Print end

local time_remaining = 5 -- in seconds function HelloWorld:OnUpdate(elapsed) -- elapsed is the amount of time in seconds since the last frame tick

time_remaining = time_remaining - elapsed if time_remaining > 0 then -- cut out early, we're not ready yet return end time_remaining = 5 -- reset to 5 seconds self.Print end

Frame Tutorial
Needs additional information on how to call a frame to show it for the user including a working example

Now lets take a look at frames and the xml.

Before we look at frames and all this stuff lets take a look at xml.

An easy XML example would be:

We see that XML has something like tags in HTML. (called elements in XML) An element can be opened and closed again or be empty, which is shown through the "/" at the end of the element.

Elements can have attributes (height) with a value (1,5m), but they aren't necessary.

Elements have parents (the outer element; parent of MyBookshelf would be MyRoom) and children (a child has only one parent but a parent can have multiple children).

To make a frame for our AddOn we'll do the following in our .xml:

What does everything do?

Starts a Frame with the apperance of a default-frame. (like the bag- or guild-frame) name = Name of the frame. Must be unique and is used to identify the element in the .lua. parent = The parent of the frame (I don't know if you can leave this out). inherits = Some default-values for the element rather then setting everithing by hand (UICommonFrameTemplate can be found in "ui.xls" in "interface.fdb/interface/worldxml/". hidden = Defines if the frame is hidden or not. enablemouse = Defines if the frame can get mouse input.

Defines the size of the element

An element to define sizes. x = Width. y = Height.

Contains the location of the element via anchors.

An anchor for the element. point = A relative point. If no element to align relative to is given then the parent will be used. CENTER aligns the frame in the center of the parent element.

An Offset of the element. Can be used to align it e.g. 200 px right from the center.

Again AbsDimension. Here the Offset is set.

Layers are texts on the frame.  contains all of them.

One layer.

FontString is a layer with Text in it. text = The text that is displayed on the FontString.

This displays a Frame with the title set in the FontString.

But just a frame with a title isn't enough for a real addon. Where are the buttons, textfields and that stuff? To Use all that Stuff we first need to set a Frame where all this is going. (I don't know why it cannot be put into MyAddon_MainFrame, but it can't.) So add the following code:

What does  do? It gives us a space inside an element, where we can add frames inside of it. In our example we add a frame called "MyAddon_Content" into "MyAddon_MainFrame" to put the button in. In the MyAddon_Content frame we open  again to add the button. (because the button is threaded as a frame itself)

The Text between the

We see that we use an element called. With inherits="UIPanelButtonTemplate" we will use the standard-button used in RoM, which prevents us from the need to define a texture and stuff like that. You can unpack "interface.fdb" and look into the files in "/interface/worldxml/" to see other templates.

There are still some things to lern about placement of elements in frames. as seen in  and in the frame ingame the button is places in the top left corner of the frame. This is done defining a relative anchor.

point = The point where the element should be "grabbed" at to place it relative. possible are: TOP TOPRIGHT RIGHT BOTTOMRIGHT BOTTOM BOTTOMLEFT LEFT TOPLEFT

relativeTo = An element to place relative to. If not set then outward element will be used.

relativePoint = Where at the relativeTo-element the at "point" defined point should be attached to. Cas have the same values as point.

There are more elements like CheckButtons, EditBoxes and stuff, which are used pretty similar in the code like the button. And maybe some examples out of WoW can be used to.

The complete code would look like