diff --git a/Libs/Deformat-2.0/Deformat-2.0.lua b/Libs/Deformat-2.0/Deformat-2.0.lua new file mode 100644 index 0000000..901590c --- /dev/null +++ b/Libs/Deformat-2.0/Deformat-2.0.lua @@ -0,0 +1,343 @@ +--[[ +Name: Deformat-2.0 +Revision: $Rev: 6804 $ +Author(s): ckknight (ckknight@gmail.com) +Website: http://ckknight.wowinterface.com/ +Documentation: http://wiki.wowace.com/index.php/Deformat-2.0 +SVN: http://svn.wowace.com/root/trunk/Deformat/Deformat-2.0 +Description: A library to deformat format strings. +Dependencies: AceLibrary +]] + +local MAJOR_VERSION = "Deformat-2.0" +local MINOR_VERSION = "$Revision: 6804 $" + + +if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary") end +if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end + +local Deformat = {} + +do + local sequences = { + ["%d*d"] = "%%-?%%d+", + ["s"] = ".+", + ["[fg]"] = "%%-?%%d+%%.%%d+", + ["%%%.%d[fg]"] = "%%-?%%d+%%.?%%d*", + ["c"] = ".", + } + local curries = {} + + local function doNothing(item) + return item + end + local v = {} + + local function concat(a1, a2, a3, a4, a5) + local left, right + if not a2 then + return a1 + elseif not a3 then + left, right = a1, a2 + elseif not a4 then + return concat(concat(a1, a2), a3) + elseif not a5 then + return concat(concat(concat(a1, a2), a3), a4) + else + return concat(concat(concat(concat(a1, a2), a3), a4), a5) + end + if not string.find(left, "%%1%$") and not string.find(right, "%%1%$") then + return left .. right + elseif not string.find(right, "%%1%$") then + local i + for j = 9, 1, -1 do + if string.find(left, "%%" .. j .. "%$") then + i = j + break + end + end + while true do + local first + local firstPat + for x, y in pairs(sequences) do + local i = string.find(right, "%%" .. x) + if not first or (i and i < first) then + first = i + firstPat = x + end + end + if not first then + break + end + i = i + 1 + right = string.gsub(right, "%%(" .. firstPat .. ")", "%%" .. i .. "$%1") + end + return left .. right + elseif not string.find(left, "%%1%$") then + local i = 1 + while true do + local first + local firstPat + for x, y in pairs(sequences) do + local i = string.find(left, "%%" .. x) + if not first or (i and i < first) then + first = i + firstPat = x + end + end + if not first then + break + end + i = i + 1 + left = string.gsub(left, "%%(" .. firstPat .. ")", "%%" .. i .. "$%1") + end + return concat(left, right) + else + local i + for j = 9, 1, -1 do + if string.find(left, "%%" .. j .. "%$") then + i = j + break + end + end + local j + for k = 9, 1, -1 do + if string.find(right, "%%" .. k .. "%$") then + j = k + break + end + end + for k = j, 1, -1 do + right = string.gsub(right, "%%" .. k .. "%$", "%%" .. k + i .. "%$") + end + return left .. right + end + end + + local function Curry(a1, a2, a3, a4, a5) + local pattern = concat(a1, a2, a3, a4, a5) + if not string.find(pattern, "%%1%$") then + local unpattern = string.gsub(pattern, "([%(%)%.%*%+%-%[%]%?%^%$%%])", "%%%1") + local f = {} + local i = 0 + while true do + local first + local firstPat + for x, y in pairs(sequences) do + local i = string.find(unpattern, "%%%%" .. x) + if not first or (i and i < first) then + first = i + firstPat = x + end + end + if not first then + break + end + unpattern = string.gsub(unpattern, "%%%%" .. firstPat, "(" .. sequences[firstPat] .. ")", 1) + i = i + 1 + if firstPat == "c" or firstPat == "s" then + table.insert(f, doNothing) + else + table.insert(f, tonumber) + end + end + unpattern = "^" .. unpattern .. "$" + local _,alpha, bravo, charlie, delta, echo, foxtrot, golf, hotel, india + if i == 0 then + return + elseif i == 1 then + return function(text) + _,_,alpha = string.find(text, unpattern) + if alpha then + return f[1](alpha) + end + end + elseif i == 2 then + return function(text) + _,_,alpha, bravo = string.find(text, unpattern) + if alpha then + return f[1](alpha), f[2](bravo) + end + end + elseif i == 3 then + return function(text) + _,_,alpha, bravo, charlie = string.find(text, unpattern) + if alpha then + return f[1](alpha), f[2](bravo), f[3](charlie) + end + end + elseif i == 4 then + return function(text) + _,_,alpha, bravo, charlie, delta = string.find(text, unpattern) + if alpha then + return f[1](alpha), f[2](bravo), f[3](charlie), f[4](delta) + end + end + elseif i == 5 then + return function(text) + _,_,alpha, bravo, charlie, delta, echo = string.find(text, unpattern) + if alpha then + return f[1](alpha), f[2](bravo), f[3](charlie), f[4](delta), f[5](echo) + end + end + elseif i == 6 then + return function(text) + _,_,alpha, bravo, charlie, delta, echo, foxtrot = string.find(text, unpattern) + if alpha then + return f[1](alpha), f[2](bravo), f[3](charlie), f[4](delta), f[5](echo), f[6](foxtrot) + end + end + elseif i == 7 then + return function(text) + _,_,alpha, bravo, charlie, delta, echo, foxtrot, golf = string.find(text, unpattern) + if alpha then + return f[1](alpha), f[2](bravo), f[3](charlie), f[4](delta), f[5](echo), f[6](foxtrot), f[7](golf) + end + end + elseif i == 8 then + return function(text) + _,_,alpha, bravo, charlie, delta, echo, foxtrot, golf, hotel = string.find(text, unpattern) + if alpha then + return f[1](alpha), f[2](bravo), f[3](charlie), f[4](delta), f[5](echo), f[6](foxtrot), f[7](golf), f[8](hotel) + end + end + else + return function(text) + _,_,alpha, bravo, charlie, delta, echo, foxtrot, golf, hotel, india = string.find(text, unpattern) + if alpha then + return f[1](alpha), f[2](bravo), f[3](charlie), f[4](delta), f[5](echo), f[6](foxtrot), f[7](golf), f[8](hotel), f[9](india) + end + end + end + else + local o = {} + local f = {} + local unpattern = string.gsub(pattern, "([%(%)%.%*%+%-%[%]%?%^%$%%])", "%%%1") + local i = 1 + while true do + local pat + for x, y in pairs(sequences) do + if not pat and string.find(unpattern, "%%%%" .. i .. "%%%$" .. x) then + pat = x + break + end + end + if not pat then + break + end + unpattern = string.gsub(unpattern, "%%%%" .. i .. "%%%$" .. pat, "(" .. sequences[pat] .. ")", 1) + if pat == "c" or pat == "s" then + table.insert(f, doNothing) + else + table.insert(f, tonumber) + end + i = i + 1 + end + i = 1 + string.gsub(pattern, "%%(%d)%$", function(w) o[i] = tonumber(w); i = i + 1; end) + v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8],v[9] = nil + for x, y in pairs(f) do + v[x] = f[y] + end + for x, y in pairs(v) do + f[x] = v[x] + end + unpattern = "^" .. unpattern .. "$" + i = i - 1 + if i == 0 then + return function(text) + return + end + elseif i == 1 then + return function(text) + _,_,v[1] = string.find(text, unpattern) + if v[1] then + return f[1](v[1]) + end + end + elseif i == 2 then + return function(text) + _,_,v[1],v[2] = string.find(text, unpattern) + if v[1] then + return f[1](v[o[1]]), f[2](v[o[2]]) + end + end + elseif i == 3 then + return function(text) + _,_,v[1],v[2],v[3] = string.find(text, unpattern) + if v[1] then + return f[1](v[o[1]]), f[2](v[o[2]]), f[3](v[o[3]]) + end + end + elseif i == 4 then + return function(text) + _,_,v[1],v[2],v[3],v[4] = string.find(text, unpattern) + if v[1] then + return f[1](v[o[1]]), f[2](v[o[2]]), f[3](v[o[3]]), f[4](v[o[4]]) + end + end + elseif i == 5 then + return function(text) + _,_,v[1],v[2],v[3],v[4],v[5] = string.find(text, unpattern) + if v[1] then + return f[1](v[o[1]]), f[2](v[o[2]]), f[3](v[o[3]]), f[4](v[o[4]]), f[5](v[o[5]]) + end + end + elseif i == 6 then + return function(text) + _,_,v[1],v[2],v[3],v[4],v[5],v[6] = string.find(text, unpattern) + if v[1] then + return f[1](v[o[1]]), f[2](v[o[2]]), f[3](v[o[3]]), f[4](v[o[4]]), f[5](v[o[5]]), f[6](v[o[6]]) + end + end + elseif i == 7 then + return function(text) + _,_,v[1],v[2],v[3],v[4],v[5],v[6],v[7] = string.find(text, unpattern) + if v[1] then + return f[1](v[o[1]]), f[2](v[o[2]]), f[3](v[o[3]]), f[4](v[o[4]]), f[5](v[o[5]]), f[6](v[o[6]]), f[7](v[o[7]]) + end + end + elseif i == 8 then + return function(text) + _,_,v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8] = string.find(text, unpattern) + if v[1] then + return f[1](v[o[1]]), f[2](v[o[2]]), f[3](v[o[3]]), f[4](v[o[4]]), f[5](v[o[5]]), f[6](v[o[6]]), f[7](v[o[7]]), f[8](v[o[8]]) + end + end + else + return function(text) + _,_,v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8],v[9] = string.find(text, unpattern) + if v[1] then + return f[1](v[o[1]]), f[2](v[o[2]]), f[3](v[o[3]]), f[4](v[o[4]]), f[5](v[o[5]]), f[6](v[o[6]]), f[7](v[o[7]]), f[8](v[o[8]]), f[9](v[o[9]]) + end + end + end + end + end + + function Deformat:Deformat(text, a1, a2, a3, a4, a5) + self:argCheck(text, 2, "string") + self:argCheck(a1, 3, "string") + local pattern = a1 + if a5 then + pattern = a1 .. a2 .. a3 .. a4 .. a5 + elseif a4 then + pattern = a1 .. a2 .. a3 .. a4 + elseif a3 then + pattern = a1 .. a2 .. a3 + elseif a2 then + pattern = a1 .. a2 + end + if curries[pattern] == nil then + curries[pattern] = Curry(a1, a2, a3, a4, a5) + end + return curries[pattern](text) + end +end + +local mt = getmetatable(Deformat) or {} +mt.__call = Deformat.Deformat +setmetatable(Deformat, mt) + +AceLibrary:Register(Deformat, MAJOR_VERSION, MINOR_VERSION) +Deformat = nil diff --git a/Libs/Gratuity-2.0/Gratuity-2.0.lua b/Libs/Gratuity-2.0/Gratuity-2.0.lua new file mode 100644 index 0000000..0cf3782 --- /dev/null +++ b/Libs/Gratuity-2.0/Gratuity-2.0.lua @@ -0,0 +1,220 @@ +--[[ +Name: Gratuity-2.0 +Revision: $Rev: 11053 $ +Author: Tekkub Stoutwrithe (tekkub@gmail.com) +Website: http://wiki.wowace.com/index.php/GratuityLib +Documentation: http://wiki.wowace.com/index.php/Gratuity-2.0_API_Documentation +SVN: svn://svn.wowace.com/root/trunk/GratuityLib/Gratuity-2.0 +Description: Tooltip parsing library +Dependencies: AceLibrary, (optional) Compost-2.0, (optional) Deformat-2.0 +]] + +local vmajor, vminor = "Gratuity-2.0", "$Revision: 11053 $" + +if not AceLibrary then error(vmajor .. " requires AceLibrary.") end +if not AceLibrary:IsNewVersion(vmajor, vminor) then return end + +local lib = {} +local methods = { + "SetBagItem", "SetAction", "SetAuctionItem", "SetAuctionSellItem", "SetBuybackItem", + "SetCraftItem", "SetCraftSpell", "SetHyperlink", "SetInboxItem", "SetInventoryItem", + "SetLootItem", "SetLootRollItem", "SetMerchantItem", "SetPetAction", "SetPlayerBuff", + "SetQuestItem", "SetQuestLogItem", "SetQuestRewardSpell", "SetSendMailItem", "SetShapeshift", + "SetSpell", "SetTalent", "SetTrackingSpell", "SetTradePlayerItem", "SetTradeSkillItem", "SetTradeTargetItem", + "SetTrainerService", "SetUnit", "SetUnitBuff", "SetUnitDebuff", +} + + +-- Activate a new instance of this library +local function activate(self, oldLib, oldDeactivate) + if oldLib then self.vars = oldLib.vars + else + self.vars = {} + self:CreateTooltip() + end + + self:CreateSetMethods() + + if oldDeactivate then oldDeactivate(oldLib) end +end + + +function lib:InitCompost() + if not self.vars.compost and AceLibrary:HasInstance("Compost-2.0") then self.vars.compost = AceLibrary("Compost-2.0") end +end + + +function lib:CreateTooltip() + local tt = CreateFrame("GameTooltip") + + self.vars.tooltip = tt + tt:SetOwner(tt, "ANCHOR_NONE") +-- tooltip:SetParent() + + self.vars.Llines, self.vars.Rlines = {}, {} + for i=1,30 do + self.vars.Llines[i], self.vars.Rlines[i] = tt:CreateFontString(), tt:CreateFontString() + self.vars.Llines[i]:SetFontObject(GameFontNormal) + self.vars.Rlines[i]:SetFontObject(GameFontNormal) + tt:AddFontStrings(self.vars.Llines[i], self.vars.Rlines[i]) + end +end + + +-- Clears the tooltip completely, none of this "erase left, hide right" crap blizzard does +function lib:Erase() + self.vars.tooltip:ClearLines() -- Ensures tooltip's NumLines is reset + for i=1,30 do self.vars.Rlines[i]:SetText() end -- Clear text from right side (ClearLines only hides them) + if not self.vars.tooltip:IsOwned(self.vars.tooltip) then self.vars.tooltip:SetOwner(self.vars.tooltip, "ANCHOR_NONE") end + self:assert(self.vars.tooltip:IsOwned(self.vars.tooltip), "Gratuity's tooltip is not scanable") +end + + +-- Get the number of lines +-- Arg: endln - If passed and tooltip's NumLines is higher, endln is returned back +function lib:NumLines(endln) + local num = self.vars.tooltip:NumLines() + return endln and num > endln and endln or num or 0 +end + +local FindDefault = function(str, pattern) + return string.find(str, pattern); +end; + +local FindExact = function(str, pattern) + if (str == pattern) then + return string.find(str, pattern); + end; +end; + +-- If text is found on tooltip then results of string.find are returned +-- Args: +-- txt - The text string to find +-- startln - First tooltip line to check, default 1 +-- endln - Last line to test, default 30 +-- ignoreleft / ignoreright - Causes text on one side of the tooltip to be ignored +-- exact - the compare will be an exact match vs the default behaviour of +function lib:Find(txt, startln, endln, ignoreleft, ignoreright, exact) + local searchFunction = FindDefault; + if (exact == true) then + searchFunction = FindExact; + end; + self:argCheck(txt, 2, "string", "number") + local t1, t2 = type(startln or 1), type(self:NumLines(endln)) + if (t1 ~= "number" or t2 ~= "number") then print(t1, t2, (startln or 1),self:NumLines(endln)) end + for i=(startln or 1),self:NumLines(endln) do + if not ignoreleft then + local txtl = self.vars.Llines[i]:GetText() + if (txtl and searchFunction(txtl, txt)) then return string.find(txtl, txt) end + end + + if not ignoreright then + local txtr = self.vars.Rlines[i]:GetText() + if (txtr and searchFunction(txtr, txt)) then return string.find(txtr, txt) end + end + end +end + + +-- Calls Find many times. +-- Args are passed directly to Find, t1-t10 replace the txt arg +-- Returns Find results for the first match found, if any +function lib:MultiFind(startln, endln, ignoreleft, ignoreright, t1,t2,t3,t4,t5,t6,t7,t8,t9,t10) + self:argCheck(t1, 6, "string", "number") + if t1 and self:Find(t1, startln, endln, ignoreleft, ignoreright) then return self:Find(t1, startln, endln, ignoreleft, ignoreright) + elseif t2 then return self:MultiFind(startln, endln, ignoreleft, ignoreright, t2,t3,t4,t5,t6,t7,t8,t9,t10) end +end + + +local deformat +-- If text is found on tooltip then results of deformat:Deformat are returned +-- Args: +-- txt - The text string to deformat and serach for +-- startln - First tooltip line to check, default 1 +-- endln - Last line to test, default 30 +-- ignoreleft / ignoreright - Causes text on one side of the tooltip to be ignored +function lib:FindDeformat(txt, startln, endln, ignoreleft, ignoreright) + self:argCheck(txt, 2, "string", "number") + if not deformat then + self:assert(AceLibrary:HasInstance("Deformat-2.0"), "FindDeformat requires Deformat-2.0 to be available") + deformat = AceLibrary("Deformat-2.0") + end + + for i=(startln or 1),self:NumLines(endln) do + if not ignoreleft then + local txtl = self.vars.Llines[i]:GetText() + if (txtl and deformat(txtl, txt)) then return deformat(txtl, txt) end + end + + if not ignoreright then + local txtr = self.vars.Rlines[i]:GetText() + if (txtr and deformat(txtr, txt)) then return deformat(txtr, txt) end + end + end +end + + +-- Returns a table of strings pulled from the tooltip, or nil if no strings in tooltip +-- Args: +-- startln - First tooltip line to check, default 1 +-- endln - Last line to test, default 30 +-- ignoreleft / ignoreright - Causes text on one side of the tooltip to be ignored +function lib:GetText(startln, endln, ignoreleft, ignoreright) + self:InitCompost() + local retval + + for i=(startln or 1),(endln or 30) do + local txtl, txtr + if not ignoreleft then txtl = self.vars.Llines[i]:GetText() end + if not ignoreright then txtr = self.vars.Rlines[i]:GetText() end + if txtl or txtr then + if not retval then retval = self.vars.compost and self.vars.compost:Acquire() or {} end + local t = self.vars.compost and self.vars.compost:Acquire(txtl, txtr) or {txtl, txtr} + table.insert(retval, t) + end + end + + return retval +end + + +-- Returns the text from a specific line (both left and right unless second arg is true) +-- Args: +-- line - the line number you wish to retrieve +-- getright - if passed the right line will be returned, if not the left will be returned +function lib:GetLine(line, getright) + self:argCheck(line, 2, "number") + if self.vars.tooltip:NumLines() < line then return end + if getright then return self.vars.Rlines[line] and self.vars.Rlines[line]:GetText() + elseif self.vars.Llines[line] then + return self.vars.Llines[line]:GetText(), self.vars.Rlines[line]:GetText() + end +end + + +----------------------------------- +-- Set tooltip methods -- +----------------------------------- + +-- These methods are designed to immitate the GameTooltip API +local testmethods = { + SetAction = function(id) return HasAction(id) end, +} +local gettrue = function() return true end +function lib:CreateSetMethods() + for _,m in pairs(methods) do + local meth = m + local func = testmethods[meth] or gettrue + self[meth] = function(self,a1,a2,a3,a4) + self:Erase() + if not func(a1,a2,a3,a4) then return end + return self:pcall(self.vars.tooltip[meth], self.vars.tooltip,a1,a2,a3,a4) end + end +end + + +-------------------------------- +-- Load this bitch! -- +-------------------------------- +AceLibrary:Register(lib, vmajor, vminor, activate) +lib = nil diff --git a/bids.lua b/bids.lua index b5b67e0..47561d6 100644 --- a/bids.lua +++ b/bids.lua @@ -40,7 +40,7 @@ end function sepgp_bids:setHideScript() local detachedFrame, tablet - for i=1,4 do + for i=1,5 do tablet = getglobal(string.format("Tablet20DetachedFrame%d",i)) if tablet and tablet.owner ~= nil and tablet.owner == "sepgp_bids" then if not (tablet:GetScript("OnHide")) then diff --git a/logs.lua b/logs.lua index 0872e48..fe77856 100644 --- a/logs.lua +++ b/logs.lua @@ -45,7 +45,7 @@ end function sepgp_logs:setHideScript() local detachedFrame, tablet - for i=1,4 do + for i=1,5 do tablet = getglobal(string.format("Tablet20DetachedFrame%d",i)) if tablet and tablet.owner ~= nil and tablet.owner == "sepgp_logs" then if not (tablet:GetScript("OnHide")) then diff --git a/loot.lua b/loot.lua new file mode 100644 index 0000000..ddc84d1 --- /dev/null +++ b/loot.lua @@ -0,0 +1,110 @@ +local T = AceLibrary("Tablet-2.0") +local D = AceLibrary("Dewdrop-2.0") +local C = AceLibrary("Crayon-2.0") + +local BC = AceLibrary("Babble-Class-2.2") + +sepgp_loot = sepgp:NewModule("sepgp_loot", "AceDB-2.0") + +function sepgp_loot:OnEnable() + if not T:IsRegistered("sepgp_loot") then + T:Register("sepgp_loot", + "children", function() + T:SetTitle("shootyepgp loot info") + self:OnTooltipUpdate() + end, + "showTitleWhenDetached", true, + "showHintWhenDetached", true, + "cantAttach", true, + "menu", function() + D:AddLine( + "text", "Refresh", + "tooltipText", "Refresh window", + "func", function() sepgp_loot:Refresh() end + ) + D:AddLine( + "text", "Clear", + "tooltipText", "Clear Loot.", + "func", function() sepgp_looted = {} sepgp_loot:Refresh() end + ) + end + ) + end + if not T:IsAttached("sepgp_loot") then + T:Open("sepgp_loot") + end +end + +function sepgp_loot:OnDisable() + T:Close("sepgp_loot") +end + +function sepgp_loot:Refresh() + T:Refresh("sepgp_loot") +end + +function sepgp_loot:setHideScript() + local detachedFrame, tablet + for i=1,5 do + tablet = getglobal(string.format("Tablet20DetachedFrame%d",i)) + if tablet and tablet.owner ~= nil and tablet.owner == "sepgp_loot" then + if not (tablet:GetScript("OnHide")) then + tablet:SetScript("OnHide",function() + if not T:IsAttached("sepgp_loot") then + T:Attach("sepgp_loot") + this:SetScript("OnHide",nil) + end + end) + end + end + end +end + +function sepgp_loot:Toggle(forceShow) + if T:IsAttached("sepgp_loot") then + T:Detach("sepgp_loot") + if (T:IsLocked("sepgp_loot")) then + T:ToggleLocked("sepgp_loot") + end + self:setHideScript() + elseif (forceShow) then + sepgp_loot:Refresh() + else + T:Attach("sepgp_loot") + end +end + +function sepgp_loot:BuildLootTable() + table.sort(sepgp_looted, function(a,b) + if (a[1] ~= b[1]) then return a[1] > b[1] + else return a[2] > b[2] end + end) + return sepgp_looted +end + +function sepgp_loot:OnClickItem(data) + +end + +function sepgp_loot:OnTooltipUpdate() + local cat = T:AddCategory( + "columns", 5, + "text", C:Orange("Time"), "child_textR", 1, "child_textG", 1, "child_textB", 1, "child_justify", "LEFT", + "text2", C:Orange("Item"), "child_text2R", 1, "child_text2G", 1, "child_text2B", 0, "child_justify2", "LEFT", + "text3", C:Orange("Binds"), "child_text3R", 0, "child_text3G", 1, "child_text3B", 0, "child_justify3", "CENTER", + "text4", C:Orange("Looter"), "child_text4R", 0, "child_text4G", 1, "child_text4B", 0, "child_justify4", "RIGHT", + "text5", C:Orange("GP Action"), "child_text5R", 0, "child_text5G", 1, "child_text5B", 0, "child_justify5", "RIGHT" + ) + local t = self:BuildLootTable() + for i = 1, table.getn(t) do + local timestamp,player,player_color,itemLink,bind,price,off_price,action = unpack(t[i]) + cat:AddLine( + "text", timestamp, + "text2", itemLink, + "text3", bind, + "text4", player_color, + "text5", action--, +-- "func", "OnClickItem", "arg1", self, "arg2", t[i] + ) + end +end \ No newline at end of file diff --git a/reserves.lua b/reserves.lua index 7da6be2..8ebb2a9 100644 --- a/reserves.lua +++ b/reserves.lua @@ -40,7 +40,7 @@ end function sepgp_reserves:setHideScript() local detachedFrame, tablet - for i=1,4 do + for i=1,5 do tablet = getglobal(string.format("Tablet20DetachedFrame%d",i)) if tablet and tablet.owner ~= nil and tablet.owner == "sepgp_reserves" then if not (tablet:GetScript("OnHide")) then diff --git a/shootyepgp.lua b/shootyepgp.lua index 6f0fd61..059c2a0 100644 --- a/shootyepgp.lua +++ b/shootyepgp.lua @@ -3,13 +3,24 @@ sepgp:SetModuleMixins("AceDebug-2.0") local D = AceLibrary("Dewdrop-2.0") local BZ = AceLibrary("Babble-Zone-2.2") local C = AceLibrary("Crayon-2.0") +local BC = AceLibrary("Babble-Class-2.2") +local DF = AceLibrary("Deformat-2.0") +local G = AceLibrary("Gratuity-2.0") sepgp.VARS = { basegp = 135, baseaward_ep = 100, decay = 0.85, max = 5000, timeout = 45, - maxloglines = 500 + maxloglines = 500, + prefix = "SEPGP_PREFIX", + bop = C:Red("BoP"), + boe = C:Yellow("BoE"), + nobid = C:White("NoBind"), + msgp = "Mainspec GP", + osgp = "Offspec GP", + bankde = "Bank-D/E", + reminder = C:Red("Unassigned") } local playerName = (UnitName("player")) local shooty_reservechan = "Reserves" @@ -39,21 +50,22 @@ do hexColorQuality[ITEM_QUALITY_COLORS[i].hex] = i end end - +-- TODO: +-- 2. Implement an Import facility to mirror Export. sepgp.reserves = {} +sepgp.bids_main,sepgp.bids_off,sepgp.bid_item = {},{},{} sepgp.timer = CreateFrame("Frame") sepgp.timer.cd_text = "" sepgp.timer:Hide() sepgp.timer:SetScript("OnUpdate",function() sepgp.OnUpdate(this,arg1) end) -sepgp.bids_main,sepgp.bids_off,sepgp.bid_item = {},{},{} - function sepgp:OnInitialize() -- ADDON_LOADED (1) unless LoD if sepgp_saychannel == nil then sepgp_saychannel = "GUILD" end if sepgp_decay == nil then sepgp_decay = sepgp.VARS.decay end if sepgp_progress == nil then sepgp_progress = "T1" end if sepgp_discount == nil then sepgp_discount = 0.25 end if sepgp_log == nil then sepgp_log = {} end + if sepgp_looted == nil then sepgp_looted = {} end sepgp.extratip = CreateFrame("GameTooltip","shootyepgp_tooltip",UIParent,"GameTooltipTemplate") end @@ -87,36 +99,42 @@ function sepgp:AceEvent_FullyInitialized() -- SYNTHETIC EVENT, later than PLAYER -- hook SetItemRef to parse our client bid links self:Hook("SetItemRef") -- hook tooltip to add our GP values - sepgp:TipHook() + self:TipHook() -- hook LootFrameItem_OnClick to add our own click handlers for bid calls self:SecureHook("LootFrameItem_OnClick") + -- hook ContainerFrameItemButton_OnClick to add our own click handlers for bid calls + self:Hook("ContainerFrameItemButton_OnClick") -- hook pfUI loot module :( if pfUI ~= nil and pfUI.loot ~= nil and type(pfUI.loot.UpdateLootFrame) == "function" then self:SecureHook(pfUI.loot, "UpdateLootFrame", "pfUI_UpdateLootFrame") end -- make tablets closable with ESC - for i=1,4 do + for i=1,5 do table.insert(UISpecialFrames,string.format("Tablet20DetachedFrame%d",i)) end - sepgp:RegisterChatCommand({"/shooty","/sepgp","/shootyepgp"},function() sepgp_standings:Toggle() end) + self:RegisterChatCommand({"/shooty","/sepgp","/shootyepgp"},function() sepgp_standings:Toggle() end) end function sepgp:OnEnable() -- PLAYER_LOGIN (2) - sepgp:RegisterEvent("GUILD_ROSTER_UPDATE",function() + self:RegisterEvent("GUILD_ROSTER_UPDATE",function() if (arg1) then -- member join /leave self:SetRefresh(true) end end) - sepgp:RegisterEvent("RAID_ROSTER_UPDATE",function() + self:RegisterEvent("RAID_ROSTER_UPDATE",function() self:SetRefresh(true) end) - sepgp:RegisterEvent("PARTY_MEMBERS_CHANGED",function() + self:RegisterEvent("PARTY_MEMBERS_CHANGED",function() self:SetRefresh(true) end) - sepgp:RegisterEvent("CHAT_MSG_RAID","captureLootCall") - sepgp:RegisterEvent("CHAT_MSG_RAID_LEADER","captureLootCall") - sepgp:RegisterEvent("CHAT_MSG_RAID_WARNING","captureLootCall") - sepgp:RegisterEvent("CHAT_MSG_WHISPER","captureBid") + self:RegisterEvent("CHAT_MSG_RAID","captureLootCall") + self:RegisterEvent("CHAT_MSG_RAID_LEADER","captureLootCall") + self:RegisterEvent("CHAT_MSG_RAID_WARNING","captureLootCall") + self:RegisterEvent("CHAT_MSG_WHISPER","captureBid") + self:RegisterEvent("CHAT_MSG_ADDON","addonComms") + self:RegisterEvent("CHAT_MSG_LOOT","captureLoot") + self:RegisterEvent("TRADE_PLAYER_ITEM_CHANGED","tradeLoot") + self:RegisterEvent("TRADE_ACCEPT_UPDATE","tradeLoot") if (IsInGuild()) then if (GetNumGuildMembers()==0) then @@ -138,9 +156,19 @@ end function sepgp:TipHook() self:SecureHook(GameTooltip, "SetBagItem", function(this, bag, slot) - sepgp:AddDataToTooltip(GameTooltip, GetContainerItemLink(bag, slot)) + local itemLink = GetContainerItemLink(bag, slot) + local ml_tip + if (itemLink) then + local is_master = (sepgp:lootMaster()) and true or nil + local link_found, _, itemColor, itemString, itemName = string.find(itemLink, "^(|c%x+)|H(.+)|h(%[.+%])") + if (link_found) then + local bind = self:itemBinding(itemString) or "" + ml_tip = is_master and bind == sepgp.VARS.boe + end + end + sepgp:AddDataToTooltip(GameTooltip, itemLink, nil, ml_tip) end - ) -- we leave it in for now so they can check if they were billed the correct GP + ) self:SecureHook(GameTooltip, "SetLootItem", function(this, slot) local is_master = (sepgp:lootMaster()) and true or nil sepgp:AddDataToTooltip(GameTooltip, GetLootSlotLink(slot), nil, is_master) @@ -172,7 +200,7 @@ function sepgp:delayedInit() if sepgp_reservechannel == nil then sepgp_reservechannel = shooty_reservechan end local reservesChannelID = tonumber((GetChannelName(sepgp_reservechannel))) if (reservesChannelID) and (reservesChannelID ~= 0) then - sepgp:reservesToggle(true) + self:reservesToggle(true) end -- migrate EPGP storage if needed local _,_,major_ver = string.find((GetAddOnMetadata("shootyepgp","Version")),"^(%d+)%.[%d%.%-]+$") @@ -203,12 +231,12 @@ function sepgp:AddDataToTooltip(tooltip,itemlink,itemstring,is_master) else line_limit = 29 end - local ep,gp = (sepgp:get_ep_v3(playerName) or 0), (sepgp:get_gp_v3(playerName) or sepgp.VARS.basegp) + local ep,gp = (self:get_ep_v3(playerName) or 0), (self:get_gp_v3(playerName) or sepgp.VARS.basegp) local off_price = math.floor(price*sepgp_discount) local pr,new_pr,new_pr_off = ep/gp, ep/(gp+price), ep/(gp+off_price) local pr_delta = new_pr - pr local pr_delta_off = new_pr_off - pr - local textRight = string.format("cost:|cff32cd32%d|r (|cffff0000%.02f|r |cffff7f00pr|r) offspec:|cff20b2aa%d|r (|cffff0000%.02f|r |cffff7f00pr|r)",price,new_pr,off_price,new_pr_off) + local textRight = string.format("gp:|cff32cd32%d|r(|cffff0000%.02f|r|cffff7f00pr|r) os:|cff20b2aa%d|r(|cffff0000%.02f|r|cffff7f00pr|r)",price,new_pr,off_price,new_pr_off) if (tooltip:NumLines() < line_limit) then tooltip:AddLine(" ") tooltip:AddDoubleLine("|cff9664c8shootyepgp|r",textRight) @@ -221,8 +249,9 @@ function sepgp:AddDataToTooltip(tooltip,itemlink,itemstring,is_master) sepgp.extratip:SetOwner(tooltip,"ANCHOR_NONE") sepgp.extratip:ClearAllPoints() sepgp.extratip:SetPoint("TOPLEFT", tooltip, "BOTTOMLEFT", 0, -5) - sepgp.extratip:SetPoint("TOPRIGHT", tooltip, "BOTTOMRIGHT", 0, -5) - sepgp.extratip:AddDoubleLine("|cff9664c8shootyepgp|r",textRight) + --sepgp.extratip:SetPoint("TOPRIGHT", tooltip, "BOTTOMRIGHT", 0, -5) + sepgp.extratip:SetText("|cff9664c8shootyepgp|r") + sepgp.extratip:AddLine(textRight) if (is_master) then sepgp.extratip:AddDoubleLine(left1,right1) end @@ -275,7 +304,7 @@ function sepgp:SetItemRef(link, name, button) else bid = nil end - if not sepgp:inRaid(masterlooter) then + if not self:inRaid(masterlooter) then masterlooter = nil end if (bid and masterlooter) then @@ -288,7 +317,7 @@ function sepgp:SetItemRef(link, name, button) if (strsub(link, 1, 4) == "item") then if (ItemRefTooltip:IsVisible()) then if (not DressUpFrame:IsVisible()) then - sepgp:AddDataToTooltip(ItemRefTooltip, link) + self:AddDataToTooltip(ItemRefTooltip, link) end ItemRefTooltip.isDisplayDone = nil end @@ -297,8 +326,9 @@ function sepgp:SetItemRef(link, name, button) end function sepgp:LootFrameItem_OnClick(button,data) + if not IsAltKeyDown() then return end if not UnitInRaid("player") then return end - if not sepgp:lootMaster() then return end + if not self:lootMaster() then return end local slot, quality if data ~= nil then slot,quality = data:GetID(), data.quality @@ -311,24 +341,56 @@ function sepgp:LootFrameItem_OnClick(button,data) end end if LootSlotIsItem(slot) and quality >= 3 then - if (IsAltKeyDown()) then - local itemLink = GetLootSlotLink(slot) - if (itemLink) then - if button == "LeftButton" then - self:widestAudience(string.format("Whisper + for %s (mainspec)",itemLink)) - --SendChatMessage(string.format("Whisper + for %s (mainspec)",itemLink),"RAID") - elseif button == "RightButton" then - self:widestAudience(string.format("Whisper - for %s (offspec)",itemLink)) - --SendChatMessage(string.format("Whisper - for %s (offspec)",itemLink),"RAID") - elseif button == "MiddleButton" then - self:widestAudience(string.format("Whisper + or - for %s",itemLink)) - --SendChatMessage(string.format("Whisper + or - for %s",itemLink),"RAID") - end + local itemLink = GetLootSlotLink(slot) + if (itemLink) then + if button == "LeftButton" then + self:widestAudience(string.format("Whisper + for %s (mainspec)",itemLink)) + elseif button == "RightButton" then + self:widestAudience(string.format("Whisper - for %s (offspec)",itemLink)) + elseif button == "MiddleButton" then + self:widestAudience(string.format("Whisper + or - for %s",itemLink)) end end end end +function sepgp:ContainerFrameItemButton_OnClick(button,ignoreModifiers) + if not IsAltKeyDown() then + return self.hooks["ContainerFrameItemButton_OnClick"](button,ignoreModifiers) + end + if not UnitInRaid("player") then + return self.hooks["ContainerFrameItemButton_OnClick"](button,ignoreModifiers) + end + if not self:lootMaster() then + return self.hooks["ContainerFrameItemButton_OnClick"](button,ignoreModifiers) + end + if not (this._hasExtraClicks) then + this:RegisterForClicks("LeftButtonUp","RightButtonUp","MiddleButtonUp") + this._hasExtraClicks = true + end + local bag,slot = this:GetParent():GetID(), this:GetID() + local itemLink = GetContainerItemLink(bag, slot) + if (itemLink) then + local link_found, _, itemColor, itemString, itemName = string.find(itemLink, "^(|c%x+)|H(.+)|h(%[.+%])") + if (link_found) then + local bind = self:itemBinding(itemString) or "" + if (bind == self.VARS.boe) then + if button == "LeftButton" then + self:widestAudience(string.format("Whisper + for %s (mainspec)",itemLink)) + return + elseif button == "RightButton" then + self:widestAudience(string.format("Whisper - for %s (offspec)",itemLink)) + return + elseif button == "MiddleButton" then + self:widestAudience(string.format("Whisper + or - for %s",itemLink)) + return + end + end + end + end + return self.hooks["ContainerFrameItemButton_OnClick"](button,ignoreModifiers) +end + function sepgp:pfUI_UpdateLootFrame() for slotid, pflootitem in pairs(pfUI.loot.slots) do if not self:IsHooked(pflootitem,"OnClick") then @@ -356,9 +418,9 @@ end function sepgp:debugPrint(msg) if (shooty_debugchat) then shooty_debugchat:AddMessage(string.format(out,msg)) - sepgp:flashFrame(shooty_debugchat) + self:flashFrame(shooty_debugchat) else - sepgp:defaultPrint(msg) + self:defaultPrint(msg) end end @@ -429,6 +491,45 @@ function sepgp:widestAudience(msg) SendChatMessage(msg, channel) end +function sepgp:addonMessage(message,channel,sender) + SendAddonMessage(self.VARS.prefix,message,channel,sender) +end + +function sepgp:addonComms(prefix,message,channel,sender) + if not prefix == self.VARS.prefix then return end -- we don't care for messages from other addons + if sender == playerName then return end -- we don't care for messages from ourselves + if not self:verifyGuildMember(sender,true) then return end -- only accept messages from guild members + local who,what,amount + for name,epgp,change in string.gfind(message,"([^;]+);([^;]+);([^;]+)") do + who=name + what=epgp + amount=tonumber(change) + end + if (who) and (what) and (amount) then + local msg + if who == playerName then + if what == "EP" then + if amount < 0 then + msg = string.format("You have received a %d EP penalty.",amount) + else + msg = string.format("You have been awarded %d EP.",amount) + end + elseif what == "GP" then + msg = string.format("You have gained %d GP.",amount) + end + elseif who == "ALL" and what == "DECAY" then + msg = string.format("%s%% decay to EP and GP.",amount) + elseif who == "RAID" and what == "AWARD" then + msg = string.format("%d EP awarded to Raid.",amount) + end + if msg and msg~="" then + self:defaultPrint(msg) + local report = self:my_epgp() + self:defaultPrint(report) + end + end +end + --------------------- -- EPGP Operations --------------------- @@ -455,7 +556,7 @@ function sepgp:init_notes_v3(guild_index,name,officernote) return officernote end -function sepgp:update_epgp_v3(ep,gp,guild_index,name,officernote) +function sepgp:update_epgp_v3(ep,gp,guild_index,name,officernote,special_action) officernote = self:init_notes_v3(guild_index,name,officernote) local newnote if (ep) then @@ -485,7 +586,7 @@ function sepgp:update_ep_v2(getname,ep) for i = 1, GetNumGuildMembers(1) do local name, _, _, _, class, _, note, officernote, _, _ = GetGuildRosterInfo(i) if (name==getname) then - sepgp:init_notes_v2(i,note,officernote) + self:init_notes_v2(i,note,officernote) GuildRosterSetPublicNote(i,ep) end end @@ -504,7 +605,7 @@ function sepgp:update_gp_v2(getname,gp) for i = 1, GetNumGuildMembers(1) do local name, _, _, _, class, _, note, officernote, _, _ = GetGuildRosterInfo(i) if (name==getname) then - sepgp:init_notes_v2(i,note,officernote) + self:init_notes_v2(i,note,officernote) GuildRosterSetOfficerNote(i,gp,true) end end @@ -571,22 +672,27 @@ end function sepgp:award_raid_ep(ep) -- awards ep to raid members in zone if GetNumRaidMembers()>0 then - sepgp:simpleSay(string.format("Giving %d ep to all raidmembers",ep)) - self:addToLog(string.format("Giving %d ep to all raidmembers",ep)) for i = 1, GetNumRaidMembers(true) do local name, rank, subgroup, level, class, fileName, zone, online, isDead = GetRaidRosterInfo(i) - sepgp:givename_ep(name,ep) + self:givename_ep(name,ep) end + self:simpleSay(string.format("Giving %d ep to all raidmembers",ep)) + self:addToLog(string.format("Giving %d ep to all raidmembers",ep)) + local addonMsg = string.format("RAID;AWARD;%s",ep) + self:addonMessage(addonMsg,"RAID") else UIErrorsFrame:AddMessage("You aren't in a raid dummy",1,0,0)end end function sepgp:award_reserve_ep(ep) -- awards ep to reserve list - if table.getn(sepgp.shooty_reserves) > 0 then - sepgp:simpleSay(string.format("Giving %d ep to active reserves",ep)) - self:addToLog(string.format("Giving %d ep to active reserves",ep)) - for i, name in ipairs(sepgp.shooty_reserves) do - sepgp:givename_ep(name,ep) + if table.getn(sepgp.reserves) > 0 then + for i, reserve in ipairs(sepgp.reserves) do + local name, class, rank, alt = unpack(reserve[i]) + self:givename_ep(name,ep) end + self:simpleSay(string.format("Giving %d ep to active reserves",ep)) + self:addToLog(string.format("Giving %d ep to active reserves",ep)) + local addonMsg = string.format("RESERVES;AWARD;%s",ep) + self:addonMessage(addonMsg,"GUILD") sepgp.reserves = {} reserves_blacklist = {} end @@ -594,25 +700,29 @@ end function sepgp:givename_ep(getname,ep) -- awards ep to a single character if not (admin()) then return end - sepgp:debugPrint(string.format("Giving %d ep to %s",ep,getname)) - if ep < 0 then -- inform admins of penalties + local newep = ep + (self:get_ep_v3(getname) or 0) --DONE: update v3 + self:update_ep_v3(getname,newep) --DONE: update v3 + self:debugPrint(string.format("Giving %d ep to %s",ep,getname)) + if ep < 0 then -- inform admins and victim of penalties local msg = string.format("%s EP Penalty to %s.",ep,getname) - sepgp:adminSay(msg) + self:adminSay(msg) self:addToLog(msg) - end - ep = ep + (sepgp:get_ep_v3(getname) or 0) --DONE: update v3 - sepgp:update_ep_v3(getname,ep) --DONE: update v3 + local addonMsg = string.format("%s;%s;%s",getname,"EP",ep) + self:addonMessage(addonMsg,"GUILD") + end end function sepgp:givename_gp(getname,gp) -- assigns gp to a single character if not (admin()) then return end - sepgp:debugPrint(string.format("Giving %d gp to %s",gp,getname)) - local oldgp = (sepgp:get_gp_v3(getname) or sepgp.VARS.basegp) --DONE: update v3 + local oldgp = (self:get_gp_v3(getname) or sepgp.VARS.basegp) --DONE: update v3 local newgp = gp + oldgp + self:update_gp_v3(getname,newgp) --DONE: update v3 + self:debugPrint(string.format("Giving %d gp to %s",gp,getname)) local msg = string.format("Awarding %d GP to %s. (Previous: %d, New: %d)",gp,getname,oldgp,math.max(sepgp.VARS.basegp,newgp)) - sepgp:adminSay(msg) + self:adminSay(msg) self:addToLog(msg) - sepgp:update_gp_v3(getname,newgp) --DONE: update v3 + local addonMsg = string.format("%s;%s;%s",getname,"GP",gp) + self:addonMessage(addonMsg,"GUILD") end function sepgp:decay_epgp_v2() -- decays entire roster's ep and gp @@ -628,16 +738,16 @@ function sepgp:decay_epgp_v2() -- decays entire roster's ep and gp self:debugPrint(msg) self:adminSay(msg) else - ep = math.max(0,sepgp:num_round(ep*sepgp_decay)) + ep = math.max(0,self:num_round(ep*sepgp_decay)) GuildRosterSetPublicNote(i,ep) - gp = math.max(sepgp.VARS.basegp,sepgp:num_round(gp*sepgp_decay)) + gp = math.max(sepgp.VARS.basegp,self:num_round(gp*sepgp_decay)) GuildRosterSetOfficerNote(i,gp,true) end end end local msg = string.format("All EP and GP decayed by %d%%",(1-sepgp_decay)*100) - sepgp:simpleSay(msg) - if not (sepgp_saychannel=="OFFICER") then sepgp:adminSay(msg) end + self:simpleSay(msg) + if not (sepgp_saychannel=="OFFICER") then self:adminSay(msg) end self:addToLog(msg) end @@ -647,14 +757,16 @@ function sepgp:decay_epgp_v3() local name,_,_,_,class,_,note,officernote,_,_ = GetGuildRosterInfo(i) local ep,gp = self:get_ep_v3(name,officernote), self:get_gp_v3(name,officernote) if (ep and gp) then - ep = sepgp:num_round(ep*sepgp_decay) - gp = sepgp:num_round(gp*sepgp_decay) - sepgp:update_epgp_v3(ep,gp,i,name,officernote) + ep = self:num_round(ep*sepgp_decay) + gp = self:num_round(gp*sepgp_decay) + self:update_epgp_v3(ep,gp,i,name,officernote) end end local msg = string.format("All EP and GP decayed by %s%%",(1-sepgp_decay)*100) - sepgp:simpleSay(msg) - if not (sepgp_saychannel=="OFFICER") then sepgp:adminSay(msg) end + self:simpleSay(msg) + if not (sepgp_saychannel=="OFFICER") then self:adminSay(msg) end + local addonMsg = string.format("ALL;DECAY;%s",(1-(sepgp_decay or sepgp.VARS.decay))*100) + self:addonMessage(addonMsg,"GUILD") self:addToLog(msg) end @@ -663,7 +775,7 @@ function sepgp:gp_reset_v2() for i = 1, GetNumGuildMembers(1) do GuildRosterSetOfficerNote(i, sepgp.VARS.basegp,true) end - sepgp:debugPrint(string.format("All GP has been reset to %d.",sepgp.VARS.basegp)) + self:debugPrint(string.format("All GP has been reset to %d.",sepgp.VARS.basegp)) self:adminSay(string.format("All GP has been reset to %d.",sepgp.VARS.basegp)) self:addToLog(string.format("All GP has been reset to %d.",sepgp.VARS.basegp)) end @@ -675,16 +787,23 @@ function sepgp:gp_reset_v3() local name,_,_,_,class,_,note,officernote,_,_ = GetGuildRosterInfo(i) local ep,gp = self:get_ep_v3(name,officernote), self:get_gp_v3(name,officernote) if (ep and gp) then - sepgp:update_epgp_v3(0,sepgp.VARS.basegp,i,name,officernote) + self:update_epgp_v3(0,sepgp.VARS.basegp,i,name,officernote) end end local msg = "All EP and GP has been reset to 0/%d." - sepgp:debugPrint(string.format(msg,sepgp.VARS.basegp)) + self:debugPrint(string.format(msg,sepgp.VARS.basegp)) self:adminSay(string.format(msg,sepgp.VARS.basegp)) self:addToLog(string.format(msg,sepgp.VARS.basegp)) end end +function sepgp:my_epgp() + local ep,gp = (self:get_ep_v3(playerName) or 0), (self:get_gp_v3(playerName) or sepgp.VARS.basegp) + local pr = ep/gp + local msg = string.format("You now have: %d EP %d GP |cffffff00%.03f|r|cffff7f00PR|r.", ep,gp,pr) + return msg +end + --------- -- Menu --------- @@ -698,7 +817,7 @@ sepgp.hasIcon = "Interface\\Icons\\INV_Misc_Orb_04" function sepgp:OnTooltipUpdate() local hint = "|cffffff00Click|r to toggle Standings.%s \n|cffffff00Right-Click|r for Options." if (admin()) then - hint = string.format(hint," \n|cffffff00Ctrl+Click|r to toggle Reserves. \n|cffffff00Alt+Click|r to toggle Bids. \n|cffffff00Shift+Click|r to toggle Logs.") + hint = string.format(hint," \n|cffffff00Ctrl+Click|r to toggle Reserves. \n|cffffff00Alt+Click|r to toggle Bids. \n|cffffff00Shift+Click|r to toggle Loot. \n|cffffff00Ctrl+Shift+Click|r to toggle Logs.") else hint = string.format(hint,"") end @@ -712,6 +831,8 @@ function sepgp:OnClick() elseif (IsAltKeyDown() and is_admin) then sepgp_bids:Toggle() elseif (IsShiftKeyDown() and is_admin) then + sepgp_loot:Toggle() + elseif (IsShiftKeyDown() and IsControlKeyDown() and is_admin) then sepgp_logs:Toggle() else sepgp_standings:Toggle() @@ -960,22 +1081,22 @@ function sepgp:reservesToggle(flag) if (reservesChannelID) and reservesChannelID ~= 0 then sepgp.reservesChannelID = reservesChannelID if not self:IsEventRegistered("CHAT_MSG_CHANNEL") then - sepgp:RegisterEvent("CHAT_MSG_CHANNEL","captureReserveChatter") + self:RegisterEvent("CHAT_MSG_CHANNEL","captureReserveChatter") end return true else - sepgp:RegisterEvent("CHAT_MSG_CHANNEL_NOTICE","reservesChannelChange") + self:RegisterEvent("CHAT_MSG_CHANNEL_NOTICE","reservesChannelChange") JoinChannelByName(sepgp_reservechannel) return end else -- we want out if (reservesChannelID) and reservesChannelID ~= 0 then - sepgp:RegisterEvent("CHAT_MSG_CHANNEL_NOTICE","reservesChannelChange") + self:RegisterEvent("CHAT_MSG_CHANNEL_NOTICE","reservesChannelChange") LeaveChannelByName(sepgp_reservechannel) return else - if sepgp:IsEventRegistered("CHAT_MSG_CHANNEL") then - sepgp:UnregisterEvent("CHAT_MSG_CHANNEL") + if self:IsEventRegistered("CHAT_MSG_CHANNEL") then + self:UnregisterEvent("CHAT_MSG_CHANNEL") end return false end @@ -987,14 +1108,14 @@ function sepgp:reservesChannelChange(msg,_,_,_,_,_,_,_,channel) if msg == "YOU_JOINED" then sepgp.reservesChannelID = tonumber((GetChannelName(sepgp_reservechannel))) RemoveChatWindowChannel(DEFAULT_CHAT_FRAME:GetID(), sepgp_reservechannel) - sepgp:RegisterEvent("CHAT_MSG_CHANNEL","captureReserveChatter") + self:RegisterEvent("CHAT_MSG_CHANNEL","captureReserveChatter") elseif msg == "YOU_LEFT" then sepgp.reservesChannelID = nil - if sepgp:IsEventRegistered("CHAT_MSG_CHANNEL") then - sepgp:UnregisterEvent("CHAT_MSG_CHANNEL") + if self:IsEventRegistered("CHAT_MSG_CHANNEL") then + self:UnregisterEvent("CHAT_MSG_CHANNEL") end end - sepgp:UnregisterEvent("CHAT_MSG_CHANNEL_NOTICE") + self:UnregisterEvent("CHAT_MSG_CHANNEL_NOTICE") D:Close() end end @@ -1031,15 +1152,15 @@ function sepgp:captureReserveChatter(text, sender, _, _, _, _, _, _, channel) if (r) and (running_check) then if (rdy) then if (name) and (name ~= "") then - if (not sepgp:inRaid(name)) then - reserve, reserve_class, reserve_rank = sepgp:verifyGuildMember(name) + if (not self:inRaid(name)) then + reserve, reserve_class, reserve_rank = self:verifyGuildMember(name) if reserve ~= sender then reserve_alt = sender end end else - if (not sepgp:inRaid(sender)) then - reserve, reserve_class, reserve_rank = sepgp:verifyGuildMember(sender) + if (not self:inRaid(sender)) then + reserve, reserve_class, reserve_rank = self:verifyGuildMember(sender) end end if reserve and reserve_class and reserve_rank then @@ -1048,14 +1169,14 @@ function sepgp:captureReserveChatter(text, sender, _, _, _, _, _, _, channel) reserves_blacklist[reserve_alt] = true table.insert(sepgp.reserves,{reserve,reserve_class,reserve_rank,reserve_alt}) else - sepgp:defaultPrint(string.format("|cffff0000%s|r trying to add %s to Reserves, but has already added a member. Discarding!",reserve_alt,reserve)) + self:defaultPrint(string.format("|cffff0000%s|r trying to add %s to Reserves, but has already added a member. Discarding!",reserve_alt,reserve)) end else if not reserves_blacklist[reserve] then reserves_blacklist[reserve] = true table.insert(sepgp.reserves,{reserve,reserve_class,reserve_rank}) else - sepgp:defaultPrint(string.format("|cffff0000%s|r has already been added to Reserves. Discarding!",reserve)) + self:defaultPrint(string.format("|cffff0000%s|r has already been added to Reserves. Discarding!",reserve)) end end end @@ -1064,7 +1185,7 @@ function sepgp:captureReserveChatter(text, sender, _, _, _, _, _, _, channel) end local q = string.find(text,"^{shootyepgp}Type") if (q) and not (running_check) then - if (not UnitInRaid("player")) or (not sepgp:inRaid(sender)) then + if (not UnitInRaid("player")) or (not self:inRaid(sender)) then StaticPopup_Show("SHOOTY_EPGP_RESERVE_AFKCHECK_RESPONCE") end end @@ -1133,7 +1254,7 @@ function sepgp:captureLootCall(text, sender) self:debugPrint("Capturing Bids for 5min.") sepgp_bids:Toggle(true) end - sepgp:bidPrint(itemLink,sender,mskw_found,oskw_found,whisperkw_found) + self:bidPrint(itemLink,sender,mskw_found,oskw_found,whisperkw_found) end end end @@ -1182,7 +1303,7 @@ end function sepgp:clearBids(reset) if reset~=nil then - sepgp:debugPrint("Clearing old Bids") + self:debugPrint("Clearing old Bids") end sepgp.bid_item = {} sepgp.bids_main = {} @@ -1196,10 +1317,150 @@ function sepgp:clearBids(reset) sepgp_bids:Refresh() end +---------------- +-- Loot Tracker +---------------- +-- test: "You receive loot: \124cffa335ee\124Hitem:16866:0:0:0\124h[Helm of Might]\124h\124r." +-- test: "Raerlas receives loot: \124cffa335ee\124Hitem:16846:0:0:0\124h[Giantstalker's Helmet]\124h\124r." +sepgp.loot_index = { + time=1, + player=2, + player_c=3, + item=4, + bind=5, + price=6, + off_price=7, + action=8, + update=9 +} +function sepgp:captureLoot(message) + if not (UnitInRaid("player") and self:lootMaster()) then return end + local who,what,amount,player,itemLink + who,what,amount = DF:Deformat(message,LOOT_ITEM_MULTIPLE) + if (amount) then -- skip multiples / stacks + else + player, itemLink = DF:Deformat(message,LOOT_ITEM) + end + who,what,amount = YOU, DF:Deformat(message,LOOT_ITEM_SELF_MULTIPLE) + if (amount) then -- skip multiples / stacks + else + if not (player and itemLink) then + player, itemLink = YOU, DF:Deformat(message,LOOT_ITEM_SELF) + end + end + if not (player and itemLink) then return end + local link_found, _, itemColor, itemString, itemName = string.find(itemLink, "^(|c%x+)|H(.+)|h(%[.+%])") + if player and itemLink and link_found then + local bind = self:itemBinding(itemString) + if not (bind) then return end + local price = sepgp_prices:GetPrice(itemString,sepgp_progress) + if not (price) or price == 0 then + return + end + local class,_ + if player == YOU then + class = UnitClass("player") -- localized + else + _, class = self:verifyGuildMember(player,true) -- localized + end + if not (class) then return end + local player_color = C:Colorize(BC:GetHexColor(class),player) + local off_price = math.floor(price*sepgp_discount) + local quality = hexColorQuality[itemColor] or -1 + local timestamp = date("%b/%d %H:%M:%S") + local data = {[self.loot_index.time]=timestamp,[self.loot_index.player]=player,[self.loot_index.player_c]=player_color,[self.loot_index.item]=itemLink,[self.loot_index.bind]=bind,[self.loot_index.price]=price,[self.loot_index.off_price]=off_price} + local dialog = StaticPopup_Show("SHOOTY_EPGP_AUTO_GEARPOINTS",data[self.loot_index.player_c],data[self.loot_index.item],data) + if (dialog) then + dialog.data = data + end + end +end + +function sepgp:findLootReminder(itemLink) + for i,data in ipairs(sepgp_looted) do + if data[self.loot_index.item] == itemLink --[[and data[self.loot_index.action] == self.VARS.reminder]] then + return data + end + end +end + +function sepgp:tradeLoot(playerState,targetState) + if not (UnitInRaid("player") and self:lootMaster()) then return end + if (playerState ~= nil and targetState ~= nil) and playerState == 1 and targetState == 1 then + local itemLink + for id=1,MAX_TRADABLE_ITEMS do + itemLink = GetTradePlayerItemLink(id) + if (itemLink) then + break + end + end + if (itemLink) then + local link_found, _, itemColor, itemString, itemName = string.find(itemLink, "^(|c%x+)|H(.+)|h(%[.+%])") + if (link_found) then + local price = sepgp_prices:GetPrice(itemString,sepgp_progress) + if not (price) or price == 0 then + return + end + local bind = self:itemBinding(itemString) + if (not bind) or (bind ~= self.VARS.boe) then return end + if UnitExists("target") and UnitIsPlayer("target") and UnitCanCooperate("target") and (not UnitIsUnit("player","target")) then + local tradeTarget = UnitName("target") + local _, class = self:verifyGuildMember(tradeTarget,true) + if not (class) then return end + local target_color = C:Colorize(BC:GetHexColor(class),tradeTarget) + local timestamp = date("%b/%d %H:%M:%S") + local data = self:findLootReminder(itemLink) -- verify that it updates the data in the referenced table and not creating a copy + if (data) then + data[self.loot_index.time] = timestamp + data[self.loot_index.player] = tradeTarget + data[self.loot_index.player_c] = target_color + data[self.loot_index.update] = 1 + local dialog = StaticPopup_Show("SHOOTY_EPGP_AUTO_GEARPOINTS",data[self.loot_index.player_c],data[self.loot_index.item],data) + if (dialog) then + dialog.data = data + end + end + end + end + end + end +end + +sepgp.item_bind_patterns = { + CRAFT = "("..ITEM_SPELL_TRIGGER_ONUSE..")", + BOP = "("..ITEM_BIND_ON_PICKUP..")", + QUEST = "("..ITEM_BIND_QUEST..")", + BOU = "("..ITEM_BIND_ON_EQUIP..")", + BOE = "("..ITEM_BIND_ON_USE..")" +} +function sepgp:itemBinding(item) + G:SetHyperlink(item) + if G:Find(self.item_bind_patterns.CRAFT,2,4,nil,true) then + else + if G:Find(self.item_bind_patterns.BOP,2,4,nil,true) then + return sepgp.VARS.bop + elseif G:Find(self.item_bind_patterns.QUEST,2,4,nil,true) then + return sepgp.VARS.bop + elseif G:Find(self.item_bind_patterns.BOE,2,4,nil,true) then + return sepgp.VARS.boe + elseif G:Find(self.item_bind_patterns.BOU,2,4,nil,true) then + return sepgp.VARS.boe + else + return sepgp.VARS.nobind + end + end + return +end + +function sepgp:addOrUpdateLoot(data,update) + if not (update) then + table.insert(sepgp_looted,data) + end +end + ------------ -- Logging ------------ - function sepgp:addToLog(line,skipTime) local over = table.getn(sepgp_log)-sepgp.VARS.maxloglines+1 if over > 0 then @@ -1223,15 +1484,15 @@ function sepgp:num_round(i) return math.floor(i+0.5) end -function sepgp:verifyGuildMember(name) +function sepgp:verifyGuildMember(name,silent) for i=1,GetNumGuildMembers(1) do local g_name, g_rank, g_rankIndex, g_level, g_class, g_zone, g_note, g_officernote, g_online = GetGuildRosterInfo(i) if (string.lower(name) == string.lower(g_name)) and (tonumber(g_level) == MAX_PLAYER_LEVEL) then return g_name, g_class, g_rank end end - if (name) and name ~= "" then - sepgp:defaultPrint(string.format("%s not found in the guild or not max level!",name)) + if (name) and name ~= "" and not (silent) then + self:defaultPrint(string.format("%s not found in the guild or not max level!",name)) end return end @@ -1304,6 +1565,7 @@ end ------------- -- Dialogs ------------- + StaticPopupDialogs["SHOOTY_EPGP_SET_MAIN"] = { text = "Set your main to be able to participate in Reserve List EPGP Checks.", button1 = TEXT(ACCEPT), @@ -1362,4 +1624,92 @@ StaticPopupDialogs["SHOOTY_EPGP_CONFIRM_RESET"] = { exclusive = 1, showAlert = 1, hideOnEscape = 1 -}; +} + +local sepgp_auto_gp_menu = { + --{text = "Choose an Action", isTitle = true}, + {text = "Add MainSpec GP", func = function() + local dialog = StaticPopup_FindVisible("SHOOTY_EPGP_AUTO_GEARPOINTS") + if (dialog) then + local data = dialog.data + local player, price = data[sepgp.loot_index.player], data[sepgp.loot_index.price] + sepgp:givename_gp((player==YOU and playerName or player),price) + data[sepgp.loot_index.action] = sepgp.VARS.msgp + local update = data[sepgp.loot_index.update] ~= nil + sepgp:addOrUpdateLoot(data,update) + StaticPopup_Hide("SHOOTY_EPGP_AUTO_GEARPOINTS") + sepgp_loot:Refresh() + end + end}, + {text = "Add OffSpec GP", func = function() + local dialog = StaticPopup_FindVisible("SHOOTY_EPGP_AUTO_GEARPOINTS") + if (dialog) then + local data = dialog.data + local player, off_price = data[sepgp.loot_index.player], data[sepgp.loot_index.off_price] + sepgp:givename_gp((player==YOU and playerName or player),off_price) + data[sepgp.loot_index.action] = sepgp.VARS.osgp + local update = data[sepgp.loot_index.update] ~= nil + sepgp:addOrUpdateLoot(data,update) + StaticPopup_Hide("SHOOTY_EPGP_AUTO_GEARPOINTS") + sepgp_loot:Refresh() + end + end}, + {text = "Bank or D/E", func = function() + local dialog = StaticPopup_FindVisible("SHOOTY_EPGP_AUTO_GEARPOINTS") + if (dialog) then + local data = dialog.data + data[sepgp.loot_index.action] = sepgp.VARS.bankde + local update = data[sepgp.loot_index.update] ~= nil + sepgp:addOrUpdateLoot(data,update) + StaticPopup_Hide("SHOOTY_EPGP_AUTO_GEARPOINTS") + sepgp_loot:Refresh() + end + end} +} +StaticPopupDialogs["SHOOTY_EPGP_AUTO_GEARPOINTS"] = { + text = "%s looted %s. What do you want to do?", + button1 = "GP Actions", + button2 = "Remind me Later", + OnAccept = function() + sepgp:EasyMenu(sepgp_auto_gp_menu, this:GetParent().menuFrame, this, 0, 0, "MENU") + return true + end, + OnCancel = function(data,reason) + if reason == "override" or reason == "clicked" then + data[sepgp.loot_index.action] = sepgp.VARS.reminder + local update = data[sepgp.loot_index.update] ~= nil + sepgp:addOrUpdateLoot(data,update) + sepgp_loot:Refresh() + return + elseif reason == "timeout" then + return + end + end, + OnShow = function() + this.menuFrame = this.menuFrame or CreateFrame("Frame", "sepgp_auto_gp_menuframe", UIParent, "UIDropDownMenuTemplate") + end, + OnHide = function() + CloseDropDownMenus() + end, + timeout = 0, + exclusive = 1, + whileDead = 0, + hideOnEscape = 1 +} + +function sepgp:EasyMenu(menuList, menuFrame, anchor, x, y, displayMode) + if ( displayMode == "MENU" ) then + menuFrame.displayMode = displayMode + end + UIDropDownMenu_Initialize(menuFrame, function() sepgp:EasyMenu_Initialize(level, menuList) end, displayMode, nil, menuList) + ToggleDropDownMenu(1, nil, menuFrame, anchor, x, y, menuList) +end +function sepgp:EasyMenu_Initialize(level, menuList) + for index = 1, table.getn( menuList ) do + value = menuList[index] + if (value.text) then + value.index = index; + UIDropDownMenu_AddButton( value, level ); + end + end +end \ No newline at end of file diff --git a/shootyepgp.toc b/shootyepgp.toc index a2b8599..edb0f15 100644 --- a/shootyepgp.toc +++ b/shootyepgp.toc @@ -2,11 +2,11 @@ ## Title: shootyepgp ## Notes: Effort Points/Gear Points Loot System ## Author: Roadblock -## X-Credits: shooty for original version -## Version: 3.16 +## X-Credits: shooty +## Version: 3.17 ## OptionalDeps: Ace2 ## SavedVariables: sepgp_saychannel,sepgp_groupbyclass,sepgp_raidonly,sepgp_decay,sepgp_reservechannel,sepgp_main,sepgp_progress,sepgp_discount -## SavedVariablesPerCharacter: sepgp_log, sepgp_dbver +## SavedVariablesPerCharacter: sepgp_log, sepgp_dbver, sepgp_looted Libs\AceLibrary\AceLibrary.lua Libs\AceOO-2.0\AceOO-2.0.lua @@ -19,18 +19,21 @@ Libs\AceDB-2.0\AceDB-2.0.lua Libs\AceDebug-2.0\AceDebug-2.0.lua Libs\AceLocale-2.2\AceLocale-2.2.lua +Libs\Deformat-2.0\Deformat-2.0.lua Libs\Babble-Class-2.2\Babble-Class-2.2.lua Libs\Babble-Zone-2.2\Babble-Zone-2.2.lua Libs\Crayon-2.0\Crayon-2.0.lua Libs\Compost-2.0\Compost-2.0.lua Libs\Dewdrop-2.0\Dewdrop-2.0.lua -Libs\FuBarPlugin-2.0\FuBarPlugin-2.0.lua Libs\Tablet-2.0\Tablet-2.0.lua +Libs\Gratuity-2.0\Gratuity-2.0.lua +Libs\FuBarPlugin-2.0\FuBarPlugin-2.0.lua shootyepgp.lua migrations.lua -standings.lua -reserves.lua -bids.lua prices.lua +standings.lua +bids.lua +loot.lua +reserves.lua logs.lua \ No newline at end of file diff --git a/standings.lua b/standings.lua index b40d42b..c35d4b3 100644 --- a/standings.lua +++ b/standings.lua @@ -124,7 +124,7 @@ end function sepgp_standings:setHideScript() local detachedFrame, tablet - for i=1,4 do + for i=1,5 do tablet = getglobal(string.format("Tablet20DetachedFrame%d",i)) if tablet and tablet.owner ~= nil and tablet.owner == "sepgp_standings" then if not (tablet:GetScript("OnHide")) then