World of Warcraft AddOn Tutorial
World of Warcraft supports the ability for players to create modules that extend the game's user interface. These modules are called AddOns. The interface of World of Warcraft is built from XML files which describe its look and layout, and Lua files, which contain scripting functionality. This document is a short introduction into creating an AddOn that works directly with the game client. The creation of AddOns is a very technical endeavor, and you should not attempt it unless you have a good working knowledge of XML and Lua.

The Interface AddOn Kit extracts the XML and Lua files into the "Blizzard Interface Data" directory, and the interface artwork into the "Blizzard Interface Art" directory. The interface files are provided for your education, and are not supported in any way. That said, we hope that World of Warcraft provides a robust and flexible environment for your creativity.

The Basics

There are three types of files used in AddOns: the .toc, .xml, .lua.

The .toc is a table of contents for the AddOn. This file contains important header information that the WoW client reads to identify your AddOn. It also contains a list of files that are loaded in the order they appear.

XML is a mark-up language used to describe the look and layout of the interface. Custom AddOns that require an interface component will need an XML definition. Learn more about XML at: http://www.xml.com. The Interface artwork is in a .blp format, which is a proprietary format. The existing art can be converted to something viewable using third party tools. Custom artwork for AddOns may use the TARGA (.tga) format, as well.

Lua is the scripting language used to define the functionality of the interface. The manual for Lua 5.0 is available online at: http://www.lua.org/manual/5.0/.

The best way to become familiar with how Lua is used to script the interface is to look at the scripts in the XML files, denoted by the <script> tag, and to browse the Lua files. The Lua files typically contain functions that are used by the corresponding XML files.

For questions, insight, and more reading, check out the official World of Warcraft User Interface & Macros forum.

Creating Your First Add On - "Hello World!"

The World of Warcraft install folder should have a directory called Interface\AddOns\. This is where the AddOns live.

The first AddOn we'll create is a simple script to say "Hello World" which will pop up a message window when the game loads and display the text: "Hello World!". Though not complicated, this AddOn will ultilize a bit of XML, Lua, and the WoW UI spec - enough to get your feet wet.

Step 1: Create a directory in your AddOns folder and name it "HelloWorld".

Step 2: Create three files in your new directory: HelloWorld.toc, HelloWorld.xml, HelloWorld.lua.

Step 3: Write your AddOn!

The first file to populate is the .toc file. This contains the instructions that tell WoW what files to load and in what order. The scripts should be listed before the XML files that reference them.

## Interface:          Version number of WoW your AddOn is written for
## Title:                 Name your AddOn
## Notes:               Additional Info
## Dependencies:    Any other AddOns that it depends on, comma delimited
included.lua
included.xml

Note:The value you would need to copy for the Interface version lives in the FrameXML.toc which can be found in the "Blizzard Interface Data\FrameXML" directory. The game's interface version is updated with each major patch, so you'll need to update the version number for your AddOn to match. It's important for AddOn authors to consistantly update their AddOns to be compatible with the current release version of World of Warcraft. If an AddOn is out of date, the AddOn interface will flag it as such.

So with this in mind, the .toc file should look something like this:

HelloWorld.toc
## Interface: 20000
## Title: Hello World
## Notes: Learning is fun!
## Dependencies:
HelloWorld.lua
HelloWorld.xml

Next we tackle the .xml file.

HelloWorld.xml
<Ui xmlns="http://www.blizzard.com/wow/ui/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.blizzard.com/wow/ui/
..\..\FrameXML\UI.xsd">

</Ui>

The first statement is a basic definition of the UI, the specification it's based off of, and where the UI definitions file lives in the game directory. Since there's nothing here, nothing would happen if you loaded the game. In order to make something happen, we need to insert the following into the XML file between the <Ui> and </Ui>:

Note: Remember, each XML file typically describes one element of UI on the screen. To get a feeling for the syntax, take a look at the files extracted into the "Blizzard Interface Data" directory. These XML files strictly adhere to the XML 1.0 standard and can be validated against the custom schema defined in UI.xsd.

HelloWorld.xml
<Frame name="HelloWorldFrame">
 <Scripts>
  <OnLoad>
   HelloWorld();
  </OnLoad>
 </Scripts>
</Frame>

This code uses the Frame tag to define a frame named HelloWorld. When the frame loads, the <OnLoad> element instructs the client to perform the HelloWorld() function. So our next step is to actually write that function.

HelloWorld.lua
function HelloWorld()
  message("Hello World!");
end

The above demonstrates the simple format of a Lua function. The key things to note are that the function is defined and then named, and is concluded with an "end" after all of the instructions. Also notice we use the message() function. This is a built in function that shows a message on the screen in a pre-defined pop-up box.

