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 C = AceLibrary("Crayon-2.0") local BC = AceLibrary("Babble-Class-2.2") local DF = AceLibrary("Deformat-2.0") local G = AceLibrary("Gratuity-2.0") local T = AceLibrary("Tablet-2.0") local L = AceLibrary("AceLocale-2.2"):new("shootyepgp") sepgp.VARS = { basegp = 300, minep = 0, baseaward_ep = 100, decay = 0.9, max = 1000, timeout = 60, minlevel = 55, maxloglines = 500, prefix = "SEPGP_PREFIX", reservechan = "Reserves", reserveanswer = "^(%+)(%a*)$", bop = C:Red("BoP"), boe = C:Yellow("BoE"), nobind = C:White("NoBind"), msgp = "Mainspec GP", osgp = "Offspec GP", bankde = "Bank-D/E", reminder = C:Red("Unassigned"), } sepgp.VARS.reservecall = string.format(L["{shootyepgp}Type \"+\" if on main, or \"+\" (without quotes) if on alt within %dsec."],sepgp.VARS.timeout) sepgp._playerName = (UnitName("player")) local out = "|cff999999EPGP:|r %s" local raidStatus,lastRaidStatus local lastUpdate = 0 local needInit,needRefresh = true local admin,sanitizeNote local shooty_debugchat local running_check,running_bid local partyUnit,raidUnit = {},{} local hexColorQuality = {} local reserves_blacklist,bids_blacklist = {},{} local bid_broadcast_queue = {} local bid_broadcast_running = false local BROADCAST_INTERVAL = 1.5 local bidlink = { ["ms"]=L["|cff0066ff|Hshootybid:1:$ML|h[MAINSPEC]|h|r"], ["os"]=L["|cff3ade2f|Hshootybid:2:$ML|h[OFFSPEC]|h|r"], ["prioos"] = L["|cff3ade2f|Hshootybid:3:$ML|h[|r|cffff0000PRIO|r |cff3ade2fOFFSPEC]|h|r"] } local options do for i=1,40 do raidUnit[i] = "raid"..i end for i=1,4 do partyUnit[i] = "party"..i end for i=-1,6 do hexColorQuality[ITEM_QUALITY_COLORS[i].hex] = i end end local admincmd, membercmd = {type = "group", handler = sepgp, args = { bids = { type = "execute", name = L["Bids"], desc = L["Show Bids Table."], func = function() sepgp_bids:Toggle() end, order = 1, }, show = { type = "execute", name = L["Standings"], desc = L["Show Standings Table."], func = function() sepgp_standings:Toggle() end, order = 2, }, clearloot = { type = "execute", name = L["ClearLoot"], desc = L["Clear Loot Table."], func = function() sepgp_looted = {} sepgp_loot:Refresh() sepgp:defaultPrint(L["Loot info cleared"]) end, order = 3, }, clearlogs = { type = "execute", name = L["ClearLogs"], desc = L["Clear Logs Table."], func = function() sepgp_log = {} sepgp_logs:Refresh() sepgp:defaultPrint(L["Logs cleared"]) end, order = 4, }, progress = { type = "execute", name = L["Progress"], desc = L["Print Progress Multiplier."], func = function() sepgp:defaultPrint(sepgp_progress) end, order = 5, }, offspec = { type = "execute", name = L["Offspec"], desc = L["Print Offspec Price."], func = function() sepgp:defaultPrint(string.format("%s%%",sepgp_discount*100)) end, order = 6, }, restart = { type = "execute", name = L["Restart"], desc = L["Restart shootyepgp if having startup problems."], func = function() sepgp:OnEnable() sepgp:defaultPrint(L["Restarted"]) end, order = 7, }, }}, {type = "group", handler = sepgp, args = { show = { type = "execute", name = L["Standings"], desc = L["Show Standings Table."], func = function() sepgp_standings:Toggle() end, order = 1, }, progress = { type = "execute", name = L["Progress"], desc = L["Print Progress Multiplier."], func = function() sepgp:defaultPrint(sepgp_progress) end, order = 2, }, offspec = { type = "execute", name = L["Offspec"], desc = L["Print Offspec Price."], func = function() sepgp:defaultPrint(string.format("%s%%",sepgp_discount*100)) end, order = 3, }, restart = { type = "execute", name = L["Restart"], desc = L["Restart shootyepgp if having startup problems."], func = function() sepgp:OnEnable() sepgp:defaultPrint(L["Restarted"]) end, order = 4, }, }} --[[{ type = "execute", name = "Standings", desc = "Show Standings Table.", func = function() sepgp_standings:Toggle() end, }]] sepgp.cmdtable = function() if (admin()) then return admincmd else return membercmd end end 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.timer:SetScript("OnEvent",function() end) sepgp.alts = {} function sepgp:buildMenu() if not (options) then options = { type = "group", desc = L["shootyepgp options"], handler = self, args = { } } options.args["ep"] = { type = "group", name = L["+EPs to Member"], desc = L["Account EPs for member."], order = 10, hidden = function() return not (admin()) end, } options.args["ep_raid"] = { type = "text", name = L["+EPs to Raid"], desc = L["Award EPs to all raid members."], order = 20, get = "suggestedAwardEP", set = function(v) sepgp:award_raid_ep(tonumber(v)) end, usage = "", hidden = function() return not (admin()) end, validate = function(v) local n = tonumber(v) return n and n >= 0 and n < sepgp.VARS.max end } options.args["gp"] = { type = "group", name = L["+GPs to Member"], desc = L["Account GPs for member."], order = 30, hidden = function() return not (admin()) end, } options.args["ep_reserves"] = { type = "text", name = L["+EPs to Reserves"], desc = L["Award EPs to all active Reserves."], order = 40, get = "suggestedAwardEP", set = function(v) sepgp:award_reserve_ep(tonumber(v)) end, usage = "", hidden = function() return not (admin()) end, validate = function(v) local n = tonumber(v) return n and n >= 0 and n < sepgp.VARS.max end } options.args["reserves"] = { type = "toggle", name = L["Enable Reserves"], desc = L["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 = L["AFK Check Reserves"], desc = L["AFK Check Reserves List"], order = 60, hidden = function() return not (admin()) end, func = function() sepgp:afkcheck_reserves() end } options.args["alts"] = { type = "toggle", name = L["Enable Alts"], desc = L["Allow Alts to use Main\'s EPGP."], order = 63, hidden = function() return not (admin()) end, disabled = function() return not (IsGuildLeader()) end, get = function() return not not sepgp_altspool end, set = function(v) sepgp_altspool = not sepgp_altspool if (IsGuildLeader()) then sepgp:shareSettings(true) end end, } options.args["alts_percent"] = { type = "range", name = L["Alts EP %"], desc = L["Set the % EP Alts can earn."], order = 66, hidden = function() return (not sepgp_altspool) or (not IsGuildLeader()) end, get = function() return sepgp_altpercent end, set = function(v) sepgp_altpercent = v if (IsGuildLeader()) then sepgp:shareSettings(true) end end, min = 0.5, max = 1, step = 0.05, isPercent = true } options.args["set_main"] = { type = "text", name = L["Set Main"], desc = L["Set your Main Character for Reserve List."], order = 70, usage = "", get = function() return sepgp_main end, set = function(v) sepgp_main = (sepgp:verifyGuildMember(v)) end, } options.args["raid_only"] = { type = "toggle", name = L["Raid Only"], desc = L["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["loot_sounds"] = { type = "toggle", name = "Loot sounds", desc = "Enable or disable loot sounds.", order = 82, get = function() return sepgp_sound == 1 end, set = function(v) if sepgp_sound == 1 then sepgp_sound = 0 else sepgp_sound = 1 end end, } options.args["progress_tier_header"] = { type = "header", name = string.format(L["Progress Setting: %s"],sepgp_progress), order = 85, hidden = function() return admin() end, } options.args["progress_tier"] = { type = "text", name = L["Raid Progress"], desc = L["Highest Tier the Guild is raiding.\nUsed to adjust GP Prices.\nUsed for suggested EP awards."], order = 90, hidden = function() return not (admin()) end, get = function() return sepgp_progress end, set = function(v) sepgp_progress = v sepgp:refreshPRTablets() if (IsGuildLeader()) then sepgp:shareSettings(true) end end, validate = { ["T3.5"]=L["5.Tower of Karazhan"], ["T3"]=L["4.Naxxramas"], ["T2.5"]=L["3.Temple of Ahn\'Qiraj"], ["T2"]=L["2.Blackwing Lair"], ["T1"]=L["1.Molten Core"]}, } options.args["report_channel"] = { type = "text", name = L["Reporting channel"], desc = L["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 = L["Decay EPGP"], desc = string.format(L["Decays all EPGP by %s%%"],(1-(sepgp_decay or sepgp.VARS.decay))*100), order = 100, hidden = function() return not (admin()) end, func = function() sepgp:decay_epgp_v3() end } options.args["set_decay"] = { type = "range", name = L["Set Decay %"], desc = L["Set Decay percentage (Admin only)."], order = 110, usage = "", get = function() return (1.0-sepgp_decay) end, set = function(v) sepgp_decay = (1 - v) options.args["decay"].desc = string.format(L["Decays all EPGP by %s%%"],(1-sepgp_decay)*100) if (IsGuildLeader()) then sepgp:shareSettings(true) end 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_header"] = { type = "header", name = string.format(L["Offspec Price: %s%%"],sepgp_discount*100), order = 111, hidden = function() return admin() end, } options.args["set_discount"] = { type = "range", name = L["Offspec Price %"], desc = L["Set Offspec Items GP Percent."], order = 115, hidden = function() return not (admin()) end, get = function() return sepgp_discount end, set = function(v) sepgp_discount = v if (IsGuildLeader()) then sepgp:shareSettings(true) end end, min = 0, max = 1, step = 0.05, isPercent = true } options.args["set_min_ep_header"] = { type = "header", name = string.format(L["Minimum EP: %s"],sepgp_minep), order = 117, hidden = function() return admin() end, } options.args["set_min_ep"] = { type = "text", name = L["Minimum EP"], desc = L["Set Minimum EP"], usage = "", order = 118, get = function() return sepgp_minep end, set = function(v) sepgp_minep = tonumber(v) sepgp:refreshPRTablets() if (IsGuildLeader()) then sepgp:shareSettings(true) end end, validate = function(v) local n = tonumber(v) return n and n >= 0 and n <= sepgp.VARS.max end, hidden = function() return not admin() end, } options.args["reset"] = { type = "execute", name = L["Reset EPGP"], desc = string.format(L["Resets everyone\'s EPGP to 0/%d (Admin only)."],sepgp.VARS.basegp), order = 120, hidden = function() return not (IsGuildLeader()) end, func = function() StaticPopup_Show("SHOOTY_EPGP_CONFIRM_RESET") end } end if (needInit) or (needRefresh) then local members = sepgp:buildRosterTable() self:debugPrint(string.format(L["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 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_minep == nil then sepgp_minep = sepgp.VARS.minep end if sepgp_progress == nil then sepgp_progress = "T1" end if sepgp_discount == nil then sepgp_discount = 0.25 end if sepgp_altspool == nil then sepgp_altspool = false end if sepgp_altpercent == nil then sepgp_altpercent = 1.0 end if sepgp_log == nil then sepgp_log = {} end if sepgp_looted == nil then sepgp_looted = {} end if sepgp_debug == nil then sepgp_debug = {} end self:RegisterDB("sepgp_fubar") self:RegisterDefaults("char",{}) --table.insert(sepgp_debug,{[date("%b/%d %H:%M:%S")]="OnInitialize"}) end function sepgp:OnEnable() -- PLAYER_LOGIN (2) --table.insert(sepgp_debug,{[date("%b/%d %H:%M:%S")]="OnEnable"}) sepgp._playerLevel = UnitLevel("player") sepgp.extratip = (sepgp.extratip) or CreateFrame("GameTooltip","shootyepgp_tooltip",UIParent,"GameTooltipTemplate") sepgp._versionString = GetAddOnMetadata("shootyepgp","Version") sepgp._websiteString = GetAddOnMetadata("shootyepgp","X-Website") if (IsInGuild()) then if (GetNumGuildMembers()==0) then GuildRoster() end end self:RegisterEvent("GUILD_ROSTER_UPDATE",function() if (arg1) then -- member join /leave sepgp:SetRefresh(true) end end) self:RegisterEvent("RAID_ROSTER_UPDATE",function() sepgp:SetRefresh(true) sepgp:testLootPrompt() end) self:RegisterEvent("PARTY_MEMBERS_CHANGED",function() sepgp:SetRefresh(true) sepgp:testLootPrompt() end) self:RegisterEvent("PLAYER_ENTERING_WORLD",function() sepgp:SetRefresh(true) sepgp:testLootPrompt() end) if sepgp._playerLevel and sepgp._playerLevel < MAX_PLAYER_LEVEL then self:RegisterEvent("PLAYER_LEVEL_UP", function() if (arg1) then sepgp._playerLevel = tonumber(arg1) if sepgp._playerLevel == MAX_PLAYER_LEVEL then sepgp:UnregisterEvent("PLAYER_LEVEL_UP") end if sepgp._playerLevel and sepgp._playerLevel >= sepgp.VARS.minlevel then sepgp:testMain() end end end) end 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_LOOT","captureLoot") self:RegisterEvent("TRADE_PLAYER_ITEM_CHANGED","tradeLoot") self:RegisterEvent("TRADE_ACCEPT_UPDATE","tradeLoot") if AceLibrary("AceEvent-2.0"):IsFullyInitialized() then self:AceEvent_FullyInitialized() else self:RegisterEvent("AceEvent_FullyInitialized") end end function sepgp:OnDisable() --table.insert(sepgp_debug,{[date("%b/%d %H:%M:%S")]="OnDisable"}) self:UnregisterAllEvents() end function sepgp:AceEvent_FullyInitialized() -- SYNTHETIC EVENT, later than PLAYER_LOGIN, PLAYER_ENTERING_WORLD (3) --table.insert(sepgp_debug,{[date("%b/%d %H:%M:%S")]="AceEvent_FullyInitialized"}) if self._hasInitFull then return end 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 self:testMain() local delay = 2 if self:IsEventRegistered("AceEvent_FullyInitialized") then self:UnregisterEvent("AceEvent_FullyInitialized") delay = 3 end if not self:IsEventScheduled("shootyepgpChannelInit") then self:ScheduleEvent("shootyepgpChannelInit",self.delayedInit,delay,self) end -- if pfUI loaded, skin the extra tooltip if not IsAddOnLoaded("pfUI-addonskins") then 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,tonumber(pfUI_config.tooltip.alpha)) end end -- hook GiveMasterLoot to catch loot assign to members too far for chat parsing self:SecureHook("GiveMasterLoot") -- hook SetItemRef to parse our client bid links self:Hook("SetItemRef") -- hook tooltip to add our GP values 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 self._hasInitFull = true end sepgp._lastRosterRequest = false function sepgp:OnMenuRequest() local now = GetTime() if not self._lastRosterRequest or (now - self._lastRosterRequest > 2) then self._lastRosterRequest = now self:SetRefresh(true) GuildRoster() end self._options = self:buildMenu() D:FeedAceOptionsTable(self._options) end function sepgp:TipHook() self:SecureHook(GameTooltip, "SetHyperlink", function(this, itemstring) sepgp:AddDataToTooltip(GameTooltip, nil, itemstring) end) self:SecureHook(GameTooltip, "SetBagItem", function(this, 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 if (ml_tip) then local frame = GetMouseFocus() if (frame) and (frame.IsFrameType ~= nil) and (frame:IsFrameType("Button")) then if not (frame._hasExtraClicks) then frame:RegisterForClicks("LeftButtonUp","RightButtonUp","MiddleButtonUp") frame._hasExtraClicks = true end end end end end sepgp:AddDataToTooltip(GameTooltip, itemLink, nil, ml_tip) end ) self:SecureHook(GameTooltip, "SetLootItem", function(this, slot) local is_master = (sepgp:lootMaster()) and true or nil if (is_master) then local frame = GetMouseFocus() if (frame) and (frame.IsFrameType ~= nil) and (frame:IsFrameType("Button")) then if not (frame._hasExtraClicks) then frame:RegisterForClicks("LeftButtonUp","RightButtonUp","MiddleButtonUp") frame._hasExtraClicks = true end end end sepgp:AddDataToTooltip(GameTooltip, GetLootSlotLink(slot), nil, is_master) end ) self:SecureHook(GameTooltip, "SetLootRollItem", function(this, id) sepgp:AddDataToTooltip(GameTooltip, GetLootRollItemLink(id)) 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 ) if (AtlasLootTooltip) then self:SecureHook(AtlasLootTooltip, "SetHyperlink", function(this, itemstring) sepgp:AddDataToTooltip(AtlasLootTooltip,nil,itemstring) end) self:HookScript(AtlasLootTooltip, "OnHide", function() if sepgp.extratip:IsVisible() then sepgp.extratip:Hide() end self.hooks[AtlasLootTooltip]["OnHide"]() end) end end function sepgp:delayedInit() --table.insert(sepgp_debug,{[date("%b/%d %H:%M:%S")]="delayedInit"}) if (IsInGuild()) then local guildName = (GetGuildInfo("player")) if (guildName) and guildName ~= "" then sepgp_reservechannel = string.format("%sReserves",(string.gsub(guildName," ",""))) -- TODO: Check if channel names can have chinese characters end end if sepgp_reservechannel == nil then sepgp_reservechannel = sepgp.VARS.reservechan end local reservesChannelID = tonumber((GetChannelName(sepgp_reservechannel))) if (reservesChannelID) and (reservesChannelID ~= 0) then self:reservesToggle(true) end -- migrate EPGP storage if needed self:parseVersion(sepgp._versionString) local major_ver = self._version.major if IsGuildLeader() and ( (sepgp_dbver == nil) or (major_ver > sepgp_dbver) ) then sepgp[string.format("v%dtov%d",(sepgp_dbver or 2),major_ver)](sepgp) end -- init options and comms self._options = self:buildMenu() self:RegisterChatCommand({"/shooty","/sepgp","/shootyepgp"},self.cmdtable()) self:RegisterEvent("CHAT_MSG_ADDON","addonComms") -- broadcast our version local addonMsg = string.format("VERSION;%s;%d",sepgp._versionString,major_ver) self:addonMessage(addonMsg,"GUILD") if (IsGuildLeader()) then self:shareSettings() end -- safe officer note setting when we are admin if (admin()) then if not self:IsHooked("GuildRosterSetOfficerNote") then self:Hook("GuildRosterSetOfficerNote") end end self:defaultPrint(string.format(L["v%s Loaded."],sepgp._versionString)) end function sepgp:AddDataToTooltip(tooltip,itemlink,itemstring,is_master) 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 line_limit, left1,right1 if (is_master) then line_limit = 27 left1,right1 = C:Yellow(L["Alt Click/RClick/MClick"]), C:Orange(L["Call for: MS/OS/Both"]) else line_limit = 28 end 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(L["gp:|cff32cd32%d|r gp_os:|cff20b2aa%d|r"],price,off_price) local textRight2 = string.format(L["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(" ") -- ### START: Insert after 'line_limit' is defined, before GP/PR lines local itemID = nil -- Attempt itemlink first if type(itemlink) == "string" then local _, _, id = string.find(itemlink, "Hitem:(%d+)") if not id then -- fallback if above didn't work _, _, id = string.find(itemlink, "item:(%d+)") end if id then itemID = id end end -- If nothing found, try itemstring if (not itemID) and type(itemstring) == "string" then local _, _, id = string.find(itemstring, "Hitem:(%d+)") if not id then -- fallback if above didn't work _, _, id = string.find(itemstring, "item:(%d+)") end if id then itemID = id end end -- Now safely add Item ID to the tooltip if itemID then if tooltip:NumLines() < line_limit then tooltip:AddLine("Item ID: " .. itemID) tooltip:Show() else -- If pfUI forced us to use the extra tooltip sepgp.extratip:AddLine("Item ID: " .. itemID) sepgp.extratip:Show() end end -- ### END tooltip:AddDoubleLine("|cff999999EPGP|r",textRight) tooltip:AddDoubleLine(" ",textRight2) if (is_master) then tooltip:AddDoubleLine(left1,right1) end tooltip:Show() else sepgp.extratip:ClearLines() sepgp.extratip:SetOwner(tooltip,"ANCHOR_NONE") sepgp.extratip:ClearAllPoints() if (EnhTooltip) and EnhancedTooltip:IsVisible() then sepgp.extratip:SetPoint("BOTTOMLEFT", tooltip, "TOPLEFT", 0, 5) sepgp.extratip:SetPoint("BOTTOMRIGHT", tooltip, "TOPRIGHT", 0, 5) else sepgp.extratip:SetPoint("TOPLEFT", tooltip, "BOTTOMLEFT", 0, -5) sepgp.extratip:SetPoint("TOPRIGHT", tooltip, "BOTTOMRIGHT", 0, -5) end sepgp.extratip:SetText("|cff999999EPGP|r") sepgp.extratip:AddDoubleLine(" ",textRight) sepgp.extratip:AddDoubleLine(" ",textRight2) if (is_master) then sepgp.extratip:AddDoubleLine(left1,right1) end 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 = L["|cffff0000Finished|r"] sepgp_reserves:Refresh() else sepgp.timer.cd_text = string.format(L["|cff00ff00%02d|r|cffffffffsec|r"],sepgp.timer.count_down) end if lastUpdate > 0.5 then lastUpdate = 0 sepgp_reserves:Refresh() end end function sepgp:GuildRosterSetOfficerNote(index,note,fromAddon) if (fromAddon) then self.hooks["GuildRosterSetOfficerNote"](index,note) else local name, _, _, _, _, _, _, prevnote, _, _ = GetGuildRosterInfo(index) local _,_,_,oldepgp,_ = string.find(prevnote or "","(.*)({%d+:%d+})(.*)") local _,_,_,epgp,_ = string.find(note or "","(.*)({%d+:%d+})(.*)") if (sepgp_altspool) then local oldmain = self:parseAlt(name,prevnote) local main = self:parseAlt(name,note) if oldmain ~= nil then if main == nil or main ~= oldmain then self:adminSay(string.format(L["Manually modified %s\'s note. Previous main was %s"],name,oldmain)) self:defaultPrint(string.format(L["|cffff0000Manually modified %s\'s note. Previous main was %s|r"],name,oldmain)) end end end if oldepgp ~= nil then if epgp == nil or epgp ~= oldepgp then self:adminSay(string.format(L["Manually modified %s\'s note. EPGP was %s"],name,oldepgp)) self:defaultPrint(string.format(L["|cffff0000Manually modified %s\'s note. EPGP was %s|r"],name,oldepgp)) end end local safenote = string.gsub(note,"(.*)({%d+:%d+})(.*)",sanitizeNote) return self.hooks["GuildRosterSetOfficerNote"](index,safenote) end end function sepgp:SetItemRef(link, name, button) if string.sub(link,1,9) == "shootybid" then local _,_,bid,masterlooter = string.find(link,"shootybid:(%d+):(%w+)") if bid == "1" then bid = "+" elseif bid == "2" then bid = "-" elseif bid == "3" then bid = "OSPRIO" else bid = nil end if not self:inRaid(masterlooter) then masterlooter = nil end if (bid and masterlooter) then SendChatMessage(bid,"WHISPER",nil,masterlooter) end return end self.hooks["SetItemRef"](link, name, button) if (link and name and ItemRefTooltip) then if (strsub(link, 1, 4) == "item") then if (ItemRefTooltip:IsVisible()) then if (not DressUpFrame:IsVisible()) then self:AddDataToTooltip(ItemRefTooltip, link) end ItemRefTooltip.isDisplayDone = nil end end end end function sepgp:LootFrameItem_OnClick(button,data) if not IsAltKeyDown() then return end if not UnitInRaid("player") then return end local slot, quality if data ~= nil then slot,quality = data:GetID(), data.quality else slot = LootFrame.selectedSlot or 0 quality = LootFrame.selectedQuality or -1 if not (this._hasExtraClicks) then this:RegisterForClicks("LeftButtonUp","RightButtonUp","MiddleButtonUp") this._hasExtraClicks = true end end if LootSlotIsItem(slot) and quality >= 3 then if not (self:lootMaster()) then self:defaultPrint(L["Need MasterLooter to perform Bid Calls!"]) UIErrorsFrame:AddMessage(L["Need MasterLooter to perform Bid Calls!"],1,0,0) return end local itemLink = GetLootSlotLink(slot) if (itemLink) then if button == "LeftButton" then self:widestAudience(string.format(L["Whisper %s a '+' for MS / '-' for OS / 'OSPRIO' for full price OS with prio for the item: %s"],sepgp._playerName,itemLink)) elseif button == "RightButton" then self:widestAudience(string.format(L["Whisper %s a - for %s (offspec)"],sepgp._playerName,itemLink)) elseif button == "MiddleButton" then self:widestAudience(string.format(L["Whisper %s a + or - for %s (mainspec or offspec)"],sepgp._playerName,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 (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 not (self:lootMaster()) then self:defaultPrint(L["Need MasterLooter to perform Bid Calls!"]) UIErrorsFrame:AddMessage(L["Need MasterLooter to perform Bid Calls!"],1,0,0) return self.hooks["ContainerFrameItemButton_OnClick"](button,ignoreModifiers) end if button == "LeftButton" then self:widestAudience(string.format(L["Whisper %s a '+' for MS / '-' for OS / 'OSPRIO' for full price OS with prio for the item: %s"],sepgp._playerName,itemLink)) return elseif button == "RightButton" then self:widestAudience(string.format(L["Whisper %s a - for %s (offspec)"],sepgp._playerName,itemLink)) return elseif button == "MiddleButton" then self:widestAudience(string.format(L["Whisper %s a + or - for %s (mainspec or offspec)"],sepgp._playerName,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 pflootitem:RegisterForClicks("LeftButtonUp","RightButtonUp","MiddleButtonUp") self:HookScript(pflootitem,"OnClick",function() self:LootFrameItem_OnClick(arg1,this) self.hooks[this]["OnClick"](this,arg1) end) end 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)) self:flashFrame(shooty_debugchat) else self: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:bidPrint(link, masterlooter, need, greed, bid) -- Build each clickable link local mslink = string.gsub(bidlink["ms"], "$ML", masterlooter) local oslink = string.gsub(bidlink["os"], "$ML", masterlooter) local priooslink = string.gsub(bidlink["prioos"], "$ML", masterlooter) -- Start with a string that has placeholders for all three local msg = string.format(L["Click $MS or $PRIOOS or $OS for %s"], link) math.randomseed(GetTime() * 1000) local randomSound = math.random(1, 28) if sepgp_sound == 1 then PlaySoundFile("Interface\\AddOns\\shootyepgp\\Sounds\\loot-" .. randomSound .. ".wav") end -- Decide which placeholders to keep/remove based on need/greed/bid if (need and greed) or bid then -- Keep all three msg = string.gsub(msg, "$MS", mslink) msg = string.gsub(msg, "$PRIOOS", priooslink) msg = string.gsub(msg, "$OS", oslink) elseif (need) then -- Only show MS, remove the others msg = string.gsub(msg, "$MS", mslink) msg = string.gsub(msg, " or $PRIOOS or $OS", "") elseif (greed) then -- Only show OS and PRIOOS, remove MS msg = string.gsub(msg, "$PRIOOS", priooslink) msg = string.gsub(msg, "$OS", oslink) msg = string.gsub(msg, "$MS or ", "") end -- If there's still an un-replaced placeholder, exit local _, count = string.gsub(msg, "%$", "%$") if (count > 0) then return end -- Decide which chat frame to print in local chatframe if SELECTED_CHAT_FRAME then chatframe = SELECTED_CHAT_FRAME else if not DEFAULT_CHAT_FRAME:IsVisible() then FCF_SelectDockFrame(DEFAULT_CHAT_FRAME) end chatframe = DEFAULT_CHAT_FRAME end -- Output to chat if chatframe then chatframe:AddMessage(" ") chatframe:AddMessage(string.format(out, msg), NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b ) end 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 function sepgp:widestAudience(msg) local channel = "SAY" if UnitInRaid("player") then if (IsRaidLeader() or IsRaidOfficer()) then channel = "RAID_WARNING" else channel = "RAID" end elseif UnitExists("party1") then channel = "PARTY" end 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 == 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 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 local for_main = (sepgp_main and (who == sepgp_main)) if (who == self._playerName) or (for_main) then if what == "EP" then if amount < 0 then msg = string.format(L["You have received a %d EP penalty."],amount) else msg = string.format(L["You have been awarded %d EP."],amount) end elseif what == "GP" then msg = string.format(L["You have gained %d GP."],amount) end elseif who == "ALL" and what == "DECAY" then msg = string.format(L["%s%% decay to EP and GP."],amount) elseif who == "RAID" and what == "AWARD" then msg = string.format(L["%d EP awarded to Raid."],amount) elseif who == "RESERVES" and what == "AWARD" then msg = string.format(L["%d EP awarded to Reserves."],amount) elseif who == "VERSION" then local out_of_date, version_type = self:parseVersion(self._versionString,what) if (out_of_date) and self._newVersionNotification == nil then self._newVersionNotification = true -- only inform once per session self:defaultPrint(string.format(L["New %s version available: |cff00ff00%s|r"],version_type,what)) self:defaultPrint(string.format(L["Visit %s to update."],self._websiteString)) end if (IsGuildLeader()) then self:shareSettings() end elseif who == "SETTINGS" then for progress,discount,decay,minep,alts,altspct in string.gfind(what, "([^:]+):([^:]+):([^:]+):([^:]+):([^:]+):([^:]+)") do discount = tonumber(discount) decay = tonumber(decay) minep = tonumber(minep) alts = (alts == "true") and true or false altspct = tonumber(altspct) local settings_notice if progress and progress ~= sepgp_progress then sepgp_progress = progress settings_notice = L["New raid progress"] end if discount and discount ~= sepgp_discount then sepgp_discount = discount if (settings_notice) then settings_notice = settings_notice..L[", offspec price %"] else settings_notice = L["New offspec price %"] end end if minep and minep ~= sepgp_minep then sepgp_minep = minep settings_notice = L["New Minimum EP"] sepgp:refreshPRTablets() end if decay and decay ~= sepgp_decay then sepgp_decay = decay if (admin()) then if (settings_notice) then settings_notice = settings_notice..L[", decay %"] else settings_notice = L["New decay %"] end end end if alts ~= nil and alts ~= sepgp_altspool then sepgp_altspool = alts if (admin()) then if (settings_notice) then settings_notice = settings_notice..L[", alts"] else settings_notice = L["New Alts"] end end end if altspct and altspct ~= sepgp_altpercent then sepgp_altpercent = altspct if (admin()) then if (settings_notice) then settings_notice = settings_notice..L[", alts ep %"] else settings_notice = L["New Alts EP %"] end end end if (settings_notice) and settings_notice ~= "" then local sender_rank = string.format("%s(%s)",C:Colorize(BC:GetHexColor(class),sender),rank) settings_notice = settings_notice..string.format(L[" settings accepted from %s"],sender_rank) self:defaultPrint(settings_notice) self._options.args["progress_tier_header"].name = string.format(L["Progress Setting: %s"],sepgp_progress) self._options.args["set_discount_header"].name = string.format(L["Offspec Price: %s%%"],sepgp_discount*100) self._options.args["set_min_ep_header"].name = string.format(L["Minimum EP: %s"],sepgp_minep) end end -- Handle bid start broadcast from master looter elseif who == "BIDSTART" then -- Only officers/supreme leaders who are NOT the ML should process this if not self:lootMaster() and self:canReceiveBidBroadcast() then -- Parse: BIDSTART;itemID;1 local itemID = what if not itemID or itemID == "" then return end -- Use GetItemInfo to get item details locally local itemName, itemLink, itemQuality = GetItemInfo(tonumber(itemID)) if not itemName then -- Item not in cache, try to query it self:debugPrint("Item not in cache, waiting for server...") return end -- Build itemString format expected by GetPrice local itemString = string.format("item:%s:0:0:0", itemID) -- Get quality color local _, _, _, itemColor = GetItemQualityColor(itemQuality or 1) local coloredName = string.format("%s%s|r", itemColor or "|cffffffff", itemName) -- Set up bid tracking for this officer self:clearBids() sepgp.bid_item.link = itemString sepgp.bid_item.linkFull = itemLink sepgp.bid_item.name = coloredName running_bid = true self:ScheduleEvent("shootyepgpBidTimeout", self.clearBids, 300, self) -- DO NOT auto-open bid window for officers, they must open manually sepgp_bids:Refresh() end -- Handle bid data broadcast from master looter elseif who == "BIDS" then -- Only officers/supreme leaders who are NOT the ML should process this if not self:lootMaster() and self:canReceiveBidBroadcast() then if not running_bid then return end -- Parse comma-separated bid entries for bidData in string.gfind(what, "([^,]+)") do local bidType, name, class, ep, gp, pr, main_name, prio_flag = self:deserializeBid(bidData) if bidType and name and name ~= "" then -- Check if this bid already exists (by name) local exists = false if bidType == "MS" then for i = 1, table.getn(sepgp.bids_main) do if sepgp.bids_main[i][1] == name then exists = true break end end if not exists then table.insert(sepgp.bids_main, {name, class, ep, gp, pr, main_name or "", prio_flag or ""}) end elseif bidType == "OS" or bidType == "OSPRIO" then for i = 1, table.getn(sepgp.bids_off) do if sepgp.bids_off[i][1] == name then exists = true break end end if not exists then local flag = "" if bidType == "OSPRIO" then flag = "OSPRIO" end table.insert(sepgp.bids_off, {name, class, ep, gp, pr, main_name or "", flag}) end end end end -- Refresh display if window is open sepgp_bids:Refresh() end -- Handle bid clear broadcast from master looter elseif who == "BIDCLEAR" then -- Only officers/supreme leaders who are NOT the ML should process this if not self:lootMaster() and self:canReceiveBidBroadcast() then self:clearBids() end -- Handle attention signal from master looter elseif who == "BIDATTENTION" then -- Only officers/supreme leaders who are NOT the ML should process this if not self:lootMaster() and self:canReceiveBidBroadcast() then self:playAttentionSound() self:defaultPrint(C:Yellow(L["Attention! Master Looter wants you to check the bid window."])) end end if msg and msg~="" then self:defaultPrint(msg) self:my_epgp(for_main) end end end function sepgp:shareSettings(force) local now = GetTime() if self._lastSettingsShare == nil or (now - self._lastSettingsShare > 30) or (force) then self._lastSettingsShare = now local addonMsg = string.format("SETTINGS;%s:%s:%s:%s:%s:%s;1",sepgp_progress,sepgp_discount,sepgp_decay,sepgp_minep,tostring(sepgp_altspool),sepgp_altpercent) self:addonMessage(addonMsg,"GUILD") end end function sepgp:refreshPRTablets() --if not T:IsAttached("sepgp_standings") then sepgp_standings:Refresh() --end --if not T:IsAttached("sepgp_bids") then sepgp_bids:Refresh() --end end --------------------- -- EPGP Operations --------------------- function sepgp:init_notes_v2(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) < sepgp.VARS.basegp) then GuildRosterSetOfficerNote(guild_index,sepgp.VARS.basegp,true) end end function sepgp:init_notes_v3(guild_index,name,officernote) local ep,gp = self:get_ep_v3(name,officernote), self:get_gp_v3(name,officernote) if not (ep and gp) then local initstring = string.format("{%d:%d}",0,sepgp.VARS.basegp) local newnote = string.format("%s%s",officernote,initstring) newnote = string.gsub(newnote,"(.*)({%d+:%d+})(.*)",sanitizeNote) officernote = newnote else officernote = string.gsub(officernote,"(.*)({%d+:%d+})(.*)",sanitizeNote) end GuildRosterSetOfficerNote(guild_index,officernote,true) return officernote end 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 ep = math.max(0,ep) newnote = string.gsub(officernote,"(.*{)(%d+)(:)(%d+)(}.*)",function(head,oldep,divider,oldgp,tail) return string.format("%s%s%s%s%s",head,ep,divider,oldgp,tail) end) end if (gp) then gp = math.max(sepgp.VARS.basegp,gp) if (newnote) then newnote = string.gsub(newnote,"(.*{)(%d+)(:)(%d+)(}.*)",function(head,oldep,divider,oldgp,tail) return string.format("%s%s%s%s%s",head,oldep,divider,gp,tail) end) else newnote = string.gsub(officernote,"(.*{)(%d+)(:)(%d+)(}.*)",function(head,oldep,divider,oldgp,tail) return string.format("%s%s%s%s%s",head,oldep,divider,gp,tail) end) end end if (newnote) then GuildRosterSetOfficerNote(guild_index,newnote,true) end end function sepgp:update_ep_v2(getname,ep) for i = 1, GetNumGuildMembers(1) do local name, _, _, _, class, _, note, officernote, _, _ = GetGuildRosterInfo(i) if (name==getname) then self:init_notes_v2(i,note,officernote) GuildRosterSetPublicNote(i,ep) end end end function sepgp:update_ep_v3(getname,ep) for i = 1, GetNumGuildMembers(1) do local name, _, _, _, class, _, note, officernote, _, _ = GetGuildRosterInfo(i) if (name==getname) then self:update_epgp_v3(ep,nil,i,name,officernote) end end end function sepgp:update_gp_v2(getname,gp) for i = 1, GetNumGuildMembers(1) do local name, _, _, _, class, _, note, officernote, _, _ = GetGuildRosterInfo(i) if (name==getname) then self:init_notes_v2(i,note,officernote) GuildRosterSetOfficerNote(i,gp,true) end end end function sepgp:update_gp_v3(getname,gp) for i = 1, GetNumGuildMembers(1) do local name, _, _, _, class, _, note, officernote, _, _ = GetGuildRosterInfo(i) if (name==getname) then self:update_epgp_v3(nil,gp,i,name,officernote) end end end function sepgp:get_ep_v2(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_ep_v3(getname,officernote) -- gets ep by name or note if (officernote) then local _,_,ep = string.find(officernote,".*{(%d+):%d+}.*") return tonumber(ep) end for i = 1, GetNumGuildMembers(1) do local name, _, _, _, class, _, note, officernote, _, _ = GetGuildRosterInfo(i) local _,_,ep = string.find(officernote,".*{(%d+):%d+}.*") if (name==getname) then return tonumber(ep) end end return end function sepgp:get_gp_v2(getname,officernote) -- gets gp by name or officernote if (officernote) then if tonumber(officernote)==nil then return sepgp.VARS.basegp end end for i = 1, GetNumGuildMembers(1) do local name, _, _, _, class, _, note, officernote, _, _ = GetGuildRosterInfo(i) if tonumber(officernote)==nil then officernote=sepgp.VARS.basegp end if (name==getname) then return tonumber(officernote) end end return(sepgp.VARS.basegp) end function sepgp:get_gp_v3(getname,officernote) -- gets gp by name or officernote if (officernote) then local _,_,gp = string.find(officernote,".*{%d+:(%d+)}.*") return tonumber(gp) end for i = 1, GetNumGuildMembers(1) do local name, _, _, _, class, _, note, officernote, _, _ = GetGuildRosterInfo(i) local _,_,gp = string.find(officernote,".*{%d+:(%d+)}.*") if (name==getname) then return tonumber(gp) end end return end function sepgp:award_raid_ep(ep) -- awards ep to raid members in zone if GetNumRaidMembers()>0 then for i = 1, GetNumRaidMembers(true) do local name, rank, subgroup, level, class, fileName, zone, online, isDead = GetRaidRosterInfo(i) if level >= sepgp.VARS.minlevel then self:givename_ep(name,ep) end end self:simpleSay(string.format(L["Giving %d ep to all raidmembers"],ep)) self:addToLog(string.format(L["Giving %d ep to all raidmembers"],ep)) local addonMsg = string.format("RAID;AWARD;%s",ep) self:addonMessage(addonMsg,"RAID") self:refreshPRTablets() else UIErrorsFrame:AddMessage(L["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.reserves) > 0 then for i, reserve in ipairs(sepgp.reserves) do local name, class, rank, alt = unpack(reserve) self:givename_ep(name,ep) end self:simpleSay(string.format(L["Giving %d ep to active reserves"],ep)) self:addToLog(string.format(L["Giving %d ep to active reserves"],ep)) local addonMsg = string.format("RESERVES;AWARD;%s",ep) self:addonMessage(addonMsg,"GUILD") sepgp.reserves = {} reserves_blacklist = {} self:refreshPRTablets() end end function sepgp:givename_ep(getname,ep) -- awards ep to a single character if not (admin()) then return end local postfix, alt = "" if (sepgp_altspool) then local main = self:parseAlt(getname) if (main) then alt = getname getname = main ep = self:num_round(sepgp_altpercent*ep) postfix = string.format(L[", %s\'s Main."],alt) end end local newep = ep + (self:get_ep_v3(getname) or 0) self:update_ep_v3(getname,newep) self:debugPrint(string.format(L["Giving %d ep to %s%s."],ep,getname,postfix)) if ep < 0 then -- inform admins and victim of penalties local msg = string.format(L["%s EP Penalty to %s%s."],ep,getname,postfix) self:adminSay(msg) self:addToLog(msg) 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 local postfix, alt = "" if (sepgp_altspool) then local main = self:parseAlt(getname) if (main) then alt = getname getname = main postfix = string.format(L[", %s\'s Main."],alt) end end local oldgp = (self:get_gp_v3(getname) or sepgp.VARS.basegp) local newgp = gp + oldgp self:update_gp_v3(getname,newgp) self:debugPrint(string.format(L["Giving %d gp to %s%s."],gp,getname,postfix)) local msg = string.format(L["Awarding %d GP to %s%s. (Previous: %d, New: %d)"],gp,getname,postfix,oldgp,math.max(sepgp.VARS.basegp,newgp)) self:adminSay(msg) self:addToLog(msg) 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 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 if gp == nil then local msg = string.format(L["%s\'s officernote is broken:%q"],name,tostring(gp)) self:debugPrint(msg) self:adminSay(msg) else ep = math.max(0,self:num_round(ep*sepgp_decay)) GuildRosterSetPublicNote(i,ep) gp = math.max(sepgp.VARS.basegp,self:num_round(gp*sepgp_decay)) GuildRosterSetOfficerNote(i,gp,true) end end end local msg = string.format(L["All EP and GP decayed by %d%%"],(1-sepgp_decay)*100) self:simpleSay(msg) if not (sepgp_saychannel=="OFFICER") then self:adminSay(msg) end self:addToLog(msg) end function sepgp:decay_epgp_v3() if not (admin()) then return end for i = 1, GetNumGuildMembers(1) do 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 = 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(L["All EP and GP decayed by %s%%"],(1-sepgp_decay)*100) 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) self:refreshPRTablets() end function sepgp:gp_reset_v2() if (IsGuildLeader()) then for i = 1, GetNumGuildMembers(1) do GuildRosterSetOfficerNote(i, sepgp.VARS.basegp,true) end self:debugPrint(string.format(L["All GP has been reset to %d."],sepgp.VARS.basegp)) self:adminSay(string.format(L["All GP has been reset to %d."],sepgp.VARS.basegp)) self:addToLog(string.format(L["All GP has been reset to %d."],sepgp.VARS.basegp)) end end function sepgp:gp_reset_v3() if (IsGuildLeader()) then for i = 1, GetNumGuildMembers(1) do 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 self:update_epgp_v3(0,sepgp.VARS.basegp,i,name,officernote) end end local msg = L["All EP and GP has been reset to 0/%d."] 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: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.5) 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(use_main) local ep,gp if (use_main) then ep,gp = (self:get_ep_v3(sepgp_main) or 0), (self:get_gp_v3(sepgp_main) or sepgp.VARS.basegp) else ep,gp = (self:get_ep_v3(self._playerName) or 0), (self:get_gp_v3(self._playerName) or sepgp.VARS.basegp) end local pr = ep/gp local msg = string.format(L["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(L["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(use_main) GuildRoster() self:ScheduleEvent("shootyepgpRosterRefresh",self.my_epgp_announce,3,self,use_main) end --------- -- Menu --------- sepgp.hasIcon = "Interface\\PetitionFrame\\GuildCharter-Icon" sepgp.title = "shootyepgp" sepgp.defaultMinimapPosition = 180 sepgp.defaultPosition = "RIGHT" sepgp.cannotDetachTooltip = true sepgp.tooltipHiddenWhenEmpty = false sepgp.independentProfile = true function sepgp:OnTooltipUpdate() local hint = L["|cffffff00Click|r to toggle Standings.%s \n|cffffff00Right-Click|r for Options."] if (admin()) then hint = string.format(hint,L[" \n|cffffff00Ctrl+Click|r to toggle Reserves. \n|cffffff00Alt+Click|r to toggle Bids. \n|cffffff00Shift+Click|r to toggle Loot. \n|cffffff00Ctrl+Alt+Click|r to toggle Alts. \n|cffffff00Ctrl+Shift+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 IsShiftKeyDown() and is_admin) then sepgp_logs:Toggle() elseif (IsControlKeyDown() and IsAltKeyDown() and is_admin) then sepgp_alts:Toggle() elseif (IsControlKeyDown() and is_admin) then sepgp_reserves:Toggle() elseif (IsShiftKeyDown() and is_admin) then sepgp_loot:Toggle() elseif (IsAltKeyDown() and is_admin) then sepgp_bids:Toggle() else sepgp_standings:Toggle() end end function sepgp:SetRefresh(flag) needRefresh = flag if (flag) then self:refreshPRTablets() 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) if (name) then r[name] = true end end end sepgp.alts = {} for i = 1, numGuildMembers do local member_name,_,_,level,class,_,note,officernote,_,_ = GetGuildRosterInfo(i) if member_name and member_name ~= "" then local main, main_class, main_rank = self:parseAlt(member_name,officernote) local is_raid_level = tonumber(level) and level >= sepgp.VARS.minlevel if (main) then if ((self._playerName) and (name == self._playerName)) then if (not sepgp_main) or (sepgp_main and sepgp_main ~= main) then sepgp_main = main self:defaultPrint(L["Your main has been set to %s"],sepgp_main) end end main = C:Colorize(BC:GetHexColor(main_class), main) sepgp.alts[main] = sepgp.alts[main] or {} sepgp.alts[main][member_name] = class end if (sepgp_raidonly) and next(r) then if r[member_name] and is_raid_level then table.insert(g,{["name"]=member_name,["class"]=class}) end else if is_raid_level then table.insert(g,{["name"]=member_name,["class"]=class}) end end end end return g end function sepgp:buildClassMemberTable(roster,epgp) local desc,usage if epgp == "ep" then desc = L["Account EPs to %s."] usage = "" elseif epgp == "gp" then desc = L["Account GPs to %s."] usage = "" end local c = { } for i,member in ipairs(roster) do local class,name = member.class, member.name if (class) and (c[class] == nil) then c[class] = { } c[class].type = "group" c[class].name = C:Colorize(BC:GetHexColor(class),class) c[class].desc = class .. " members" c[class].hidden = function() return not (admin()) end c[class].args = { } end if (name) and (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)) sepgp:refreshPRTablets() end elseif epgp == "gp" then c[class].args[name].get = false c[class].args[name].set = function(v) sepgp:givename_gp(name, tonumber(v)) sepgp:refreshPRTablets() end end c[class].args[name].validate = function(v) return (type(v) == "number" or tonumber(v)) and tonumber(v) < sepgp.VARS.max end end end return c end --------------- -- Alts --------------- function sepgp:parseAlt(name,officernote) if (officernote) then local _,_,_,main,_ = string.find(officernote or "","(.*){([%a][%a]%a*)}(.*)") if type(main)=="string" and (string.len(main) < 13) then main = self:camelCase(main) local g_name, g_class, g_rank, g_officernote = self:verifyGuildMember(main) if (g_name) then return g_name, g_class, g_rank, g_officernote else return nil end else return nil end else for i=1,GetNumGuildMembers(1) do local g_name, _, _, _, g_class, _, g_note, g_officernote, _, _ = GetGuildRosterInfo(i) if (name == g_name) then return self:parseAlt(g_name, g_officernote) end end end return nil 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 self:RegisterEvent("CHAT_MSG_CHANNEL","captureReserveChatter") end return true else self:RegisterEvent("CHAT_MSG_CHANNEL_NOTICE","reservesChannelChange") JoinChannelByName(sepgp_reservechannel) return end else -- we want out if (reservesChannelID) and reservesChannelID ~= 0 then self:RegisterEvent("CHAT_MSG_CHANNEL_NOTICE","reservesChannelChange") LeaveChannelByName(sepgp_reservechannel) return else if self:IsEventRegistered("CHAT_MSG_CHANNEL") then self: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) self:RegisterEvent("CHAT_MSG_CHANNEL","captureReserveChatter") elseif msg == "YOU_LEFT" then sepgp.reservesChannelID = nil if self:IsEventRegistered("CHAT_MSG_CHANNEL") then self:UnregisterEvent("CHAT_MSG_CHANNEL") end end self: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 = sepgp.VARS.timeout sepgp.timer:Show() SendChatMessage(sepgp.VARS.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 == self._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,sepgp.VARS.reserveanswer) if (r) and (running_check) then if (rdy) then if (name) and (name ~= "") then 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 self:inRaid(sender)) then reserve, reserve_class, reserve_rank = self: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 self:defaultPrint(string.format(L["|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 self:defaultPrint(string.format(L["|cffff0000%s|r has already been added to Reserves. Discarding!"],reserve)) end end end end return end local q = string.find(text,L["^{shootyepgp}Type"]) if (q) and not (running_check) then if --[[(not UnitInRaid("player")) or]] (not self: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).+" } lootCall.bs = { -- blacklist "^(roll)[%s%p%c]+.+",".+[%s%p%c]+(roll)$",".*[%s%p%c]+(roll)[%s%p%c]+.*" } function sepgp:captureLootCall(text, sender) 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, blacklist_found for _,f in ipairs(lootCall.bs) do blacklist_found = string.find(lowtext,f) if (blacklist_found) then return end end 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 local quality = hexColorQuality[itemColor] or -1 if (quality >= 3) then if (IsRaidLeader() or self:lootMaster()) then self:clearBids(true) 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,300,self) running_bid = true self:debugPrint("Capturing Bids for 5min.") sepgp_bids:Toggle(true) -- Broadcast bid start to officers self:broadcastBidStart(itemString, itemLink, sepgp.bid_item.name) end self:bidPrint(itemLink,sender,mskw_found,oskw_found,whisperkw_found) end end end end local lootBid = {} lootBid.ms = {"(%+)",".+(%+).*",".*(%+).+",".*(%+).*","(ms)","(need)"} lootBid.os = {"(%-)",".+(%-).*",".*(%-).+",".*(%-).*","(os)","(greed)"} lootBid.msos = {".*[oO][sS][pP][rR][iI][oO].*"} 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, msoskw_found -- Check for + (mainspec) for _, f in ipairs(lootBid.ms) do if string.find(text, f) then mskw_found = true break end end -- Check for - (offspec) for _, f in ipairs(lootBid.os) do if string.find(text, f) then oskw_found = true break end end -- Check for OSPRIO for _, f in ipairs(lootBid.msos) do if string.find(text, f) then msoskw_found = true break end end if mskw_found or oskw_found or msoskw_found then if self:inRaid(sender) and not bids_blacklist[sender] then local prio_flag = "OSPRIO" for i = 1, GetNumGuildMembers() do local name, _, _, _, class, _, note, officernote, _, _ = GetGuildRosterInfo(i) if name == sender then local ep = (self:get_ep_v3(name, officernote) or 0) local gp = (self:get_gp_v3(name, officernote) or sepgp.VARS.basegp) local main_name -- If pooling alts into main's EPGP if sepgp_altspool then local alt_main, alt_class, _, alt_officernote = self:parseAlt(name, officernote) if alt_main then ep = (self:get_ep_v3(alt_main, alt_officernote) or 0) gp = (self:get_gp_v3(alt_main, alt_officernote) or sepgp.VARS.basegp) main_name = alt_main end end -- Mark them so we don't double-add bids_blacklist[sender] = true local pr = ep / gp if mskw_found then -- It's a + (Mainspec) if main_name then table.insert(sepgp.bids_main, {name, class, ep, gp, pr, main_name, ""}) else table.insert(sepgp.bids_main, {name, class, ep, gp, pr, "", ""}) end -- Queue broadcast to officers self:queueBidBroadcast("MS", name, class, ep, gp, pr, main_name or "", "") elseif oskw_found then -- It's a - (Offspec) if main_name then table.insert(sepgp.bids_off, {name, class, ep, gp, pr, main_name, ""}) else table.insert(sepgp.bids_off, {name, class, ep, gp, pr, "", ""}) end -- Queue broadcast to officers self:queueBidBroadcast("OS", name, class, ep, gp, pr, main_name or "", "") elseif msoskw_found then -- It's OSPRIO -> Also place in the Offspec table, -- but with "OSPRIO" flag so we can detect it in the GUI if main_name then table.insert(sepgp.bids_off, {name, class, ep, gp, pr, main_name, prio_flag}) else table.insert(sepgp.bids_off, {name, class, ep, gp, pr, "", prio_flag}) end -- Queue broadcast to officers self:queueBidBroadcast("OSPRIO", name, class, ep, gp, pr, main_name or "", prio_flag) end -- Refresh the bids window sepgp_bids:Toggle(true) return end end end end end function sepgp:clearBids(reset) if reset~=nil then self:debugPrint(L["Clearing old Bids"]) end -- Broadcast clear to officers if we are the ML/RL if (IsRaidLeader() or self:lootMaster()) and running_bid then self:broadcastBidClear() end sepgp.bid_item = {} sepgp.bids_main = {} sepgp.bids_off = {} bids_blacklist = {} bid_broadcast_queue = {} if self:IsEventScheduled("shootyepgpBidTimeout") then self:CancelScheduledEvent("shootyepgpBidTimeout") end if self:IsEventScheduled("shootyepgpBidBroadcast") then self:CancelScheduledEvent("shootyepgpBidBroadcast") end bid_broadcast_running = false running_bid = false sepgp_bids._counterText = "" sepgp_bids:Refresh() end ---------------- -- Loot Tracker ---------------- -- /script DEFAULT_CHAT_FRAME:AddMessage("\124cffa335ee\124Hitem:16864:0:0:0:0:0:0:0:0\124h[Belt of Might]\124h\124r"); -- test: "You receive loot: \124cffa335ee\124Hitem:16866:0:0:0\124h[Helm of Might]\124h\124r." -- test: /run sepgp:captureLoot("Raerlas receives loot: \124cffa335ee\124Hitem:16846:0:0:0\124h[Giantstalker's Helmet]\124h\124r.") -- test: /run sepgp:captureLoot("You receive loot: \124cffa335ee\124Hitem:16864:0:0:0\124h[Belt of Might]\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() and admin()) 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 self:processLoot(player,itemLink,"chat") end function sepgp:GiveMasterLoot(slot, index) if LootSlotIsItem(slot) then local texture, itemname, quantity, quality = GetLootSlotInfo(slot) if quantity == 1 and quality >= 3 then -- not a stack and rare or higher local itemLink = GetLootSlotLink(slot) local player = GetMasterLootCandidate(index) if not (player and itemLink) then return end self:processLoot(player,itemLink,"masterloot") 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() and admin()) 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("player","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) 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 function sepgp:testLootPrompt() raidStatus = UnitInRaid("player") and true or false if lastRaidStatus == nil then lastRaidStatus = raidStatus end if (raidStatus == false) and (lastRaidStatus == true) then local hasLoot = table.getn(sepgp_looted) local dialog = StaticPopup_FindVisible("SHOOTY_EPGP_CLEAR_LOOT") if (not (dialog)) and (hasLoot > 0) then StaticPopup_Show("SHOOTY_EPGP_CLEAR_LOOT",hasLoot) end end lastRaidStatus = raidStatus end ------------ -- Logging ------------ function sepgp:addToLog(line,skipTime) local over = table.getn(sepgp_log)-sepgp.VARS.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: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:processLootDupe(player,itemName,source) local now = GetTime() local player_name = player == YOU and self._playerName or player local player_item = string.format("%s%s",player_name,itemName) if ((self._lastPlayerItem) and self._lastPlayerItem == player_item) and ((self._lastPlayerItemTime) and (now - self._lastPlayerItemTime) < 3) and ((self._lastPlayerItemSource) and self._lastPlayerItemSource ~= source) then return true, player_item, now end return false, player_item, now end function sepgp:processLoot(player,itemLink,source) local link_found, _, itemColor, itemString, itemName = string.find(itemLink, "^(|c%x+)|H(.+)|h(%[.+%])") if link_found then local dupe, player_item, now = self:processLootDupe(player,itemName,source) if dupe then return end 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 player = self._playerName end if player == self._playerName then class = UnitClass("player") -- localized else _, class = self:verifyGuildMember(player,true) -- localized end if not (class) then return end self._lastPlayerItem, self._lastPlayerItemTime, self._lastPlayerItemSource = player_item, now, source 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: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) >= sepgp.VARS.minlevel) then -- == MAX_PLAYER_LEVEL]] return g_name, g_class, g_rank, g_officernote end end if (name) and name ~= "" and not (silent) then self:defaultPrint(string.format(L["%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 -- Check if player can receive bid broadcasts (Officer or Supreme leader rank) function sepgp:canReceiveBidBroadcast() if not IsInGuild() then return false end local playerName = self._playerName for i = 1, GetNumGuildMembers(true) do local name, rankName = GetGuildRosterInfo(i) if name == playerName then if rankName == "Officer" or rankName == "Supreme leader" then return true end return false end end return false end -- Serialize a single bid entry for broadcast -- Format: type~name~class~ep~gp~pr~main_name~prio_flag function sepgp:serializeBid(bidType, name, class, ep, gp, pr, main_name, prio_flag) return string.format("%s~%s~%s~%s~%s~%s~%s~%s", bidType or "", name or "", class or "", tostring(ep or 0), tostring(gp or 0), tostring(pr or 0), main_name or "", prio_flag or "") end -- Deserialize a bid entry from broadcast function sepgp:deserializeBid(data) local parts = {} local start = 1 while true do local pos = string.find(data, "~", start, true) if pos then table.insert(parts, string.sub(data, start, pos - 1)) start = pos + 1 else table.insert(parts, string.sub(data, start)) break end end return parts[1], parts[2], parts[3], tonumber(parts[4]) or 0, tonumber(parts[5]) or 0, tonumber(parts[6]) or 0, parts[7], parts[8] end -- Queue a bid for broadcast function sepgp:queueBidBroadcast(bidType, name, class, ep, gp, pr, main_name, prio_flag) local serialized = self:serializeBid(bidType, name, class, ep, gp, pr, main_name, prio_flag) table.insert(bid_broadcast_queue, serialized) -- Start broadcast timer if not already running if not bid_broadcast_running then bid_broadcast_running = true self:ScheduleRepeatingEvent("shootyepgpBidBroadcast", self.sendBidBroadcast, BROADCAST_INTERVAL, self) end end -- Send queued bids via addon message function sepgp:sendBidBroadcast() if table.getn(bid_broadcast_queue) == 0 then -- No more bids to send, stop the timer if self:IsEventScheduled("shootyepgpBidBroadcast") then self:CancelScheduledEvent("shootyepgpBidBroadcast") end bid_broadcast_running = false return end -- Send all queued bids in one message (comma-separated) local bidsData = table.concat(bid_broadcast_queue, ",") local addonMsg = string.format("BIDS;%s;1", bidsData) -- Broadcast to raid if in raid, otherwise do nothing if GetNumRaidMembers() > 0 then self:addonMessage(addonMsg, "RAID") end -- Clear the queue bid_broadcast_queue = {} end -- Broadcast bid start (item info) to officers function sepgp:broadcastBidStart(itemString, itemLink, itemName) if GetNumRaidMembers() == 0 then return end -- Extract just the item ID from itemString (e.g., "item:12345:0:0:0" -> "12345") local _, _, itemID = string.find(itemString, "item:(%d+)") if not itemID then return end -- Send only the item ID - receiver will use GetItemInfo to get the rest local addonMsg = string.format("BIDSTART;%s;1", itemID) self:addonMessage(addonMsg, "RAID") end -- Broadcast bid clear to officers function sepgp:broadcastBidClear() if GetNumRaidMembers() == 0 then return end local addonMsg = "BIDCLEAR;1;1" self:addonMessage(addonMsg, "RAID") end -- Broadcast attention signal to officers (plays sound) function sepgp:broadcastBidAttention() if GetNumRaidMembers() == 0 then return end local addonMsg = "BIDATTENTION;1;1" self:addonMessage(addonMsg, "RAID") end -- Play attention notification sound function sepgp:playAttentionSound() PlaySoundFile("Interface\\AddOns\\shootyepgp\\Sounds\\notification.wav") end function sepgp:testMain() if (sepgp_main == nil) or (sepgp_main == "") then if (IsInGuild()) then StaticPopup_Show("SHOOTY_EPGP_SET_MAIN") end end end function sepgp:make_escable(framename,operation) local found for i,f in ipairs(UISpecialFrames) do if f==framename then found = i end end if not found and operation=="add" then table.insert(UISpecialFrames,framename) elseif found and operation=="remove" then table.remove(UISpecialFrames,found) end end local raidZones = {[L["Molten Core"]]="T1",[L["Onyxia\'s Lair"]]="T1.5",[L["Blackwing Lair"]]="T2",[L["Ahn\'Qiraj"]]="T2.5",[L["Naxxramas"]]="T3",[L["Tower of Karazhan"]]="T3.5"} -- Updated zone_multipliers table with added "T3.5" columns and a new row for raid progress "T3.5": local zone_multipliers = { ["T3.5"] = { ["T3.5"] = 1, ["T3"] = 0.8, ["T2.5"] = 0.65, ["T2"] = 0.5, ["T1.5"] = 0.3, ["T1"] = 0.3 }, ["T3"] = { ["T3.5"] = 1, ["T3"] = 1, ["T2.5"] = 0.75, ["T2"] = 0.5, ["T1.5"] = 0.25, ["T1"] = 0.25 }, ["T2.5"] = { ["T3.5"] = 1, ["T3"] = 1, ["T2.5"] = 1, ["T2"] = 0.7, ["T1.5"] = 0.4, ["T1"] = 0.4 }, ["T2"] = { ["T3.5"] = 1, ["T3"] = 1, ["T2.5"] = 1, ["T2"] = 1, ["T1.5"] = 0.5, ["T1"] = 0.5 }, ["T1"] = { ["T3.5"] = 1, ["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 sepgp.VARS.baseaward_ep else multiplier = zone_multipliers[sepgp_progress][currentTier] end if (multiplier) then return multiplier*sepgp.VARS.baseaward_ep else return sepgp.VARS.baseaward_ep end end function sepgp:parseVersion(version,otherVersion) if not sepgp._version then sepgp._version = {} end for major,minor,patch in string.gfind(version,"(%d+)[^%d]?(%d*)[^%d]?(%d*)") do sepgp._version.major = tonumber(major) sepgp._version.minor = tonumber(minor) sepgp._version.patch = tonumber(patch) end if (otherVersion) then if not sepgp._otherversion then sepgp._otherversion = {} end for major,minor,patch in string.gfind(otherVersion,"(%d+)[^%d]?(%d*)[^%d]?(%d*)") do sepgp._otherversion.major = tonumber(major) sepgp._otherversion.minor = tonumber(minor) sepgp._otherversion.patch = tonumber(patch) end if (sepgp._otherversion.major ~= nil and sepgp._version.major ~= nil) then if (sepgp._otherversion.major < sepgp._version.major) then -- we are newer return elseif (sepgp._otherversion.major > sepgp._version.major) then -- they are newer return true, "major" else -- tied on major, go minor if (sepgp._otherversion.minor ~= nil and sepgp._version.minor ~= nil) then if (sepgp._otherversion.minor < sepgp._version.minor) then -- we are newer return elseif (sepgp._otherversion.minor > sepgp._version.minor) then -- they are newer return true, "minor" else -- tied on minor, go patch if (sepgp._otherversion.patch ~= nil and sepgp._version.patch ~= nil) then if (sepgp._otherversion.patch < sepgp._version.patch) then -- we are newer return elseif (sepgp._otherversion.patch > sepgp._version.patch) then -- they are newwer return true, "patch" end elseif (sepgp._otherversion.patch ~= nil and sepgp._version.patch == nil) then -- they are newer return true, "patch" end end elseif (sepgp._otherversion.minor ~= nil and sepgp._version.minor == nil) then -- they are newer return true, "minor" end end end end end function sepgp:camelCase(word) return string.gsub(word,"(%a)([%w_']*)",function(head,tail) return string.format("%s%s",string.upper(head),string.lower(tail)) end) end admin = function() return (CanEditOfficerNote() --[[and CanEditPublicNote()]]) end sanitizeNote = function(prefix,epgp,postfix) -- reserve 12 chars for the epgp pattern {xxxxx:yyyy} max public/officernote = 31 local remainder = string.format("%s%s",prefix,postfix) local clip = math.min(31-12,string.len(remainder)) local prepend = string.sub(remainder,1,clip) return string.format("%s%s",prepend,epgp) end ------------- -- Dialogs ------------- StaticPopupDialogs["SHOOTY_EPGP_CLEAR_LOOT"] = { text = L["There are %d loot drops stored. It is recommended to clear loot info before a new raid. Do you want to clear it now?"], button1 = TEXT(YES), button2 = L["Show me"], OnAccept = function() sepgp_looted = {} sepgp:defaultPrint(L["Loot info cleared"]) end, OnCancel = function(_,reason) if reason == "clicked" then sepgp_loot:Toggle(true) sepgp:defaultPrint(L["Loot info can be cleared at any time from the Tablet context menu or '/shooty clearloot' command"]) end end, timeout = 0, whileDead = 1, exclusive = 0, hideOnEscape = 1 } StaticPopupDialogs["SHOOTY_EPGP_SET_MAIN"] = { text = L["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") local name = sepgp:camelCase(editBox:GetText()) sepgp_main = sepgp:verifyGuildMember(name) 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 = " ", button1 = TEXT(YES), button2 = TEXT(NO), OnShow = function() this._timeout = sepgp.VARS.timeout-1 end, OnUpdate = function(elapsed,dialog) this._timeout = this._timeout - elapsed getglobal(dialog:GetName().."Text"):SetText(string.format(L["Reserves AFKCheck. Are you available? |cff00ff00%0d|rsec."],this._timeout)) if (this._timeout<=0) then this._timeout = 0 dialog:Hide() end end, OnAccept = function() this._timeout = 0 sepgp:sendReserverResponce() end, timeout = 0,--sepgp.VARS.timeout, exclusive = 1, showAlert = 1, whileDead = 1, hideOnEscape = 1 } StaticPopupDialogs["SHOOTY_EPGP_CONFIRM_RESET"] = { text = L["|cffff0000Are you sure you want to Reset ALL EPGP?|r"], button1 = TEXT(OKAY), button2 = TEXT(CANCEL), OnAccept = function() sepgp:gp_reset_v3() end, timeout = 0, whileDead = 1, exclusive = 1, showAlert = 1, hideOnEscape = 1 } -- Xmog Player Selection Frame function sepgp:ShowXmogPlayerSelection(data) -- Create frame if it doesn't exist if not sepgp_xmog_frame then sepgp_xmog_frame = CreateFrame("Frame", "SepgpXmogFrame", UIParent) sepgp_xmog_frame:SetWidth(280) sepgp_xmog_frame:SetHeight(400) sepgp_xmog_frame:SetPoint("CENTER", UIParent, "CENTER") sepgp_xmog_frame:SetBackdrop({ bgFile = "Interface\\DialogFrame\\UI-DialogBox-Background", edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Border", tile = true, tileSize = 32, edgeSize = 32, insets = { left = 11, right = 12, top = 12, bottom = 11 } }) sepgp_xmog_frame:SetBackdropColor(0, 0, 0, 1) sepgp_xmog_frame:EnableMouse(true) sepgp_xmog_frame:SetMovable(true) sepgp_xmog_frame:RegisterForDrag("LeftButton") sepgp_xmog_frame:SetScript("OnDragStart", function() this:StartMoving() end) sepgp_xmog_frame:SetScript("OnDragStop", function() this:StopMovingOrSizing() end) sepgp_xmog_frame:SetFrameStrata("DIALOG") -- Title local title = sepgp_xmog_frame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge") title:SetPoint("TOP", 0, -15) title:SetText("Who won the item?") sepgp_xmog_frame.title = title -- Close button local closeBtn = CreateFrame("Button", nil, sepgp_xmog_frame, "UIPanelCloseButton") closeBtn:SetPoint("TOPRIGHT", -5, -5) closeBtn:SetScript("OnClick", function() sepgp_xmog_frame:Hide() end) -- Scroll frame local scrollFrame = CreateFrame("ScrollFrame", "SepgpXmogScrollFrame", sepgp_xmog_frame, "UIPanelScrollFrameTemplate") scrollFrame:SetPoint("TOPLEFT", 20, -40) scrollFrame:SetPoint("BOTTOMRIGHT", -30, 15) -- Content frame local contentFrame = CreateFrame("Frame", nil, scrollFrame) contentFrame:SetWidth(230) contentFrame:SetHeight(1) scrollFrame:SetScrollChild(contentFrame) sepgp_xmog_frame.contentFrame = contentFrame sepgp_xmog_frame.scrollFrame = scrollFrame -- Store player rows for reuse sepgp_xmog_frame.playerRows = {} end -- Store the loot data for later use sepgp_xmog_frame.lootData = data -- Clear existing rows for _, row in ipairs(sepgp_xmog_frame.playerRows) do row:Hide() end -- Get raid members local raidMembers = {} if GetNumRaidMembers() > 0 then for i = 1, GetNumRaidMembers(true) do local name, rank, subgroup, level, class, fileName, zone, online, isDead = GetRaidRosterInfo(i) if name and class then table.insert(raidMembers, {name = name, class = class}) end end end -- Define class order for sorting (Warrior, Paladin, Rogue, etc.) local classOrder = { ["Warrior"] = 1, ["Paladin"] = 2, ["Hunter"] = 3, ["Rogue"] = 4, ["Priest"] = 5, ["Shaman"] = 6, ["Mage"] = 7, ["Warlock"] = 8, ["Druid"] = 9 } -- Sort by class order, then by name table.sort(raidMembers, function(a, b) local orderA = classOrder[a.class] or 99 local orderB = classOrder[b.class] or 99 if orderA == orderB then return a.name < b.name end return orderA < orderB end) -- Create/update player rows local yOffset = -2 for i, member in ipairs(raidMembers) do local row = sepgp_xmog_frame.playerRows[i] if not row then row = CreateFrame("Frame", nil, sepgp_xmog_frame.contentFrame) row:SetWidth(230) row:SetHeight(20) -- Player name row.nameText = row:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall") row.nameText:SetPoint("LEFT", 5, 0) row.nameText:SetWidth(95) row.nameText:SetJustifyH("LEFT") -- MS button row.msBtn = CreateFrame("Button", nil, row) row.msBtn:SetWidth(38) row.msBtn:SetHeight(18) row.msBtn:SetPoint("LEFT", row.nameText, "RIGHT", 3, 0) row.msBtn:SetBackdrop({ bgFile = "Interface\\Buttons\\WHITE8X8", edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border", tile = true, tileSize = 8, edgeSize = 12, insets = { left = 2, right = 2, top = 2, bottom = 2 } }) row.msBtn:SetBackdropColor(0.4, 0.15, 0.15, 1) row.msBtn:SetBackdropBorderColor(0.3, 0.1, 0.1, 1) row.msBtn.text = row.msBtn:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall") row.msBtn.text:SetPoint("CENTER", 0, 0) row.msBtn.text:SetText("MS") row.msBtn:SetScript("OnEnter", function() this:SetBackdropColor(0.5, 0.2, 0.2, 1) end) row.msBtn:SetScript("OnLeave", function() this:SetBackdropColor(0.4, 0.15, 0.15, 1) end) row.msBtn:SetScript("OnClick", function() sepgp:AwardXmogGP(this:GetParent().playerName, "ms") end) -- OS button row.osBtn = CreateFrame("Button", nil, row) row.osBtn:SetWidth(38) row.osBtn:SetHeight(18) row.osBtn:SetPoint("LEFT", row.msBtn, "RIGHT", 1, 0) row.osBtn:SetBackdrop({ bgFile = "Interface\\Buttons\\WHITE8X8", edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border", tile = true, tileSize = 8, edgeSize = 12, insets = { left = 2, right = 2, top = 2, bottom = 2 } }) row.osBtn:SetBackdropColor(0.45, 0.28, 0.15, 1) row.osBtn:SetBackdropBorderColor(0.35, 0.22, 0.1, 1) row.osBtn.text = row.osBtn:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall") row.osBtn.text:SetPoint("CENTER", 0, 0) row.osBtn.text:SetText("OS") row.osBtn:SetScript("OnEnter", function() this:SetBackdropColor(0.55, 0.35, 0.2, 1) end) row.osBtn:SetScript("OnLeave", function() this:SetBackdropColor(0.45, 0.28, 0.15, 1) end) row.osBtn:SetScript("OnClick", function() sepgp:AwardXmogGP(this:GetParent().playerName, "os") end) -- DE button row.deBtn = CreateFrame("Button", nil, row) row.deBtn:SetWidth(38) row.deBtn:SetHeight(18) row.deBtn:SetPoint("LEFT", row.osBtn, "RIGHT", 1, 0) row.deBtn:SetBackdrop({ bgFile = "Interface\\Buttons\\WHITE8X8", edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border", tile = true, tileSize = 8, edgeSize = 12, insets = { left = 2, right = 2, top = 2, bottom = 2 } }) row.deBtn:SetBackdropColor(0.2, 0.2, 0.2, 1) row.deBtn:SetBackdropBorderColor(0.4, 0.4, 0.4, 1) row.deBtn.text = row.deBtn:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall") row.deBtn.text:SetPoint("CENTER", 0, 0) row.deBtn.text:SetText("DE") row.deBtn:SetScript("OnEnter", function() this:SetBackdropColor(0.4, 0.4, 0.4, 1) end) row.deBtn:SetScript("OnLeave", function() this:SetBackdropColor(0.2, 0.2, 0.2, 1) end) row.deBtn:SetScript("OnClick", function() sepgp:AwardXmogGP(this:GetParent().playerName, "de") end) sepgp_xmog_frame.playerRows[i] = row end row:SetPoint("TOPLEFT", 0, yOffset) row.playerName = member.name -- Set player name with class color local coloredName = C:Colorize(BC:GetHexColor(member.class), member.name) row.nameText:SetText(coloredName) row:Show() yOffset = yOffset - 20 end -- Update content frame height sepgp_xmog_frame.contentFrame:SetHeight(math.max(1, table.getn(raidMembers) * 20 + 5)) -- Show the frame sepgp_xmog_frame:Show() end -- Award GP from Xmog selection function sepgp:AwardXmogGP(playerName, gpType) if not sepgp_xmog_frame or not sepgp_xmog_frame.lootData then return end local data = sepgp_xmog_frame.lootData local price = data[sepgp.loot_index.price] local off_price = data[sepgp.loot_index.off_price] local itemLink = data[sepgp.loot_index.item] local gp = 0 local actionText = "" if gpType == "ms" then gp = price actionText = sepgp.VARS.msgp elseif gpType == "os" then gp = off_price actionText = sepgp.VARS.osgp elseif gpType == "de" then gp = 0 actionText = sepgp.VARS.bankde end -- Award GP if applicable if gp > 0 then sepgp:givename_gp((playerName == YOU and sepgp._playerName or playerName), gp) sepgp:refreshPRTablets() end -- Update loot record with xmog info data[sepgp.loot_index.action] = string.format("Xmog (%s: %s)", playerName, actionText) local update = data[sepgp.loot_index.update] ~= nil sepgp:addOrUpdateLoot(data, update) sepgp_loot:Refresh() -- Hide the frame sepgp_xmog_frame:Hide() end local sepgp_auto_gp_menu = { --{text = "Choose an Action", isTitle = true}, {text = L["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 sepgp._playerName or player),price) sepgp:refreshPRTablets() 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 = L["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 sepgp._playerName or player),off_price) sepgp:refreshPRTablets() 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 = L["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}, {text = L["Xmog"], func = function() local dialog = StaticPopup_FindVisible("SHOOTY_EPGP_AUTO_GEARPOINTS") if (dialog) then local data = dialog.data sepgp:ShowXmogPlayerSelection(data) StaticPopup_Hide("SHOOTY_EPGP_AUTO_GEARPOINTS") end end} } StaticPopupDialogs["SHOOTY_EPGP_AUTO_GEARPOINTS"] = { text = L["%s looted %s. What do you want to do?"], button1 = L["GP Actions"], button2 = L["Remind me Later"], OnAccept = function() sepgp:EasyMenu(sepgp_auto_gp_menu, sepgp._menuFrame, this, 0, 0, "MENU", 1) 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() sepgp._menuFrame = sepgp._menuFrame or CreateFrame("Frame", "sepgp_auto_gp_menuframe", UIParent, "UIDropDownMenuTemplate") end, OnHide = function() CloseDropDownMenus() end, timeout = 0, exclusive = 1, whileDead = 1, hideOnEscape = 1 } function sepgp:EasyMenu_Initialize(level, menuList) for i, info in ipairs(menuList) do if (info.text) then info.index = i UIDropDownMenu_AddButton( info, level ) end end end function sepgp:EasyMenu(menuList, menuFrame, anchor, x, y, displayMode, level) if ( displayMode == "MENU" ) then menuFrame.displayMode = displayMode end UIDropDownMenu_Initialize(menuFrame, function() sepgp:EasyMenu_Initialize(level, menuList) end, displayMode, level) ToggleDropDownMenu(1, nil, menuFrame, anchor, x, y) end -- GLOBALS: sepgp_saychannel,sepgp_groupbyclass,sepgp_groupbyarmor,sepgp_groupbyrole,sepgp_raidonly,sepgp_decay,sepgp_minep,sepgp_reservechannel,sepgp_main,sepgp_progress,sepgp_discount,sepgp_altspool,sepgp_altpercent,sepgp_log,sepgp_dbver,sepgp_looted,sepgp_debug,sepgp_fubar -- GLOBALS: sepgp,sepgp_prices,sepgp_standings,sepgp_bids,sepgp_loot,sepgp_reserves,sepgp_alts,sepgp_logs