/trunk
local MAJOR = "LibInternalCooldowns-1.0" |
local MINOR = tonumber(("$Revision: 15 $"):match("%d+")) |
local lib, oldminor = LibStub:NewLibrary(MAJOR, MINOR) |
if not lib then return end -- No Upgrade needed. |
local CallbackHandler = LibStub:GetLibrary("CallbackHandler-1.0") |
local GetInventoryItemLink = _G.GetInventoryItemLink |
local GetInventoryItemTexture = _G.GetInventoryItemTexture |
local GetMacroInfo = _G.GetMacroInfo |
local GetActionInfo = _G.GetActionInfo |
local substr = _G.string.sub |
local wipe = _G.wipe |
local playerGUID = UnitGUID("player") |
local GetTime = _G.GetTime |
lib.spellToItem = lib.spellToItem or {} |
lib.cooldownStartTimes = lib.cooldownStartTimes or {} |
lib.cooldownDurations = lib.cooldownDurations or {} |
lib.callbacks = lib.callbacks or CallbackHandler:New(lib) |
lib.cooldowns = lib.cooldowns or nil |
lib.hooks = lib.hooks or {} |
local enchantProcTimes = {} |
if not lib.eventFrame then |
lib.eventFrame = CreateFrame("Frame") |
lib.eventFrame:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED") |
lib.eventFrame:RegisterEvent("PLAYER_ENTERING_WORLD") |
lib.eventFrame:SetScript("OnEvent", function(frame, event, ...) |
frame.lib[event](frame.lib, event, ...) |
end) |
end |
lib.eventFrame.lib = lib |
local INVALID_EVENTS = { |
SPELL_DISPEL = true, |
SPELL_DISPEL_FAILED = true, |
SPELL_STOLEN = true, |
SPELL_AURA_REMOVED = true, |
SPELL_AURA_REMOVED_DOSE = true, |
SPELL_AURA_BROKEN = true, |
SPELL_AURA_BROKEN_SPELL = true, |
SPELL_CAST_FAILED = true |
} |
local slots = { |
AMMOSLOT = 0, |
INVTYPE_HEAD = 1, |
INVTYPE_NECK = 2, |
INVTYPE_SHOULDER = 3, |
INVTYPE_BODY = 4, |
INVTYPE_CHEST = 5, |
INVTYPE_WAIST = 6, |
INVTYPE_LEGS = 7, |
INVTYPE_FEET = 8, |
INVTYPE_WRIST = 9, |
INVTYPE_HAND = 10, |
INVTYPE_FINGER = {11, 12}, |
INVTYPE_TRINKET = {13, 14}, |
INVTYPE_CLOAK = 15, |
INVTYPE_WEAPONMAINHAND = 16, |
INVTYPE_2HWEAPON = 16, |
INVTYPE_WEAPON = {16, 17}, |
INVTYPE_HOLDABLE = 17, |
INVTYPE_SHIELD = 17, |
INVTYPE_WEAPONOFFHAND = 17, |
INVTYPE_RANGED = 18 |
} |
function lib:PLAYER_ENTERING_WORLD() |
playerGUID = UnitGUID("player") |
self:Hook("GetInventoryItemCooldown") |
self:Hook("GetActionCooldown") |
self:Hook("GetItemCooldown") |
end |
function lib:Hook(name) |
-- unhook if a hook existed from an older copy |
if lib.hooks[name] then |
_G[name] = lib.hooks[name] |
end |
-- Re-hook it now |
lib.hooks[name] = _G[name] |
_G[name] = function(...) |
return self[name](self, ...) |
end |
end |
local function checkSlotForEnchantID(slot, enchantID) |
local link = GetInventoryItemLink("player", slot) |
if not link then return false; end |
local itemID, enchant = link:match("item:(%d+):(%d+)") |
if tonumber(enchant or -1) == enchantID then |
return true, tonumber(itemID) |
else |
return false |
end |
end |
local function isEquipped(itemID) |
local _, _, _, _, _, _, _, _, equipLoc = GetItemInfo(itemID) |
local slot = slots[equipLoc] |
if type(slot) == "table" then |
for _, v in ipairs(slot) do |
local link = GetInventoryItemLink("player", v) |
if link and link:match(("item:%s"):format(itemID)) then |
return true |
end |
end |
else |
local link = GetInventoryItemLink("player", slot) |
if link and link:match(("item:%s"):format(itemID)) then |
return true |
end |
end |
return false |
end |
function lib:COMBAT_LOG_EVENT_UNFILTERED(frame, timestamp, event, sourceGUID, sourceName, sourceFlags, destGUID, destName, destFlags, spellID, spellName) |
playerGUID = playerGUID or UnitGUID("player") |
if ((destGUID == playerGUID and (sourceGUID == nil or sourceGUID == destGUID)) or sourceGUID == playerGUID) and not INVALID_EVENTS[event] and substr(event, 0, 6) == "SPELL_" then |
local itemID = lib.spellToItem[spellID] |
if itemID then |
if type(itemID) == "table" then |
for k, v in ipairs(itemID) do |
if isEquipped(v) then |
self:SetCooldownFor(v, spellID, "ITEM") |
end |
end |
return |
else |
if isEquipped(itemID) then |
self:SetCooldownFor(itemID, spellID, "ITEM") |
end |
return |
end |
end |
-- Tests for enchant procs |
local enchantID = lib.enchants[spellID] |
if enchantID then |
local enchantID, slot1, slot2 = unpack(enchantID) |
local enchantPresent, itemID, first, second |
enchantPresent, itemID = checkSlotForEnchantID(slot1, enchantID) |
if enchantPresent then |
first = itemID |
if (enchantProcTimes[slot1] or 0) < GetTime() - (lib.cooldowns[spellID] or 45) then |
enchantProcTimes[slot1] = GetTime() |
self:SetCooldownFor(itemID, spellID, "ENCHANT") |
return |
end |
end |
enchantPresent, itemID = checkSlotForEnchantID(slot2, enchantID) |
if enchantPresent then |
second = itemID |
if (enchantProcTimes[slot2] or 0) < GetTime() - (lib.cooldowns[spellID] or 45) then |
enchantProcTimes[slot2] = GetTime() |
self:SetCooldownFor(itemID, spellID, "ENCHANT") |
return |
end |
end |
if first and second then |
if enchantProcTimes[slot1] < enchantProcTimes[slot2] then |
self:SetCooldownFor(first, spellID, "ENCHANT") |
else |
self:SetCooldownFor(second, spellID, "ENCHANT") |
end |
end |
end |
local metaID = lib.metas[spellID] |
if metaID then |
local link = GetInventoryItemLink("player", 1) |
if link then |
local id = tonumber(link:match("item:(%d+)") or 0) |
if id and id ~= 0 then |
self:SetCooldownFor(id, spellID, "META") |
end |
end |
return |
end |
local talentID = lib.talents[spellID] |
if talentID then |
self:SetCooldownFor(("%s: %s"):format(UnitClass("player"), talentID), spellID, "TALENT") |
return |
end |
end |
end |
function lib:SetCooldownFor(itemID, spellID, procSource) |
local duration = lib.cooldowns[spellID] or 45 |
lib.cooldownStartTimes[itemID] = GetTime() |
lib.cooldownDurations[itemID] = duration |
-- Talents have a separate callback, so that InternalCooldowns_Proc always has an item ID. |
if procSource == "TALENT" then |
lib.callbacks:Fire("InternalCooldowns_TalentProc", spellID, GetTime(), duration, procSource) |
else |
lib.callbacks:Fire("InternalCooldowns_Proc", itemID, spellID, GetTime(), duration, procSource) |
end |
end |
local function cooldownReturn(id) |
if not id then return end |
local hasItem = id and lib.cooldownStartTimes[id] and lib.cooldownDurations[id] |
if hasItem then |
if lib.cooldownStartTimes[id] + lib.cooldownDurations[id] > GetTime() then |
return lib.cooldownStartTimes[id], lib.cooldownDurations[id], 1 |
else |
return 0, 0, 0 |
end |
else |
return nil |
end |
end |
function lib:IsInternalItemCooldown(itemID) |
return cooldownReturn(itemID) ~= nil |
end |
function lib:GetInventoryItemCooldown(unit, slot) |
local start, duration, enable = self.hooks.GetInventoryItemCooldown(unit, slot) |
if not enable or enable == 0 then |
local link = GetInventoryItemLink("player", slot) |
if link then |
local itemID = link:match("item:(%d+)") |
itemID = tonumber(itemID or 0) |
local start, duration, running = cooldownReturn(itemID) |
if start then return start, duration, running end |
end |
end |
return start, duration, enable |
end |
function lib:GetActionCooldown(slotID) |
local t, id, subtype, globalID = GetActionInfo(slotID) |
if t == "item" then |
local start, duration, running = cooldownReturn(id) |
if start then return start, duration, running end |
elseif t == "macro" then |
local _, tex = GetMacroInfo(id) |
if tex == GetInventoryItemTexture("player", 13) then |
id = tonumber(GetInventoryItemLink("player", 13):match("item:(%d+)")) |
local start, duration, running = cooldownReturn(id) |
if start then return start, duration, running end |
elseif tex == GetInventoryItemTexture("player", 14) then |
id = tonumber(GetInventoryItemLink("player", 14):match("item:(%d+)")) |
local start, duration, running = cooldownReturn(id) |
if start then return start, duration, running end |
end |
end |
return self.hooks.GetActionCooldown(slotID) |
end |
function lib:GetItemCooldown(param) |
local id |
local iparam = tonumber(param) |
if iparam and iparam > 0 then |
id = param |
elseif type(param) == "string" then |
local name, link = GetItemInfo(param) |
if link then |
id = link:match("item:(%d+)") |
end |
end |
if id then |
id = tonumber(id) |
local start, duration, running = cooldownReturn(id) |
if start then return start, duration, running end |
end |
return self.hooks.GetItemCooldown(param) |
end |
local lib, oldminor = LibStub:GetLibrary("LibInternalCooldowns-1.0") |
-- Format is spellID = itemID | {itemID, itemID, ... itemID} |
local spellToItem = { |
[64411] = 46017, -- Val'anyr, Hammer of Ancient Kings |
[60065] = {44914, 40684, 49074}, -- Anvil of the Titans, Mirror of Truth, Coren's Chromium Coaster |
[60488] = 40373, -- Extract of Necromatic Power |
[64713] = 45518, -- Flare of the Heavens |
[60064] = {44912, 40682, 49706}, -- Flow of Knowledge, Sundial of the Exiled, Mithril Pocketwatch |
[67703] = {47303, 47115}, -- Death's Choice, Death's Verdict (AGI) |
[67708] = {47303, 47115}, -- Death's Choice, Death's Verdict (STR) |
[67772] = {47464, 47131}, -- Death's Choice, Death's Verdict (Heroic) (AGI) |
[67773] = {47464, 47131}, -- Death's Choice, Death's Verdict (Heroic) (STR) |
-- ICC epix |
-- Rep rings |
[72416] = {50398, 50397}, |
[72412] = {50402, 50401}, |
[72418] = {50399, 50400}, |
[72414] = {50404, 50403}, |
-- Deathbringer's Will (Non-heroic) |
[71485] = 50362, |
[71492] = 50362, |
[71486] = 50362, |
[71484] = 50362, |
[71491] = 50362, |
[71487] = 50362, |
-- Deathbringer's Will (Heroic) |
[71556] = 50363, |
[71560] = 50363, |
[71558] = 50363, |
[71561] = 50363, |
[71559] = 50363, |
[71557] = 50363, |
[71403] = 50198, -- Needle-Encrusted Scorpion |
[71610] = 50359, -- Althor's Abacus |
[71633] = 50352, -- Corpse-tongue coin |
[71601] = 50353, -- Dislodged Foreign Object |
[71584] = 50358, -- Purified Lunar Dust |
[71401] = 50342, -- Whispering Fanged Skull |
-- DK T9 2pc. WTF. |
[67117] = {48501, 48502, 48503, 48504, 48505, 48472, 48474, 48476, 48478, 48480, 48491, 48492, 48493, 48494, 48495, 48496, 48497, 48498, 48499, 48500, 48486, 48487, 48488, 48489, 48490, 48481, 48482, 48483, 48484, 48485}, |
-- WotLK Epix |
[67671] = 47214, -- Banner of Victory |
[67669] = 47213, -- Abyssal Rune |
[64772] = 45609, -- Comet's Trail |
[65024] = 46038, -- Dark Matter |
[60443] = 40371, -- Bandit's Insignia |
[64790] = 45522, -- Blood of the Old God |
[60203] = 42990, -- Darkmoon Card: Death |
[60494] = 40255, -- Dying Curse |
[65004] = 65005, -- Elemental Focus Stone |
[60492] = 39229, -- Embrace of the Spider |
[60530] = 40258, -- Forethought Talisman |
[60437] = 40256, -- Grim Toll |
[49623] = 37835, -- Je'Tze's Bell |
[65019] = 45931, -- Mjolnir Runestone |
[64741] = 45490, -- Pandora's Plea |
[65014] = 45286, -- Pyrite Infuser |
[65003] = 45929, -- Sif's Remembrance |
[60538] = 40382, -- Soul of the Dead |
[58904] = 43573, -- Tears of Bitter Anguish |
[60062] = {40685, 49078}, -- The Egg of Mortal Essence, Ancient Pickled Egg |
[64765] = 45507, -- The General's Heart |
-- WotLK Blues |
[51353] = 38358, -- Arcane Revitalizer |
[60218] = 37220, -- Essence of Gossamer |
[60479] = 37660, -- Forge Ember |
[51348] = 38359, -- Goblin Repetition Reducer |
[63250] = 45131, -- Jouster's Fury |
[63250] = 45219, -- Jouster's Fury |
[60302] = 37390, -- Meteorite Whetstone |
[54808] = 40865, -- Noise Machine |
[60483] = 37264, -- Pendulum of Telluric Currents |
[52424] = 38675, -- Signet of the Dark Brotherhood |
[55018] = 40767, -- Sonic Booster |
[52419] = 38674, -- Soul Harvester's Charm |
-- [18350] = 37111, -- Soul Preserver, no internal cooldown |
[60520] = 37657, -- Spark of Life |
[60307] = 37064, -- Vestige of Haldor |
-- Greatness cards |
[60233] = {44253, 44254, 44255, 42987}, -- Greatness, AGI |
[60235] = {44253, 44254, 44255, 42987}, -- Greatness, SPI |
[60229] = {44253, 44254, 44255, 42987}, -- Greatness, INT |
[60234] = {44253, 44254, 44255, 42987}, -- Greatness, STR |
-- Burning Crusade trinkets |
-- None yet. |
-- Vanilla Epix |
[23684] = 19288, -- Darkmoon Card: Blue Dragon |
} |
-- spell ID = {enchant ID, slot1[, slot2]} |
local enchants = { |
-- [59620] = {3789, 16, 17}, -- Berserking, no ICD via testing. |
-- [28093] = {2673, 16, 17}, -- Mongoose |
-- [13907] = {912, 16, 17}, -- Demonslaying |
[55637] = {3722, 15}, -- Lightweave |
[55775] = {3730, 15}, -- Swordguard |
[55767] = {3728, 15}, -- Darkglow |
[59626] = {3790, 16}, -- Black Magic ? |
[59625] = {3790, 16}, -- Black Magic ? |
} |
-- ICDs on metas assumed to be 45 sec. Needs testing. |
local metas = { |
-- I've commented these two out, because there aren't really any tactical decisions you could make based on them |
-- [55382] = 41401, -- Insightful Earthsiege Diamond |
-- [32848] = 25901, -- Insightful Earthstorm Diamond |
[23454] = 25899, -- Brutal Earthstorm Diamond |
[55341] = 41385, -- Invigorating Earthsiege Diamond |
[18803] = 25893, -- Mystical Skyfire Diamond |
[32845] = 25898, -- Tenacious Earthstorm Diamond |
[39959] = 32410, -- Thundering Skyfire Diamond |
[55379] = 41400 -- Thundering Skyflare Diamond |
} |
-- Spell ID => cooldown, in seconds |
-- If an item isn't in here, 45 sec is assumed. |
local cooldowns = { |
-- ICC rep rings |
[72416] = 60, |
[72412] = 60, |
[72418] = 60, |
[72414] = 60, |
[60488] = 15, |
[51348] = 10, |
[51353] = 10, |
[54808] = 60, |
[55018] = 60, |
[52419] = 30, |
[59620] = 90, |
[55382] = 15, |
[32848] = 15, |
[55341] = 90, -- Invigorating Earthsiege, based on WowHead comments (lol?) |
[48517] = 30, |
[48518] = 30, |
[47755] = 12, |
-- Deathbringer's Will, XI from #elitistjerks says it's 105 sec so if it's wrong yell at him. |
[71485] = 105, |
[71492] = 105, |
[71486] = 105, |
[71484] = 105, |
[71491] = 105, |
[71487] = 105, |
-- Deathbringer's Will (Heroic) |
[71556] = 105, |
[71560] = 105, |
[71558] = 105, |
[71561] = 105, |
[71559] = 105, |
[71557] = 105, |
-- Black Magic |
[59626] = 35, |
[59625] = 35, |
} |
-- Procced spell effect ID = unique name |
-- The name doesn't matter, as long as it's non-numeric and unique to the ICD. |
local talents = { |
-- Druid |
[48517] = "Eclipse", |
[48518] = "Eclipse", |
-- Hunter |
[56453] = "Lock and Load", |
-- Death Knight |
[52286] = "Will of the Necropolis", |
-- Priest |
[47755] = "Rapture" |
} |
----------------------------------------------------------------------- |
-- Don't edit past this line -- |
----------------------------------------------------------------------- |
------------------------------------ |
-- Upgrade this data into the lib |
------------------------------------ |
lib.spellToItem = lib.spellToItem or {} |
lib.cooldowns = lib.cooldowns or {} |
lib.enchants = lib.enchants or {} |
lib.metas = lib.metas or {} |
lib.talents = lib.talents or {} |
local tt, tts = {}, {} |
local function merge(t1, t2) |
wipe(tts) |
for _, v in ipairs(t1) do |
tts[v] = true |
end |
for _, v in ipairs(t2) do |
if not tts[v] then |
tinsert(t1, v) |
end |
end |
end |
for k, v in pairs(spellToItem) do |
local e = lib.spellToItem[k] |
if e and e ~= v then |
if type(e) == "table" then |
if type(v) ~= "table" then |
wipe(tt) |
tinsert(tt, v) |
end |
merge(e, tt) |
else |
lib.spellToItem[k] = {e, v} |
end |
else |
lib.spellToItem[k] = v |
end |
end |
for k, v in pairs(cooldowns) do |
lib.cooldowns[k] = v |
end |
for k, v in pairs(enchants) do |
lib.enchants[k] = v |
end |
for k, v in pairs(metas) do |
lib.metas[k] = v |
end |
for k, v in pairs(talents) do |
lib.talents[k] = v |
end |
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/ |
..\FrameXML\UI.xsd"> |
<Script file="LibInternalCooldowns-1.0.lua"/> |
<Script file="Data.lua"/> |
</Ui> |
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/ ..\FrameXML\UI.xsd"> |
<Script file="LibDebugLog-1.0.lua"/> |
</Ui> |
--[[ |
LibDebugLog-1.0 - Library providing simple debug logging for WoW addons |
Copyright (C) 2008 Adirelle |
This program is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public License |
as published by the Free Software Foundation; either version 2 |
of the License, or (at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
--]] |
local MAJOR, MINOR = "LibDebugLog-1.0", 100000 + tonumber(("$Revision: 20 $"):match("%d+")) |
assert(LibStub, MAJOR.." requires LibStub") |
local CBH = LibStub("CallbackHandler-1.0",false) |
assert(CBH, MAJOR.." requires CallbackHandler-1.0") |
local lib = LibStub:NewLibrary(MAJOR, MINOR) |
if not lib then return end |
lib.loggers = lib.loggers or {} |
lib.debugging = lib.debugging or {} |
lib.mixins = lib.mixins or {} |
lib.options = lib.options or {} |
lib.callbacks = lib.callbacks or CBH:New(lib) |
function lib.callbacks:OnUsed(_, event) |
if event == "MessageLogged" then |
lib.quiet = true |
end |
end |
function lib.callbacks:OnUnused(_, event) |
if event == "MessageLogged" then |
lib.quiet = false |
end |
end |
local loggers = lib.loggers |
local debugging = lib.debugging |
local mixins = lib.mixins |
local options = lib.options |
function mixins:ToggleDebugLog(value) |
value = not not value |
if value ~= debugging[self] then |
if not value then |
self:Debug("Debug disabled") |
end |
debugging[self] = value |
if value then |
self:Debug("Debug enabled") |
end |
lib.callbacks:Fire(value and 'DebugLogEnabled' or 'DebugLogDisabled', self, value) |
end |
end |
function mixins:IsDebugLogEnabled() |
return debugging[self] |
end |
do |
-- Based on AceDebug-2.0 |
local tmp = {} |
local function LogMessage(self, a1, ...) |
if lib.globalToggle == false or (lib.globalToggle == nil and not debugging[self]) then return end |
local message, now, n = "", GetTime(), select('#', ...) |
for i=1,n do tmp[i] = tostring(select(i, ...)) end |
a1 = tostring(a1) |
if a1:find("%%") and n >= 1 then |
message = a1:format(unpack(tmp)) |
else |
message = a1 .. " " .. table.concat(tmp, " ") |
end |
for i=1,n do tmp[i] = nil end |
if lib.quiet then |
lib.callbacks:Fire("MessageLogged", self, now, message) |
else |
DEFAULT_CHAT_FRAME:AddMessage( |
("|cff7fff7f(DEBUG) %s:[%s.%3d]|r: %s"):format( |
tostring(self), date("%H:%M:%S"), (now % 1) * 1000, message |
) |
) |
end |
end |
function mixins:Debug(...) |
local success, errorMsg = pcall(LogMessage, self, ...) |
if not success then |
geterrorhandler()(errorMsg) |
end |
end |
end |
function lib:SetGlobalToggle(value) |
if value ~= nil then |
value = not not value |
end |
if value ~= lib.globalToggle then |
lib.globalToggle = value |
lib.callbacks:Fire(value and 'GlobalDebugEnabled' or 'GlobalDebugDisabled', value) |
end |
end |
function lib:GetGlobalToggle() |
return lib.globalToggle |
end |
function lib:GetAce3OptionTable(logger, order) |
if not loggers[logger] then return end |
if not options[logger] then |
options[logger] = { |
name = 'Enable debug logs', |
type = 'toggle', |
get = function(info) return logger:IsDebugLogEnabled() end, |
set = function(info, value) return logger:ToggleDebugLog(value) end, |
disabled = function() return lib.globalToggle ~= nil end, |
order = order or 100, |
} |
end |
return options[logger] |
end |
do |
local function iter(onlyNamed, logger) |
while true do |
local name |
logger, name = next(loggers, logger) |
if not logger then |
return |
elseif not onlyNamed or name ~= true then |
return logger, name |
end |
end |
end |
function lib:IterateLoggers(onlyNamed) |
return iter, onlyNamed |
end |
end |
function lib:Embed(logger) |
assert(type(logger) == 'table') |
for name,func in pairs(mixins) do |
logger[name] = func |
end |
if not loggers[logger] then |
local name = rawget(logger, 'name') |
loggers[logger] = name or true |
self.callbacks:Fire('NewLogger', logger, name) |
self.callbacks:Fire('NewBroker', logger, name) -- Compat |
end |
end |
function lib:GetLoggerName(logger) |
local name = loggers[logger] |
return name ~= true and name or nil |
end |
lib.GetBrokerName = lib.GetLoggerName -- Compat |
lib.IterateBrokers = lib.IterateLoggers -- Compat |
for logger in pairs(loggers) do |
lib:Embed(logger) |
end |
--[[ |
Name: LibSharedMedia-3.0 |
Revision: $Revision: 58 $ |
Author: Elkano (elkano@gmx.de) |
Inspired By: SurfaceLib by Haste/Otravi (troeks@gmail.com) |
Website: http://www.wowace.com/projects/libsharedmedia-3-0/ |
Description: Shared handling of media data (fonts, sounds, textures, ...) between addons. |
Dependencies: LibStub, CallbackHandler-1.0 |
License: LGPL v2.1 |
]] |
local MAJOR, MINOR = "LibSharedMedia-3.0", 90000 + tonumber(("$Revision: 58 $"):match("(%d+)")) |
local lib = LibStub:NewLibrary(MAJOR, MINOR) |
if not lib then return end |
local _G = getfenv(0) |
local pairs = _G.pairs |
local type = _G.type |
local band = _G.bit.band |
local table_insert = _G.table.insert |
local table_sort = _G.table.sort |
local locale = GetLocale() |
local locale_is_western |
local LOCALE_MASK = 0 |
lib.LOCALE_BIT_koKR = 1 |
lib.LOCALE_BIT_ruRU = 2 |
lib.LOCALE_BIT_zhCN = 4 |
lib.LOCALE_BIT_zhTW = 8 |
lib.LOCALE_BIT_western = 128 |
local CallbackHandler = LibStub:GetLibrary("CallbackHandler-1.0") |
lib.callbacks = lib.callbacks or CallbackHandler:New(lib) |
lib.DefaultMedia = lib.DefaultMedia or {} |
lib.MediaList = lib.MediaList or {} |
lib.MediaTable = lib.MediaTable or {} |
lib.MediaType = lib.MediaType or {} |
lib.OverrideMedia = lib.OverrideMedia or {} |
local defaultMedia = lib.DefaultMedia |
local mediaList = lib.MediaList |
local mediaTable = lib.MediaTable |
local overrideMedia = lib.OverrideMedia |
-- create mediatype constants |
lib.MediaType.BACKGROUND = "background" -- background textures |
lib.MediaType.BORDER = "border" -- border textures |
lib.MediaType.FONT = "font" -- fonts |
lib.MediaType.STATUSBAR = "statusbar" -- statusbar textures |
lib.MediaType.SOUND = "sound" -- sound files |
-- populate lib with default Blizzard data |
-- BACKGROUND |
if not lib.MediaTable.background then lib.MediaTable.background = {} end |
lib.MediaTable.background["Blizzard Dialog Background"] = [[Interface\DialogFrame\UI-DialogBox-Background]] |
lib.MediaTable.background["Blizzard Low Health"] = [[Interface\FullScreenTextures\LowHealth]] |
lib.MediaTable.background["Blizzard Out of Control"] = [[Interface\FullScreenTextures\OutOfControl]] |
lib.MediaTable.background["Blizzard Parchment"] = [[Interface\AchievementFrame\UI-Achievement-Parchment-Horizontal]] |
lib.MediaTable.background["Blizzard Parchment 2"] = [[Interface\AchievementFrame\UI-Achievement-Parchment]] |
lib.MediaTable.background["Blizzard Tabard Background"] = [[Interface\TabardFrame\TabardFrameBackground]] |
lib.MediaTable.background["Blizzard Tooltip"] = [[Interface\Tooltips\UI-Tooltip-Background]] |
lib.MediaTable.background["Solid"] = [[Interface\Buttons\WHITE8X8]] |
-- BORDER |
if not lib.MediaTable.border then lib.MediaTable.border = {} end |
lib.MediaTable.border["None"] = [[Interface\None]] |
lib.MediaTable.border["Blizzard Achievement Wood"] = [[Interface\AchievementFrame\UI-Achievement-WoodBorder]] |
lib.MediaTable.border["Blizzard Chat Bubble"] = [[Interface\Tooltips\ChatBubble-Backdrop]] |
lib.MediaTable.border["Blizzard Dialog"] = [[Interface\DialogFrame\UI-DialogBox-Border]] |
lib.MediaTable.border["Blizzard Dialog Gold"] = [[Interface\DialogFrame\UI-DialogBox-Gold-Border]] |
lib.MediaTable.border["Blizzard Party"] = [[Interface\CHARACTERFRAME\UI-Party-Border]] |
lib.MediaTable.border["Blizzard Tooltip"] = [[Interface\Tooltips\UI-Tooltip-Border]] |
-- FONT |
if not lib.MediaTable.font then lib.MediaTable.font = {} end |
local SML_MT_font = lib.MediaTable.font |
if locale == "koKR" then |
LOCALE_MASK = lib.LOCALE_BIT_koKR |
-- |
SML_MT_font["êµµì ê¸ê¼´"] = [[Fonts\2002B.TTF]] |
SML_MT_font["기본 ê¸ê¼´"] = [[Fonts\2002.TTF]] |
SML_MT_font["ë°ë¯¸ì§ ê¸ê¼´"] = [[Fonts\K_Damage.TTF]] |
SML_MT_font["íì¤í¸ ê¸ê¼´"] = [[Fonts\K_Pagetext.TTF]] |
-- |
lib.DefaultMedia["font"] = "기본 ê¸ê¼´" -- someone from koKR please adjust if needed |
-- |
elseif locale == "zhCN" then |
LOCALE_MASK = lib.LOCALE_BIT_zhCN |
-- |
SML_MT_font["伤害æ°å"] = [[Fonts\ZYKai_C.ttf]] |
SML_MT_font["é»è®¤"] = [[Fonts\ZYKai_T.ttf]] |
SML_MT_font["è天"] = [[Fonts\ZYHei.ttf]] |
-- |
lib.DefaultMedia["font"] = "é»è®¤" -- someone from zhCN please adjust if needed |
-- |
elseif locale == "zhTW" then |
LOCALE_MASK = lib.LOCALE_BIT_zhTW |
-- |
SML_MT_font["æ示è¨æ¯"] = [[Fonts\bHEI00M.ttf]] |
SML_MT_font["è天"] = [[Fonts\bHEI01B.ttf]] |
SML_MT_font["å·å®³æ¸å"] = [[Fonts\bKAI00M.ttf]] |
SML_MT_font["é è¨"] = [[Fonts\bLEI00D.ttf]] |
-- |
lib.DefaultMedia["font"] = "é è¨" -- someone from zhTW please adjust if needed |
elseif locale == "ruRU" then |
LOCALE_MASK = lib.LOCALE_BIT_ruRU |
-- |
SML_MT_font["Arial Narrow"] = [[Fonts\ARIALN.TTF]] |
SML_MT_font["Friz Quadrata TT"] = [[Fonts\FRIZQT__.TTF]] |
SML_MT_font["Morpheus"] = [[Fonts\MORPHEUS.TTF]] |
SML_MT_font["Nimrod MT"] = [[Fonts\NIM_____.ttf]] |
SML_MT_font["Skurri"] = [[Fonts\SKURRI.TTF]] |
-- |
lib.DefaultMedia.font = "Friz Quadrata TT" |
-- |
else |
LOCALE_MASK = lib.LOCALE_BIT_western |
locale_is_western = true |
-- |
SML_MT_font["Arial Narrow"] = [[Fonts\ARIALN.TTF]] |
SML_MT_font["Friz Quadrata TT"] = [[Fonts\FRIZQT__.TTF]] |
SML_MT_font["Morpheus"] = [[Fonts\MORPHEUS.TTF]] |
SML_MT_font["Skurri"] = [[Fonts\SKURRI.TTF]] |
-- |
lib.DefaultMedia.font = "Friz Quadrata TT" |
-- |
end |
-- STATUSBAR |
if not lib.MediaTable.statusbar then lib.MediaTable.statusbar = {} end |
lib.MediaTable.statusbar["Blizzard"] = [[Interface\TargetingFrame\UI-StatusBar]] |
lib.DefaultMedia.statusbar = "Blizzard" |
-- SOUND |
if not lib.MediaTable.sound then lib.MediaTable.sound = {} end |
lib.MediaTable.sound["None"] = [[Interface\Quiet.mp3]] -- Relies on the fact that PlaySound[File] doesn't error on non-existing input. |
lib.DefaultMedia.sound = "None" |
local function rebuildMediaList(mediatype) |
local mtable = mediaTable[mediatype] |
if not mtable then return end |
if not mediaList[mediatype] then mediaList[mediatype] = {} end |
local mlist = mediaList[mediatype] |
-- list can only get larger, so simply overwrite it |
local i = 0 |
for k in pairs(mtable) do |
i = i + 1 |
mlist[i] = k |
end |
table_sort(mlist) |
end |
function lib:Register(mediatype, key, data, langmask) |
if type(mediatype) ~= "string" then |
error(MAJOR..":Register(mediatype, key, data, langmask) - mediatype must be string, got "..type(mediatype)) |
end |
if type(key) ~= "string" then |
error(MAJOR..":Register(mediatype, key, data, langmask) - key must be string, got "..type(key)) |
end |
if mediatype == lib.MediaType.FONT and ((langmask and band(langmask, LOCALE_MASK) == 0) or not (langmask or locale_is_western)) then return false end |
mediatype = mediatype:lower() |
if not mediaTable[mediatype] then mediaTable[mediatype] = {} end |
local mtable = mediaTable[mediatype] |
if mtable[key] then return false end |
mtable[key] = data |
rebuildMediaList(mediatype) |
self.callbacks:Fire("LibSharedMedia_Registered", mediatype, key) |
return true |
end |
function lib:Fetch(mediatype, key, noDefault) |
local mtt = mediaTable[mediatype] |
local overridekey = overrideMedia[mediatype] |
local result = mtt and ((overridekey and mtt[overridekey] or mtt[key]) or (not noDefault and defaultMedia[mediatype] and mtt[defaultMedia[mediatype]])) or nil |
return result |
end |
function lib:IsValid(mediatype, key) |
return mediaTable[mediatype] and (not key or mediaTable[mediatype][key]) and true or false |
end |
function lib:HashTable(mediatype) |
return mediaTable[mediatype] |
end |
function lib:List(mediatype) |
if not mediaTable[mediatype] then |
return nil |
end |
if not mediaList[mediatype] then |
rebuildMediaList(mediatype) |
end |
return mediaList[mediatype] |
end |
function lib:GetGlobal(mediatype) |
return overrideMedia[mediatype] |
end |
function lib:SetGlobal(mediatype, key) |
if not mediaTable[mediatype] then |
return false |
end |
overrideMedia[mediatype] = (key and mediaTable[mediatype][key]) and key or nil |
self.callbacks:Fire("LibSharedMedia_SetGlobal", mediatype, overrideMedia[mediatype]) |
return true |
end |
function lib:GetDefault(mediatype) |
return defaultMedia[mediatype] |
end |
function lib:SetDefault(mediatype, key) |
if mediaTable[mediatype] and mediaTable[mediatype][key] and not defaultMedia[mediatype] then |
defaultMedia[mediatype] = key |
return true |
else |
return false |
end |
end |
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/ |
..\FrameXML\UI.xsd"> |
<Script file="LibSharedMedia-3.0.lua" /> |
</Ui> |