diff --git a/shootyepgp.lua b/shootyepgp.lua index ab35165..1b6c775 100644 --- a/shootyepgp.lua +++ b/shootyepgp.lua @@ -7,9 +7,9 @@ local BC = AceLibrary("Babble-Class-2.2") local DF = AceLibrary("Deformat-2.0") local G = AceLibrary("Gratuity-2.0") sepgp.VARS = { - basegp = 135, + basegp = 100, baseaward_ep = 100, - decay = 0.85, + decay = 0.9, max = 5000, timeout = 60, maxloglines = 500, @@ -22,7 +22,7 @@ sepgp.VARS = { bankde = "Bank-D/E", reminder = C:Red("Unassigned"), } -local playerName = (UnitName("player")) +sepgp._playerName = (UnitName("player")) local shooty_reservechan = "Reserves" local shooty_reservecall = string.format("{shootyepgp}Type \"+\" if on main, or \"+\" (without quotes) if on alt within %dsec.",sepgp.VARS.timeout) local shooty_reserveanswer = "^(%+)(%a*)$" @@ -50,8 +50,7 @@ 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") @@ -260,20 +259,22 @@ function sepgp:AddDataToTooltip(tooltip,itemlink,itemstring,is_master) if not price then return end local line_limit, left1,right1 if (is_master) then - line_limit = 28 + line_limit = 27 left1,right1 = C:Yellow("Alt Click/RClick/MClick"), C:Orange("Call for: MS/OS/Both") else - line_limit = 29 + line_limit = 28 end - local ep,gp = (self:get_ep_v3(playerName) or 0), (self:get_gp_v3(playerName) or sepgp.VARS.basegp) + local ep,gp = (self:get_ep_v3(self._playerName) or 0), (self:get_gp_v3(self._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("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) + local textRight = string.format("gp:|cff32cd32%d|r gp_os:|cff20b2aa%d|r",price,off_price) + local textRight2 = string.format("pr:|cffff0000%.02f|r(%.02f) pr_os:|cffff0000%.02f|r(%.02f)",pr_delta,new_pr,pr_delta_off,new_pr_off) if (tooltip:NumLines() < line_limit) then tooltip:AddLine(" ") tooltip:AddDoubleLine("|cff9664c8shootyepgp|r",textRight) + tooltip:AddDoubleLine(" ",textRight2) if (is_master) then tooltip:AddDoubleLine(left1,right1) end @@ -285,7 +286,8 @@ function sepgp:AddDataToTooltip(tooltip,itemlink,itemstring,is_master) sepgp.extratip:SetPoint("TOPLEFT", tooltip, "BOTTOMLEFT", 0, -5) --sepgp.extratip:SetPoint("TOPRIGHT", tooltip, "BOTTOMRIGHT", 0, -5) sepgp.extratip:SetText("|cff9664c8shootyepgp|r") - sepgp.extratip:AddLine(textRight) + sepgp.extratip:AddDoubleLine(" ",textRight) + sepgp.extratip:AddDoubleLine(" ",textRight2) if (is_master) then sepgp.extratip:AddDoubleLine(left1,right1) end @@ -531,7 +533,7 @@ 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 sender == self._playerName then return end -- we don't care for messages from ourselves local name_g,class,rank = self:verifyGuildMember(sender,true) if not (name_g) then return end -- only accept messages from guild members local who,what,amount @@ -542,7 +544,7 @@ function sepgp:addonComms(prefix,message,channel,sender) end if (who) and (what) and (amount) then local msg - if who == playerName then + if who == self._playerName then if what == "EP" then if amount < 0 then msg = string.format("You have received a %d EP penalty.",amount) @@ -886,16 +888,41 @@ function sepgp:gp_reset_v3() end end +function sepgp:capcalc(ep,gp,gain) + -- CAP_EP = EP_GAIN*DECAY/(1-DECAY) CAP_PR = CAP_EP/base_gp + local pr = ep/gp + local ep_decayed = self:num_round(ep*sepgp_decay) + local gp_decayed = math.max(sepgp.VARS.basegp,self:num_round(gp*sepgp_decay)) + local pr_decay = tonumber(string.format("%.03f",pr))-tonumber(string.format("%.03f",ep_decayed/gp_decayed)) + if pr_decay < 0.01 then + pr_decay = 0 + else + pr_decay = -tonumber(string.format("%.02f",pr_decay)) + end + local cycle_gain = tonumber(gain) + local cap_ep, cap_pr + if (cycle_gain) then + cap_ep = self:num_round(cycle_gain*sepgp_decay/(1-sepgp_decay)) + cap_pr = tonumber(string.format("%.03f",cap_ep/sepgp.VARS.basegp)) + end + return pr_decay, cap_ep, cap_pr +end + function sepgp:my_epgp_announce() - local ep,gp = (self:get_ep_v3(playerName) or 0), (self:get_gp_v3(playerName) or sepgp.VARS.basegp) + local ep,gp = (self:get_ep_v3(self._playerName) or 0), (self:get_gp_v3(self._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) self:defaultPrint(msg) + local pr_decay, cap_ep, cap_pr = self:capcalc(ep,gp) + if pr_decay < 0 then + msg = string.format("Close to EPGP Cap. Next Decay will change your |cffff7f00PR|r by |cffff0000%.4g|r.",pr_decay) + self:defaultPrint(msg) + end end function sepgp:my_epgp() GuildRoster() - self:ScheduleEvent("shootyepgpRosterRefresh",self.my_epgp_announce,2,self) + self:ScheduleEvent("shootyepgpRosterRefresh",self.my_epgp_announce,3,self) end --------- @@ -1244,7 +1271,7 @@ end function sepgp:sendReserverResponce() if sepgp.reservesChannelID ~= nil then if (sepgp_main) then - if sepgp_main == playerName then + if sepgp_main == self._playerName then SendChatMessage("+","CHANNEL",nil,sepgp.reservesChannelID) else SendChatMessage(string.format("+%s",sepgp_main),"CHANNEL",nil,sepgp.reservesChannelID) @@ -1352,7 +1379,7 @@ function sepgp:captureLootCall(text, sender) if (link_found) then local quality = hexColorQuality[itemColor] or -1 if (quality >= 3) then - if (IsRaidLeader() or self:lootMaster()) and (sender == playerName) then + if (IsRaidLeader() or self:lootMaster()) and (sender == self._playerName) then self:clearBids(true) sepgp.bid_item.link = itemString sepgp.bid_item.linkFull = itemLink @@ -1594,6 +1621,13 @@ function sepgp:num_round(i) return math.floor(i+0.5) end +function sepgp:strsplit(delimiter, subject) + local delimiter, fields = delimiter or ":", {} + local pattern = string.format("([^%s]+)", delimiter) + string.gsub(subject, pattern, function(c) fields[table.getn(fields)+1] = c end) + return unpack(fields) +end + 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) @@ -1791,7 +1825,7 @@ local sepgp_auto_gp_menu = { 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) + sepgp:givename_gp((player==YOU and sepgp._playerName or player),price) data[sepgp.loot_index.action] = sepgp.VARS.msgp local update = data[sepgp.loot_index.update] ~= nil sepgp:addOrUpdateLoot(data,update) @@ -1804,7 +1838,7 @@ local sepgp_auto_gp_menu = { 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) + sepgp:givename_gp((player==YOU and sepgp._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) @@ -1873,4 +1907,4 @@ function sepgp:EasyMenu_Initialize(level, menuList) end -- GLOBALS: sepgp_saychannel,sepgp_groupbyclass,sepgp_raidonly,sepgp_decay,sepgp_reservechannel,sepgp_main,sepgp_progress,sepgp_discount,sepgp_log,sepgp_dbver,sepgp_looted --- GLOBALS: sepgp,sepgp_prices,sepgp_standings,sepgp_bids,sepgp_loot,sepgp_reserves,sepgp_logs \ No newline at end of file +-- GLOBALS: sepgp,sepgp_prices,sepgp_standings,sepgp_bids,sepgp_loot,sepgp_reserves,sepgp_logs diff --git a/shootyepgp.toc b/shootyepgp.toc index b4654e3..1060774 100644 --- a/shootyepgp.toc +++ b/shootyepgp.toc @@ -5,10 +5,11 @@ ## X-Website: https://github.com/Road-block/shootyepgp/releases/latest ## X-Category: Guild ## X-Credits: shooty -## Version: 3.21.2 +## Version: 3.30 +## X-Alpha: ## OptionalDeps: Ace2 -## SavedVariables: sepgp_saychannel,sepgp_groupbyclass,sepgp_raidonly,sepgp_decay,sepgp_reservechannel,sepgp_main,sepgp_progress,sepgp_discount -## SavedVariablesPerCharacter: sepgp_log, sepgp_dbver, sepgp_looted +## SavedVariables: sepgp_saychannel, sepgp_groupbyclass, sepgp_raidonly, sepgp_dbver +## SavedVariablesPerCharacter: sepgp_main, sepgp_log, sepgp_looted, sepgp_decay, sepgp_reservechannel, sepgp_progress, sepgp_discount Libs\AceLibrary\AceLibrary.lua Libs\AceOO-2.0\AceOO-2.0.lua @@ -38,4 +39,4 @@ standings.lua bids.lua loot.lua reserves.lua -logs.lua \ No newline at end of file +logs.lua diff --git a/standings.lua b/standings.lua index 3608d72..0041a12 100644 --- a/standings.lua +++ b/standings.lua @@ -21,13 +21,19 @@ shooty_export:SetBackdrop({ }) shooty_export:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b) shooty_export:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b) +shooty_export.action = CreateFrame("Button","shooty_exportaction", shooty_export, "UIPanelButtonTemplate") +shooty_export.action:SetWidth(100) +shooty_export.action:SetHeight(22) +shooty_export.action:SetPoint("BOTTOM",0,-20) +shooty_export.action:SetText("Import") +shooty_export.action:Hide() +shooty_export.action:SetScript("OnClick",function() sepgp_standings.import() end) shooty_export.title = shooty_export:CreateFontString(nil,"OVERLAY") shooty_export.title:SetPoint("TOP",0,-5) shooty_export.title:SetFont("Fonts\\FRIZQT__.TTF", 12) shooty_export.title:SetWidth(200) shooty_export.title:SetJustifyH("LEFT") shooty_export.title:SetJustifyV("CENTER") -shooty_export.title:SetText(C:Gold("Ctrl-C to copy. Esc to close.")) shooty_export.title:SetShadowOffset(1, -1) shooty_export.edit = CreateFrame("EditBox", "shooty_exportedit", shooty_export) shooty_export.edit:SetMultiLine(true) @@ -42,6 +48,12 @@ shooty_export.edit:SetScript("OnEscapePressed", function() shooty_export.edit:SetText("") shooty_export:Hide() end) +shooty_export.edit:SetScript("OnEditFocusGained", function() + shooty_export.edit:HighlightText() +end) +shooty_export.edit:SetScript("OnCursorChanged", function() + shooty_export.edit:HighlightText() +end) shooty_export.AddSelectText = function(txt) shooty_export.edit:SetText(txt) shooty_export.edit:HighlightText() @@ -52,6 +64,78 @@ shooty_export.scroll:SetPoint('BOTTOMRIGHT', shooty_export, 'BOTTOMRIGHT', -30, shooty_export.scroll:SetScrollChild(shooty_export.edit) table.insert(UISpecialFrames,"shooty_exportframe") +function sepgp_standings:Export() + shooty_export.action:Hide() + shooty_export.title:SetText(C:Gold("Ctrl-C to copy. Esc to close.")) + local t = {} + for i = 1, GetNumGuildMembers(1) do + local name, _, _, _, class, _, note, officernote, _, _ = GetGuildRosterInfo(i) + local ep = (sepgp:get_ep_v3(name,officernote) or 0) --DONE: update v3 + local gp = (sepgp:get_gp_v3(name,officernote) or sepgp.VARS.basegp) --DONE: update v3 + if ep > 0 then + table.insert(t,{name,ep,gp,ep/gp}) + end + end + table.sort(t, function(a,b) + return tonumber(a[4]) > tonumber(b[4]) + end) + shooty_export:Show() + local txt = "Name;EP;GP;PR\n" + for i,val in ipairs(t) do + txt = string.format("%s%s;%d;%d;%.4f\n",txt,val[1],val[2],val[3],val[4]) + end + shooty_export.AddSelectText(txt) +end + +function sepgp_standings:Import() + if not IsGuildLeader() then return end + shooty_export.action:Show() + shooty_export.title:SetText(C:Red("Ctrl-V to paste data. Esc to close.")) + shooty_export.AddSelectText([[Warning: +Import overwrites all existing EPGP values. + +Paste all the csv data here replacing this text, +then hit Import. +Results will print here when done.]]) + shooty_export:Show() +end + +function sepgp_standings.import() + if not IsGuildLeader() then return end + local text = shooty_export.edit:GetText() + local t = {} + local found + for line in string.gfind(text,"[^\r\n]+") do + local name,ep,gp,pr = sepgp:strsplit(";",line) + ep,gp,pr = tonumber(ep),tonumber(gp),tonumber(pr) + if (name) and (ep) and (gp) and (pr) then + t[name]={ep,gp} + found = true + end + end + if (found) then + local count = 0 + shooty_export.edit:SetText("") + for i=1,GetNumGuildMembers(1) do + local name, _, _, _, class, _, note, officernote, _, _ = GetGuildRosterInfo(i) + local name_epgp = t[name] + if (name_epgp) then + count = count + 1 + --sepgp:debugPrint(string.format("%s {%s:%s}",name,name_epgp[1],name_epgp[2])) -- Debug + sepgp:update_epgp_v3(name_epgp[1],name_epgp[2],i,name,officernote) + t[name]=nil + end + end + sepgp:defaultPrint(string.format("Imported %d members.",count)) + local report = string.format("Imported %d members.\n",count) + report = string.format("%s\nFailed to import:",report) + for name,epgp in pairs(t) do + report = string.format("%s%s {%s:%s}\n",report,name,t[1],t[2]) + end + shooty_export.AddSelectText(report) + end +end + function sepgp_standings:OnEnable() if not T:IsRegistered("sepgp_standings") then T:Register("sepgp_standings", @@ -85,6 +169,13 @@ function sepgp_standings:OnEnable() "tooltipText", "Export standings to csv.", "func", function() sepgp_standings:Export() end ) + if IsGuildLeader() then + D:AddLine( + "text", "Import", + "tooltipText", "Import standings from csv.", + "func", function() sepgp_standings:Import() end + ) + end end ) end @@ -101,27 +192,6 @@ function sepgp_standings:Refresh() T:Refresh("sepgp_standings") end -function sepgp_standings:Export() - local t = {} - for i = 1, GetNumGuildMembers(1) do - local name, _, _, _, class, _, note, officernote, _, _ = GetGuildRosterInfo(i) - local ep = (sepgp:get_ep_v3(name,officernote) or 0) --DONE: update v3 - local gp = (sepgp:get_gp_v3(name,officernote) or sepgp.VARS.basegp) --DONE: update v3 - if ep > 0 then - table.insert(t,{name,ep,gp,ep/gp}) - end - end - table.sort(t, function(a,b) - return tonumber(a[4]) > tonumber(b[4]) - end) - shooty_export:Show() - local txt = "Name;EP;GP;PR\n" - for i,val in ipairs(t) do - txt = string.format("%s%s;%d;%d;%.4f\n",txt,val[1],val[2],val[3],val[4]) - end - shooty_export.AddSelectText(txt) -end - function sepgp_standings:setHideScript() local detachedFrame, tablet for i=1,5 do @@ -212,11 +282,22 @@ function sepgp_standings:OnTooltipUpdate() local t = self:BuildStandingsTable() for i = 1, table.getn(t) do local name, class, ep, gp, pr = unpack(t[i]) + local text = C:Colorize(BC:GetHexColor(class), name) + local text2 = string.format("%.4g", ep) + local text3 = string.format("%.4g", gp) + local text4 = string.format("%.4g", pr) + if (sepgp._playerName) and sepgp._playerName == name then + text = string.format("(*)%s",text) + local pr_decay = sepgp:capcalc(ep,gp) + if pr_decay < 0 then + text4 = string.format("%s(|cffff0000%.4g|r)",text4,pr_decay) + end + end cat:AddLine( - "text", C:Colorize(BC:GetHexColor(class), name), - "text2", string.format("%.4g", ep), - "text3", string.format("%.4g", gp), - "text4", string.format("%.4g", pr) + "text", text, + "text2", text2, + "text3", text3, + "text4", text4 ) end end