WoWInterface SVN Ara_Broker_Tradeskills

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /
    from Rev 1 to Rev 2
    Reverse comparison

Rev 1 → Rev 2

UIDropDownMenu - sample.lua.bak --- Ara_Broker_XP/trunk/Ara_Broker_XP.lua (revision 0) +++ Ara_Broker_XP/trunk/Ara_Broker_XP.lua (revision 2) @@ -0,0 +1,48 @@ +local length, char, colorXP, colorRested, colorRemaining = + 30, "||", "6060ff", "ff8040", "cccccc" + +if( UnitLevel"player" == 80 )then return end +local self = CreateFrame"Frame" +local strsub, format, floor, XP, restedXP, maxXP, frame = strsub, format, floor +local lenChar, bar = strlen(char), strrep(char, length) + +local block = LibStub("LibDataBroker-1.1"):NewDataObject("|cFFFFB366Ara|r XP", { + text = "-", + OnLeave = function() frame = nil return GameTooltip:Hide() end +}) + +local function FormatXP( value ) + local p = floor( value/maxXP*1000 +.5 ) * .1 + if( value >= 1000000 )then return format( "%i %.3i %.3i [%.2i.%.0f%%]", floor(value*0.000001), floor((value%1000000)*0.001), value%1000, p, p*10%10 ) + elseif( value >= 1000 )then return format( "%i %.3i [%.2i.%.0f%%]", floor(value*0.001), value%1000, p, p*10%10 ) + else return format( "%i [%.2i.%.0f%%]", value, p, p*10%10 ) end +end + +block.OnEnter = function(self) + frame = self + local showBelow = select( 2, self:GetCenter() ) > UIParent:GetHeight() / 2 + GameTooltip:SetOwner( self, "ANCHOR_NONE" ) + GameTooltip:SetPoint( showBelow and "TOP" or "BOTTOM", self, showBelow and "BOTTOM" or "TOP" ) + GameTooltip:AddLine( format( "Lv. %i", UnitLevel"player" ) ) + GameTooltip:AddDoubleLine( "|cff"..colorXP.."XP|r", "|cff"..colorXP..FormatXP(XP) ) + GameTooltip:AddDoubleLine( "|cff"..colorRested.."Rested|r", "|cff"..colorRested..FormatXP(restedXP) ) + GameTooltip:AddDoubleLine( "|cff"..colorRemaining.."Remaining|r", "|cff"..colorRemaining..FormatXP(maxXP-XP) ) + return GameTooltip:Show() +end + +local function OnEvent(self, event, unit) + if unit and unit ~= "player" then return end + XP, restedXP, maxXP = UnitXP"player", GetXPExhaustion() or 0, UnitXPMax"player" + local lenXP = floor( XP/maxXP *length +.5 ) + local lenRested = floor( min( XP+restedXP, maxXP ) / maxXP * length - lenXP + .5 ) + block.text = + "|cff"..colorXP ..strsub( bar, 1, lenXP*lenChar ).. + "|r|cff"..colorRested ..strsub( bar, 1, lenRested*lenChar ).. + "|r|cff"..colorRemaining..strsub( bar, 1, (length-lenXP-lenRested) * lenChar ).."|r" + if frame then return block.OnEnter(frame) end +end +self:SetScript("OnEvent", OnEvent) + +self:RegisterEvent"PLAYER_XP_UPDATE" +self:RegisterEvent"UPDATE_EXHAUSTION" +return IsLoggedIn() and OnEvent(self) or self:RegisterEvent"PLAYER_LOGIN" \ No newline at end of file
Ara_Broker_XP/trunk/Ara_Broker_XP.toc New file
0,0 → 1,15
## Interface: 30000
## Title: |cFFFFB366Ara|r - Broker - XP
## Version: r1
## Notes: A data broker plugin that displays an ASCII XP bar.
## Dependencies:
## SavedVariablesPerCharacter:
 
## LoadManagers: AddonLoader
## X-LoadOn-Always: delayed
 
libs\LibStub.lua
libs\CallbackHandler-1.0.lua
libs\LibDataBroker-1.1.lua
 
Ara_Broker_XP.lua
\ No newline at end of file
Ara_Broker_XP/trunk/libs/LibDataBroker-1.1.lua New file
0,0 → 1,66
 
assert(LibStub, "LibDataBroker-1.1 requires LibStub")
assert(LibStub:GetLibrary("CallbackHandler-1.0", true), "LibDataBroker-1.1 requires CallbackHandler-1.0")
 
local lib, oldminor = LibStub:NewLibrary("LibDataBroker-1.1", 3)
if not lib then return end
oldminor = oldminor or 0
 
 
lib.callbacks = lib.callbacks or LibStub:GetLibrary("CallbackHandler-1.0"):New(lib)
lib.attributestorage, lib.namestorage, lib.proxystorage = lib.attributestorage or {}, lib.namestorage or {}, lib.proxystorage or {}
local attributestorage, namestorage, callbacks = lib.attributestorage, lib.namestorage, lib.callbacks
 
if oldminor < 2 then
lib.domt = {
__metatable = "access denied",
__index = function(self, key) return attributestorage[self] and attributestorage[self][key] end,
}
end
 
if oldminor < 3 then
lib.domt.__newindex = function(self, key, value)
if not attributestorage[self] then attributestorage[self] = {} end
if attributestorage[self][key] == value then return end
attributestorage[self][key] = value
local name = namestorage[self]
if not name then return end
callbacks:Fire("LibDataBroker_AttributeChanged", name, key, value, self)
callbacks:Fire("LibDataBroker_AttributeChanged_"..name, name, key, value, self)
callbacks:Fire("LibDataBroker_AttributeChanged_"..name.."_"..key, name, key, value, self)
callbacks:Fire("LibDataBroker_AttributeChanged__"..key, name, key, value, self)
end
end
 
if oldminor < 2 then
function lib:NewDataObject(name, dataobj)
if self.proxystorage[name] then return end
 
if dataobj then
assert(type(dataobj) == "table", "Invalid dataobj, must be nil or a table")
self.attributestorage[dataobj] = {}
for i,v in pairs(dataobj) do
self.attributestorage[dataobj][i] = v
dataobj[i] = nil
end
end
dataobj = setmetatable(dataobj or {}, self.domt)
self.proxystorage[name], self.namestorage[dataobj] = dataobj, name
self.callbacks:Fire("LibDataBroker_DataObjectCreated", name, dataobj)
return dataobj
end
end
 
if oldminor < 1 then
function lib:DataObjectIterator()
return pairs(self.proxystorage)
end
 
function lib:GetDataObjectByName(dataobjectname)
return self.proxystorage[dataobjectname]
end
 
function lib:GetNameByDataObject(dataobject)
return self.namestorage[dataobject]
end
end
Ara_Broker_XP/trunk/libs/LibStub.lua New file
0,0 → 1,30
-- LibStub is a simple versioning stub meant for use in Libraries. http://www.wowace.com/wiki/LibStub for more info
-- LibStub is hereby placed in the Public Domain Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel, joshborke
local LIBSTUB_MAJOR, LIBSTUB_MINOR = "LibStub", 2 -- NEVER MAKE THIS AN SVN REVISION! IT NEEDS TO BE USABLE IN ALL REPOS!
local LibStub = _G[LIBSTUB_MAJOR]
 
if not LibStub or LibStub.minor < LIBSTUB_MINOR then
LibStub = LibStub or {libs = {}, minors = {} }
_G[LIBSTUB_MAJOR] = LibStub
LibStub.minor = LIBSTUB_MINOR
 
function LibStub:NewLibrary(major, minor)
assert(type(major) == "string", "Bad argument #2 to `NewLibrary' (string expected)")
minor = assert(tonumber(strmatch(minor, "%d+")), "Minor version must either be a number or contain a number.")
 
local oldminor = self.minors[major]
if oldminor and oldminor >= minor then return nil end
self.minors[major], self.libs[major] = minor, self.libs[major] or {}
return self.libs[major], oldminor
end
 
function LibStub:GetLibrary(major, silent)
if not self.libs[major] and not silent then
error(("Cannot find a library instance of %q."):format(tostring(major)), 2)
end
return self.libs[major], self.minors[major]
end
 
function LibStub:IterateLibraries() return pairs(self.libs) end
setmetatable(LibStub, { __call = LibStub.GetLibrary })
end
Ara_Broker_XP/trunk/libs/CallbackHandler-1.0.lua New file
0,0 → 1,239
--[[ $Id: CallbackHandler-1.0.lua 60697 2008-02-09 16:51:20Z nevcairiel $ ]]
local MAJOR, MINOR = "CallbackHandler-1.0", 3
local CallbackHandler = LibStub:NewLibrary(MAJOR, MINOR)
 
if not CallbackHandler then return end -- No upgrade needed
 
local meta = {__index = function(tbl, key) tbl[key] = {} return tbl[key] end}
 
local type = type
local pcall = pcall
local pairs = pairs
local assert = assert
local concat = table.concat
local loadstring = loadstring
local next = next
local select = select
local type = type
local xpcall = xpcall
 
local function errorhandler(err)
return geterrorhandler()(err)
end
 
local function CreateDispatcher(argCount)
local code = [[
local next, xpcall, eh = ...
 
local method, ARGS
local function call() method(ARGS) end
 
local function dispatch(handlers, ...)
local index
index, method = next(handlers)
if not method then return end
local OLD_ARGS = ARGS
ARGS = ...
repeat
xpcall(call, eh)
index, method = next(handlers, index)
until not method
ARGS = OLD_ARGS
end
 
return dispatch
]]
 
local ARGS, OLD_ARGS = {}, {}
for i = 1, argCount do ARGS[i], OLD_ARGS[i] = "arg"..i, "old_arg"..i end
code = code:gsub("OLD_ARGS", concat(OLD_ARGS, ", ")):gsub("ARGS", concat(ARGS, ", "))
return assert(loadstring(code, "safecall Dispatcher["..argCount.."]"))(next, xpcall, errorhandler)
end
 
local Dispatchers = setmetatable({}, {__index=function(self, argCount)
local dispatcher = CreateDispatcher(argCount)
rawset(self, argCount, dispatcher)
return dispatcher
end})
 
--------------------------------------------------------------------------
-- CallbackHandler:New
--
-- target - target object to embed public APIs in
-- RegisterName - name of the callback registration API, default "RegisterCallback"
-- UnregisterName - name of the callback unregistration API, default "UnregisterCallback"
-- UnregisterAllName - name of the API to unregister all callbacks, default "UnregisterAllCallbacks". false == don't publish this API.
 
function CallbackHandler:New(target, RegisterName, UnregisterName, UnregisterAllName, OnUsed, OnUnused)
-- TODO: Remove this after beta has gone out
assert(not OnUsed and not OnUnused, "ACE-80: OnUsed/OnUnused are deprecated. Callbacks are now done to registry.OnUsed and registry.OnUnused")
 
RegisterName = RegisterName or "RegisterCallback"
UnregisterName = UnregisterName or "UnregisterCallback"
if UnregisterAllName==nil then -- false is used to indicate "don't want this method"
UnregisterAllName = "UnregisterAllCallbacks"
end
 
-- we declare all objects and exported APIs inside this closure to quickly gain access
-- to e.g. function names, the "target" parameter, etc
 
 
-- Create the registry object
local events = setmetatable({}, meta)
local registry = { recurse=0, events=events }
 
-- registry:Fire() - fires the given event/message into the registry
function registry:Fire(eventname, ...)
if not rawget(events, eventname) or not next(events[eventname]) then return end
local oldrecurse = registry.recurse
registry.recurse = oldrecurse + 1
 
Dispatchers[select('#', ...) + 1](events[eventname], eventname, ...)
 
registry.recurse = oldrecurse
 
if registry.insertQueue and oldrecurse==0 then
-- Something in one of our callbacks wanted to register more callbacks; they got queued
for eventname,callbacks in pairs(registry.insertQueue) do
local first = not rawget(events, eventname) or not next(events[eventname]) -- test for empty before. not test for one member after. that one member may have been overwritten.
for self,func in pairs(callbacks) do
events[eventname][self] = func
-- fire OnUsed callback?
if first and registry.OnUsed then
registry.OnUsed(registry, target, eventname)
first = nil
end
end
end
registry.insertQueue = nil
end
end
 