Step 4: Launch World of Warcraft and see your message!

Tip: AddOns can be switched on and off using the AddOn interface accessed through a button in the lower-lefthand corner of the Character Selection screen. By default, your new AddOn will be switched on.

Congratulations!

You've just built your first World of Warcraft AddOn! When you feel ready, you can move on to the more advanced tutorial: Show Me The Money!

 

Advanced Tutorial: Show Me The Money!
So you'd like to learn more about creating a WoW AddOn... We've thrown together a more advanced tutorial to familiarize yourself with some key concepts in the WoW UI framework.

Show Me The Money!

For those of you wishing you had a way to keep track of the total amount of money you've ever accumulated on your character, today's your lucky day. "Show Me The Money!" is an AddOn designed to do just that - it adds any cash you gain to a persistent total across game sessions for each unique character. The intention of this tutorial is to demonstrate the use of key functionality within the World of Warcraft interface framework: OnLoad, OnEvent, OnUpdate, and saved variables. However, since this AddOn is a bit more complex than the one we went through up above, copy the "ShowMeTheMoney" directory from "Blizzard Interface Tutorial" to "Interface\AddOns" to see how it functions in the game. To see the AddOn in action just go to a vendor and sell something! It would also be helpful to have the associated files viewable for reference while reading through this tutorial. The code itself has more inline commentary to clarify what each bit of code does, whereas here we will go over key concepts.

There are four neccesary files for this tutorial:

ShowMeTheMoney.toc
ShowMeTheMoney.xml
ShowMeTheMoney.lua
CashMoney.tga

ShowMeTheMoney.toc

For this AddOn, we've got a fairly straightforward .toc file. One particular thing of note, however, is a new field called "SavedVariablesPerCharacter". This is a comma separated list of global variables that are automatically saved and restored with this AddOn.

ShowMeTheMoney.toc
## Interface: 20000
## Title: Show Me The Money!
## Notes: An advanced tutorial
## Dependencies:
## SavedVariablesPerCharacter: SHOWMETHEMONEY_MONEY
ShowMeTheMoney.lua
ShowMeTheMoney.xml
ShowMeTheMoney.xml

The best way to tackle building an add on is first determining what it is you want the AddOn to look like. Once you get the looks down, it's easy to add the functionality piece by piece, testing it each step of the way. Once the XML is built, you can actually load your AddOn into the game and use the "/script ReloadUI();" command every time you save an update to your files. If there are syntax errors in loading, you can just edit, fix, and reload. Keep in mind, however, that ReloadUI(); will not load new files, only existing ones.

Let's take a closer look at the key elements within the ShowMeTheMoney.xml.

Since the XML can be somewhat complex, let's move down chunk by chunk and discuss what's being called within it.

ShowMeTheMoney.xml
<Frame name="ShowMeTheMoneyFrame" toplevel="true" parent="UIParent" movable="true" 
            hidden="false">
   <Size x="148" y="30"/>
   <Anchors>
      <Anchor point="TOPLEFT" relativeTo="Minimap" relativePoint="BOTTOMLEFT">
         <Offset x="-3" y="-10"/>
      </Anchor>
   </Anchors>

This is the frame that contains our AddOn. It is essentially an empty frame, since it houses an interior frame that accepts game events. We will utilize this frame to handle mouse events while our interior frame is hidden, since a frame will only detect mouse movement if it is visible. It is a top-level frame, because it is a container, and its parent is UIParent, the parent of all top-level frames. Yes, this frame is movable (since we want it to move our event-driven frame). We also have established the overall size of this AddOn's frame, and where it should render within the game screen (in this case, just below the Minimap).

Note: Frames work together in a number of ways. It can inherit the features and settings of a parent frame or have a relative attachment to another frame. Many frames within the World of Warcraft UI are constructed this way. Poke around in the extracted files (specifically UIParent.xml) to see a few examples.

Within the container frame, we then define our active frame. We will need to establish look and feel (any artwork drawn in to create our box), our active elements, and related scripts. For this AddOn, we're going to utilize a pre-created Tooltip look and feel, the format for which was obtained from the WoW Interface source files. We also want to have a little animation that plays on each cash event that our AddOn registers, so we'll define and position that texture here as well.

Note: Whenever a frame, texture, or fontstring is defined in XML, its initial attributes are defined and, if named, a global variable with that name is created to represent that object in Lua.

