Standings list (for members) and other lists (for admins) can now be dismissed with Esc. Add log window for admins. Better permission checking, confirmation dialog for some important actions. Fix Bid detection regex false positives eg.[Elixir of Mongoose]. Remove a bunch of menus and windows for members that they never use.
1033 lines
33 KiB
Lua
1033 lines
33 KiB
Lua
sepgp = AceLibrary("AceAddon-2.0"):new("AceConsole-2.0", "AceHook-2.1", "AceDB-2.0", "AceDebug-2.0", "AceEvent-2.0", "AceModuleCore-2.0", "FuBarPlugin-2.0")
|
|
sepgp:SetModuleMixins("AceDebug-2.0")
|
|
local D = AceLibrary("Dewdrop-2.0")
|
|
local BZ = AceLibrary("Babble-Zone-2.2")
|
|
|
|
local playerName = (UnitName("player"))
|
|
local shooty_basegp = 135
|
|
local shooty_baseaward_ep = 100
|
|
local shooty_decay = 0.85
|
|
local shooty_max = 5000
|
|
local shooty_timeout = 45
|
|
local shooty_maxloglines = 300
|
|
local shooty_reservechan = "Reserves"
|
|
local shooty_reservecall = string.format("{shootyepgp}Type \"+\" in this channel if on main, or \"+<MainName>\" if on alt within %dsec.",shooty_timeout)
|
|
local shooty_reserveanswer = "^(%+)(%a*)$"
|
|
local out = "|cff9664c8shootyepgp:|r %s"
|
|
local lastUpdate = 0
|
|
local needInit = true
|
|
local admin
|
|
local shooty_debugchat
|
|
local running_check,running_bid
|
|
local partyUnit,raidUnit = {},{}
|
|
local reserves_blacklist,bids_blacklist = {},{}
|
|
do
|
|
for i=1,40 do
|
|
raidUnit[i] = "raid"..i
|
|
end
|
|
for i=1,4 do
|
|
partyUnit[i] = "party"..i
|
|
end
|
|
end
|
|
|
|
sepgp.reserves = {}
|
|
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 = shooty_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
|
|
sepgp.extratip = CreateFrame("GameTooltip","shootyepgp_tooltip",UIParent,"GameTooltipTemplate")
|
|
end
|
|
|
|
function sepgp:AceEvent_FullyInitialized() -- SYNTHETIC EVENT, later than PLAYER_LOGIN, PLAYER_ENTERING_WORLD (3)
|
|
for i=1,NUM_CHAT_WINDOWS do
|
|
local tab = getglobal("ChatFrame"..i.."Tab")
|
|
local cf = getglobal("ChatFrame"..i)
|
|
local tabName = tab:GetText()
|
|
if tab ~= nil and (string.lower(tabName) == "debug") then
|
|
shooty_debugchat = cf
|
|
ChatFrame_RemoveAllMessageGroups(shooty_debugchat)
|
|
shooty_debugchat:SetMaxLines(1024)
|
|
break
|
|
end
|
|
end
|
|
|
|
if (not sepgp_main) or (sepgp_main == "") then
|
|
StaticPopup_Show("SHOOTY_EPGP_SET_MAIN")
|
|
end
|
|
|
|
if not self:IsEventScheduled("shootyepgpChannelInit") then
|
|
self:ScheduleEvent("shootyepgpChannelInit",self.getReserveStatus,2,self)
|
|
end
|
|
|
|
-- if pfUI loaded, skin the extra tooltip
|
|
if (pfUI) and pfUI.api and pfUI.api.CreateBackdrop and pfUI_config and pfUI_config.tooltip and pfUI_config.tooltip.alpha then
|
|
pfUI.api.CreateBackdrop(sepgp.extratip,nil,nil,pfUI_config.tooltip.alpha)
|
|
end
|
|
-- hook tooltip to add our GP values
|
|
sepgp:TipHook()
|
|
|
|
-- make tablets closable with ESC
|
|
for i=1,4 do
|
|
table.insert(UISpecialFrames,string.format("Tablet20DetachedFrame%d",i))
|
|
end
|
|
end
|
|
|
|
function sepgp:OnEnable() -- PLAYER_LOGIN (2)
|
|
sepgp:RegisterEvent("GUILD_ROSTER_UPDATE",function()
|
|
if (arg1) then -- member join /leave
|
|
self:SetRefresh(true)
|
|
end
|
|
end)
|
|
sepgp:RegisterEvent("RAID_ROSTER_UPDATE",function()
|
|
self:SetRefresh(true)
|
|
end)
|
|
sepgp: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")
|
|
|
|
if (IsInGuild()) then
|
|
if (GetNumGuildMembers()==0) then
|
|
GuildRoster()
|
|
end
|
|
end
|
|
|
|
if AceLibrary("AceEvent-2.0"):IsFullyInitialized() then
|
|
self:AceEvent_FullyInitialized()
|
|
else
|
|
self:RegisterEvent("AceEvent_FullyInitialized")
|
|
end
|
|
|
|
end
|
|
|
|
function sepgp:OnMenuRequest()
|
|
D:FeedAceOptionsTable(self:buildMenu())
|
|
end
|
|
|
|
function sepgp:TipHook()
|
|
self:SecureHook(GameTooltip, "SetBagItem", function(this, bag, slot)
|
|
sepgp:AddDataToTooltip(GameTooltip, GetContainerItemLink(bag, slot))
|
|
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)
|
|
sepgp:AddDataToTooltip(GameTooltip, GetLootSlotLink(slot))
|
|
end
|
|
)
|
|
self:SecureHook(GameTooltip, "SetLootRollItem", function(this, id)
|
|
sepgp:AddDataToTooltip(GameTooltip, GetLootRollItemLink(id))
|
|
end
|
|
)
|
|
self:SecureHook("SetItemRef", function(link, name, button)
|
|
if (link and name and ItemRefTooltip) then
|
|
if (strsub(link, 1, 6) ~= "Player") then
|
|
if (ItemRefTooltip:IsVisible()) then
|
|
if (not DressUpFrame:IsVisible()) then
|
|
sepgp:AddDataToTooltip(ItemRefTooltip, link)
|
|
end
|
|
ItemRefTooltip.isDisplayDone = nil
|
|
end
|
|
end
|
|
end
|
|
end
|
|
)
|
|
self:HookScript(GameTooltip, "OnHide", function()
|
|
if sepgp.extratip:IsVisible() then sepgp.extratip:Hide() end
|
|
self.hooks[GameTooltip]["OnHide"]()
|
|
end
|
|
)
|
|
self:HookScript(ItemRefTooltip, "OnHide", function()
|
|
if sepgp.extratip:IsVisible() then sepgp.extratip:Hide() end
|
|
self.hooks[ItemRefTooltip]["OnHide"]()
|
|
end
|
|
)
|
|
end
|
|
|
|
function sepgp:getReserveStatus()
|
|
if (IsInGuild()) then
|
|
local guildName = (GetGuildInfo("player"))
|
|
if (guildName) and guildName ~= "" then
|
|
sepgp_reservechannel = string.format("%sReserves",(string.gsub(guildName," ","")))
|
|
end
|
|
end
|
|
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)
|
|
end
|
|
end
|
|
|
|
function sepgp:AddDataToTooltip(tooltip,itemlink,itemstring)
|
|
local price
|
|
if (itemstring) then
|
|
price = sepgp_prices:GetPrice(itemstring,sepgp_progress)
|
|
elseif (itemlink) then
|
|
price = sepgp_prices:GetPrice(itemlink,sepgp_progress)
|
|
end
|
|
if not price then return end
|
|
local textRight = string.format("cost:|cff32cd32%d|r offspec:|cff20b2aa%d|r",price,math.floor(price*sepgp_discount))
|
|
if (tooltip:NumLines() < 29) then
|
|
tooltip:AddLine(" ")
|
|
tooltip:AddDoubleLine("|cff9664c8shootyepgp|r",textRight)
|
|
tooltip:Show()
|
|
else
|
|
sepgp.extratip:ClearLines()
|
|
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:Show()
|
|
end
|
|
end
|
|
|
|
function sepgp:OnUpdate(elapsed)
|
|
sepgp.timer.count_down = sepgp.timer.count_down - elapsed
|
|
lastUpdate = lastUpdate + elapsed
|
|
if sepgp.timer.count_down <= 0 then
|
|
running_check = nil
|
|
sepgp.timer:Hide()
|
|
sepgp.timer.cd_text = "|cffff0000Finished|r"
|
|
sepgp_reserves:Refresh()
|
|
else
|
|
sepgp.timer.cd_text = string.format("|cff00ff00%02d|r|cffffffffsec|r",sepgp.timer.count_down)
|
|
end
|
|
if lastUpdate > 0.5 then
|
|
lastUpdate = 0
|
|
sepgp_reserves:Refresh()
|
|
end
|
|
end
|
|
|
|
-------------------
|
|
-- Communication
|
|
-------------------
|
|
function sepgp:flashFrame(frame)
|
|
local tabFlash = getglobal(frame:GetName().."TabFlash")
|
|
if ( not frame.isDocked or (frame == SELECTED_DOCK_FRAME) or UIFrameIsFlashing(tabFlash) ) then
|
|
return
|
|
end
|
|
tabFlash:Show()
|
|
UIFrameFlash(tabFlash, 0.25, 0.25, 60, nil, 0.5, 0.5)
|
|
end
|
|
|
|
function sepgp:debugPrint(msg)
|
|
if (shooty_debugchat) then
|
|
shooty_debugchat:AddMessage(string.format(out,msg))
|
|
sepgp:flashFrame(shooty_debugchat)
|
|
else
|
|
sepgp:defaultPrint(msg)
|
|
end
|
|
end
|
|
|
|
function sepgp:defaultPrint(msg)
|
|
if not DEFAULT_CHAT_FRAME:IsVisible() then
|
|
FCF_SelectDockFrame(DEFAULT_CHAT_FRAME)
|
|
end
|
|
DEFAULT_CHAT_FRAME:AddMessage(string.format(out,msg))
|
|
end
|
|
|
|
function sepgp:simpleSay(msg)
|
|
SendChatMessage(string.format("shootyepgp: %s",msg), sepgp_saychannel)
|
|
end
|
|
|
|
function sepgp:adminSay(msg)
|
|
-- API is broken on Elysium
|
|
-- local g_listen, g_speak, officer_listen, officer_speak, g_promote, g_demote, g_invite, g_remove, set_gmotd, set_publicnote, view_officernote, edit_officernote, set_guildinfo = GuildControlGetRankFlags()
|
|
-- if (officer_speak) then
|
|
SendChatMessage(string.format("shootyepgp: %s",msg),"OFFICER")
|
|
-- end
|
|
end
|
|
|
|
---------------------
|
|
-- EPGP Operations
|
|
---------------------
|
|
function sepgp:init_notes(guild_index,note,officernote)
|
|
if not tonumber(note) or (tonumber(note) < 0) then
|
|
GuildRosterSetPublicNote(guild_index,0)
|
|
end
|
|
if not tonumber(officernote) or (tonumber(officernote) < shooty_basegp) then
|
|
GuildRosterSetOfficerNote(guild_index,shooty_basegp)
|
|
end
|
|
end
|
|
|
|
function sepgp:update_ep(getname,ep)
|
|
for i = 1, GetNumGuildMembers(1) do
|
|
local name, _, _, _, class, _, note, officernote, _, _ = GetGuildRosterInfo(i)
|
|
if (name==getname) then
|
|
sepgp:init_notes(i,note,officernote)
|
|
GuildRosterSetPublicNote(i,ep)
|
|
end
|
|
end
|
|
end
|
|
|
|
function sepgp:update_gp(getname,gp)
|
|
for i = 1, GetNumGuildMembers(1) do
|
|
local name, _, _, _, class, _, note, officernote, _, _ = GetGuildRosterInfo(i)
|
|
if (name==getname) then
|
|
sepgp:init_notes(i,note,officernote)
|
|
GuildRosterSetOfficerNote(i,gp)
|
|
end
|
|
end
|
|
end
|
|
|
|
function sepgp:get_ep(getname,note) -- gets ep by name or note
|
|
if (note) then
|
|
if tonumber(note)==nil then return 0 end
|
|
end
|
|
for i = 1, GetNumGuildMembers(1) do
|
|
local name, _, _, _, class, _, note, officernote, _, _ = GetGuildRosterInfo(i)
|
|
if tonumber(note)==nil then note=0 end
|
|
if (name==getname) then return tonumber(note) end
|
|
end
|
|
return(0)
|
|
end
|
|
|
|
function sepgp:get_gp(getname,officernote) -- gets gp by name or officernote
|
|
if (officernote) then
|
|
if tonumber(officernote)==nil then return shooty_basegp end
|
|
end
|
|
for i = 1, GetNumGuildMembers(1) do
|
|
local name, _, _, _, class, _, note, officernote, _, _ = GetGuildRosterInfo(i)
|
|
if tonumber(officernote)==nil then officernote=shooty_basegp end
|
|
if (name==getname) then return tonumber(officernote) end
|
|
end
|
|
return(shooty_basegp)
|
|
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)
|
|
end
|
|
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)
|
|
end
|
|
sepgp.reserves = {}
|
|
reserves_blacklist = {}
|
|
end
|
|
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))
|
|
ep = ep + sepgp:get_ep(getname)
|
|
sepgp:update_ep(getname,ep)
|
|
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(getname)
|
|
local newgp = gp + oldgp
|
|
sepgp:adminSay(string.format("Awarding %d GP to %s. (Previous: %d, New: %d)",gp,getname,oldgp,newgp))
|
|
self:addToLog(string.format("Awarding %d GP to %s. (Previous: %d, New: %d)",gp,getname,oldgp,newgp))
|
|
sepgp:update_gp(getname,newgp)
|
|
end
|
|
|
|
function sepgp:decay_epgp() -- decays entire roster's ep and gp
|
|
if not (admin()) then return end
|
|
for i = 1, GetNumGuildMembers(1) do
|
|
local name,_,_,_,class,_,ep,gp,_,_ = GetGuildRosterInfo(i)
|
|
ep = tonumber(ep)
|
|
gp = tonumber(gp)
|
|
if ep == nil then
|
|
else
|
|
ep = math.max(0,sepgp:num_round(ep*sepgp_decay))
|
|
GuildRosterSetPublicNote(i,ep)
|
|
gp = math.max(shooty_basegp,sepgp:num_round(gp*sepgp_decay))
|
|
GuildRosterSetOfficerNote(i,gp)
|
|
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:addToLog(msg)
|
|
end
|
|
|
|
function sepgp:gp_reset()
|
|
if (IsGuildLeader()) then
|
|
for i = 1, GetNumGuildMembers(1) do
|
|
GuildRosterSetOfficerNote(i, shooty_basegp)
|
|
end
|
|
sepgp:debugPrint(string.format("All GP has been reset to %d.",shooty_basegp))
|
|
self:adminSay(string.format("All GP has been reset to %d.",shooty_basegp))
|
|
self:addToLog(string.format("All GP has been reset to %d.",shooty_basegp))
|
|
end
|
|
end
|
|
|
|
---------
|
|
-- Menu
|
|
---------
|
|
local T = AceLibrary("Tablet-2.0")
|
|
|
|
sepgp.defaultMinimapPosition = 180
|
|
sepgp.cannotDetachTooltip = true
|
|
sepgp.tooltipHidderWhenEmpty = false
|
|
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.")
|
|
else
|
|
hint = string.format(hint,"")
|
|
end
|
|
T:SetHint(hint)
|
|
end
|
|
|
|
function sepgp:OnClick()
|
|
local is_admin = admin()
|
|
if (IsControlKeyDown() and is_admin) then
|
|
sepgp_reserves:Toggle()
|
|
elseif (IsAltKeyDown() and is_admin) then
|
|
sepgp_bids:Toggle()
|
|
elseif (IsShiftKeyDown() and is_admin) then
|
|
sepgp_logs:Toggle()
|
|
else
|
|
sepgp_standings:Toggle()
|
|
end
|
|
end
|
|
|
|
function sepgp:SetRefresh(flag)
|
|
needRefresh = flag
|
|
if (flag) then
|
|
sepgp_standings:Refresh()
|
|
end
|
|
end
|
|
|
|
function sepgp:buildRosterTable()
|
|
local g, r = { }, { }
|
|
local numGuildMembers = GetNumGuildMembers(1)
|
|
if (sepgp_raidonly) and GetNumRaidMembers() > 0 then
|
|
for i = 1, GetNumRaidMembers(true) do
|
|
local name, rank, subgroup, level, class, fileName, zone, online, isDead = GetRaidRosterInfo(i)
|
|
r[name] = true
|
|
end
|
|
end
|
|
for i = 1, numGuildMembers do
|
|
local member_name,_,_,_,class,_,ep,gp,_,_ = GetGuildRosterInfo(i)
|
|
if (sepgp_raidonly) and next(r) then
|
|
if r[member_name] then
|
|
table.insert(g,{["name"]=member_name,["class"]=class})
|
|
end
|
|
else
|
|
table.insert(g,{["name"]=member_name,["class"]=class})
|
|
end
|
|
end
|
|
return g
|
|
end
|
|
|
|
function sepgp:buildClassMemberTable(roster,epgp)
|
|
local desc,usage
|
|
if epgp == "ep" then
|
|
desc = "Account EPs to %s."
|
|
usage = "<EP>"
|
|
elseif epgp == "gp" then
|
|
desc = "Account GPs to %s."
|
|
usage = "<GP>"
|
|
end
|
|
local c = { }
|
|
for i,member in ipairs(roster) do
|
|
local class,name = member.class, member.name
|
|
if c[class] == nil then
|
|
c[class] = { }
|
|
c[class].type = "group"
|
|
c[class].name = class
|
|
c[class].desc = class .. " members"
|
|
c[class].hidden = function() return not (admin()) end
|
|
c[class].args = { }
|
|
end
|
|
if c[class].args[name] == nil then
|
|
c[class].args[name] = { }
|
|
c[class].args[name].type = "text"
|
|
c[class].args[name].name = name
|
|
c[class].args[name].desc = string.format(desc,name)
|
|
c[class].args[name].usage = usage
|
|
if epgp == "ep" then
|
|
c[class].args[name].get = "suggestedAwardEP"
|
|
c[class].args[name].set = function(v) sepgp:givename_ep(name, tonumber(v)) end
|
|
elseif epgp == "gp" then
|
|
c[class].args[name].get = false
|
|
c[class].args[name].set = function(v) sepgp:givename_gp(name, tonumber(v)) end
|
|
end
|
|
c[class].args[name].validate = function(v) return (type(v) == "number" or tonumber(v)) and tonumber(v) < shooty_max end
|
|
end
|
|
end
|
|
return c
|
|
end
|
|
|
|
local options
|
|
function sepgp:buildMenu()
|
|
if not (options) then
|
|
options = {
|
|
type = "group",
|
|
desc = "shootyepgp options",
|
|
handler = self,
|
|
args = { }
|
|
}
|
|
options.args["ep"] = {
|
|
type = "group",
|
|
name = "+EPs to Member",
|
|
desc = "Account EPs for member.",
|
|
order = 10,
|
|
hidden = function() return not (admin()) end,
|
|
}
|
|
options.args["ep_raid"] = {
|
|
type = "text",
|
|
name = "+EPs to Raid",
|
|
desc = "Award EPs to all raid members.",
|
|
order = 20,
|
|
get = "suggestedAwardEP",
|
|
set = function(v) sepgp:award_raid_ep(tonumber(v)) end,
|
|
usage = "<EP>",
|
|
hidden = function() return not (admin()) end,
|
|
validate = function(v)
|
|
local n = tonumber(v)
|
|
return n and n >= 0 and n < shooty_max
|
|
end
|
|
}
|
|
options.args["gp"] = {
|
|
type = "group",
|
|
name = "+GPs to Member",
|
|
desc = "Account GPs for member.",
|
|
order = 30,
|
|
hidden = function() return not (admin()) end,
|
|
}
|
|
options.args["ep_reserves"] = {
|
|
type = "text",
|
|
name = "+EPs to Reserves",
|
|
desc = "Award EPs to all active Reserves.",
|
|
order = 40,
|
|
get = "suggestedAwardEP",
|
|
set = function(v) sepgp:award_reserve_ep(tonumber(v)) end,
|
|
usage = "<EP>",
|
|
hidden = function() return not (admin()) end,
|
|
validate = function(v)
|
|
local n = tonumber(v)
|
|
return n and n >= 0 and n < shooty_max
|
|
end
|
|
}
|
|
options.args["reserves"] = {
|
|
type = "toggle",
|
|
name = "Enable Reserves",
|
|
desc = "Participate in Standby Raiders List.\n|cffff0000Requires Main Character Name.|r",
|
|
order = 50,
|
|
get = function() return (sepgp.reservesChannelID ~= nil) and (sepgp.reservesChannelID ~= 0) end,
|
|
set = function(v) sepgp:reservesToggle(v) end,
|
|
disabled = function() return (sepgp_main == nil) end
|
|
}
|
|
options.args["afkcheck_reserves"] = {
|
|
type = "execute",
|
|
name = "AFK Check Reserves",
|
|
desc = "AFK Check Reserves List",
|
|
order = 60,
|
|
hidden = function() return not (admin()) end,
|
|
func = function() sepgp:afkcheck_reserves() end
|
|
}
|
|
options.args["set_main"] = {
|
|
type = "text",
|
|
name = "Set Main",
|
|
desc = "Set your Main Character for Reserve List.",
|
|
order = 70,
|
|
usage = "<MainChar>",
|
|
get = function() return sepgp_main end,
|
|
set = function(v) sepgp_main = (sepgp:verifyGuildMember(v)) end,
|
|
}
|
|
options.args["raid_only"] = {
|
|
type = "toggle",
|
|
name = "Raid Only",
|
|
desc = "Only show members in raid.",
|
|
order = 80,
|
|
get = function() return not not sepgp_raidonly end,
|
|
set = function(v)
|
|
sepgp_raidonly = not sepgp_raidonly
|
|
sepgp:SetRefresh(true)
|
|
end,
|
|
}
|
|
options.args["progress_tier"] = {
|
|
type = "text",
|
|
name = "Raid Progress",
|
|
desc = "Highest Tier the Guild is raiding.\nUsed to adjust GP Prices.",
|
|
order = 90,
|
|
get = function() return sepgp_progress end,
|
|
set = function(v) sepgp_progress = v sepgp_bids:Refresh() end,
|
|
validate = { ["T3"]="4.Naxxramas", ["T2.5"]="3.Temple of Ahn\'Qiraj", ["T2"]="2.Blackwing Lair", ["T1"]="1.Molten Core"},
|
|
}
|
|
options.args["report_channel"] = {
|
|
type = "text",
|
|
name = "Reporting channel",
|
|
desc = "Channel used by reporting functions.",
|
|
order = 95,
|
|
hidden = function() return not (admin()) end,
|
|
get = function() return sepgp_saychannel end,
|
|
set = function(v) sepgp_saychannel = v end,
|
|
validate = { "PARTY", "RAID", "GUILD", "OFFICER" },
|
|
}
|
|
options.args["decay"] = {
|
|
type = "execute",
|
|
name = "Decay EPGP",
|
|
desc = string.format("Decays all EPGP by %d%%",(1-(sepgp_decay or shooty_decay))*100),
|
|
order = 100,
|
|
hidden = function() return not (admin()) end,
|
|
func = function() sepgp:decay_epgp() end
|
|
}
|
|
options.args["set_decay"] = {
|
|
type = "range",
|
|
name = "Set Decay %",
|
|
desc = "Set Decay percentage (Admin only).",
|
|
order = 110,
|
|
usage = "<Decay>",
|
|
get = function() return (1.0-sepgp_decay) end,
|
|
set = function(v) sepgp_decay = (1 - v) end,
|
|
min = 0.01,
|
|
max = 0.5,
|
|
step = 0.01,
|
|
bigStep = 0.05,
|
|
isPercent = true,
|
|
hidden = function() return not (admin()) end,
|
|
}
|
|
options.args["set_discount"] = {
|
|
type = "range",
|
|
name = "Offspec Price %",
|
|
desc = "Set Offspec / Resistance Items GP Percent.",
|
|
order = 115,
|
|
get = function() return sepgp_discount end,
|
|
set = function(v) sepgp_discount = v end,
|
|
min = 0,
|
|
max = 1,
|
|
step = 0.05,
|
|
isPercent = true
|
|
}
|
|
options.args["reset"] = {
|
|
type = "execute",
|
|
name = "Reset GP",
|
|
desc = string.format("gives everybody %d basic GP (Admin only).",shooty_basegp),
|
|
order = 120,
|
|
hidden = function() return not (IsGuildLeader()) end,
|
|
func = function() StaticPopup_Show("SHOOTY_EPGP_CONFIRM_RESET_GP") end
|
|
}
|
|
end
|
|
if (needInit) or (needRefresh) then
|
|
local members = sepgp:buildRosterTable()
|
|
self:debugPrint(string.format("Scanning %d members for EP/GP data. (%s)",table.getn(members),(sepgp_raidonly and "Raid" or "Full")))
|
|
options.args["ep"].args = sepgp:buildClassMemberTable(members,"ep")
|
|
options.args["gp"].args = sepgp:buildClassMemberTable(members,"gp")
|
|
if (needInit) then needInit = false end
|
|
if (needRefresh) then needRefresh = false end
|
|
end
|
|
return options
|
|
end
|
|
|
|
---------------
|
|
-- Reserves
|
|
---------------
|
|
function sepgp:reservesToggle(flag)
|
|
local reservesChannelID = tonumber((GetChannelName(sepgp_reservechannel)))
|
|
if (flag) then -- we want in
|
|
if (reservesChannelID) and reservesChannelID ~= 0 then
|
|
sepgp.reservesChannelID = reservesChannelID
|
|
if not self:IsEventRegistered("CHAT_MSG_CHANNEL") then
|
|
sepgp:RegisterEvent("CHAT_MSG_CHANNEL","captureReserveChatter")
|
|
end
|
|
return true
|
|
else
|
|
sepgp: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")
|
|
LeaveChannelByName(sepgp_reservechannel)
|
|
return
|
|
else
|
|
if sepgp:IsEventRegistered("CHAT_MSG_CHANNEL") then
|
|
sepgp:UnregisterEvent("CHAT_MSG_CHANNEL")
|
|
end
|
|
return false
|
|
end
|
|
end
|
|
end
|
|
|
|
function sepgp:reservesChannelChange(msg,_,_,_,_,_,_,_,channel)
|
|
if (msg) and (channel) and (channel == sepgp_reservechannel) then
|
|
if msg == "YOU_JOINED" then
|
|
sepgp.reservesChannelID = tonumber((GetChannelName(sepgp_reservechannel)))
|
|
RemoveChatWindowChannel(DEFAULT_CHAT_FRAME:GetID(), sepgp_reservechannel)
|
|
sepgp: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")
|
|
end
|
|
end
|
|
sepgp:UnregisterEvent("CHAT_MSG_CHANNEL_NOTICE")
|
|
D:Close()
|
|
end
|
|
end
|
|
|
|
function sepgp:afkcheck_reserves()
|
|
if (running_check) then return end
|
|
if sepgp.reservesChannelID ~= nil and ((GetChannelName(sepgp.reservesChannelID)) == sepgp.reservesChannelID) then
|
|
reserves_blacklist = {}
|
|
sepgp.reserves = {}
|
|
running_check = true
|
|
sepgp.timer.count_down = shooty_timeout
|
|
sepgp.timer:Show()
|
|
SendChatMessage(shooty_reservecall,"CHANNEL",nil,sepgp.reservesChannelID)
|
|
sepgp_reserves:Toggle(true)
|
|
end
|
|
end
|
|
|
|
function sepgp:sendReserverResponce()
|
|
if sepgp.reservesChannelID ~= nil then
|
|
if (sepgp_main) then
|
|
if sepgp_main == playerName then
|
|
SendChatMessage("+","CHANNEL",nil,sepgp.reservesChannelID)
|
|
else
|
|
SendChatMessage(string.format("+%s",sepgp_main),"CHANNEL",nil,sepgp.reservesChannelID)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function sepgp:captureReserveChatter(text, sender, _, _, _, _, _, _, channel)
|
|
if not (channel) or not (channel == sepgp_reservechannel) then return end
|
|
local reserve, reserve_class, reserve_rank, reserve_alt = nil,nil,nil,nil
|
|
local r,_,rdy,name = string.find(text,shooty_reserveanswer)
|
|
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 reserve ~= sender then
|
|
reserve_alt = sender
|
|
end
|
|
end
|
|
else
|
|
if (not sepgp:inRaid(sender)) then
|
|
reserve, reserve_class, reserve_rank = sepgp:verifyGuildMember(sender)
|
|
end
|
|
end
|
|
if reserve and reserve_class and reserve_rank then
|
|
if reserve_alt then
|
|
if not reserves_blacklist[reserve_alt] then
|
|
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))
|
|
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))
|
|
end
|
|
end
|
|
end
|
|
end
|
|
return
|
|
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
|
|
StaticPopup_Show("SHOOTY_EPGP_RESERVE_AFKCHECK_RESPONCE")
|
|
end
|
|
end
|
|
end
|
|
|
|
---------
|
|
-- Bids
|
|
---------
|
|
local lootCall = {}
|
|
lootCall.whisp = {
|
|
"^(w)[%s%p%c]+.+",".+[%s%p%c]+(w)$",".+[%s%p%c]+(w)[%s%p%c]+.*",".*[%s%p%c]+(w)[%s%p%c]+.+",
|
|
"^(whisper)[%s%p%c]+.+",".+[%s%p%c]+(whisper)$",".+[%s%p%c]+(whisper)[%s%p%c]+.*",".*[%s%p%c]+(whisper)[%s%p%c]+.+",
|
|
".+[%s%p%c]+(bid)[%s%p%c]*.*",".*[%s%p%c]*(bid)[%s%p%c]+.+"
|
|
}
|
|
lootCall.ms = {
|
|
".+(%+).*",".*(%+).+",
|
|
"^(ms)[%s%p%c]+.+",".+[%s%p%c]+(ms)$",".+[%s%p%c]+(ms)[%s%p%c]+.*",".*[%s%p%c]+(ms)[%s%p%c]+.+",
|
|
".+(mainspec).*",".*(mainspec).+"
|
|
}
|
|
lootCall.os = {
|
|
".+(%-).*",".*(%-).+",
|
|
"^(os)[%s%p%c]+.+",".+[%s%p%c]+(os)$",".+[%s%p%c]+(os)[%s%p%c]+.*",".*[%s%p%c]+(os)[%s%p%c]+.+",
|
|
".+(offspec).*",".*(offspec).+"
|
|
}
|
|
function sepgp:captureLootCall(text, sender)
|
|
if not (IsRaidLeader() or self:lootMaster()) then return end
|
|
if not sender == playerName then return end
|
|
if not (string.find(text, "|Hitem:", 1, true)) then return end
|
|
local linkstriptext, count = string.gsub(text,"|c%x+|H[eimt:%d]+|h%[[%w%s'%-]+%]|h|r"," ; ")
|
|
if count > 1 then return end
|
|
local lowtext = string.lower(linkstriptext)
|
|
local whisperkw_found, mskw_found, oskw_found, link_found
|
|
local _, itemLink, itemColor, itemString, itemName
|
|
for _,f in ipairs(lootCall.whisp) do
|
|
whisperkw_found = string.find(lowtext,f)
|
|
if (whisperkw_found) then break end
|
|
end
|
|
for _,f in ipairs(lootCall.ms) do
|
|
mskw_found = string.find(lowtext,f)
|
|
if (mskw_found) then break end
|
|
end
|
|
for _,f in ipairs(lootCall.os) do
|
|
oskw_found = string.find(lowtext,f)
|
|
if (oskw_found) then break end
|
|
end
|
|
if (whisperkw_found) or (mskw_found) or (oskw_found) then
|
|
_,_,itemLink = string.find(text,"(|c%x+|H[eimt:%d]+|h%[[%w%s'%-]+%]|h|r)")
|
|
if (itemLink) and (itemLink ~= "") then
|
|
link_found, _, itemColor, itemString, itemName = string.find(itemLink, "^(|c%x+)|H(.+)|h(%[.+%])")
|
|
end
|
|
if (link_found) then
|
|
self:clearBids()
|
|
sepgp.bid_item.link = itemString
|
|
sepgp.bid_item.linkFull = itemLink
|
|
sepgp.bid_item.name = string.format("%s%s|r",itemColor,itemName)
|
|
self:ScheduleEvent("shootyepgpBidTimeout",self.clearBids,360,self)
|
|
running_bid = true
|
|
self:debugPrint("Capturing Bids for 6min.")
|
|
sepgp_bids:Toggle(true)
|
|
end
|
|
end
|
|
end
|
|
|
|
local lootBid = {}
|
|
lootBid.ms = {"(%+)",".+(%+).*",".*(%+).+",".*(%+).*","(ms)"}
|
|
lootBid.os = {"(%-)",".+(%-).*",".*(%-).+",".*(%-).*","(os)"}
|
|
function sepgp:captureBid(text, sender)
|
|
if not (running_bid) then return end
|
|
if not (IsRaidLeader() or self:lootMaster()) then return end
|
|
if not sepgp.bid_item.link then return end
|
|
local mskw_found,oskw_found
|
|
local lowtext = string.lower(text)
|
|
for _,f in ipairs(lootBid.ms) do
|
|
mskw_found = string.find(text,f)
|
|
if (mskw_found) then break end
|
|
end
|
|
for _,f in ipairs(lootBid.os) do
|
|
oskw_found = string.find(text,f)
|
|
if (oskw_found) then break end
|
|
end
|
|
if (mskw_found) or (oskw_found) then
|
|
if self:inRaid(sender) then
|
|
if bids_blacklist[sender] == nil then
|
|
for i = 1, GetNumGuildMembers(1) do
|
|
local name, _, _, _, class, _, note, officernote, _, _ = GetGuildRosterInfo(i)
|
|
if name == sender then
|
|
local ep = self:get_ep(name,note)
|
|
local gp = self:get_gp(name,officernote)
|
|
if (mskw_found) then
|
|
bids_blacklist[sender] = true
|
|
table.insert(sepgp.bids_main,{name,class,ep,gp,ep/gp})
|
|
elseif (oskw_found) then
|
|
bids_blacklist[sender] = true
|
|
table.insert(sepgp.bids_off,{name,class,ep,gp,ep/gp})
|
|
end
|
|
sepgp_bids:Toggle(true)
|
|
sepgp_bids:Refresh()
|
|
return
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function sepgp:clearBids()
|
|
sepgp:defaultPrint("clearBids")
|
|
sepgp.bid_item = {}
|
|
sepgp.bids_main = {}
|
|
sepgp.bids_off = {}
|
|
bids_blacklist = {}
|
|
if self:IsEventScheduled("shootyepgpBidTimeout") then
|
|
self:CancelScheduledEvent("shootyepgpBidTimeout")
|
|
end
|
|
running_bid = false
|
|
sepgp_bids:Refresh()
|
|
end
|
|
|
|
------------
|
|
-- Logging
|
|
------------
|
|
|
|
function sepgp:addToLog(line,skipTime)
|
|
local over = table.getn(sepgp_log)-shooty_maxloglines+1
|
|
if over > 0 then
|
|
for i=1,over do
|
|
table.remove(sepgp_log,1)
|
|
end
|
|
end
|
|
local timestamp
|
|
if (skipTime) then
|
|
timestamp = ""
|
|
else
|
|
timestamp = date("%b/%d %H:%M:%S")
|
|
end
|
|
table.insert(sepgp_log,{timestamp,line})
|
|
end
|
|
|
|
------------
|
|
-- Utility
|
|
------------
|
|
function sepgp:num_round(i)
|
|
return math.floor(i+0.5)
|
|
end
|
|
|
|
function sepgp:verifyGuildMember(name)
|
|
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))
|
|
end
|
|
return
|
|
end
|
|
|
|
function sepgp:inRaid(name)
|
|
for i=1,GetNumRaidMembers() do
|
|
if name == (UnitName(raidUnit[i])) then
|
|
return true
|
|
end
|
|
end
|
|
return false
|
|
end
|
|
|
|
function sepgp:lootMaster()
|
|
local method, lootmasterID = GetLootMethod()
|
|
if method == "master" and lootmasterID == 0 then
|
|
return true
|
|
else
|
|
return false
|
|
end
|
|
end
|
|
|
|
local raidZones = {["Molten Core"]="T1",["Onyxia\'s Lair"]="T1.5",["Blackwing Lair"]="T2",["Ahn'Qiraj"]="T2.5",["Naxxramas"]="T3"}
|
|
local zone_multipliers = {
|
|
["T3"] = {["T3"]=1,["T2.5"]=0.75,["T2"]=0.5,["T1.5"]=0.25,["T1"]=0.25},
|
|
["T2.5"] = {["T3"]=1,["T2.5"]=1,["T2"]=0.7,["T1.5"]=0.4,["T1"]=0.4},
|
|
["T2"] = {["T3"]=1,["T2.5"]=1,["T2"]=1,["T1.5"]=0.5,["T1"]=0.5},
|
|
["T1"] = {["T3"]=1,["T2.5"]=1,["T2"]=1,["T1.5"]=1,["T1"]=1}
|
|
}
|
|
function sepgp:suggestedAwardEP()
|
|
local currentTier, zoneEN, zoneLoc, checkTier, multiplier
|
|
local inInstance, instanceType = IsInInstance()
|
|
if (inInstance == nil) or (instanceType ~= nil and instanceType == "none") then
|
|
currentTier = "T1.5"
|
|
end
|
|
if (inInstance) and (instanceType == "raid") then
|
|
zoneLoc = GetRealZoneText()
|
|
if (BZ:HasReverseTranslation(zoneLoc)) then
|
|
zoneEN = BZ:GetReverseTranslation(zoneLoc)
|
|
checkTier = raidZones[zoneEN]
|
|
if (checkTier) then
|
|
currentTier = checkTier
|
|
end
|
|
end
|
|
end
|
|
if not currentTier then
|
|
return shooty_baseaward_ep
|
|
else
|
|
multiplier = zone_multipliers[sepgp_progress][currentTier]
|
|
end
|
|
if (multiplier) then
|
|
return multiplier*shooty_baseaward_ep
|
|
else
|
|
return shooty_baseaward_ep
|
|
end
|
|
end
|
|
|
|
admin = function()
|
|
return (CanEditOfficerNote() and CanEditPublicNote())
|
|
end
|
|
|
|
-------------
|
|
-- Dialogs
|
|
-------------
|
|
StaticPopupDialogs["SHOOTY_EPGP_SET_MAIN"] = {
|
|
text = "Set your main to be able to participate in Reserve List EPGP Checks.",
|
|
button1 = TEXT(ACCEPT),
|
|
button2 = TEXT(CANCEL),
|
|
hasEditBox = 1,
|
|
maxLetters = 12,
|
|
OnAccept = function()
|
|
local editBox = getglobal(this:GetParent():GetName().."EditBox")
|
|
sepgp_main = sepgp:verifyGuildMember(editBox:GetText())
|
|
end,
|
|
OnShow = function()
|
|
getglobal(this:GetName().."EditBox"):SetText(sepgp_main or "")
|
|
getglobal(this:GetName().."EditBox"):SetFocus()
|
|
end,
|
|
OnHide = function()
|
|
if ( ChatFrameEditBox:IsVisible() ) then
|
|
ChatFrameEditBox:SetFocus()
|
|
end
|
|
getglobal(this:GetName().."EditBox"):SetText("")
|
|
end,
|
|
EditBoxOnEnterPressed = function()
|
|
local editBox = getglobal(this:GetParent():GetName().."EditBox")
|
|
sepgp_main = sepgp:verifyGuildMember(editBox:GetText())
|
|
this:GetParent():Hide()
|
|
end,
|
|
EditBoxOnEscapePressed = function()
|
|
this:GetParent():Hide()
|
|
end,
|
|
timeout = 0,
|
|
exclusive = 1,
|
|
whileDead = 1,
|
|
hideOnEscape = 1
|
|
}
|
|
StaticPopupDialogs["SHOOTY_EPGP_RESERVE_AFKCHECK_RESPONCE"] = {
|
|
text = "Reserves: AFKCheck. Are you available?",
|
|
button1 = TEXT(YES),
|
|
button2 = TEXT(NO),
|
|
OnAccept = function()
|
|
sepgp:sendReserverResponce()
|
|
end,
|
|
timeout = shooty_timeout,
|
|
exclusive = 1,
|
|
showAlert = 1,
|
|
whileDead = 1,
|
|
hideOnEscape = 1
|
|
}
|
|
StaticPopupDialogs["SHOOTY_EPGP_CONFIRM_RESET_GP"] = {
|
|
text = "Are you sure you want to Reset ALL GP?",
|
|
button1 = "|cffff0000"..TEXT(OKAY).."|r",
|
|
button2 = TEXT(CANCEL),
|
|
OnAccept = function()
|
|
sepgp:gp_reset()
|
|
end,
|
|
timeout = 0,
|
|
whileDead = 1,
|
|
exclusive = 1,
|
|
showAlert = 1,
|
|
hideOnEscape = 1
|
|
};
|