-- Registration of a callback, handles:
-- self["method"], leads to self["method"](self, ...)
-- self with function ref, leads to functionref(...)
-- "addonId" (instead of self) with function ref, leads to functionref(...)
-- all with an optional arg, which, if present, gets passed as first argument (after self if present)
target[RegisterName] = function(self, eventname, method, ... --[[actually just a single arg]])
if type(eventname) ~= "string" then
error("Usage: "..RegisterName.."(eventname, method[, arg]): 'eventname' - string expected.", 2)
end
 
method = method or eventname
 
local first = not rawget(events, eventname) or not next(events[eventname]) -- test for empty before. not test for one member after. that one member may have been overwritten.
 
if type(method) ~= "string" and type(method) ~= "function" then
error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): 'methodname' - string or function expected.", 2)
end
 
local regfunc
 
if type(method) == "string" then
-- self["method"] calling style
if type(self) ~= "table" then
error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): self was not a table?", 2)
elseif self==target then
error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): do not use Library:"..RegisterName.."(), use your own 'self'", 2)
elseif type(self[method]) ~= "function" then
error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): 'methodname' - method '"..tostring(method).."' not found on self.", 2)
end
 
if select("#",...)>=1 then -- this is not the same as testing for arg==nil!
local arg=select(1,...)
regfunc = function(...) self[method](self,arg,...) end
else
regfunc = function(...) self[method](self,...) end
end
else
-- function ref with self=object or self="addonId"
if type(self)~="table" and type(self)~="string" then
error("Usage: "..RegisterName.."(self or \"addonId\", eventname, method): 'self or addonId': table or string expected.", 2)
end
 
if select("#",...)>=1 then -- this is not the same as testing for arg==nil!
local arg=select(1,...)
regfunc = function(...) method(arg,...) end
else
regfunc = method
end
end
 
 
if events[eventname][self] or registry.recurse<1 then
-- if registry.recurse<1 then
-- we're overwriting an existing entry, or not currently recursing. just set it.
events[eventname][self] = regfunc
-- fire OnUsed callback?
if registry.OnUsed and first then
registry.OnUsed(registry, target, eventname)
end
else
-- we're currently processing a callback in this registry, so delay the registration of this new entry!
-- yes, we're a bit wasteful on garbage, but this is a fringe case, so we're picking low implementation overhead over garbage efficiency
registry.insertQueue = registry.insertQueue or setmetatable({},meta)
registry.insertQueue[eventname][self] = regfunc
end
end
 
-- Unregister a callback
target[UnregisterName] = function(self, eventname)
if not self or self==target then
error("Usage: "..UnregisterName.."(eventname): bad 'self'", 2)
end
if type(eventname) ~= "string" then
error("Usage: "..UnregisterName.."(eventname): 'eventname' - string expected.", 2)
end
if rawget(events, eventname) and events[eventname][self] then
events[eventname][self] = nil
-- Fire OnUnused callback?
if registry.OnUnused and not next(events[eventname]) then
registry.OnUnused(registry, target, eventname)
end
end
if registry.insertQueue and rawget(registry.insertQueue, eventname) and registry.insertQueue[eventname][self] then
registry.insertQueue[eventname][self] = nil
end
end
 
-- OPTIONAL: Unregister all callbacks for given selfs/addonIds
if UnregisterAllName then
target[UnregisterAllName] = function(...)
if select("#",...)<1 then
error("Usage: "..UnregisterAllName.."([whatFor]): missing 'self' or \"addonId\" to unregister events for.", 2)
end
if select("#",...)==1 and ...==target then
error("Usage: "..UnregisterAllName.."([whatFor]): supply a meaningful 'self' or \"addonId\"", 2)
end
 
 
for i=1,select("#",...) do
local self = select(i,...)
if registry.insertQueue then
for eventname, callbacks in pairs(registry.insertQueue) do
if callbacks[self] then
callbacks[self] = nil
end
end
end
for eventname, callbacks in pairs(events) do
if callbacks[self] then
callbacks[self] = nil
-- Fire OnUnused callback?
if registry.OnUnused and not next(callbacks) then
registry.OnUnused(registry, target, eventname)
end
end
end
end
end
end
 
return registry
end
 
 
-- CallbackHandler purposefully does NOT do explicit embedding. Nor does it
-- try to upgrade old implicit embeds since the system is selfcontained and
-- relies on closures to work.
 
UIDropDownMenu - sample.lua New file
0,0 → 1,34
local dd_item = {} -- supprime la génération de garbage liée aux dropdown menus
local dd_value -- = { buff_name=nil }
 
-- fonction a passer dans le param "SecureActionButton.menu"
function MSB_ShowMenu(button)
dd_value = button.value -- passage indirecte de valeur à l'initialisation du menu
MSB_dropdown = global["MSB_DD"] or CreateFrame("Frame", "MSB_DD", UIParent, "UIDropDownMenuTemplate")
UIDropDownMenu_Initialize(MSB_dropdown, MSB_CreateMenuItems, "MENU")
UIDropDownMenu_SetAnchor(3-this:GetParent():GetWidth(),0,MSB_dropdown,"TOPRIGHT",this:GetParent():GetName(),"TOPRIGHT")
UIDropDownMenu_Refresh(this);
ToggleDropDownMenu(1, nil, MSB_dropdown) --, MSB_top_frame, 0, nb_entry*20+20 )
end
 
-- scope = menu (pas de hidden self en arg)
function MSB_CreateMenuItems(level)
if( not level ) then return end
local items = MSB:GetClassItems(buffs[dd_value].group)
for i,v in ipairs(items) do
local item_quantity = GetItemCount(v)
if( item_quantity > 0 ) then
dd_item.text = string.format( "%s [|cff60C060%d|r]", v, item_quantity )
dd_item.func = MSB_MenuItems_OnClick
dd_item.arg1 = v
dd_item.owner = this:GetParent()
UIDropDownMenu_AddButton(dd_item)
end
end
end
 
 
-- scope = menu items
function MSB_MenuItems_OnClick()
-- DEFAULT_CHAT_FRAME:AddMessage("testing menu: "..(this.arg1 or "nil"))
end
Ara_Broker_Guild_Friends/trunk/LocalizedClasses.lua New file
0,0 → 1,27
local function SetTranslations(...)
local L = {}
for i=1, select("#",...), 2 do
local k,v = select(i,...)
L[k] = v
end
_G.ABGF_TC = L
end
 
local l = GetLocale()
if l == "enUS" then
SetTranslations( "Death Knight", "DEATHKNIGHT" )
elseif l == "deDE" then
SetTranslations( "Hexenmeister", "WARLOCK", "Krieger", "WARRIOR", "J\195\164ger", "HUNTER", "Magier", "MAGE", "Priester", "PRIEST", "Druide", "DRUID", "Paladin", "PALADIN", "Schamane", "SHAMAN", "Schurke", "ROGUE", "Todesritter", "DEATHKNIGHT", "Hexenmeisterin", "WARLOCK", "Kriegerin", "WARRIOR", "J\195\164gerin", "HUNTER", "Magierin", "MAGE", "Priesterin", "PRIEST", "Druidin", "DRUID", "Paladin", "PALADIN", "Schamanin", "SHAMAN", "Schurkin", "ROGUE", "Todesritter", "DEATHKNIGHT" )
elseif l == "frFR" then
SetTranslations( "Démoniste", "WARLOCK", "Guerrier", "WARRIOR", "Chasseur", "HUNTER", "Mage", "MAGE", "Prêtre", "PRIEST", "Druide", "DRUID", "Paladin", "PALADIN", "Chaman", "SHAMAN", "Voleur", "ROGUE", "Chevalier de la mort", "DEATHKNIGHT", "Guerrière", "WARRIOR", "Chasseresse", "HUNTER", "Prêtresse", "PRIEST", "Druidesse", "DRUID", "Chamane", "SHAMAN", "Voleuse", "ROGUE" )
elseif l == "zhCN" then
SetTranslations( "术士", "WARLOCK", "战士", "WARRIOR", "猎人", "HUNTER", "法师", "MAGE", "牧师", "PRIEST", "德鲁伊", "DRUID", "圣骑士", "PALADIN", "萨满祭司", "SHAMAN", "潜行者", "ROGUE", "死亡骑士", "DEATHKNIGHT", "术士", "WARLOCK", "战士", "WARRIOR", "猎人", "HUNTER", "法师", "MAGE", "牧师", "PRIEST", "德鲁伊", "DRUID", "圣骑士", "PALADIN", "萨满祭司", "SHAMAN", "潜行者", "ROGUE", "死亡骑士", "DEATHKNIGHT" )
elseif l == "zhTW" then
SetTranslations( "術士", "WARLOCK", "戰士", "WARRIOR", "獵人", "HUNTER", "法師", "MAGE", "牧師", "PRIEST", "德魯伊", "DRUID", "聖騎士", "PALADIN", "薩滿", "SHAMAN", "盜賊", "ROGUE", "死亡騎士", "DEATHKNIGHT", "術士", "WARLOCK", "戰士", "WARRIOR", "獵人", "HUNTER", "法師", "MAGE", "牧師", "PRIEST", "德魯伊", "DRUID", "聖騎士", "PALADIN", "薩滿", "SHAMAN", "盜賊", "ROGUE", "死亡騎士", "DEATHKNIGHT" )
elseif l == "koKR" then
SetTranslations( "흑마법사", "WARLOCK", "전사", "WARRIOR", "사냥꾼", "HUNTER", "마법사", "MAGE", "사제", "PRIEST", "드루이드", "DRUID", "성기사", "PALADIN", "주술사", "SHAMAN", "도적", "ROGUE", "죽음의 기사", "DEATHKNIGHT", "흑마법사", "WARLOCK", "전사", "WARRIOR", "사냥꾼", "HUNTER", "마법사", "MAGE", "사제", "PRIEST", "드루이드", "DRUID", "성기사", "PALADIN", "주술사", "SHAMAN", "도적", "ROGUE", "죽음의 기사", "DEATHKNIGHT" )
elseif l == "esES" then
SetTranslations( "Brujo", "WARLOCK", "Guerrero", "WARRIOR", "Cazador", "HUNTER", "Mago", "MAGE", "Sacerdote", "PRIEST", "Druida", "DRUID", "Palad\195\173n", "PALADIN", "Cham\195\161n", "SHAMAN", "P\195\173caro", "ROGUE", "Bruja", "WARLOCK", "Guerrera", "WARRIOR", "Cazadora", "HUNTER", "Maga", "MAGE", "Sacerdotisa", "PRIEST", "Druida", "DRUID", "Palad\195\173n", "PALADIN", "Cham\195\161n", "SHAMAN", "P\195\173cara", "ROGUE" )
elseif l == "ruRU" then
SetTranslations( "Чернокнижник", "WARLOCK", "Воин", "WARRIOR", "Охотник", "HUNTER", "Маг", "MAGE", "Жрец", "PRIEST", "Друид", "DRUID", "Паладин", "PALADIN", "Шаман", "SHAMAN", "Разбойник", "ROGUE", "Рыцарь смерти", "DEATHKNIGHT", "Чернокнижница", "WARLOCK", "Охотница", "HUNTER", "Жрица", "PRIEST", "Шаманка", "SHAMAN", "Разбойница", "ROGUE" )
end
\ No newline at end of file
Ara_Broker_Guild_Friends/trunk/friends.tga Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Property changes : Added: svn:mime-type + application/octet-stream
Ara_Broker_Guild_Friends/trunk/Ara_Broker_Guild_Friends.lua New file
0,0 → 1,459
-- TODO: scroll large guild members
local BUTTON_HEIGHT, ICON_SIZE, GAP, TEXT_OFFSET =
15, 13, 10, 5
 
local f = CreateFrame( "Frame", "AraBrokerGuildFriends", UIParent )
local t = CreateFrame"Frame"
 
local dontShow, block, horde, config, isGuild, tip, tipShown = true
local defaultConfig = { showGuildNotes = true, showGuildName = true, sortType = "class", sortDESC = false, fontSize=12 }
local guildEntries, friendEntries = {}, {}
 
local format, strfind, strupper, GetGuildRosterInfo, GetFriendInfo, RAID_CLASS_COLORS, CLASS_BUTTONS =
format, strfind, strupper, GetGuildRosterInfo, GetFriendInfo, RAID_CLASS_COLORS, CLASS_BUTTONS
 
local L = setmetatable( _G.ABGF_TC or {}, { __index = function(t,k) return strupper(k) end } )
 