ShowMeTheMoney.xml
   <Frames>
      <Frame name="ShowMeTheMoney" setAllPoints="true" hidden="true">
         <Backdrop bgFile="Interface\Tooltips\UI-Tooltip-Background"
                          edgeFile="Interface\Tooltips\UI-Tooltip-Border" tile="true">
            <EdgeSize>
               <AbsValue val="16"/>
            </EdgeSize>
            <TileSize>
               <AbsValue val="16"/>
            </TileSize>
            <BackgroundInsets>
               <AbsInset left="5" right="5" top="5" bottom="5"/>
            </BackgroundInsets>
         </Backdrop>
         <Layers>
            <Layer level="BACKGROUND">
               <Texture name="CashMoney" file="Interface\AddOns\ShowMeTheMoney\CashMoney">
                  <Size x="16" y="16"/>
                  <Anchors>
                     <Anchor point="RIGHT" relativePoint="LEFT"/>
                  </Anchors>
               </Texture>
            </Layer>
         </Layers>

Now that we've got the look, we need the functionality. Since we're working with Money related events, we'll utilize another portion of the pre-existing UI for our functionality: the MoneyFrame. If you'd like to learn more about the MoneyFrame, browse through MoneyFrame.xml and MoneyFrame.lua in the "Blizzard Interface Data\FrameXML" directory to familiarize yourself with some of the concepts. For this AddOn, we'll take advantage of the "SmallMoneyFrameTemplate" which is typically viewed in the player's Backpack. It is within this frame that we'll call our functions defined within ShowMeTheMoney.lua.

Note: There is a call to set a Money Type within our script, and that's because MoneyFrame.lua will complain if no type is set, so we set a pre-defined type.

ShowMeTheMoney.xml
         <Frames>
            <Frame name="$parentMoneyFrame" inherits="SmallMoneyFrameTemplate" hidden="false">
               <Size x="0" y="30"/>
               <Anchors>
                  <Anchor point="TOPRIGHT"/>
               </Anchors>
               <Scripts>
                  <OnLoad>
                     self.staticMoney = 0;
                     MoneyFrame_SetType("STATIC");
                  </OnLoad>
               </Scripts>
            </Frame>
         </Frames>
         <Scripts>
            <OnLoad>
               ShowMeTheMoney_OnLoad(self);
            </OnLoad>
            <OnEvent>
               ShowMeTheMoney_OnEvent(self, event, ...);
            </OnEvent>
            <OnUpdate>
               ShowMeTheMoney_OnUpdate(self, elapsed);
            </OnUpdate>
         </Scripts>

The following code is all related to the UI interaction - fading the window in and out, on Mouse Enter and Leave respectively, and the ability for the user to reposition it wherever they like. To do these things, we'll use some pre-defined functions within UIParent.lua.

ShowMeTheMoney.xml
      </Frame>
   </Frames>
   <Scripts>
      <OnEnter>
         UIFrameFadeRemoveFrame(ShowMeTheMoney);
         UIFrameFlashRemoveFrame(ShowMeTheMoney);
         UIFrameFadeIn(ShowMeTheMoney, 0.1);
      </OnEnter>
      <OnLeave>
         UIFrameFadeRemoveFrame(ShowMeTheMoney);
         UIFrameFlashRemoveFrame(ShowMeTheMoney);
         UIFrameFadeOut(ShowMeTheMoney, 0.25);
      </OnLeave>
      <OnMouseDown>
         self:StartMoving();
      </OnMouseDown>
      <OnMouseUp>
         self:StopMovingOrSizing();
      </OnMouseUp>
   </Scripts>
</Frame>

Now that we've familiarized ourselves with the XML and how it's written, let's take a look at the supporting .lua that drives this beast. There are four key elements to understand within the WoW UI: AddOn variables, OnLoad, OnEvent, and OnUpdate. We will utilize all of these components in our AddOn.

One thing to note is that our primary functions (OnLoad, OnEvent, OnUpdate) are passing through pre-defined local variables. These are variables present in each of the supporting functions driven by the SCRIPT tags in the XML. self refers to the frame the code is referencing, event is a trigger that the code is listening for (which will be dealt with later on in this tutorial), and elapsed refers to the time interval between each rendered frame.

OnLoad

This is the script that fires when the frame is loaded. In the case of our AddOn, we're initilizing elements of our animation, setting our backdrop color, and registering the events neccesary for the remainder of our functionality.

ShowMeTheMoney.lua
function ShowMeTheMoney_OnLoad()

   ShowMeTheMoney_Animate(SHOWMETHEMONEY_ANIM_NUMFRAMES);

   self:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, 
	TOOLTIP_DEFAULT_COLOR.b);
   self:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, 
	TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b);
  
   self:RegisterEvent("ADDON_LOADED");
   self:RegisterEvent("PLAYER_ENTERING_WORLD");
   self:RegisterEvent("PLAYER_MONEY");

