--[[--------------------------------------------------------------------
Ovale Spell Priority
Copyright (C) 2013 Johnny C. Lam
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License in the LICENSE
file accompanying this program.
--]]--------------------------------------------------------------------
--[[--------------------------------------------------------------------
This file implements parts of the WoW API for development and
unit-testing.
This file is not meant to be loaded into the addon. It should be
used only outside of the WoW environment, such as when loaded by a
standalone Lua 5.1 interpreter.
--]]--------------------------------------------------------------------
-- Globally-accessible module table.
WoWAPI = {}
--
local self_state = {}
local self_privateSymbol = {
["ExportSymbols"] = true,
["Initialize"] = true,
}
-- Metatable to provide __index method to tables so that if the requested key
-- is missing from the table, then a new key is inserted with the value being
-- the same as the missing key.
local KeysAreMissingValuesMetatable = {
__index = function(t, k)
rawset(t, k, k)
return k
end,
}
--
--
function DeepCopy(orig)
local orig_type = type(orig)
local copy
if orig_type == 'table' then
copy = {}
for orig_key, orig_value in next, orig, nil do
copy[DeepCopy(orig_key)] = DeepCopy(orig_value)
end
setmetatable(copy, DeepCopy(getmetatable(orig)))
else -- number, string, boolean, etc
copy = orig
end
return copy
end
--
--
--[[--------------------------------
Fake library implementations.
--]]--------------------------------
-- AceAddon-3.0
local AceAddon = nil
do
local lib = {}
AceAddon = lib
lib.initializationQueue = {}
local prototype = {}
prototype.GetModule = function(addon, name)
addon.modules = addon.modules or {}
return addon.modules[name]
end
prototype.GetName = function(addon)
return addon.moduleName or addon.name
end
prototype.IterateModules = function(addon)
return pairs(addon.modules)
end
prototype.NewModule = function(addon, name, ...)
local args = { ... }
local mod = lib:NewAddon(string.format("%s_%s", addon.name, name))
mod.moduleName = name
-- Embed methods from named libraries.
for _, libName in ipairs(args) do
local lib = LibStub(libName)
if lib then
for k, v in pairs(lib) do
mod[k] = v
end
end
end
addon.modules = addon.modules or {}
addon.modules[name] = mod
return mod
end
lib.GetAddon = function(lib, name)
lib.addons = lib.addons or {}
return lib.addons[name]
end
lib.ADDON_LOADED = function(lib, event)
for _, addon in ipairs(lib.initializationQueue) do
if addon.OnInitialize then
addon:OnInitialize()
end
end
end
lib.IterateAddons = function(lib)
return pairs(lib.addons)
end
lib.NewAddon = function(lib, name, ...)
local addon
local args
if type(name) == "nil" then
addon = {}
name = ...
args = { select(2, ...) }
elseif type(name) == "table" then
addon = name
name = ...
args = { select(2, ...) }
else
addon = {}
args = { ... }
end
-- Copy addon prototype.
for k, v in pairs(prototype) do
addon[k] = v
end
-- Embed methods from named libraries.
for _, libName in ipairs(args) do
local lib = LibStub(libName)
if lib then
for k, v in pairs(lib) do
addon[k] = v
end
end
end
addon.name = name
lib.addons = lib.addons or {}
lib.addons[name] = addon
lib.initializationQueue[#lib.initializationQueue + 1] = addon
return addon
end
end
-- AceConfig-3.0
local AceConfig = nil
do
local lib = {}
AceConfig = lib
lib.RegisterOptionsTable = function(lib, ...) end
end
-- AceConfigDialog-3.0
local AceConfigDialog = nil
do
local lib = {}
AceConfigDialog = lib
lib.AddToBlizOptions = function(lib, ...) end
end
-- AceConsole-3.0
local AceConsole = nil
do
local lib = {}
AceConsole = lib
lib.Print = function(lib, ...)
print(...)
end
lib.Printf = function(lib, ...)
print(string.format(...))
end
end
-- AceDB-3.0
local AceDB = nil
do
local lib = {}
AceDB = lib
lib.New = function(lib, name, template)
template = template or {}
local db = DeepCopy(template)
db.RegisterCallback = function(...) end
return db
end
end
-- AceDBOptions-3.0
local AceDBOptions = nil
do
local lib = {}
AceDBOptions = lib
lib.GetOptionsTable = function(db) end
end
-- AceEvent-3.0
local AceEvent = nil
do
local lib = {}
AceEvent = lib
lib.SendMessage = function(lib, message, ...) end
end
-- AceGUI-3.0
local AceGUI = nil
do
local lib = {}
AceGUI = lib
lib.RegisterWidgetType = function(...) end
end
-- AceLocale-3.0
local AceLocale = nil
do
local lib = {}
AceLocale = lib
lib.GetLocale = function(lib, name)
local L
if lib.locale and lib.locale[name] then
L = lib.locale[name]
else
L = lib:NewLocale(name, nil)
end
return L
end
lib.NewLocale = function(lib, name, locale)
local L = setmetatable({}, KeysAreMissingValuesMetatable)
lib.locale = lib.locale or {}
lib.locale[name] = L
return L
end
end
-- LibBabble-CreatureType-3.0
local LibBabbleCreatureType = nil
do
local lib = {}
LibBabbleCreatureType = lib
lib.GetLookupTable = function(lib)
local tbl = lib.lookupTable or setmetatable({}, KeysAreMissingValuesMetatable)
lib.lookupTable = tbl
return tbl
end
end
-- LibStub
local LibStub = nil
do
local lib = {}
LibStub = lib
lib.library = {
["AceAddon-3.0"] = AceAddon,
["AceConfig-3.0"] = AceConfig,
["AceConfigDialog-3.0"] = AceConfigDialog,
["AceConsole-3.0"] = AceConsole,
["AceDB-3.0"] = AceDB,
["AceDBOptions-3.0"] = AceDBOptions,
["AceEvent-3.0"] = AceEvent,
["AceGUI-3.0"] = AceGUI,
["AceLocale-3.0"] = AceLocale,
["LibBabble-CreatureType-3.0"] = LibBabbleCreatureType,
}
local mt = {
__call = function(lib, name, flag)
return lib:GetLibrary(name, flag)
end,
}
lib.GetLibrary = function(lib, name, flag)
return lib.library[name]
end
setmetatable(lib, mt)
end
--
--
--[[----------------------
FrameXML/Constants
--]]----------------------
-- Inventory slots
WoWAPI.INVSLOT_AMMO = 0
WoWAPI.INVSLOT_HEAD = 1
WoWAPI.INVSLOT_NECK = 2
WoWAPI.INVSLOT_SHOULDER = 3
WoWAPI.INVSLOT_BODY = 4
WoWAPI.INVSLOT_CHEST = 5
WoWAPI.INVSLOT_WAIST = 6
WoWAPI.INVSLOT_LEGS = 7
WoWAPI.INVSLOT_FEET = 8
WoWAPI.INVSLOT_WRIST = 9
WoWAPI.INVSLOT_HAND = 10
WoWAPI.INVSLOT_FINGER1 = 11
WoWAPI.INVSLOT_FINGER2 = 12
WoWAPI.INVSLOT_TRINKET1 = 13
WoWAPI.INVSLOT_TRINKET2 = 14
WoWAPI.INVSLOT_BACK = 15
WoWAPI.INVSLOT_MAINHAND = 16
WoWAPI.INVSLOT_OFFHAND = 17
WoWAPI.INVSLOT_RANGED = 18
WoWAPI.INVSLOT_TABARD = 19
WoWAPI.INVSLOT_FIRST_EQUIPPED = WoWAPI.INVSLOT_HEAD
WoWAPI.INVSLOT_LAST_EQUIPPED = WoWAPI.INVSLOT_TABARD
-- Power Types
WoWAPI.SPELL_POWER_MANA = 0
WoWAPI.SPELL_POWER_RAGE = 1
WoWAPI.SPELL_POWER_FOCUS = 2
WoWAPI.SPELL_POWER_ENERGY = 3
--WoWAPI.SPELL_POWER_CHI = 4 -- This is obsolete now.
WoWAPI.SPELL_POWER_RUNES = 5
WoWAPI.SPELL_POWER_RUNIC_POWER = 6
WoWAPI.SPELL_POWER_SOUL_SHARDS = 7
WoWAPI.SPELL_POWER_ECLIPSE = 8
WoWAPI.SPELL_POWER_HOLY_POWER = 9
WoWAPI.SPELL_POWER_ALTERNATE_POWER = 10
WoWAPI.SPELL_POWER_DARK_FORCE = 11
WoWAPI.SPELL_POWER_CHI = 12
WoWAPI.SPELL_POWER_SHADOW_ORBS = 13
WoWAPI.SPELL_POWER_BURNING_EMBERS = 14
WoWAPI.SPELL_POWER_DEMONIC_FURY = 15
WoWAPI.RAID_CLASS_COLORS = {
["HUNTER"] = { r = 0.67, g = 0.83, b = 0.45, colorStr = "ffabd473" },
["WARLOCK"] = { r = 0.58, g = 0.51, b = 0.79, colorStr = "ff9482c9" },
["PRIEST"] = { r = 1.0, g = 1.0, b = 1.0, colorStr = "ffffffff" },
["PALADIN"] = { r = 0.96, g = 0.55, b = 0.73, colorStr = "fff58cba" },
["MAGE"] = { r = 0.41, g = 0.8, b = 0.94, colorStr = "ff69ccf0" },
["ROGUE"] = { r = 1.0, g = 0.96, b = 0.41, colorStr = "fffff569" },
["DRUID"] = { r = 1.0, g = 0.49, b = 0.04, colorStr = "ffff7d0a" },
["SHAMAN"] = { r = 0.0, g = 0.44, b = 0.87, colorStr = "ff0070de" },
["WARRIOR"] = { r = 0.78, g = 0.61, b = 0.43, colorStr = "ffc79c6e" },
["DEATHKNIGHT"] = { r = 0.77, g = 0.12 , b = 0.23, colorStr = "ffc41f3b" },
["MONK"] = { r = 0.0, g = 1.00 , b = 0.59, colorStr = "ff00ff96" },
}
--[[--------------------------
FrameXML/GlobalStrings
--]]--------------------------
WoWAPI.ITEM_LEVEL = "Item Level %d"
--[[--------------------------------------------------------------------
debugprofilestop() is a non-standard Lua function that returns the
current time in milliseconds.
This is a trivial implementation to just get the Profiler module
working.
--]]--------------------------------------------------------------------
WoWAPI.debugprofilestop = function()
return 0
end
--[[--------------------------------------------------------------------
strsplit() is a non-standard Lua function that splits a string and
returns multiple return values for each substring delimited by the
named delimiter character.
This implementation is taken verbatim from:
http://lua-users.org/wiki/SplitJoin
--]]--------------------------------------------------------------------
WoWAPI.strsplit = function(delim, str, maxNb)
-- Fix up '.' character class.
delim = string.gsub(delim, "%.", "%%.")
-- Eliminate bad cases...
if string.find(str, delim) == nil then
return str
end
if maxNb == nil or maxNb < 1 then
maxNb = 0 -- No limit
end
local result = {}
local pat = "(.-)" .. delim .. "()"
local nb = 0
local lastPos
for part, pos in string.gfind(str, pat) do
nb = nb + 1
result[nb] = part
lastPos = pos
if nb == maxNb then break end
end
-- Handle the last field
if nb ~= maxNb then
result[nb + 1] = string.sub(str, lastPos)
end
return unpack(result)
end
--[[--------------------------------------------------------------------
wipe() is a non-standard Lua function that clears the contents of a
table and leaves the table pointer intact.
--]]--------------------------------------------------------------------
WoWAPI.wipe = function(t)
for k in pairs(t) do
t[k] = nil
end
end
--[[-------------------------------------------------
Fake Blizzard API functions for unit testing.
--]]-------------------------------------------------
WoWAPI.CreateFrame = function(...)
return {
SetOwner = function(...) end,
}
end
WoWAPI.GetAuctionItemSubClasses = function(classIndex)
return
"One-Handed Axes",
"Two-Handed Axes",
"Bows",
"Guns",
"One-Handed Maces",
"Two-Handed Maces",
"Polearms",
"One-Handed Swords",
"Two-Handed Swords",
"Staves",
"Fist Weapons",
"Miscellaneous",
"Daggers",
"Thrown",
"Crossbows",
"Wands",
"Fishing Poles"
end
WoWAPI.GetItemInfo = function(item)
if type(item) == "number" then
item = string.format("Item Name Of %d", item)
end
return item
end
WoWAPI.GetSpellInfo = function(spell)
if type(spell) == "number" then
spell = string.format("Spell Name Of %d", spell)
end
return spell
end
WoWAPI.RegisterAddonMessagePrefix = function(prefixString) end
WoWAPI.UnitClass = function()
local class = self_state.class
return class, class
end
WoWAPI.UnitLevel = function()
return self_state.level
end
WoWAPI.bit = {
band = function(...) end,
bor = function(...) end,
}
WoWAPI.LibStub = LibStub
--
--
local function FileExists(filename, directory, verbose)
if directory then
filename = directory .. filename
end
local fh = io.open(filename, "r")
if fh then
fh:close()
return true
else
if verbose then
print(string.format("Warning: '%s' not found.", filename))
end
return false
end
end
--
--
function WoWAPI:Initialize(addonName, state)
state = state or {}
for k, v in pairs(state) do
self_state[k] = v
end
self_state.addonName = addonName
end
-- Export symbols to the given namespace, taking care not to overwrite existing symbols.
function WoWAPI:ExportSymbols(namespace)
-- Default to adding symbols to the global namespace.
namespace = namespace or _G
for k, v in pairs(self) do
if not self_privateSymbol[k] then
namespace[k] = namespace[k] or v
end
end
-- Special handling for strsplit() to add to "string" module.
string.split = string.split or WoWAPI.strsplit
-- Special handling for wipe() to add to "table" module.
table.wipe = table.wipe or WoWAPI.wipe
end
--[[--------------------------------------------------------------------
LoadAddOnFile() dispatches to the proper method to load the file
based on the file extension.
--]]--------------------------------------------------------------------
function WoWAPI:LoadAddonFile(filename, directory, verbose)
local s = directory and (directory .. filename) or filename
directory, filename = string.match(s, "^(.+/)([^/]+[.][%w]+)$")
if not directory then
filename = s
end
if string.find(filename, "[.]lua$") then
return self:LoadLua(filename, directory, verbose)
elseif string.find(filename, "[.]toc$") then
return self:LoadTOC(filename, directory, verbose)
elseif string.find(filename, "[.]xml$") then
return self:LoadXML(filename, directory, verbose)
end
end
--[[--------------------------------------------------------------------
LoadAddonFile() does the equivalent of dofile(), but munges the WoW
addon file line that uses ... to get the file arguments.
--]]--------------------------------------------------------------------
function WoWAPI:LoadLua(filename, directory, verbose)
if directory then
filename = directory .. filename
end
if verbose then
print(string.format("Loading Lua: %s", filename))
end
local ok = FileExists(filename, nil, verbose)
if ok then
local list = {}
for line in io.lines(filename) do
local varName = string.match(line, "^local%s+([%w_]+)%s*,[%w%s_,]*=%s*[.][.][.]%s*$")
if varName then
line = string.format("local %s = %q", varName, self_state.addonName)
end
table.insert(list, line)
end
local fileString = table.concat(list, "\n")
local func = loadstring(fileString)
if func then
func()
else
print(string.format("Error loading '%s'.", filename))
ok = false
end
end
return ok
end
--[[--------------------------------------------------------------------
LoadTOC() loads all of the addon's files listed in the TOC file.
--]]--------------------------------------------------------------------
function WoWAPI:LoadTOC(filename, directory, verbose)
if directory then
filename = directory .. filename
end
if verbose then
print(string.format("Loading TOC: %s", filename))
end
local ok = FileExists(filename, nil, verbose)
if ok then
local list = {}
for line in io.lines(filename) do
line = string.gsub(line, "\\", "/")
local t = {}
t.directory, t.file = string.match(line, "^([^#]+/)([^/]+[.][%w]+)$")
if t.directory then
if directory then
t.directory = directory .. t.directory
end
else
t.directory = directory
t.file = string.match(line, "^[%w_]+[.][%w]+$")
end
if t.file then
table.insert(list, t)
end
end
for _, t in ipairs(list) do
if string.find(t.file, "[.]lua$") then
ok = ok and self:LoadLua(t.file, t.directory, verbose)
elseif string.find(t.file, "[.]xml$") then
ok = ok and self:LoadXML(t.file, t.directory, verbose)
end
if not ok then
break
end
end
end
return ok
end
--[[--------------------------------------------------------------------
LoadXML() loads all of the addon's Lua files listed in the XML file.
--]]--------------------------------------------------------------------
function WoWAPI:LoadXML(filename, directory, verbose)
if directory then
filename = directory .. filename
end
if verbose then
print(string.format("Loading XML: %s", filename))
end
local ok = FileExists(filename, nil, verbose)
if ok then
local list = {}
for line in io.lines(filename) do
local s = string.match(line, '