diff --git a/libs/LibDataBroker-1.1/Changelog-libdatabroker-1-1-v1.1.4.txt b/libs/LibDataBroker-1.1/Changelog-libdatabroker-1-1-v1.1.4.txt deleted file mode 100644 index d5b31ed..0000000 --- a/libs/LibDataBroker-1.1/Changelog-libdatabroker-1-1-v1.1.4.txt +++ /dev/null @@ -1,33 +0,0 @@ -tag v1.1.4 -ddb0519a000c69ddf3a28c3f9fe2e62bb3fd00c5 -Tekkub -2008-11-06 22:03:04 -0700 - -Build 1.1.4 - - --------------------- - -Tekkub: - Add pairs and ipairs iters, since we can't use the normal iters on our dataobjs - Simplify readme, all docs have been moved into GitHub wiki pages - Documentation on how to use LDB data (for display addons) - Add StatBlockCore forum link - Add link to Fortress thread - And rearrange the addon list a bit too - Make field lists into nice pretty tables - Add list of who is using LDB - Always with the typos, I hate my fingers - Add tooltiptext and OnTooltipShow to data addon spec - Readme rejiggering - Add in some documentation on how to push data into LDB - Meh, fuck you textile - Adding readme - Pass current dataobj with attr change callbacks to avoid excessive calls to :GetDataObjectByName -Tekkub Stoutwrithe: - Make passed dataobj actually work - I always forget the 'then' - Minor memory optimization - - Only hold upvalues to locals in the functions called frequently - - Retain the metatable across future lib upgrades (the one in v1 will be lost) - Allow caller to pass a pre-populated table to NewDataObject diff --git a/libs/LibDataBroker-1.1/LibDataBroker-1.1.lua b/libs/LibDataBroker-1.1/LibDataBroker-1.1.lua deleted file mode 100644 index f47c0cd..0000000 --- a/libs/LibDataBroker-1.1/LibDataBroker-1.1.lua +++ /dev/null @@ -1,90 +0,0 @@ - -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", 4) -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 - -if oldminor < 4 then - local next = pairs(attributestorage) - function lib:pairs(dataobject_or_name) - local t = type(dataobject_or_name) - assert(t == "string" or t == "table", "Usage: ldb:pairs('dataobjectname') or ldb:pairs(dataobject)") - - local dataobj = self.proxystorage[dataobject_or_name] or dataobject_or_name - assert(attributestorage[dataobj], "Data object not found") - - return next, attributestorage[dataobj], nil - end - - local ipairs_iter = ipairs(attributestorage) - function lib:ipairs(dataobject_or_name) - local t = type(dataobject_or_name) - assert(t == "string" or t == "table", "Usage: ldb:ipairs('dataobjectname') or ldb:ipairs(dataobject)") - - local dataobj = self.proxystorage[dataobject_or_name] or dataobject_or_name - assert(attributestorage[dataobj], "Data object not found") - - return ipairs_iter, attributestorage[dataobj], 0 - end -end diff --git a/libs/LibDataBroker-1.1/README.textile b/libs/LibDataBroker-1.1/README.textile deleted file mode 100644 index ef16fed..0000000 --- a/libs/LibDataBroker-1.1/README.textile +++ /dev/null @@ -1,13 +0,0 @@ -LibDataBroker is a small WoW addon library designed to provide a "MVC":http://en.wikipedia.org/wiki/Model-view-controller interface for use in various addons. -LDB's primary goal is to "detach" plugins for TitanPanel and FuBar from the display addon. -Plugins can provide data into a simple table, and display addons can receive callbacks to refresh their display of this data. -LDB also provides a place for addons to register "quicklaunch" functions, removing the need for authors to embed many large libraries to create minimap buttons. -Users who do not wish to be "plagued" by these buttons simply do not install an addon to render them. - -Due to it's simple generic design, LDB can be used for any design where you wish to have an addon notified of changes to a table. - -h2. Links - -* "API documentation":http://github.com/tekkub/libdatabroker-1-1/wikis/api -* "Data specifications":http://github.com/tekkub/libdatabroker-1-1/wikis/data-specifications -* "Addons using LDB":http://github.com/tekkub/libdatabroker-1-1/wikis/addons-using-ldb diff --git a/libs/LibQuixote-2.0/ChatThrottleLib.lua b/libs/LibQuixote-2.0/ChatThrottleLib.lua deleted file mode 100644 index 6ba406c..0000000 --- a/libs/LibQuixote-2.0/ChatThrottleLib.lua +++ /dev/null @@ -1,510 +0,0 @@ --- --- ChatThrottleLib by Mikk --- --- Manages AddOn chat output to keep player from getting kicked off. --- --- ChatThrottleLib:SendChatMessage/:SendAddonMessage functions that accept --- a Priority ("BULK", "NORMAL", "ALERT") as well as prefix for SendChatMessage. --- --- Priorities get an equal share of available bandwidth when fully loaded. --- Communication channels are separated on extension+chattype+destination and --- get round-robinned. (Destination only matters for whispers and channels, --- obviously) --- --- Will install hooks for SendChatMessage and SendAddonMessage to measure --- bandwidth bypassing the library and use less bandwidth itself. --- --- --- Fully embeddable library. Just copy this file into your addon directory, --- add it to the .toc, and it's done. --- --- Can run as a standalone addon also, but, really, just embed it! :-) --- - -local CTL_VERSION = 22 - -local _G = _G - -if _G.ChatThrottleLib then - if _G.ChatThrottleLib.version >= CTL_VERSION then - -- There's already a newer (or same) version loaded. Buh-bye. - return - elseif not _G.ChatThrottleLib.securelyHooked then - print("ChatThrottleLib: Warning: There's an ANCIENT ChatThrottleLib.lua (pre-wow 2.0, =v16) in it!") - -- ATTEMPT to unhook; this'll behave badly if someone else has hooked... - -- ... and if someone has securehooked, they can kiss that goodbye too... >.< - _G.SendChatMessage = _G.ChatThrottleLib.ORIG_SendChatMessage - if _G.ChatThrottleLib.ORIG_SendAddonMessage then - _G.SendAddonMessage = _G.ChatThrottleLib.ORIG_SendAddonMessage - end - end - _G.ChatThrottleLib.ORIG_SendChatMessage = nil - _G.ChatThrottleLib.ORIG_SendAddonMessage = nil -end - -if not _G.ChatThrottleLib then - _G.ChatThrottleLib = {} -end - -ChatThrottleLib = _G.ChatThrottleLib -- in case some addon does "local ChatThrottleLib" above us and we're copypasted (AceComm-2, sigh) -local ChatThrottleLib = _G.ChatThrottleLib - -ChatThrottleLib.version = CTL_VERSION - - - ------------------- TWEAKABLES ----------------- - -ChatThrottleLib.MAX_CPS = 800 -- 2000 seems to be safe if NOTHING ELSE is happening. let's call it 800. -ChatThrottleLib.MSG_OVERHEAD = 40 -- Guesstimate overhead for sending a message; source+dest+chattype+protocolstuff - -ChatThrottleLib.BURST = 4000 -- WoW's server buffer seems to be about 32KB. 8KB should be safe, but seen disconnects on _some_ servers. Using 4KB now. - -ChatThrottleLib.MIN_FPS = 20 -- Reduce output CPS to half (and don't burst) if FPS drops below this value - - -local setmetatable = setmetatable -local table_remove = table.remove -local tostring = tostring -local GetTime = GetTime -local math_min = math.min -local math_max = math.max -local next = next -local strlen = string.len -local GetFrameRate = GetFrameRate - - - ------------------------------------------------------------------------ --- Double-linked ring implementation - -local Ring = {} -local RingMeta = { __index = Ring } - -function Ring:New() - local ret = {} - setmetatable(ret, RingMeta) - return ret -end - -function Ring:Add(obj) -- Append at the "far end" of the ring (aka just before the current position) - if self.pos then - obj.prev = self.pos.prev - obj.prev.next = obj - obj.next = self.pos - obj.next.prev = obj - else - obj.next = obj - obj.prev = obj - self.pos = obj - end -end - -function Ring:Remove(obj) - obj.next.prev = obj.prev - obj.prev.next = obj.next - if self.pos == obj then - self.pos = obj.next - if self.pos == obj then - self.pos = nil - end - end -end - - - ------------------------------------------------------------------------ --- Recycling bin for pipes --- A pipe is a plain integer-indexed queue, which also happens to be a ring member - -ChatThrottleLib.PipeBin = nil -- pre-v19, drastically different -local PipeBin = setmetatable({}, {__mode="k"}) - -local function DelPipe(pipe) - for i = #pipe, 1, -1 do - pipe[i] = nil - end - pipe.prev = nil - pipe.next = nil - - PipeBin[pipe] = true -end - -local function NewPipe() - local pipe = next(PipeBin) - if pipe then - PipeBin[pipe] = nil - return pipe - end - return {} -end - - - - ------------------------------------------------------------------------ --- Recycling bin for messages - -ChatThrottleLib.MsgBin = nil -- pre-v19, drastically different -local MsgBin = setmetatable({}, {__mode="k"}) - -local function DelMsg(msg) - msg[1] = nil - -- there's more parameters, but they're very repetetive so the string pool doesn't suffer really, and it's faster to just not delete them. - MsgBin[msg] = true -end - -local function NewMsg() - local msg = next(MsgBin) - if msg then - MsgBin[msg] = nil - return msg - end - return {} -end - - ------------------------------------------------------------------------ --- ChatThrottleLib:Init --- Initialize queues, set up frame for OnUpdate, etc - - -function ChatThrottleLib:Init() - - -- Set up queues - if not self.Prio then - self.Prio = {} - self.Prio["ALERT"] = { ByName = {}, Ring = Ring:New(), avail = 0 } - self.Prio["NORMAL"] = { ByName = {}, Ring = Ring:New(), avail = 0 } - self.Prio["BULK"] = { ByName = {}, Ring = Ring:New(), avail = 0 } - end - - -- v4: total send counters per priority - for _, Prio in pairs(self.Prio) do - Prio.nTotalSent = Prio.nTotalSent or 0 - end - - if not self.avail then - self.avail = 0 -- v5 - end - if not self.nTotalSent then - self.nTotalSent = 0 -- v5 - end - - - -- Set up a frame to get OnUpdate events - if not self.Frame then - self.Frame = CreateFrame("Frame") - self.Frame:Hide() - end - self.Frame:SetScript("OnUpdate", self.OnUpdate) - self.Frame:SetScript("OnEvent", self.OnEvent) -- v11: Monitor P_E_W so we can throttle hard for a few seconds - self.Frame:RegisterEvent("PLAYER_ENTERING_WORLD") - self.OnUpdateDelay = 0 - self.LastAvailUpdate = GetTime() - self.HardThrottlingBeginTime = GetTime() -- v11: Throttle hard for a few seconds after startup - - -- Hook SendChatMessage and SendAddonMessage so we can measure unpiped traffic and avoid overloads (v7) - if not self.securelyHooked then - -- Use secure hooks as of v16. Old regular hook support yanked out in v21. - self.securelyHooked = true - --SendChatMessage - hooksecurefunc("SendChatMessage", function(...) - return ChatThrottleLib.Hook_SendChatMessage(...) - end) - --SendAddonMessage - hooksecurefunc("SendAddonMessage", function(...) - return ChatThrottleLib.Hook_SendAddonMessage(...) - end) - end - self.nBypass = 0 -end - - ------------------------------------------------------------------------ --- ChatThrottleLib.Hook_SendChatMessage / .Hook_SendAddonMessage - -local bMyTraffic = false - -function ChatThrottleLib.Hook_SendChatMessage(text, chattype, language, destination, ...) - if bMyTraffic then - return - end - local self = ChatThrottleLib - local size = strlen(tostring(text or "")) + strlen(tostring(destination or "")) + self.MSG_OVERHEAD - self.avail = self.avail - size - self.nBypass = self.nBypass + size -- just a statistic -end -function ChatThrottleLib.Hook_SendAddonMessage(prefix, text, chattype, destination, ...) - if bMyTraffic then - return - end - local self = ChatThrottleLib - local size = tostring(text or ""):len() + tostring(prefix or ""):len(); - size = size + tostring(destination or ""):len() + self.MSG_OVERHEAD - self.avail = self.avail - size - self.nBypass = self.nBypass + size -- just a statistic -end - - - ------------------------------------------------------------------------ --- ChatThrottleLib:UpdateAvail --- Update self.avail with how much bandwidth is currently available - -function ChatThrottleLib:UpdateAvail() - local now = GetTime() - local MAX_CPS = self.MAX_CPS; - local newavail = MAX_CPS * (now - self.LastAvailUpdate) - local avail = self.avail - - if now - self.HardThrottlingBeginTime < 5 then - -- First 5 seconds after startup/zoning: VERY hard clamping to avoid irritating the server rate limiter, it seems very cranky then - avail = math_min(avail + (newavail*0.1), MAX_CPS*0.5) - self.bChoking = true - elseif GetFramerate() < self.MIN_FPS then -- GetFrameRate call takes ~0.002 secs - avail = math_min(MAX_CPS, avail + newavail*0.5) - self.bChoking = true -- just a statistic - else - avail = math_min(self.BURST, avail + newavail) - self.bChoking = false - end - - avail = math_max(avail, 0-(MAX_CPS*2)) -- Can go negative when someone is eating bandwidth past the lib. but we refuse to stay silent for more than 2 seconds; if they can do it, we can. - - self.avail = avail - self.LastAvailUpdate = now - - return avail -end - - ------------------------------------------------------------------------ --- Despooling logic - -function ChatThrottleLib:Despool(Prio) - local ring = Prio.Ring - while ring.pos and Prio.avail > ring.pos[1].nSize do - local msg = table_remove(Prio.Ring.pos, 1) - if not Prio.Ring.pos[1] then - local pipe = Prio.Ring.pos - Prio.Ring:Remove(pipe) - Prio.ByName[pipe.name] = nil - DelPipe(pipe) - else - Prio.Ring.pos = Prio.Ring.pos.next - end - Prio.avail = Prio.avail - msg.nSize - bMyTraffic = true - msg.f(unpack(msg, 1, msg.n)) - bMyTraffic = false - Prio.nTotalSent = Prio.nTotalSent + msg.nSize - DelMsg(msg) - if msg.callbackFn then - msg.callbackFn (msg.callbackArg) - end - end -end - - -function ChatThrottleLib.OnEvent(this,event) - -- v11: We know that the rate limiter is touchy after login. Assume that it's touchy after zoning, too. - local self = ChatThrottleLib - if event == "PLAYER_ENTERING_WORLD" then - self.HardThrottlingBeginTime = GetTime() -- Throttle hard for a few seconds after zoning - self.avail = 0 - end -end - - -function ChatThrottleLib.OnUpdate(this,delay) - local self = ChatThrottleLib - - self.OnUpdateDelay = self.OnUpdateDelay + delay - if self.OnUpdateDelay < 0.08 then - return - end - self.OnUpdateDelay = 0 - - self:UpdateAvail() - - if self.avail < 0 then - return -- argh. some bastard is spewing stuff past the lib. just bail early to save cpu. - end - - -- See how many of our priorities have queued messages (we only have 3, don't worry about the loop) - local n = 0 - for prioname,Prio in pairs(self.Prio) do - if Prio.Ring.pos or Prio.avail < 0 then - n = n + 1 - end - end - - -- Anything queued still? - if n<1 then - -- Nope. Move spillover bandwidth to global availability gauge and clear self.bQueueing - for prioname, Prio in pairs(self.Prio) do - self.avail = self.avail + Prio.avail - Prio.avail = 0 - end - self.bQueueing = false - self.Frame:Hide() - return - end - - -- There's stuff queued. Hand out available bandwidth to priorities as needed and despool their queues - local avail = self.avail/n - self.avail = 0 - - for prioname, Prio in pairs(self.Prio) do - if Prio.Ring.pos or Prio.avail < 0 then - Prio.avail = Prio.avail + avail - if Prio.Ring.pos and Prio.avail > Prio.Ring.pos[1].nSize then - self:Despool(Prio) - -- Note: We might not get here if the user-supplied callback function errors out! Take care! - end - end - end - -end - - - - ------------------------------------------------------------------------ --- Spooling logic - - -function ChatThrottleLib:Enqueue(prioname, pipename, msg) - local Prio = self.Prio[prioname] - local pipe = Prio.ByName[pipename] - if not pipe then - self.Frame:Show() - pipe = NewPipe() - pipe.name = pipename - Prio.ByName[pipename] = pipe - Prio.Ring:Add(pipe) - end - - pipe[#pipe + 1] = msg - - self.bQueueing = true -end - - - -function ChatThrottleLib:SendChatMessage(prio, prefix, text, chattype, language, destination, queueName, callbackFn, callbackArg) - if not self or not prio or not prefix or not text or not self.Prio[prio] then - error('Usage: ChatThrottleLib:SendChatMessage("{BULK||NORMAL||ALERT}", "prefix", "text"[, "chattype"[, "language"[, "destination"]]]', 2) - end - if callbackFn and type(callbackFn)~="function" then - error('ChatThrottleLib:ChatMessage(): callbackFn: expected function, got '..type(callbackFn), 2) - end - - local nSize = text:len() - - if nSize>255 then - error("ChatThrottleLib:SendChatMessage(): message length cannot exceed 255 bytes", 2) - end - - nSize = nSize + self.MSG_OVERHEAD - - -- Check if there's room in the global available bandwidth gauge to send directly - if not self.bQueueing and nSize < self:UpdateAvail() then - self.avail = self.avail - nSize - bMyTraffic = true - _G.SendChatMessage(text, chattype, language, destination) - bMyTraffic = false - self.Prio[prio].nTotalSent = self.Prio[prio].nTotalSent + nSize - if callbackFn then - callbackFn (callbackArg) - end - return - end - - -- Message needs to be queued - local msg = NewMsg() - msg.f = _G.SendChatMessage - msg[1] = text - msg[2] = chattype or "SAY" - msg[3] = language - msg[4] = destination - msg.n = 4 - msg.nSize = nSize - msg.callbackFn = callbackFn - msg.callbackArg = callbackArg - - self:Enqueue(prio, queueName or (prefix..(chattype or "SAY")..(destination or "")), msg) -end - - -function ChatThrottleLib:SendAddonMessage(prio, prefix, text, chattype, target, queueName, callbackFn, callbackArg) - if not self or not prio or not prefix or not text or not chattype or not self.Prio[prio] then - error('Usage: ChatThrottleLib:SendAddonMessage("{BULK||NORMAL||ALERT}", "prefix", "text", "chattype"[, "target"])', 2) - end - if callbackFn and type(callbackFn)~="function" then - error('ChatThrottleLib:SendAddonMessage(): callbackFn: expected function, got '..type(callbackFn), 2) - end - - local nSize = text:len(); - - if RegisterAddonMessagePrefix then - if nSize>255 then - error("ChatThrottleLib:SendAddonMessage(): message length cannot exceed 255 bytes", 2) - end - else - nSize = nSize + prefix:len() + 1 - if nSize>255 then - error("ChatThrottleLib:SendAddonMessage(): prefix + message length cannot exceed 254 bytes", 2) - end - end - - nSize = nSize + self.MSG_OVERHEAD; - - -- Check if there's room in the global available bandwidth gauge to send directly - if not self.bQueueing and nSize < self:UpdateAvail() then - self.avail = self.avail - nSize - bMyTraffic = true - _G.SendAddonMessage(prefix, text, chattype, target) - bMyTraffic = false - self.Prio[prio].nTotalSent = self.Prio[prio].nTotalSent + nSize - if callbackFn then - callbackFn (callbackArg) - end - return - end - - -- Message needs to be queued - local msg = NewMsg() - msg.f = _G.SendAddonMessage - msg[1] = prefix - msg[2] = text - msg[3] = chattype - msg[4] = target - msg.n = (target~=nil) and 4 or 3; - msg.nSize = nSize - msg.callbackFn = callbackFn - msg.callbackArg = callbackArg - - self:Enqueue(prio, queueName or (prefix..chattype..(target or "")), msg) -end - - - - ------------------------------------------------------------------------ --- Get the ball rolling! - -ChatThrottleLib:Init() - ---[[ WoWBench debugging snippet -if(WOWB_VER) then - local function SayTimer() - print("SAY: "..GetTime().." "..arg1) - end - ChatThrottleLib.Frame:SetScript("OnEvent", SayTimer) - ChatThrottleLib.Frame:RegisterEvent("CHAT_MSG_SAY") -end -]] - - diff --git a/libs/LibQuixote-2.0/LibQuixote-2.0.lua b/libs/LibQuixote-2.0/LibQuixote-2.0.lua deleted file mode 100644 index d633316..0000000 --- a/libs/LibQuixote-2.0/LibQuixote-2.0.lua +++ /dev/null @@ -1,976 +0,0 @@ ---[[ -Name: LibQuixote-2.0 -Revision: $Revision: 107 $ -Author(s): David Lynch (kemayo@gmail.com) -Website: http://www.wowace.com/wiki/LibQuixote-2.0 -Documentation: http://www.wowace.com/wiki/LibQuixote-2.0 -SVN: http://svn.wowace.com/wowace/trunk/LibQuixote-2.0/ -Description: Abstracts out questlog handling. -License: LGPL v2.1 -]] - -local MAJOR_VERSION = "LibQuixote-2.0" -local MINOR_VERSION = 90000 + (tonumber(("$Revision: 107 $"):match("%d+")) or 0) - --- #AUTODOC_NAMESPACE lib - -local lib, oldMinor = LibStub:NewLibrary(MAJOR_VERSION, MINOR_VERSION) -if not lib then return end - -local debugf = tekDebug and tekDebug:GetFrame("LibQuixote-2.0") -local function Debug(...) if debugf then debugf:AddMessage(string.join(", ", tostringall(...))) end end - --- localization issues: -local DUNGEON = LFG_TYPE_DUNGEON -local HEROIC = DUNGEON_DIFFICULTY2 or PLAYER_DIFFICULTY2 -local SCENARIO = GUILD_CHALLENGE_TYPE4 or "Scenario" -local ACCOUNT = "Account" -- can't find a localization for this... -local shorttags = { - [ELITE] = '+', - [GROUP] = 'g', - [PVP] = 'p', - [RAID] = 'r', - [DUNGEON] = 'd', - [HEROIC] = 'd+', - [DAILY] = "\226\128\162", -- adorable little circle - [WEEKLY] = 'w', - [SCENARIO] = "s", - [ACCOUNT] = "a", -} -lib.shorttags = shorttags -local tagWeight = { - [ELITE] = 1, - [GROUP] = 2, - [PVP] = 3, - [RAID] = 4, - [DUNGEON] = 5, - [HEROIC] = 6, - [DAILY] = 7, - [WEEKLY] = 8, - [SCENARIO] = 9, - [ACCOUNT] = 10, -} -lib.tags = { - ELITE = ELITE, - GROUP = GROUP, - PVP = PVP, - RAID = RAID, - DUNGEON = DUNGEON, - HEROIC = HEROIC, - DAILY = DAILY, - SCENARIO = SCENARIO, - ACCOUNT = ACCOUNT, - WEEKLY = WEEKLY, -} - -local playerName = UnitName("player") - -local _G = _G -local GetTime = _G.GetTime -local GetQuestLink = _G.GetQuestLink -local GetQuestLogTitle = _G.GetQuestLogTitle -local GetQuestLogSelection = _G.GetQuestLogSelection -local GetNumQuestLogEntries = _G.GetNumQuestLogEntries -local GetQuestLogQuestText = _G.GetQuestLogQuestText -local GetNumQuestLeaderBoards = _G.GetNumQuestLeaderBoards - -local new, del, deepDel, doAll -do - local list = setmetatable({}, {__mode='k'}) - function new(...) - local t = next(list) - if t then - list[t] = nil - for i = 1, select('#', ...) do - t[i] = select(i, ...) - end - return t - else - return { ... } - end - end - function del(t) - setmetatable(t, nil) - table.wipe(t) - list[t] = true - return nil - end - function deepDel(t) - if type(t) ~= "table" then - return nil - end - for k,v in pairs(t) do - t[k] = deepDel(v) - end - return del(t) - end - function doAll(func, ...) - for i=1, select('#', ...) do - func(select(i, ...)) - end - end -end - -if lib.frame then - lib.frame:UnregisterAllEvents() - lib.frame:SetScript("OnEvent", nil) - lib.frame:SetScript("OnUpdate", nil) -else - lib.frame = CreateFrame("Frame", MAJOR_VERSION .. "_Frame") -end -local frame = lib.frame - -frame:RegisterEvent("QUEST_LOG_UPDATE") -frame:RegisterEvent("GROUP_ROSTER_UPDATE") -frame:RegisterEvent("CHAT_MSG_ADDON") - -frame:SetScript("OnEvent", function(self, event, ...) - self[event](lib, ...) -end) - -if lib.callbacks then - lib:UnregisterAll(lib) -- unregisters all callbacks that quixote is doing on itself (comms stuff, mostly) - lib:UnhookDialogs() -else - lib.callbacks = LibStub("CallbackHandler-1.0"):New(lib, nil, nil, "UnregisterAll") -end - -do - local tooltip = lib.tooltip - local function tooltip_line(link, line) - if not tooltip then - tooltip = CreateFrame("GameTooltip", MAJOR_VERSION.."_Tooltip", nil, "GameTooltipTemplate") - tooltip:SetOwner(UIParent, "ANCHOR_NONE") - lib.tooltip = tooltip - end - tooltip:ClearLines() - tooltip:SetHyperlink(link) - - if tooltip:NumLines() < line then return false end - return _G[MAJOR_VERSION.."_TooltipTextLeft"..line]:GetText() - end - lib.UID_to_name = setmetatable(lib.UID_to_name or {}, {__index = function(self, key) - local link = (type(key) == 'string') and key or ('quest:'..key) - local uid = string.match(link, '%d+') - local name = tooltip_line(link, 1) - if name then - self[uid] = name - return name - end - return false - end,}) -end - --- Sorts a table of quests by level, with quests of the same level ordered --- by elite, dungeon or raid tags, i.e. normal < elite < dungeon < raid. --- Quests of the same level and tag are sorted alphabetically by title. -local questSort = function(a, b) - local q = lib.quests - local aa = (q[a].level * 8) + (q[a].tag and tagWeight[q[a].tag] or 0) - local bb = (q[b].level * 8) + (q[b].tag and tagWeight[q[b].tag] or 0) - if aa == bb then - return q[a].title < q[b].title - end - return aa < bb -end - --- Various data tables: -lib.quests = lib.quests or new() -lib.quests_complete = lib.quests_complete or 0 -lib.quest_ids = lib.quest_ids or new() -lib.quest_zones = lib.quest_zones or new() -lib.zones = lib.zones or new() -lib.quest_objectives = lib.quest_objectives or new() -lib.quest_objective_status = lib.quest_objective_status or new() -lib.quest_mobs = lib.quest_mobs or new() -lib.quest_items = lib.quest_items or new() - -do - local hooks_active = true - function lib:UnhookDialogs() - hooks_active = false - end - hooksecurefunc("AcceptQuest", function() - if not hooks_active then return false end - lib.npc = UnitName("npc") - lib.npc_is_player = UnitIsPlayer("npc") - end) - hooksecurefunc(StaticPopupDialogs["ABANDON_QUEST"], "OnAccept", function() - local name = GetAbandonQuestName() - local uid = lib:GetQuest(name) - Debug("Quest_Abandoned", name, uid) - lib.callbacks:Fire("Quest_Abandoned", name, uid) - end) - hooksecurefunc(StaticPopupDialogs["ABANDON_QUEST_WITH_ITEMS"], "OnAccept", function() - local name = GetAbandonQuestName() - local uid = lib:GetQuest(name) - lib.callbacks:Fire("Quest_Abandoned", name, uid) - end) -end - -local objects_pattern = '^' .. QUEST_OBJECTS_FOUND:gsub('(%%%d?$?.)', '(.-)') .. '$' --QUEST_OBJECTS_FOUND = "%d/%d %s" -local monsters_pattern = '^' .. QUEST_MONSTERS_KILLED:gsub('(%%%d?$?.)', '(.-)') .. '$' --QUEST_MONSTERS_KILLED = "%d/%d %s slain" -local faction_pattern = '^' .. QUEST_FACTION_NEEDED:gsub('(%%%d?$?.)', '(.-)') .. '$' --QUEST_FACTION_NEEDED = "%s / %s %s" -local player_pattern = '^' .. QUEST_PLAYERS_KILLED:gsub('(%%%d?$?.)', '(.-)') .. '$' --QUEST_PLAYERS_KILLED = "%d/%d %s Players slain" - -local troublesome_objectives = {} -local uid_zone_map = {} - -function frame:QUEST_LOG_UPDATE() - local now = GetTime() - if not frame.lastUpdate or (now - frame.lastUpdate) > TOOLTIP_UPDATE_TIME then - frame.lastUpdate = now - else - return - end - doAll(deepDel, lib.quest_ids, lib.quest_zones, lib.quest_mobs, lib.quest_items, lib.zones) - - local quests, old_quests = new(), lib.quests - local quest_objective_status, old_quest_objective_status = new(), lib.quest_objective_status - local quest_zones, old_quest_zones = new(), lib.quest_zones - local quest_ids, zones, quest_mobs, quest_items, quest_objectives = new(), new(), new(), new(), new(), new() - - -- The quest log is scanned: - local numEntries, numQuests = GetNumQuestLogEntries() - local numQuestsComplete = 0 - local zone - - Debug("entries", numEntries, numQuests) - - if numEntries > 0 then - local quest_count, id, overflow_handled = 0, 0, false - while quest_count < numQuests do - id = id + 1 - local name, level, group, header, collapsed, complete, frequency, unique_id = GetQuestLogTitle(id) - -- title, level, suggestedGroup, isHeader, isCollapsed, isComplete, frequency, questID, startEvent, displayQuestID, isOnMap, hasLocalPOI, isTask, isStory - Debug("Scan", name, header, collapsed, unique_id) - if header then - zone = name or (UNKNOWN .. " " .. id) - table.insert(zones, zone) - quest_zones[zone] = new() - else - quest_count = quest_count + 1 - if id > numEntries then - Debug("Overflow", name, uid_zone_map[unique_id]) - zone = uid_zone_map[unique_id] or UNKNOWN - if zone == UNKNOWN and not overflow_handled then - table.insert(zones, zone) - quest_zones[zone] = new() - overflow_handled = true - end - else - -- it's in a real zone; remember this in case things get collapsed later - uid_zone_map[unique_id] = zone - end - local q = new() - - local tagid, tag = GetQuestTagInfo(unique_id) - - q.unique_id = unique_id - q.id = id - q.title = name - q.level = level - q.tag = tag - q.group = group - q.daily = frequency == LE_QUEST_FREQUENCY_DAILY - q.weekly = frequency == LE_QUEST_FREQUENCY_WEEKLY - if frequency and not tag then - if frequency == LE_QUEST_FREQUENCY_DAILY then - q.tag = DAILY - elseif frequency == LE_QUEST_FREQUENCY_WEEKLY then - q.tag = WEEKLY - end - end - q.complete = complete -- 1, -1, nil - q.zone = zone - - if complete == 1 then - numQuestsComplete = numQuestsComplete + 1 - end - - local numObjectives = GetNumQuestLeaderBoards(id) - if numObjectives and numObjectives > 0 then - local trouble = troublesome_objectives[unique_id] or 0 - local objectives = new() - quest_objectives[unique_id] = new() - for o = 1, numObjectives do - local desc, qtype, done = GetQuestLogLeaderBoard(o, id) - local numNeeded, numItems, mobName - - if qtype == 'item' or qtype == 'object' then --'object' for the leaderboard in Dousing the Flames of Protection; maybe others. - numItems, numNeeded, desc = desc:match(objects_pattern) - numItems = tonumber(numItems) - numNeeded = tonumber(numNeeded) - quest_items[desc] = unique_id - elseif qtype == 'monster' then - numItems, numNeeded, mobName = desc:match(monsters_pattern) - if mobName == nil or numItems == nil or numNeeded == nil then - --Sometimes we get objectives like "Find Mankrik's Wife: 0/1", which are listed as "monster". - numItems, numNeeded, mobName = desc:match(objects_pattern) - end - numItems = tonumber(numItems) - numNeeded = tonumber(numNeeded) - desc = mobName - - if quest_mobs[desc] then - --Another quest also wants this mob! Convert quest_mobs[desc] to a table. - if type(quest_mobs[desc]) ~= 'table' then - quest_mobs[desc] = new(quest_mobs[desc]) - end - table.insert(quest_mobs[desc], unique_id) - else - quest_mobs[desc] = unique_id - end - elseif qtype == 'reputation' then - numItems, numNeeded, desc = desc:match(faction_pattern) - elseif (qtype == 'event') or (qtype == 'log') then - numNeeded = 1 - numItems = done and 1 or 0 - elseif qtype == 'player' then - numItems, numNeeded = desc:match(player_pattern) - desc = COMBATLOG_FILTER_STRING_HOSTILE_PLAYERS -- "Enemy Players" - elseif qtype == 'spell' then - -- desc can stay as-is - numItems = done and 1 or 0 - numNeeded = 1 - end - if (not desc) or strtrim(desc) == "" then - trouble = trouble + 1 - end - if desc then - objectives[desc] = new(numItems, numNeeded, qtype) - table.insert(quest_objectives[unique_id], desc) - end - end - quest_objective_status[unique_id] = objectives - - if (trouble > 0) and (trouble / numObjectives < 10) then - troublesome_objectives[unique_id] = trouble - frame:Show() -- schedules a rescan in 0.1 seconds - end - else - quest_objectives[unique_id] = false - quest_objective_status[unique_id] = false - end - quests[unique_id] = q - table.insert(quest_ids, unique_id) - table.insert(quest_zones[zone], unique_id) - end - if id == numQuests * 2 then - -- just in case, to avoid infinite loops (I don't trust whiles) - quest_count = numQuests - end - end - end - - lib.quests = quests - lib.quest_ids = quest_ids - lib.quest_zones = quest_zones - lib.zones = zones - lib.quest_objectives = quest_objectives - lib.quest_objective_status = quest_objective_status - lib.quest_items = quest_items - lib.quest_mobs = quest_mobs - lib.quests_complete = numQuestsComplete - - table.sort(zones) - table.sort(quests, questSort) - table.sort(quest_ids, questSort) - for _, zquests in pairs(quest_zones) do - table.sort(zquests, questSort) - end - - -- Event firing - local changed = false - if lib.firstDone then - for uid, quest in pairs(quests) do - if not old_quests[uid] then - -- Gained a quest - lib.callbacks:Fire("Quest_Gained", quest.title, uid, GetNumQuestLeaderBoards(quest.id), quest.zone, lib.npc, lib.npc_is_player) - changed = true - else - local oldquest = old_quests[uid] - -- Any objectives changed? - if quest_objective_status[uid] then - for desc, goal in pairs(quest_objective_status[uid]) do - -- goal: {got, needed, type} - if (old_quest_objective_status[uid]) then - local oldgoal = old_quest_objective_status[uid][desc] - if (goal[1] ~= 0) and (oldgoal and oldgoal[1] ~= goal[1]) then - -- An objective has advanced - lib.callbacks:Fire("Objective_Update", quest.title, uid, desc, oldgoal and oldgoal[1] or 0, goal[1], goal[2], goal[3]) - changed = true - end - end - end - if old_quest_objective_status[uid] and old_quest_objective_status[uid][""] and not quest_objective_status[uid][""] then - -- An objective was previously uncached and has now been filled in. - changed = true - end - end - --Completed? - if oldquest.complete ~= quest.complete then - if quest.complete == 1 then - lib.callbacks:Fire("Quest_Complete", quest.title, uid) - elseif quest.complete == -1 then - lib.callbacks:Fire("Quest_Failed", quest.title, uid) - end - changed = true - end - end - end - for uid, oldquest in pairs(old_quests) do - -- Lost a quest? - if not quests[uid] then - lib.callbacks:Fire("Quest_Lost", oldquest.title, uid, oldquest.zone) - changed = true - end - end - for zone, zquests in pairs(quest_zones) do - if not old_quest_zones[zone] then - lib.callbacks:Fire("Quest_Zone_Gained", zone, #zquests) - changed = true - elseif #old_quest_zones[zone] ~= #zquests then - lib.callbacks:Fire("Zone_Quests_Changed", zone, #zquests) - changed = true - end - end - else - changed = true - lib.firstDone = true - frame:GROUP_ROSTER_UPDATE() - - lib.callbacks:Fire("Ready") - end - - if changed then - lib.callbacks:Fire("Update") - end - - -- clean up junk tables - - doAll(deepDel, old_quests, old_quest_objectives, old_quest_objective_status) -end - --- Comms: --- Someone joins party -> version info exchanged -> quest data shared - -local last_incompatible_version = 0 - -lib.party = lib.party or {} -lib.party_quests = lib.party_quests or {} - -local ChatThrottleLib = ChatThrottleLib -function lib:SendAddonMessage(contents, distribution, target, priority) - if ChatThrottleLib and not lib.disable_comms then - ChatThrottleLib:SendAddonMessage(priority or "NORMAL", "Quixote2", contents, distribution or "PARTY", target); - end -end - ---/dump LibStub("LibQuixote-2.0").party_quests -function frame:GROUP_ROSTER_UPDATE() - if(#lib.quest_ids == 0) then return end - local p = new() - local sent - for i=1, GetNumSubgroupMembers() do - local name, realm = UnitName('party'..i) - if name then - p[name] = true - if lib.party[name] == nil and name ~= UNKNOWN and not realm then - lib:SendAddonMessage("v"..MINOR_VERSION, "WHISPER", name) - lib.party[name] = false -- to prevent spamming with pointless version data - lib.party_quests[name] = new() - lib.party_quests[name].waiting = true - end - end - end - for known in pairs(lib.party) do - if not p[known] then - lib.party[known] = deepDel(lib.party[known]) - lib.party_quests[known] = deepDel(lib.party_quests[known]) - end - end - del(p) -end - -local commhandlers = { - --version - -- implicit sync request; 'v' is never broadcast to the party, only to unknown party members - -- upon receiving 'v', begin a sync to the sender - v = function(msg, distribution, sender) - local version = tonumber(msg) - if version <= last_incompatible_version then - lib.callbacks:Fire("Incompatible_Version", sender, version) - end - if version > MINOR_VERSION then - lib.callbacks:Fire("New_Version", sender, version) - end - lib.worth_sending = true - - lib.party[sender] = version - --And sync: - for _, uid in pairs(lib.quest_ids) do - lib:SendAddonMessage("q"..uid, "WHISPER", sender, "BULK") - if lib.quest_objective_status[uid] then - for desc, o in pairs(lib.quest_objective_status[uid]) do - local isrep = o[3] == "reputation" - local got = isrep and lib:GetReactionLevel(o[1]) or o[1] or '1' - local need = isrep and lib:GetReactionLevel(o[2]) or o[2] or '1' - lib:SendAddonMessage("o"..uid.."~"..desc.."~"..(isrep and "r" or "")..got.."/"..need, "WHISPER", sender, "BULK") - end - end - lib:SendAddonMessage("r"..uid, "WHISPER", sender, "BULK") - end - lib:SendAddonMessage("d", "WHISPER", sender, "BULK") - end, - --quest gained - q = function(msg, distribution, sender) - local uid = tonumber(msg) - if not lib.party_quests[sender] then return end - local name = lib.UID_to_name[uid] -- Forces the tooltip request. - lib.party_quests[sender][uid] = lib.party_quests[sender][uid] or new() - end, - --objective update - o = function(msg, distribution, sender) - local uid, objective, isrep, got, need = msg:match("^(.-)~(.-)~(r?)(%d-)/(%d-)$") - uid = tonumber(uid) - if not (lib.party_quests[sender] and lib.party_quests[sender][uid]) then return end - local o = lib.party_quests[sender][uid][objective] - isrep = isrep == 'r' - got = isrep and lib:GetReactionName(tonumber(got)) or tonumber(got) - need = isrep and lib:GetReactionName(tonumber(need)) or tonumber(need) - if o then - o[1] = got - o[2] = need - o[3] = isrep - if not lib.party_quests[sender].waiting then - lib.callbacks:Fire("Party_Objective_Update", sender, uid, lib.UID_to_name[uid], objective, got, need, isrep) - lib.callbacks:Fire("Party_Update", sender, uid) - end - else - lib.party_quests[sender][uid][objective] = new(got, need, isrep) - end - end, - --sending a quest is complete - r = function(msg, distribution, sender) - local uid = tonumber(msg) - if not (lib.party_quests[sender] and lib.party_quests[sender][uid]) then return end - if not lib.party_quests[sender].waiting then - lib.callbacks:Fire("Party_Quest_Gained", sender, uid, lib.UID_to_name[uid]) - lib.callbacks:Fire("Party_Update", sender, uid) - end - end, - --quest finished - c = function(msg, distribution, sender) - local uid = tonumber(msg) - lib.callbacks:Fire("Party_Quest_Complete", sender, uid, lib.UID_to_name[uid]) - lib.callbacks:Fire("Party_Update", sender, uid) - end, - --quest failed - f = function(msg, distribution, sender) - local uid = tonumber(msg) - lib.callbacks:Fire("Party_Quest_Failed", sender, uid, lib.UID_to_name[uid]) - lib.callbacks:Fire("Party_Update", sender, uid) - end, - --quest lost - l = function(msg, distribution, sender) - local uid = tonumber(msg) - if not (lib.party_quests[sender] and lib.party_quests[sender][uid]) then return end - lib.callbacks:Fire("Party_Quest_Lost", sender, uid, lib.UID_to_name[uid]) - lib.callbacks:Fire("Party_Update", sender, uid) - lib.party_quests[sender][uid] = deepDel(lib.party_quests[sender][uid]) - end, - --sync done - d = function(msg, distribution, sender) - if not lib.party_quests[sender] then return end - lib.party_quests[sender].waiting = nil - lib.callbacks:Fire("Sync_Finished", sender) - lib.callbacks:Fire("Party_Update", sender) - end, -} -function frame:CHAT_MSG_ADDON(prefix, msg, distribution, sender) - if prefix ~= "Quixote2" or sender == playerName or lib.disable_comms then return end - - local commtype, remainder = msg:match("^(%a)(.*)") - if (not commtype) or (not commhandlers[commtype]) then return end - - commhandlers[commtype](remainder, distribution, sender) -end -local function worth_sending() return lib.worth_sending and (not IsInRaid()) and (GetNumGroupMembers() > 0) end -lib:RegisterCallback("Quest_Gained", function(event, title, uid, objectives) - if not worth_sending() then return end - lib:SendAddonMessage("q"..uid) - if objectives > 0 then - for objective, got, need, t in lib:IterateObjectivesForQuest(uid) do - lib:SendAddonMessage("o"..uid.."~"..objective.."~"..(t=="reputation" and "r" or "")..got.."/"..need) - end - end - lib:SendAddonMessage("r"..uid) -end) -lib:RegisterCallback("Quest_Lost", function(event, title, uid) - if not worth_sending() then return end - lib:SendAddonMessage("l"..uid) -end) -lib:RegisterCallback("Quest_Complete", function(event, title, uid) - if not worth_sending() then return end - lib:SendAddonMessage("c"..uid) -end) -lib:RegisterCallback("Quest_Failed", function(event, title, uid) - if not worth_sending() then return end - lib:SendAddonMessage("f"..uid) -end) -lib:RegisterCallback("Objective_Update", function(event, title, uid, objective, had, got, need, t) - if not worth_sending() then return end - lib:SendAddonMessage("o"..uid.."~"..objective.."~"..(t=="reputation" and ("r"..lib:GetReactionLevel(got).."/"..lib:GetReactionLevel(need)) or (got.."/"..need))) -end) - --- Public API: - -function lib:IterateZones() - return ipairs(self.zones) -end - -local function zoneQuestIter(t, i) - if not t then return end - i = (i or 0) + 1 - if t[i] then - return i, lib:GetQuestByUid(t[i]) - end -end -function lib:IterateQuestsInZone(zone) - return zoneQuestIter, self.quest_zones[zone], nil -end - -function lib:IterateQuestsByLevel() - return zoneQuestIter, self.quest_ids, nil -end - -do - -- There's a sorted and unsorted version presented here via argument, with slightly - -- different returns. This is because I didn't want to release a whole new version - -- for this one minor change. When next the major version is bumped, get rid of - -- unsorted. - local current_uid - local function objIter(t, i) - if not t then return end - local i = (i or 0) + 1 - local value = t[i] - if value and lib.quest_objective_status[current_uid][value] then - return i, value, unpack(lib.quest_objective_status[current_uid][value]) - end - end - local function objIterUnsorted(t, k) - if not t then return end - local k, v = next(t, k) - if k then - return k, unpack(v) - end - end - function lib:IterateObjectivesForQuest(uid, sorted) - if sorted then - current_uid = uid - return objIter, self.quest_objectives[uid], nil - end - return objIterUnsorted, self.quest_objective_status[uid], nil - end -end - -function lib:GetNumQuests() - return #self.quest_ids, self.quests_complete -end - -function lib:GetQuest(id) - if type(id) == 'string' then - for uid, q in pairs(lib.quests) do - if q.title == id then - id = uid - break - end - end - end - return self:GetQuestByUid(id) -end - -function lib:GetQuestByUid(uid) - local q = self.quests[uid] - if not q then return end - return q.unique_id, q.id, q.title, q.level, q.tag, GetNumQuestLeaderBoards(q.id), q.complete, q.group, q.daily, q.zone -end - -function lib:GetQuestById(id) - --By quest log id. - for uid, quest in pairs(self.quests) do - if quest.id == id then - return self:GetQuestByUid(uid) - end - end -end - -function lib:GetQuestObjective(uid, desc) - local q = self.quest_objectives[uid] - if q and q[desc] then - return desc, unpack(self.quest_objective_status[uid][q[desc]]) - end -end - -function lib:GetNumQuestObjectives(uid) - local q = self.quest_objectives[uid] - if not q then return end - - local c = 0 - for desc,o in pairs(q) do - if o[1] == o[2] then - c = c + 1 - end - end - return GetNumQuestLeaderBoards(self.quests[uid].id), c -end - -function lib:GetQuestText(uid) - local q = self.quests[uid] - if not q then return end - - local selectionId = GetQuestLogSelection() - SelectQuestLogEntry(q.id) - local description, objectives = GetQuestLogQuestText(q.id) - SelectQuestLogEntry(selectionId) - return description, objectives -end - -function lib:IsQuestMob(mobname) - return self.quest_mobs[mobname] and true -end - -local function mobIter(mobList, i) - -- This iterator is lightly special-cased to allow mobList to either be a list or a string. - if type(mobList) == 'table' then - i = next(mobList, i) - return i, mobList[i] - else - return i==nil and 1 or nil, mobList - end -end -function lib:IterateQuestsForMob(mobname) - if self.quest_mobs[mobname] then - return mobIter, self.quest_mobs[mobname], nil - end -end - -function lib:IsQuestItem(itemname) - local uid = self.quest_items[itemname] - if uid then - return uid, itemname, unpack(self.quest_objectives[uid][itemname]) - end -end - --- Party: - -local function realname(name) - if type(name) == 'number' then - return UnitName("party"..name), "party"..name - end - if name:match("^party%d$") then - return UnitName(name), name - end - return name -end - -function lib:PartyMemberHasQuixote(name) - name = realname(name) - return self.party[name] -end - --- TODO: Can this be turned into tooltip-scanning in 2.4? -function lib:PartyMemberHasQuest(name, uid) - local name, unit = realname(name) - if self.party_quests[name] then - return self.party_quests[name][uid] - elseif self.quests[uid] then - --They don't have quixote, but we *do* have the quest, so IsUnitOnQuest can be fallen back on. - if not unit then - for i=1, GetNumSubgroupMembers() do - local u = "party"..i - if name == UnitName(u) then - unit = u - break - end - end - end - if unit then - return IsUnitOnQuestByQuestID(uid, unit) - end - end -end - -function lib:GetNumPartyMembersWithQuest(uid) - local count = 0 - for i=1, GetNumSubgroupMembers() do - if self:PartyMemberHasQuest(i, uid) then - count = count + 1 - end - end - return count -end - -local function partySort(a, b) - -- pure alphabetical sorting - return lib.UID_to_name[a] < lib.UID_to_name[b] -end -local function partyIter(t, k) - k = next(t, k) - if t[k] then - return k, t[k] - else - del(t) - end -end -function lib:IteratePartyMemberQuests(name) - name = realname(name) - if not self.party_quests[name] then - return partyIter - end - local tmp = new() - for uid in pairs(self.party_quests[name]) do - table.insert(tmp, uid) - end - table.sort(tmp, partySort) - return partyIter, tmp, nil -end - -function lib:GetPartyQuestObjective(name, uid, objective) - name = realname(name) - if self.party_quests[name] and self.party_quests[name][uid] and self.party_quests[name][uid][objective] then - return unpack(self.party_quests[name][uid][objective]) - end -end - -function lib:GetPartyQuestNumObjectives(name, uid) - name = realname(name) - local objectives = self.party_quests[name] and self.party_quests[name][uid] - if objectives then - local total, complete = 0, 0 - for desc, status in pairs(objectives) do - total = total + 1 - if status[1] == status[2] then - complete = complete + 1 - end - end - return total, complete - end -end - --- Utility: - -function lib:IsQuestWatchedByUid(uid) - local quid = self.quests[uid] and self.quests[uid].id - if qid then - return IsQuestWatched(qid) - end -end - -function lib:AddQuestWatchByUid(uid, watchTime) - local qid = self.quests[uid] and self.quests[uid].id - if qid then - AddQuestWatch(qid, watchTime) - return qid - end -end - -function lib:RemoveQuestWatchByUid(uid, watchTime) - local qid = self.quests[uid] and self.quests[uid].id - if qid then - RemoveQuestWatch(qid, watchTime) - return qid - end -end - -function lib:ShareQuestByUid(uid) - -- Share the quest with nearby party members. - local qid = self.quests[uid] and self.quests[uid].id - if qid then - local wasSelected = GetQuestLogSelection() - SelectQuestLogEntry(qid) - if GetQuestLogPushable() and GetNumGroupMembers() > 0 then - QuestLogPushQuest() - end - SelectQuestLogEntry(wasSelected) - end -end - -function lib:ShowQuestLog(uid) - local id = self.quests[uid] and self.quests[uid].id - if id then - QuestLog_SetSelection(id) - else - ShowUIPanel(QuestLogFrame) - end -end - -function lib:GetShortTagForQuest(uid) - local q = self.quests[uid] - if q.shorttag then return q.shorttag end - if q and q.tag and shorttags[q.tag] then - local tag = shorttags[q.tag] - if q.tag == GROUP then - tag = tag .. q.group - end - if q.daily and tag ~= shorttags[DAILY] then - tag = tag .. shorttags[DAILY] - end - q.shorttag = tag - return tag - end - return '' -end - -function lib:GetTaggedQuestName(uid) - -- It's such a common pattern - local q = self.quests[uid] - if q then - return '['..q.level..self:GetShortTagForQuest(uid)..'] '..q.title - end - return '' -end - --- Get a numeric equivalent to a reaction level, from Hated=1 to Exalted=8. -do - local reactions = { - [FACTION_STANDING_LABEL1] = 1, - [FACTION_STANDING_LABEL1_FEMALE] = 1, - [FACTION_STANDING_LABEL2] = 2, - [FACTION_STANDING_LABEL2_FEMALE] = 2, - [FACTION_STANDING_LABEL3] = 3, - [FACTION_STANDING_LABEL3_FEMALE] = 3, - [FACTION_STANDING_LABEL4] = 4, - [FACTION_STANDING_LABEL4_FEMALE] = 4, - [FACTION_STANDING_LABEL5] = 5, - [FACTION_STANDING_LABEL5_FEMALE] = 5, - [FACTION_STANDING_LABEL6] = 6, - [FACTION_STANDING_LABEL6_FEMALE] = 6, - [FACTION_STANDING_LABEL7] = 7, - [FACTION_STANDING_LABEL7_FEMALE] = 7, - [FACTION_STANDING_LABEL8] = 8, - [FACTION_STANDING_LABEL8_FEMALE] = 8, - } - -------------------------------------------- - -- Arguments: - -- string - faction standing text - -- - -- Notes: - -- Returns a numeric-equivalent for faction standings. - -- - -- Returns: - -- * number - number from 1 to 8 or -1 if invalid - -------------------------------------------- - function lib:GetReactionLevel(leveltext) - return leveltext and reactions[leveltext] or -1 - end - - function lib:GetReactionName(level) - for react, index in pairs(reactions) do - if index == level then - return react - end - end - end -end diff --git a/libs/LibQuixote-2.0/lib.xml b/libs/LibQuixote-2.0/lib.xml deleted file mode 100644 index 41df5c3..0000000 --- a/libs/LibQuixote-2.0/lib.xml +++ /dev/null @@ -1,5 +0,0 @@ - -