Initial import of shootyepgp 2.0

80% rewrite of shootyepgp 1.x
compatible with shootyepgp 1.x
This commit is contained in:
Road-block
2017-08-08 15:43:54 +03:00
parent 773301b311
commit df067abf2c
22 changed files with 18496 additions and 0 deletions
+982
View File
@@ -0,0 +1,982 @@
--[[
Name: AceAddon-2.0
Revision: $Rev: 14832 $
Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team)
Inspired By: Ace 1.x by Turan (turan@gryphon.com)
Website: http://www.wowace.com/
Documentation: http://www.wowace.com/index.php/AceAddon-2.0
SVN: http://svn.wowace.com/root/trunk/Ace2/AceAddon-2.0
Description: Base for all Ace addons to inherit from.
Dependencies: AceLibrary, AceOO-2.0, AceEvent-2.0, (optional) AceConsole-2.0
]]
local MAJOR_VERSION = "AceAddon-2.0"
local MINOR_VERSION = "$Revision: 14832 $"
-- This ensures the code is only executed if the libary doesn't already exist, or is a newer version
if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary.") end
if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end
if not AceLibrary:HasInstance("AceOO-2.0") then error(MAJOR_VERSION .. " requires AceOO-2.0.") end
-- Localization
local STANDBY, TITLE, NOTES, VERSION, AUTHOR, DATE, CATEGORY, EMAIL, WEBSITE, CATEGORIES, ABOUT, PRINT_ADDON_INFO
if GetLocale() == "deDE" then
STANDBY = "|cffff5050(Standby)|r" -- capitalized
TITLE = "Titel"
NOTES = "Anmerkung"
VERSION = "Version"
AUTHOR = "Autor"
DATE = "Datum"
CATEGORY = "Kategorie"
EMAIL = "E-mail"
WEBSITE = "Webseite"
ABOUT = "\195\188ber"
PRINT_ADDON_INFO = "Gibt Addondaten aus"
CATEGORIES = {
["Action Bars"] = "Aktionsleisten",
["Auction"] = "Auktion",
["Audio"] = "Audio",
["Battlegrounds/PvP"] = "Schlachtfeld/PvP",
["Buffs"] = "Buffs",
["Chat/Communication"] = "Chat/Kommunikation",
["Druid"] = "Druide",
["Hunter"] = "Jäger",
["Mage"] = "Magier",
["Paladin"] = "Paladin",
["Priest"] = "Priester",
["Rogue"] = "Schurke",
["Shaman"] = "Schamane",
["Warlock"] = "Hexenmeister",
["Warrior"] = "Krieger",
["Healer"] = "Heiler",
["Tank"] = "Tank", -- noone use "Brecher"...
["Caster"] = "Caster",
["Combat"] = "Kampf",
["Compilations"] = "Compilations", -- whats that o_O
["Data Export"] = "Datenexport",
["Development Tools"] = "Entwicklungs Tools",
["Guild"] = "Gilde",
["Frame Modification"] = "Frame Modifikation",
["Interface Enhancements"] = "Interface Verbesserungen",
["Inventory"] = "Inventar",
["Library"] = "Library",
["Map"] = "Map",
["Mail"] = "Mail",
["Miscellaneous"] = "Diverses",
["Quest"] = "Quest",
["Raid"] = "Schlachtzug",
["Tradeskill"] = "Handelsf\195\164higkeit",
["UnitFrame"] = "UnitFrame",
}
elseif GetLocale() == "frFR" then
STANDBY = "|cffff5050(attente)|r"
TITLE = "Titre"
NOTES = "Notes"
VERSION = "Version"
AUTHOR = "Auteur"
DATE = "Date"
CATEGORY = "Cat\195\169gorie"
EMAIL = "E-mail"
WEBSITE = "Site web"
ABOUT = "A propos"
PRINT_ADDON_INFO = "Afficher les informations sur l'addon"
CATEGORIES = {
["Action Bars"] = "Barres d'action",
["Auction"] = "H\195\180tel des ventes",
["Audio"] = "Audio",
["Battlegrounds/PvP"] = "Champs de bataille/JcJ",
["Buffs"] = "Buffs",
["Chat/Communication"] = "Chat/Communication",
["Druid"] = "Druide",
["Hunter"] = "Chasseur",
["Mage"] = "Mage",
["Paladin"] = "Paladin",
["Priest"] = "Pr\195\170tre",
["Rogue"] = "Voleur",
["Shaman"] = "Chaman",
["Warlock"] = "D\195\169moniste",
["Warrior"] = "Guerrier",
["Healer"] = "Soigneur",
["Tank"] = "Tank",
["Caster"] = "Casteur",
["Combat"] = "Combat",
["Compilations"] = "Compilations",
["Data Export"] = "Exportation de donn\195\169es",
["Development Tools"] = "Outils de d\195\169veloppement",
["Guild"] = "Guilde",
["Frame Modification"] = "Modification des fen\195\170tres",
["Interface Enhancements"] = "Am\195\169liorations de l'interface",
["Inventory"] = "Inventaire",
["Library"] = "Biblioth\195\168ques",
["Map"] = "Carte",
["Mail"] = "Courrier",
["Miscellaneous"] = "Divers",
["Quest"] = "Qu\195\170tes",
["Raid"] = "Raid",
["Tradeskill"] = "M\195\169tiers",
["UnitFrame"] = "Fen\195\170tres d'unit\195\169",
}
elseif GetLocale() == "koKR" then
STANDBY = "|cffff5050(사용가능)|r"
TITLE = "제목"
NOTES = "노트"
VERSION = "버전"
AUTHOR = "저작�"
DATE = "날짜"
CATEGORY = "분류"
EMAIL = "E-mail"
WEBSITE = "웹사�트"
ABOUT = "ì •ë³´"
PRINT_ADDON_INFO = "애드온 정보 출력"
CATEGORIES = {
["Action Bars"] = "액션바",
["Auction"] = "경매",
["Audio"] = "�향",
["Battlegrounds/PvP"] = "전장/PvP",
["Buffs"] = "버프",
["Chat/Communication"] = "대화/�사소통",
["Druid"] = "드루�드",
["Hunter"] = "사냥꾼",
["Mage"] = "마법사",
["Paladin"] = "성기사",
["Priest"] = "사제",
["Rogue"] = "��",
["Shaman"] = "주술사",
["Warlock"] = "�마법사",
["Warrior"] = "전사",
["Healer"] = "�러",
["Tank"] = "탱커",
["Caster"] = "�스터",
["Combat"] = "전투",
["Compilations"] = "복합",
["Data Export"] = "�료 출력",
["Development Tools"] = "개발 �구",
["Guild"] = "길드",
["Frame Modification"] = "구조 변경",
["Interface Enhancements"] = "�터페�스 강화",
["Inventory"] = "�벤토리",
["Library"] = "��브러리",
["Map"] = "지�",
["Mail"] = "우편",
["Miscellaneous"] = "기타",
["Quest"] = "퀘스트",
["Raid"] = "공격대",
["Tradeskill"] = "전문기술",
["UnitFrame"] = "유닛 프레임",
}
elseif GetLocale() == "zhTW" then
STANDBY = "|cffff5050(待命)|r"
TITLE = "標題"
NOTES = "註記"
VERSION = "版本"
AUTHOR = "作者"
DATE = "日期"
CATEGORY = "類別"
EMAIL = "E-mail"
WEBSITE = "網站"
ABOUT = "關於"
PRINT_ADDON_INFO = "顯示�件資訊"
CATEGORIES = {
["Action Bars"] = "動作列",
["Auction"] = "�賣",
["Audio"] = "音樂",
["Battlegrounds/PvP"] = "戰場/PvP",
["Buffs"] = "增益",
["Chat/Communication"] = "�天/通訊",
["Druid"] = "德魯伊",
["Hunter"] = "�人",
["Mage"] = "法師",
["Paladin"] = "�騎士",
["Priest"] = "牧師",
["Rogue"] = "盜賊",
["Shaman"] = "薩滿",
["Warlock"] = "術士",
["Warrior"] = "戰士",
["Healer"] = "治療者",
["Tank"] = "�克",
["Caster"] = "施法者",
["Combat"] = "戰鬥",
["Compilations"] = "編輯",
["Data Export"] = "資料匯出",
["Development Tools"] = "開發工具",
["Guild"] = "公會",
["Frame Modification"] = "框架修改",
["Interface Enhancements"] = "介�增強",
["Inventory"] = "背包",
["Library"] = "資料庫",
["Map"] = "地圖",
["Mail"] = "郵件",
["Miscellaneous"] = "綜�",
["Quest"] = "任務",
["Raid"] = "團隊",
["Tradeskill"] = "商業技能",
["UnitFrame"] = "單�框架",
}
elseif GetLocale() == "zhCN" then
STANDBY = "|cffff5050(\230\154\130\230\140\130)|r"
TITLE = "\230\160\135\233\162\152"
NOTES = "\233\153\132\230\179\168"
VERSION = "\231\137\136\230\156\172"
AUTHOR = "\228\189\156\232\128\133"
DATE = "\230\151\165\230\156\159"
CATEGORY = "\229\136\134\231\177\187"
EMAIL = "\231\148\181\229\173\144\233\130\174\228\187\182"
WEBSITE = "\231\189\145\231\171\153"
ABOUT = "\229\133\179\228\186\142"
PRINT_ADDON_INFO = "\229\141\176\229\136\151\229\135\186\230\143\146\228\187\182\228\191\161\230\129\175"
CATEGORIES = {
["Action Bars"] = "\229\138\168\228\189\156\230\157\161",
["Auction"] = "\230\139\141\229\141\150",
["Audio"] = "\233\159\179\233\162\145",
["Battlegrounds/PvP"] = "\230\136\152\229\156\186/PvP",
["Buffs"] = "\229\162\158\231\155\138\233\173\148\230\179\149",
["Chat/Communication"] = "\232\129\138\229\164\169/\228\186\164\230\181\129",
["Druid"] = "\229\190\183\233\178\129\228\188\138",
["Hunter"] = "\231\140\142\228\186\186",
["Mage"] = "\230\179\149\229\184\136",
["Paladin"] = "\229\156\163\233\170\145\229\163\171",
["Priest"] = "\231\137\167\229\184\136",
["Rogue"] = "\231\155\151\232\180\188",
["Shaman"] = "\232\144\168\230\187\161\231\165\173\229\143\184",
["Warlock"] = "\230\156\175\229\163\171",
["Warrior"] = "\230\136\152\229\163\171",
-- ["Healer"] = "\230\178\187\231\150\151\228\191\157\233\154\156",
-- ["Tank"] = "\232\191\145\230\136\152\230\142\167\229\136\182",
-- ["Caster"] = "\232\191\156\231\168\139\232\190\147\229\135\186",
["Combat"] = "\230\136\152\230\150\151",
["Compilations"] = "\231\188\150\232\175\145",
["Data Export"] = "\230\149\176\230\141\174\229\175\188\229\135\186",
["Development Tools"] = "\229\188\128\229\143\145\229\183\165\229\133\183",
["Guild"] = "\229\133\172\228\188\154",
["Frame Modification"] = "\230\161\134\230\158\182\228\191\174\230\148\185",
["Interface Enhancements"] = "\231\149\140\233\157\162\229\162\158\229\188\186",
["Inventory"] = "\232\131\140\229\140\133",
["Library"] = "\229\186\147",
["Map"] = "\229\156\176\229\155\190",
["Mail"] = "\233\130\174\228\187\182",
["Miscellaneous"] = "\230\157\130\233\161\185",
["Quest"] = "\228\187\187\229\138\161",
["Raid"] = "\229\155\162\233\152\159",
["Tradeskill"] = "\229\149\134\228\184\154\230\138\128\232\131\189",
["UnitFrame"] = "\229\164\180\229\131\143\230\161\134\230\158\182",
}
else -- enUS
STANDBY = "|cffff5050(standby)|r"
TITLE = "Title"
NOTES = "Notes"
VERSION = "Version"
AUTHOR = "Author"
DATE = "Date"
CATEGORY = "Category"
EMAIL = "E-mail"
WEBSITE = "Website"
ABOUT = "About"
PRINT_ADDON_INFO = "Print out addon info"
CATEGORIES = {
["Action Bars"] = "Action Bars",
["Auction"] = "Auction",
["Audio"] = "Audio",
["Battlegrounds/PvP"] = "Battlegrounds/PvP",
["Buffs"] = "Buffs",
["Chat/Communication"] = "Chat/Communication",
["Druid"] = "Druid",
["Hunter"] = "Hunter",
["Mage"] = "Mage",
["Paladin"] = "Paladin",
["Priest"] = "Priest",
["Rogue"] = "Rogue",
["Shaman"] = "Shaman",
["Warlock"] = "Warlock",
["Warrior"] = "Warrior",
["Healer"] = "Healer",
["Tank"] = "Tank",
["Caster"] = "Caster",
["Combat"] = "Combat",
["Compilations"] = "Compilations",
["Data Export"] = "Data Export",
["Development Tools"] = "Development Tools",
["Guild"] = "Guild",
["Frame Modification"] = "Frame Modification",
["Interface Enhancements"] = "Interface Enhancements",
["Inventory"] = "Inventory",
["Library"] = "Library",
["Map"] = "Map",
["Mail"] = "Mail",
["Miscellaneous"] = "Miscellaneous",
["Quest"] = "Quest",
["Raid"] = "Raid",
["Tradeskill"] = "Tradeskill",
["UnitFrame"] = "UnitFrame",
}
end
setmetatable(CATEGORIES, { __index = function(self, key) -- case-insensitive
local lowerKey = string.lower(key)
for k,v in CATEGORIES do
if string.lower(k) == lowerKey then
return v
end
end
end })
-- Create the library object
local AceOO = AceLibrary("AceOO-2.0")
local AceAddon = AceOO.Class()
local AceEvent
local AceConsole
local AceModuleCore
function AceAddon:ToString()
return "AceAddon"
end
local function print(text)
DEFAULT_CHAT_FRAME:AddMessage(text)
end
function AceAddon:ADDON_LOADED(name)
while table.getn(self.nextAddon) > 0 do
local addon = table.remove(self.nextAddon, 1)
table.insert(self.addons, addon)
if not self.addons[name] then
self.addons[name] = addon
end
self:InitializeAddon(addon, name)
end
end
local function RegisterOnEnable(self)
if DEFAULT_CHAT_FRAME and DEFAULT_CHAT_FRAME.defaultLanguage then -- HACK
AceAddon.playerLoginFired = true
end
if AceAddon.playerLoginFired then
AceAddon.addonsStarted[self] = true
if (type(self.IsActive) ~= "function" or self:IsActive()) and (not AceModuleCore or not AceModuleCore:IsModule(self) or AceModuleCore:IsModuleActive(self)) then
local current = self.class
while true do
if current == AceOO.Class then
break
end
if current.mixins then
for mixin in pairs(current.mixins) do
if type(mixin.OnEmbedEnable) == "function" then
mixin:OnEmbedEnable(self)
end
end
end
current = current.super
end
if type(self.OnEnable) == "function" then
self:OnEnable()
end
end
else
if not AceAddon.addonsToOnEnable then
AceAddon.addonsToOnEnable = {}
end
table.insert(AceAddon.addonsToOnEnable, self)
end
end
local function stripSpaces(text)
if type(text) == "string" then
return (string.gsub(string.gsub(text, "^%s*(.-)%s*$", "%1"), "%s%s+", " "))
end
return text
end
function AceAddon:InitializeAddon(addon, name)
if addon.name == nil then
addon.name = name
end
if GetAddOnMetadata then
-- TOC checks
if addon.title == nil then
addon.title = GetAddOnMetadata(name, "Title")
if addon.title then
local num = string.find(addon.title, " |cff7fff7f %-Ace2%-|r$")
if num then
addon.title = string.sub(addon.title, 1, num - 1)
end
addon.title = stripSpaces(addon.title)
end
end
if addon.notes == nil then
addon.notes = GetAddOnMetadata(name, "Notes")
addon.notes = stripSpaces(addon.notes)
end
if addon.version == nil then
addon.version = GetAddOnMetadata(name, "Version")
if addon.version then
if string.find(addon.version, "%$Revision: (%d+) %$") then
addon.version = string.gsub(addon.version, "%$Revision: (%d+) %$", "%1")
elseif string.find(addon.version, "%$Rev: (%d+) %$") then
addon.version = string.gsub(addon.version, "%$Rev: (%d+) %$", "%1")
elseif string.find(addon.version, "%$LastChangedRevision: (%d+) %$") then
addon.version = string.gsub(addon.version, "%$LastChangedRevision: (%d+) %$", "%1")
end
end
addon.version = stripSpaces(addon.version)
end
if addon.author == nil then
addon.author = GetAddOnMetadata(name, "Author")
addon.author = stripSpaces(addon.author)
end
if addon.date == nil then
addon.date = GetAddOnMetadata(name, "X-Date") or GetAddOnMetadata(name, "X-ReleaseDate")
if addon.date then
if string.find(addon.date, "%$Date: (.-) %$") then
addon.date = string.gsub(addon.date, "%$Date: (.-) %$", "%1")
elseif string.find(addon.date, "%$LastChangedDate: (.-) %$") then
addon.date = string.gsub(addon.date, "%$LastChangedDate: (.-) %$", "%1")
end
end
addon.date = stripSpaces(addon.date)
end
if addon.category == nil then
addon.category = GetAddOnMetadata(name, "X-Category")
addon.category = stripSpaces(addon.category)
end
if addon.email == nil then
addon.email = GetAddOnMetadata(name, "X-eMail") or GetAddOnMetadata(name, "X-Email")
addon.email = stripSpaces(addon.email)
end
if addon.website == nil then
addon.website = GetAddOnMetadata(name, "X-Website")
addon.website = stripSpaces(addon.website)
end
end
local current = addon.class
while true do
if current == AceOO.Class then
break
end
if current.mixins then
for mixin in pairs(current.mixins) do
if type(mixin.OnEmbedInitialize) == "function" then
mixin:OnEmbedInitialize(addon, name)
end
end
end
current = current.super
end
if type(addon.OnInitialize) == "function" then
addon:OnInitialize(name)
end
RegisterOnEnable(addon)
end
function AceAddon.prototype:PrintAddonInfo()
local x
if self.title then
x = "|cffffff7f" .. tostring(self.title) .. "|r"
elseif self.name then
x = "|cffffff7f" .. tostring(self.name) .. "|r"
else
x = "|cffffff7f<" .. tostring(self.class) .. " instance>|r"
end
if type(self.IsActive) == "function" then
if not self:IsActive() then
x = x .. " " .. STANDBY
end
end
if self.version then
x = x .. " - |cffffff7f" .. tostring(self.version) .. "|r"
end
if self.notes then
x = x .. " - " .. tostring(self.notes)
end
print(x)
if self.author then
print(" - |cffffff7f" .. AUTHOR .. ":|r " .. tostring(self.author))
end
if self.date then
print(" - |cffffff7f" .. DATE .. ":|r " .. tostring(self.date))
end
if self.category then
local category = CATEGORIES[self.category]
if category then
print(" - |cffffff7f" .. CATEGORY .. ":|r " .. category)
end
end
if self.email then
print(" - |cffffff7f" .. EMAIL .. ":|r " .. tostring(self.email))
end
if self.website then
print(" - |cffffff7f" .. WEBSITE .. ":|r " .. tostring(self.website))
end
end
local options
function AceAddon:GetAceOptionsDataTable(target)
if not options then
options = {
about = {
name = ABOUT,
desc = PRINT_ADDON_INFO,
type = "execute",
func = "PrintAddonInfo",
order = -1,
}
}
end
return options
end
function AceAddon:PLAYER_LOGIN()
self.playerLoginFired = true
if self.addonsToOnEnable then
while table.getn(self.addonsToOnEnable) > 0 do
local addon = table.remove(self.addonsToOnEnable, 1)
self.addonsStarted[addon] = true
if (type(addon.IsActive) ~= "function" or addon:IsActive()) and (not AceModuleCore or not AceModuleCore:IsModule(addon) or AceModuleCore:IsModuleActive(addon)) then
local current = addon.class
while true do
if current == AceOO.Class then
break
end
if current.mixins then
for mixin in pairs(current.mixins) do
if type(mixin.OnEmbedEnable) == "function" then
mixin:OnEmbedEnable(addon)
end
end
end
current = current.super
end
if type(addon.OnEnable) == "function" then
addon:OnEnable()
end
end
end
self.addonsToOnEnable = nil
end
end
function AceAddon.prototype:Inject(t)
AceAddon:argCheck(t, 2, "table")
for k,v in pairs(t) do
self[k] = v
end
end
function AceAddon.prototype:init()
if not AceEvent then
error(MAJOR_VERSION .. " requires AceEvent-2.0", 4)
end
AceAddon.super.prototype.init(self)
self.super = self.class.prototype
AceAddon:RegisterEvent("ADDON_LOADED", "ADDON_LOADED", true)
table.insert(AceAddon.nextAddon, self)
end
function AceAddon.prototype:ToString()
local x
if type(self.title) == "string" then
x = self.title
elseif type(self.name) == "string" then
x = self.name
else
x = "<" .. tostring(self.class) .. " instance>"
end
if (type(self.IsActive) == "function" and not self:IsActive()) or (AceModuleCore and AceModuleCore:IsModule(addon) and AceModuleCore:IsModuleActive(addon)) then
x = x .. " " .. STANDBY
end
return x
end
AceAddon.new = function(self, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m13, m14, m15, m16, m17, m18, m19, m20)
local class = AceAddon:pcall(AceOO.Classpool, self, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m13, m14, m15, m16, m17, m18, m19, m20)
return class:new()
end
local function external(self, major, instance)
if major == "AceEvent-2.0" then
AceEvent = instance
AceEvent:embed(self)
self:RegisterEvent("PLAYER_LOGIN", "PLAYER_LOGIN", true)
elseif major == "AceConsole-2.0" then
AceConsole = instance
local slashCommands = { "/ace2" }
local _,_,_,enabled,loadable = GetAddOnInfo("Ace")
if not enabled or not loadable then
table.insert(slashCommands, "/ace")
end
local function listAddon(addon, depth)
if not depth then
depth = 0
end
local s = string.rep(" ", depth) .. " - " .. tostring(addon)
if rawget(addon, 'version') then
s = s .. " - |cffffff7f" .. tostring(addon.version) .. "|r"
end
if rawget(addon, 'slashCommand') then
s = s .. " |cffffff7f(" .. tostring(addon.slashCommand) .. ")|r"
end
print(s)
if type(rawget(addon, 'modules')) == "table" then
local i = 0
for k,v in pairs(addon.modules) do
i = i + 1
if i == 6 then
print(string.rep(" ", depth + 1) .. " - more...")
break
else
listAddon(v, depth + 1)
end
end
end
end
local function listNormalAddon(i)
local name,_,_,enabled,loadable = GetAddOnInfo(i)
if not loadable then
enabled = false
end
if self.addons[name] then
local addon = self.addons[name]
if not AceCoreAddon or not AceCoreAddon:IsModule(addon) then
listAddon(addon)
end
else
local s = " - " .. tostring(GetAddOnMetadata(i, "Title") or name)
local version = GetAddOnMetadata(i, "Version")
if version then
if string.find(version, "%$Revision: (%d+) %$") then
version = string.gsub(version, "%$Revision: (%d+) %$", "%1")
elseif string.find(version, "%$Rev: (%d+) %$") then
version = string.gsub(version, "%$Rev: (%d+) %$", "%1")
elseif string.find(version, "%$LastChangedRevision: (%d+) %$") then
version = string.gsub(version, "%$LastChangedRevision: (%d+) %$", "%1")
end
s = s .. " - |cffffff7f" .. version .. "|r"
end
if not enabled then
s = s .. " |cffff0000(disabled)|r"
end
if IsAddOnLoadOnDemand(i) then
s = s .. " |cff00ff00[LoD]|r"
end
print(s)
end
end
local function mySort(alpha, bravo)
return tostring(alpha) < tostring(bravo)
end
AceConsole.RegisterChatCommand(self, slashCommands, {
desc = "AddOn development framework",
name = "Ace2",
type = "group",
args = {
about = {
desc = "Get information about Ace2",
name = "About",
type = "execute",
func = function()
print("|cffffff7fAce2|r - |cffffff7f2.0." .. string.gsub(MINOR_VERSION, "%$Revision: (%d+) %$", "%1") .. "|r - AddOn development framework")
print(" - |cffffff7f" .. AUTHOR .. ":|r Ace Development Team")
print(" - |cffffff7f" .. WEBSITE .. ":|r http://www.wowace.com/")
end
},
list = {
desc = "List addons",
name = "List",
type = "group",
args = {
ace2 = {
desc = "List addons using Ace2",
name = "Ace2",
type = "execute",
func = function()
print("|cffffff7fAddon list:|r")
local AceCoreAddon = AceLibrary:HasInstance("AceCoreAddon-2.0") and AceLibrary("AceCoreAddon-2.0")
table.sort(self.addons, mySort)
for _,v in ipairs(self.addons) do
if not AceCoreAddon or not AceCoreAddon:IsModule(v) then
listAddon(v)
end
end
end
},
all = {
desc = "List all addons",
name = "All",
type = "execute",
func = function()
print("|cffffff7fAddon list:|r")
local AceCoreAddon = AceLibrary:HasInstance("AceCoreAddon-2.0") and AceLibrary("AceCoreAddon-2.0")
local count = GetNumAddOns()
for i = 1, count do
listNormalAddon(i)
end
end
},
enabled = {
desc = "List all enabled addons",
name = "Enabled",
type = "execute",
func = function()
print("|cffffff7fAddon list:|r")
local AceCoreAddon = AceLibrary:HasInstance("AceCoreAddon-2.0") and AceLibrary("AceCoreAddon-2.0")
local count = GetNumAddOns()
for i = 1, count do
local _,_,_,enabled,loadable = GetAddOnInfo(i)
if enabled and loadable then
listNormalAddon(i)
end
end
end
},
disabled = {
desc = "List all disabled addons",
name = "Disabled",
type = "execute",
func = function()
print("|cffffff7fAddon list:|r")
local AceCoreAddon = AceLibrary:HasInstance("AceCoreAddon-2.0") and AceLibrary("AceCoreAddon-2.0")
local count = GetNumAddOns()
for i = 1, count do
local _,_,_,enabled,loadable = GetAddOnInfo(i)
if not enabled or not loadable then
listNormalAddon(i)
end
end
end
},
lod = {
desc = "List all LoadOnDemand addons",
name = "LoadOnDemand",
type = "execute",
func = function()
print("|cffffff7fAddon list:|r")
local AceCoreAddon = AceLibrary:HasInstance("AceCoreAddon-2.0") and AceLibrary("AceCoreAddon-2.0")
local count = GetNumAddOns()
for i = 1, count do
if IsAddOnLoadOnDemand(i) then
listNormalAddon(i)
end
end
end
},
ace1 = {
desc = "List all addons using Ace1",
name = "Ace 1.x",
type = "execute",
func = function()
print("|cffffff7fAddon list:|r")
local count = GetNumAddOns()
for i = 1, count do
local dep1, dep2, dep3, dep4 = GetAddOnDependencies(i)
if dep1 == "Ace" or dep2 == "Ace" or dep3 == "Ace" or dep4 == "Ace" then
listNormalAddon(i)
end
end
end
},
libs = {
desc = "List all libraries using AceLibrary",
name = "Libraries",
type = "execute",
func = function()
if type(AceLibrary) == "table" and type(AceLibrary.libs) == "table" then
print("|cffffff7fLibrary list:|r")
for name, data in pairs(AceLibrary.libs) do
local s
if data.minor then
s = " - " .. tostring(name) .. "." .. tostring(data.minor)
else
s = " - " .. tostring(name)
end
if AceLibrary(name).slashCommand then
s = s .. " |cffffff7f(" .. tostring(AceLibrary(name).slashCommand) .. "|cffffff7f)"
end
print(s)
end
end
end
},
search = {
desc = "Search by name",
name = "Search",
type = "text",
usage = "<keyword>",
input = true,
get = false,
set = function(...)
for i,v in ipairs(arg) do
arg[i] = string.lower(string.gsub(string.gsub(v, '%*', '.*'), '%%', '%%%%'))
end
local count = GetNumAddOns()
for i = 1, count do
local name = GetAddOnInfo(i)
local good = true
for _,v in ipairs(arg) do
if not string.find(string.lower(name), v) then
good = false
break
end
end
if good then
listNormalAddon(i)
end
end
end
}
},
},
enable = {
desc = "Enable addon",
name = "Enable",
type = "text",
usage = "<addon>",
get = false,
set = function(text)
local name,title,_,_,_,reason = GetAddOnInfo(text)
if reason == "MISSING" then
print(string.format("|cffffff7fAce2:|r AddOn %q does not exist", text))
else
EnableAddOn(text)
print(string.format("|cffffff7fAce2:|r %s is now enabled", title or name))
end
end,
},
disable = {
desc = "Disable addon",
name = "Disable",
type = "text",
usage = "<addon>",
get = false,
set = function(text)
local name,title,_,_,_,reason = GetAddOnInfo(text)
if reason == "MISSING" then
print(string.format("|cffffff7fAce2:|r AddOn %q does not exist", text))
else
DisableAddOn(text)
print(string.format("|cffffff7fAce2:|r %s is now disabled", title or name))
end
end,
},
load = {
desc = "Load addon",
name = "Load",
type = "text",
usage = "<addon>",
get = false,
set = function(text)
local name,title,_,_,loadable,reason = GetAddOnInfo(text)
if reason == "MISSING" then
print(string.format("|cffffff7fAce2:|r AddOn %q does not exist.", text))
elseif not loadable then
print(string.format("|cffffff7fAce2:|r AddOn %q is not loadable. Reason: %s", text, reason))
else
LoadAddOn(text)
print(string.format("|cffffff7fAce2:|r %s is now loaded", title or name))
end
end
},
info = {
desc = "Display information",
name = "Information",
type = "execute",
func = function()
local mem, threshold = gcinfo()
print(string.format(" - |cffffff7fMemory usage [|r%.3f MiB|cffffff7f]|r", mem / 1024))
print(string.format(" - |cffffff7fThreshold [|r%.3f MiB|cffffff7f]|r", threshold / 1024))
print(string.format(" - |cffffff7fFramerate [|r%.0f fps|cffffff7f]|r", GetFramerate()))
local bandwidthIn, bandwidthOut, latency = GetNetStats()
bandwidthIn, bandwidthOut = floor(bandwidthIn * 1024), floor(bandwidthOut * 1024)
print(string.format(" - |cffffff7fLatency [|r%.0f ms|cffffff7f]|r", latency))
print(string.format(" - |cffffff7fBandwidth in [|r%.0f B/s|cffffff7f]|r", bandwidthIn))
print(string.format(" - |cffffff7fBandwidth out [|r%.0f B/s|cffffff7f]|r", bandwidthOut))
print(string.format(" - |cffffff7fTotal addons [|r%d|cffffff7f]|r", GetNumAddOns()))
print(string.format(" - |cffffff7fAce2 addons [|r%d|cffffff7f]|r", table.getn(self.addons)))
local ace = 0
local enabled = 0
local disabled = 0
local lod = 0
for i = 1, GetNumAddOns() do
local dep1, dep2, dep3, dep4 = GetAddOnDependencies(i)
if dep1 == "Ace" or dep2 == "Ace" or dep3 == "Ace" or dep4 == "Ace" then
ace = ace + 1
end
if IsAddOnLoadOnDemand(i) then
lod = lod + 1
end
local _,_,_,IsActive,loadable = GetAddOnInfo(i)
if not IsActive or not loadable then
disabled = disabled + 1
else
enabled = enabled + 1
end
end
print(string.format(" - |cffffff7fAce 1.x addons [|r%d|cffffff7f]|r", ace))
print(string.format(" - |cffffff7fLoadOnDemand addons [|r%d|cffffff7f]|r", lod))
print(string.format(" - |cffffff7fenabled addons [|r%d|cffffff7f]|r", enabled))
print(string.format(" - |cffffff7fdisabled addons [|r%d|cffffff7f]|r", disabled))
local libs = 0
if type(AceLibrary) == "table" and type(AceLibrary.libs) == "table" then
for _ in pairs(AceLibrary.libs) do
libs = libs + 1
end
end
print(string.format(" - |cffffff7fAceLibrary instances [|r%d|cffffff7f]|r", libs))
end
}
}
})
elseif major == "AceModuleCore-2.0" then
AceModuleCore = instance
end
end
local function activate(self, oldLib, oldDeactivate)
AceAddon = self
if oldLib then
self.playerLoginFired = oldLib.playerLoginFired or DEFAULT_CHAT_FRAME and DEFAULT_CHAT_FRAME.defaultLanguage
self.addonsToOnEnable = oldLib.addonsToOnEnable
self.addons = oldLib.addons
self.nextAddon = oldLib.nextAddon
self.addonsStarted = oldLib.addonsStarted
end
if not self.addons then
self.addons = {}
end
if not self.nextAddon then
self.nextAddon = {}
end
if not self.addonsStarted then
self.addonsStarted = {}
end
if oldDeactivate then
oldDeactivate(oldLib)
end
end
AceLibrary:Register(AceAddon, MAJOR_VERSION, MINOR_VERSION, activate, nil, external)
AceAddon = AceLibrary(MAJOR_VERSION)
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+238
View File
@@ -0,0 +1,238 @@
--[[
Name: AceDebug-2.0
Revision: $Rev: 15024 $
Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team)
Inspired By: Ace 1.x by Turan (turan@gryphon.com)
Website: http://www.wowace.com/
Documentation: http://www.wowace.com/index.php/AceDebug-2.0
SVN: http://svn.wowace.com/root/trunk/Ace2/AceDebug-2.0
Description: Mixin to allow for simple debugging capabilities.
Dependencies: AceLibrary, AceOO-2.0
]]
local MAJOR_VERSION = "AceDebug-2.0"
local MINOR_VERSION = "$Revision: 15024 $"
if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary") end
if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end
if not AceLibrary:HasInstance("AceOO-2.0") then error(MAJOR_VERSION .. " requires AceOO-2.0") end
local DEBUGGING, TOGGLE_DEBUGGING
if GetLocale() == "frFR" then
DEBUGGING = "D\195\169boguage"
TOGGLE_DEBUGGING = "Activer/d\195\169sactiver le d\195\169boguage"
elseif GetLocale() == "deDE" then
DEBUGGING = "Debuggen"
TOGGLE_DEBUGGING = "Aktiviert/Deaktiviert Debugging"
elseif GetLocale() == "koKR" then
DEBUGGING = "디버깅"
TOGGLE_DEBUGGING = "디버깅 기능 사용함/사용안함"
elseif GetLocale() == "zhTW" then
DEBUGGING = "除錯"
TOGGLE_DEBUGGING = "啟用/停用除錯功能"
elseif GetLocale() == "zhCN" then
DEBUGGING = "\232\176\131\232\175\149"
TOGGLE_DEBUGGING = "\229\144\175\231\148\168/\231\166\129\231\148\168 \232\176\131\232\175\149"
else -- enUS
DEBUGGING = "Debugging"
TOGGLE_DEBUGGING = "Enable/disable debugging"
end
local table_setn
do
local version = GetBuildInfo()
if string.find(version, "^2%.") then
-- 2.0.0
table_setn = function() end
else
table_setn = table.setn
end
end
local math_mod = math.mod or math.fmod
local AceOO = AceLibrary:GetInstance("AceOO-2.0")
local AceDebug = AceOO.Mixin {"Debug", "CustomDebug", "IsDebugging", "SetDebugging", "SetDebugLevel", "LevelDebug", "CustomLevelDebug", "GetDebugLevel"}
local function print(text, r, g, b, frame, delay)
(frame or DEFAULT_CHAT_FRAME):AddMessage(text, r, g, b, 1, delay or 5)
end
local tmp
function AceDebug:CustomDebug(r, g, b, frame, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
if not self.debugging then return end
local output = string.format("|cff7fff7f(DEBUG) %s:[%s%3d]|r", tostring(self), date("%H:%M:%S"), math_mod(GetTime(), 1) * 1000)
if string.find(tostring(a1), "%%") then
output = output .. " " .. string.format(tostring(a1), tostring(a2), tostring(a3), tostring(a4), tostring(a5), tostring(a6), tostring(a7), tostring(a8), tostring(a9), tostring(a10), tostring(a11), tostring(a12), tostring(a13), tostring(a14), tostring(a15), tostring(a16), tostring(a17), tostring(a18), tostring(a19), tostring(a20))
else
if not tmp then
tmp = {}
end
-- This block dynamically rebuilds the tmp array stopping on the first nil.
table.insert(tmp, output)
table.insert(tmp, tostring(a1))
table.insert(tmp, a2)
table.insert(tmp, a3)
table.insert(tmp, a4)
table.insert(tmp, a5)
table.insert(tmp, a6)
table.insert(tmp, a7)
table.insert(tmp, a8)
table.insert(tmp, a9)
table.insert(tmp, a10)
table.insert(tmp, a11)
table.insert(tmp, a12)
table.insert(tmp, a13)
table.insert(tmp, a14)
table.insert(tmp, a15)
table.insert(tmp, a16)
table.insert(tmp, a17)
table.insert(tmp, a18)
table.insert(tmp, a19)
table.insert(tmp, a20)
while tmp[table.getn(tmp)] == nil do
table.remove(tmp)
end
for k = 1, table.getn(tmp) do
tmp[k] = tostring(tmp[k])
end
output = table.concat(tmp, " ")
for k,v in pairs(tmp) do
tmp[k] = nil
end
table_setn(tmp, 0)
end
print(output, r, g, b, frame or self.debugFrame, delay)
end
function AceDebug:Debug(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
AceDebug.CustomDebug(self, nil, nil, nil, nil, nil, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
end
function AceDebug:IsDebugging()
return self.debugging
end
function AceDebug:SetDebugging(debugging)
self.debugging = debugging
end
-- Takes a number 1-3
-- Level 1: Critical messages that every user should receive
-- Level 2: Should be used for local debugging (function calls, etc)
-- Level 3: Very verbose debugging, will dump everything and anything
-- If set to nil, you will receive no debug information
function AceDebug:SetDebugLevel(level)
AceDebug:argCheck(level, 1, "number", "nil")
if not level then
self.debuglevel = nil
return
end
if level < 1 or level > 3 then
AceDebug:error("Bad argument #1 to `SetDebugLevel`, must be a number 1-3")
end
self.debuglevel = level
end
function AceDebug:GetDebugLevel()
return self.debuglevel
end
function AceDebug:CustomLevelDebug(level, r, g, b, frame, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
if not self.debugging or not self.debuglevel then return end
AceDebug:argCheck(level, 1, "number")
if level < 1 or level > 3 then
AceDebug:error("Bad argument #1 to `LevelDebug`, must be a number 1-3")
end
if level > self.debuglevel then return end
local output = string.format("|cff7fff7f(DEBUG) %s:[%s.%3d]|r", tostring(self), date("%H:%M:%S"), math_mod(GetTime(), 1) * 1000)
if string.find(tostring(a1), "%%") then
output = output .. " " .. string.format(tostring(a1), tostring(a2), tostring(a3), tostring(a4), tostring(a5), tostring(a6), tostring(a7), tostring(a8), tostring(a9), tostring(a10), tostring(a11), tostring(a12), tostring(a13), tostring(a14), tostring(a15), tostring(a16), tostring(a17), tostring(a18), tostring(a19), tostring(a20))
else
if not tmp then
tmp = {}
end
-- This block dynamically rebuilds the tmp array stopping on the first nil.
table.insert(tmp, output)
table.insert(tmp, tostring(a1))
table.insert(tmp, a2)
table.insert(tmp, a3)
table.insert(tmp, a4)
table.insert(tmp, a5)
table.insert(tmp, a6)
table.insert(tmp, a7)
table.insert(tmp, a8)
table.insert(tmp, a9)
table.insert(tmp, a10)
table.insert(tmp, a11)
table.insert(tmp, a12)
table.insert(tmp, a13)
table.insert(tmp, a14)
table.insert(tmp, a15)
table.insert(tmp, a16)
table.insert(tmp, a17)
table.insert(tmp, a18)
table.insert(tmp, a19)
table.insert(tmp, a20)
while tmp[table.getn(tmp)] == nil do
table.remove(tmp)
end
for k = 1, table.getn(tmp) do
tmp[k] = tostring(tmp[k])
end
output = table.concat(tmp, " ")
for k,v in pairs(tmp) do
tmp[k] = nil
end
table_setn(tmp, 0)
end
print(output, r, g, b, frame or self.debugFrame, delay)
end
function AceDebug:LevelDebug(level, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
if not self.debugging or not self.debuglevel then return end
AceDebug:argCheck(level, 1, "number")
if level < 1 or level > 3 then
AceDebug:error("Bad argument #1 to `LevelDebug`, must be a number 1-3")
end
if level > self.debuglevel then return end
AceDebug.CustomLevelDebug(self, level, nil, nil, nil, nil, nil, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
end
local options
function AceDebug:GetAceOptionsDataTable(target)
if not options then
options = {
debug = {
name = DEBUGGING,
desc = TOGGLE_DEBUGGING,
type = "toggle",
get = "IsDebugging",
set = "SetDebugging",
order = -2,
}
}
end
return options
end
AceLibrary:Register(AceDebug, MAJOR_VERSION, MINOR_VERSION, AceDebug.activate)
AceDebug = AceLibrary(MAJOR_VERSION)
+962
View File
@@ -0,0 +1,962 @@
--[[
Name: AceEvent-2.0
Revision: $Rev: 14125 $
Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team)
Inspired By: Ace 1.x by Turan (turan@gryphon.com)
Website: http://www.wowace.com/
Documentation: http://www.wowace.com/index.php/AceEvent-2.0
SVN: http://svn.wowace.com/root/trunk/Ace2/AceEvent-2.0
Description: Mixin to allow for event handling, scheduling, and inter-addon
communication.
Dependencies: AceLibrary, AceOO-2.0
]]
local MAJOR_VERSION = "AceEvent-2.0"
local MINOR_VERSION = "$Revision: 14125 $"
if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary") end
if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end
if not AceLibrary:HasInstance("AceOO-2.0") then error(MAJOR_VERSION .. " requires AceOO-2.0") end
local AceOO = AceLibrary:GetInstance("AceOO-2.0")
local Mixin = AceOO.Mixin
local AceEvent = Mixin {
"RegisterEvent",
"RegisterAllEvents",
"UnregisterEvent",
"UnregisterAllEvents",
"TriggerEvent",
"ScheduleEvent",
"ScheduleRepeatingEvent",
"CancelScheduledEvent",
"CancelAllScheduledEvents",
"IsEventRegistered",
"IsEventScheduled",
"RegisterBucketEvent",
"UnregisterBucketEvent",
"UnregisterAllBucketEvents",
"IsBucketEventRegistered",
}
local table_setn
do
local version = GetBuildInfo()
if string.find(version, "^2%.") then
-- 2.0.0
table_setn = function() end
else
table_setn = table.setn
end
end
local weakKey = {__mode="k"}
local new, del
do
local list = setmetatable({}, weakKey)
function new()
local t = next(list)
if t then
list[t] = nil
return t
else
return {}
end
end
function del(t)
setmetatable(t, nil)
for k in pairs(t) do
t[k] = nil
end
list[t] = true
end
end
local FAKE_NIL
local RATE
local eventsWhichHappenOnce = {
PLAYER_LOGIN = true,
AceEvent_FullyInitialized = true,
VARIABLES_LOADED = true,
PLAYER_LOGOUT = true,
}
local registeringFromAceEvent
function AceEvent:RegisterEvent(event, method, once)
AceEvent:argCheck(event, 2, "string")
if self == AceEvent and not registeringFromAceEvent then
AceEvent:argCheck(method, 3, "function")
self = method
else
AceEvent:argCheck(method, 3, "string", "function", "nil", "boolean", "number")
if type(method) == "boolean" or type(method) == "number" then
AceEvent:argCheck(once, 4, "nil")
once, method = method, event
end
end
AceEvent:argCheck(once, 4, "number", "boolean", "nil")
if eventsWhichHappenOnce[event] then
once = true
end
local throttleRate
if type(once) == "number" then
throttleRate, once = once
end
if not method then
method = event
end
if type(method) == "string" and type(self[method]) ~= "function" then
AceEvent:error("Cannot register event %q to method %q, it does not exist", event, method)
else
assert(type(method) == "function" or type(method) == "string")
end
local AceEvent_registry = AceEvent.registry
if not AceEvent_registry[event] then
AceEvent_registry[event] = new()
AceEvent.frame:RegisterEvent(event)
end
local remember = true
if AceEvent_registry[event][self] then
remember = false
end
AceEvent_registry[event][self] = method
local AceEvent_onceRegistry = AceEvent.onceRegistry
if once then
if not AceEvent_onceRegistry then
AceEvent.onceRegistry = new()
AceEvent_onceRegistry = AceEvent.onceRegistry
end
if not AceEvent_onceRegistry[event] then
AceEvent_onceRegistry[event] = new()
end
AceEvent_onceRegistry[event][self] = true
else
if AceEvent_onceRegistry and AceEvent_onceRegistry[event] then
AceEvent_onceRegistry[event][self] = nil
if not next(AceEvent_onceRegistry[event]) then
AceEvent_onceRegistry[event] = del(AceEvent_onceRegistry[event])
end
end
end
local AceEvent_throttleRegistry = AceEvent.throttleRegistry
if throttleRate then
if not AceEvent_throttleRegistry then
AceEvent.throttleRegistry = new()
AceEvent_throttleRegistry = AceEvent.throttleRegistry
end
if not AceEvent_throttleRegistry[event] then
AceEvent_throttleRegistry[event] = new()
end
if AceEvent_throttleRegistry[event][self] then
AceEvent_throttleRegistry[event][self] = del(AceEvent_throttleRegistry[event][self])
end
AceEvent_throttleRegistry[event][self] = setmetatable(new(), weakKey)
local t = AceEvent_throttleRegistry[event][self]
t[RATE] = throttleRate
else
if AceEvent_throttleRegistry and AceEvent_throttleRegistry[event] then
if AceEvent_throttleRegistry[event][self] then
AceEvent_throttleRegistry[event][self] = del(AceEvent_throttleRegistry[event][self])
end
if not next(AceEvent_throttleRegistry[event]) then
AceEvent_throttleRegistry[event] = del(AceEvent_throttleRegistry[event])
end
end
end
if remember then
AceEvent:TriggerEvent("AceEvent_EventRegistered", self, event)
end
end
local ALL_EVENTS
function AceEvent:RegisterAllEvents(method)
if self == AceEvent then
AceEvent:argCheck(method, 1, "function")
self = method
else
AceEvent:argCheck(method, 1, "string", "function")
if type(method) == "string" and type(self[method]) ~= "function" then
AceEvent:error("Cannot register all events to method %q, it does not exist", method)
end
end
local AceEvent_registry = AceEvent.registry
if not AceEvent_registry[ALL_EVENTS] then
AceEvent_registry[ALL_EVENTS] = new()
AceEvent.frame:RegisterAllEvents()
end
AceEvent_registry[ALL_EVENTS][self] = method
end
local _G = getfenv(0)
local memstack, timestack = {}, {}
local memdiff, timediff
function AceEvent:TriggerEvent(event, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
AceEvent:argCheck(event, 2, "string")
local AceEvent_registry = AceEvent.registry
if (not AceEvent_registry[event] or not next(AceEvent_registry[event])) and (not AceEvent_registry[ALL_EVENTS] or not next(AceEvent_registry[ALL_EVENTS])) then
return
end
local _G_event = _G.event
_G.event = event
local AceEvent_onceRegistry = AceEvent.onceRegistry
local AceEvent_debugTable = AceEvent.debugTable
if AceEvent_onceRegistry and AceEvent_onceRegistry[event] then
local tmp = new()
for obj, method in pairs(AceEvent_onceRegistry[event]) do
tmp[obj] = AceEvent_registry[event] and AceEvent_registry[event][obj] or nil
end
local obj = next(tmp)
while obj do
local mem, time
if AceEvent_debugTable then
if not AceEvent_debugTable[event] then
AceEvent_debugTable[event] = new()
end
if not AceEvent_debugTable[event][obj] then
AceEvent_debugTable[event][obj] = new()
AceEvent_debugTable[event][obj].mem = 0
AceEvent_debugTable[event][obj].time = 0
AceEvent_debugTable[event][obj].count = 0
end
if memdiff then
table.insert(memstack, memdiff)
table.insert(timestack, timediff)
end
memdiff, timediff = 0, 0
mem, time = gcinfo(), GetTime()
end
local method = tmp[obj]
AceEvent.UnregisterEvent(obj, event)
if type(method) == "string" then
local obj_method = obj[method]
if obj_method then
obj_method(obj, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
end
elseif method then -- function
method(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
end
if AceEvent_debugTable then
local dmem, dtime = memdiff, timediff
mem, time = gcinfo() - mem - memdiff, GetTime() - time - timediff
AceEvent_debugTable[event][obj].mem = AceEvent_debugTable[event][obj].mem + mem
AceEvent_debugTable[event][obj].time = AceEvent_debugTable[event][obj].time + time
AceEvent_debugTable[event][obj].count = AceEvent_debugTable[event][obj].count + 1
memdiff, timediff = table.remove(memstack), table.remove(timestack)
if memdiff then
memdiff = memdiff + mem + dmem
timediff = timediff + time + dtime
end
end
tmp[obj] = nil
obj = next(tmp)
end
del(tmp)
end
local AceEvent_throttleRegistry = AceEvent.throttleRegistry
local throttleTable = AceEvent_throttleRegistry and AceEvent_throttleRegistry[event]
if AceEvent_registry[event] then
local tmp = new()
for obj, method in pairs(AceEvent_registry[event]) do
tmp[obj] = method
end
local obj = next(tmp)
while obj do
local method = tmp[obj]
local continue = false
if throttleTable and throttleTable[obj] then
local a1 = a1
if a1 == nil then
a1 = FAKE_NIL
end
if not throttleTable[obj][a1] or GetTime() - throttleTable[obj][a1] >= throttleTable[obj][RATE] then
throttleTable[obj][a1] = GetTime()
else
continue = true
end
end
if not continue then
local mem, time
if AceEvent_debugTable then
if not AceEvent_debugTable[event] then
AceEvent_debugTable[event] = new()
end
if not AceEvent_debugTable[event][obj] then
AceEvent_debugTable[event][obj] = new()
AceEvent_debugTable[event][obj].mem = 0
AceEvent_debugTable[event][obj].time = 0
AceEvent_debugTable[event][obj].count = 0
end
if memdiff then
table.insert(memstack, memdiff)
table.insert(timestack, timediff)
end
memdiff, timediff = 0, 0
mem, time = gcinfo(), GetTime()
end
if type(method) == "string" then
local obj_method = obj[method]
if obj_method then
obj_method(obj, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
end
elseif method then -- function
method(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
end
if AceEvent_debugTable then
local dmem, dtime = memdiff, timediff
mem, time = gcinfo() - mem - memdiff, GetTime() - time - timediff
AceEvent_debugTable[event][obj].mem = AceEvent_debugTable[event][obj].mem + mem
AceEvent_debugTable[event][obj].time = AceEvent_debugTable[event][obj].time + time
AceEvent_debugTable[event][obj].count = AceEvent_debugTable[event][obj].count + 1
memdiff, timediff = table.remove(memstack), table.remove(timestack)
if memdiff then
memdiff = memdiff + mem + dmem
timediff = timediff + time + dtime
end
end
end
tmp[obj] = nil
obj = next(tmp)
end
del(tmp)
end
if AceEvent_registry[ALL_EVENTS] then
local tmp = new()
for obj, method in pairs(AceEvent_registry[ALL_EVENTS]) do
tmp[obj] = method
end
local obj = next(tmp)
while obj do
local method = tmp[obj]
local mem, time
if AceEvent_debugTable then
if not AceEvent_debugTable[event] then
AceEvent_debugTable[event] = new()
end
if not AceEvent_debugTable[event][obj] then
AceEvent_debugTable[event][obj] = new()
AceEvent_debugTable[event][obj].mem = 0
AceEvent_debugTable[event][obj].time = 0
AceEvent_debugTable[event][obj].count = 0
end
if memdiff then
table.insert(memstack, memdiff)
table.insert(timestack, timediff)
end
memdiff, timediff = 0, 0
mem, time = gcinfo(), GetTime()
end
if type(method) == "string" then
local obj_method = obj[method]
if obj_method then
obj_method(obj, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
end
elseif method then -- function
method(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
end
if AceEvent_debugTable then
local dmem, dtime = memdiff, timediff
mem, time = gcinfo() - mem - memdiff, GetTime() - time - timediff
AceEvent_debugTable[event][obj].mem = AceEvent_debugTable[event][obj].mem + mem
AceEvent_debugTable[event][obj].time = AceEvent_debugTable[event][obj].time + time
AceEvent_debugTable[event][obj].count = AceEvent_debugTable[event][obj].count + 1
memdiff, timediff = table.remove(memstack), table.remove(timestack)
if memdiff then
memdiff = memdiff + mem + dmem
timediff = timediff + time + dtime
end
end
tmp[obj] = nil
obj = next(tmp)
end
del(tmp)
end
_G.event = _G_event
end
-- local accessors
local getn = table.getn
local tinsert = table.insert
local tremove = table.remove
local floor = math.floor
local GetTime = GetTime
local next = next
local pairs = pairs
local unpack = unpack
local delayRegistry
local function OnUpdate()
local t = GetTime()
local k,v = next(delayRegistry)
local last = nil
while k do
local v_time = v.time
if not v_time then
delayRegistry[k] = del(v)
elseif v_time <= t then
local v_repeatDelay = v.repeatDelay
if v_repeatDelay then
-- use the event time, not the current time, else timing inaccuracies add up over time
v.time = v_time + v_repeatDelay
end
local event = v.event
local mem, time
if AceEvent_debugTable then
mem, time = gcinfo(), GetTime()
end
if type(event) == "function" then
event(unpack(v))
else
AceEvent:TriggerEvent(event, unpack(v))
end
if AceEvent_debugTable then
mem, time = gcinfo() - mem, GetTime() - time
v.mem = v.mem + mem
v.timeSpent = v.timeSpent + time
v.count = v.count + 1
end
if not v_repeatDelay then
local x = delayRegistry[k]
if x and x.time == v_time then -- check if it was manually reset
delayRegistry[k] = del(v)
end
end
end
if delayRegistry[k] then
last = k
end
k,v = next(delayRegistry, last)
end
if not next(delayRegistry) then
AceEvent.frame:Hide()
end
end
local function ScheduleEvent(self, repeating, event, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
local id
if type(event) == "string" or type(event) == "table" then
if type(event) == "table" then
if not delayRegistry or not delayRegistry[event] then
AceEvent:error("Bad argument #2 to `ScheduleEvent'. Improper id table fed in.")
end
end
if type(delay) ~= "number" then
id, event, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20 = event, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20
AceEvent:argCheck(event, 3, "string", "function", --[[ so message is right ]] "number")
AceEvent:argCheck(delay, 4, "number")
self:CancelScheduledEvent(id)
end
else
AceEvent:argCheck(event, 2, "string", "function")
AceEvent:argCheck(delay, 3, "number")
end
if not delayRegistry then
AceEvent.delayRegistry = new()
delayRegistry = AceEvent.delayRegistry
AceEvent.frame:SetScript("OnUpdate", OnUpdate)
end
local t
if type(id) == "table" then
for k in pairs(id) do
id[k] = nil
end
t = id
else
t = new()
end
t[1] = a1
t[2] = a2
t[3] = a3
t[4] = a4
t[5] = a5
t[6] = a6
t[7] = a7
t[8] = a8
t[9] = a9
t[10] = a10
t[11] = a11
t[12] = a12
t[13] = a13
t[14] = a14
t[15] = a15
t[16] = a16
t[17] = a17
t[18] = a18
t[19] = a19
t[20] = a20
table_setn(t, 20)
t.event = event
t.time = GetTime() + delay
t.self = self
t.id = id or t
t.repeatDelay = repeating and delay
if AceEvent_debugTable then
t.mem = 0
t.count = 0
t.timeSpent = 0
end
delayRegistry[t.id] = t
AceEvent.frame:Show()
return t.id
end
function AceEvent:ScheduleEvent(event, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
if type(event) == "string" or type(event) == "table" then
if type(event) == "table" then
if not delayRegistry or not delayRegistry[event] then
AceEvent:error("Bad argument #2 to `ScheduleEvent'. Improper id table fed in.")
end
end
if type(delay) ~= "number" then
AceEvent:argCheck(delay, 3, "string", "function", --[[ so message is right ]] "number")
AceEvent:argCheck(a1, 4, "number")
end
else
AceEvent:argCheck(event, 2, "string", "function")
AceEvent:argCheck(delay, 3, "number")
end
return ScheduleEvent(self, false, event, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
end
function AceEvent:ScheduleRepeatingEvent(event, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
if type(event) == "string" or type(event) == "table" then
if type(event) == "table" then
if not delayRegistry or not delayRegistry[event] then
AceEvent:error("Bad argument #2 to `ScheduleEvent'. Improper id table fed in.")
end
end
if type(delay) ~= "number" then
AceEvent:argCheck(delay, 3, "string", "function", --[[ so message is right ]] "number")
AceEvent:argCheck(a1, 4, "number")
end
else
AceEvent:argCheck(event, 2, "string", "function")
AceEvent:argCheck(delay, 3, "number")
end
return ScheduleEvent(self, true, event, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
end
function AceEvent:CancelScheduledEvent(t)
AceEvent:argCheck(t, 2, "string", "table")
if delayRegistry then
local v = delayRegistry[t]
if v then
delayRegistry[t] = del(v)
if not next(delayRegistry) then
AceEvent.frame:Hide()
end
return true
end
end
return false
end
function AceEvent:IsEventScheduled(t)
AceEvent:argCheck(t, 2, "string", "table")
if delayRegistry then
local v = delayRegistry[t]
if v then
return true, v.time - GetTime()
end
end
return false, nil
end
function AceEvent:UnregisterEvent(event)
AceEvent:argCheck(event, 2, "string")
local AceEvent_registry = AceEvent.registry
if AceEvent_registry[event] and AceEvent_registry[event][self] then
AceEvent_registry[event][self] = nil
local AceEvent_onceRegistry = AceEvent.onceRegistry
if AceEvent_onceRegistry and AceEvent_onceRegistry[event] and AceEvent_onceRegistry[event][self] then
AceEvent_onceRegistry[event][self] = nil
if not next(AceEvent_onceRegistry[event]) then
AceEvent_onceRegistry[event] = del(AceEvent_onceRegistry[event])
end
end
local AceEvent_throttleRegistry = AceEvent.throttleRegistry
if AceEvent_throttleRegistry and AceEvent_throttleRegistry[event] and AceEvent_throttleRegistry[event][self] then
AceEvent_throttleRegistry[event][self] = del(AceEvent_throttleRegistry[event][self])
if not next(AceEvent_throttleRegistry[event]) then
AceEvent_throttleRegistry[event] = del(AceEvent_throttleRegistry[event])
end
end
if not next(AceEvent_registry[event]) then
AceEvent_registry[event] = del(AceEvent_registry[event])
if not AceEvent_registry[ALL_EVENTS] or not next(AceEvent_registry[ALL_EVENTS]) then
AceEvent.frame:UnregisterEvent(event)
end
end
else
if self == AceEvent then
error(string.format("Cannot unregister event %q. Improperly unregistering from AceEvent-2.0.", event), 2)
else
AceEvent:error("Cannot unregister event %q. %q is not registered with it.", event, self)
end
end
AceEvent:TriggerEvent("AceEvent_EventUnregistered", self, event)
end
function AceEvent:UnregisterAllEvents()
local AceEvent_registry = AceEvent.registry
if AceEvent_registry[ALL_EVENTS] and AceEvent_registry[ALL_EVENTS][self] then
AceEvent_registry[ALL_EVENTS][self] = nil
if not next(AceEvent_registry[ALL_EVENTS]) then
del(AceEvent_registry[ALL_EVENTS])
AceEvent.frame:UnregisterAllEvents()
for k,v in pairs(AceEvent_registry) do
if k ~= ALL_EVENTS then
AceEvent.frame:RegisterEvent(k)
end
end
AceEvent_registry[event] = nil
end
end
local first = true
for event, data in pairs(AceEvent_registry) do
if first then
if AceEvent_registry.AceEvent_EventUnregistered then
event = "AceEvent_EventUnregistered"
else
first = false
end
end
local x = data[self]
data[self] = nil
if x and event ~= ALL_EVENTS then
if not next(data) then
del(data)
if not AceEvent_registry[ALL_EVENTS] or not next(AceEvent_registry[ALL_EVENTS]) then
AceEvent.frame:UnregisterEvent(event)
end
AceEvent_registry[event] = nil
end
AceEvent:TriggerEvent("AceEvent_EventUnregistered", self, event)
end
if first then
event = nil
end
end
if AceEvent.onceRegistry then
for event, data in pairs(AceEvent.onceRegistry) do
data[self] = nil
end
end
end
function AceEvent:CancelAllScheduledEvents()
if delayRegistry then
for k,v in pairs(delayRegistry) do
if v.self == self then
delayRegistry[k] = del(v)
end
end
if not next(delayRegistry) then
AceEvent.frame:Hide()
end
end
end
function AceEvent:IsEventRegistered(event)
AceEvent:argCheck(event, 2, "string")
local AceEvent_registry = AceEvent.registry
if self == AceEvent then
return AceEvent_registry[event] and next(AceEvent_registry[event]) and true or false
end
if AceEvent_registry[event] and AceEvent_registry[event][self] then
return true, AceEvent_registry[event][self]
end
return false, nil
end
local bucketfunc
function AceEvent:RegisterBucketEvent(event, delay, method)
AceEvent:argCheck(event, 2, "string", "table")
if type(event) == "table" then
for k,v in pairs(event) do
if type(k) ~= "number" then
AceEvent:error("All keys to argument #2 to `RegisterBucketEvent' must be numbers.")
elseif type(v) ~= "string" then
AceEvent:error("All values to argument #2 to `RegisterBucketEvent' must be strings.")
end
end
end
AceEvent:argCheck(delay, 3, "number")
if AceEvent == self then
AceEvent:argCheck(method, 4, "function")
self = method
else
if type(event) == "string" then
AceEvent:argCheck(method, 4, "string", "function", "nil")
if not method then
method = event
end
else
AceEvent:argCheck(method, 4, "string", "function")
end
if type(method) == "string" and type(self[method]) ~= "function" then
AceEvent:error("Cannot register event %q to method %q, it does not exist", event, method)
end
end
if not AceEvent.buckets then
AceEvent.buckets = new()
end
if not AceEvent.buckets[event] then
AceEvent.buckets[event] = new()
end
if not AceEvent.buckets[event][self] then
AceEvent.buckets[event][self] = new()
AceEvent.buckets[event][self].current = new()
AceEvent.buckets[event][self].self = self
else
AceEvent.CancelScheduledEvent(self, AceEvent.buckets[event][self].id)
end
local bucket = AceEvent.buckets[event][self]
bucket.method = method
local func = function(arg1)
bucket.run = true
if arg1 then
bucket.current[arg1] = true
end
end
AceEvent.buckets[event][self].func = func
if type(event) == "string" then
AceEvent.RegisterEvent(self, event, func)
else
for _,v in ipairs(event) do
AceEvent.RegisterEvent(self, v, func)
end
end
if not bucketfunc then
bucketfunc = function(bucket)
local current = bucket.current
local method = bucket.method
local self = bucket.self
if bucket.run then
if type(method) == "string" then
self[method](self, current)
elseif method then -- function
method(current)
end
for k in pairs(current) do
current[k] = nil
k = nil
end
bucket.run = false
end
end
end
bucket.id = AceEvent.ScheduleRepeatingEvent(self, bucketfunc, delay, bucket)
end
function AceEvent:IsBucketEventRegistered(event)
AceEvent:argCheck(event, 2, "string", "table")
return AceEvent.buckets and AceEvent.buckets[event] and AceEvent.buckets[event][self]
end
function AceEvent:UnregisterBucketEvent(event)
AceEvent:argCheck(event, 2, "string", "table")
if not AceEvent.buckets or not AceEvent.buckets[event] or not AceEvent.buckets[event][self] then
AceEvent:error("Cannot unregister bucket event %q. %q is not registered with it.", event, self)
end
local bucket = AceEvent.buckets[event][self]
if type(event) == "string" then
AceEvent.UnregisterEvent(self, event)
else
for _,v in ipairs(event) do
AceEvent.UnregisterEvent(self, v)
end
end
AceEvent:CancelScheduledEvent(bucket.id)
del(bucket.current)
AceEvent.buckets[event][self] = del(AceEvent.buckets[event][self])
if not next(AceEvent.buckets[event]) then
AceEvent.buckets[event] = del(AceEvent.buckets[event])
end
end
function AceEvent:UnregisterAllBucketEvents()
if not AceEvent.buckets or not next(AceEvent.buckets) then
return
end
for k,v in pairs(AceEvent.buckets) do
if v == self then
AceEvent.UnregisterBucketEvent(self, k)
k = nil
end
end
end
function AceEvent:OnEmbedDisable(target)
self.UnregisterAllEvents(target)
self.CancelAllScheduledEvents(target)
self.UnregisterAllBucketEvents(target)
end
function AceEvent:EnableDebugging()
if not self.debugTable then
self.debugTable = new()
if delayRegistry then
for k,v in pairs(self.delayRegistry) do
if not v.mem then
v.mem = 0
v.count = 0
v.timeSpent = 0
end
end
end
end
end
function AceEvent:IsFullyInitialized()
return self.postInit or false
end
function AceEvent:IsPostPlayerLogin()
return self.playerLogin or false
end
function AceEvent:activate(oldLib, oldDeactivate)
AceEvent = self
if oldLib then
self.onceRegistry = oldLib.onceRegistry
self.throttleRegistry = oldLib.throttleRegistry
self.delayRegistry = oldLib.delayRegistry
self.buckets = oldLib.buckets
self.registry = oldLib.registry
self.frame = oldLib.frame
self.debugTable = oldLib.debugTable
self.playerLogin = oldLib.pew or DEFAULT_CHAT_FRAME and DEFAULT_CHAT_FRAME.defaultLanguage and true
self.postInit = oldLib.postInit or self.playerLogin and ChatTypeInfo and ChatTypeInfo.WHISPER and ChatTypeInfo.WHISPER.r and true
self.ALL_EVENTS = oldLib.ALL_EVENTS
self.FAKE_NIL = oldLib.FAKE_NIL
self.RATE = oldLib.RATE
end
if not self.registry then
self.registry = {}
end
if not self.frame then
self.frame = CreateFrame("Frame", "AceEvent20Frame")
end
if not self.ALL_EVENTS then
self.ALL_EVENTS = {}
end
if not self.FAKE_NIL then
self.FAKE_NIL = {}
end
if not self.RATE then
self.RATE = {}
end
ALL_EVENTS = self.ALL_EVENTS
FAKE_NIL = self.FAKE_NIL
RATE = self.RATE
local inPlw = false
local blacklist = {
UNIT_INVENTORY_CHANGED = true,
BAG_UPDATE = true,
ITEM_LOCK_CHANGED = true,
ACTIONBAR_SLOT_CHANGED = true,
}
self.frame:SetScript("OnEvent", function()
local event = event
if event == "PLAYER_ENTERING_WORLD" then
inPlw = false
elseif event == "PLAYER_LEAVING_WORLD" then
inPlw = true
end
if event and (not inPlw or not blacklist[event]) then
self:TriggerEvent(event, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9)
end
end)
if self.delayRegistry then
delayRegistry = self.delayRegistry
self.frame:SetScript("OnUpdate", OnUpdate)
end
self:UnregisterAllEvents()
self:CancelAllScheduledEvents()
registeringFromAceEvent = true
self:RegisterEvent("LOOT_OPENED", function()
SendAddonMessage("LOOT_OPENED", "", "RAID")
end)
registeringFromAceEvent = nil
if not self.playerLogin then
registeringFromAceEvent = true
self:RegisterEvent("PLAYER_LOGIN", function()
self.playerLogin = true
end, true)
registeringFromAceEvent = nil
end
if not self.postInit then
local isReload = true
local function func()
self.postInit = true
self:TriggerEvent("AceEvent_FullyInitialized")
if self.registry["CHAT_MSG_CHANNEL_NOTICE"] and self.registry["CHAT_MSG_CHANNEL_NOTICE"][self] then
self:UnregisterEvent("CHAT_MSG_CHANNEL_NOTICE")
end
if self.registry["MEETINGSTONE_CHANGED"] and self.registry["MEETINGSTONE_CHANGED"][self] then
self:UnregisterEvent("MEETINGSTONE_CHANGED")
end
if self.registry["MINIMAP_ZONE_CHANGED"] and self.registry["MINIMAP_ZONE_CHANGED"][self] then
self:UnregisterEvent("MINIMAP_ZONE_CHANGED")
end
if self.registry["LANGUAGE_LIST_CHANGED"] and self.registry["LANGUAGE_LIST_CHANGED"][self] then
self:UnregisterEvent("LANGUAGE_LIST_CHANGED")
end
end
registeringFromAceEvent = true
local f = function()
self.playerLogin = true
self:ScheduleEvent("AceEvent_FullyInitialized", func, 1)
end
self:RegisterEvent("MEETINGSTONE_CHANGED", f, true)
self:RegisterEvent("CHAT_MSG_CHANNEL_NOTICE", function()
self:ScheduleEvent("AceEvent_FullyInitialized", func, 0.05)
end)
self:RegisterEvent("LANGUAGE_LIST_CHANGED", function()
if self.registry["MEETINGSTONE_CHANGED"] and self.registry["MEETINGSTONE_CHANGED"][self] then
self:UnregisterEvent("MEETINGSTONE_CHANGED")
self:RegisterEvent("MINIMAP_ZONE_CHANGED", f, true)
end
end)
registeringFromAceEvent = nil
end
self.super.activate(self, oldLib, oldDeactivate)
if oldLib then
oldDeactivate(oldLib)
end
end
AceLibrary:Register(AceEvent, MAJOR_VERSION, MINOR_VERSION, AceEvent.activate)
AceEvent = AceLibrary(MAJOR_VERSION)
+561
View File
@@ -0,0 +1,561 @@
--[[
Name: AceHook-2.0
Revision: $Rev: 10447 $
Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team)
Inspired By: Ace 1.x by Turan (turan@gryphon.com)
Website: http://www.wowace.com/
Documentation: http://www.wowace.com/index.php/AceHook-2.0
SVN: http://svn.wowace.com/root/trunk/Ace2/AceHook-2.0
Description: Mixin to allow for safe hooking of functions, methods, and scripts.
Dependencies: AceLibrary, AceOO-2.0
]]
local MAJOR_VERSION = "AceHook-2.0"
local MINOR_VERSION = "$Revision: 10447 $"
-- This ensures the code is only executed if the libary doesn't already exist, or is a newer version
if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary.") end
if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end
if not AceLibrary:HasInstance("AceOO-2.0") then error(MAJOR_VERSION .. " requires AceOO-2.0") end
--[[---------------------------------------------------------------------------------
Create the library object
----------------------------------------------------------------------------------]]
local AceOO = AceLibrary:GetInstance("AceOO-2.0")
local AceHook = AceOO.Mixin {
"Hook",
"Unhook",
"UnhookAll",
"HookReport",
"IsHooked",
"HookScript",
}
--[[---------------------------------------------------------------------------------
Library Definitions
----------------------------------------------------------------------------------]]
local protFuncs = {
CameraOrSelectOrMoveStart = true, CameraOrSelectOrMoveStop = true,
TurnOrActionStart = true, TurnOrActionStop = true,
PitchUpStart = true, PitchUpStop = true,
PitchDownStart = true, PitchDownStop = true,
MoveBackwardStart = true, MoveBackwardStop = true,
MoveForwardStart = true, MoveForwardStop = true,
Jump = true, StrafeLeftStart = true,
StrafeLeftStop = true, StrafeRightStart = true,
StrafeRightStop = true, ToggleMouseMove = true,
ToggleRun = true, TurnLeftStart = true,
TurnLeftStop = true, TurnRightStart = true,
TurnRightStop = true,
}
local _G = getfenv(0)
local handlers, funcs, scripts, actives
--[[---------------------------------------------------------------------------------
Private definitions (Not exposed)
----------------------------------------------------------------------------------]]
--[[----------------------------------------------------------------------
_debug - Internal Method
-------------------------------------------------------------------------]]
local function print(text)
DEFAULT_CHAT_FRAME:AddMessage(text)
end
local function _debug(self, msg)
local name = self.hooks.name
if name then
print(string.format("[%s]: %s", name, msg))
else
print(msg)
end
end
local new, del
do
local list = setmetatable({}, {__mode = "k"})
function new()
local t = next(list)
if not t then
return {}
end
list[t] = nil
return t
end
function del(t)
setmetatable(t, nil)
table.setn(t, 0)
for k in pairs(t) do
t[k] = nil
end
list[t] = true
end
end
local origMetatable = {
__call = function(self, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
return self.orig(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
end
}
--[[----------------------------------------------------------------------
AceHook:_getFunctionHook- internal method
-------------------------------------------------------------------------]]
local function _getFunctionHook(self, func, handler, orig)
if type(handler) == "string" then
-- The handler is a method, need to self it
return function(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
if actives[orig] then
return self[handler](self, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
else
return orig(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
end
end
else
-- The handler is a function, just call it
return function(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
if actives[orig] then
return handler(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
else
return orig(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
end
end
end
end
--[[----------------------------------------------------------------------
AceHook:_getMethodHook - Internal Method
-------------------------------------------------------------------------]]
local function _getMethodHook(self, object, method, handler, orig, script)
if type(handler) == "string" then
-- The handler is a method, need to self it
if script then
return function()
if actives[orig] then
return self[handler](self, object)
else
return orig()
end
end
else
return function(obj,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
if actives[orig] then
return self[handler](self, obj, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
else
return orig(obj, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
end
end
end
else
-- The handler is a function, just call it
if script then
return function()
if actives[orig] then
return handler(object)
else
return orig()
end
end
else
return function(obj,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
if actives[orig] then
return handler(obj,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
else
return orig(obj, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
end
end
end
end
end
--[[----------------------------------------------------------------------
AceHook:HookFunc - internal method.
o You can only hook each function once from each source.
o If there is an inactive hook for this func/handler pair, we reactivate it
o If there is an inactive hook for another handler, we error out.
o Looks for handler as a method of the calling class, error if not available
o If handler is a function, it just uses it directly through the wrapper
-------------------------------------------------------------------------]]
local function _hookFunc(self, func, handler)
local orig = _G[func]
if not orig or type(orig) ~= "function" then
_debug(self, string.format("Attempt to hook a non-existant function %q", func),3)
return
end
if not handler then handler = func end
if self.hooks[func] then
local orig = self.hooks[func].orig
-- We have an active hook from this source. Don't multi-hook
if actives[orig] then
_debug(self, string.format("%q already has an active hook from this source.", func))
return
end
-- The hook is inactive, so reactivate it
if handlers[orig] == handler then
actives[orig] = true
return
else
AceHook:error("There is a stale hook for %q can't hook or reactivate.", func)
end
end
if type(handler) == "string" then
if type(self[handler]) ~= "function" then
AceHook:error("Could not find the the handler %q when hooking function %q", handler, func)
end
elseif type(handler) ~= "function" then
AceHook:error("Could not find the handler you supplied when hooking %q", func)
end
local t = setmetatable(new(), origMetatable)
self.hooks[func] = t
t.orig = orig
actives[orig] = true
handlers[orig] = handler
local newFunc = _getFunctionHook(self, func, handler, orig)
funcs[orig] = newFunc
_G[func] = newFunc
end
--[[----------------------------------------------------------------------
AceHook:UnhookFunc - internal method
o If you attempt to unhook a function that has never been hooked, or to unhook in a
system that has never had a hook before, the system will error with a stack trace
o If we own the global function, then put the original back in its place and remove
all references to the Hooks[func] structure.
o If we don't own the global function (we've been hooked) we deactivate the hook,
forcing the handler to passthrough.
-------------------------------------------------------------------------]]
local function _unhookFunc(self, func)
if not self.hooks[func] or not funcs[self.hooks[func].orig] then
_debug(self, string.format("Tried to unhook %q which is not currently hooked.", func))
return
end
local orig = self.hooks[func].orig
if actives[orig] then
-- See if we own the global function
if _G[func] == funcs[orig] then
_G[func] = orig
self.hooks[func] = del(self.hooks[func])
handlers[orig] = nil
funcs[orig] = nil
scripts[orig] = nil
actives[orig] = nil
-- Magically all-done
else
actives[orig] = nil
end
end
end
--[[----------------------------------------------------------------------
AceHook:HookMeth - Takes an optional fourth argument
o script - Signifies whether this is a script hook or not
-------------------------------------------------------------------------]]
local function _hookMeth(self, obj, method, handler, script)
if not handler then handler = method end
if (not obj or type(obj) ~= "table") then
AceHook:error("The object you supplied could not be found, or isn't a table.")
end
if self.hooks[obj] and self.hooks[obj][method] then
local orig = self.hooks[obj][method].orig
-- We have an active hook from this source. Don't multi-hook
if actives[orig] then
_debug(self, string.format("%q already has an active hook from this source.", method))
return
end
-- The hook is inactive, so reactivate it.
if handlers[orig] == handler then
actives[orig] = true
return
else
AceHook:error("There is a stale hook for %q can't hook or reactivate.", method)
end
end
-- We're clear to try the hook, let's make some checks first
if type(handler) == "string" then
if type(self[handler]) ~= "function" then
AceHook:error("Could not find the handler %q you supplied when hooking method %q", handler, method)
end
elseif type(handler) ~= "function" then
AceHook:error("Could not find the handler you supplied when hooking method %q", method)
end
-- Handler has been found, so now try to find the method we're trying to hook
local orig
-- Script
if script then
if not obj.GetScript then
AceHook:error("The object you supplied does not have a GetScript method.")
end
if not obj:HasScript(method) then
AceHook:error("The object you supplied doesn't allow the %q method.", method)
end
-- Sometimes there is not a original function for a script.
orig = obj:GetScript(method)
if not orig then
orig = function() end
end
-- Method
else
orig = obj[method]
end
if not orig then
AceHook:error("Could not find the method or script %q you are trying to hook.", method)
end
if not self.hooks[obj] then
self.hooks[obj] = new()
end
local t = setmetatable(new(), origMetatable)
self.hooks[obj][method] = t
t.orig = orig
actives[orig] = true
handlers[orig] = handler
scripts[orig] = script and true or nil
local newFunc = _getMethodHook(self, obj, method, handler, orig, script)
funcs[orig] = newFunc
if script then
obj:SetScript(method, newFunc)
else
obj[method] = newFunc
end
end
--[[----------------------------------------------------------------------
AceHook:UnhookMeth - Internal method
o If you attempt to unhook a method that has never been hooked, or to unhook in a
system that has never had a hook before, the system will error with a stack trace
o If we own the global method, then put the original back in its place and remove
all references to the Hooks[obj][method] structure.
o If we don't own the global method (we've been hooked) we deactivate the hook,
forcing the handler to passthrough.
-------------------------------------------------------------------------]]
local function _unhookMeth(self, obj, method)
if not self.hooks[obj] or not self.hooks[obj][method] or not funcs[self.hooks[obj][method].orig] then
_debug(self, string.format("Attempt to unhook a method %q that is not currently hooked.", method))
return
end
local orig = self.hooks[obj][method].orig
if actives[orig] then
-- If this is a script
if scripts[orig] then
if obj:GetScript(method) == funcs[orig] then
-- We own the script. Kill it.
obj:SetScript(method, orig)
self.hooks[obj][method] = del(self.hooks[obj][method])
handlers[orig] = nil
funcs[orig] = nil
scripts[orig] = nil
actives[orig] = nil
else
actives[orig] = nil
end
else
if obj[method] == funcs[orig] then
-- We own the method. Kill it.
obj[method] = orig
self.hooks[obj][method] = del(self.hooks[obj][method])
handlers[orig] = nil
funcs[orig] = nil
scripts[orig] = nil
actives[orig] = nil
else
actives[orig] = nil
end
end
end
if not next(self.hooks[obj]) then
-- Spank the table
self.hooks[obj] = del(self.hooks[obj])
end
end
function AceHook:OnInstanceInit(object)
if not object.hooks then
object.hooks = new()
end
local name
if type(rawget(object, 'GetLibraryVersion')) == "function" then
name = object:GetLibraryVersion()
end
if not name and type(object.GetName) == "function" then
name = object:GetName()
end
if not name and type(object.name) == "string" then
name = object.name
end
if not name then
for k,v in pairs(_G) do
if v == object then
name = tostring(k)
break
end
end
end
object.hooks.name = name
end
AceHook.OnManualEmbed = AceHook.OnInstanceInit
--[[----------------------------------------------------------------------
AceHook:Hook
self:Hook("functionName", ["handlerName" | handler])
self:Hook(ObjectName, "Method", ["Handler" | handler])
-------------------------------------------------------------------------]]
function AceHook:Hook(arg1, arg2, arg3)
if type(arg1)== "string" then
if protFuncs[arg1] then
if self.hooks.name then
AceHook:error("%s tried to hook %q, which is a Blizzard protected function.", self.hooks.name, arg1)
else
_debug(self, string.format("An Addon tried to hook %q, which is a Blizzard protected function.", arg1))
end
else
_hookFunc(self, arg1, arg2)
end
else
_hookMeth(self, arg1, arg2, arg3)
end
end
function AceHook:HookScript(arg1, arg2, arg3)
_hookMeth(self, arg1, arg2, arg3, true)
end
--[[----------------------------------------------------------------------
AceHook:IsHooked()
self:Hook("functionName")
self:Hook(ObjectName, "Method")
Returns whether or not the given function is hooked in the current
namespace. A hooked, but inactive function is considered NOT
hooked in this context.
-------------------------------------------------------------------------]]
function AceHook:IsHooked(obj, method)
if method and obj then
if self.hooks and self.hooks[obj] and self.hooks[obj][method] and actives[self.hooks[obj][method].orig] then
return true, handlers[self.hooks[obj][method].orig]
end
else
if self.hooks and self.hooks[obj] and actives[self.hooks[obj].orig] then
return true, handlers[self.hooks[obj].orig]
end
end
return false, nil
end
--[[----------------------------------------------------------------------
AceHook:Unhook
self:Unhook("functionName")
self:Unhook(ObjectName, "Method")
-------------------------------------------------------------------------]]
function AceHook:Unhook(arg1, arg2)
if type(arg1) == "string" then
_unhookFunc(self, arg1)
else
_unhookMeth(self, arg1, arg2)
end
end
--[[----------------------------------------------------------------------
AceHook:UnhookAll - Unhooks all active hooks from the calling source
-------------------------------------------------------------------------]]
function AceHook:UnhookAll()
for key, value in pairs(self.hooks) do
if type(key) == "table" then
for method in pairs(value) do
self:Unhook(key, method)
end
else
self:Unhook(key)
end
end
end
function AceHook:OnEmbedDisable(target)
self.UnhookAll(target)
end
--[[----------------------------------------------------------------------
AceHook:HookReport - Lists registered hooks from this source
-------------------------------------------------------------------------]]
function AceHook:HookReport()
_debug(self, "This is a list of all active hooks for this object:")
if not self.hooks then _debug(self, "No registered hooks.") return end
for key, value in pairs(self.hooks) do
if type(value) == "table" then
for method in pairs(value) do
_debug(self, string.format("key: %s method: %q |cff%s|r", tostring(key), method, self.hooks[key][method].active and "00ff00Active" or "ffff00Inactive"))
end
else
_debug(self, string.format("key: %s value: %q |cff%s|r", tostring(key), tostring(value), self.hooks[key].active and "00ff00Active" or "ffff00Inactive"))
end
end
end
--[[---------------------------------------------------------------------------------
Stub and Library registration
----------------------------------------------------------------------------------]]
local function activate(self, oldLib, oldDeactivate)
AceHook = self
AceHook.super.activate(self, oldLib, oldDeactivate)
if oldLib then
self.handlers = oldLib.handlers
self.funcs = oldLib.funcs
self.scripts = oldLib.scripts
self.actives = oldLib.actives
end
if not self.handlers then
self.handlers = {}
end
if not self.funcs then
self.funcs = {}
end
if not self.scripts then
self.scripts = {}
end
if not self.actives then
self.actives = {}
end
handlers = self.handlers
funcs = self.funcs
scripts = self.scripts
actives = self.actives
if oldDeactivate then
oldDeactivate(oldLib)
end
end
AceLibrary:Register(AceHook, MAJOR_VERSION, MINOR_VERSION, activate)
+751
View File
@@ -0,0 +1,751 @@
--[[
Name: AceLibrary
Revision: $Rev: 14130 $
Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team)
Inspired By: Iriel (iriel@vigilance-committee.org)
Tekkub (tekkub@gmail.com)
Revision: $Rev: 14130 $
Website: http://www.wowace.com/
Documentation: http://www.wowace.com/index.php/AceLibrary
SVN: http://svn.wowace.com/root/trunk/Ace2/AceLibrary
Description: Versioning library to handle other library instances, upgrading,
and proper access.
It also provides a base for libraries to work off of, providing
proper error tools. It is handy because all the errors occur in the
file that called it, not in the library file itself.
Dependencies: None
]]
local ACELIBRARY_MAJOR = "AceLibrary"
local ACELIBRARY_MINOR = "$Revision: 14130 $"
local table_setn
do
local version = GetBuildInfo()
if string.find(version, "^2%.") then
-- 2.0.0
table_setn = function() end
else
table_setn = table.setn
end
end
local string_gfind = string.gmatch or string.gfind
local _G = getfenv(0)
local previous = _G[ACELIBRARY_MAJOR]
if previous and not previous:IsNewVersion(ACELIBRARY_MAJOR, ACELIBRARY_MINOR) then return end
-- @table AceLibrary
-- @brief System to handle all versioning of libraries.
local AceLibrary = {}
local AceLibrary_mt = {}
setmetatable(AceLibrary, AceLibrary_mt)
local tmp
local function error(self, message, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
if type(self) ~= "table" then
_G.error(string.format("Bad argument #1 to `error' (table expected, got %s)", type(self)), 2)
end
if not tmp then
tmp = {}
else
for k in pairs(tmp) do tmp[k] = nil end
table_setn(tmp, 0)
end
table.insert(tmp, a1)
table.insert(tmp, a2)
table.insert(tmp, a3)
table.insert(tmp, a4)
table.insert(tmp, a5)
table.insert(tmp, a6)
table.insert(tmp, a7)
table.insert(tmp, a8)
table.insert(tmp, a9)
table.insert(tmp, a10)
table.insert(tmp, a11)
table.insert(tmp, a12)
table.insert(tmp, a13)
table.insert(tmp, a14)
table.insert(tmp, a15)
table.insert(tmp, a16)
table.insert(tmp, a17)
table.insert(tmp, a18)
table.insert(tmp, a19)
table.insert(tmp, a20)
local stack = debugstack()
if not message then
local _,_,second = string.find(stack, "\n(.-)\n")
message = "error raised! " .. second
else
for i = 1,table.getn(tmp) do
tmp[i] = tostring(tmp[i])
end
for i = 1,10 do
table.insert(tmp, "nil")
end
message = string.format(message, unpack(tmp))
end
if getmetatable(self) and getmetatable(self).__tostring then
message = string.format("%s: %s", tostring(self), message)
elseif type(rawget(self, 'GetLibraryVersion')) == "function" and AceLibrary:HasInstance(self:GetLibraryVersion()) then
message = string.format("%s: %s", self:GetLibraryVersion(), message)
elseif type(rawget(self, 'class')) == "table" and type(rawget(self.class, 'GetLibraryVersion')) == "function" and AceLibrary:HasInstance(self.class:GetLibraryVersion()) then
message = string.format("%s: %s", self.class:GetLibraryVersion(), message)
end
local first = string.gsub(stack, "\n.*", "")
local file = string.gsub(first, ".*\\(.*).lua:%d+: .*", "%1")
file = string.gsub(file, "([%(%)%.%*%+%-%[%]%?%^%$%%])", "%%%1")
local i = 0
for s in string_gfind(stack, "\n([^\n]*)") do
i = i + 1
if not string.find(s, file .. "%.lua:%d+:") then
file = string.gsub(s, "^.*\\(.*).lua:%d+: .*", "%1")
file = string.gsub(file, "([%(%)%.%*%+%-%[%]%?%^%$%%])", "%%%1")
break
end
end
local j = 0
for s in string_gfind(stack, "\n([^\n]*)") do
j = j + 1
if j > i and not string.find(s, file .. "%.lua:%d+:") then
_G.error(message, j + 1)
return
end
end
_G.error(message, 2)
return
end
local function assert(self, condition, message, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
if not condition then
if not message then
local stack = debugstack()
local _,_,second = string.find(stack, "\n(.-)\n")
message = "assertion failed! " .. second
end
error(self, message, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
return
end
return condition
end
local function argCheck(self, arg, num, kind, kind2, kind3, kind4, kind5)
if type(num) ~= "number" then
error(self, "Bad argument #3 to `argCheck' (number expected, got %s)", type(num))
elseif type(kind) ~= "string" then
error(self, "Bad argument #4 to `argCheck' (string expected, got %s)", type(kind))
end
local errored = false
arg = type(arg)
if arg ~= kind and arg ~= kind2 and arg ~= kind3 and arg ~= kind4 and arg ~= kind5 then
local _,_,func = string.find(debugstack(), "`argCheck'.-([`<].-['>])")
if not func then
_,_,func = string.find(debugstack(), "([`<].-['>])")
end
if kind5 then
error(self, "Bad argument #%s to %s (%s, %s, %s, %s, or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, kind3, kind4, kind5, arg)
elseif kind4 then
error(self, "Bad argument #%s to %s (%s, %s, %s, or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, kind3, kind4, arg)
elseif kind3 then
error(self, "Bad argument #%s to %s (%s, %s, or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, kind3, arg)
elseif kind2 then
error(self, "Bad argument #%s to %s (%s or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, arg)
else
error(self, "Bad argument #%s to %s (%s expected, got %s)", tonumber(num) or 0/0, func, kind, arg)
end
end
end
local function pcall(self, func, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20 = _G.pcall(func, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
if not a1 then
error(self, string.gsub(a2, ".-%.lua:%d-: ", ""))
else
return a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20
end
end
local recurse = {}
local function addToPositions(t, major)
if not AceLibrary.positions[t] or AceLibrary.positions[t] == major then
rawset(t, recurse, true)
AceLibrary.positions[t] = major
for k,v in pairs(t) do
if type(v) == "table" and not rawget(v, recurse) then
addToPositions(v, major)
end
if type(k) == "table" and not rawget(k, recurse) then
addToPositions(k, major)
end
end
local mt = getmetatable(t)
if mt and not rawget(mt, recurse) then
addToPositions(mt, major)
end
rawset(t, recurse, nil)
end
end
local function svnRevisionToNumber(text)
if type(text) == "string" then
if string.find(text, "^%$Revision: (%d+) %$$") then
return tonumber((string.gsub(text, "^%$Revision: (%d+) %$$", "%1")))
elseif string.find(text, "^%$Rev: (%d+) %$$") then
return tonumber((string.gsub(text, "^%$Rev: (%d+) %$$", "%1")))
elseif string.find(text, "^%$LastChangedRevision: (%d+) %$$") then
return tonumber((string.gsub(text, "^%$LastChangedRevision: (%d+) %$$", "%1")))
end
elseif type(text) == "number" then
return text
end
return nil
end
local crawlReplace
do
local recurse = {}
local function func(t, to, from)
if recurse[t] then
return
end
recurse[t] = true
local mt = getmetatable(t)
setmetatable(t, nil)
rawset(t, to, rawget(t, from))
rawset(t, from, nil)
for k,v in pairs(t) do
if v == from then
t[k] = to
elseif type(v) == "table" then
if not recurse[v] then
func(v, to, from)
end
end
if type(k) == "table" then
if not recurse[k] then
func(k, to, from)
end
end
end
setmetatable(t, mt)
if mt then
if mt == from then
setmetatable(t, to)
elseif not recurse[mt] then
func(mt, to, from)
end
end
end
function crawlReplace(t, to, from)
func(t, to, from)
for k in pairs(recurse) do
recurse[k] = nil
end
end
end
-- @function destroyTable
-- @brief remove all the contents of a table
-- @param t table to destroy
local function destroyTable(t)
setmetatable(t, nil)
for k,v in pairs(t) do t[k] = nil end
table_setn(t, 0)
end
local function isFrame(frame)
return type(frame) == "table" and type(rawget(frame, 0)) == "userdata" and type(rawget(frame, 'IsFrameType')) == "function" and getmetatable(frame) and type(rawget(getmetatable(frame), '__index')) == "function"
end
local new, del
do
local tables = setmetatable({}, {__mode = "k"})
function new()
local t = next(tables)
if t then
tables[t] = nil
return t
else
return {}
end
end
function del(t, depth)
if depth and depth > 0 then
for k,v in pairs(t) do
if type(v) == "table" and not isFrame(v) then
del(v, depth - 1)
end
end
end
destroyTable(t)
tables[t] = true
end
end
-- @function copyTable
-- @brief Create a shallow copy of a table and return it.
-- @param from The table to copy from
-- @return A shallow copy of the table
local function copyTable(from)
local to = new()
for k,v in pairs(from) do to[k] = v end
table_setn(to, table.getn(from))
setmetatable(to, getmetatable(from))
return to
end
-- @function deepTransfer
-- @brief Fully transfer all data, keeping proper previous table
-- backreferences stable.
-- @param to The table with which data is to be injected into
-- @param from The table whose data will be injected into the first
-- @param saveFields If available, a shallow copy of the basic data is saved
-- in here.
-- @param list The account of table references
-- @param list2 The current status on which tables have been traversed.
local deepTransfer
do
-- @function examine
-- @brief Take account of all the table references to be shared
-- between the to and from tables.
-- @param to The table with which data is to be injected into
-- @param from The table whose data will be injected into the first
-- @param list An account of the table references
local function examine(to, from, list, major)
list[from] = to
for k,v in pairs(from) do
if rawget(to, k) and type(from[k]) == "table" and type(to[k]) == "table" and not list[from[k]] then
if from[k] == to[k] then
list[from[k]] = to[k]
elseif AceLibrary.positions[from[v]] ~= major and AceLibrary.positions[from[v]] then
list[from[k]] = from[k]
elseif not list[from[k]] then
examine(to[k], from[k], list, major)
end
end
end
return list
end
function deepTransfer(to, from, saveFields, major, list, list2)
setmetatable(to, nil)
local createdList
if not list then
createdList = true
list = new()
list2 = new()
examine(to, from, list, major)
end
list2[to] = to
for k,v in pairs(to) do
if type(rawget(from, k)) ~= "table" or type(v) ~= "table" or isFrame(v) then
if saveFields then
saveFields[k] = v
end
to[k] = nil
elseif v ~= _G then
if saveFields then
saveFields[k] = copyTable(v)
end
end
end
for k in pairs(from) do
if rawget(to, k) and to[k] ~= from[k] and AceLibrary.positions[to[k]] == major and from[k] ~= _G then
if not list2[to[k]] then
deepTransfer(to[k], from[k], nil, major, list, list2)
end
to[k] = list[to[k]] or list2[to[k]]
else
rawset(to, k, from[k])
end
end
table_setn(to, table.getn(from))
setmetatable(to, getmetatable(from))
local mt = getmetatable(to)
if mt then
if list[mt] then
setmetatable(to, list[mt])
elseif mt.__index and list[mt.__index] then
mt.__index = list[mt.__index]
end
end
destroyTable(from)
if createdList then
del(list)
del(list2)
end
end
end
-- @method TryToLoadStandalone
-- @brief Attempt to find and load a standalone version of the requested library
-- @param major A string representing the major version
-- @return If library is found, return values from the call to LoadAddOn are returned
-- If the library has been requested previously, nil is returned.
local function TryToLoadStandalone(major)
if not AceLibrary.scannedlibs then AceLibrary.scannedlibs = {} end
if AceLibrary.scannedlibs[major] then return end
AceLibrary.scannedlibs[major] = true
local name, _, _, enabled, loadable = GetAddOnInfo(major)
if loadable then
return LoadAddOn(name)
end
for i=1,GetNumAddOns() do
if GetAddOnMetadata(i, "X-AceLibrary-"..major) then
local name, _, _, enabled, loadable = GetAddOnInfo(i)
if loadable then
return LoadAddOn(name)
end
end
end
end
-- @method IsNewVersion
-- @brief Obtain whether the supplied version would be an upgrade to the
-- current version. This allows for bypass code in library
-- declaration.
-- @param major A string representing the major version
-- @param minor An integer or an svn revision string representing the minor version
-- @return whether the supplied version would be newer than what is
-- currently available.
function AceLibrary:IsNewVersion(major, minor)
argCheck(self, major, 2, "string")
TryToLoadStandalone(major)
if type(minor) == "string" then
local m = svnRevisionToNumber(minor)
if m then
minor = m
else
_G.error(string.format("Bad argument #3 to `IsNewVersion'. Must be a number or SVN revision string. %q is not appropriate", minor), 2)
end
end
argCheck(self, minor, 3, "number")
local data = self.libs[major]
if not data then
return true
end
return data.minor < minor
end
-- @method HasInstance
-- @brief Returns whether an instance exists. This allows for optional support of a library.
-- @param major A string representing the major version.
-- @param minor (optional) An integer or an svn revision string representing the minor version.
-- @return Whether an instance exists.
function AceLibrary:HasInstance(major, minor)
argCheck(self, major, 2, "string")
TryToLoadStandalone(major)
if minor then
if type(minor) == "string" then
local m = svnRevisionToNumber(minor)
if m then
minor = m
else
_G.error(string.format("Bad argument #3 to `HasInstance'. Must be a number or SVN revision string. %q is not appropriate", minor), 2)
end
end
argCheck(self, minor, 3, "number")
if not self.libs[major] then
return
end
return self.libs[major].minor == minor
end
return self.libs[major] and true
end
-- @method GetInstance
-- @brief Returns the library with the given major/minor version.
-- @param major A string representing the major version.
-- @param minor (optional) An integer or an svn revision string representing the minor version.
-- @return The library with the given major/minor version.
function AceLibrary:GetInstance(major, minor)
argCheck(self, major, 2, "string")
TryToLoadStandalone(major)
local data = self.libs[major]
if not data then
_G.error(string.format("Cannot find a library instance of %s.", major), 2)
return
end
if minor then
if type(minor) == "string" then
local m = svnRevisionToNumber(minor)
if m then
minor = m
else
_G.error(string.format("Bad argument #3 to `GetInstance'. Must be a number or SVN revision string. %q is not appropriate", minor), 2)
end
end
argCheck(self, minor, 2, "number")
if data.minor ~= minor then
_G.error(string.format("Cannot find a library instance of %s, minor version %d.", major, minor), 2)
return
end
end
return data.instance
end
-- Syntax sugar. AceLibrary("FooBar-1.0")
AceLibrary_mt.__call = AceLibrary.GetInstance
local donothing
local AceEvent
-- @method Register
-- @brief Registers a new version of a given library.
-- @param newInstance the library to register
-- @param major the major version of the library
-- @param minor the minor version of the library
-- @param activateFunc (optional) A function to be called when the library is
-- fully activated. Takes the arguments
-- (newInstance [, oldInstance, oldDeactivateFunc]). If
-- oldInstance is given, you should probably call
-- oldDeactivateFunc(oldInstance).
-- @param deactivateFunc (optional) A function to be called by a newer library's
-- activateFunc.
-- @param externalFunc (optional) A function to be called whenever a new
-- library is registered.
function AceLibrary:Register(newInstance, major, minor, activateFunc, deactivateFunc, externalFunc)
argCheck(self, newInstance, 2, "table")
argCheck(self, major, 3, "string")
if type(minor) == "string" then
local m = svnRevisionToNumber(minor)
if m then
minor = m
else
_G.error(string.format("Bad argument #4 to `Register'. Must be a number or SVN revision string. %q is not appropriate", minor), 2)
end
end
argCheck(self, minor, 4, "number")
if math.floor(minor) ~= minor or minor < 0 then
error(self, "Bad argument #4 to `Register' (integer >= 0 expected, got %s)", minor)
end
argCheck(self, activateFunc, 5, "function", "nil")
argCheck(self, deactivateFunc, 6, "function", "nil")
argCheck(self, externalFunc, 7, "function", "nil")
if not deactivateFunc then
if not donothing then
donothing = function() end
end
deactivateFunc = donothing
end
local data = self.libs[major]
if not data then
-- This is new
local instance = copyTable(newInstance)
crawlReplace(instance, instance, newInstance)
destroyTable(newInstance)
if AceLibrary == newInstance then
self = instance
AceLibrary = instance
end
self.libs[major] = {
instance = instance,
minor = minor,
deactivateFunc = deactivateFunc,
externalFunc = externalFunc,
}
rawset(instance, 'GetLibraryVersion', function(self)
return major, minor
end)
if not rawget(instance, 'error') then
rawset(instance, 'error', error)
end
if not rawget(instance, 'assert') then
rawset(instance, 'assert', assert)
end
if not rawget(instance, 'argCheck') then
rawset(instance, 'argCheck', argCheck)
end
if not rawget(instance, 'pcall') then
rawset(instance, 'pcall', pcall)
end
addToPositions(instance, major)
if activateFunc then
activateFunc(instance, nil, nil) -- no old version, so explicit nil
end
if externalFunc then
for k,data in pairs(self.libs) do
if k ~= major then
externalFunc(instance, k, data.instance)
end
end
end
for k,data in pairs(self.libs) do
if k ~= major and data.externalFunc then
data.externalFunc(data.instance, major, instance)
end
end
if major == "AceEvent-2.0" then
AceEvent = instance
end
if AceEvent then
AceEvent.TriggerEvent(self, "AceLibrary_Register", major, instance)
end
return instance
end
local instance = data.instance
if minor <= data.minor then
-- This one is already obsolete, raise an error.
_G.error(string.format("Obsolete library registered. %s is already registered at version %d. You are trying to register version %d. Hint: if not AceLibrary:IsNewVersion(%q, %d) then return end", major, data.minor, minor, major, minor), 2)
return
end
-- This is an update
local oldInstance = new()
addToPositions(newInstance, major)
local isAceLibrary = (AceLibrary == newInstance)
local old_error, old_assert, old_argCheck, old_pcall
if isAceLibrary then
self = instance
AceLibrary = instance
old_error = instance.error
old_assert = instance.assert
old_argCheck = instance.argCheck
old_pcall = instance.pcall
self.error = error
self.assert = assert
self.argCheck = argCheck
self.pcall = pcall
end
deepTransfer(instance, newInstance, oldInstance, major)
crawlReplace(instance, instance, newInstance)
local oldDeactivateFunc = data.deactivateFunc
data.minor = minor
data.deactivateFunc = deactivateFunc
data.externalFunc = externalFunc
rawset(instance, 'GetLibraryVersion', function(self)
return major, minor
end)
if not rawget(instance, 'error') then
rawset(instance, 'error', error)
end
if not rawget(instance, 'assert') then
rawset(instance, 'assert', assert)
end
if not rawget(instance, 'argCheck') then
rawset(instance, 'argCheck', argCheck)
end
if not rawget(instance, 'pcall') then
rawset(instance, 'pcall', pcall)
end
if isAceLibrary then
for _,v in pairs(self.libs) do
local i = type(v) == "table" and v.instance
if type(i) == "table" then
if not rawget(i, 'error') or i.error == old_error then
rawset(i, 'error', error)
end
if not rawget(i, 'assert') or i.assert == old_assert then
rawset(i, 'assert', assert)
end
if not rawget(i, 'argCheck') or i.argCheck == old_argCheck then
rawset(i, 'argCheck', argCheck)
end
if not rawget(i, 'pcall') or i.pcall == old_pcall then
rawset(i, 'pcall', pcall)
end
end
end
end
if activateFunc then
activateFunc(instance, oldInstance, oldDeactivateFunc)
else
oldDeactivateFunc(oldInstance)
end
del(oldInstance)
if externalFunc then
for k,data in pairs(self.libs) do
if k ~= major then
externalFunc(instance, k, data.instance)
end
end
end
return instance
end
local iter
function AceLibrary:IterateLibraries()
if not iter then
local function iter(t, k)
k = next(t, k)
if not k then
return nil
else
return k, t[k].instance
end
end
end
return iter, self.libs, nil
end
-- @function Activate
-- @brief The activateFunc for AceLibrary itself. Called when
-- AceLibrary properly registers.
-- @param self Reference to AceLibrary
-- @param oldLib (optional) Reference to an old version of AceLibrary
-- @param oldDeactivate (optional) Function to deactivate the old lib
local function activate(self, oldLib, oldDeactivate)
if not self.libs then
if oldLib then
self.libs = oldLib.libs
self.scannedlibs = oldLib.scannedlibs
end
if not self.libs then
self.libs = {}
end
if not self.scannedlibs then
self.scannedlibs = {}
end
end
if not self.positions then
if oldLib then
self.positions = oldLib.positions
end
if not self.positions then
self.positions = setmetatable({}, { __mode = "k" })
end
end
-- Expose the library in the global environment
_G[ACELIBRARY_MAJOR] = self
if oldDeactivate then
oldDeactivate(oldLib)
end
end
if not previous then
previous = AceLibrary
end
if not previous.libs then
previous.libs = {}
end
AceLibrary.libs = previous.libs
if not previous.positions then
previous.positions = setmetatable({}, { __mode = "k" })
end
AceLibrary.positions = previous.positions
AceLibrary:Register(AceLibrary, ACELIBRARY_MAJOR, ACELIBRARY_MINOR, activate)
+537
View File
@@ -0,0 +1,537 @@
--[[
Name: AceLocale-2.2
Revision: $Rev: 15291 $
Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team)
Inspired By: Ace 1.x by Turan (turan@gryphon.com)
Website: http://www.wowace.com/
Documentation: http://www.wowace.com/index.php/AceLocale-2.2
SVN: http://svn.wowace.com/root/trunk/Ace2/AceLocale-2.2
Description: Localization library for addons to use to handle proper
localization and internationalization.
Dependencies: AceLibrary
]]
local MAJOR_VERSION = "AceLocale-2.2"
local MINOR_VERSION = "$Revision: 15291 $"
if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary.") end
if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end
local AceLocale = {}
local DEFAULT_LOCALE = "enUS"
local _G = getfenv(0)
local BASE_TRANSLATIONS, DEBUGGING, TRANSLATIONS, BASE_LOCALE, TRANSLATION_TABLES, REVERSE_TRANSLATIONS, STRICTNESS, DYNAMIC_LOCALES, CURRENT_LOCALE, NAME
local rawget = rawget
local rawset = rawset
local type = type
local newRegistries = {}
local scheduleClear
local lastSelf
local __index = function(self, key)
lastSelf = self
local value = (rawget(self, TRANSLATIONS) or AceLocale.prototype)[key]
rawset(self, key, value)
return value
end
local __newindex = function(self, k, v)
if type(v) ~= "function" and type(k) ~= "table" then
AceLocale.error(self, "Cannot change the values of an AceLocale instance.")
end
rawset(self, k, v)
end
local __tostring = function(self)
if type(rawget(self, 'GetLibraryVersion')) == "function" then
return self:GetLibraryVersion()
else
return "AceLocale(" .. self[NAME] .. ")"
end
end
local function clearCache(self)
if not rawget(self, BASE_TRANSLATIONS) then
return
end
local cache = self[BASE_TRANSLATIONS]
rawset(self, REVERSE_TRANSLATIONS, nil)
for k in pairs(self) do
if rawget(cache, k) ~= nil then
self[k] = nil
end
end
rawset(self, 'tmp', true)
self.tmp = nil
end
local function refixInstance(instance)
if getmetatable(instance) then
setmetatable(instance, nil)
end
local translations = instance[TRANSLATIONS]
if translations then
if getmetatable(translations) then
setmetatable(translations, nil)
end
local baseTranslations = instance[BASE_TRANSLATIONS]
if getmetatable(baseTranslations) then
setmetatable(baseTranslations, nil)
end
if translations == baseTranslations or instance[STRICTNESS] then
setmetatable(instance, {
__index = __index,
__newindex = __newindex,
__tostring = __tostring
})
setmetatable(translations, {
__index = AceLocale.prototype
})
else
setmetatable(instance, {
__index = __index,
__newindex = __newindex,
__tostring = __tostring
})
setmetatable(translations, {
__index = baseTranslations,
})
setmetatable(baseTranslations, {
__index = AceLocale.prototype,
})
end
else
setmetatable(instance, {
__index = __index,
__newindex = __newindex,
__tostring = __tostring,
})
end
clearCache(instance)
newRegistries[instance] = true
scheduleClear()
return instance
end
function AceLocale:new(name)
self:argCheck(name, 2, "string")
if self.registry[name] and type(rawget(self.registry[name], 'GetLibraryVersion')) ~= "function" then
return self.registry[name]
end
AceLocale.registry[name] = refixInstance({
[STRICTNESS] = false,
[NAME] = name,
})
newRegistries[AceLocale.registry[name]] = true
return AceLocale.registry[name]
end
AceLocale.prototype = { class = AceLocale }
function AceLocale.prototype:EnableDebugging()
if rawget(self, BASE_TRANSLATIONS) then
AceLocale.error(self, "Cannot enable debugging after a translation has been registered.")
end
rawset(self, DEBUGGING, true)
end
function AceLocale.prototype:EnableDynamicLocales(override)
AceLocale.argCheck(self, override, 2, "boolean", "nil")
if not override and rawget(self, BASE_TRANSLATIONS) then
AceLocale.error(self, "Cannot enable dynamic locales after a translation has been registered.")
end
if not rawget(self, DYNAMIC_LOCALES) then
rawset(self, DYNAMIC_LOCALES, true)
if rawget(self, BASE_LOCALE) then
if not rawget(self, TRANSLATION_TABLES) then
rawset(self, TRANSLATION_TABLES, {})
end
self[TRANSLATION_TABLES][self[BASE_LOCALE]] = self[BASE_TRANSLATIONS]
self[TRANSLATION_TABLES][self[CURRENT_LOCALE]] = self[TRANSLATIONS]
end
end
end
function AceLocale.prototype:RegisterTranslations(locale, func)
AceLocale.argCheck(self, locale, 2, "string")
AceLocale.argCheck(self, func, 3, "function")
if locale == rawget(self, BASE_LOCALE) then
AceLocale.error(self, "Cannot provide the same locale more than once. %q provided twice.", locale)
end
if rawget(self, BASE_TRANSLATIONS) and GetLocale() ~= locale then
if rawget(self, DEBUGGING) or rawget(self, DYNAMIC_LOCALES) then
if not rawget(self, TRANSLATION_TABLES) then
rawset(self, TRANSLATION_TABLES, {})
end
if self[TRANSLATION_TABLES][locale] then
AceLocale.error(self, "Cannot provide the same locale more than once. %q provided twice.", locale)
end
local t = func()
func = nil
if type(t) ~= "table" then
AceLocale.error(self, "Bad argument #3 to `RegisterTranslations'. function did not return a table. (expected table, got %s)", type(t))
end
self[TRANSLATION_TABLES][locale] = t
t = nil
end
func = nil
return
end
local t = func()
func = nil
if type(t) ~= "table" then
AceLocale.error(self, "Bad argument #3 to `RegisterTranslations'. function did not return a table. (expected table, got %s)", type(t))
end
rawset(self, TRANSLATIONS, t)
if not rawget(self, BASE_TRANSLATIONS) then
rawset(self, BASE_TRANSLATIONS, t)
rawset(self, BASE_LOCALE, locale)
for key,value in pairs(t) do
if value == true then
t[key] = key
end
end
else
for key, value in pairs(self[TRANSLATIONS]) do
if not rawget(self[BASE_TRANSLATIONS], key) then
AceLocale.error(self, "Improper translation exists. %q is likely misspelled for locale %s.", key, locale)
end
if value == true then
AceLocale.error(self, "Can only accept true as a value on the base locale. %q is the base locale, %q is not.", rawget(self, BASE_LOCALE), locale)
end
end
end
rawset(self, CURRENT_LOCALE, locale)
refixInstance(self)
if rawget(self, DEBUGGING) or rawget(self, DYNAMIC_LOCALES) then
if not rawget(self, TRANSLATION_TABLES) then
rawset(self, TRANSLATION_TABLES, {})
end
self[TRANSLATION_TABLES][locale] = t
end
t = nil
end
function AceLocale.prototype:SetLocale(locale)
AceLocale.argCheck(self, locale, 2, "string", "boolean")
if not rawget(self, DYNAMIC_LOCALES) then
AceLocale.error(self, "Cannot call `SetLocale' without first calling `EnableDynamicLocales'.")
end
if not rawget(self, TRANSLATION_TABLES) then
AceLocale.error(self, "Cannot call `SetLocale' without first calling `RegisterTranslations'.")
end
if locale == true then
locale = GetLocale()
if not self[TRANSLATION_TABLES][locale] then
locale = self[BASE_LOCALE]
end
end
if self[CURRENT_LOCALE] == locale then
return
end
if not self[TRANSLATION_TABLES][locale] then
AceLocale.error(self, "Locale %q not registered.", locale)
end
self[TRANSLATIONS] = self[TRANSLATION_TABLES][locale]
self[CURRENT_LOCALE] = locale
refixInstance(self)
end
function AceLocale.prototype:GetLocale()
if not rawget(self, TRANSLATION_TABLES) then
AceLocale.error(self, "Cannot call `GetLocale' without first calling `RegisterTranslations'.")
end
return self[CURRENT_LOCALE]
end
local function iter(t, position)
return (next(t, position))
end
function AceLocale.prototype:IterateAvailableLocales()
if not rawget(self, DYNAMIC_LOCALES) then
AceLocale.error(self, "Cannot call `IterateAvailableLocales' without first calling `EnableDynamicLocales'.")
end
if not rawget(self, TRANSLATION_TABLES) then
AceLocale.error(self, "Cannot call `IterateAvailableLocales' without first calling `RegisterTranslations'.")
end
return iter, self[TRANSLATION_TABLES], nil
end
function AceLocale.prototype:HasLocale(locale)
if not rawget(self, DYNAMIC_LOCALES) then
AceLocale.error(self, "Cannot call `HasLocale' without first calling `EnableDynamicLocales'.")
end
AceLocale.argCheck(self, locale, 2, "string")
return rawget(self, TRANSLATION_TABLES) and self[TRANSLATION_TABLES][locale] ~= nil
end
function AceLocale.prototype:SetStrictness(strict)
AceLocale.argCheck(self, strict, 2, "boolean")
local mt = getmetatable(self)
if not mt then
AceLocale.error(self, "Cannot call `SetStrictness' without a metatable.")
end
if not rawget(self, TRANSLATIONS) then
AceLocale.error(self, "No translations registered.")
end
rawset(self, STRICTNESS, strict)
refixInstance(self)
end
local function initReverse(self)
rawset(self, REVERSE_TRANSLATIONS, {})
local alpha = self[TRANSLATIONS]
local bravo = self[REVERSE_TRANSLATIONS]
for base, localized in pairs(alpha) do
bravo[localized] = base
end
end
function AceLocale.prototype:GetTranslation(text)
AceLocale.argCheck(self, text, 1, "string", "number")
if not rawget(self, TRANSLATIONS) then
AceLocale.error(self, "No translations registered")
end
return self[text]
end
function AceLocale.prototype:GetStrictTranslation(text)
AceLocale.argCheck(self, text, 1, "string", "number")
local x = rawget(self, TRANSLATIONS)
if not x then
AceLocale.error(self, "No translations registered")
end
local value = rawget(x, text)
if value == nil then
AceLocale.error(self, "Translation %q does not exist for locale %s", text, self[CURRENT_LOCALE])
end
return value
end
function AceLocale.prototype:GetReverseTranslation(text)
local x = rawget(self, REVERSE_TRANSLATIONS)
if not x then
if not rawget(self, TRANSLATIONS) then
AceLocale.error(self, "No translations registered")
end
initReverse(self)
x = self[REVERSE_TRANSLATIONS]
end
local translation = x[text]
if not translation then
AceLocale.error(self, "Reverse translation for %q does not exist", text)
end
return translation
end
function AceLocale.prototype:GetIterator()
local x = rawget(self, TRANSLATIONS)
if not x then
AceLocale.error(self, "No translations registered")
end
return next, x, nil
end
function AceLocale.prototype:GetReverseIterator()
local x = rawget(self, REVERSE_TRANSLATIONS)
if not x then
if not rawget(self, TRANSLATIONS) then
AceLocale.error(self, "No translations registered")
end
initReverse(self)
x = self[REVERSE_TRANSLATIONS]
end
return next, x, nil
end
function AceLocale.prototype:HasTranslation(text)
AceLocale.argCheck(self, text, 1, "string", "number")
local x = rawget(self, TRANSLATIONS)
if not x then
AceLocale.error(self, "No translations registered")
end
return rawget(x, text) and true
end
function AceLocale.prototype:HasReverseTranslation(text)
local x = rawget(self, REVERSE_TRANSLATIONS)
if not x then
if not rawget(self, TRANSLATIONS) then
AceLocale.error(self, "No translations registered")
end
initReverse(self)
x = self[REVERSE_TRANSLATIONS]
end
return x[text] and true
end
function AceLocale.prototype:Debug()
if not rawget(self, DEBUGGING) then
return
end
local words = {}
local locales = {"enUS", "deDE", "frFR", "koKR", "zhCN", "zhTW", "esES"}
local localizations = {}
DEFAULT_CHAT_FRAME:AddMessage("--- AceLocale Debug ---")
for _,locale in ipairs(locales) do
if not self[TRANSLATION_TABLES][locale] then
DEFAULT_CHAT_FRAME:AddMessage(string.format("Locale %q not found", locale))
else
localizations[locale] = self[TRANSLATION_TABLES][locale]
end
end
local localeDebug = {}
for locale, localization in pairs(localizations) do
localeDebug[locale] = {}
for word in pairs(localization) do
if type(localization[word]) == "table" then
if type(words[word]) ~= "table" then
words[word] = {}
end
for bit in pairs(localization[word]) do
if type(localization[word][bit]) == "string" then
words[word][bit] = true
end
end
elseif type(localization[word]) == "string" then
words[word] = true
end
end
end
for word in pairs(words) do
if type(words[word]) == "table" then
for bit in pairs(words[word]) do
for locale, localization in pairs(localizations) do
if not rawget(localization, word) or not localization[word][bit] then
localeDebug[locale][word .. "::" .. bit] = true
end
end
end
else
for locale, localization in pairs(localizations) do
if not rawget(localization, word) then
localeDebug[locale][word] = true
end
end
end
end
for locale, t in pairs(localeDebug) do
if not next(t) then
DEFAULT_CHAT_FRAME:AddMessage(string.format("Locale %q complete", locale))
else
DEFAULT_CHAT_FRAME:AddMessage(string.format("Locale %q missing:", locale))
for word in pairs(t) do
DEFAULT_CHAT_FRAME:AddMessage(string.format(" %q", word))
end
end
end
DEFAULT_CHAT_FRAME:AddMessage("--- End AceLocale Debug ---")
end
setmetatable(AceLocale.prototype, {
__index = function(self, k)
if type(k) ~= "table" and k ~= 0 and k ~= "GetLibraryVersion" and k ~= "error" and k ~= "assert" and k ~= "argCheck" and k ~= "pcall" then -- HACK: remove "GetLibraryVersion" and such later.
AceLocale.error(lastSelf or self, "Translation %q does not exist.", k)
end
return nil
end
})
local function activate(self, oldLib, oldDeactivate)
AceLocale = self
self.frame = oldLib and oldLib.frame or CreateFrame("Frame")
self.registry = oldLib and oldLib.registry or {}
self.BASE_TRANSLATIONS = oldLib and oldLib.BASE_TRANSLATIONS or {}
self.DEBUGGING = oldLib and oldLib.DEBUGGING or {}
self.TRANSLATIONS = oldLib and oldLib.TRANSLATIONS or {}
self.BASE_LOCALE = oldLib and oldLib.BASE_LOCALE or {}
self.TRANSLATION_TABLES = oldLib and oldLib.TRANSLATION_TABLES or {}
self.REVERSE_TRANSLATIONS = oldLib and oldLib.REVERSE_TRANSLATIONS or {}
self.STRICTNESS = oldLib and oldLib.STRICTNESS or {}
self.NAME = oldLib and oldLib.NAME or {}
self.DYNAMIC_LOCALES = oldLib and oldLib.DYNAMIC_LOCALES or {}
self.CURRENT_LOCALE = oldLib and oldLib.CURRENT_LOCALE or {}
BASE_TRANSLATIONS = self.BASE_TRANSLATIONS
DEBUGGING = self.DEBUGGING
TRANSLATIONS = self.TRANSLATIONS
BASE_LOCALE = self.BASE_LOCALE
TRANSLATION_TABLES = self.TRANSLATION_TABLES
REVERSE_TRANSLATIONS = self.REVERSE_TRANSLATIONS
STRICTNESS = self.STRICTNESS
NAME = self.NAME
DYNAMIC_LOCALES = self.DYNAMIC_LOCALES
CURRENT_LOCALE = self.CURRENT_LOCALE
local GetTime = GetTime
local timeUntilClear = GetTime() + 5
scheduleClear = function()
if next(newRegistries) then
self.frame:Show()
timeUntilClear = GetTime() + 5
end
end
if not self.registry then
self.registry = {}
else
for name, instance in pairs(self.registry) do
local name = name
local mt = getmetatable(instance)
setmetatable(instance, nil)
instance[NAME] = name
local strict
if instance[STRICTNESS] ~= nil then
strict = instance[STRICTNESS]
elseif instance[TRANSLATIONS] ~= instance[BASE_TRANSLATIONS] then
if getmetatable(instance[TRANSLATIONS]).__index == oldLib.prototype then
strict = true
end
end
instance[STRICTNESS] = strict and true or false
refixInstance(instance)
end
end
self.frame:SetScript("OnEvent", scheduleClear)
self.frame:SetScript("OnUpdate", function() -- (this, elapsed)
if timeUntilClear - GetTime() <= 0 then
self.frame:Hide()
for k in pairs(newRegistries) do
clearCache(k)
newRegistries[k] = nil
k = nil
end
end
end)
self.frame:UnregisterAllEvents()
self.frame:RegisterEvent("ADDON_LOADED")
self.frame:RegisterEvent("PLAYER_ENTERING_WORLD")
self.frame:Show()
if oldDeactivate then
oldDeactivate(oldLib)
end
end
AceLibrary:Register(AceLocale, MAJOR_VERSION, MINOR_VERSION, activate)
@@ -0,0 +1,404 @@
--[[
Name: AceModuleCore-2.0
Revision: $Rev: 12441 $
Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team)
Inspired By: Ace 1.x by Turan (turan@gryphon.com)
Website: http://www.wowace.com/
Documentation: http://www.wowace.com/index.php/AceModuleCore-2.0
SVN: http://svn.wowace.com/root/trunk/Ace2/AceModuleCore-2.0
Description: Mixin to provide a module system so that modules or plugins can
use an addon as its core.
Dependencies: AceLibrary, AceOO-2.0, AceAddon-2.0, Compost-2.0 (optional)
]]
local MAJOR_VERSION = "AceModuleCore-2.0"
local MINOR_VERSION = "$Revision: 12441 $"
if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary") end
if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end
if not AceLibrary:HasInstance("AceOO-2.0") then error(MAJOR_VERSION .. " requires AceOO-2.0") end
local table_setn
do
local version = GetBuildInfo()
if string.find(version, "^2%.") then
-- 2.0.0
table_setn = function() end
else
table_setn = table.setn
end
end
local new, del
do
local list = setmetatable({}, {__mode = 'k'})
function new()
local t = next(list)
if t then
list[t] = nil
return t
else
return {}
end
end
function del(t)
for k in pairs(t) do
t[k] = nil
end
table_setn(t, 0)
list[t] = true
return nil
end
end
local AceOO = AceLibrary:GetInstance("AceOO-2.0")
local AceModuleCore = AceOO.Mixin {
"NewModule",
"HasModule",
"GetModule",
"IsModule",
"IterateModules",
"SetModuleMixins",
"SetModuleClass",
"IsModuleActive",
"ToggleModuleActive"
}
local Compost = AceLibrary:HasInstance("Compost-2.0") and AceLibrary("Compost-2.0")
local function getlibrary(lib)
if type(lib) == "string" then
return AceLibrary(lib)
else
return lib
end
end
local tmp
function AceModuleCore:NewModule(name, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
if not self.modules then
AceModuleCore:error("CreatePrototype() must be called before attempting to create a new module.", 2)
end
AceModuleCore:argCheck(name, 2, "string")
if string.len(name) == 0 then
AceModuleCore:error("Bad argument #2 to `NewModule`, string must not be empty")
end
if self.modules[name] then
AceModuleCore:error("The module %q has already been registered", name)
end
if not tmp then
tmp = {}
end
if a1 then table.insert(tmp, a1)
if a2 then table.insert(tmp, a2)
if a3 then table.insert(tmp, a3)
if a4 then table.insert(tmp, a4)
if a5 then table.insert(tmp, a5)
if a6 then table.insert(tmp, a6)
if a7 then table.insert(tmp, a7)
if a8 then table.insert(tmp, a8)
if a9 then table.insert(tmp, a9)
if a10 then table.insert(tmp, a10)
if a11 then table.insert(tmp, a11)
if a12 then table.insert(tmp, a12)
if a13 then table.insert(tmp, a13)
if a14 then table.insert(tmp, a14)
if a15 then table.insert(tmp, a15)
if a16 then table.insert(tmp, a16)
if a17 then table.insert(tmp, a17)
if a18 then table.insert(tmp, a18)
if a19 then table.insert(tmp, a19)
if a20 then table.insert(tmp, a20)
end end end end end end end end end end end end end end end end end end end end
for k,v in ipairs(tmp) do
tmp[k] = getlibrary(v)
end
if self.moduleMixins then
for _,mixin in ipairs(self.moduleMixins) do
local exists = false
for _,v in ipairs(tmp) do
if mixin == v then
exists = true
break
end
end
if not exists then
table.insert(tmp, mixin)
end
end
end
local module = AceOO.Classpool(self.moduleClass, unpack(tmp)):new(name)
self.modules[name] = module
module.name = name
module.title = name
AceModuleCore.totalModules[module] = self
for k in pairs(tmp) do
tmp[k] = nil
end
table_setn(tmp, 0)
return module
end
function AceModuleCore:HasModule(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
if a1 then if not self.modules[a1] then return false end
if a2 then if not self.modules[a2] then return false end
if a3 then if not self.modules[a3] then return false end
if a4 then if not self.modules[a4] then return false end
if a5 then if not self.modules[a5] then return false end
if a6 then if not self.modules[a6] then return false end
if a7 then if not self.modules[a7] then return false end
if a8 then if not self.modules[a8] then return false end
if a9 then if not self.modules[a9] then return false end
if a10 then if not self.modules[a10] then return false end
if a11 then if not self.modules[a11] then return false end
if a12 then if not self.modules[a12] then return false end
if a13 then if not self.modules[a13] then return false end
if a14 then if not self.modules[a14] then return false end
if a15 then if not self.modules[a15] then return false end
if a16 then if not self.modules[a16] then return false end
if a17 then if not self.modules[a17] then return false end
if a18 then if not self.modules[a18] then return false end
if a19 then if not self.modules[a19] then return false end
if a20 then if not self.modules[a20] then return false end
end end end end end end end end end end end end end end end end end end end end
return true
end
function AceModuleCore:GetModule(name)
if not self.modules then
AceModuleCore:error("Error initializing class. Please report error.")
end
if not self.modules[name] then
AceModuleCore:error("Cannot find module %q.", name)
end
return self.modules[name]
end
function AceModuleCore:IsModule(module)
if self == AceModuleCore then
return AceModuleCore.totalModules[module]
else
for k,v in pairs(self.modules) do
if v == module then
return true
end
end
return false
end
end
function AceModuleCore:IterateModules()
local t = new()
for k in pairs(self.modules) do
table.insert(t, k)
end
table.sort(t)
local i = 0
return function()
i = i + 1
local x = t[i]
if x then
return x, self.modules[x]
else
t = del(t)
return nil
end
end, nil, nil
end
function AceModuleCore:SetModuleMixins(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
if self.moduleMixins then
AceModuleCore:error('Cannot call "SetModuleMixins" twice')
elseif not self.modules then
AceModuleCore:error("Error initializing class. Please report error.")
elseif next(self.modules) then
AceModuleCore:error('Cannot call "SetModuleMixins" after "NewModule" has been called.')
end
self.moduleMixins = Compost and Compost:Acquire(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) or {a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20}
for k,v in ipairs(self.moduleMixins) do
self.moduleMixins[k] = getlibrary(v)
end
end
function AceModuleCore:SetModuleClass(class)
class = getlibrary(class)
AceModuleCore:assert(AceOO.inherits(class, AceOO.Class), "Bad argument #2 to `SetModuleClass' (Class expected)")
if not self.modules then
AceModuleCore:error("Error initializing class. Please report error.")
end
if self.customModuleClass then
AceModuleCore:error("Cannot call `SetModuleClass' twice.")
end
self.customModuleClass = true
self.moduleClass = class
self.modulePrototype = class.prototype
end
function AceModuleCore:ToggleModuleActive(module, state)
AceModuleCore:argCheck(module, 2, "table", "string")
AceModuleCore:argCheck(state, 3, "nil", "boolean")
if type(module) == "string" then
if not self:HasModule(module) then
AceModuleCore:error("Cannot find module %q", module)
end
module = self:GetModule(module)
else
if not self:IsModule(module) then
AceModuleCore:error("%q is not a module", module)
end
end
local disable
if state == nil then
disable = self:IsModuleActive(module)
else
disable = not state
if disable ~= self:IsModuleActive(module) then
return
end
end
if type(module.ToggleActive) == "function" then
return module:ToggleActive(not disable)
elseif AceOO.inherits(self, "AceDB-2.0") then
if not self.db or not self.db.raw then
AceModuleCore:error("Cannot toggle a module until `RegisterDB' has been called and `ADDON_LOADED' has been fireed.")
end
if type(self.db.raw.disabledModules) ~= "table" then
self.db.raw.disabledModules = Compost and Compost:Acquire() or {}
end
local _,profile = self:GetProfile()
if type(self.db.raw.disabledModules[profile]) ~= "table" then
self.db.raw.disabledModules[profile] = Compost and Compost:Acquire() or {}
end
if type(self.db.raw.disabledModules[profile][module.name]) ~= "table" then
self.db.raw.disabledModules[profile][module.name] = disable or nil
end
if not disable then
if not next(self.db.raw.disabledModules[profile]) then
if Compost then
Compost:Reclaim(self.db.raw.disabledModules[profile])
end
self.db.raw.disabledModules[profile] = nil
end
if not next(self.db.raw.disabledModules) then
if Compost then
Compost:Reclaim(self.db.raw.disabledModules)
end
self.db.raw.disabledModules = nil
end
end
else
if type(self.disabledModules) ~= "table" then
self.disabledModules = Compost and Compost:Acquire() or {}
end
self.disabledModules[module.name] = disable or nil
end
if AceOO.inherits(module, "AceAddon-2.0") then
local AceAddon = AceLibrary("AceAddon-2.0")
if not AceAddon.addonsStarted[module] then
return
end
end
if not disable then
if type(module.OnEnable) == "function" then
module:OnEnable()
end
else
local current = module.class
while true do
if current == AceOO.Class then
break
end
if current.mixins then
for mixin in pairs(current.mixins) do
if type(mixin.OnEmbedDisable) == "function" then
mixin:OnEmbedDisable(module)
end
end
end
current = current.super
end
if type(module.OnDisable) == "function" then
module:OnDisable()
end
end
return not disable
end
function AceModuleCore:IsModuleActive(module)
AceModuleCore:argCheck(module, 2, "table", "string")
if AceModuleCore == self then
self:argCheck(module, 2, "table")
local core = AceModuleCore.totalModules[module]
if not core then
self:error("Bad argument #2 to `IsModuleActive'. Not a module")
end
return core:IsModuleActive(module)
end
if type(module) == "string" then
if not self:HasModule(module) then
AceModuleCore:error("Cannot find module %q", module)
end
module = self:GetModule(module)
else
if not self:IsModule(module) then
AceModuleCore:error("%q is not a module", module)
end
end
if type(module.IsActive) == "function" then
return module:IsActive()
elseif AceOO.inherits(self, "AceDB-2.0") then
local _,profile = self:GetProfile()
return not self.db or not self.db.raw or not self.db.raw.disabledModules or not self.db.raw.disabledModules[profile] or not self.db.raw.disabledModules[profile][module.name]
else
return not self.disabledModules or not self.disabledModules[module.name]
end
end
function AceModuleCore:OnInstanceInit(target)
if target.modules then
AceModuleCore:error("OnInstanceInit cannot be called twice")
end
target.modules = Compost and Compost:Acquire() or {}
target.moduleClass = AceOO.Class("AceAddon-2.0")
target.modulePrototype = target.moduleClass.prototype
end
AceModuleCore.OnManualEmbed = AceModuleCore.OnInstanceInit
local function activate(self, oldLib, oldDeactivate)
AceModuleCore = self
self.super.activate(self, oldLib, oldDeactivate)
if oldLib then
self.totalModules = oldLib.totalModules
end
if not self.totalModules then
self.totalModules = {}
end
end
local function external(self, major, instance)
if major == "Compost-2.0" then
Compost = instance
end
end
AceLibrary:Register(AceModuleCore, MAJOR_VERSION, MINOR_VERSION, activate)
AceModuleCore = AceLibrary(MAJOR_VERSION)
File diff suppressed because it is too large Load Diff
+136
View File
@@ -0,0 +1,136 @@
--[[
Name: Babble-Class-2.2
Revision: $Rev: 14410 $
Author(s): ckknight (ckknight@gmail.com)
Website: http://ckknight.wowinterface.com/
Documentation: http://wiki.wowace.com/index.php/Babble-Class-2.2
SVN: http://svn.wowace.com/root/trunk/Babble-2.2/Babble-Class-2.2
Description: A library to provide localizations for classes.
Dependencies: AceLibrary, AceLocale-2.2
]]
local MAJOR_VERSION = "Babble-Class-2.2"
local MINOR_VERSION = tonumber(string.sub("$Revision: 14410 $", 12, -3))
if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary") end
if not AceLibrary:HasInstance("AceLocale-2.2") then error(MAJOR_VERSION .. " requires AceLocale-2.2") end
local _, x = AceLibrary("AceLocale-2.2"):GetLibraryVersion()
MINOR_VERSION = MINOR_VERSION * 100000 + x
if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end
local BabbleClass = AceLibrary("AceLocale-2.2"):new(MAJOR_VERSION)
-- uncomment below for debug information
-- BabbleClass:EnableDebugging()
BabbleClass:RegisterTranslations("enUS", function()
return {
["Warlock"] = true,
["Warrior"] = true,
["Hunter"] = true,
["Mage"] = true,
["Priest"] = true,
["Druid"] = true,
["Paladin"] = true,
["Shaman"] = true,
["Rogue"] = true,
}
end)
BabbleClass:RegisterTranslations("deDE", function()
return {
["Warlock"] = "Hexenmeister",
["Warrior"] = "Krieger",
["Hunter"] = "Jäger",
["Mage"] = "Magier",
["Priest"] = "Priester",
["Druid"] = "Druide",
["Paladin"] = "Paladin",
["Shaman"] = "Schamane",
["Rogue"] = "Schurke",
}
end)
BabbleClass:RegisterTranslations("frFR", function()
return {
["Warlock"] = "D\195\169moniste",
["Warrior"] = "Guerrier",
["Hunter"] = "Chasseur",
["Mage"] = "Mage",
["Priest"] = "Pr\195\170tre",
["Druid"] = "Druide",
["Paladin"] = "Paladin",
["Shaman"] = "Chaman",
["Rogue"] = "Voleur",
}
end)
BabbleClass:RegisterTranslations("zhCN", function()
return {
["Warlock"] = "术士",
["Warrior"] = "战士",
["Hunter"] = "猎人",
["Mage"] = "法师",
["Priest"] = "牧师",
["Druid"] = "德鲁伊",
["Paladin"] = "圣骑士",
["Shaman"] = "萨满祭司",
["Rogue"] = "盗贼",
}
end)
BabbleClass:RegisterTranslations("zhTW", function()
return {
["Warlock"] = "術士",
["Warrior"] = "戰士",
["Hunter"] = "獵人",
["Mage"] = "法師",
["Priest"] = "牧師",
["Druid"] = "德魯伊",
["Paladin"] = "聖騎士",
["Shaman"] = "薩滿",
["Rogue"] = "盜賊",
}
end)
BabbleClass:RegisterTranslations("koKR", function()
return {
["Warlock"] = "흑마법사",
["Warrior"] = "전사",
["Hunter"] = "사냥꾼",
["Mage"] = "마법사",
["Priest"] = "사제",
["Druid"] = "드루이드",
["Paladin"] = "성기사",
["Shaman"] = "주술사",
["Rogue"] = "도적",
}
end)
BabbleClass:Debug()
BabbleClass:SetStrictness(true)
function BabbleClass:GetColor(class)
self:argCheck(class, 2, "string")
if self:HasReverseTranslation(class) then
class = string.upper(self:GetReverseTranslation(class))
else
class = string.upper(class)
end
if RAID_CLASS_COLORS and RAID_CLASS_COLORS[class] then
return RAID_CLASS_COLORS[class].r, RAID_CLASS_COLORS[class].g, RAID_CLASS_COLORS[class].b
end
return 0.63, 0.63, 0.63
end
function BabbleClass:GetHexColor(class)
self:argCheck(class, 2, "string")
local r, g, b = self:GetColor(class)
return string.format("%02x%02x%02x", r * 255, g * 255, b * 255)
end
AceLibrary:Register(BabbleClass, MAJOR_VERSION, MINOR_VERSION)
BabbleClass = nil
+277
View File
@@ -0,0 +1,277 @@
--[[
Name: Compost-2.0
Revision: $Rev: 11579 $
Author: Tekkub Stoutwrithe (tekkub@gmail.com)
Website: http://wiki.wowace.com/index.php/CompostLib
Documentation: http://wiki.wowace.com/index.php/Compost-2.0_API_Documentation
SVN: svn://svn.wowace.com/root/trunk/CompostLib/Compost-2.0
Description: Recycle tables to reduce garbage generation
Dependencies: AceLibrary
]]
local vmajor, vminor = "Compost-2.0", "$Revision: 11579 $"
if not AceLibrary then error(vmajor .. " requires AceLibrary.") end
if not AceLibrary:IsNewVersion(vmajor, vminor) then return end
local lib = {}
local table_setn
do
local version = GetBuildInfo()
if string.find(version, "^2%.") then
-- 2.0.0
table_setn = function() end
else
table_setn = table.setn
end
end
-- Activate a new instance of this library
local function activate(self, oldLib, oldDeactivate)
if oldLib then -- if upgrading
self.var, self.k = oldLib.var, oldLib.k
else
self.k = { -- Constants go here
maxcache = 10, -- I think this is a good number, I'll change it later if necessary
}
self.var = { -- "Local" variables go here
cache = {},
secondarycache = {},
}
-- This makes the secondary cache table a weak table, any values in it will be reclaimed
-- during a GC if there are no other references to them
setmetatable(self.var.secondarycache, {__mode = "v"})
end
if not self.var.tablechecks then
self.var.tablechecks = {}
setmetatable(self.var.tablechecks, {__mode = "kv"})
for i,v in ipairs(self.var.cache) do self.var.tablechecks[v] = true end
for i,v in ipairs(self.var.secondarycache) do self.var.tablechecks[v] = true end
end
if oldDeactivate then oldDeactivate(oldLib) end
end
-- Removes an empty table from the cache and returns it
-- or generates a new table if none available
function lib:GetTable()
if self.var.disabled then return {} end
if table.getn(self.var.cache) > 0 then
for i in pairs(self.var.cache) do
local t = table.remove(self.var.cache, i)
self.var.tablechecks[t] = nil
if next(t) then -- Table has been modified, someone holds a ref still, discard it
error("Someone is modifying tables reclaimed by Compost!")
self:IncDec("numdiscarded", 1)
else -- It's clean, we think... return it.
self:IncDec("totn", -1)
self:IncDec("numrecycled", 1)
return t
end
end
end
if next(self.var.secondarycache) then
for i in pairs(self.var.secondarycache) do
local t = table.remove(self.var.secondarycache, i)
self.var.tablechecks[t] = nil
if next(t) then -- Table has been modified, someone holds a ref still, discard it
error("Someone is modifying tables reclaimed by Compost!")
self:IncDec("numdiscarded", 1)
else -- It's clean, we think... return it.
self:IncDec("totn", -1)
self:IncDec("numrecycled", 1)
return t
end
end
end
self:IncDec("numnew", 1)
return {}
end
-- Returns a table, populated with any variables passed
-- basically: return {a1, a2, ... a20}
function lib:Acquire(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
local t = self:GetTable()
return self:Populate(t,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
end
-- Acquires a table and fills it with values, hash style
-- basically: return {k1 = v1, k2 = v2, ... k10 = v10}
function lib:AcquireHash(k1,v1,k2,v2,k3,v3,k4,v4,k5,v5,k6,v6,k7,v7,k8,v8,k9,v9,k10,v10)
local t = self:GetTable()
return self:PopulateHash(t,k1,v1,k2,v2,k3,v3,k4,v4,k5,v5,k6,v6,k7,v7,k8,v8,k9,v9,k10,v10)
end
-- Erases the table passed, fills it with the args passed, and returns it
-- Essentially the same as doing Reclaim then Acquire, except the same table is reused
function lib:Recycle(t,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
t = self:Erase(t)
return self:Populate(t,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
end
-- Erases the table passed, fills it with the args passed, and returns it
-- Essentially the same as doing Reclaim then AcquireHash, except the same table is reused
function lib:RecycleHash(t,k1,v1,k2,v2,k3,v3,k4,v4,k5,v5,k6,v6,k7,v7,k8,v8,k9,v9,k10,v10)
t = self:Erase(t)
return self:PopulateHash(t,k1,v1,k2,v2,k3,v3,k4,v4,k5,v5,k6,v6,k7,v7,k8,v8,k9,v9,k10,v10)
end
-- Returns a table to the cache
-- All tables referenced inside the passed table will be reclaimed also
-- If a depth is passed, Reclaim will call itsself recursivly
-- to reclaim all tables contained in t to the depth specified
function lib:Reclaim(t, depth)
if type(t) ~= "table" or self.var.disabled then return end
self:assert(not self.var.tablechecks[t], "Cannot reclaim a table twice")
if not self:ItemsInSecondaryCache() then self.var.totn = table.getn(self.var.cache) end
if depth and depth > 0 then
for i in pairs(t) do
if type(t[i]) == "table" then self:Reclaim(t[i], depth - 1) end
end
end
self:Erase(t)
if self.k.maxcache and table.getn(self.var.cache) >= self.k.maxcache then
table.insert(self.var.secondarycache, t)
else
table.insert(self.var.cache, t)
end
self:IncDec("numreclaim", 1)
self:IncDec("totn", 1)
self.var.maxn = math.max(self.var.maxn or 0, self.var.totn)
self.var.tablechecks[t] = true
end
-- Reclaims multiple tables, can take 10 recursive sets or 20 non-recursives,
-- or any combination of the two. Pass args in the following manner:
-- table1, depth1, tabl2, depth2, table3, table4, table5, depth5, ...
function lib:ReclaimMulti(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
if not a1 then return end
if type(a2) == "number" then
self:Reclaim(a1, a2)
self:ReclaimMulti(a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
else
self:Reclaim(a1)
self:ReclaimMulti(a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
end
end
-- Erases the table passed, nothing more nothing less :)
-- Tables referenced inside the passed table are NOT erased
function lib:Erase(t)
if type(t) ~= "table" then return end
if self.var.disabled then return {} end
local mem = gcinfo()
setmetatable(t, nil)
for i in pairs(t) do
t[i] = nil
end
t.reset = 1
t.reset = nil
table_setn(t, 0)
self:IncDec("memfreed", math.abs(gcinfo() - mem))
self:IncDec("numerased", 1)
return t
end
-- Fills the table passed with the args passed
function lib:Populate(t,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
if not t then return end
if a1 ~= nil then table.insert(t, a1) end
if a2 ~= nil then table.insert(t, a2) end
if a3 ~= nil then table.insert(t, a3) end
if a4 ~= nil then table.insert(t, a4) end
if a5 ~= nil then table.insert(t, a5) end
if a6 ~= nil then table.insert(t, a6) end
if a7 ~= nil then table.insert(t, a7) end
if a8 ~= nil then table.insert(t, a8) end
if a9 ~= nil then table.insert(t, a9) end
if a10 ~= nil then table.insert(t, a10) end
if a11 ~= nil then table.insert(t, a11) end
if a12 ~= nil then table.insert(t, a12) end
if a13 ~= nil then table.insert(t, a13) end
if a14 ~= nil then table.insert(t, a14) end
if a15 ~= nil then table.insert(t, a15) end
if a16 ~= nil then table.insert(t, a16) end
if a17 ~= nil then table.insert(t, a17) end
if a18 ~= nil then table.insert(t, a18) end
if a19 ~= nil then table.insert(t, a19) end
if a20 ~= nil then table.insert(t, a20) end
return t
end
-- Same as Populate, but takes 10 key-value pairs instead
function lib:PopulateHash(t,k1,v1,k2,v2,k3,v3,k4,v4,k5,v5,k6,v6,k7,v7,k8,v8,k9,v9,k10,v10)
if not t then return end
if k1 ~= nil then t[k1] = v1 end
if k2 ~= nil then t[k2] = v2 end
if k3 ~= nil then t[k3] = v3 end
if k4 ~= nil then t[k4] = v4 end
if k5 ~= nil then t[k5] = v5 end
if k6 ~= nil then t[k6] = v6 end
if k7 ~= nil then t[k7] = v7 end
if k8 ~= nil then t[k8] = v8 end
if k9 ~= nil then t[k9] = v9 end
if k10 ~= nil then t[k10] = v10 end
return t
end
function lib:IncDec(variable, diff)
self.var[variable] = (self.var[variable] or 0) + diff
end
function lib:ItemsInSecondaryCache()
for i in pairs(self.var.secondarycache) do return true end
end
function lib:GetSecondaryCacheSize()
local n = 0
for i in pairs(self.var.secondarycache) do n = n + 1 end
return n
end
-- Prints out statistics on table recycling
-- /script CompostLib:GetInstance("compost-1"):Stats()
function lib:Stats()
if self.var.disabled then ChatFrame1:AddMessage("CompostLib is disabled!")
else ChatFrame1:AddMessage(
string.format(
"|cff00ff00New: %d|r | |cffffff00Recycled: %d|r | |cff00ffffMain: %d|r | |cffff0000Secondary: %d|r | |cffff8800Max %d|r | |cff888888Erases: %d|r | |cffff00ffMem Saved: %d KiB|r | |cffff0088Lost to GC: %d",
self.var.numnew or 0,
self.var.numrecycled or 0,
table.getn(self.var.cache),
self:GetSecondaryCacheSize(),
self.var.maxn or 0,
(self.var.numerased or 0) - (self.var.numreclaim or 0),
(self.var.memfreed or 0) + 32/1024*(self.var.numrecycled or 0),
(self.var.numreclaim or 0) - (self.var.numrecycled or 0) - table.getn(self.var.cache)))
end
end
setmetatable(lib, { __call = lib.Acquire })
--------------------------------
-- Load this bitch! --
--------------------------------
AceLibrary:Register(lib, vmajor, vminor, activate)
lib = nil
+156
View File
@@ -0,0 +1,156 @@
--[[
Name: Crayon-2.0
Revision: $Rev: 7622 $
Author(s): ckknight (ckknight@gmail.com)
Website: http://ckknight.wowinterface.com/
Documentation: http://wiki.wowace.com/index.php/Crayon-2.0
SVN: http://svn.wowace.com/root/trunk/CrayonLib/Crayon-2.0
Description: A library to provide coloring tools.
Dependencies: AceLibrary
]]
--Theondry (theondry@gmail.com) added the purple. yell at me if it's wrong, please
local MAJOR_VERSION = "Crayon-2.0"
local MINOR_VERSION = "$Revision: 7622 $"
if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary") end
if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end
local Crayon = {}
Crayon.COLOR_HEX_RED = "ff0000"
Crayon.COLOR_HEX_ORANGE = "ff7f00"
Crayon.COLOR_HEX_YELLOW = "ffff00"
Crayon.COLOR_HEX_GREEN = "00ff00"
Crayon.COLOR_HEX_WHITE = "ffffff"
Crayon.COLOR_HEX_COPPER = "eda55f"
Crayon.COLOR_HEX_SILVER = "c7c7cf"
Crayon.COLOR_HEX_GOLD = "ffd700"
Crayon.COLOR_HEX_PURPLE = "9980CC"
function Crayon:Colorize(hexColor, text)
return "|cff" .. tostring(hexColor or 'ffffff') .. tostring(text) .. "|r"
end
function Crayon:Red(text) return self:Colorize(self.COLOR_HEX_RED, text) end
function Crayon:Orange(text) return self:Colorize(self.COLOR_HEX_ORANGE, text) end
function Crayon:Yellow(text) return self:Colorize(self.COLOR_HEX_YELLOW, text) end
function Crayon:Green(text) return self:Colorize(self.COLOR_HEX_GREEN, text) end
function Crayon:White(text) return self:Colorize(self.COLOR_HEX_WHITE, text) end
function Crayon:Copper(text) return self:Colorize(self.COLOR_HEX_COPPER, text) end
function Crayon:Silver(text) return self:Colorize(self.COLOR_HEX_SILVER, text) end
function Crayon:Gold(text) return self:Colorize(self.COLOR_HEX_GOLD, text) end
function Crayon:Purple(text) return self:Colorize(self.COLOR_HEX_PURPLE, text) end
local inf = 1/0
function Crayon:GetThresholdColor(quality, worst, worse, normal, better, best)
self:argCheck(quality, 2, "number")
if quality ~= quality or quality == inf or quality == -inf then
return 1, 1, 1
end
if not best then
worst = 0
worse = 0.25
normal = 0.5
better = 0.75
best = 1
end
if worst < best then
if (worse == better and quality == worse) or (worst == best and quality == worst) then
return 1, 1, 0
elseif quality <= worst then
return 1, 0, 0
elseif quality <= worse then
return 1, 0.5 * (quality - worst) / (worse - worst), 0
elseif quality <= normal then
return 1, 0.5 + 0.5 * (quality - worse) / (normal - worse), 0
elseif quality <= better then
return 1 - 0.5 * (quality - normal) / (better - normal), 1, 0
elseif quality <= best then
return 0.5 - 0.5 * (quality - better) / (best - better), 1, 0
else
return 0, 1, 0
end
else
if (worse == better and quality == worse) or (worst == best and quality == worst) then
return 1, 1, 0
elseif quality >= worst then
return 1, 0, 0
elseif quality >= worse then
return 1, 0.5 - 0.5 * (quality - worse) / (worst - worse), 0
elseif quality >= normal then
return 1, 1 - 0.5 * (quality - normal) / (worse - normal), 0
elseif quality >= better then
return 0.5 + 0.5 * (quality - better) / (normal - better), 1, 0
elseif quality >= best then
return 0.5 * (quality - best) / (better - best), 1, 0
else
return 0, 1, 0
end
end
end
function Crayon:GetThresholdHexColor(quality, worst, worse, normal, better, best)
local r, g, b = self:GetThresholdColor(quality, worst, worse, normal, better, best)
return string.format("%02x%02x%02x", r*255, g*255, b*255)
end
function Crayon:GetThresholdColorTrivial(quality, worst, worse, normal, better, best)
self:argCheck(quality, 2, "number")
if quality ~= quality or quality == inf or quality == -inf then
return 1, 1, 1
end
if not best then
worst = 0
worse = 0.25
normal = 0.5
better = 0.75
best = 1
end
if worst < best then
if worse == better and normal == worse then
return 1, 1, 0
elseif quality <= worst then
return 1, 0, 0
elseif quality <= worse then
return 1, 0.5 * (quality - worst) / (worse - worst), 0
elseif quality <= normal then
return 1, 0.5 + 0.5 * (quality - worse) / (normal - worse), 0
elseif quality <= better then
return 1 - (quality - normal) / (better - normal), 1, 0
elseif quality <= best then
local x = 0.5 * (quality - better) / (best - better)
return x, 1 - x, x
else
return 0.5, 0.5, 0.5
end
else
if worse == better and normal == worse then
return 1, 1, 0
elseif quality >= worst then
return 1, 0, 0
elseif quality >= worse then
return 1, 0.5 - 0.5 * (quality - worse) / (worst - worse), 0
elseif quality >= normal then
return 1, 1 - 0.5 * (quality - normal) / (worse - normal), 0
elseif quality >= better then
return (quality - better) / (normal - better), 1, 0
elseif quality >= best then
local x = 0.5 * (quality - best) / (better - best)
return 0.5 - x, 0.5 + x, 0.5 - x
else
return 0.5, 0.5, 0.5
end
end
end
function Crayon:GetThresholdHexColorTrivial(quality, worst, worse, normal, better, best)
local r, g, b = self:GetThresholdColorTrivial(quality, worst, worse, normal, better, best)
return string.format("%02x%02x%02x", r*255, g*255, b*255)
end
AceLibrary:Register(Crayon, MAJOR_VERSION, MINOR_VERSION)
Crayon = nil
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+179
View File
@@ -0,0 +1,179 @@
local T = AceLibrary("Tablet-2.0")
local D = AceLibrary("Dewdrop-2.0")
local C = AceLibrary("Crayon-2.0")
local BC = AceLibrary("Babble-Class-2.2")
sepgp_bids = sepgp:NewModule("sepgp_bids", "AceDB-2.0")
sepgp_bids.tipOwner = CreateFrame("Frame","shootyepgp_bids_tipowner",UIParent)
sepgp_bids.tipOwner:Show()
function sepgp_bids:OnEnable()
if not T:IsRegistered("sepgp_bids") then
T:Register("sepgp_bids",
"children", function()
T:SetTitle("shootyepgp bids")
self:OnTooltipUpdate()
end,
"showTitleWhenDetached", true,
"showHintWhenDetached", true,
"cantAttach", true,
"menu", function()
D:AddLine(
"text", "Refresh",
"tooltipText", "Refresh window",
"func", function() sepgp_bids:Refresh() end
)
end
)
end
if not T:IsAttached("sepgp_bids") then
T:Open("sepgp_bids")
end
end
function sepgp_bids:OnDisable()
T:Close("sepgp_bids")
end
function sepgp_bids:Refresh()
T:Refresh("sepgp_bids")
end
function sepgp_bids:Toggle(forceShow)
if T:IsAttached("sepgp_bids") then
T:Detach("sepgp_bids")
if (T:IsLocked("sepgp_bids")) then
T:ToggleLocked("sepgp_bids")
end
--[[if not (sepgp:IsEventScheduled("shootyepgpBidRefresh")) then
sepgp:ScheduleRepeatingEvent("shootyepgpBidRefresh", self.Refresh, 5, self)
end]]
elseif (forceShow) then
else
T:Attach("sepgp_bids")
if GameTooltip:IsOwned(self.tipOwner) and GameTooltip:IsShown() then
GameTooltip:Hide()
end
--[[if (sepgp:IsEventScheduled("shootyepgpBidRefresh")) then
sepgp:CancelScheduledEvent("shootyepgpBidRefresh")
end]]
end
end
function sepgp_bids:lineTooltip(item,line)
if line and line.highlight then
if not sepgp:IsHooked(line.highlight,"Show") then
sepgp:SecureHook(line.highlight,"Show",function()
if not (GameTooltip:IsOwned(sepgp_bids.tipOwner) and GameTooltip:IsShown()) then
GameTooltip:SetOwner(sepgp_bids.tipOwner,"ANCHOR_CURSOR")
GameTooltip:SetHyperlink(item)
GameTooltip:Show()
end
end)
end
if not sepgp:IsHooked(line.highlight,"Hide") then
sepgp:SecureHook(line.highlight,"Hide",function()
if GameTooltip:IsOwned(sepgp_bids.tipOwner) and GameTooltip:IsShown() then
GameTooltip:Hide()
end
end)
end
end
end
function sepgp_bids:announceWinnerMS(name, pr)
if GetNumRaidMembers()>0 then
SendChatMessage(string.format("Highest MainSpec Bid is %s with %dPR",name,pr),"RAID")
end
end
function sepgp_bids:announceWinnerOS(name, pr)
if GetNumRaidMembers()>0 then
SendChatMessage(string.format("Highest OffSpec Bid is %s with %dPR",name,pr),"RAID")
end
end
function sepgp_bids:BuildBidsTable()
-- {name,class,ep,gp,ep/gp}
table.sort(sepgp.bids_main, function(a,b)
return a[5] > b[5]
end)
table.sort(sepgp.bids_off, function(a,b)
return a[5] > b[5]
end)
return sepgp.bids_main, sepgp.bids_off
end
function sepgp_bids:OnTooltipUpdate()
if not (sepgp.bid_item and sepgp.bid_item.link) then return end
local link = sepgp.bid_item.link
local itemName = sepgp.bid_item.name
local price = sepgp_prices:GetPrice(link,sepgp_progress)
local offspec
if not price then
price = "<n/a>"
offspec = "<n/a>"
else
offspec = math.floor(price*sepgp_discount)
end
local bidcat = T:AddCategory(
"columns", 3,
"text", C:Orange("Bid Item"), "child_textR", 1, "child_textG", 1, "child_textB", 1, "child_justify", "LEFT",
"text2", C:Orange("GP Cost"), "child_text2R", 50/255, "child_text2G", 205/255, "child_text2B", 50/255, "child_justify2", "RIGHT",
"text3", C:Orange("OffSpec"), "child_text3R", 32/255, "child_text3G", 178/255, "child_text3B", 170/255, "child_justify3", "RIGHT",
"hideBlankLine", true
)
bidcat:AddLine(
"text", itemName,
"text2", price,
"text3", offspec,
"func", "lineTooltip", "arg1", self, "arg2", link, "arg3", this
)
local maincatHeader = T:AddCategory(
"columns", 1,
"text", C:Gold("MainSpec Bids")
):AddLine("text","")
local maincat = T:AddCategory(
"columns", 4,
"text", C:Orange("Name"), "child_textR", 1, "child_textG", 1, "child_textB", 1, "child_justify", "LEFT",
"text2", C:Orange("ep"), "child_text2R", 1, "child_text2G", 1, "child_text2B", 1, "child_justify2", "RIGHT",
"text3", C:Orange("gp"), "child_text3R", 1, "child_text3G", 1, "child_text3B", 1, "child_justify3", "RIGHT",
"text4", C:Orange("pr"), "child_text4R", 1, "child_text4G", 1, "child_text4B", 0, "child_justify4", "RIGHT",
"hideBlankLine", true
)
local tm = self:BuildBidsTable()
for i = 1, table.getn(tm) do
local name, class, ep, gp, pr = unpack(tm[i])
maincat:AddLine(
"text", C:Colorize(BC:GetHexColor(class), name),
"text2", string.format("%.4g", ep),
"text3", string.format("%.4g", gp),
"text4", string.format("%.4g", pr),
"func", "announceWinnerMS", "arg1", self, "arg2", name, "arg3", pr
)
end
local offcatHeader = T:AddCategory(
"columns", 1,
"text", C:Silver("OffSpec Bids")
):AddLine("text","")
local offcat = T:AddCategory(
"columns", 4,
"text", C:Orange("Name"), "child_textR", 1, "child_textG", 1, "child_textB", 1, "child_justify", "LEFT",
"text2", C:Orange("ep"), "child_text2R", 1, "child_text2G", 1, "child_text2B", 1, "child_justify2", "RIGHT",
"text3", C:Orange("gp"), "child_text3R", 1, "child_text3G", 1, "child_text3B", 1, "child_justify3", "RIGHT",
"text4", C:Orange("pr"), "child_text4R", 1, "child_text4G", 1, "child_text4B", 0, "child_justify4", "RIGHT",
"hideBlankLine", true
)
local _,to = self:BuildBidsTable()
for i = 1, table.getn(to) do
local name, class, ep, gp, pr = unpack(to[i])
offcat:AddLine(
"text", C:Colorize(BC:GetHexColor(class), name),
"text2", string.format("%.4g", ep),
"text3", string.format("%.4g", gp),
"text4", string.format("%.4g", pr),
"func", "announceWinnerOS", "arg1", self, "arg2", name, "arg3", pr
)
end
end
+875
View File
@@ -0,0 +1,875 @@
local prices = {
-----------------
--- Naxxramas ---
-----------------
[23226] = {104,"T3"}; --Ghoul Skin Tunic
[23663] = {48,"T3"}; --Girdle of Elemental Fury
[23044] = {116,"T3"}; --Harbinger of Doom
[23665] = {48,"T3"}; --Leggings of Elemental Fury
[23221] = {100,"T3"}; --Misplaced Servo Arm
[23069] = {18,"T3"}; --Necro-knight Garb
[23664] = {48,"T3"}; --Pauldrons of Elemental Fury
[23237] = {60,"T3"}; --Ring of Eternal Flame
[23238] = {40,"T3"}; --Stygian Buckler
[22939] = {72,"T3"}; --Band of Unanswered Prayers
[22938] = {96,"T3"}; --Cryptfiend Silk Cloak
[22937] = {48,"T3"}; --Gem of Nerubis
[22935] = {4,"T3"}; --Touch of Frost
[22936] = {72,"T3"}; --Wristguards of Vengeance
[22369] = {84,"T3"}; --T3 Wrist Token
[22362] = {84,"T3"}; --T3 Wrist Token
[22355] = {84,"T3"}; --T3 Wrist Token
[22940] = {4,"T3"}; --Icebane Pauldrons
[22943] = {60,"T3"}; --Malice Stone Pendant
[22941] = {4,"T3"}; --Polar Shoulderpads
[22942] = {116,"T3"}; --The Widow's Embrace
[22806] = {116,"T3"}; --Widow's Remorse
[23220] = {132,"T3"}; --Crystal Webbed Robe
[22954] = {116,"T3"}; --Kiss of the Spider
[22804] = {116,"T3"}; --Maexxna's Fang
[22947] = {24,"T3"}; --Pendant of Forgotten Names
[22807] = {152,"T3"}; --Wraith Blade
[22371] = {96,"T3"}; --T3 Gloves Token
[22364] = {96,"T3"}; --T3 Gloves Token
[22357] = {96,"T3"}; --T3 Gloves Token
[22961] = {80,"T3"}; --Band of Reanimation
[22960] = {96,"T3"}; --Cloak of Suturing
[22815] = {88,"T3"}; --Severance
[22818] = {92,"T3"}; --The Plague Bearer
[22820] = {72,"T3"}; --Wand of Fates
[22368] = {100,"T3"}; --T3 Shoulder Token
[22361] = {100,"T3"}; --T3 Shoulder Token
[22354] = {100,"T3"}; --T3 Shoulder Token
[22968] = {4,"T3"}; --Glacial Mantle
[22967] = {4,"T3"}; --Icy Scale Spaulders
[22803] = {80,"T3"}; --Midnight Haze
[22988] = {152,"T3"}; --The End of Dreams
[22810] = {44,"T3"}; --Toxin Injector
[22813] = {72,"T3"}; --Claymore of Unholy Might
[23075] = {80,"T3"}; --Death's Bargain
[22994] = {24,"T3"}; --Digested Hand of Power
[22981] = {52,"T3"}; --Gluth's Missing Collar
[22983] = {112,"T3"}; --Rime Covered Mantle
[23001] = {96,"T3"}; --Eye of Diminution
[23070] = {136,"T3"}; --Leggings of Polarity
[23000] = {136,"T3"}; --Plated Abomination Ribcage
[22801] = {140,"T3"}; --Spire of Twilight
[22808] = {116,"T3"}; --The Castigator
[22367] = {120,"T3"}; --T3 Helm Token
[22360] = {120,"T3"}; --T3 Helm Token
[22353] = {120,"T3"}; --T3 Helm Token
[23031] = {76,"T3"}; --Band of the Inevitable
[23030] = {68,"T3"}; --Cloak of the Scourge
[23028] = {16,"T3"}; --Hailstone Band
[22816] = {136,"T3"}; --Hatchet of Sundered Bone
[23029] = {60,"T3"}; --Noth's Frigid Heart
[23005] = {68,"T3"}; --Totem of Flowing Water
[22370] = {92,"T3"}; --T3 Belt Token
[22363] = {92,"T3"}; --T3 Belt Token
[22356] = {92,"T3"}; --T3 Belt Token
[23019] = {4,"T3"}; --Icebane Helmet
[23033] = {4,"T3"}; --Icy Scale Coif
[23068] = {124,"T3"}; --Legplates of Carnage
[23036] = {72,"T3"}; --Necklace of Necropsy
[23035] = {112,"T3"}; --Preceptor's Hat
[23038] = {88,"T3"}; --Band of Unnatural Forces
[22800] = {160,"T3"}; --Brimstone Staff
[23042] = {12,"T3"}; --Loatheb's Reflection
[23037] = {24,"T3"}; --Ring of Spiritual Fervor
[23039] = {132,"T3"}; --The Eye of Nerub
[22366] = {136,"T3"}; --T3 Pants Token
[22359] = {136,"T3"}; --T3 Pants Token
[22352] = {136,"T3"}; --T3 Pants Token
[23017] = {48,"T3"}; --Veil of Eclipse
[23219] = {124,"T3"}; --Girdle of the Mentor
[23014] = {120,"T3"}; --Iblis, Blade of the Fallen Seraph
[23009] = {72,"T3"}; --Wand of the Whispering Dead
[23018] = {84,"T3"}; --Signets of the Fallen Defender
[23004] = {48,"T3"}; --Idol of Longevity
[22372] = {92,"T3"}; --T3 Boots Token
[22365] = {92,"T3"}; --T3 Boots Token
[22358] = {92,"T3"}; --T3 Boots Token
[23073] = {32,"T3"}; --Boots of Displacement
[23032] = {4,"T3"}; --Glacial Headdress
[23020] = {4,"T3"}; --Polar Helmet
[23021] = {96,"T3"}; --The Soul Harvester's Bindings
[23023] = {48,"T3"}; --Sadist's Collar
[22691] = {200,"T3"}; --Corrupted Ashbringer
[22811] = {172,"T3"}; --Soulstring
[22809] = {60,"T3"}; --Maul of the Redeemed Crusader
[23071] = {144,"T3"}; --Leggings of Apocalypse
[23025] = {92,"T3"}; --Seal of the Damned
[23027] = {96,"T3"}; --Warmth of Forgiveness
[22351] = {148,"T3"}; --T3 Chest Token
[22350] = {148,"T3"}; --T3 Chest Token
[22349] = {148,"T3"}; --T3 Chest Token
[23050] = {160,"T3"}; --Cloak of the Necropolis
[23045] = {160,"T3"}; --Shroud of Dominion
[23043] = {150,"T3"}; --The Face of Death
[23242] = {180,"T3"}; --Claw of the Frost Wyrm
[23049] = {160,"T3"}; --Sapphiron's Left Eye
[23048] = {160,"T3"}; --Sapphiron's Right Eye
[23040] = {160,"T3"}; --Glyph of Deflection
[23047] = {160,"T3"}; --Eye of the Dead
[23046] = {160,"T3"}; --The Restrained Essence of Sapphiron
[23041] = {160,"T3"}; --Slayer's Crest
[23548] = {80,"T3"}; --Might of the Scourge
[23545] = {80,"T3"}; --Power of the Scourge
[23547] = {80,"T3"}; --Resilience of the Scourge
[23549] = {120,"T3"}; --Fortitude of the Scourge
[22802] = {200,"T3"}; --Kingsfall
[23054] = {200,"T3"}; --Gressil, Dawn of Ruin
[23577] = {200,"T3"}; --The Hungering Cold
[23056] = {240,"T3"}; --Hammer of the Twisting Nether
[22798] = {300,"T3"}; --Might of Menethil
[22799] = {300,"T3"}; --Soulseeker
[22821] = {116,"T3"}; --Doomfinger
[22812] = {300,"T3"}; --Nerubian Slavemaker
[22819] = {180,"T3"}; --Shield of Condemnation
[23057] = {140,"T3"}; --Gem of Trapped Innocents
[23053] = {140,"T3"}; --Stormrage's Talisman of Seething
[22520] = {0,"T3"}; --The Phylactery of Kel'Thuzad
[22733] = {400,"T3"}; --Staff Head of Atiesh
[22490] = {120,"T3"}; --Dreamwalker Raiment
[22491] = {100,"T3"}; --Dreamwalker Raiment
[22488] = {148,"T3"}; --Dreamwalker Raiment
[22495] = {84,"T3"}; --Dreamwalker Raiment
[22493] = {96,"T3"}; --Dreamwalker Raiment
[22494] = {92,"T3"}; --Dreamwalker Raiment
[22489] = {136,"T3"}; --Dreamwalker Raiment
[22492] = {92,"T3"}; --Dreamwalker Raiment
[23064] = {500,"T3"}; --Dreamwalker Raiment
[22438] = {120,"T3"}; --Cryptstalker Armor
[22439] = {100,"T3"}; --Cryptstalker Armor
[22436] = {148,"T3"}; --Cryptstalker Armor
[22443] = {84,"T3"}; --Cryptstalker Armor
[22441] = {96,"T3"}; --Cryptstalker Armor
[22442] = {92,"T3"}; --Cryptstalker Armor
[22437] = {136,"T3"}; --Cryptstalker Armor
[22440] = {92,"T3"}; --Cryptstalker Armor
[23067] = {500,"T3"}; --Cryptstalker Armor
[22498] = {120,"T3"}; --Frostfire Regalia
[22499] = {100,"T3"}; --Frostfire Regalia
[22496] = {148,"T3"}; --Frostfire Regalia
[22503] = {84,"T3"}; --Frostfire Regalia
[22501] = {96,"T3"}; --Frostfire Regalia
[22502] = {92,"T3"}; --Frostfire Regalia
[22497] = {136,"T3"}; --Frostfire Regalia
[22500] = {92,"T3"}; --Frostfire Regalia
[23062] = {500,"T3"}; --Frostfire Regalia
[22514] = {120,"T3"}; --Vestments of Faith
[22515] = {100,"T3"}; --Vestments of Faith
[22512] = {148,"T3"}; --Vestments of Faith
[22519] = {84,"T3"}; --Vestments of Faith
[22517] = {96,"T3"}; --Vestments of Faith
[22518] = {92,"T3"}; --Vestments of Faith
[22513] = {136,"T3"}; --Vestments of Faith
[22516] = {92,"T3"}; --Vestments of Faith
[23061] = {500,"T3"}; --Vestments of Faith
[22478] = {120,"T3"}; --Bonescythe Armor
[22479] = {100,"T3"}; --Bonescythe Armor
[22476] = {148,"T3"}; --Bonescythe Armor
[22483] = {84,"T3"}; --Bonescythe Armor
[22481] = {96,"T3"}; --Bonescythe Armor
[22482] = {92,"T3"}; --Bonescythe Armor
[22477] = {136,"T3"}; --Bonescythe Armor
[22480] = {92,"T3"}; --Bonescythe Armor
[23060] = {500,"T3"}; --Bonescythe Armor
[22466] = {120,"T3"}; --The Earthshatterer
[22467] = {100,"T3"}; --The Earthshatterer
[22464] = {148,"T3"}; --The Earthshatterer
[22471] = {84,"T3"}; --The Earthshatterer
[22469] = {96,"T3"}; --The Earthshatterer
[22470] = {92,"T3"}; --The Earthshatterer
[22465] = {136,"T3"}; --The Earthshatterer
[22468] = {92,"T3"}; --The Earthshatterer
[23065] = {500,"T3"}; --The Earthshatterer
[22506] = {120,"T3"}; --Plaguehart Raiment
[22507] = {100,"T3"}; --Plaguehart Raiment
[22504] = {148,"T3"}; --Plaguehart Raiment
[22511] = {84,"T3"}; --Plaguehart Raiment
[22509] = {96,"T3"}; --Plaguehart Raiment
[22510] = {92,"T3"}; --Plaguehart Raiment
[22505] = {136,"T3"}; --Plaguehart Raiment
[22508] = {92,"T3"}; --Plaguehart Raiment
[23063] = {500,"T3"}; --Plaguehart Raiment
[22418] = {120,"T3"}; --Dreadnaught's Battlegear
[22419] = {100,"T3"}; --Dreadnaught's Battlegear
[22416] = {148,"T3"}; --Dreadnaught's Battlegear
[22423] = {84,"T3"}; --Dreadnaught's Battlegear
[22421] = {96,"T3"}; --Dreadnaught's Battlegear
[22422] = {92,"T3"}; --Dreadnaught's Battlegear
[22417] = {136,"T3"}; --Dreadnaught's Battlegear
[22420] = {92,"T3"}; --Dreadnaught's Battlegear
[23059] = {500,"T3"}; --Dreadnaught's Battlegear
---------------------------
--- Temple of Ahn'Qiraj ---
---------------------------
[21837] = {40,"T2.5"}; --Anubisath Warhammer
[21838] = {4,"T2.5"}; --Garb of Royal Ascension
[21888] = {8,"T2.5"}; --Gloves of the Immortal
[21889] = {0,"T2.5"}; --Gloves of the Redeemed Prophet
[21856] = {16,"T2.5"}; --Neretzek, The Blood Drinker
[21836] = {44,"T2.5"}; --Ritssyn's Ring of Chaos
[21891] = {64,"T2.5"}; --Shard of the Fallen Star
[21702] = {4,"T2.5"}; --Amulet of Foul Warding
[21699] = {36,"T2.5"}; --Barrage Shoulders
[21708] = {4,"T2.5"}; --Beetle Scaled Wristguards
[21705] = {12,"T2.5"}; --Boots of the Fallen Prophet
[21706] = {28,"T2.5"}; --Boots of the Unwavering Will
[21814] = {92,"T2.5"}; --Breastplate of Annihilation
[21701] = {88,"T2.5"}; --Cloak of the Concentrated Hatred
[21703] = {24,"T2.5"}; --Hammer of Ji'zhi
[21698] = {40,"T2.5"}; --Leggings of Immersion
[21700] = {24,"T2.5"}; --Pendant of the Qiraji Guardian
[21707] = {48,"T2.5"}; --Ring of Swarming Thought
[21128] = {52,"T2.5"}; --Staff of the Qiraji Prophets
[21232] = {116,"T2.5"}; --Imperial Qiraji Armaments
[21242] = {116,"T2.5"}; --Imperial Qiraji Armaments
[21272] = {116,"T2.5"}; --Imperial Qiraji Armaments
[21244] = {116,"T2.5"}; --Imperial Qiraji Armaments
[21269] = {116,"T2.5"}; --Imperial Qiraji Armaments
[21237] = {84,"T2.5"}; --Imperial Qiraji Regalia
[21273] = {84,"T2.5"}; --Imperial Qiraji Regalia
[21275] = {84,"T2.5"}; --Imperial Qiraji Regalia
[21268] = {84,"T2.5"}; --Imperial Qiraji Regalia
[21695] = {80,"T2.5"}; --Angelista's Touch
[21697] = {4,"T2.5"}; --Cape of the Trinity
[21693] = {60,"T2.5"}; --Guise of the Devourer
[21696] = {4,"T2.5"}; --Robes of the Triumvirate
[21694] = {60,"T2.5"}; --Ternary Mantle
[21692] = {32,"T2.5"}; --Triad Girdle
[21690] = {48,"T2.5"}; --Angelista's Charm
[21688] = {68,"T2.5"}; --Boots of the Fallen Hero
[21689] = {60,"T2.5"}; --Gloves of Ebru
[21691] = {4,"T2.5"}; --Ooze-ridden Gauntlets
[21685] = {4,"T2.5"}; --Petrified Scarab
[21681] = {64,"T2.5"}; --Ring of the Devoured
[21680] = {56,"T2.5"}; --Vest of Swift Execution
[21603] = {56,"T2.5"}; --Wand of the Qiraji Nobility
[21682] = {4,"T2.5"}; --Bile-Covered Gauntlets
[21686] = {40,"T2.5"}; --Mantle of Phrenic Power
[21683] = {0,"T2.5"}; --Mantle of the Desert Crusade
[21684] = {4,"T2.5"}; --Mantle of the Desert's Fury
[21687] = {4,"T2.5"}; --Ukko's Ring of Darkness
[21670] = {44,"T2.5"}; --Badge of the Swarmguard
[21669] = {48,"T2.5"}; --Creeping Vine Helm
[21674] = {64,"T2.5"}; --Gauntlets of Steadfast Determ..
[21672] = {64,"T2.5"}; --Gloves of Enforcement
[21667] = {0,"T2.5"}; --Legplates of Blazing Light
[21676] = {32,"T2.5"}; --Leggings of the Festering Swa..
[21678] = {4,"T2.5"}; --Necklace of Purity
[21648] = {4,"T2.5"}; --Recomposed Boots
[21671] = {48,"T2.5"}; --Robes of the Battleguard
[21666] = {88,"T2.5"}; --Sartura's Might
[21668] = {20,"T2.5"}; --Scaled Leggings of Qiraji Fury
[21673] = {32,"T2.5"}; --Silithid Claw
[21675] = {60,"T2.5"}; --Thick Qirajihide Belt
[21650] = {112,"T2.5"}; --Ancient Qiraji Ripper
[21664] = {80,"T2.5"}; --Barbed Choker
[21635] = {104,"T2.5"}; --Barb of the Sand Reaver
[21627] = {4,"T2.5"}; --Cloak of Untold Secrets
[21647] = {28,"T2.5"}; --Fetish of the Sand Reaver
[21645] = {60,"T2.5"}; --Hive Tunneler's Boots
[22402] = {0,"T2.5"}; --Libram of Grace
[21665] = {72,"T2.5"}; --Mantle of Wicked Revenge
[21639] = {76,"T2.5"}; --Pauldrons of the Unrelenting
[21663] = {136,"T2.5"}; --Robes of the Guardian Saint
[21651] = {52,"T2.5"}; --Scaled Sand Reaver Leggings
[21652] = {4,"T2.5"}; --Silithid Carapace Chestguard
[22396] = {4,"T2.5"}; --Totem of Life
[21623] = {0,"T2.5"}; --Gauntlets of the Right. Champ
[21624] = {48,"T2.5"}; --Gauntlets of Kalimdor
[22399] = {68,"T2.5"}; --Idol of Health
[21677] = {56,"T2.5"}; --Ring of the Qiraji Fury
[21625] = {48,"T2.5"}; --Scarab Brooch
[21622] = {100,"T2.5"}; --Sharpened Silithid Femur
[21626] = {4,"T2.5"}; --Slime-coated Leggings
[20928] = {68,"T2.5"}; --Qiraji Bindings of Command
[20932] = {68,"T2.5"}; --Qiraji Bindings of Dominance
[21621] = {40,"T2.5"}; --Cloak of the Golden Hive
[21619] = {44,"T2.5"}; --Gloves of the Messiah
[21618] = {24,"T2.5"}; --Hive Defiler Wristguards
[21616] = {52,"T2.5"}; --Huhuran's Stinger
[21620] = {80,"T2.5"}; --Ring of the Martyr
[21617] = {64,"T2.5"}; --Wasphide Gauntlets
[21608] = {80,"T2.5"}; --Amulet of Vek'nilash
[21606] = {0,"T2.5"}; --Belt of the Fallen Emperor
[21600] = {88,"T2.5"}; --Boots of Epiphany
[21604] = {80,"T2.5"}; --Bracelets of Royal Redemption
[21605] = {60,"T2.5"}; --Gloves of the Hidden Temple
[21607] = {20,"T2.5"}; --Grasp of the Fallen Emperor
[21679] = {48,"T2.5"}; --Kalimdor's Revenge
[21609] = {52,"T2.5"}; --Regenerating Belt of Vek'nilash
[21601] = {80,"T2.5"}; --Ring of Emperor Vek'lor
[21597] = {88,"T2.5"}; --Royal Scepter of Vek'lor
[21598] = {84,"T2.5"}; --Royal Qiraji Belt
[21599] = {68,"T2.5"}; --Vek'lor's Gloves of Devastation
[21602] = {88,"T2.5"}; --Qiraji Execution Bracers
[20926] = {72,"T2.5"}; --Vek'nilash's Circlet
[20930] = {72,"T2.5"}; --Vek'lor's Diadem
[21611] = {48,"T2.5"}; --Burrower Bracers
[21615] = {88,"T2.5"}; --Don Rigoberto's Lost Hat
[23570] = {80,"T2.5"}; --Jom Gabbar
[23557] = {128,"T2.5"}; --Larvae of the Great Worm
[23558] = {24,"T2.5"}; --The Burrower's Shell
[21610] = {88,"T2.5"}; --Wormscale Blocker
[20927] = {76,"T2.5"}; --Ouro's Intact Hide
[20931] = {76,"T2.5"}; --Skin of the Great Sandworm
[21586] = {124,"T2.5"}; --Belt of Never-ending Agony
[21583] = {116,"T2.5"}; --Cloak of Clarity
[22731] = {116,"T2.5"}; --Cloak of the Devoured
[21134] = {172,"T2.5"}; --Dark Edge of Insanity
[21585] = {132,"T2.5"}; --Dark Storm Gauntlets
[21126] = {152,"T2.5"}; --Death's Sting
[22730] = {124,"T2.5"}; --Eyestalk Waist Cord
[21581] = {116,"T2.5"}; --Gauntlets of Annihilation
[21582] = {124,"T2.5"}; --Grasp of the Old God
[22732] = {116,"T2.5"}; --Mark of C'thun
[21596] = {104,"T2.5"}; --Ring of the Godslayer
[21839] = {180,"T2.5"}; --Scepter of the False Prophet
[21579] = {44,"T2.5"}; --Vanquished Tentacle of C'thun
[21221] = {96,"T2.5"}; --Eye of C'thun
[21712] = {96,"T2.5"}; --Eye of C'thun
[21710] = {96,"T2.5"}; --Eye of C'thun
[21709] = {96,"T2.5"}; --Eye of C'thun
[20929] = {128,"T2.5"}; --Carapace of the Old God
[20933] = {128,"T2.5"}; --Husk of the Old God
[21357] = {128,"T2.5"}; --Genesis Raiment
[21353] = {72,"T2.5"}; --Genesis Raiment
[21356] = {76,"T2.5"}; --Genesis Raiment
[21354] = {68,"T2.5"}; --Genesis Raiment
[21355] = {68,"T2.5"}; --Genesis Raiment
[21370] = {128,"T2.5"}; --Striker's Garb
[21366] = {72,"T2.5"}; --Striker's Garb
[21368] = {76,"T2.5"}; --Striker's Garb
[21367] = {68,"T2.5"}; --Striker's Garb
[21365] = {68,"T2.5"}; --Striker's Garb
[21343] = {128,"T2.5"}; --Enigma Vestments
[21347] = {72,"T2.5"}; --Enigma Vestments
[21346] = {76,"T2.5"}; --Enigma Vestments
[21345] = {68,"T2.5"}; --Enigma Vestments
[21344] = {68,"T2.5"}; --Enigma Vestments
[21351] = {128,"T2.5"}; --Garments of the Oracle
[21348] = {72,"T2.5"}; --Garments of the Oracle
[21352] = {76,"T2.5"}; --Garments of the Oracle
[21350] = {68,"T2.5"}; --Garments of the Oracle
[21349] = {68,"T2.5"}; --Garments of the Oracle
[21364] = {128,"T2.5"}; --Deathdealer's Embrace
[21360] = {72,"T2.5"}; --Deathdealer's Embrace
[21362] = {76,"T2.5"}; --Deathdealer's Embrace
[21361] = {68,"T2.5"}; --Deathdealer's Embrace
[21359] = {68,"T2.5"}; --Deathdealer's Embrace
[21374] = {128,"T2.5"}; --Stormcaller's Garb
[21372] = {72,"T2.5"}; --Stormcaller's Garb
[21375] = {76,"T2.5"}; --Stormcaller's Garb
[21376] = {68,"T2.5"}; --Stormcaller's Garb
[21373] = {68,"T2.5"}; --Stormcaller's Garb
[21334] = {128,"T2.5"}; --Doomcaller's Attire
[21337] = {72,"T2.5"}; --Doomcaller's Attire
[21336] = {76,"T2.5"}; --Doomcaller's Attire
[21335] = {68,"T2.5"}; --Doomcaller's Attire
[21338] = {68,"T2.5"}; --Doomcaller's Attire
[21331] = {128,"T2.5"}; --Conqueror's Battlegear
[21329] = {72,"T2.5"}; --Conqueror's Battlegear
[21332] = {76,"T2.5"}; --Conqueror's Battlegear
[21330] = {68,"T2.5"}; --Conqueror's Battlegear
[21333] = {68,"T2.5"}; --Conqueror's Battlegear
----------------------
--- Blackwing Lair ---
----------------------
[19434] = {40,"T2"}; --Band of Dark Dominion
[19437] = {48,"T2"}; --Boots of Pure Thought
[19436] = {16,"T2"}; --Cloak of Draconic Might
[19362] = {32,"T2"}; --Doom's Edge
[19354] = {16,"T2"}; --Draconic Avenger
[19358] = {12,"T2"}; --Draconic Maul
[19435] = {8,"T2"}; --Essence Gatherer
[19439] = {4,"T2"}; --Interlaced Shadow Jerkin
[19438] = {48,"T2"}; --Ringo's Blizzard Boots
[19336] = {16,"T2"}; --Arcane Infused Gem
[19369] = {16,"T2"}; --Gloves of Rapid Evolution
[19370] = {72,"T2"}; --Mantle of the Blackwing Cabal
[19335] = {20,"T2"}; --Spineshatter
[19337] = {16,"T2"}; --The Black Book
[19334] = {32,"T2"}; --The Untamed Blade
[19346] = {48,"T2"}; --Dragonfang Blade
[19372] = {44,"T2"}; --Helm of Endless Rage
[19339] = {40,"T2"}; --Mind Quickening Gem
[19371] = {28,"T2"}; --Pendant of the Fallen Dragon
[19348] = {28,"T2"}; --Red Dragonscale Protector
[19340] = {16,"T2"}; --Rune of Metamorphosis
[19373] = {40,"T2"}; --Black Brood Pauldrons
[19374] = {72,"T2"}; --Bracers of Arcane Accuracy
[19350] = {40,"T2"}; --Heartstriker
[19341] = {68,"T2"}; --Lifegiving Gem
[19351] = {92,"T2"}; --Maladath, Runed Blade of the..
[19342] = {16,"T2"}; --Venomous Totem
[20383] = {40,"T2"}; --Head of Broodlord Lashlayer
[19399] = {12,"T2"}; --Black Ash Robe
[19365] = {52,"T2"}; --Claw of the Black Drake
[19398] = {32,"T2"}; --Cloak of Firemaw
[19353] = {32,"T2"}; --Drake Talon Cleaver
[19394] = {52,"T2"}; --Drake Talon Pauldrons
[19400] = {44,"T2"}; --Firemaw's Clutch
[19402] = {0,"T2"}; --Legguards of the Fallen Crusader
[19344] = {20,"T2"}; --Natural Alignment Crystal
[19401] = {20,"T2"}; --Primalist's Linked Legguards
[19395] = {116,"T2"}; --Rejuvenating Gem
[19397] = {52,"T2"}; --Ring of Blackrock
[19355] = {48,"T2"}; --Shadow Wing Focus Staff
[19396] = {36,"T2"}; --Taut Dragonhide Belt
[19345] = {20,"T2"}; --Aegis of Preservation
[19403] = {52,"T2"}; --Band of Forced Concentration
[19368] = {52,"T2"}; --Dragonbreath Hand Cannon
[19406] = {116,"T2"}; --Drake Fang Talisman
[19407] = {40,"T2"}; --Ebony Flame Gloves
[19405] = {60,"T2"}; --Malfurion's Blessed Bulwark
[19432] = {32,"T2"}; --Circle of Applied Force
[19367] = {32,"T2"}; --Dragon's Touch
[19433] = {12,"T2"}; --Emberweave Leggings
[19357] = {32,"T2"}; --Herald of Woe
[19430] = {64,"T2"}; --Shroud of Pure Thought
[19431] = {116,"T2"}; --Styleen's Impeding Scarab
[19388] = {36,"T2"}; --Angelista's Grasp
[19361] = {124,"T2"}; --Ashjre'thul, Crossbow of Smiting
[19352] = {76,"T2"}; --Chromatically Tempered Sword
[19387] = {84,"T2"}; --Chromatic Boots
[19347] = {72,"T2"}; --Claw of Chromaggus
[19349] = {76,"T2"}; --Elementium Reinforced Bulwark
[19386] = {32,"T2"}; --Elementium Threaded Cloak
[19385] = {100,"T2"}; --Empowered Leggings
[19392] = {0,"T2"}; --Girdle of the Fallen Crusader
[19393] = {16,"T2"}; --Primalist's Linked Waistguard
[19391] = {40,"T2"}; --Shimmering Geta
[19390] = {24,"T2"}; --Taut Dragonhide Gloves
[19389] = {44,"T2"}; --Taut Dragonhide Shoulderpads
[19376] = {20,"T2"}; --Archimtiros' Ring of Reckoning
[19364] = {64,"T2"}; --Ashkandi, Greatsword of the Bro..
[19381] = {84,"T2"}; --Boots of the Shadow Flame
[19378] = {20,"T2"}; --Cloak of the Brood Lord
[19363] = {100,"T2"}; --Crul'shoruk, Edge of Chaos
[19360] = {60,"T2"}; --Lok'amir il Romathis
[19375] = {96,"T2"}; --Mish'undare, Circlet of the Mind…
[19379] = {116,"T2"}; --Neltharion's Tear
[19377] = {76,"T2"}; --Prestor's Talisman of Connivery
[19382] = {76,"T2"}; --Pure Elementium Band
[19356] = {80,"T2"}; --Staff of the Shadow Flame
[19380] = {36,"T2"}; --Therazane's Link
[19003] = {52,"T2"}; --Head of Nefarian
[19383] = {52,"T2"}; --Head of Nefarian
[19366] = {52,"T2"}; --Head of Nefarian
[19384] = {52,"T2"}; --Head of Nefarian
[16900] = {40,"T2"}; --Stormrage Raiment
[16902] = {40,"T2"}; --Stormrage Raiment
[16897] = {48,"T2"}; --Stormrage Raiment
[16904] = {28,"T2"}; --Stormrage Raiment
[16899] = {32,"T2"}; --Stormrage Raiment
[16903] = {32,"T2"}; --Stormrage Raiment
[16901] = {32,"T2"}; --Stormrage Raiment
[16898] = {32,"T2"}; --Stormrage Raiment
[16939] = {40,"T2"}; --Dragonstalker Armor
[16937] = {40,"T2"}; --Dragonstalker Armor
[16942] = {48,"T2"}; --Dragonstalker Armor
[16935] = {28,"T2"}; --Dragonstalker Armor
[16940] = {32,"T2"}; --Dragonstalker Armor
[16936] = {32,"T2"}; --Dragonstalker Armor
[16938] = {32,"T2"}; --Dragonstalker Armor
[16941] = {32,"T2"}; --Dragonstalker Armor
[16914] = {40,"T2"}; --Netherwind Regalia
[16917] = {40,"T2"}; --Netherwind Regalia
[16916] = {48,"T2"}; --Netherwind Regalia
[16918] = {28,"T2"}; --Netherwind Regalia
[16913] = {32,"T2"}; --Netherwind Regalia
[16818] = {32,"T2"}; --Netherwind Regalia
[16915] = {32,"T2"}; --Netherwind Regalia
[16912] = {32,"T2"}; --Netherwind Regalia
[16921] = {40,"T2"}; --Vestments of Transcendence
[16924] = {40,"T2"}; --Vestments of Transcendence
[16923] = {48,"T2"}; --Vestments of Transcendence
[16926] = {28,"T2"}; --Vestments of Transcendence
[16920] = {32,"T2"}; --Vestments of Transcendence
[16925] = {32,"T2"}; --Vestments of Transcendence
[16922] = {32,"T2"}; --Vestments of Transcendence
[16919] = {32,"T2"}; --Vestments of Transcendence
[16908] = {40,"T2"}; --Bloodfang Armor
[16832] = {40,"T2"}; --Bloodfang Armor
[16905] = {48,"T2"}; --Bloodfang Armor
[16911] = {28,"T2"}; --Bloodfang Armor
[16907] = {32,"T2"}; --Bloodfang Armor
[16910] = {32,"T2"}; --Bloodfang Armor
[16909] = {32,"T2"}; --Bloodfang Armor
[16906] = {32,"T2"}; --Bloodfang Armor
[16947] = {40,"T2"}; --The Ten Storms
[16945] = {40,"T2"}; --The Ten Storms
[16950] = {48,"T2"}; --The Ten Storms
[16943] = {28,"T2"}; --The Ten Storms
[16948] = {32,"T2"}; --The Ten Storms
[16944] = {32,"T2"}; --The Ten Storms
[16946] = {32,"T2"}; --The Ten Storms
[16949] = {32,"T2"}; --The Ten Storms
[16929] = {40,"T2"}; --Nemesis Raiment
[16932] = {40,"T2"}; --Nemesis Raiment
[16931] = {48,"T2"}; --Nemesis Raiment
[16934] = {28,"T2"}; --Nemesis Raiment
[16928] = {32,"T2"}; --Nemesis Raiment
[16933] = {32,"T2"}; --Nemesis Raiment
[16930] = {32,"T2"}; --Nemesis Raiment
[16927] = {32,"T2"}; --Nemesis Raiment
[16963] = {40,"T2"}; --Battlegear of Wrath
[16961] = {40,"T2"}; --Battlegear of Wrath
[16966] = {48,"T2"}; --Battlegear of Wrath
[16959] = {28,"T2"}; --Battlegear of Wrath
[16964] = {32,"T2"}; --Battlegear of Wrath
[16960] = {32,"T2"}; --Battlegear of Wrath
[16962] = {32,"T2"}; --Battlegear of Wrath
[16965] = {32,"T2"}; --Battlegear of Wrath
-------------------
--- Molten Core ---
-------------------
[13982] = {4,"T1"}; -- [DEBUG]Warblade of Caer Darrow
[17109] = {8,"T1"}; --Choker of Enlightenment
[17077] = {4,"T1"}; --Crimson Shocker
[18861] = {4,"T1"}; --Flamewalker Legplates
[18879] = {40,"T1"}; --Heavy Dark Iron Ring
[18870] = {8,"T1"}; --Helm of the Lifegiver
[18872] = {8,"T1"}; --Manastorm Leggings
[19147] = {8,"T1"}; --Ring of Spell Power
[19145] = {60,"T1"}; --Robe of Volatile Power
[18875] = {60,"T1"}; --Salamander Scale Pants
[18878] = {16,"T1"}; --Sorcerous Dagger
[19146] = {8,"T1"}; --Wristguards of Stability
[16665] = {0,"T1"}; --Tome of Tranquilizing Shot
[18823] = {12,"T1"}; --Aged Core Leather Gloves
[18829] = {20,"T1"}; --Deep Earth Spaulders
[17073] = {12,"T1"}; --Earthshaker
[18203] = {16,"T1"}; --Eskhandar's Right Claw
[19142] = {12,"T1"}; --Fire Runed Grimoire
[19143] = {14,"T1"}; --Flameguard Gauntlets
[18861] = {4,"T1"}; --Flamewalker Legplates
[18824] = {0,"T1"}; --Magma Tempered Boots
[19136] = {36,"T1"}; --Mana Igniting Cord
[17065] = {48,"T1"}; --Medallion of Steadfast Might
[18822] = {12,"T1"}; --Obsidian Edged Blade
[18821] = {48,"T1"}; --Quick Strike Ring
[19144] = {12,"T1"}; --Sabatons of the Flamewalker
[17069] = {56,"T1"}; --Striker's Mark
[18820] = {48,"T1"}; --Talisman of Ephemeral Power
[17105] = {24,"T1"}; --Aurastone Hammer
[18832] = {28,"T1"}; --Brutality Blade
[17066] = {28,"T1"}; --Drillborer Disk
[17071] = {12,"T1"}; --Gutgore Ripper
[18564] = {150,"T1"}; --Bindings of the Windseeker
[17110] = {8,"T1"}; --Seal of the Archmagus
[18563] = {150,"T1"}; --Bindings of the Windseeker
[17074] = {4,"T1"}; --Shadowstrike
[17103] = {36,"T1"}; --Azuresong Mageblade
[17072] = {24,"T1"}; --Blastershot Launcher
[18842] = {28,"T1"}; --Staff of Dominance
[18703] = {48,"T1"}; --Ancient Petrified Leaf
[19140] = {36,"T1"}; --Cauterizing Band
[18806] = {4,"T1"}; --Core Forged Greaves
[18805] = {44,"T1"}; --Core Hound Tooth
[18803] = {12,"T1"}; --Finkle's Lava Dredger
[19139] = {4,"T1"}; --Fireguard Shoulders
[18811] = {4,"T1"}; --Fireproof Cloak
[18808] = {16,"T1"}; --Gloves of the Hypnotic Flame
[18809] = {16,"T1"}; --Sash of Whispered Secrets
[18646] = {36,"T1"}; --The Eye of Divinity
[18810] = {48,"T1"}; --Wild Growth Spaulders
[18812] = {36,"T1"}; --Wristguards of True Flight
[17063] = {80,"T1"}; --Band of Accuria
[19138] = {28,"T1"}; --Band of Sulfuras
[17076] = {24,"T1"}; --Bonereaver's Edge
[18814] = {60,"T1"}; --Choker of the Firelord
[17102] = {20,"T1"}; --Cloak of the Shrouded Mists
[18817] = {56,"T1"}; --Crown of Destruction
[17107] = {16,"T1"}; --Dragon's Blood Cape
[18815] = {12,"T1"}; --Essence of the Pure Flame
[17106] = {16,"T1"}; --Malistar's Defender
[19137] = {80,"T1"}; --Onslaught Girdle
[18816] = {56,"T1"}; --Perdition's Blade
[17082] = {12,"T1"}; --Shard of the Flame
[17104] = {20,"T1"}; --Spinal Reaper
[17204] = {150,"T1"}; --Eye of Sulfuras
[16834] = {12,"T1"}; --Cenarion Raiment
[16836] = {12,"T1"}; --Cenarion Raiment
[16833] = {16,"T1"}; --Cenarion Raiment
[16830] = {8,"T1"}; --Cenarion Raiment
[16831] = {12,"T1"}; --Cenarion Raiment
[16828] = {8,"T1"}; --Cenarion Raiment
[16835] = {12,"T1"}; --Cenarion Raiment
[16829] = {12,"T1"}; --Cenarion Raiment
[16846] = {12,"T1"}; --Giantstalker Armor
[16848] = {12,"T1"}; --Giantstalker Armor
[16845] = {16,"T1"}; --Giantstalker Armor
[16850] = {8,"T1"}; --Giantstalker Armor
[16852] = {12,"T1"}; --Giantstalker Armor
[16851] = {8,"T1"}; --Giantstalker Armor
[16847] = {12,"T1"}; --Giantstalker Armor
[16849] = {12,"T1"}; --Giantstalker Armor
[16795] = {12,"T1"}; --Arcanist Regalia
[16797] = {12,"T1"}; --Arcanist Regalia
[16798] = {16,"T1"}; --Arcanist Regalia
[16799] = {8,"T1"}; --Arcanist Regalia
[16801] = {12,"T1"}; --Arcanist Regalia
[16802] = {8,"T1"}; --Arcanist Regalia
[16796] = {12,"T1"}; --Arcanist Regalia
[16800] = {12,"T1"}; --Arcanist Regalia
[16813] = {12,"T1"}; --Vestments of Prophecy
[16816] = {12,"T1"}; --Vestments of Prophecy
[16815] = {16,"T1"}; --Vestments of Prophecy
[16819] = {8,"T1"}; --Vestments of Prophecy
[16812] = {12,"T1"}; --Vestments of Prophecy
[16817] = {8,"T1"}; --Vestments of Prophecy
[16814] = {12,"T1"}; --Vestments of Prophecy
[16811] = {12,"T1"}; --Vestments of Prophecy
[16821] = {12,"T1"}; --Nightslayer Armor
[16823] = {12,"T1"}; --Nightslayer Armor
[16820] = {16,"T1"}; --Nightslayer Armor
[16825] = {8,"T1"}; --Nightslayer Armor
[16826] = {12,"T1"}; --Nightslayer Armor
[16827] = {8,"T1"}; --Nightslayer Armor
[16822] = {12,"T1"}; --Nightslayer Armor
[16824] = {12,"T1"}; --Nightslayer Armor
[16842] = {12,"T1"}; --The Earthfury
[16844] = {12,"T1"}; --The Earthfury
[16841] = {16,"T1"}; --The Earthfury
[16840] = {8,"T1"}; --The Earthfury
[16839] = {12,"T1"}; --The Earthfury
[16838] = {8,"T1"}; --The Earthfury
[16843] = {12,"T1"}; --The Earthfury
[16837] = {12,"T1"}; --The Earthfury
[16808] = {12,"T1"}; --Felheart Raiment
[16807] = {12,"T1"}; --Felheart Raiment
[16809] = {16,"T1"}; --Felheart Raiment
[16804] = {8,"T1"}; --Felheart Raiment
[16805] = {12,"T1"}; --Felheart Raiment
[16806] = {8,"T1"}; --Felheart Raiment
[16810] = {12,"T1"}; --Felheart Raiment
[16803] = {12,"T1"}; --Felheart Raiment
[16866] = {12,"T1"}; --Battlegear of Might
[16868] = {12,"T1"}; --Battlegear of Might
[16865] = {16,"T1"}; --Battlegear of Might
[16861] = {8,"T1"}; --Battlegear of Might
[16863] = {12,"T1"}; --Battlegear of Might
[16864] = {8,"T1"}; --Battlegear of Might
[16867] = {12,"T1"}; --Battlegear of Might
[16862] = {12,"T1"}; --Battlegear of Might
---------------------
--- Single Bosses ---
---------------------
[17067] = {12,"T1.5"}; --Ancient Cornerstone Grimoire
[17068] = {32,"T1.5"}; --Deathbringer
[18205] = {16,"T1.5"}; --Eskhandar's Collar
[18705] = {0,"T1.5"}; --Mature Black Dragon Sinew
[18813] = {4,"T1.5"}; --Ring of Binding
[17078] = {20,"T1.5"}; --Sapphiron Drape
[17064] = {68,"T1.5"}; --Shard of the Scale
[17075] = {24,"T1.5"}; --Vis'kag the Bloodletter
[18423] = {48,"T1.5"}; --Head of Onyxia
[18403] = {48,"T1.5"}; --Head of Onyxia
[18404] = {48,"T1.5"}; --Head of Onyxia
[18406] = {48,"T1.5"}; --Head of Onyxia
[19130] = {52,"T1.5"}; --Cold Snap
[19132] = {92,"T1.5"}; --Crystal Adorned Crown
[18208] = {12,"T1.5"}; --Drape of Benediction
[18202] = {20,"T1.5"}; --Eskhandar's Left Claw
[17070] = {36,"T1.5"}; --Fang of the Mystics
[18545] = {4,"T1.5"}; --Leggings of Arcane Supremacy
[18704] = {0,"T1.5"}; --Mature Black Dragon Sinew
[18541] = {68,"T1.5"}; --Puissant Cape
[19131] = {80,"T1.5"}; --Snowblind Shoes
[18542] = {12,"T1.5"}; --Typhoon
[18547] = {4,"T1.5"}; --Unmelting Ice Girdle
[20625] = {4,"T1.5"}; --Belt of the Dark Bog
[20626] = {20,"T1.5"}; --Black Bark Wristbands
[20627] = {64,"T1.5"}; --Dark Heart Pants
[20628] = {72,"T1.5"}; --Deviate Growth Cap
[20630] = {0,"T1.5"}; --Gauntlets of the Shining Light
[20629] = {12,"T1.5"}; --Malignant Footguards
[20619] = {4,"T1.5"}; --Acid Inscribed Greaves
[20617] = {28,"T1.5"}; --Ancient Corroded Leggings
[20616] = {16,"T1.5"}; --Dragonbone Wristguards
[20615] = {16,"T1.5"}; --Dragonspur Wraps
[20579] = {4,"T1.5"}; --Green Dragonskin Cloak
[20618] = {40,"T1.5"}; --Gloves of Delusional Power
[20580] = {32,"T1.5"}; --Hammer of Bestial Fury
[20581] = {40,"T1.5"}; --Staff of Rampant Growth
[20582] = {20,"T1.5"}; --Trance Stone
[20644] = {4,"T1.5"}; --Nightmare Engulfed Object
[20600] = {4,"T1.5"}; --Nightmare Engulfed Object
[20621] = {24,"T1.5"}; --Boots of the Endless Moor
[20623] = {32,"T1.5"}; --Circlet of Restless Dreams
[20622] = {20,"T1.5"}; --Dragonheart Necklace
[20599] = {28,"T1.5"}; --Polished Ironwood Crossbow
[20624] = {24,"T1.5"}; --Ring of the Unliving
[20634] = {24,"T1.5"}; --Boots of Fright
[20631] = {40,"T1.5"}; --Mendicant's Slippers
[20632] = {20,"T1.5"}; --Mindtear Band
[20577] = {36,"T1.5"}; --Nightmare Blade
[20633] = {4,"T1.5"}; --Unnatural Leather Spaulders
[20637] = {4,"T1.5"}; --Acid Inscribed Pauldrons
[20578] = {36,"T1.5"}; --Emerald Dragonfang
[20636] = {68,"T1.5"}; --Hibernating Crystal
[20635] = {36,"T1.5"}; --Jade Inlaid Vestments
[20638] = {32,"T1.5"}; --Leggings of the Demented Mind
[20639] = {0,"T1.5"}; --Strangely Glyphed Legplates
[17113] = {24,"T1.5"}; --Amberseal Keeper
[19135] = {12,"T1.5"}; --Blacklight Bracer
[17111] = {16,"T1.5"}; --Blazefury Medallion
[18544] = {20,"T1.5"}; --Doomhide Gauntlets
[17112] = {20,"T1.5"}; --Empyrean Demolisher
[18204] = {12,"T1.5"}; --Eskhandar's Pelt
[19133] = {72,"T1.5"}; --Fel Infused Leggings
[19134] = {16,"T1.5"}; --Flayed Doomguard Belt
[18546] = {24,"T1.5"}; --Infernal Headcage
[18543] = {12,"T1.5"}; --Ring of Entropy
[18665] = {0,"T1.5"}; --The Eye of Shadow
}
sepgp.gp_prices = prices
--[[local price_scaling = {
["T1"] = 1,
["T1.5"] = 1,
["T2"] = 3,
["T2.5"] = 6,
["T3"] = 9
}]]
local progress_scaling = {
["T3"] = {["T3"]=1,["T2.5"]=1,["T2"]=1,["T1.5"]=1,["T1"]=1},
["T2.5"] = {["T3"]=1.5,["T2.5"]=1.5,["T2"]=2,["T1.5"]=2,["T1"]=2},
["T2"] = {["T3"]=1.5,["T2.5"]=1.5,["T2"]=3,["T1.5"]=3,["T1"]=3},
["T1"] = {["T3"]=4.5,["T2.5"]=4.5,["T2"]=4.5,["T1.5"]=9,["T1"]=9}
}
local function get_adjusted_price(price,tier,progress)
if not progress_scaling[progress] then return price end
if not progress_scaling[progress][tier] then return price end
return math.floor(progress_scaling[progress][tier] * price)
end
sepgp_prices = sepgp:NewModule("sepgp_prices", "AceDB-2.0")
function sepgp_prices:GetPrice(item,progress)
if not progress then progress = "T3" end
local itemID,found,_,itemString,data,tier
local price
if (type(item)=="number") then
itemID = tonumber(item)
end
if (type(item)=="string") then
found,_,is = string.find(item,"^item:(%d+):.+")
if (found) then
itemID = tonumber(is)
else
found,_,il = string.find(item,"^|c%x+|Hitem:(%d+):.+")
if (found) then
itemID = tonumber(il)
end
end
end
if (itemID) then
data = prices[itemID]
if (data) then
price, tier = data[1], data[2]
price = get_adjusted_price(price,tier,progress)
else
return
end
end
return price
end
+90
View File
@@ -0,0 +1,90 @@
local T = AceLibrary("Tablet-2.0")
local D = AceLibrary("Dewdrop-2.0")
local C = AceLibrary("Crayon-2.0")
local BC = AceLibrary("Babble-Class-2.2")
sepgp_reserves = sepgp:NewModule("sepgp_reserves", "AceDB-2.0")
function sepgp_reserves:OnEnable()
if not T:IsRegistered("sepgp_reserves") then
T:Register("sepgp_reserves",
"children", function()
T:SetTitle("shootyepgp reserves")
self:OnTooltipUpdate()
end,
"showTitleWhenDetached", true,
"showHintWhenDetached", true,
"cantAttach", true,
"menu", function()
D:AddLine(
"text", "Refresh",
"tooltipText", "Refresh window",
"func", function() sepgp_reserves:Refresh() end
)
end
)
end
if not T:IsAttached("sepgp_reserves") then
T:Open("sepgp_reserves")
end
end
function sepgp_reserves:OnDisable()
T:Close("sepgp_reserves")
end
function sepgp_reserves:Refresh()
T:Refresh("sepgp_reserves")
end
function sepgp_reserves:Toggle(forceShow)
if T:IsAttached("sepgp_reserves") then
T:Detach("sepgp_reserves")
if (T:IsLocked("sepgp_reserves")) then
T:ToggleLocked("sepgp_reserves")
end
elseif (forceShow) then
else
T:Attach("sepgp_reserves")
end
end
function sepgp_reserves:OnClickItem(name)
ChatFrame_SendTell(name)
end
function sepgp_reserves:BuildReservesTable()
--{name,class,rank,alt}
table.sort(sepgp.reserves, function(a,b)
if (a[2] ~= b[2]) then return a[2] > b[2]
else return a[1] > b[1] end
end)
return sepgp.reserves
end
function sepgp_reserves:OnTooltipUpdate()
local cdcat = T:AddCategory(
"columns", 2
)
cdcat:AddLine(
"text", C:Orange("Countdown"),
"text2", sepgp.timer.cd_text
)
local cat = T:AddCategory(
"columns", 3,
"text", C:Orange("Name"), "child_textR", 1, "child_textG", 1, "child_textB", 1, "child_justify", "LEFT",
"text2", C:Orange("Rank"), "child_text2R", 1, "child_text2G", 1, "child_text2B", 0, "child_justify2", "RIGHT",
"text3", C:Orange("OnAlt"), "child_text3R", 0, "child_text3G", 1, "child_text3B", 0, "child_justify3", "RIGHT"
)
local t = self:BuildReservesTable()
for i = 1, table.getn(t) do
local name, class, rank, alt = unpack(t[i])
cat:AddLine(
"text", C:Colorize(BC:GetHexColor(class), name),
"text2", rank,
"text3", alt or "",
"func", "OnClickItem", "arg1", self, "arg2", alt or name
)
end
end
+906
View File
@@ -0,0 +1,906 @@
sepgp = AceLibrary("AceAddon-2.0"):new("AceConsole-2.0", "AceHook-2.1", "AceDB-2.0", "AceDebug-2.0", "AceEvent-2.0", "AceModuleCore-2.0", "FuBarPlugin-2.0")
sepgp:SetModuleMixins("AceDebug-2.0")
local D = AceLibrary("Dewdrop-2.0")
local playerName = (UnitName("player"))
local shooty_basegp = 135
local shooty_decay = 0.85
local shooty_max = 10000
local shooty_timeout = 45
local shooty_reservechan = "Reserves"
local shooty_reservecall = string.format("{shootyepgp}Type \"+\" in this channel if on main, or \"+<MainName>\" if on alt within %dsec.",shooty_timeout)
local shooty_reserveanswer = "^(%+)(%a*)$"
local out = "|cff9664c8shootyepgp:|r %s"
local lastUpdate = 0
local needInit = true
local shooty_debugchat
local running_check,running_bid
local partyUnit,raidUnit = {},{}
local reserves_blacklist,bids_blacklist = {},{}
do
for i=1,40 do
raidUnit[i] = "raid"..i
end
for i=1,4 do
partyUnit[i] = "party"..i
end
end
sepgp.reserves = {}
sepgp.timer = CreateFrame("Frame")
sepgp.timer.cd_text = ""
sepgp.timer:Hide()
sepgp.timer:SetScript("OnUpdate",function() sepgp.OnUpdate(this,arg1) end)
sepgp.bids_main,sepgp.bids_off,sepgp.bid_item = {},{},{}
function sepgp:OnInitialize() -- ADDON_LOADED (1) unless LoD
if sepgp_saychannel == nil then sepgp_saychannel = "GUILD" end
if sepgp_decay == nil then sepgp_decay = shooty_decay end
if sepgp_progress == nil then sepgp_progress = "T1" end
if sepgp_discount == nil then sepgp_discount = 0.25 end
sepgp.extratip = CreateFrame("GameTooltip","shootyepgp_tooltip",UIParent,"GameTooltipTemplate")
end
function sepgp:AceEvent_FullyInitialized() -- SYNTHETIC EVENT, later than PLAYER_LOGIN, PLAYER_ENTERING_WORLD (3)
for i=1,NUM_CHAT_WINDOWS do
local tab = getglobal("ChatFrame"..i.."Tab")
local cf = getglobal("ChatFrame"..i)
local tabName = tab:GetText()
if tab ~= nil and (string.lower(tabName) == "debug") then
shooty_debugchat = cf
ChatFrame_RemoveAllMessageGroups(shooty_debugchat)
shooty_debugchat:SetMaxLines(1024)
break
end
end
if (not sepgp_main) or (sepgp_main == "") then
StaticPopup_Show("SHOOTY_EPGP_SET_MAIN")
end
if not self:IsEventScheduled("shootyepgpChannelInit") then
self:ScheduleEvent("shootyepgpChannelInit",self.getReserveStatus,2,self)
end
-- if pfUI loaded, skin the extra tooltip
if (pfUI) and pfUI.api and pfUI.api.CreateBackdrop and pfUI_config and pfUI_config.tooltip and pfUI_config.tooltip.alpha then
pfUI.api.CreateBackdrop(sepgp.extratip,nil,nil,pfUI_config.tooltip.alpha)
end
-- hook tooltip to add our GP values
sepgp:TipHook()
end
function sepgp:OnEnable() -- PLAYER_LOGIN (2)
sepgp:RegisterEvent("GUILD_ROSTER_UPDATE",function()
if (arg1) then -- member join /leave
self:SetRefresh(true)
end
end)
sepgp:RegisterEvent("RAID_ROSTER_UPDATE",function()
self:SetRefresh(true)
end)
sepgp:RegisterEvent("PARTY_MEMBERS_CHANGED",function()
self:SetRefresh(true)
end)
sepgp:RegisterEvent("CHAT_MSG_RAID","captureLootCall")
sepgp:RegisterEvent("CHAT_MSG_RAID_LEADER","captureLootCall")
sepgp:RegisterEvent("CHAT_MSG_RAID_WARNING","captureLootCall")
sepgp:RegisterEvent("CHAT_MSG_WHISPER","captureBid")
if (IsInGuild()) then
if (GetNumGuildMembers()==0) then
GuildRoster()
end
end
if AceLibrary("AceEvent-2.0"):IsFullyInitialized() then
self:AceEvent_FullyInitialized()
else
self:RegisterEvent("AceEvent_FullyInitialized")
end
end
function sepgp:OnMenuRequest()
D:FeedAceOptionsTable(self:buildMenu())
end
function sepgp:TipHook()
self:SecureHook(GameTooltip, "SetBagItem", function(this, bag, slot)
sepgp:AddDataToTooltip(GameTooltip, GetContainerItemLink(bag, slot))
end
) -- DEBUG - remove for final
self:SecureHook(GameTooltip, "SetLootItem", function(this, slot)
sepgp:AddDataToTooltip(GameTooltip, GetLootSlotLink(slot))
end
)
self:SecureHook(GameTooltip, "SetLootRollItem", function(this, id)
sepgp:AddDataToTooltip(GameTooltip, GetLootRollItemLink(id))
end
)
self:SecureHook("SetItemRef", function(link, name, button)
if (link and name and ItemRefTooltip) then
if (strsub(link, 1, 6) ~= "Player") then
if (ItemRefTooltip:IsVisible()) then
if (not DressUpFrame:IsVisible()) then
sepgp:AddDataToTooltip(ItemRefTooltip, link)
end
ItemRefTooltip.isDisplayDone = nil
end
end
end
end
)
self:HookScript(GameTooltip, "OnHide", function()
if sepgp.extratip:IsVisible() then sepgp.extratip:Hide() end
self.hooks[GameTooltip]["OnHide"]()
end
)
self:HookScript(ItemRefTooltip, "OnHide", function()
if sepgp.extratip:IsVisible() then sepgp.extratip:Hide() end
self.hooks[ItemRefTooltip]["OnHide"]()
end
)
end
function sepgp:getReserveStatus()
if (IsInGuild()) then
local guildName = (GetGuildInfo("player"))
if (guildName) and guildName ~= "" then
sepgp_reservechannel = string.format("%sReserves",(string.gsub(guildName," ","")))
end
end
if sepgp_reservechannel == nil then sepgp_reservechannel = shooty_reservechan end
local reservesChannelID = tonumber((GetChannelName(sepgp_reservechannel)))
if (reservesChannelID) and (reservesChannelID ~= 0) then
sepgp:reservesToggle(true)
end
end
function sepgp:AddDataToTooltip(tooltip,itemlink,itemstring)
local price
if (itemstring) then
price = sepgp_prices:GetPrice(itemstring,sepgp_progress)
elseif (itemlink) then
price = sepgp_prices:GetPrice(itemlink,sepgp_progress)
end
if not price then return end
local textRight = string.format("cost:|cff32cd32%d|r offspec:|cff20b2aa%d|r",price,math.floor(price*sepgp_discount))
if (tooltip:NumLines() < 29) then
tooltip:AddLine(" ")
tooltip:AddDoubleLine("|cff9664c8shootyepgp|r",textRight)
tooltip:Show()
else
sepgp.extratip:ClearLines()
sepgp.extratip:SetOwner(tooltip,"ANCHOR_NONE")
sepgp.extratip:ClearAllPoints()
sepgp.extratip:SetPoint("TOPLEFT", tooltip, "BOTTOMLEFT", 0, -5)
sepgp.extratip:SetPoint("TOPRIGHT", tooltip, "BOTTOMRIGHT", 0, -5)
sepgp.extratip:AddDoubleLine("|cff9664c8shootyepgp|r",textRight)
sepgp.extratip:Show()
end
end
function sepgp:OnUpdate(elapsed)
sepgp.timer.count_down = sepgp.timer.count_down - elapsed
lastUpdate = lastUpdate + elapsed
if sepgp.timer.count_down <= 0 then
running_check = nil
sepgp.timer:Hide()
sepgp.timer.cd_text = "|cffff0000Finished|r"
sepgp_reserves:Refresh()
else
sepgp.timer.cd_text = string.format("|cff00ff00%02d|r|cffffffffsec|r",sepgp.timer.count_down)
end
if lastUpdate > 0.5 then
lastUpdate = 0
sepgp_reserves:Refresh()
end
end
-------------------
-- Communication
-------------------
function sepgp:flashFrame(frame)
local tabFlash = getglobal(frame:GetName().."TabFlash")
if ( not frame.isDocked or (frame == SELECTED_DOCK_FRAME) or UIFrameIsFlashing(tabFlash) ) then
return
end
tabFlash:Show()
UIFrameFlash(tabFlash, 0.25, 0.25, 60, nil, 0.5, 0.5)
end
function sepgp:debugPrint(msg)
if (shooty_debugchat) then
shooty_debugchat:AddMessage(string.format(out,msg))
sepgp:flashFrame(shooty_debugchat)
else
sepgp:defaultPrint(msg)
end
end
function sepgp:defaultPrint(msg)
if not DEFAULT_CHAT_FRAME:IsVisible() then
FCF_SelectDockFrame(DEFAULT_CHAT_FRAME)
end
DEFAULT_CHAT_FRAME:AddMessage(string.format(out,msg))
end
function sepgp:simpleSay(msg)
SendChatMessage(string.format("shootyepgp: %s",msg), sepgp_saychannel)
end
function sepgp:adminSay(msg)
-- API is broken on Elysium
-- local g_listen, g_speak, officer_listen, officer_speak, g_promote, g_demote, g_invite, g_remove, set_gmotd, set_publicnote, view_officernote, edit_officernote, set_guildinfo = GuildControlGetRankFlags()
-- if (officer_speak) then
SendChatMessage(string.format("shootyepgp: %s",msg),"OFFICER")
-- end
end
---------------------
-- EPGP Operations
---------------------
function sepgp:init_notes(guild_index,note,officernote)
if not tonumber(note) or (tonumber(note) < 0) then
GuildRosterSetPublicNote(guild_index,0)
end
if not tonumber(officernote) or (tonumber(officernote) < shooty_basegp) then
GuildRosterSetOfficerNote(guild_index,shooty_basegp)
end
end
function sepgp:update_ep(getname,ep)
for i = 1, GetNumGuildMembers(1) do
local name, _, _, _, class, _, note, officernote, _, _ = GetGuildRosterInfo(i)
if (name==getname) then
sepgp:init_notes(i,note,officernote)
GuildRosterSetPublicNote(i,ep)
end
end
end
function sepgp:update_gp(getname,gp)
for i = 1, GetNumGuildMembers(1) do
local name, _, _, _, class, _, note, officernote, _, _ = GetGuildRosterInfo(i)
if (name==getname) then
sepgp:init_notes(i,note,officernote)
GuildRosterSetOfficerNote(i,gp)
end
end
end
function sepgp:get_ep(getname,note) -- gets ep by name or note
if (note) then
if tonumber(note)==nil then return 0 end
end
for i = 1, GetNumGuildMembers(1) do
local name, _, _, _, class, _, note, officernote, _, _ = GetGuildRosterInfo(i)
if tonumber(note)==nil then note=0 end
if (name==getname) then return tonumber(note) end
end
return(0)
end
function sepgp:get_gp(getname,officernote) -- gets gp by name or officernote
if (officernote) then
if tonumber(officernote)==nil then return shooty_basegp end
end
for i = 1, GetNumGuildMembers(1) do
local name, _, _, _, class, _, note, officernote, _, _ = GetGuildRosterInfo(i)
if tonumber(officernote)==nil then officernote=shooty_basegp end
if (name==getname) then return tonumber(officernote) end
end
return(shooty_basegp)
end
function sepgp:award_raid_ep(ep) -- awards ep to raid members in zone
if GetNumRaidMembers()>0 then
sepgp:simpleSay(string.format("Giving %d ep to all raidmembers",ep))
for i = 1, GetNumRaidMembers(true) do
local name, rank, subgroup, level, class, fileName, zone, online, isDead = GetRaidRosterInfo(i)
sepgp:givename_ep(name,ep)
end
else UIErrorsFrame:AddMessage("You aren't in a raid dummy",1,0,0)end
end
function sepgp:award_reserve_ep(ep) -- awards ep to reserve list
if table.getn(sepgp.shooty_reserves) > 0 then
sepgp:simpleSay(string.format("Giving %d ep to active reserves",ep))
for i, name in ipairs(sepgp.shooty_reserves) do
sepgp:givename_ep(name,ep)
end
sepgp.reserves = {}
reserves_blacklist = {}
end
end
function sepgp:givename_ep(getname,ep) -- awards ep to a single character
sepgp:debugPrint(string.format("Giving %d ep to %s",ep,getname))
ep = ep + sepgp:get_ep(getname)
sepgp:update_ep(getname,ep)
end
function sepgp:givename_gp(getname,gp) -- assigns gp to a single character
sepgp:debugPrint(string.format("Giving %d gp to %s",gp,getname))
local oldgp = sepgp:get_gp(getname)
local newgp = gp + oldgp
sepgp:adminSay(string.format("Awarding %d GP to %s. (Previous: %d, New: %d)",gp,getname,oldgp,newgp))
sepgp:update_gp(getname,newgp)
end
function sepgp:decay_epgp() -- decays entire roster's ep and gp
for i = 1, GetNumGuildMembers(1) do
local name,_,_,_,class,_,ep,gp,_,_ = GetGuildRosterInfo(i)
ep = tonumber(ep)
gp = tonumber(gp)
if ep == nil then
else
ep = math.max(0,sepgp:num_round(ep*sepgp_decay))
GuildRosterSetPublicNote(i,ep)
gp = math.max(shooty_basegp,sepgp:num_round(gp*sepgp_decay))
GuildRosterSetOfficerNote(i,gp)
end
end
local msg = string.format("all ep and gp decayed by %d%%",(1-sepgp_decay)*100)
sepgp:simpleSay(msg)
end
function sepgp:gp_reset()
for i = 1, GetNumGuildMembers(1) do
GuildRosterSetOfficerNote(i, shooty_basegp)
end
sepgp:debugPrint(string.format("All GP has been reset to %d.",shooty_basegp))
end
---------
-- Menu
---------
local T = AceLibrary("Tablet-2.0")
sepgp.defaultMinimapPosition = 180
sepgp.cannotDetachTooltip = true
sepgp.tooltipHidderWhenEmpty = false
sepgp.hasIcon = "Interface\\Icons\\INV_Misc_Orb_04"
function sepgp:OnTooltipUpdate()
T:SetHint("|cffffff00Click|r to toggle Standings. \n|cffffff00Ctrl+Click|r to toggle Reserves. \n|cffffff00Alt+Click|r to toggle Bids. \n|cffffff00Right-Click|r for Options.")
end
function sepgp:OnClick()
if (IsControlKeyDown()) then
sepgp_reserves:Toggle()
elseif (IsAltKeyDown()) then
sepgp_bids:Toggle()
else
sepgp_standings:Toggle()
end
end
function sepgp:SetRefresh(flag)
needRefresh = flag
if (flag) then
sepgp_standings:Refresh()
end
end
function sepgp:buildRosterTable()
local g, r = { }, { }
local numGuildMembers = GetNumGuildMembers(1)
if (sepgp_raidonly) and GetNumRaidMembers() > 0 then
for i = 1, GetNumRaidMembers(true) do
local name, rank, subgroup, level, class, fileName, zone, online, isDead = GetRaidRosterInfo(i)
r[name] = true
end
end
for i = 1, numGuildMembers do
local member_name,_,_,_,class,_,ep,gp,_,_ = GetGuildRosterInfo(i)
if (sepgp_raidonly) and next(r) then
if r[member_name] then
table.insert(g,{["name"]=member_name,["class"]=class})
end
else
table.insert(g,{["name"]=member_name,["class"]=class})
end
end
return g
end
function sepgp:buildClassMemberTable(roster,epgp)
local desc,usage
if epgp == "ep" then
desc = "Account EPs to %s."
usage = "<EP>"
elseif epgp == "gp" then
desc = "Account GPs to %s."
usage = "<GP>"
end
local c = { }
for i,member in ipairs(roster) do
local class,name = member.class, member.name
if c[class] == nil then
c[class] = { }
c[class].type = "group"
c[class].name = class
c[class].desc = class .. " members"
c[class].hidden = function() return not (CanEditOfficerNote() and CanEditPublicNote()) end
c[class].args = { }
end
if c[class].args[name] == nil then
c[class].args[name] = { }
c[class].args[name].type = "text"
c[class].args[name].name = name
c[class].args[name].desc = string.format(desc,name)
c[class].args[name].usage = usage
c[class].args[name].get = false
if epgp == "ep" then
c[class].args[name].set = function(v) sepgp:givename_ep(name, tonumber(v)) end
elseif epgp == "gp" then
c[class].args[name].set = function(v) sepgp:givename_gp(name, tonumber(v)) end
end
c[class].args[name].validate = function(v) return (type(v) == "number" or tonumber(v)) and tonumber(v) < shooty_max end
end
end
return c
end
local options
function sepgp:buildMenu()
if not (options) then
options = {
type = "group",
desc = "shootyepgp options",
args = { }
}
options.args["ep"] = {
type = "group",
name = "+EPs to Member",
desc = "Account EPs for member.",
order = 10,
hidden = function() return not (CanEditOfficerNote() and CanEditPublicNote()) end,
}
options.args["ep_raid"] = {
type = "text",
name = "+EPs to Raid",
desc = "Award EPs to all raid members.",
order = 20,
get = false,
set = function(v) sepgp:award_raid_ep(tonumber(v)) end,
usage = "<EP>",
hidden = function() return not (CanEditOfficerNote() and CanEditPublicNote()) end,
validate = function(v)
local n = tonumber(v)
return n and n >= 0 and n < shooty_max
end
}
options.args["gp"] = {
type = "group",
name = "+GPs to Member",
desc = "Account GPs for member.",
order = 30,
hidden = function() return not (CanEditOfficerNote() and CanEditPublicNote()) end,
}
options.args["ep_reserves"] = {
type = "text",
name = "+EPs to Reserves",
desc = "Award EPs to all active Reserves.",
order = 40,
get = false,
set = function(v) sepgp:award_reserve_ep(tonumber(v))end,
usage = "<EP>",
hidden = function() return not (CanEditOfficerNote() and CanEditPublicNote()) end,
validate = function(v)
local n = tonumber(v)
return n and n >= 0 and n < shooty_max
end
}
options.args["reserves"] = {
type = "toggle",
name = "Enable Reserves",
desc = "Participate in Reserves Functionality.\n|cffff0000Needs Main Set in Options.|r",
order = 50,
get = function() return (sepgp.reservesChannelID ~= nil) and (sepgp.reservesChannelID ~= 0) end,
set = function(v) sepgp:reservesToggle(v) end,
disabled = function() return (sepgp_main == nil) end
}
options.args["afkcheck_reserves"] = {
type = "execute",
name = "AFK Check Reserves",
desc = "AFK Check Reserves List",
order = 60,
hidden = function() return not (CanEditOfficerNote() and CanEditPublicNote()) end,
func = function() sepgp:afkcheck_reserves() end
}
options.args["set_main"] = {
type = "text",
name = "Set Main",
desc = "Set your Main Character for Reserve List.",
order = 70,
usage = "<MainChar>",
get = function() return sepgp_main end,
set = function(v) sepgp_main = (sepgp:verifyGuildMember(v)) end,
}
options.args["raid_only"] = {
type = "toggle",
name = "Raid Only",
desc = "Only show members in raid.",
order = 80,
get = function() return not not sepgp_raidonly end,
set = function(v)
sepgp_raidonly = not sepgp_raidonly
sepgp:SetRefresh(true)
end,
}
options.args["report_channel"] = {
type = "text",
name = "Reporting channel",
desc = "Channel used by reporting functions.",
order = 90,
get = function() return sepgp_saychannel end,
set = function(v) sepgp_saychannel = v end,
validate = { "PARTY", "RAID", "GUILD", "OFFICER" },
}
options.args["progress_tier"] = {
type = "text",
name = "Raid Progress",
desc = "Highest Tier the Guild is raiding.\nUsed to adjust GP Prices.",
order = 95,
get = function() return sepgp_progress end,
set = function(v) sepgp_progress = v sepgp_bids:Refresh() end,
validate = { ["T3"]="4.Naxxramas", ["T2.5"]="3.Temple of Ahn\'Qiraj", ["T2"]="2.Blackwing Lair", ["T1"]="1.Molten Core"},
}
options.args["decay"] = {
type = "execute",
name = "Decay EPGP",
desc = string.format("Decays all EPGP by %d%%",(1-(sepgp_decay or shooty_decay))*100),
order = 100,
hidden = function() return not (CanEditOfficerNote() and CanEditPublicNote()) end,
func = function() sepgp:decay_epgp() end
}
options.args["set_decay"] = {
type = "range",
name = "Set Decay %",
desc = "Set Decay percentage (Admin only).",
order = 110,
usage = "<Decay>",
get = function() return (1.0-sepgp_decay) end,
set = function(v) sepgp_decay = (1 - v) end,
min = 0.01,
max = 0.5,
step = 0.01,
bigStep = 0.05,
isPercent = true,
hidden = function() return not (IsGuildLeader()) end,
}
options.args["set_discount"] = {
type = "range",
name = "Offspec Price %",
desc = "Set Offspec / Resistance Items GP Percent.",
order = 115,
get = function() return sepgp_discount end,
set = function(v) sepgp_discount = v end,
min = 0,
max = 1,
step = 0.05,
isPercent = true
}
options.args["reset"] = {
type = "execute",
name = "Reset GP",
desc = string.format("gives everybody %d basic GP (Admin only).",shooty_basegp),
order = 120,
hidden = function() return not (IsGuildLeader()) end,
func = function() sepgp:gp_reset() end
}
end
if (needInit) or (needRefresh) then
local members = sepgp:buildRosterTable()
self:debugPrint(string.format("Scanning %d members for EP/GP data. (%s)",table.getn(members),(sepgp_raidonly and "Raid" or "Full")))
options.args["ep"].args = sepgp:buildClassMemberTable(members,"ep")
options.args["gp"].args = sepgp:buildClassMemberTable(members,"gp")
if (needInit) then needInit = false end
if (needRefresh) then needRefresh = false end
end
return options
end
---------------
-- Reserves
---------------
function sepgp:reservesToggle(flag)
local reservesChannelID = tonumber((GetChannelName(sepgp_reservechannel)))
if (flag) then -- we want in
if (reservesChannelID) and reservesChannelID ~= 0 then
sepgp.reservesChannelID = reservesChannelID
return true
else
sepgp:RegisterEvent("CHAT_MSG_CHANNEL_NOTICE","reservesChannelChange")
JoinChannelByName(sepgp_reservechannel)
return
end
else -- we want out
if (reservesChannelID) and reservesChannelID ~= 0 then
sepgp:RegisterEvent("CHAT_MSG_CHANNEL_NOTICE","reservesChannelChange")
LeaveChannelByName(sepgp_reservechannel)
return
else
return false
end
end
end
function sepgp:reservesChannelChange(msg,_,_,_,_,_,_,_,channel)
if (msg) and (channel) and (channel == sepgp_reservechannel) then
if msg == "YOU_JOINED" then
sepgp.reservesChannelID = tonumber((GetChannelName(sepgp_reservechannel)))
RemoveChatWindowChannel(DEFAULT_CHAT_FRAME:GetID(), sepgp_reservechannel)
sepgp:RegisterEvent("CHAT_MSG_CHANNEL","captureReserveChatter")
elseif msg == "YOU_LEFT" then
sepgp.reservesChannelID = nil
if sepgp:IsEventRegistered("CHAT_MSG_CHANNEL") then
sepgp:UnregisterEvent("CHAT_MSG_CHANNEL")
end
end
sepgp:UnregisterEvent("CHAT_MSG_CHANNEL_NOTICE")
D:Close()
end
end
function sepgp:afkcheck_reserves()
if (running_check) then return end
if sepgp.reservesChannelID ~= nil and ((GetChannelName(sepgp.reservesChannelID)) == sepgp.reservesChannelID) then
reserves_blacklist = {}
sepgp.reserves = {}
running_check = true
sepgp.timer.count_down = shooty_timeout
sepgp.timer:Show()
SendChatMessage(shooty_reservecall,"CHANNEL",nil,sepgp.reservesChannelID)
sepgp_reserves:Toggle(true)
end
end
function sepgp:sendReserverResponce()
if sepgp.reservesChannelID ~= nil then
if (sepgp_main) then
if sepgp_main == playerName then
SendChatMessage("+","CHANNEL",nil,sepgp.reservesChannelID)
else
SendChatMessage(string.format("+%s",sepgp_main),"CHANNEL",nil,sepgp.reservesChannelID)
end
end
end
end
function sepgp:captureReserveChatter(text, sender, _, _, _, _, _, _, channel)
if not (channel) or not (channel == sepgp_reservechannel) then return end
local reserve, reserve_class, reserve_rank, reserve_alt = nil,nil,nil,nil
local r,_,rdy,name = string.find(text,shooty_reserveanswer)
if (r) and (running_check) then -- need to check that the same person is not declaring multiple mains (cheaters)
if (rdy) then
if (name) and (name ~= "") then
reserve, reserve_class, reserve_rank = sepgp:verifyGuildMember(name)
if reserve ~= sender then
reserve_alt = sender
end
else
reserve, reserve_class, reserve_rank = sepgp:verifyGuildMember(sender)
end
if reserve and reserve_class and reserve_rank then
if reserve_alt then
if not reserves_blacklist[reserve_alt] then
reserves_blacklist[reserve_alt] = true
table.insert(sepgp.reserves,{reserve,reserve_class,reserve_rank,reserve_alt})
else
sepgp:defaultPrint(string.format("|cffff0000%s|r has already added a member to Reserves. Discarding!"))
end
else
if not reserves_blacklist[reserve] then
reserves_blacklist[reserve] = true
table.insert(sepgp.reserves,{reserve,reserve_class,reserve_rank})
else
sepgp:defaultPrint(string.format("|cffff0000%s|r has already added a member to Reserves. Discarding!"))
end
end
end
end
return
end
local q = string.find(text,"^{shootyepgp}Type")
if (q) and not (running_check) then
if (not UnitInRaid("player")) or (not sepgp:inRaid(sender)) then
StaticPopup_Show("SHOOTY_EPGP_RESERVE_AFKCHECK_RESPONCE")
end
end
end
---------
-- Bids
---------
local lootCall = {}
lootCall.whisp = {
"^(w)[%s%p%c]+.+",".+[%s%p%c]+(w)$",".+[%s%p%c]+(w)[%s%p%c]+.*",".*[%s%p%c]+(w)[%s%p%c]+.+",
"^(whisper)[%s%p%c]+.+",".+[%s%p%c]+(whisper)$",".+[%s%p%c]+(whisper)[%s%p%c]+.*",".*[%s%p%c]+(whisper)[%s%p%c]+.+",
".+[%s%p%c]+(bid)[%s%p%c]*.*",".*[%s%p%c]*(bid)[%s%p%c]+.+"
}
lootCall.ms = {".+(%+).*",".*(%+).+", ".+(ms).*",".*(ms).+", ".+(mainspec).*",".*(mainspec).+"}
lootCall.os = {".+(%-).*",".*(%-).+", ".+(os).*",".*(os).+", ".+(offspec).*",".*(offspec).+"}
function sepgp:captureLootCall(text, sender)
if not (IsRaidLeader() or self:lootMaster()) then return end
if not sender == playerName then return end
if not (string.find(text, "|Hitem:", 1, true)) then return end
local lowtext = string.lower(text)
local whisperkw_found, mskw_found, oskw_found, link_found
local _, itemLink, itemColor, itemString, itemName
for _,f in ipairs(lootCall.whisp) do
whisperkw_found = string.find(lowtext,f)
if (whisperkw_found) then break end
end
for _,f in ipairs(lootCall.ms) do
mskw_found = string.find(lowtext,f)
if (mskw_found) then break end
end
for _,f in ipairs(lootCall.os) do
oskw_found = string.find(lowtext,f)
if (oskw_found) then break end
end
if (whisperkw_found) or (mskw_found) or (oskw_found) then
_,_,itemLink = string.find(text,"(|c%x+|H.+|h%[.+%]|h|r)")
if (itemLink) and (itemLink ~= "") then
link_found, _, itemColor, itemString, itemName = string.find(itemLink, "^(|c%x+)|H(.+)|h(%[.+%])")
end
if (link_found) then
self:clearBids()
sepgp.bid_item.link = itemString
sepgp.bid_item.linkFull = itemLink
sepgp.bid_item.name = string.format("%s%s|r",itemColor,itemName)
self:ScheduleEvent("shootyepgpBidTimeout",self.clearBids,360,self)
running_bid = true
self:debugPrint("Capturing Bids for 6min.")
sepgp_bids:Toggle(true)
end
end
end
local lootBid = {}
lootBid.ms = {"(%+)",".+(%+).*",".*(%+).+",".*(%+).*","(ms)"}
lootBid.os = {"(%-)",".+(%-).*",".*(%-).+",".*(%-).*","(os)"}
function sepgp:captureBid(text, sender)
if not (running_bid) then return end
if not (IsRaidLeader() or self:lootMaster()) then return end
if not sepgp.bid_item.link then return end
local mskw_found,oskw_found
local lowtext = string.lower(text)
for _,f in ipairs(lootBid.ms) do
mskw_found = string.find(text,f)
if (mskw_found) then break end
end
for _,f in ipairs(lootBid.os) do
oskw_found = string.find(text,f)
if (oskw_found) then break end
end
if (mskw_found) or (oskw_found) then
if self:inRaid(sender) then
if bids_blacklist[sender] == nil then
for i = 1, GetNumGuildMembers(1) do
local name, _, _, _, class, _, note, officernote, _, _ = GetGuildRosterInfo(i)
if name == sender then
local ep = self:get_ep(name,note)
local gp = self:get_gp(name,officernote)
if (mskw_found) then
bids_blacklist[sender] = true
table.insert(sepgp.bids_main,{name,class,ep,gp,ep/gp})
elseif (oskw_found) then
bids_blacklist[sender] = true
table.insert(sepgp.bids_off,{name,class,ep,gp,ep/gp})
end
sepgp_bids:Toggle(true)
sepgp_bids:Refresh()
return
end
end
end
end
end
end
function sepgp:clearBids()
sepgp:defaultPrint("clearBids")
sepgp.bid_item = {}
sepgp.bids_main = {}
sepgp.bids_off = {}
bids_blacklist = {}
if self:IsEventScheduled("shootyepgpBidTimeout") then
self:CancelScheduledEvent("shootyepgpBidTimeout")
end
running_bid = false
sepgp_bids:Refresh()
end
------------
-- Utility
------------
function sepgp:num_round(i)
return math.floor(i+0.5)
end
function sepgp:verifyGuildMember(name)
for i=1,GetNumGuildMembers(1) do
local g_name, g_rank, g_rankIndex, g_level, g_class, g_zone, g_note, g_officernote, g_online = GetGuildRosterInfo(i)
if (string.lower(name) == string.lower(g_name)) and (tonumber(g_level) == MAX_PLAYER_LEVEL) then
return g_name, g_class, g_rank
end
end
if (name) and name ~= "" then
sepgp:defaultPrint(string.format("%s not found in the guild or not max level!",name))
end
return
end
function sepgp:inRaid(name)
for i=1,GetNumRaidMembers() do
if name == (UnitName(raidUnit[i])) then
return true
end
end
return false
end
function sepgp:lootMaster()
local method, lootmasterID = GetLootMethod()
if method == "master" and lootmasterID == 0 then
return true
else
return false
end
end
-------------
-- Dialogs
-------------
StaticPopupDialogs["SHOOTY_EPGP_SET_MAIN"] = {
text = "Set your main to be able to participate in Reserve List EPGP Checks.",
button1 = TEXT(ACCEPT),
button2 = TEXT(CANCEL),
hasEditBox = 1,
maxLetters = 12,
OnAccept = function()
local editBox = getglobal(this:GetParent():GetName().."EditBox")
sepgp_main = sepgp:verifyGuildMember(editBox:GetText())
end,
OnShow = function()
getglobal(this:GetName().."EditBox"):SetText(sepgp_main or "")
getglobal(this:GetName().."EditBox"):SetFocus()
end,
OnHide = function()
if ( ChatFrameEditBox:IsVisible() ) then
ChatFrameEditBox:SetFocus()
end
getglobal(this:GetName().."EditBox"):SetText("")
end,
EditBoxOnEnterPressed = function()
local editBox = getglobal(this:GetParent():GetName().."EditBox")
sepgp_main = sepgp:verifyGuildMember(editBox:GetText())
this:GetParent():Hide()
end,
EditBoxOnEscapePressed = function()
this:GetParent():Hide()
end,
timeout = 0,
exclusive = 1,
whileDead = 1,
hideOnEscape = 1
}
StaticPopupDialogs["SHOOTY_EPGP_RESERVE_AFKCHECK_RESPONCE"] = {
text = "Reserves: AFKCheck. Are you available?",
button1 = TEXT(YES),
button2 = TEXT(NO),
OnAccept = function()
sepgp:sendReserverResponce()
end,
timeout = shooty_timeout,
exclusive = 1,
showAlert = 1,
whileDead = 1,
hideOnEscape = 1
}
+32
View File
@@ -0,0 +1,32 @@
## Interface: 11200
## Title: shootyepgp
## Notes: Effort Points/Gear Points Loot System
## Author: shooty, Roadblock
## Version: 2.0
## OptionalDeps: Ace2
## SavedVariables: sepgp_saychannel,sepgp_groupbyclass,sepgp_raidonly,sepgp_decay,sepgp_reservechannel,sepgp_main,sepgp_progress,sepgp_discount
## SavedVariablesPerCharacter:
Libs\AceLibrary\AceLibrary.lua
Libs\AceOO-2.0\AceOO-2.0.lua
Libs\AceEvent-2.0\AceEvent-2.0.lua
Libs\AceAddon-2.0\AceAddon-2.0.lua
Libs\AceHook-2.0\AceHook-2.0.lua
Libs\AceConsole-2.0\AceConsole-2.0.lua
Libs\AceModuleCore-2.0\AceModuleCore-2.0.lua
Libs\AceDB-2.0\AceDB-2.0.lua
Libs\AceDebug-2.0\AceDebug-2.0.lua
Libs\AceLocale-2.2\AceLocale-2.2.lua
Libs\Babble-Class-2.2\Babble-Class-2.2.lua
Libs\Crayon-2.0\Crayon-2.0.lua
Libs\Compost-2.0\Compost-2.0.lua
Libs\Dewdrop-2.0\Dewdrop-2.0.lua
Libs\FuBarPlugin-2.0\FuBarPlugin-2.0.lua
Libs\Tablet-2.0\Tablet-2.0.lua
shootyepgp.lua
standings.lua
reserves.lua
bids.lua
prices.lua
+201
View File
@@ -0,0 +1,201 @@
local T = AceLibrary("Tablet-2.0")
local D = AceLibrary("Dewdrop-2.0")
local C = AceLibrary("Crayon-2.0")
local BC = AceLibrary("Babble-Class-2.2")
sepgp_standings = sepgp:NewModule("sepgp_standings", "AceDB-2.0")
local shooty_export = CreateFrame("Frame", "shooty_exportframe", UIParent)
shooty_export:SetWidth(250)
shooty_export:SetHeight(150)
shooty_export:SetPoint('TOP', UIParent, 'TOP', 0,-80)
shooty_export:SetFrameStrata('DIALOG')
shooty_export:Hide()
shooty_export:SetBackdrop({
bgFile = [[Interface\Buttons\WHITE8x8]],
insets = {left = 3, right = 3, top = 4, bottom = 3
}})
shooty_export:SetBackdropColor(0, 0, 0, 0.7)
shooty_export.title = shooty_export:CreateFontString(nil,"OVERLAY")
shooty_export.title:SetPoint("TOP",0,0)
shooty_export.title:SetFont("Fonts\\FRIZQT__.TTF", 12)
shooty_export.title:SetWidth(200)
shooty_export.title:SetJustifyH("LEFT")
shooty_export.title:SetJustifyV("CENTER")
shooty_export.title:SetText("Ctrl-C to copy. Esc to close.")
shooty_export.title:SetTextColor(204/255,204/255,0)
shooty_export.title:SetShadowOffset(1, -1)
shooty_export.edit = CreateFrame("EditBox", "shooty_exportedit", shooty_export)
shooty_export.edit:SetMultiLine(true)
shooty_export.edit:SetAutoFocus(true)
shooty_export.edit:EnableMouse(true)
shooty_export.edit:SetMaxLetters(0)
shooty_export.edit:SetHistoryLines(1)
shooty_export.edit:SetFont('Fonts\\ARIALN.ttf', 12, 'THINOUTLINE')
shooty_export.edit:SetWidth(290)
shooty_export.edit:SetHeight(190)
shooty_export.edit:SetScript("OnEscapePressed", function()
shooty_export.edit:SetText("")
shooty_export:Hide()
end)
shooty_export.AddSelectText = function(txt)
shooty_export.edit:SetText(txt)
shooty_export.edit:HighlightText()
end
shooty_export.scroll = CreateFrame("ScrollFrame", "shooty_exportscroll", shooty_export, 'UIPanelScrollFrameTemplate')
shooty_export.scroll:SetPoint('TOPLEFT', shooty_export, 'TOPLEFT', 8, -30)
shooty_export.scroll:SetPoint('BOTTOMRIGHT', shooty_export, 'BOTTOMRIGHT', -30, 8)
shooty_export.scroll:SetScrollChild(shooty_export.edit)
table.insert(UISpecialFrames,"shooty_exportframe")
function sepgp_standings:OnEnable()
if not T:IsRegistered("sepgp_standings") then
T:Register("sepgp_standings",
"children", function()
T:SetTitle("shootyepgp standings")
self:OnTooltipUpdate()
end,
"showTitleWhenDetached", true,
"showHintWhenDetached", true,
"cantAttach", true,
"menu", function()
D:AddLine(
"text", "Raid Only",
"tooltipText", "Only show members in raid.",
"checked", sepgp_raidonly,
"func", function() sepgp_standings:ToggleRaidOnly() end
)
D:AddLine(
"text", "Group by class",
"tooltipText", "Group members by class.",
"checked", sepgp_groupbyclass,
"func", function() sepgp_standings:ToggleGroupByClass() end
)
D:AddLine(
"text", "Refresh",
"tooltipText", "Refresh window",
"func", function() sepgp_standings:Refresh() end
)
D:AddLine(
"text", "Export",
"tooltipText", "Export standings to csv.",
"func", function() sepgp_standings:Export() end
)
end
)
end
if not T:IsAttached("sepgp_standings") then
T:Open("sepgp_standings")
end
end
function sepgp_standings:OnDisable()
T:Close("sepgp_standings")
end
function sepgp_standings:Refresh()
T:Refresh("sepgp_standings")
end
function sepgp_standings:Export()
local t = {}
for i = 1, GetNumGuildMembers(1) do
local name, _, _, _, class, _, note, officernote, _, _ = GetGuildRosterInfo(i)
local ep = sepgp:get_ep(name,note)
local gp = sepgp:get_gp(name,officernote)
if ep > 0 then
table.insert(t,{name,ep,gp,ep/gp})
end
end
table.sort(t, function(a,b)
return tonumber(a[4]) > tonumber(b[4])
end)
shooty_export:Show()
local txt = "Name;EP;GP;PR\n"
for i,val in ipairs(t) do
txt = string.format("%s%s;%d;%d;%.4f\n",txt,val[1],val[2],val[3],val[4])
end
shooty_export.AddSelectText(txt)
end
function sepgp_standings:Toggle()
if T:IsAttached("sepgp_standings") then
T:Detach("sepgp_standings")
if (T:IsLocked("sepgp_standings")) then
T:ToggleLocked("sepgp_standings")
end
else
T:Attach("sepgp_standings")
end
end
function sepgp_standings:ToggleGroupByClass()
sepgp_groupbyclass = not sepgp_groupbyclass
self:Refresh()
end
function sepgp_standings:ToggleRaidOnly()
sepgp_raidonly = not sepgp_raidonly
self:Refresh()
sepgp:SetRefresh(true)
end
-- Builds a standings table with record:
-- name, class, EP, GP, PR
-- and sorted by PR
function sepgp_standings:BuildStandingsTable()
local t = { }
local r = { }
if (sepgp_raidonly) and GetNumRaidMembers() > 0 then
for i = 1, GetNumRaidMembers(true) do
local name, rank, subgroup, level, class, fileName, zone, online, isDead = GetRaidRosterInfo(i)
r[name] = true
end
end
for i = 1, GetNumGuildMembers(1) do
local name, _, _, _, class, _, note, officernote, _, _ = GetGuildRosterInfo(i)
local ep = sepgp:get_ep(name)
local gp = sepgp:get_gp(name)
if ep > 0 then
if (sepgp_raidonly) and next(r) then
if r[name] then
table.insert(t,{name,class,ep,gp,ep/gp})
end
else
table.insert(t,{name,class,ep,gp,ep/gp})
end
end
end
if (sepgp_groupbyclass) then
table.sort(t, function(a,b)
if (a[2] ~= b[2]) then return a[2] > b[2]
else return a[5] > b[5] end
end)
else
table.sort(t, function(a,b)
return a[5] > b[5]
end)
end
return t
end
function sepgp_standings:OnTooltipUpdate()
local cat = T:AddCategory(
"columns", 4,
"text", C:Orange("Name"), "child_textR", 1, "child_textG", 1, "child_textB", 1, "child_justify", "LEFT",
"text2", C:Orange("ep"), "child_text2R", 1, "child_text2G", 1, "child_text2B", 1, "child_justify2", "RIGHT",
"text3", C:Orange("gp"), "child_text3R", 1, "child_text3G", 1, "child_text3B", 1, "child_justify3", "RIGHT",
"text4", C:Orange("pr"), "child_text4R", 1, "child_text4G", 1, "child_text4B", 0, "child_justify4", "RIGHT"
)
local t = self:BuildStandingsTable()
for i = 1, table.getn(t) do
local name, class, ep, gp, pr = unpack(t[i])
cat:AddLine(
"text", C:Colorize(BC:GetHexColor(class), name),
"text2", string.format("%.4g", ep),
"text3", string.format("%.4g", gp),
"text4", string.format("%.4g", pr)
)
end
end