local orgReloadUI = ReloadUI
ReloadUI = function(...)
config.reloading = true
orgReloadUI(...)
end
 
local tables = {}
 
local new = function( ... )
local table = tremove(tables) or {}
for i=1, select("#",...) do table[i] = select(i,...) end
return table
end
 
local del = function( table )
tables[ #tables + 1 ] = wipe(table)
end
 
 
local friendOnline, friendOffline = gsub(ERR_FRIEND_ONLINE_SS,"\124Hplayer:%%s\124h%[%%s%]\124h",""), gsub(ERR_FRIEND_OFFLINE_S,"%%s","")
function f:CHAT_MSG_SYSTEM( event, msg )
if strfind( msg, friendOnline ) or strfind( msg, friendOffline ) then ShowFriends() end
end
 
function f:FRIENDLIST_UPDATE()
for k,v in next,friendEntries do del(v) friendEntries[k]=nil end
local total, online = GetNumFriends(), 0
for i = 1, total do
local name, level, class, zone, connected, status, note = GetFriendInfo(i)
if connected then
if online == 0 then
friendEntries[1] = new( nil, "Name", "", "Lv", "Zone", "Notes" )
end
online = online + 1
friendEntries[online+1] = new( name, status ~= "" and format("%s %s", tostring(status), tostring(name)) or name, class, level, zone or "Unknown", note and format("[%s]",note) or "-" )
end
end
f.FriendsBlock.text = format(config.hideTotalFriends and " %d" or " %d/%d", online, total)
if not isGuild and block then f:FriendsOnEnter(block) end
end
 
function f:GUILD_ROSTER_UPDATE()
dontShow = not(isGuild and block)
f.GuildOnEnter(block)
end
 
function f:PLAYER_GUILD_UPDATE(event, unit)
if unit and unit ~= "player" then return end
return IsInGuild() and GuildRoster()
end
 
local hordeZones = "Orgrimmar,Undercity,Thunder Bluff,Silvermoon City,Durotar,Tirisfal Glades,The Barrens,Silverpine Forest,Mulgore,The Sepulcher,Eversong Woods,Ghostlands,"
local allianceZones = "Ironforge,Stormwind City,Darnassus,Azuremyst Isle,Bloodmyst Isle,Darkshore,Dun Morogh,Loch Modan,Wetlands,Elwynn Forest,Redridge Mountains,Westfall,Teldrassil,Duskwood,Darshire,Thelsamar,Deeprun Tram,The Exodar,Auberdine,Menethil Harbor,Theramore Isle"
local function GetZoneColor(zone)
if strfind( hordeZones , zone.."," ) then if horde then return 0,1,0 else return 1,0,0 end end
if strfind( allianceZones, zone.."," ) then if horde then return 1,0,0 else return 0,1,0 end end
return 1,1,0
end
 
local function ShowBlockHints()
local showBelow = select(2, f:GetCenter()) > UIParent:GetHeight()/2
tip:SetOwner(f, "ANCHOR_NONE")
tip:SetPoint(showBelow and "TOP" or "BOTTOM", f, showBelow and "BOTTOM" or "TOP")
tip:AddLine"Hints [|cffffffffBlock|r]"
tip:AddLine("|cffff8020Click|r to open panel.", .2,1,.2)
tip:AddLine("|cffff8020Ctrl+Click|r to toggle hints.", .2,1,.2)
tip:AddLine("|cffff8020Shift+RightClick|r to toggle total number.", .2,1,.2)
if isGuild then
tip:AddLine("|cffff8020Shift+Click|r to toggle guild name.", .2,1,.2)
tip:AddLine("|cffff8020RightClick|r to toggle note column.", .2,1,.2)
else
tip:AddLine("|cffff8020EverythingElse|r to add a friend.", .2,1,.2)
end
tip:Show()
end
 
local function ShowHints(btn)
if not config.hideHints and btn and btn.unit then
local showBelow = select(2, f:GetCenter()) > UIParent:GetHeight()/2
tip:SetOwner(f, "ANCHOR_NONE")
tip:SetPoint(showBelow and "TOP" or "BOTTOM", f, showBelow and "BOTTOM" or "TOP")
tip:AddLine"Hints"
tip:AddLine("|cffff8020Click|r to whisper.", .2,1,.2)
tip:AddLine("|cffff8020Alt+Click|r to invite.", .2,1,.2)
tip:AddLine("|cffff8020Shift+Click|r to query guild.", .2, 1, .2)
if not isGuild or CanEditPublicNote() then tip:AddLine("|cffff8020Ctrl+Click|r to edit note.", .2, 1, .2) end
if isGuild then
if CanEditOfficerNote() then tip:AddLine("|cffff8020Ctrl+RightClick|r to edit officer note.", .2, 1, .2) end
tip:AddLine("|cffff8020RightClick|r to sort closest column.", .2, 1, .2)
else
tip:AddLine("|cffff8020MiddleClick|r to remove friend.", .2, 1, .2)
end
tip:Show()
tipShown = true
end
end
 
local highlight = f:CreateTexture()
highlight:SetTexture"Interface\\QuestFrame\\UI-QuestTitleHighlight"
highlight:SetBlendMode"ADD"
highlight:SetAlpha(0)
 
local function Menu_OnEnter(b)
if b.index then
highlight:SetAllPoints(b)
if b.index > 1 then
highlight:SetAlpha(1)
ShowHints(b)
end
end
end
 
local function Menu_OnLeave(b)
highlight:ClearAllPoints()
tip:Hide()
tipShown = false
if b.index and b.index > 1 then highlight:SetAlpha(0) end
if not MouseIsOver(f) then block = nil f:Hide() end
end
 
local function CreateFS( index, parent, justify, anchor )
local fs = parent:CreateFontString( nil, "OVERLAY", "SystemFont_Shadow_Med1" )
fs:SetJustifyH( justify )
fs:SetTextColor( 1, index == 1 and .8 or 1, 0 )
if anchor then fs:SetPoint( "LEFT", anchor, "RIGHT", GAP, 0 ) end
return fs
end
 
local buttons = setmetatable( { }, { __index = function( table, key )
local button = CreateFrame( "Button", nil, f )
table[key] = button
button.index = key
button:SetNormalFontObject(GameFontNormal)
button:RegisterForClicks"AnyUp"
button:SetHeight( BUTTON_HEIGHT )
button:SetScript( "OnEnter", Menu_OnEnter )
button:SetScript( "OnLeave", Menu_OnLeave )
button.fontName = CreateFS( key, button, "LEFT" )
if key == 0 then
button.fontName:SetJustifyV"TOP"
else
button.icon = button:CreateTexture()
button.icon:SetWidth( ICON_SIZE ) button.icon:SetHeight( ICON_SIZE )
button.icon:SetPoint( "LEFT", button, "LEFT" )
 
button.fontName:SetPoint( "LEFT", button.icon, "RIGHT", TEXT_OFFSET, 0 )
button.fontLevel = CreateFS( key, button, "CENTER", button.fontName )
button.fontZone = CreateFS( key, button, "CENTER", button.fontLevel )
button.fontNotes = CreateFS( key, button, "CENTER", button.fontZone )
button.fontRank = CreateFS( key, button, "RIGHT", button.fontNotes )
end
return button
end } )
 
local function SetButtonData( index, name, class, level, zone, notes, rank, inGroup, isGrouped )
local button = buttons[index]
button:Show()
button.fontName:SetText( name or "" )
if class then
if index > 1 then
class = isGuild and class or L[class]
local color = RAID_CLASS_COLORS[class]
if color then
button.fontName:SetTextColor( color.r, color.g, color.b )
if inGroup then
button.icon:SetTexture(isGrouped and "Interface\\Buttons\\UI-CheckBox-Check" or "")
button.icon:SetTexCoord(.15,.85,.15,.85)
else
local classIcon = CLASS_BUTTONS[class]
button.icon:SetTexture"Interface\\Glues\\CharacterCreate\\UI-CharacterCreate-Classes"
local offset, left, right, bottom, top = 0.025, unpack( classIcon )
button.icon:SetTexCoord( left+offset, right-offset, bottom+offset, top-offset )
end
else
button.fontName:SetTextColor( 1,1,0 )
button.icon:SetTexture""
end
color = GetDifficultyColor(level)
button.fontLevel:SetTextColor( color.r, color.g, color.b )
button.fontZone:SetTextColor( GetZoneColor(zone or "#") )
end
button.fontLevel:SetText( level or "" )
button.fontZone:SetText( zone or "" )
button.fontNotes:SetText( notes or "" )
button.fontRank:SetText( rank or "" )
return button, button.fontName:GetStringWidth(), button.fontLevel:GetStringWidth(), button.fontZone:GetStringWidth(), button.fontNotes:GetStringWidth(), button.fontRank:GetStringWidth()
end
return button, button.fontName:GetStringWidth()
end
 
local function EditMOTD()
f:Hide()
block = nil
GuildMOTDEditButton:Click()
end
 
local cols, colspace = { "class", "name", "level", "zone", "note", "rank" }, { ICON_SIZE }
 
local function OnGuildmateClick( self, button )
if not( self and self.unit ) then return end
if isGuild and button ~= "LeftButton" and not IsModifierKeyDown() then -- sort columns
local prevDist = GetCursorPosition() / self:GetEffectiveScale() - self:GetLeft()
local colpos, dist = colspace[1] - prevDist
for i=2, #colspace do
colpos = colpos + colspace[i] + (i==2 and TEXT_OFFSET or GAP)
dist = abs( colpos - colspace[i]*.5 )
if dist > prevDist then dist, prevDist = i-1, -1 break else prevDist = dist end
end
colpos = prevDist < 0 and dist or #colspace
colpos = not config.showGuildNotes and colpos == 5 and "rank" or cols[colpos]
if config.sortType == colpos then
config.sortDESC = not config.sortDESC
else
config.sortType, config.sortDESC = colpos, false
end
SortGuildRoster( colpos )
elseif button == "MiddleButton" and not isGuild then
RemoveFriend( self.unit ) -- ADDED (TEST)
elseif IsAltKeyDown() then
InviteUnit( self.unit )
elseif IsControlKeyDown() then
if not isGuild then
FriendsFrame.NotesID = self.index - 1
StaticPopup_Show( "SET_FRIENDNOTE", self.unit )
elseif button == "LeftButton" and CanEditPublicNote() or button ~= "LeftButton" and CanEditOfficerNote() then
SetGuildRosterSelection( guildEntries[self.index][8] )
StaticPopup_Show( button == "LeftButton" and "SET_GUILDPLAYERNOTE" or "SET_GUILDOFFICERNOTE" )
end
else
SetItemRef("player:"..self.unit, "|Hplayer:"..self.unit.."|h["..self.unit.."]|h", "LeftButton")
end
end
 
local function ShowTablet( self, _isGuild, entries )
f:Show()
isGuild = _isGuild
block = block or self
local hasEntries = #entries > 0
if not hasEntries then
entries[1] = new( nil, isGuild and ERR_GUILD_PLAYER_NOT_IN_GUILD or "No friends online.", "" )
end
 
local offsetEntries, button = isGuild and hasEntries and 1 or 0
local nameC, levelC, zoneC, notesC, rankC = 0, 0, 0, 0, 0
local nameW, levelW, zoneW, notesW, rankW
local hideNotes = isGuild and not config.showGuildNotes
 
local extraHeight, motd = 0
if isGuild and hasEntries then
motd, extraHeight = SetButtonData( 0, "|cffffffffMOTD:|r "..GetGuildRosterMOTD() )
if CanEditMOTD() then motd:SetScript( "OnClick", EditMOTD ) end
motd.fontName:ClearAllPoints()
end
 
local isGrouped = GetNumRaidMembers()>0 and UnitInRaid or GetNumPartyMembers()>0 and UnitInParty or nil
for i, entry in ipairs(entries) do
button, nameW, levelW, zoneW, notesW, rankW = SetButtonData( i, entry[2], entry[3], entry[4], entry[5], entry[6], entry[7], isGrouped, isGrouped and entry[1] and isGrouped(entry[1]), isGrouped ) --MOD
button.unit = entry[1]
button:SetScript( "OnClick", OnGuildmateClick )
if nameW > nameC then nameC = nameW end
if levelW and levelW>0 then
if levelW > levelC then levelC = levelW end
if zoneW > zoneC then zoneC = zoneW end
if notesW > notesC then notesC = notesW end
if rankW > rankC then rankC = rankW end
if hideNotes then button.fontNotes:Hide() else button.fontNotes:Show() end
button.fontRank:SetPoint( "LEFT", hideNotes and button.fontZone or button.fontNotes, "RIGHT", GAP, 0 )
end
end
 
if hideNotes then notesC = -GAP end
local maxWidth = ICON_SIZE + TEXT_OFFSET + nameC + levelC + zoneC + notesC + rankC + GAP * (isGuild and 4 or 3)
extraHeight = ceil( extraHeight / maxWidth )
 
if isGuild and hasEntries then
motd = buttons[0]
motd:SetWidth( maxWidth )
motd:SetPoint( "TOPLEFT", f, "TOPLEFT", GAP, -GAP )
motd:SetHeight( (extraHeight+1) * BUTTON_HEIGHT )
motd.fontName:SetAllPoints(motd)
buttons[1]:SetPoint( "TOPLEFT", motd, "BOTTOMLEFT" )
elseif rawget( buttons, 0 ) then
buttons[0]:Hide()
end
 
for i=1, #entries do
button = buttons[i]
button:SetWidth( maxWidth )
if not isGuild or i>1 or not hasEntries then button:SetPoint( "TOPLEFT", f, "TOPLEFT", GAP, (1-i-extraHeight-offsetEntries) * BUTTON_HEIGHT - GAP ) end
button.fontName:SetWidth(nameC)
button.fontLevel:SetWidth(levelC)
button.fontZone:SetWidth(zoneC)
button.fontNotes:SetWidth(notesC)
button.fontRank:SetWidth(rankC)
end
colspace[2], colspace[3], colspace[4], colspace[5], colspace[6] = nameC, levelC, zoneC, notesC, rankC
 
f:SetWidth( maxWidth + GAP*2 )
f:SetHeight( BUTTON_HEIGHT * (#entries+offsetEntries+extraHeight) + GAP*2 )
 
Menu_OnEnter(self)
local showBelow = select( 2, block:GetCenter() ) > ( UIParent:GetHeight() / 2 )
f:ClearAllPoints()
f:SetPoint( showBelow and "TOP" or "BOTTOM", block, showBelow and "BOTTOM" or "TOP" )
for i=#entries+1, #buttons do buttons[i]:Hide() end
if not (tipShown or config.hideHints) then ShowBlockHints() end
end
 
 
function f:FriendsOnEnter()
if InCombatLockdown() then f:Show() return Menu_OnEnter(f) end
return ShowTablet( self, false, friendEntries )
end
 
function f:GuildOnEnter()
if not dontShow and InCombatLockdown() then f:Show() return Menu_OnEnter(f) end
for k, v in next, guildEntries do del(v) guildEntries[k]=nil end
for i=1, GetNumGuildMembers(true) do
local name, rank, _, level, _, zone, note, offnote, connected, status, class = GetGuildRosterInfo(i)
if connected then
if #guildEntries == 0 then
guildEntries[1] = new( nil, "Name", "", "Lv", "Zone", "Notes", "Rank" )
end
local notes = note ~= "" and (offnote ~= "" and
format( "[%s] - \124cffff9944[%s]\124r", note, offnote ) or
format( "[%s]", note )) or (offnote ~= "" and
format( "\124cffff9944[%s]\124r", offnote ) or "-")
guildEntries[#guildEntries+1] = new( name, status == "" and name or format( "%s %s", status, name ), class, level, zone, notes, rank, i )
end
end
f.GuildBlock.text = IsInGuild() and format(config.hideGuildTotal and" %s%d"or" %s%d/%d", config.showGuildName and GetGuildInfo"player" and GetGuildInfo"player"..": " or "", #guildEntries-1, GetNumGuildMembers(true) ) or "No Guild"
if dontShow then dontShow = false else return ShowTablet(self, true, guildEntries) end
end
 
 
local ldb = LibStub("LibDataBroker-1.1")
 
f.GuildBlock = ldb:NewDataObject( "|cFFFFB366Ara|r Guild", {
type = "data source",
text = GUILD,
icon = "Interface\\AddOns\\Ara_Broker_Guild_Friends\\guild.tga",
OnEnter = f.GuildOnEnter,
OnLeave = Menu_OnLeave,
OnClick = function(self, button)
if button == "LeftButton" then
if IsShiftKeyDown() and IsInGuild() then
config.showGuildName = not config.showGuildName
f.GuildBlock.text = format( " %s%d/%d", config.showGuildName and GetGuildInfo"player"..": " or "", #guildEntries-1, GetNumGuildMembers(true) )
elseif IsControlKeyDown() then
config.hideHints = not config.hideHints
ShowTablet( block, isGuild, isGuild and guildEntries or friendEntries )
else ToggleFriendsFrame(3) end
elseif button == "RightButton" and IsShiftKeyDown() then
config.hideGuildTotal = not config.hideGuildTotal
f:GuildOnEnter()
elseif not InCombatLockdown() then
config.showGuildNotes = not config.showGuildNotes
ShowTablet( block, true, guildEntries )
end
end,
} )
 
f.FriendsBlock = ldb:NewDataObject( "|cFFFFB366Ara|r Friends", {
type = "data source",
text = FRIENDS,
icon = "Interface\\AddOns\\Ara_Broker_Guild_Friends\\friends.tga",
OnEnter = f.FriendsOnEnter,
OnLeave = Menu_OnLeave,
OnClick = function(self, btn)
if IsControlKeyDown() then
config.hideHints = not config.hideHints
ShowTablet( block, isGuild, isGuild and guildEntries or friendEntries )
elseif IsShiftKeyDown() then
config.hideTotalFriends = not config.hideTotalFriends
f:FRIENDLIST_UPDATE()
elseif IsModifierKeyDown() or btn~="LeftButton" then
StaticPopup_Show"ADD_FRIEND"
else
ToggleFriendsFrame(1)
end
end,
} )
 
local orgGuildRoster = GuildRoster
GuildRoster = function(...)
t.guildTimer = 0
return orgGuildRoster(...)
end
 
local orgShowFriends = ShowFriends
ShowFriends = function(...)
t.friendTimer = 0
return orgShowFriends(...)
end
 
local function OnUpdate( self, elapsed )
t.guildTimer = t.guildTimer + elapsed
if t.guildTimer > 15 then
if IsInGuild() then GuildRoster() else t.guildTimer = 0 end
end
t.friendTimer = t.friendTimer + elapsed
if t.friendTimer > 15 then ShowFriends() end
end
 
function f:ADDON_LOADED( event, addon )
if addon ~= "Ara_Broker_Guild_Friends" then return else self:UnregisterEvent(event) end
AraBrokerGuildFriendsDB = AraBrokerGuildFriendsDB or defaultConfig
config = AraBrokerGuildFriendsDB
for k, v in next, defaultConfig do if config[k]==nil then config[k]=v end end
if config.reloading then config.reloading = nil else SortGuildRoster(config.sortType) if config.sortDESC then SortGuildRoster(config.sortType) end end
 
tip = _G.GameTooltip
horde = UnitFactionGroup"player" == "Horde"
if _G.Skinner then
_G.Skinner:applySkin(self)
else
f:SetBackdrop( { bgFile="Interface\\Buttons\\WHITE8X8", edgeFile="Interface\\Tooltips\\UI-Tooltip-Border",
tile=true, tileSize=12, edgeSize=12, insets = { left=2, right=2, top=2, bottom=2 } } )
f:SetBackdropColor( 0, 0, 0, .75 )
end
f.red, f.green, f.blue, f.alpha = f:GetBackdropColor()
f:SetFrameStrata"TOOLTIP"
f:SetClampedToScreen(true)
f:EnableMouse(true)
 
t:SetScript( "OnUpdate", OnUpdate )
f:SetScript( "OnEnter", Menu_OnEnter )
f:SetScript( "OnLeave", Menu_OnLeave )
 
f:RegisterEvent"GUILD_ROSTER_UPDATE"
f:RegisterEvent"PLAYER_GUILD_UPDATE"
f:RegisterEvent"FRIENDLIST_UPDATE"
f:RegisterEvent"CHAT_MSG_SYSTEM"
 
ShowFriends() t.friendTimer = 0
if IsInGuild() then GuildRoster() else t.guildTimer = 0 end
f:GuildOnEnter()
f.ADDON_LOADED = nil
end
 
f:RegisterEvent"ADDON_LOADED"
f:SetScript( "OnEvent", function(self, event, ...) return self[event](self, event, ...) end )
f:SetScript( "OnShow", function(self) f:SetBackdropColor( InCombatLockdown() and f.red+.25 or f.red, f.green, f.blue, f.alpha) end )
\ No newline at end of file
Ara_Broker_Guild_Friends/trunk/Ara_Broker_Guild_Friends.toc New file
0,0 → 1,18
## Interface: 30000
## Title: |cFFFFB366Ara|r - Broker - Guild & Friends
## Version: r17
## Author: Ara
## Notes: A Data Broker plugin that provides guildmates & friends informations and interactions.
## SavedVariables: AraBrokerGuildFriendsDB
## OptionalDeps: SharedMedia, Skinner
## X-Credits: Tekkub (picoGuild)
 
## LoadManagers: AddonLoader
## X-LoadOn-Always: delayed
 
libs\LibStub.lua
libs\CallbackHandler-1.0.lua
libs\LibDataBroker-1.1.lua
 
LocalizedClasses.lua
Ara_Broker_Guild_Friends.lua
\ No newline at end of file
Ara_Broker_Guild_Friends/trunk/libs/LibDataBroker-1.1.lua New file
0,0 → 1,66
 
assert(LibStub, "LibDataBroker-1.1 requires LibStub")
assert(LibStub:GetLibrary("CallbackHandler-1.0", true), "LibDataBroker-1.1 requires CallbackHandler-1.0")
 
local lib, oldminor = LibStub:NewLibrary("LibDataBroker-1.1", 3)
if not lib then return end
oldminor = oldminor or 0
 
 
lib.callbacks = lib.callbacks or LibStub:GetLibrary("CallbackHandler-1.0"):New(lib)
lib.attributestorage, lib.namestorage, lib.proxystorage = lib.attributestorage or {}, lib.namestorage or {}, lib.proxystorage or {}
local attributestorage, namestorage, callbacks = lib.attributestorage, lib.namestorage, lib.callbacks
 
if oldminor < 2 then
lib.domt = {
__metatable = "access denied",
__index = function(self, key) return attributestorage[self] and attributestorage[self][key] end,
}
end
 
if oldminor < 3 then
lib.domt.__newindex = function(self, key, value)
if not attributestorage[self] then attributestorage[self] = {} end
if attributestorage[self][key] == value then return end
attributestorage[self][key] = value
local name = namestorage[self]
if not name then return end
callbacks:Fire("LibDataBroker_AttributeChanged", name, key, value, self)
callbacks:Fire("LibDataBroker_AttributeChanged_"..name, name, key, value, self)
callbacks:Fire("LibDataBroker_AttributeChanged_"..name.."_"..key, name, key, value, self)
callbacks:Fire("LibDataBroker_AttributeChanged__"..key, name, key, value, self)
end
end
 
if oldminor < 2 then
function lib:NewDataObject(name, dataobj)
if self.proxystorage[name] then return end
 
if dataobj then
assert(type(dataobj) == "table", "Invalid dataobj, must be nil or a table")
self.attributestorage[dataobj] = {}
for i,v in pairs(dataobj) do
self.attributestorage[dataobj][i] = v
dataobj[i] = nil
end
end
dataobj = setmetatable(dataobj or {}, self.domt)
self.proxystorage[name], self.namestorage[dataobj] = dataobj, name
self.callbacks:Fire("LibDataBroker_DataObjectCreated", name, dataobj)
return dataobj
end
end
 
if oldminor < 1 then
function lib:DataObjectIterator()
return pairs(self.proxystorage)
end
 
function lib:GetDataObjectByName(dataobjectname)
return self.proxystorage[dataobjectname]
end
 
function lib:GetNameByDataObject(dataobject)
return self.namestorage[dataobject]
end
end
Ara_Broker_Guild_Friends/trunk/libs/LibStub.lua New file
0,0 → 1,30
-- LibStub is a simple versioning stub meant for use in Libraries. http://www.wowace.com/wiki/LibStub for more info
-- LibStub is hereby placed in the Public Domain Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel, joshborke
local LIBSTUB_MAJOR, LIBSTUB_MINOR = "LibStub", 2 -- NEVER MAKE THIS AN SVN REVISION! IT NEEDS TO BE USABLE IN ALL REPOS!
local LibStub = _G[LIBSTUB_MAJOR]
 
if not LibStub or LibStub.minor < LIBSTUB_MINOR then
LibStub = LibStub or {libs = {}, minors = {} }
_G[LIBSTUB_MAJOR] = LibStub
LibStub.minor = LIBSTUB_MINOR
 
function LibStub:NewLibrary(major, minor)
assert(type(major) == "string", "Bad argument #2 to `NewLibrary' (string expected)")
minor = assert(tonumber(strmatch(minor, "%d+")), "Minor version must either be a number or contain a number.")
 
local oldminor = self.minors[major]
if oldminor and oldminor >= minor then return nil end
self.minors[major], self.libs[major] = minor, self.libs[major] or {}
return self.libs[major], oldminor
end
 
function LibStub:GetLibrary(major, silent)
if not self.libs[major] and not silent then
error(("Cannot find a library instance of %q."):format(tostring(major)), 2)
end
return self.libs[major], self.minors[major]
end
 
function LibStub:IterateLibraries() return pairs(self.libs) end
setmetatable(LibStub, { __call = LibStub.GetLibrary })
end
Ara_Broker_Guild_Friends/trunk/libs/CallbackHandler-1.0.lua New file
0,0 → 1,239
--[[ $Id: CallbackHandler-1.0.lua 60697 2008-02-09 16:51:20Z nevcairiel $ ]]
local MAJOR, MINOR = "CallbackHandler-1.0", 3
local CallbackHandler = LibStub:NewLibrary(MAJOR, MINOR)
 
if not CallbackHandler then return end -- No upgrade needed
 
local meta = {__index = function(tbl, key) tbl[key] = {} return tbl[key] end}
 
local type = type
local pcall = pcall
local pairs = pairs
local assert = assert
local concat = table.concat
local loadstring = loadstring
local next = next
local select = select
local type = type
local xpcall = xpcall
 
local function errorhandler(err)
return geterrorhandler()(err)
end
 
local function CreateDispatcher(argCount)
local code = [[
local next, xpcall, eh = ...
 
local method, ARGS
local function call() method(ARGS) end
 
local function dispatch(handlers, ...)
local index
index, method = next(handlers)
if not method then return end
local OLD_ARGS = ARGS
ARGS = ...
repeat
xpcall(call, eh)
index, method = next(handlers, index)
until not method
ARGS = OLD_ARGS
end
 
return dispatch
]]
 
local ARGS, OLD_ARGS = {}, {}
for i = 1, argCount do ARGS[i], OLD_ARGS[i] = "arg"..i, "old_arg"..i end
code = code:gsub("OLD_ARGS", concat(OLD_ARGS, ", ")):gsub("ARGS", concat(ARGS, ", "))
return assert(loadstring(code, "safecall Dispatcher["..argCount.."]"))(next, xpcall, errorhandler)
end
 
local Dispatchers = setmetatable({}, {__index=function(self, argCount)
local dispatcher = CreateDispatcher(argCount)
rawset(self, argCount, dispatcher)
return dispatcher
end})
 
--------------------------------------------------------------------------
-- CallbackHandler:New
--
-- target - target object to embed public APIs in
-- RegisterName - name of the callback registration API, default "RegisterCallback"
-- UnregisterName - name of the callback unregistration API, default "UnregisterCallback"
-- UnregisterAllName - name of the API to unregister all callbacks, default "UnregisterAllCallbacks". false == don't publish this API.
 
function CallbackHandler:New(target, RegisterName, UnregisterName, UnregisterAllName, OnUsed, OnUnused)
-- TODO: Remove this after beta has gone out
assert(not OnUsed and not OnUnused, "ACE-80: OnUsed/OnUnused are deprecated. Callbacks are now done to registry.OnUsed and registry.OnUnused")
 
RegisterName = RegisterName or "RegisterCallback"
UnregisterName = UnregisterName or "UnregisterCallback"
if UnregisterAllName==nil then -- false is used to indicate "don't want this method"
UnregisterAllName = "UnregisterAllCallbacks"
end
 
-- we declare all objects and exported APIs inside this closure to quickly gain access
-- to e.g. function names, the "target" parameter, etc
 
 
-- Create the registry object
local events = setmetatable({}, meta)
local registry = { recurse=0, events=events }
 
-- registry:Fire() - fires the given event/message into the registry
function registry:Fire(eventname, ...)
if not rawget(events, eventname) or not next(events[eventname]) then return end
local oldrecurse = registry.recurse
registry.recurse = oldrecurse + 1
 
Dispatchers[select('#', ...) + 1](events[eventname], eventname, ...)
 
registry.recurse = oldrecurse
 
if registry.insertQueue and oldrecurse==0 then
-- Something in one of our callbacks wanted to register more callbacks; they got queued
for eventname,callbacks in pairs(registry.insertQueue) do
local first = not rawget(events, eventname) or not next(events[eventname]) -- test for empty before. not test for one member after. that one member may have been overwritten.
for self,func in pairs(callbacks) do
events[eventname][self] = func
-- fire OnUsed callback?
if first and registry.OnUsed then
registry.OnUsed(registry, target, eventname)
first = nil
end
end
end
registry.insertQueue = nil
end
end
 
-- Registration of a callback, handles:
-- self["method"], leads to self["method"](self, ...)
-- self with function ref, leads to functionref(...)
-- "addonId" (instead of self) with function ref, leads to functionref(...)
-- all with an optional arg, which, if present, gets passed as first argument (after self if present)
target[RegisterName] = function(self, eventname, method, ... --[[actually just a single arg]])
if type(eventname) ~= "string" then
error("Usage: "..RegisterName.."(eventname, method[, arg]): 'eventname' - string expected.", 2)
end
 
method = method or eventname
 
local first = not rawget(events, eventname) or not next(events[eventname]) -- test for empty before. not test for one member after. that one member may have been overwritten.
 
if type(method) ~= "string" and type(method) ~= "function" then
error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): 'methodname' - string or function expected.", 2)
end
 
local regfunc
 
if type(method) == "string" then
-- self["method"] calling style
if type(self) ~= "table" then
error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): self was not a table?", 2)
elseif self==target then
error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): do not use Library:"..RegisterName.."(), use your own 'self'", 2)
elseif type(self[method]) ~= "function" then
error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): 'methodname' - method '"..tostring(method).."' not found on self.", 2)
end
 
if select("#",...)>=1 then -- this is not the same as testing for arg==nil!
local arg=select(1,...)
regfunc = function(...) self[method](self,arg,...) end
else
regfunc = function(...) self[method](self,...) end
end
else
-- function ref with self=object or self="addonId"
if type(self)~="table" and type(self)~="string" then
error("Usage: "..RegisterName.."(self or \"addonId\", eventname, method): 'self or addonId': table or string expected.", 2)
end
 
if select("#",...)>=1 then -- this is not the same as testing for arg==nil!
local arg=select(1,...)
regfunc = function(...) method(arg,...) end
else
regfunc = method
end
end
 
 
if events[eventname][self] or registry.recurse<1 then
-- if registry.recurse<1 then
-- we're overwriting an existing entry, or not currently recursing. just set it.
events[eventname][self] = regfunc
-- fire OnUsed callback?
if registry.OnUsed and first then
registry.OnUsed(registry, target, eventname)
end
else
-- we're currently processing a callback in this registry, so delay the registration of this new entry!
-- yes, we're a bit wasteful on garbage, but this is a fringe case, so we're picking low implementation overhead over garbage efficiency
registry.insertQueue = registry.insertQueue or setmetatable({},meta)
registry.insertQueue[eventname][self] = regfunc
end
end
 
-- Unregister a callback
target[UnregisterName] = function(self, eventname)
if not self or self==target then
error("Usage: "..UnregisterName.."(eventname): bad 'self'", 2)
end
if type(eventname) ~= "string" then
error("Usage: "..UnregisterName.."(eventname): 'eventname' - string expected.", 2)
end
if rawget(events, eventname) and events[eventname][self] then
events[eventname][self] = nil
-- Fire OnUnused callback?
if registry.OnUnused and not next(events[eventname]) then
registry.OnUnused(registry, target, eventname)
end
end
if registry.insertQueue and rawget(registry.insertQueue, eventname) and registry.insertQueue[eventname][self] then
registry.insertQueue[eventname][self] = nil
end
end
 
-- OPTIONAL: Unregister all callbacks for given selfs/addonIds
if UnregisterAllName then
target[UnregisterAllName] = function(...)
if select("#",...)<1 then
error("Usage: "..UnregisterAllName.."([whatFor]): missing 'self' or \"addonId\" to unregister events for.", 2)
end
if select("#",...)==1 and ...==target then
error("Usage: "..UnregisterAllName.."([whatFor]): supply a meaningful 'self' or \"addonId\"", 2)
end
 
 
for i=1,select("#",...) do
local self = select(i,...)
if registry.insertQueue then
for eventname, callbacks in pairs(registry.insertQueue) do
if callbacks[self] then
callbacks[self] = nil
end
end
end
for eventname, callbacks in pairs(events) do
if callbacks[self] then
callbacks[self] = nil
-- Fire OnUnused callback?
if registry.OnUnused and not next(callbacks) then
registry.OnUnused(registry, target, eventname)
end
end
end
end
end
end
 
return registry
end
 
 
-- CallbackHandler purposefully does NOT do explicit embedding. Nor does it
-- try to upgrade old implicit embeds since the system is selfcontained and
-- relies on closures to work.
 
Ara_Broker_Guild_Friends/trunk/guild.tga Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Property changes : Added: svn:mime-type + application/octet-stream
Ara_Dotimer/trunk/Ara_Dotimer.lua New file
0,0 → 1,684
--[[ TODO
- when saving pos do a "SetUserPlaced(nil)" to avoid scaling problems at load time.
- meta for name/icon/rank should be handled to account for proper rank.
- dontFade/vanish attribute to zap some fade effect
]]
 
local _, playerClass = UnitClass"player"
local spells = {}
 
 
local mt = { __index = function(t,k)
if k == "hasGlyph" then -- on glyph change: if spell.glyphID then spell.hasGlyph = nil end
for i=1, GetNumGlyphSockets() do
if select( 3, GetGlyphSocketInfo(i) ) == t.glyphID then t[k] = true return true end
end
t[k] = false
return false
elseif k == "hasTalent" then -- on talent change: if spell.talentTree then spell.hasTalent = nil end
local rank = select( 5, GetTalentInfo( t.talentTree, t.talentIndex ) )
if rank > 0 then t[k], t.talentRank = true, rank return true end
t[k] = false
return false
elseif k == "name" or k == "icon" or k == "rank" then
t.name, t.rank, t.icon = GetSpellInfo( t.id ) -- UnitDebuff(unit,t.name,t.rank)
return t[k]
end
end }
 
 
local function AddSpells( ... )
local spell
for i=1, select( "#", ... ) do
local obj, id = select( i, ... )
if type(obj) == "table" then
obj.id = id
if not obj.glyphID then obj.hasGlyph = false end
if not obj.talentTree then obj.hasTalent = false end
spell = setmetatable( obj, mt )
else
spells[obj] = spell
end
end
end
 
if playerClass == "WARLOCK" then
 
local CURSE = 1
AddSpells(
--[[ Aftermath ]] { timer = 5, dontFade=true }, 18118,
--[[ Banish ]] { timer = 20, dontFade=true, glyphID=56242, glyphAdd=5 }, 710,
{ timer = 30, dontFade=true, glyphID=56242, glyphAdd=5 }, 18647,
--[[ Corruption ]] { timer = 12 }, 172,
{ timer = 15 }, 6222,
{ timer = 18 }, 6223, 7648, 11671, 11672, 25311, 27216, 47812, 47813,
--[[ Curse of Agony ]] { timer = 24, group=CURSE, glyphID=56241, glyphAdd=4 }, 980, 1014, 6217, 11711, 11712, 11713, 27218, 47863, 47864,
--[[ Curse of Doom ]] { timer = 60, group=CURSE }, 603, 30910, 47867,
--[[ Curse of Elem. ]] { timer = 300, dr=true, group=CURSE }, 1490, 11721, 11722, 27228, 47865,
--[[ Curse of Exhau. ]] { timer = 12, group=CURSE }, 18223,
--[[ Curse of Reck. ]] { timer = 120, group=CURSE }, 704, 7658, 7659, 11717, 27226, 57595,
--[[ Curse of Tongue ]] { timer = 30, dr=true, group=CURSE, pvpTimer=12 }, 1714, 11719, -- TOCHANGE
--[[ Curse of Weak. ]] { timer = 120, group=CURSE }, 702, 1108, 6205, 7646, 11707, 11708, 27224, 30909, 50511,
--[[ Enslave Demon ]] { timer = 300, dontFade=true }, 1098, 11725, 11726,
--[[ Fear ]] { timer = 10, dr=true }, 5782,
{ timer = 15, dr=true }, 6213,
{ timer = 20, dr=true }, 6215,
--[[ Haunt ]] { timer = 12 }, 48181, 59161, 59163, 59164,
--[[ Howl of Terror ]] { timer = 6, dr=true }, 5484,
{ timer = 8, dr=true }, 17928,
--[[ Immolate ]] { timer = 15 }, 348, 707, 1094, 2941, 11665, 11667, 11668, 25309, 27215, 47810, 47811,
--[[ Shadow Embrace ]] { timer = 12, dontFade=true }, 32390, 32391, 32392, 32393, 32394,
--[[*Shadowburn ]] { timer = 5, dontFade=true }, 29341,
--[[ Shadowfury ]] { timer = 3, dontFade=true, dr=true }, 30283, 30413, 30414, 47846, 47847,
--[[ Siphon Life ]] { timer = 30 }, 18265, 18879, 18880, 18881, 27264, 30911, 47861, 47862,
--[[ Succubus: Seduce]] { timer = 15, dr=true, glyphID=56250, glyphAdd=3, talentTree=2, talentIndex=7, talentMul=0.1 }, 6358,
--[[ Unstable Affli. ]] { timer = 15 }, 30108, 30404, 30405, 47841, 47843
)
 
elseif playerClass == "DRUID" then
 
AddSpells(
--[[ Animal Soothe ]] { timer = 15, dontFade=true }, 2908, 8955, 9901, 26995,
--[[ Bash ]] { timer = 2, dontFade=true, dr=true, talentTree=2, talentIndex=13, talentAdd=.5 }, 5211,
{ timer = 3, dontFade=true, dr=true, talentTree=2, talentIndex=13, talentAdd=.5 }, 6798,
{ timer = 4, dontFade=true, dr=true, talentTree=2, talentIndex=13, talentAdd=.5 }, 8983,
--[[ Cyclone ]] { timer = 6, dontFade=true, dr=true }, 33786, -- Cyclone
--[[ Demoraliz.Roar ]] { timer = 30 }, 99, 1735, 9490, 9747, 9898, 26998,
--[[ Faerie Fire ]] { timer = 40 }, 770, 778, 9749, 9907, 26993, 48476, --[[Feral]] 16857, 17390, 17391, 17392, 27011, 48475,
--[[ Feral Charge ]] { timer = 4, dontFade=true, dr=true }, 16979, -- immobilize effect
--[[ Hibernate ]] { timer = 20, dr=true }, 2637,
{ timer = 30, dr=true }, 18657,
{ timer = 40, dr=true }, 18658,
--[[ Insect Swarm ]] { timer = 12, talentTree=1, talentIndex=8, talentAdd=2 }, 5570, 24974, 24975, 24976, 24977, 27013, 48468,
--[[ Lacerate ]] { timer = 15 }, 33745, 48567, 48568,
--[[ Mangle ]] { timer = 12, glyphID=54813, glyphAdd=6 }, 33878, --[[Bear]] 33986, 33987, 48563, 48564, --[[Cat]] 33876, 33982, 33983, 48565, 48566,
--[[ Moonfire ]] { timer = 9, talentTree=1, talentIndex=8, talentAdd=3 }, 8921,
{ timer = 12, talentTree=1, talentIndex=8, talentAdd=3 }, 8924, 8925, 8926, 8927, 8928, 8929, 9833, 9834, 9835, 26987, 26988, 48462, 48463,
--[[ Pounce (stun) ]] { timer = 4, dontFade=true, dr=true, talentTree=2, talentIndex=13, talentAdd=.5 }, 9005, 9823, 9827, 27006, 49803, -- Pounce (stun part) + talent
--[[ Pounce (bleed) ]] { timer = 18 }, 9007, 9824, 9826, 27007, 49804, -- Pounce Bleed (dot part)
--[[ Rake ]] { timer = 9 }, 1822, 1823, 1824, 9904, 27003,
--[[ Rip ]] { timer = 12, glyphID=54818, glyphAdd=4 }, 1079, 9492, 9493, 9752, 9894, 9896, 27008, 49799, 49800,
--[[ Roots ]] { timer = 12, dontFade=true, dr=true }, 339,
{ timer = 15, dontFade=true, dr=true }, 1062,
{ timer = 18, dontFade=true, dr=true }, 5195,
{ timer = 21, dontFade=true, dr=true }, 5196,
{ timer = 24, dontFade=true, dr=true }, 9852,
{ timer = 27, dontFade=true, dr=true }, 9853, 26989, 53308,
--[[ Starfire ]] { timer = 3, dontFade=true }, 16922 -- Starfire Stun (EFFECT)
-- TODO: Natural Perfection,
)
 
elseif playerClass == "DEATHKNIGHT" then
 
AddSpells(
--[[ Chains of Ice ]] { timer = 10, dontFade=true, }, 47805,
--[[ Death Grip { timer = 3 }, 49560, --]]
--[[ Ebon Plague ]]-- { timer = 12, talentTree=3, talentIndex=4, talentAdd=3 }, ,
--[[ Hungering Cold ]] { timer = 10, dontFade=true }, 51209,
--[[ Icy Touch ]] { timer = 12, talentTree=3, talentIndex=4, talentAdd=3 }, 55095, -- Frost Fever (Icy Touch) ]]
--[[*Mind Freeze ]] { timer = 4, dontFade=true, SPELL_INTERRUPT=true }, 47528, -- Mind Freeze (SPELL_INTERRUPT)
--[[ Plague Strike ]] { timer = 12, talentTree=3, talentIndex=4, talentAdd=3 }, 55078, 57601, 58840, 58844, -- Blood Plague (Plague Strike dot)
--[[ Strangulate ]] { timer = 5, dontFade=true, dr=true }, 47476, 49913, 49914, 49915, 49916,
--[[ Rune of Razorice ]]{ timer = 20, dontFade=true }, 51714,
--[[ Glyph.Blood Boil ]]{ timer = 5, dontFade=true }, 58617
)
 
