Introduction
World of Warcraft is a server client application with some of the game functionality residing on a server and other game functionality residing on the client. Most of the server functionality involves the game environment that is shared by other players. The client functionality involves the user interface for the player, the presentation of messages from the server, and the sending of messages of player actions to the server. Some information is presented in the rendering of the three dimensional world in which the player's avatar or toon is located and some information is presented n the form of text and/or graphical messages that are displayed in various ways providing status information to the player.
World of Warcraft provides a mechanism for people to add their own components, addons, to the game client. Most addons are created to add to the standard user interface in order to provide additional information. Some are intended to replace much of the standard user interface components to provide a leaner and more compact set of controls or to replace some of the standard user interface components to provide a richer environment for some activities (e.g. auction house addon to help players with auctions).
Much of the user interface provided by Blizzard Entertainment is written in Lua and an addon extending, enhancing, or replacing the existing client functionality must also be written in Lua. A fairly large community of addon programmers exists with several web sites devoted to the management of addons and these web sites provide a rich source of source code and ideas for the addon builder. The standard user interface that is installed appears to be a compiled version of the Lua code however Blizzard Entertainment provides a kit, the World of Warcraft Interface Addon Kit, that allows a person to see the original Lua source and XML files. The kit is available through the Blizzard Technical Support forums and a search should provide the most up to date link.
There are a number of web sites as well as books published that provide a fair amount of information. For an indepth discussion of writing an addon, take a look at the books and web sites available. The books often provide a level of discussion missing from the various web sites. On the other hand, the various web sites are fairly good at providing specific details about the API and may provide information that is more up to date than a book. The purpose of this article is to provide a sample Warcraft addon that will provide an instructive example for beginners.
Background
There are several broad categories of user interface addons which can roughly be divided into:
- Addons to assist with combat
- Addons to assist with farming (gathering activities such as mining)
- Addons to assist with interacting with other players and with managing guilds, and
- Addons to assist with the auction house and with Non-Player Character vendors.
There are several types of combat and there are specialized addons to assist with Player versus Environment (PvE) combat (tending to be one or two to perhaps five players in a group playing against an artificial intelligence), Player versus Player (PvP) combat (tending to be larger groups of people playing against other people), and combat in raids (tending to be large groups of people playing against an artificial intelligence).
As the World of Warcraft game has matured and various people have created addons to help with particular actions, Blizzard has modified the API and the Blizzard supplied user interface as they have learned more about what people do in the game. Some of the changes have resulted in older addons no longer being of use as Blizzard has incorporated that functionality into their client. Some of the changes have resulted in older addons no longer functioning as Blizzard modified the API so that those addons no longer work when Blizzard determined that the functionality supplied by the addon conflicted with the philosophy of the game.
Using the Code
The functionality of this example addon is simple and straightforward. It provides status information to the player only which makes the source code much simpler. Displaying status also avoids a number of considerations that are required for an addon that performs actions. The developers at Blizzard Entertainment have modified the API and the functionality that is available over the years to provide additional guards against addons that do many of the actions that the developers believe should be done only by a player. Since this is an information display addon, those provisions to reduce the possibility of software agents playing a character are not a consideration. The source code contains a large number of comments to help others to understand the source.
This sample addon is a combat information type of addon. It displays a simple set of frames showing the health and power (mana, focus, rage, etc.) of a player character, the player character's pet if there is one, as well as the health and power of the currently selected target (target in this sense is some other player character, non-player character, beast, or other actor within the world that the player character has selected as a target). This addon also displays the threat level of the target which is an indication as to the target's willingness to attack.
The basic procedure in this addon as well as most is:
- Initialize any global variables
- Register for the first events for when the player enters the World of Warcraft virtual world
- Upon entry into the virtual world, build the user interface from the various widgets available in the Warcraft API
- Register for the events required to update the user interface, and
- Update the user interface as events are received
In this example there are two files, main.lua which contains the Lua source code for the addon and SimpleCombatHud.toc which contains the table of contents for the addon. Because this addon creates the user interface using Lua, there is no need for an XML file that describes the user interface window structure. The name of the .toc file must be the same as the folder in which the files are located and those names, the folder name and the .toc file name, must be the same as the name of the addon itself.
Naming of an addon is important in that the nam space for all addons as well as the World of Warcraft client is a global namespace. Programmers must be careful to use as few global variables as possible in their addons and those that they do use should be unique names. This is why addon programmers will use a Lua table variable with a global name that is the same as their addon and then any persistent data needed by the addon goes into the table. Secondary global variables such as data for settings will use a derivative of the addon name in order to reduce the possibility of the name clashing with any other global variable. The use of the local
keyword is important for temporary variables in order to reduce cluttering the global name space and possibly colliding with an already existing variable.
The .toc File
The .toc file describes the addon with a number of entries that contain a version number, a description of the addon, and a list of the files that need to be loaded to make the addon functional. There are also comments to allow the programmer to provide information to anyone who is looking at the .toc file. Some addon web sites use the information in the .toc file as a part of the descriptive information presented to people who are looking for an addon of a particular type. These web sites may have special directives they require to be used in the .toc file which the web site parses in order to determine the type of addon and how to categorize it.
An example of the first few lines in a .toc file are below. The Interface line indicates the version of the World of Warcraft client that the addon targets. If the value specified is of an earlier version of the Warcraft client, the addon will be disabled unless the player chooses to load out of date addons. The Notes line provides a basic description that will show in the Warcraft addon management dialog as will what is on the Title line.
Actual comments can be added to the file by using a single pound sign (#) at the beginning of the line.
## Interface: 40000
## Title: A simple combat HUD
## Version: 1.0.0.1
## Author: Richard Chambers
## Notes: Provides a simple status bar showing the amount of health and
power of the player as a Heads Up Display.
...
The .toc file allows for two directives for saving variables allowing an addon to save state information when the player logs out in order to return to the same state the next time the player logs in. Saved variables are on an addon basis, meaning that those variables and their values are available for all characters of the player, and/or on a character basis, meaning that those variables and their values are available only to a specific character.
## SavedVariables: SimpleCombatHudDB
## SavedVariablesPerCharacter: SimpleCombatHudPerCharDB
...
The main.lua File
The file main.lua contains the Lua source code for the addon. The World of Warcraft client is event driven. There are many events and kinds of events so the addon must register for the specific events that it wishes to receive. Each frame widget has an OnEvent
method which needs to be overridden in order to receive events for which the frame is registered. So the basic procedure is to:
- Create the frame
- Add your own
OnEvent
handler to the frame - Register for the events you want the frame widget to handle
In order to make the Lua source code easier to read and to understand, a convention used is to create an event handler that has a small body of source to just dispatch event messages to other functions. Event handlers are written as functions for specific events and the event dispatcher checks to see if a function exists for the event or not. If the frame has a function by the name of the event defined, then the event dispatcher calls the function to handle the event. If the frame does not have a function by that name, then the event is ignored. Such an OnEvent
handler is shown below using an unnamed, anonymous, or lambda function to override the OnEvent
method of the frame to dispatch event messages to the proper function of the frame.
-- Create our main table for this addon
SimpleCombatHud = SimpleCombatHud or {};
-- Create the frame that we will use for our events
SimpleCombatHud.frame = CreateFrame("Frame", "SimpleCombatHud", UIParent);
SimpleCombatHud.frame:SetFrameStrata("BACKGROUND");
-- Override the OnEvent() method to dispatch events to our processing functions.
-- Notice first argument is self referring to the frame allowing use of colon (:) notation.
SimpleCombatHud.frame:SetScript("OnEvent",
function(self, event, ...) if self[event] then return self[event](self, ...) end end);
After overriding the OnEvent
method of the frame using the above convention, we can now handle events by doing two things:
- Register for the event and
- Provide a handling function for the event using the same name as the event itself
A nice benefit of doing this is that in some cases, the function to handle an event may be reused in other ways. In the Lua source snippet below, we have an event handling function that uses another event handling function under some circumstances. This function handles the event PLAYER_TARGET_CHANGED
by checking to see if there is a unit that has been targeted. If so, then it updates the target's displayed health and power. If not, then the target health and power display frames are hidden.
function SimpleCombatHud.frame:PLAYER_TARGET_CHANGED()
if (UnitExists("target")) then
self:UNIT_HEALTH("target");
self:UNIT_POWER("target");
else
SimpleCombatHud.statusbar["target"].health:Hide();
SimpleCombatHud.statusbar["target"].power:Hide();
end
end
Points of Interest
Playing World of Warcraft is fun and the virtual world is large and interesting though at times repetitive. The standard user interface provided by Blizzard Entertainment looks quite nice and for general playing of the game works well especially with a few well chosen macros added. However serious, hard core players find the standard user interface lacking in a number of ways. Looking through the various World of Warcraft addon web sites, one can find hundreds of addons in various states of repair and usefulness. Some are small and basic, like this example and others are large and complex such as the addon Deadly Boss Mods which provides a great deal of assistance to players in the form of warnings.
The problem with writing addons for World of Warcraft is the lack of documentation. A number of books have been written, there is a large body of source code examples, and there are multiple forums for people to ask questions and receive assistance. However the lack of documentation is an impediment for addon programmers especially as the World of Warcraft programming environment is also a moving target As the development team makes changes with patches and with expansions, addons must be adapted to handle the changes. Much of what an addon presents is based on the various events and how the programmer translates the events to the presented information using the Lua language and the Warcraft API. The writer of addons must be aware that an event with a particular label may not be associated with what it appears to be associated. And an event that is used in an earlier version of Warcraft may no longer be useful in a later version. The various web sites can be helpful in determining what is useful and what is not. Those addons that are maintained and upgraded as new expansions and patches are released and which are used by a large body of the World of Warcraft community are useful resources for an addon programmer.
During development, you will most likely need to print variables and information into the chat area in order to test out what is happening. A very simple debug
print statement such as the one below can be helpful in printing information. There are a number of places in the sample addon where I used this Debug
function to check values and to see what was going on. In those places where it was used, I have left the function commented out to show how it can be used to see what may be causing a problem. Just make sure that when you are done with using it in an area of the source code that you remove the debug calls. Not only would this be a serious performance issue, it would also be a major annoyance to a player. Most players want an addon to do its function and no more.
local Debug = function (str, ...)
if ... then str = str:format(...) end
DEFAULT_CHAT_FRAME:AddMessage(("Addon: %s"):format(str));
end
Play testing an addon during development and maintenance is a must. While Blizzard Entertainment provides a version of the World of Warcraft client that is free to download and play, there are a number of restrictions, one of which is that the use of addons is not allowed. So if you are interested in writing World of Warcraft addons, you will need to be a subscriber. Play testing needs to include all of the various player classes in a variety of circumstances. Before setting out to build your own addon, you should first look for a similar addon. It may very well be that you can take the source code for that addon and either use it as is or with a few tweaks make the modifications you would like to see. And if they are useful mods, contact the developer of the addon and perhaps they will incorporate your changes for the entire community.
An example of play testing with this addon was using it with characters that had pets and those that did not. Play testing, along with the use of the Debug function allowed me to collect a variety of experiences to check that the addon was providing a reasonably accurate display of information. I needed to check the addon in a variety of environments and with a variety of character classes and to then investigate unusual behavior. One such behavior was the target's power showing improperly when some Non-Player Characters were selected as the target. It turned out to be due to the fact that some Non-Player Characters have a maximum power of zero which in the original source code ended up resulting in a divide by zero issue.
Developers of popular addons will often have a mechanism for people who find the addon useful to make a donation to the development team. Blizzard Entertainment has an addon policy which describes some of the basic do's and don'ts for addons. If you go to the World of Warcraft web site and do a search for addon policy, you should be able to find it. The basics are:
- You cannot charge for it though you can accept donations
- The addon must not have advertisements (including advertisements for donations) or objectionable material
- The source must be open and visible and inspectable, and
- Addon behavior must not adversely affect the game and must abide by the Terms of Use and the license agreement. What this basically means is that for most people writing of a World of Warcraft addon will be a fun and interesting effort and not a way to make money, at least not and be within the official addon policy.
History
- November 25, 2011 - Updated the main.lua file to correct the defect found in which after doing a zone change, the displayed values for health and power may be out of date.