end
OnEvent

World of Warcraft is designed so that it needs to know very little about the interface. Instead of calling directly into the interface whenever something interesting happens, an event is generated. Each frame registers for events that it is interested in using RegisterEvent(), and when those events happen, the OnEvent handler is called for that frame.

In this example, we have three key events: ADDON_LOADED, PLAYER_ENTERING_WORLD, and PLAYER_MONEY. Upon the occurance of each event, the following code executes.

The following code snippet deals specifically with events relating to the initial interface load.

ShowMeTheMoney.lua
function ShowMeTheMoney_OnEvent(self, event, ...)

   if ( event == "ADDON_LOADED" ) then
       local addon = select(1, ...);
	   if ( addon == "ShowMeTheMoney" ) then
           DEFAULT_CHAT_FRAME:AddMessage("ShowMeTheMoney 1.0: You have collected "
                        ..math.floor(SHOWMETHEMONEY_MONEY / 10000).." gold!");
           MoneyFrame_Update("ShowMeTheMoneyMoneyFrame", SHOWMETHEMONEY_MONEY);
       end
   end

   if ( event == "PLAYER_ENTERING_WORLD" ) then
      SHOWMETHEMONEY_LASTMONEY = GetMoney();
      return;
   end

Our first event is ADDON_LOADED. ADDON_LOADED is an event that fires when everything for an AddOn is loaded, including saved variables. In this case, it's our saved money variable. First we display in a text statement in the chat window how much total gold the player has accumulated, and update our MoneyFrame inside our AddOn window with that amount. When the player enters the world (PLAYER_ENTERING_WORLD), our function gets the character's current money, and assigns it to the global variable SHOWMETHEMONEY_LASTMONEY for use later on in our AddOn.

Tip: If you're not sure what's happening in the script, use the message() function to print a message and view variables. Once the dialog is shown, your script keeps on executing, but no other message() calls will show anything until you click the button to dismiss the dialog.

ShowMeTheMoney.lua
if ( event == "PLAYER_MONEY" ) then
      local money = GetMoney();
   
      if ( money > SHOWMETHEMONEY_LASTMONEY ) then
        local increase = (money - SHOWMETHEMONEY_LASTMONEY);
 
        SHOWMETHEMONEY_MONEY = SHOWMETHEMONEY_MONEY + increase;
 
        MoneyFrame_Update("ShowMeTheMoneyMoneyFrame", SHOWMETHEMONEY_MONEY);

        if ( not MouseIsOver(self) ) then
           UIFrameFadeRemoveFrame(self);
           UIFrameFlashRemoveFrame(self);
           UIFrameFlash(self, 0.1, 0.5, 2, false, 0, 1.4);
        end

        self.index = 1;
        self.timer = 0;

        ShowMeTheMoney_Animate(self.index);
        CashMoney:Show();
      end

      SHOWMETHEMONEY_LASTMONEY = money;
      return;
   end

end

The PLAYER_MONEY event is really the meat of our AddOn. PLAYER_MONEY is an event that fires whenever there is a money transaction within the game. Our goal is to register the money-related event, increment our total count, display our frame, and set up our animation.

OnUpdate

With this AddOn, we're utilizing OnUpdate to establish a timer for our animation frames. OnUpdate is called every visible frame. With our function we are asking OnUpdate to provide us with the elapsed time between frames so that we can use it to time our animation. This animation code itself is fairly straight forward for cycling through the animation frames in our texture file, CashMoney.tga.

ShowMeTheMoney.lua
function ShowMeTheMoney_OnUpdate(self, elapsed)
   if ( not self.timer ) then
      return;
   end
	
   local timer = self.timer + elapsed;
   local framesElapsed = math.floor(timer / SHOWMETHEMONEY_ANIM_FRAMETIME);
   local animIndex = self.index + framesElapsed;
   if ( animIndex <= SHOWMETHEMONEY_ANIM_NUMFRAMES ) then
      self.timer = timer - (framesElapsed * SHOWMETHEMONEY_ANIM_FRAMETIME);
         if ( animIndex ~= self.index ) then
            ShowMeTheMoney_Animate(animIndex);
            self.index = animIndex;
         end
      else
      self.timer = nil;
   end
end
The End ... Or the Beginning??

Though brief, this exposure to the key components of a WoW AddOn should guide you in how to implement any AddOn ideas you may have. For further questions or insight, it's highly useful to become an active member of the official World of Warcraft User Interface & Macros forum.