elseif playerClass == "PRIEST" then
 
AddSpells(
--[[ Blackout ]] { timer = 3, dontFade=true, dr=true }, 15269,
--[[ Devouring Plague ]]{ timer = 24 }, 2944, 19276, 19277, 19278, 19279, 19280, 25467, 48299, 48300,
--[[ Divine Hymn ]]-- { timer = 20 }, 47951,
--[[ Holy Fire ]] { timer = 7 }, 14914, 15262, 15263, 15264, 15265, 15266, 15267, 15261, 25384, 48134, 48135,
--[[ Mind Control ]] { timer = 60, dr=true }, 605,
--[[ Mind Soothe ]] { timer = 15, dontFade=true }, 453,
--[[ Psychic Screem ]] { timer = 8, dr=true, glyphID=55676, glyphAdd=1 }, 8122, 8124, 10888, 10890,
--[[ Shackle Undead ]] { timer = 30, dontFade=true, dr=true }, 9484,
{ timer = 40, dontFade=true, dr=true }, 9485,
{ timer = 50, dontFade=true, dr=true }, 10955,
--[[ Silence ]] { timer = 5, dontFade=true, dr=true }, 15487,
--[[ SW: Pain ]] { timer = 18 }, 589, 594, 970, 992, 2767, 10892, 10893, 10894, 25367, 25368, 48124, 48125,
--[[ Vampiric Embrace ]]{ timer = 60, dontFade=true }, 15286,
--[[ Vampiric Touch ]] { timer = 15 }, 34914, 34916, 34917, 48159, 48160
)
 
elseif playerClass == "MAGE" then
 
AddSpells(
--[[ Blast Wave ]] { timer = 6, dontFade=true }, 11113, 13018, 13019, 13020, 13021, 27133, 33933, 42944, 42945,
--[[ Cone of Cold ]] { timer = 8, dontFade=true }, 120, 8492, 10159, 10160, 10161, 27087, 42930, 42931,
--[[ Counterspell ]] { timer = 8, dontFade=true, dr=true, SPELL_INTERRUPT=true }, 2139,
--[[ Deep Freeze ]] { timer = 5, dontFade=true, dr=true }, 44572,
--[[ Dragon's Breath ]] { timer = 5, dontFade=true }, 31661, 33041, 33042, 33042, 42949, 42950,
--[[ Fingers of Frost ]]{ timer = 15, dontFade=true }, 44544,
--[[ Fireball DoT ]] { timer = 4, glyphID=56368, glyphAdd=-30 }, 133,
{ timer = 6, glyphID=56368, glyphAdd=-30 }, 143, 145,
{ timer = 8, glyphID=56368, glyphAdd=-30 }, 3140, 8400, 8401, 8402, 10148, 10149, 10150, 10151, 25306, 27070, 38692, 42832, 42833,
--[[ Flamestrike ]] { timer = 8 }, 2120, 2121, 8422, 8423, 10215, 10216, 27086, 42925, 42926,
--[[ Frost Armor ]] { timer = 5, dontFade=true, group=1 }, 6136,
--[[ Frost Nova ]] { timer = 8, dontFade=true, dr=true }, 122, 865, 6131, 10230, 27088, 42917,
--[[ Frostbite ]] { timer = 5, dontFade=true, dr=true }, 12494, -- DR ?
--[[ Frostbolt effect]] { timer = 5, dontFade=true, group=1, talentTree=3, talentIndex=7, talentAdd=1 }, 116,
{ timer = 6, dontFade=true, group=1, talentTree=3, talentIndex=7, talentAdd=1 }, 205, 837,
{ timer = 7, dontFade=true, group=1, talentTree=3, talentIndex=7, talentAdd=1 }, 7322, 8406,
{ timer = 8, dontFade=true, group=1, talentTree=3, talentIndex=7, talentAdd=1 }, 8407, 8408,
{ timer = 9, dontFade=true, group=1, talentTree=3, talentIndex=7, talentAdd=1 }, 10179, 10180, 10181, 25304, 27071, 27072, 38697, 42841, 42842,
--[[ Impact ]] { timer = 2, dontFade=true }, 12355,
--[[ Imp. CS ]] { timer = 0, dontFade=true, talentTree=1, talentIndex=12, talentAdd=2 }, 18469,
--[[ Imp. Scorch ]] { timer = 30 }, 22959,
--[[ Living Bomb ]] { timer = 12 }, 44457, 55359, 55360,
--[[ Polymorph ]] { timer = 20, dr=true }, 118,
{ timer = 30, dr=true }, 12824,
{ timer = 40, dr=true }, 12825,
{ timer = 50, dr=true }, 12826, 28271, 28272, 61025, 61305,
--[[ Slow ]] { timer = 15, dr=true }, 31589, -- pvp timer != pve timer ?
--[[ Winter's Chill ]] { timer = 15, dontFade=true }, 12579
)
 
else return end
 
-- CONST
local refreshRate = 0.100 -- sec
local BORDER_GAP = 6
local offsetTimer = 28 -- espacement horizontal entre timers
local offsetHeader = 18 -- espacement vertical entre le nom de la cible et les dots
local offsetTarget = offsetHeader + 50 -- espacement vertical des targets
local backdrop = {
bgFile = "Interface/Buttons/WHITE8X8",
edgeFile = "Interface/Tooltips/UI-Tooltip-Border",
tile = true, tileSize = 16, edgeSize = 12,
insets = { left = 2, right = 2, top = 2, bottom = 2 } }
 
-- DATA
local frame, OnUpdate = CreateFrame( "Frame", "Ara_Dotimer_Frame" )
local targets = {}
local nbTargets = 0
local playerGUID
local targetGUID, targetLevel, targeted, prevTargetGUID, prevTargetLevel
local focusGUID, focusLevel, focused
local config
local defaultConfig = { timersGrowRight=true, scale=1, x=330, y=400 }
 
local border = {
bgFile = "Interface/Buttons/WHITE8X8",
edgeFile = "Interface/Tooltips/UI-Tooltip-Border",
tile = true, tileSize = 16, edgeSize = 12,
insets = { left = 2, right = 2, top = 2, bottom = 2 } }
 
local targetBorder = CreateFrame("Frame", "Ara_Dotimer_TargetBorder", frame)
targetBorder:SetFrameStrata"BACKGROUND"
targetBorder:Show()
targetBorder:SetAlpha(0)
targetBorder:SetBackdrop( border )
targetBorder:SetBackdropBorderColor( .2, .2, 1, .15 )
targetBorder:SetBackdropColor( .2,.2,1,.15 )
 
local focusBorder = CreateFrame("Frame", "Ara_Dotimer_FocusBorder", frame)
focusBorder:SetFrameStrata"BACKGROUND"
focusBorder:Show()
focusBorder:SetAlpha(0)
focusBorder:SetBackdrop( border )
focusBorder:SetBackdropBorderColor( 1, .2, .2, .2 )
focusBorder:SetBackdropColor( 1,.2,.2,.2 )
 
 
-- LOCAL GLOBALS
local bit_or, bit_and, tremove, next, floor, format, wipe, UnitDebuff, GetTime, UnitGUID, GameFontNormal, GameFontHighlightSmall, GameFontHighlight, NumberFontNormalLarge =
bit.bor, bit.band, tremove, next, floor, format, wipe, UnitDebuff, GetTime, UnitGUID, GameFontNormal, GameFontHighlightSmall, GameFontHighlight, NumberFontNormalLarge
 
-- POOLS
local tables = {} -- table reuse
 
local function AcquireTable( ... )
local table = tremove(tables) or {}
for i = 1, select( "#", ... ), 2 do
local key, value = select( i, ... )
table[key] = value
end
return table
end
 
local function ReleaseTable(table)
tables[#tables+1] = wipe(table)
end
 
 
local fontstrings = {} -- fontstring reuse
 
local function AcquireFS(doseCounter)
local fs = tremove(fontstrings)
if not fs then
fs = frame:CreateFontString( nil, "BACKGROUND" )
fs:SetJustifyH("CENTER")
fs.hidden = true
end
fs:SetFontObject( doseCounter and NumberFontNormalLarge or GameFontHighlightSmall )
return fs
end
 
local function ReleaseFS(fs)
fs:ClearAllPoints()
fs:Hide()
fs.hidden = true
fontstrings[#fontstrings+1] = fs
end
 
 
local headers = {}
 
local function AcquireHeader()
local header = tremove(headers)
if not header then
header = frame:CreateFontString( nil, "BACKGROUND" )
header:SetJustifyH("LEFT")
header:SetFontObject(GameFontNormal)
header.hidden = true
end
return header
end
 
local function ReleaseHeader(header)
header:Hide()
header.hidden = true
headers[#headers+1] = header
end
 
 
local function ClearTargetHL()
targeted.header:SetFontObject(GameFontNormal)
targetBorder:SetAlpha(0)
targeted.targeted = nil
targeted = nil
end
 
local function SetTargetHL(target)
if targeted then ClearTargetHL() end
targeted = target
if not target then return end
target.header:SetFontObject(GameFontHighlight)
targetBorder:SetAlpha(1)
targetBorder:SetWidth( target.header:GetWidth()+BORDER_GAP*2 )
targetBorder:SetHeight( target.header:GetHeight() + offsetHeader + 16 + BORDER_GAP*2 )
targetBorder:SetPoint( "TOPLEFT", frame, config.timersGrowRight and "TOPLEFT" or "TOPRIGHT", config.timersGrowRight and -BORDER_GAP or -targetBorder:GetWidth()+BORDER_GAP, -offsetTarget*target.pos +BORDER_GAP )
target.targeted = true
end
 
 
local function ClearFocusHL()
focusBorder:SetAlpha(0)
focused.focused = nil
focused = nil
end
 
local function SetFocusHL(focus)
if focused then ClearFocusHL() end
focused = focus
if not focus then return end
focusBorder:SetAlpha(1)
focusBorder:SetWidth( focus.header:GetWidth()+BORDER_GAP*2)
focusBorder:SetHeight( focus.header:GetHeight() + offsetHeader + 16 + BORDER_GAP*2 )
focusBorder:SetPoint( "TOPLEFT", frame, config.timersGrowRight and "TOPLEFT" or "TOPRIGHT", config.timersGrowRight and -BORDER_GAP or -focusBorder:GetWidth()+BORDER_GAP, -offsetTarget*focus.pos +BORDER_GAP )
-- focusBorder:SetWidth( focus.header:GetWidth()+BORDER_GAP*2)
-- focusBorder:SetHeight( focus.header:GetHeight() + offsetHeader + 16 + BORDER_GAP*2 )
focus.focused = true
end
 
 
local function CleanUITarget( target, timers )
local removedPos, guid = target.pos, target.guid
ReleaseHeader( target.header )
ReleaseTable( timers )
if target.targeted then ClearTargetHL() end
if target.focused then ClearFocusHL() end
ReleaseTable( target )
targets[guid] = nil
nbTargets = nbTargets - 1
-- remove OnUpdate if no target
if nbTargets == 0 then
return frame:SetScript("OnUpdate",nil)
end
-- reorder ui targets
for k,v in next, targets do
if v.pos > removedPos then
v.pos = v.pos - 1
end
end
end
 
local function RemoveTimer( target, spell, keepTarget )
local timers = target.timers
local timer = timers[spell]
if timer then
local removedPos = timer.pos
ReleaseFS( timer.fs )
if timer.dose then ReleaseFS( timer.dose ) end
ReleaseTable( timer )
timers[spell] = nil
if target.nbTimers == 1 and not keepTarget then
return CleanUITarget( target, timers )
end
--if removedPos < nbTimers then -- reorder ui timers
for k,v in next, timers do
if v.pos > removedPos then
v.pos = v.pos - 1
end
end
target.nbTimers = target.nbTimers - 1
end
end
 
local function AddTimer( guid, name, spell, timestamp, offset )
local target = targets[guid]
if not target then
target = AcquireTable( "guid", guid, "name", name, "timers", AcquireTable(),
"isPlayer", strsub( guid, 3, 5 ) == "000", "pos", nbTargets, "nbTimers", 0, "header", AcquireHeader() )
target.level = targetGUID==guid and targetLevel or prevTargetGUID==guid and prevTargetLevel
or focusGUID==guid and focusLevel or UnitGUID"mouseover"==guid and UnitLevel"mouseover" or 0
if target.level==0 then
target.level="??"
elseif target.level==-1 then
target.level = "BOSS"
end
targets[guid] = target
nbTargets = nbTargets + 1
if nbTargets == 1 then
frame:SetScript("OnUpdate",OnUpdate)
end
elseif spell.group then -- curses & co
for sp in next, target.timers do
if sp.group == spell.group then
RemoveTimer( target, sp, true )
break
end
end
end
 
local timers = target.timers
local timer = timers[spell]
if not timer then -- NEW TIMER
timer = AcquireTable( "name", spell.name, "fs", AcquireFS() )
timers[spell] = timer
target.nbTimers = target.nbTimers + 1
end
 
local spellTimer, duration = offset or spell.timer
if not offset then
if spell.dr and target.isPlayer then
local unit = targetGUID==guid and "target" or focusGUID==guid and "focus" or UnitGUID"mouseover"==guid and "mouseover"
if unit then
duration = select(6, UnitDebuff( unit, spell.name, spell.rank, "PLAYER,PET" ) )
if duration then spellTimer = duration end
end
end
if not duration then
if spell.hasGlyph then spellTimer = spellTimer + spell.glyphAdd end
if spell.hasTalent then
if spell.talentAdd then
spellTimer = spellTimer + spell.talentRank * spell.talentAdd
else spellTimer = spellTimer * ( 1 + spell.talentRank * spell.talentMul ) end
end
end
end
timer.startTime, timer.expireTime = timestamp, timestamp + spellTimer
 
timer.fs:SetAlpha(1) -- ADDED fade out
timer.fadeout = nil -- ADDED fade out
 
-- sort timers ( expire: 300 -> 0 )
local insertedPos = timer.pos or target.nbTimers
timer.pos = insertedPos
for k, v in next, timers do
if timer.expireTime > v.expireTime then
if insertedPos > v.pos then
timer.pos = timer.pos - 1
v.pos = v.pos + 1
end
elseif timer.expireTime < v.expireTime then
if insertedPos < v.pos then
timer.pos = timer.pos + 1
v.pos = v.pos - 1
end
end
end
end
 
local function RemoveTarget( guid )
local target = targets[guid]
if target then
local timers = target.timers
for k,v in next, timers do
ReleaseFS( v.fs )
if v.dose then ReleaseFS( v.dose ) end
ReleaseTable( v )
timers[k] = nil
end
return CleanUITarget( target, timers )
end
end
 
 
OnUpdate = function( self, elapsed )
self.timer = self.timer - elapsed
if self.timer >= 0 then return else self.timer = refreshRate end
local currentTime = GetTime()
-- process each target
for guid, target in next, targets do
local timers = target.timers
local targetPosChanged = target.pos ~= target.prevPos
-- repositionne le nom de la target si necessaire
if targetPosChanged then
target.prevPos = target.pos
local header = target.header
-- affiche si caché
if header.hidden then
header:Show()
header:SetFormattedText( "[%s] %s", target.level ~= 0 and tostring(target.level) or "??", target.name or "unknown" )
if targetGUID==guid then SetTargetHL(target) end
if focusGUID==guid then SetFocusHL(target) end
header.hidden = false
end
if config.timersGrowRight then
header:SetPoint( "TOPLEFT", frame, "TOPLEFT", 0, -offsetTarget * target.pos )
else
header:SetPoint( "TOPLEFT", frame, "TOPRIGHT", -header:GetStringWidth(), -offsetTarget * target.pos )
end
if target.targeted then -- repositionne le target highlight
targetBorder:SetPoint( "TOPLEFT", frame, config.timersGrowRight and "TOPLEFT" or "TOPRIGHT", config.timersGrowRight and -BORDER_GAP or -targetBorder:GetWidth()+BORDER_GAP, -offsetTarget*target.pos +BORDER_GAP )
end
if target.focused then -- repositionne le focus highlight
focusBorder:SetPoint( "TOPLEFT", frame, config.timersGrowRight and "TOPLEFT" or "TOPRIGHT", config.timersGrowRight and -BORDER_GAP or -focusBorder:GetWidth()+BORDER_GAP, -offsetTarget*target.pos +BORDER_GAP )
end
end
-- process each timer
for spell, timer in next, timers do
local timeLeft = timer.expireTime - currentTime
if timeLeft > -15 then
if timeLeft >= 5 then -- less granular
timeLeft = floor( timeLeft )
if timer.prevTime ~= timeLeft then
timer.prevTime = timeLeft
local ftime = timeLeft < 60 and format( "%is", timeLeft) or format( "%i:%.2i", floor( timeLeft / 60 ), floor( timeLeft ) % 60 )
timer.fs:SetFormattedText( "\124T%s:25:25:0:0\124t\n\124cff%s%s\124r", spell.icon, timeLeft < 10 and "ffff20" or "20ff20", ftime )
end
elseif timeLeft >= 0 then
timer.fs:SetFormattedText( "\124T%s:25:25:0:0\124t\n\124cffff2020%.1f\124r", spell.icon, timeLeft )
elseif not timer.fadeout then
if spell.dontFade then return RemoveTimer( target, spell ) end
timer.fadeout = true
if timer.dose then ReleaseFS( timer.dose ) timer.dose = nil end
timer.fs:SetAlpha(.6)
-- timer.fs:SetFormattedText( "\124T%s:25:25:0:0\124t\n ", spell.icon ) -- REM, see below
end
if timer.fadeout then -- ADDED timer for 0 --> -15 sec
timer.fs:SetFormattedText( "\124T%s:25:25:0:0\124t\n\124cff800080%i\124r", spell.icon, timeLeft )
end
-- repositionne le timer si necessaire, l'affiche si caché.
if targetPosChanged or timer.prevPos ~= timer.pos then
local fs = timer.fs
if config.timersGrowRight then
fs:SetPoint( "TOPLEFT", frame, "TOPLEFT", offsetTimer * (timer.pos-1), -offsetTarget * target.pos - offsetHeader )
else
fs:SetPoint( "TOPLEFT", frame, "TOPRIGHT", -offsetTimer * (timer.pos), -offsetTarget * target.pos - offsetHeader )
end
timer.prevPos = timer.pos
if fs.hidden then
fs:Show()
fs.hidden = false
end
end
else -- fixes some issues
RemoveTimer( target, spell )
end
end
end
end
 
local combatEvents = {
["SPELL_AURA_APPLIED"] = true,
["SPELL_AURA_REFRESH"] = true,
["SPELL_AURA_REMOVED"] = true,
["SPELL_INTERRUPT"] = true,
["SPELL_AURA_APPLIED_DOSE"] = true,
["SPELL_AURA_REMOVED_DOSE"] = true,
["UNIT_DIED"] = true,
["UNIT_DESTROYED"] = true,
}
 
local function OnCombatEvent( self, event, timestamp, combatEvent, srcGUID, srcName, srcFlags, dstGUID, dstName, dstFlags, ... )
if not combatEvents[combatEvent] then return end
if srcGUID == playerGUID or srcFlags == 0x1111 --[[ pet ]] then
-- target must be unfriendly
if bit_and( dstFlags, COMBATLOG_OBJECT_REACTION_HOSTILE + COMBATLOG_OBJECT_REACTION_NEUTRAL ) == 0 then return end
local spell = spells[...]
if not spell then return end
if combatEvent == "SPELL_AURA_APPLIED" or combatEvent == "SPELL_AURA_REFRESH" then
if not spell.set then spell.set, spell.name, spell.rank, spell.icon = true, GetSpellInfo((...)) end
return AddTimer( dstGUID, dstName, spell, GetTime() ) --timestamp )
elseif combatEvent == "SPELL_AURA_REMOVED" then
local target = targets[dstGUID]
if not target then return end
local timer = target.timers[ spells[...] ]
if not timer then return end
if spell.dontFade then RemoveTimer(target, spells[...]) else timer.expireTime = GetTime() - 0.001 end
elseif combatEvent == "SPELL_INTERRUPT" then -- TODO: merge with SPELL_AURA_APPLIED ?
AddTimer( dstGUID, dstName, spell, GetTime() )
else--if combatEvent == "SPELL_AURA_APPLIED_DOSE" or combatEvent == "SPELL_AURA_REMOVED_DOSE" then
local nbDose = select(5,...)
local target = targets[dstGUID]
if not target then return end
local timer = target.timers[spell]
if not timer then return end
 
AddTimer( dstGUID, dstName, spell, GetTime() )
if not timer.dose then
timer.dose = AcquireFS(true)
timer.dose:SetPoint( "TOP", timer.fs, "TOP", 0, -2 )
timer.dose:SetTextColor( 1, 1, 1, .75 )
timer.dose:Show()
end
return timer.dose:SetText( nbDose )
end
elseif combatEvent == "UNIT_DIED" or combatEvent == "UNIT_DESTROYED" then -- ou "else" tout court ?
return RemoveTarget( dstGUID )
end
end
 
 
local function OnEvent( self, event, arg1, arg2, ... )
if event == "PLAYER_TARGET_CHANGED" then
prevTargetGUID, prevTargetLevel = targetGUID, targetLevel
targetGUID, targetLevel = UnitGUID"target", UnitLevel"target"
if nbTargets == 0 then return end
local target = targets[targetGUID]
if targeted and targeted ~= target or target then return SetTargetHL(target) end
elseif event == "PLAYER_FOCUS_CHANGED" then
focusGUID = UnitGUID"focus"
focusLevel = UnitLevel"focus"
if nbTargets == 0 then return end
local focus = targets[focusGUID]
if focused and focused ~= focus or focus then return SetFocusHL(focus) end
elseif event == "PLAYER_REGEN_ENABLED" then
-- fin du combat, on vire les mobs qui ont reset
for guid in next, targets do
if strsub(guid,5,5) == "3" then -- mob
RemoveTarget( guid )
end
end
elseif event == "PLAYER_DEAD" then
-- si joueur mort, on retire toutes les targets
for guid in next, targets do
RemoveTarget( guid )
end
elseif event == "PLAYER_TALENT_UPDATE" then
for id, spell in next, spells do
if spell.talentTree then spell.hasTalent = nil end
end
elseif event == "ADDON_LOADED" then
if arg1 ~= "Ara_Dotimer" then return else self:UnregisterEvent(event) end
AraDotimerDB = AraDotimerDB or defaultConfig
config = AraDotimerDB
for k, v in next, defaultConfig do
if config[k] == nil then config[k] = v end
end
frame:SetScale( config.scale )
frame:SetPoint( "CENTER", UIParent, "BOTTOMLEFT", config.x, config.y )
elseif event == "PLAYER_LOGIN" then
playerGUID = UnitGUID"player"
else -- GLYPH
for id, spell in next, spells do
if spell.glyphID then spell.hasGlyph = nil end
end
end
end
 
 
frame:SetScript("OnEvent",OnEvent)
frame:RegisterEvent"PLAYER_TARGET_CHANGED"
frame:RegisterEvent"PLAYER_FOCUS_CHANGED"
frame:RegisterEvent"PLAYER_REGEN_ENABLED"
frame:RegisterEvent"PLAYER_DEAD"
frame:RegisterEvent"PLAYER_TALENT_UPDATE"
frame:RegisterEvent"GLYPH_ADDED" frame:RegisterEvent"GLYPH_REMOVED" frame:RegisterEvent"GLYPH_UPDATED"
frame:RegisterEvent"ADDON_LOADED"
 
frame.timer = refreshRate
frame:SetWidth(140)
frame:SetHeight(60)
frame:SetMovable(true)
 
local extraFrame = CreateFrame"Frame"
extraFrame:SetScript("OnEvent",OnCombatEvent)
extraFrame:RegisterEvent"COMBAT_LOG_EVENT_UNFILTERED"
 
local function ToggleAnchor()
local show = not frame:IsMouseEnabled()
frame:SetBackdrop( show and backdrop or nil )
frame:EnableMouse( show )
if show then frame:SetBackdropColor( .3, 0, .3, .5 ) end
end
 
frame:SetClampedToScreen(true) -- ADDED
frame:EnableMouseWheel(true) -- ADDED
frame:SetScript("OnMouseWheel", function(self, delta)
local scale = self:GetScale() + delta * .05
config.scale = scale
self:SetScale(scale)
end)
 
SLASH_ARADOTIMER1, SLASH_ARADOTIMER2 = "/dt", "/dot"
SlashCmdList["ARADOTIMER"] = function( param, self )
param = strlower(param)
if param == "grow" then
config.timersGrowRight = not config.timersGrowRight
return print( "[|cffffb366Ara|r|cffffff00Dotimer|r] Timers grow direction set to |cff40ff40" .. (config.timersGrowRight and "RIGHT" or "LEFT") .. "|r." )
end
ToggleAnchor()
end
 
frame:SetScript( "OnMouseDown", function(self,arg) if arg~="LeftButton" then self:StopMovingOrSizing();ToggleAnchor() else self:StartMoving() end end )
frame:SetScript( "OnMouseUp", function(self,arg)
self:StopMovingOrSizing()
config.x, config.y = self:GetCenter()
end )
 
return IsLoggedIn() and OnEvent(frame, "PLAYER_LOGIN") or frame:RegisterEvent"PLAYER_LOGIN"
\ No newline at end of file
Ara_Dotimer/trunk/Ara_Dotimer.toc New file
0,0 → 1,13
## Interface: 30100
## Title: |cFFFFB366Ara|r - Dotimer
## Version: r10
## Author: Ara
## Notes: Provides a display for multiple target debuff tracking. Type "/dot" or "/dt" to move/scale the display (right-click the window after you're done positioning).
## Dependencies:
## SavedVariables: AraDotimerDB
## SavedVariablesPerCharacter:
 
## LoadManagers: AddonLoader
## X-LoadOn-Always: delayed
 
Ara_Dotimer.lua
\ No newline at end of file
TradeskillCooldowns_Draft.lua New file
0,0 → 1,59
local HOUR, DAY = 3600, 82800 -- 23h
local watchedTimers = {
-- [28027] = { name= "Prismatic Sphere", skill = "Enchanting", },
-- [28028] = { name= "Void Sphere", skill = "Enchanting", },
[47280]= { skill= L"Jewelcrafting", name= "Brilliant Glass", CD= 20*HOUR, icon= "Interface\\Icons\\INV_Misc_Gem_Diamond_03", },
-- []= { skill= L"Jewelcrafting", name= "Icy Prism", CD= 20*HOUR, icon= "Interface\\Icons\\INV_Misc_Gem_Diamond_03", },
[26751]= { skill= L"Tailoring", name= "Primal Mooncloth", CD= 4*DAY, icon= "Interface\\Icons\\INV_Fabric_MoonRag_Primal", },
[36686]= { skill= L"Tailoring", name= "Shadowcloth", CD= 4*DAY, icon= "Interface\\Icons\\INV_Fabric_Felcloth_Ebon", },
[31373]= { skill= L"Tailoring", name= "Spellcloth", CD= 4*DAY, icon= "Interface\\Icons\\INV_Fabric_Spellfire", },
[56002]= { skill= L"Tailoring", name= "Ebonweave", CD= 4*DAY, icon= "Interface\\Icons\\INV_Fabric_Ebonweave", },
[56003]= { skill= L"Tailoring", name= "Spellweave", CD= 4*DAY, icon= "Interface\\Icons\\INV_Fabric_Spellweave", },
[56001]= { skill= L"Tailoring", name= "Moonshroud", CD= 4*DAY, icon= "Interface\\Icons\\INV_Fabric_Moonshroud", },
[61288]= { skill= L"Inscription", name= "Minor Glyph R.", CD= 20*HOUR, icon= "Interface\\Icons\\INV_Inscription_Tradeskill01", },
[61177]= { skill= L"Inscription", name= "Northrend Glyph R.", CD= 20*HOUR, icon= "Interface\\Icons\\INV_Inscription_Tradeskill01", },
[55208]= { skill= L"Mining", name= "Smelt Titansteel", CD= 20*HOUR, icon= "Interface\\Icons\\INV_Ingot_Titansteel_blue", },
[60893]= { skill= L"Alchemy", name= "Alchemy Research", CD= 7*DAY, icon= "Interface\\Icons\\INV_Potion_106", },
}
 
local watchedIndex, watchedCast, watchedTimer
local orgDoTradeSkill = _G.DoTradeSkill
 
function DoTradeSkill(index, ...)
watchedTimer = watchedTimers[ tonumber( strmatch( GetTradeSkillRecipeLink(index), "enchant:(%d+)" ) ) ]
if watchedTimer then
watchedIndex, watchedCast = index, GetTradeSkillInfo(index)
f:RegisterEvent"UNIT_SPELLCAST_SUCCEEDED"
f:RegisterEvent"UNIT_SPELLCAST_STOP"
end
return orgDoTradeSkill(index, ...)
end
 
-- alternative A :
 
function f:SPELL_UPDATE_COOLDOWN()
self:UnregisterEvent"SPELL_UPDATE_COOLDOWN"
char[watchedTimer.spellID] = time() + ( GetTradeSkillCooldown(watchedIndex) --[[or watchedTimer.CD]] )
if block then Block_OnEnter(block) end
end
 
function f:UNIT_SPELLCAST_SUCCEEDED(event, unit, spell)
if unit ~= "player" or spell ~= watchedCast then return end
self:UnregisterEvent"UNIT_SPELLCAST_SUCCEEDED"
self:UnregisterEvent"UNIT_SPELLCAST_STOP"
if event ~= "UNIT_SPELLCAST_SUCCEEDED" then return end
self:RegisterEvent"SPELL_UPDATE_COOLDOWN" -- ou bien virer cet event et ajouter directe "watchedTimer.CD"
end
f.UNIT_SPELLCAST_STOP = f.UNIT_SPELLCAST_SUCCEEDED
 
-- alternative B :
 
function f:UNIT_SPELLCAST_SUCCEEDED(event, unit, spell)
if unit ~= "player" or spell ~= watchedCast then return end
self:UnregisterEvent"UNIT_SPELLCAST_SUCCEEDED"
self:UnregisterEvent"UNIT_SPELLCAST_STOP"
if event ~= "UNIT_SPELLCAST_SUCCEEDED" then return end
char[watchedTimer.spellID] = time() + watchedTimer.CD
if block then Block_OnEnter(block) end
end
f.UNIT_SPELLCAST_STOP = f.UNIT_SPELLCAST_SUCCEEDED