BenchTracker = {} local mainFrame = nil local playerFrames = {} local logEntries = {} local currentCheckData = {} local isListening = false local listenTimer = nil local listenElapsed = 0 local checkCounter = 0 local activeTab = "afk" local previousRaidRoster = {} local rosterInitialized = false -- Class colors (same as raidstrike) local CLASS_COLORS = { ["WARRIOR"] = {r = 0.78, g = 0.61, b = 0.43}, ["PALADIN"] = {r = 0.96, g = 0.55, b = 0.73}, ["HUNTER"] = {r = 0.67, g = 0.83, b = 0.45}, ["ROGUE"] = {r = 1.0, g = 0.96, b = 0.41}, ["PRIEST"] = {r = 1.0, g = 1.0, b = 1.0}, ["SHAMAN"] = {r = 0.0, g = 0.44, b = 0.87}, ["MAGE"] = {r = 0.41, g = 0.8, b = 0.94}, ["WARLOCK"] = {r = 0.58, g = 0.51, b = 0.79}, ["DRUID"] = {r = 1.0, g = 0.49, b = 0.04} } local LOCALIZED_CLASS_LOOKUP = { ["Warrior"] = "WARRIOR", ["Paladin"] = "PALADIN", ["Hunter"] = "HUNTER", ["Rogue"] = "ROGUE", ["Priest"] = "PRIEST", ["Shaman"] = "SHAMAN", ["Mage"] = "MAGE", ["Warlock"] = "WARLOCK", ["Druid"] = "DRUID", ["Krieger"] = "WARRIOR", ["Jager"] = "HUNTER", ["Schurke"] = "ROGUE", ["Priester"] = "PRIEST", ["Schamane"] = "SHAMAN", ["Magier"] = "MAGE", ["Hexenmeister"] = "WARLOCK", ["Druide"] = "DRUID", ["Guerrier"] = "WARRIOR", ["Chasseur"] = "HUNTER", ["Voleur"] = "ROGUE", ["Chaman"] = "SHAMAN", } function BenchTracker:GetEnglishClass(localizedClass) if not localizedClass then return nil end local upperClass = string.upper(localizedClass) if CLASS_COLORS[upperClass] then return upperClass end local englishClass = LOCALIZED_CLASS_LOOKUP[localizedClass] if englishClass then return englishClass end return upperClass end function BenchTracker:IsOfficer() local numMembers = GetNumGuildMembers() local playerName = UnitName("player") for i = 1, numMembers do local name, rank, rankIndex = GetGuildRosterInfo(i) if name == playerName then if rank == "Officer" or rank == "Supreme Leader" then return true end return false end end return false end function BenchTracker:GetTimestamp() local dateInfo = date("*t") local day = dateInfo.day local month = dateInfo.month local year = dateInfo.year local hour = dateInfo.hour local min = dateInfo.min local dayStr = day local monthStr = month if day < 10 then dayStr = "0" .. day end if month < 10 then monthStr = "0" .. month end local hourStr = hour local minStr = min if hour < 10 then hourStr = "0" .. hour end if min < 10 then minStr = "0" .. min end return "[" .. dayStr .. "/" .. monthStr .. "/" .. year .. " - " .. hourStr .. ":" .. minStr .. "]" end -- Get list of raid members (bench group) function BenchTracker:GetRaidMembers() local members = {} local raidSize = GetNumRaidMembers() if raidSize == 0 then return members end for i = 1, raidSize do local name, rank, subgroup, level, class = GetRaidRosterInfo(i) if name then table.insert(members, {name = name, class = class, subgroup = subgroup}) end end -- Sort alphabetically table.sort(members, function(a, b) return a.name < b.name end) return members end ---------------------------------------------------------------- -- MAIN FRAME ---------------------------------------------------------------- function BenchTracker:CreateMainFrame() if mainFrame then return end mainFrame = CreateFrame("Frame", "BenchTrackerFrame", UIParent) mainFrame:SetWidth(280) mainFrame:SetHeight(380) mainFrame:SetPoint("CENTER", UIParent, "CENTER", 0, 0) mainFrame:SetBackdrop({ bgFile = "Interface\\Tooltips\\UI-Tooltip-Background", edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border", tile = true, tileSize = 16, edgeSize = 8, insets = {left = 2, right = 2, top = 2, bottom = 2} }) mainFrame:SetBackdropColor(0.05, 0.05, 0.05, 0.95) mainFrame:SetBackdropBorderColor(0.3, 0.3, 0.3, 1) mainFrame:SetMovable(true) mainFrame:EnableMouse(true) mainFrame:RegisterForDrag("LeftButton") mainFrame:SetScript("OnDragStart", function() this:StartMoving() end) mainFrame:SetScript("OnDragStop", function() this:StopMovingOrSizing() end) mainFrame:SetFrameStrata("DIALOG") mainFrame:Hide() -- Title local title = mainFrame:CreateFontString(nil, "OVERLAY", "GameFontNormal") title:SetPoint("TOP", mainFrame, "TOP", 0, -8) title:SetText("Bench Tracker") title:SetTextColor(0.9, 0.9, 0.9, 1) -- Close button local closeButton = CreateFrame("Button", nil, mainFrame) closeButton:SetWidth(12) closeButton:SetHeight(12) closeButton:SetPoint("TOPRIGHT", mainFrame, "TOPRIGHT", -6, -6) closeButton:SetBackdrop({ bgFile = "Interface\\Tooltips\\UI-Tooltip-Background", edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border", tile = true, tileSize = 8, edgeSize = 4, insets = {left = 1, right = 1, top = 1, bottom = 1} }) closeButton:SetBackdropColor(0.8, 0.2, 0.2, 0.8) closeButton:SetBackdropBorderColor(0.6, 0.6, 0.6, 1) local closeText = closeButton:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall") closeText:SetPoint("CENTER", closeButton, "CENTER", 0, 0) closeText:SetText("x") closeText:SetTextColor(1, 1, 1, 1) closeButton:SetScript("OnEnter", function() this:SetBackdropColor(1, 0.3, 0.3, 1) end) closeButton:SetScript("OnLeave", function() this:SetBackdropColor(0.8, 0.2, 0.2, 0.8) end) closeButton:SetScript("OnClick", function() mainFrame:Hide() end) -- Tab buttons BenchTracker:CreateTabButtons() -- AFK Check content area local afkContent = CreateFrame("Frame", "BenchAfkContent", mainFrame) afkContent:SetPoint("TOPLEFT", mainFrame, "TOPLEFT", 6, -42) afkContent:SetPoint("BOTTOMRIGHT", mainFrame, "BOTTOMRIGHT", -6, 6) afkContent:SetBackdrop({ bgFile = "Interface\\Tooltips\\UI-Tooltip-Background", edgeFile = nil, tile = true, tileSize = 16, insets = {left = 0, right = 0, top = 0, bottom = 0} }) afkContent:SetBackdropColor(0.08, 0.08, 0.08, 0.5) mainFrame.afkContent = afkContent -- Column labels above the list (centered over the radio buttons) local readyLabel = afkContent:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall") readyLabel:SetPoint("TOP", afkContent, "TOPRIGHT", -50, -2) readyLabel:SetText("|cFF00CC00R|r") readyLabel:SetTextColor(0.0, 0.8, 0.0, 1) mainFrame.colReadyLabel = readyLabel local afkLabel = afkContent:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall") afkLabel:SetPoint("TOP", afkContent, "TOPRIGHT", -32, -2) afkLabel:SetText("|cFFCC0000A|r") afkLabel:SetTextColor(0.8, 0.0, 0.0, 1) mainFrame.colAfkLabel = afkLabel -- Scroll frame for AFK list local scrollFrame = CreateFrame("ScrollFrame", "BenchAfkScrollFrame", afkContent, "UIPanelScrollFrameTemplate") scrollFrame:SetPoint("TOPLEFT", afkContent, "TOPLEFT", 2, -14) scrollFrame:SetPoint("BOTTOMRIGHT", afkContent, "BOTTOMRIGHT", -2, 26) local scrollChild = CreateFrame("Frame", "BenchAfkScrollChild", scrollFrame) scrollChild:SetWidth(245) scrollChild:SetHeight(1) scrollFrame:SetScrollChild(scrollChild) mainFrame.afkScrollFrame = scrollFrame mainFrame.afkScrollChild = scrollChild -- Style scrollbar BenchTracker:StyleScrollbar(scrollFrame) -- AFK Check button (bottom-left of afk content) local afkBtn = CreateFrame("Button", nil, afkContent) afkBtn:SetWidth(85) afkBtn:SetHeight(18) afkBtn:SetPoint("BOTTOMLEFT", afkContent, "BOTTOMLEFT", 4, 4) afkBtn:SetBackdrop({ bgFile = "Interface\\Tooltips\\UI-Tooltip-Background", edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border", tile = true, tileSize = 8, edgeSize = 4, insets = {left = 1, right = 1, top = 1, bottom = 1} }) afkBtn:SetBackdropColor(0.6, 0.3, 0.0, 0.9) afkBtn:SetBackdropBorderColor(0.5, 0.5, 0.5, 1) local afkBtnText = afkBtn:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall") afkBtnText:SetPoint("CENTER", afkBtn, "CENTER", 0, 0) afkBtnText:SetText("AFK Check") afkBtnText:SetTextColor(1, 1, 1, 1) afkBtn:SetScript("OnEnter", function() this:SetBackdropColor(0.8, 0.4, 0.0, 1) end) afkBtn:SetScript("OnLeave", function() this:SetBackdropColor(0.6, 0.3, 0.0, 0.9) end) afkBtn:SetScript("OnClick", function() BenchTracker:StartAFKCheck() end) mainFrame.afkButton = afkBtn -- Add to Log button (bottom-right of afk content) local logBtn = CreateFrame("Button", nil, afkContent) logBtn:SetWidth(85) logBtn:SetHeight(18) logBtn:SetPoint("BOTTOMRIGHT", afkContent, "BOTTOMRIGHT", -4, 4) logBtn:SetBackdrop({ bgFile = "Interface\\Tooltips\\UI-Tooltip-Background", edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border", tile = true, tileSize = 8, edgeSize = 4, insets = {left = 1, right = 1, top = 1, bottom = 1} }) logBtn:SetBackdropColor(0.2, 0.4, 0.6, 0.9) logBtn:SetBackdropBorderColor(0.5, 0.5, 0.5, 1) local logBtnText = logBtn:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall") logBtnText:SetPoint("CENTER", logBtn, "CENTER", 0, 0) logBtnText:SetText("Add to Log") logBtnText:SetTextColor(1, 1, 1, 1) logBtn:SetScript("OnEnter", function() this:SetBackdropColor(0.3, 0.5, 0.7, 1) end) logBtn:SetScript("OnLeave", function() this:SetBackdropColor(0.2, 0.4, 0.6, 0.9) end) logBtn:SetScript("OnClick", function() BenchTracker:ManualLogAFKCheck() end) mainFrame.logButton = logBtn -- Log content area local logContent = CreateFrame("Frame", "BenchLogContent", mainFrame) logContent:SetPoint("TOPLEFT", mainFrame, "TOPLEFT", 6, -42) logContent:SetPoint("BOTTOMRIGHT", mainFrame, "BOTTOMRIGHT", -6, 6) logContent:SetBackdrop({ bgFile = "Interface\\Tooltips\\UI-Tooltip-Background", edgeFile = nil, tile = true, tileSize = 16, insets = {left = 0, right = 0, top = 0, bottom = 0} }) logContent:SetBackdropColor(0.08, 0.08, 0.08, 0.5) logContent:Hide() mainFrame.logContent = logContent -- Clear Log button (bottom of log content) local clearLogBtn = CreateFrame("Button", nil, logContent) clearLogBtn:SetWidth(70) clearLogBtn:SetHeight(18) clearLogBtn:SetPoint("BOTTOM", logContent, "BOTTOM", 0, 4) clearLogBtn:SetBackdrop({ bgFile = "Interface\\Tooltips\\UI-Tooltip-Background", edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border", tile = true, tileSize = 8, edgeSize = 4, insets = {left = 1, right = 1, top = 1, bottom = 1} }) clearLogBtn:SetBackdropColor(0.5, 0.15, 0.15, 0.9) clearLogBtn:SetBackdropBorderColor(0.5, 0.5, 0.5, 1) local clearLogText = clearLogBtn:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall") clearLogText:SetPoint("CENTER", clearLogBtn, "CENTER", 0, 0) clearLogText:SetText("Clear Log") clearLogText:SetTextColor(1, 1, 1, 1) clearLogBtn:SetScript("OnEnter", function() this:SetBackdropColor(0.7, 0.2, 0.2, 1) end) clearLogBtn:SetScript("OnLeave", function() this:SetBackdropColor(0.5, 0.15, 0.15, 0.9) end) clearLogBtn:SetScript("OnClick", function() BenchTracker:ClearLog() end) mainFrame.clearLogButton = clearLogBtn -- Scroll frame for Log local logScrollFrame = CreateFrame("ScrollFrame", "BenchLogScrollFrame", logContent, "UIPanelScrollFrameTemplate") logScrollFrame:SetPoint("TOPLEFT", logContent, "TOPLEFT", 2, -2) logScrollFrame:SetPoint("BOTTOMRIGHT", logContent, "BOTTOMRIGHT", -2, 26) local logScrollChild = CreateFrame("Frame", "BenchLogScrollChild", logScrollFrame) logScrollChild:SetWidth(245) logScrollChild:SetHeight(1) logScrollFrame:SetScrollChild(logScrollChild) mainFrame.logScrollFrame = logScrollFrame mainFrame.logScrollChild = logScrollChild BenchTracker:StyleScrollbar(logScrollFrame) end function BenchTracker:StyleScrollbar(scrollFrame) local scrollBar = getglobal(scrollFrame:GetName() .. "ScrollBar") if scrollBar then scrollBar:ClearAllPoints() scrollBar:SetPoint("TOPRIGHT", scrollFrame, "TOPRIGHT", 0, -16) scrollBar:SetPoint("BOTTOMRIGHT", scrollFrame, "BOTTOMRIGHT", 0, 16) scrollBar:SetWidth(5) scrollBar:SetBackdrop({ bgFile = "Interface\\Tooltips\\UI-Tooltip-Background", edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border", tile = true, tileSize = 8, edgeSize = 2, insets = {left = 1, right = 1, top = 1, bottom = 1} }) scrollBar:SetBackdropColor(0.15, 0.15, 0.15, 0.8) scrollBar:SetBackdropBorderColor(0.3, 0.3, 0.3, 0.6) local thumb = getglobal(scrollBar:GetName() .. "ThumbTexture") if thumb then thumb:SetTexture("Interface\\Tooltips\\UI-Tooltip-Background") thumb:SetVertexColor(0.9, 0.9, 0.9, 0.9) thumb:SetWidth(8) end local upButton = getglobal(scrollBar:GetName() .. "ScrollUpButton") local downButton = getglobal(scrollBar:GetName() .. "ScrollDownButton") if upButton then upButton:SetWidth(0) end if downButton then downButton:SetWidth(0) end end end ---------------------------------------------------------------- -- TAB BUTTONS ---------------------------------------------------------------- function BenchTracker:CreateTabButtons() -- AFK Check tab local tabAfk = CreateFrame("Button", "BenchTabAfk", mainFrame) tabAfk:SetWidth(80) tabAfk:SetHeight(16) tabAfk:SetPoint("TOPLEFT", mainFrame, "TOPLEFT", 8, -22) tabAfk:SetBackdrop({ bgFile = "Interface\\Tooltips\\UI-Tooltip-Background", edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border", tile = true, tileSize = 8, edgeSize = 4, insets = {left = 1, right = 1, top = 1, bottom = 1} }) local tabAfkText = tabAfk:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall") tabAfkText:SetPoint("CENTER", tabAfk, "CENTER", 0, 0) tabAfkText:SetText("AFK Check") tabAfk:SetScript("OnClick", function() BenchTracker:SwitchTab("afk") end) mainFrame.tabAfk = tabAfk mainFrame.tabAfkText = tabAfkText -- Log tab local tabLog = CreateFrame("Button", "BenchTabLog", mainFrame) tabLog:SetWidth(80) tabLog:SetHeight(16) tabLog:SetPoint("LEFT", tabAfk, "RIGHT", 4, 0) tabLog:SetBackdrop({ bgFile = "Interface\\Tooltips\\UI-Tooltip-Background", edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border", tile = true, tileSize = 8, edgeSize = 4, insets = {left = 1, right = 1, top = 1, bottom = 1} }) local tabLogText = tabLog:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall") tabLogText:SetPoint("CENTER", tabLog, "CENTER", 0, 0) tabLogText:SetText("Log") tabLog:SetScript("OnClick", function() BenchTracker:SwitchTab("log") end) mainFrame.tabLog = tabLog mainFrame.tabLogText = tabLogText end function BenchTracker:SwitchTab(tab) activeTab = tab if tab == "afk" then mainFrame.afkContent:Show() mainFrame.logContent:Hide() mainFrame.tabAfk:SetBackdropColor(0.3, 0.3, 0.5, 1) mainFrame.tabAfk:SetBackdropBorderColor(0.6, 0.6, 0.8, 1) mainFrame.tabAfkText:SetTextColor(1, 1, 1, 1) mainFrame.tabLog:SetBackdropColor(0.15, 0.15, 0.15, 0.8) mainFrame.tabLog:SetBackdropBorderColor(0.4, 0.4, 0.4, 1) mainFrame.tabLogText:SetTextColor(0.6, 0.6, 0.6, 1) BenchTracker:UpdateAFKDisplay() else mainFrame.afkContent:Hide() mainFrame.logContent:Show() mainFrame.tabLog:SetBackdropColor(0.3, 0.3, 0.5, 1) mainFrame.tabLog:SetBackdropBorderColor(0.6, 0.6, 0.8, 1) mainFrame.tabLogText:SetTextColor(1, 1, 1, 1) mainFrame.tabAfk:SetBackdropColor(0.15, 0.15, 0.15, 0.8) mainFrame.tabAfk:SetBackdropBorderColor(0.4, 0.4, 0.4, 1) mainFrame.tabAfkText:SetTextColor(0.6, 0.6, 0.6, 1) BenchTracker:UpdateLogDisplay() end end ---------------------------------------------------------------- -- PLAYER ROW (AFK TAB) ---------------------------------------------------------------- function BenchTracker:CreatePlayerRow(parent, index) local frame = CreateFrame("Frame", "BenchPlayerRow" .. index, parent) frame:SetWidth(245) frame:SetHeight(16) frame:SetBackdrop({ bgFile = "Interface\\Tooltips\\UI-Tooltip-Background", edgeFile = nil, tile = true, tileSize = 16, insets = {left = 0, right = 0, top = 0, bottom = 0} }) frame:SetBackdropColor(0.15, 0.15, 0.15, 0.6) frame:EnableMouse(true) frame:SetScript("OnEnter", function() this:SetBackdropColor(0.25, 0.35, 0.45, 0.8) end) frame:SetScript("OnLeave", function() this:SetBackdropColor(0.15, 0.15, 0.15, 0.6) end) -- Player name local nameText = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall") nameText:SetPoint("LEFT", frame, "LEFT", 4, 0) nameText:SetWidth(140) nameText:SetJustifyH("LEFT") frame.nameText = nameText -- Ready button (green) local readyBtn = CreateFrame("Button", nil, frame) readyBtn:SetWidth(14) readyBtn:SetHeight(14) readyBtn:SetPoint("RIGHT", frame, "RIGHT", -22, 0) readyBtn:SetBackdrop({ bgFile = "Interface\\Tooltips\\UI-Tooltip-Background", edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border", tile = true, tileSize = 8, edgeSize = 4, insets = {left = 1, right = 1, top = 1, bottom = 1} }) readyBtn.baseR, readyBtn.baseG, readyBtn.baseB, readyBtn.baseA = 0.25, 0.25, 0.25, 0.6 readyBtn:SetScript("OnEnter", function() local r = this.baseR + 0.15 local g = this.baseG + 0.15 local b = this.baseB + 0.15 if r > 1 then r = 1 end if g > 1 then g = 1 end if b > 1 then b = 1 end this:SetBackdropColor(r, g, b, 1) this:GetParent():SetBackdropColor(0.25, 0.35, 0.45, 0.8) GameTooltip:SetOwner(this, "ANCHOR_RIGHT") GameTooltip:SetText("Ready", 0.2, 0.8, 0.2) GameTooltip:Show() end) readyBtn:SetScript("OnLeave", function() this:SetBackdropColor(this.baseR, this.baseG, this.baseB, this.baseA) this:GetParent():SetBackdropColor(0.15, 0.15, 0.15, 0.6) GameTooltip:Hide() end) frame.readyBtn = readyBtn -- AFK button (red) local afkBtn = CreateFrame("Button", nil, frame) afkBtn:SetWidth(14) afkBtn:SetHeight(14) afkBtn:SetPoint("RIGHT", frame, "RIGHT", -4, 0) afkBtn:SetBackdrop({ bgFile = "Interface\\Tooltips\\UI-Tooltip-Background", edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border", tile = true, tileSize = 8, edgeSize = 4, insets = {left = 1, right = 1, top = 1, bottom = 1} }) afkBtn.baseR, afkBtn.baseG, afkBtn.baseB, afkBtn.baseA = 0.25, 0.25, 0.25, 0.6 afkBtn:SetScript("OnEnter", function() local r = this.baseR + 0.15 local g = this.baseG + 0.15 local b = this.baseB + 0.15 if r > 1 then r = 1 end if g > 1 then g = 1 end if b > 1 then b = 1 end this:SetBackdropColor(r, g, b, 1) this:GetParent():SetBackdropColor(0.25, 0.35, 0.45, 0.8) GameTooltip:SetOwner(this, "ANCHOR_RIGHT") GameTooltip:SetText("AFK", 0.8, 0.2, 0.2) GameTooltip:Show() end) afkBtn:SetScript("OnLeave", function() this:SetBackdropColor(this.baseR, this.baseG, this.baseB, this.baseA) this:GetParent():SetBackdropColor(0.15, 0.15, 0.15, 0.6) GameTooltip:Hide() end) frame.afkBtn = afkBtn frame:Hide() return frame end function BenchTracker:SetRadioState(frame, state) -- state: "ready", "afk", or "none" if state == "ready" then frame.readyBtn.baseR, frame.readyBtn.baseG, frame.readyBtn.baseB, frame.readyBtn.baseA = 0.1, 0.7, 0.1, 0.9 frame.readyBtn:SetBackdropColor(0.1, 0.7, 0.1, 0.9) frame.readyBtn:SetBackdropBorderColor(0.1, 0.5, 0.1, 1) frame.afkBtn.baseR, frame.afkBtn.baseG, frame.afkBtn.baseB, frame.afkBtn.baseA = 0.25, 0.25, 0.25, 0.6 frame.afkBtn:SetBackdropColor(0.25, 0.25, 0.25, 0.6) frame.afkBtn:SetBackdropBorderColor(0.4, 0.4, 0.4, 0.8) elseif state == "afk" then frame.readyBtn.baseR, frame.readyBtn.baseG, frame.readyBtn.baseB, frame.readyBtn.baseA = 0.25, 0.25, 0.25, 0.6 frame.readyBtn:SetBackdropColor(0.25, 0.25, 0.25, 0.6) frame.readyBtn:SetBackdropBorderColor(0.4, 0.4, 0.4, 0.8) frame.afkBtn.baseR, frame.afkBtn.baseG, frame.afkBtn.baseB, frame.afkBtn.baseA = 0.8, 0.1, 0.1, 0.9 frame.afkBtn:SetBackdropColor(0.8, 0.1, 0.1, 0.9) frame.afkBtn:SetBackdropBorderColor(0.6, 0.1, 0.1, 1) else frame.readyBtn.baseR, frame.readyBtn.baseG, frame.readyBtn.baseB, frame.readyBtn.baseA = 0.25, 0.25, 0.25, 0.6 frame.readyBtn:SetBackdropColor(0.25, 0.25, 0.25, 0.6) frame.readyBtn:SetBackdropBorderColor(0.4, 0.4, 0.4, 0.8) frame.afkBtn.baseR, frame.afkBtn.baseG, frame.afkBtn.baseB, frame.afkBtn.baseA = 0.25, 0.25, 0.25, 0.6 frame.afkBtn:SetBackdropColor(0.25, 0.25, 0.25, 0.6) frame.afkBtn:SetBackdropBorderColor(0.4, 0.4, 0.4, 0.8) end end ---------------------------------------------------------------- -- AFK DISPLAY ---------------------------------------------------------------- function BenchTracker:UpdateAFKDisplay() if not mainFrame or not mainFrame:IsVisible() then return end if activeTab ~= "afk" then return end local isOfficer = BenchTracker:IsOfficer() local members = BenchTracker:GetRaidMembers() local scrollChild = mainFrame.afkScrollChild -- Show/hide buttons based on officer status if mainFrame.afkButton then if isOfficer then mainFrame.afkButton:Show() else mainFrame.afkButton:Hide() end end if mainFrame.logButton then if isOfficer then mainFrame.logButton:Show() else mainFrame.logButton:Hide() end end -- Hide all existing rows for i = 1, table.getn(playerFrames) do playerFrames[i]:Hide() end local yOffset = 0 for i = 1, table.getn(members) do local member = members[i] if not playerFrames[i] then playerFrames[i] = BenchTracker:CreatePlayerRow(scrollChild, i) end local row = playerFrames[i] row:ClearAllPoints() row:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", 0, yOffset) row:Show() row.nameText:SetText(member.name) local englishClass = BenchTracker:GetEnglishClass(member.class) local color = CLASS_COLORS[englishClass] or {r = 0.5, g = 0.5, b = 0.5} row.nameText:SetTextColor(color.r, color.g, color.b, 1) row.playerName = member.name -- Determine current status local status = "none" if currentCheckData[member.name] then status = currentCheckData[member.name] end BenchTracker:SetRadioState(row, status) -- Button click handlers if isOfficer then row.readyBtn:SetScript("OnClick", function() local pName = this:GetParent().playerName currentCheckData[pName] = "ready" BenchTracker:UpdateAFKDisplay() end) row.afkBtn:SetScript("OnClick", function() local pName = this:GetParent().playerName currentCheckData[pName] = "afk" BenchTracker:UpdateAFKDisplay() end) row.readyBtn:EnableMouse(true) row.afkBtn:EnableMouse(true) else row.readyBtn:EnableMouse(false) row.afkBtn:EnableMouse(false) end yOffset = yOffset - 17 end local contentHeight = table.getn(members) * 17 + 10 scrollChild:SetHeight(contentHeight) if mainFrame.afkScrollFrame then mainFrame.afkScrollFrame:UpdateScrollChildRect() end end ---------------------------------------------------------------- -- AFK CHECK LOGIC ---------------------------------------------------------------- function BenchTracker:StartAFKCheck() if not BenchTracker:IsOfficer() then return end if isListening then DEFAULT_CHAT_FRAME:AddMessage("|cFFFF0000BenchTracker: An AFK check is already in progress!|r") return end -- Reset status for current raid members currentCheckData = {} local members = BenchTracker:GetRaidMembers() for i = 1, table.getn(members) do currentCheckData[members[i].name] = "afk" end checkCounter = checkCounter + 1 isListening = true listenElapsed = 0 -- Send announcements SendChatMessage("BENCH GROUP: Type in [Guild Chat] or in [#General on Discord] within 30sec if you're here.", "GUILD") SendChatMessage("BENCH GROUP: Type in [Guild Chat] or in [#General on Discord] within 30sec if you're here.", "RAID_WARNING") -- Trigger /pull 30 (BigWigs Pulltimer) if SlashCmdList["BWPT_SHORTHAND"] then SlashCmdList["BWPT_SHORTHAND"]("30") end -- Start 30 second timer BenchTracker:StartListenTimer() BenchTracker:UpdateAFKDisplay() DEFAULT_CHAT_FRAME:AddMessage("|cFF00FF00BenchTracker: AFK check started! Listening for 30 seconds...|r") end function BenchTracker:StartListenTimer() if not listenTimer then listenTimer = CreateFrame("Frame", "BenchListenTimer", UIParent) end listenElapsed = 0 listenTimer:SetScript("OnUpdate", function() listenElapsed = listenElapsed + arg1 if listenElapsed >= 30 then BenchTracker:StopListening() end end) listenTimer:Show() end function BenchTracker:StopListening() isListening = false if listenTimer then listenTimer:SetScript("OnUpdate", nil) listenTimer:Hide() end DEFAULT_CHAT_FRAME:AddMessage("|cFFFFFF00BenchTracker: AFK check listening ended. Review results and click 'Add to Log' when ready.|r") BenchTracker:UpdateAFKDisplay() end function BenchTracker:OnChatMessage(playerName) if not isListening then return end -- Check if this player is in our bench raid if currentCheckData[playerName] then currentCheckData[playerName] = "ready" BenchTracker:UpdateAFKDisplay() end end ---------------------------------------------------------------- -- LOGGING ---------------------------------------------------------------- function BenchTracker:LogAFKCheck() local timestamp = BenchTracker:GetTimestamp() local readyList = {} local afkList = {} for name, status in pairs(currentCheckData) do if status == "ready" then table.insert(readyList, name) else table.insert(afkList, name) end end table.sort(readyList) table.sort(afkList) local entry = { entryType = "afk", timestamp = timestamp, checkNum = checkCounter, ready = readyList, afk = afkList } table.insert(logEntries, entry) BenchTrackerDB.log = logEntries BenchTrackerDB.checkCounter = checkCounter if activeTab == "log" then BenchTracker:UpdateLogDisplay() end end function BenchTracker:ManualLogAFKCheck() if not BenchTracker:IsOfficer() then return end -- Check if there is any data to log local hasData = false for name, status in pairs(currentCheckData) do hasData = true break end if not hasData then DEFAULT_CHAT_FRAME:AddMessage("|cFFFF0000BenchTracker: Nothing to log. Run an AFK check first.|r") return end BenchTracker:LogAFKCheck() -- Reset radio buttons currentCheckData = {} DEFAULT_CHAT_FRAME:AddMessage("|cFF00FF00BenchTracker: AFK check results added to log.|r") BenchTracker:UpdateAFKDisplay() if activeTab == "log" then BenchTracker:UpdateLogDisplay() end end function BenchTracker:LogEPAward(epAmount) local timestamp = BenchTracker:GetTimestamp() local nameList = {} local raidSize = GetNumRaidMembers() for i = 1, raidSize do local name, rank, subgroup, level, class, fileName, zone, online = GetRaidRosterInfo(i) if name and online then table.insert(nameList, name) end end table.sort(nameList) local entry = { entryType = "ep", timestamp = timestamp, ep = epAmount, players = nameList } table.insert(logEntries, entry) BenchTrackerDB.log = logEntries if activeTab == "log" then BenchTracker:UpdateLogDisplay() end end function BenchTracker:IsInBenchRaid(playerName) local members = BenchTracker:GetRaidMembers() for i = 1, table.getn(members) do if members[i].name == playerName then return true end end return false end function BenchTracker:LogIndividualEP(playerName, epAmount) if not BenchTracker:IsInBenchRaid(playerName) then return end local timestamp = BenchTracker:GetTimestamp() local entry = { entryType = "ep_individual", timestamp = timestamp, ep = epAmount, player = playerName } table.insert(logEntries, entry) BenchTrackerDB.log = logEntries if activeTab == "log" then BenchTracker:UpdateLogDisplay() end end ---------------------------------------------------------------- -- ROSTER CHANGE TRACKING ---------------------------------------------------------------- function BenchTracker:GetCurrentRosterMap() local roster = {} local raidSize = GetNumRaidMembers() for i = 1, raidSize do local name, rank, subgroup, level, class = GetRaidRosterInfo(i) if name then roster[name] = class or "Unknown" end end return roster end function BenchTracker:CheckRosterChanges() local currentRoster = BenchTracker:GetCurrentRosterMap() if not rosterInitialized then previousRaidRoster = currentRoster rosterInitialized = true return end local timestamp = BenchTracker:GetTimestamp() local changed = false -- Check for new players (joined) for name, class in pairs(currentRoster) do if not previousRaidRoster[name] then local englishClass = BenchTracker:GetEnglishClass(class) local entry = { entryType = "roster_join", timestamp = timestamp, player = name, class = englishClass } table.insert(logEntries, entry) changed = true end end -- Check for removed players (left) for name, class in pairs(previousRaidRoster) do if not currentRoster[name] then local englishClass = BenchTracker:GetEnglishClass(class) local entry = { entryType = "roster_leave", timestamp = timestamp, player = name, class = englishClass } table.insert(logEntries, entry) changed = true end end if changed then BenchTrackerDB.log = logEntries if activeTab == "log" then BenchTracker:UpdateLogDisplay() end end previousRaidRoster = currentRoster end ---------------------------------------------------------------- -- LOG DISPLAY ---------------------------------------------------------------- local LOG_LINE_HEIGHT = 12 local logEntryFrames = {} local emptyLogFS = nil local pendingDeleteIndex = nil local function GetWrappedHeight(fs, maxWidth) local textWidth = fs:GetStringWidth() if textWidth <= 0 then return LOG_LINE_HEIGHT end local numLines = math.ceil(textWidth / maxWidth) if numLines < 1 then numLines = 1 end return numLines * LOG_LINE_HEIGHT end function BenchTracker:ClearLog() if not BenchTracker:IsOfficer() then return end logEntries = {} checkCounter = 0 BenchTrackerDB.log = logEntries BenchTrackerDB.checkCounter = 0 DEFAULT_CHAT_FRAME:AddMessage("|cFFFFFF00BenchTracker: Log cleared.|r") BenchTracker:UpdateLogDisplay() end StaticPopupDialogs["BENCH_CONFIRM_DELETE"] = { text = "Are you sure you want to delete this log entry?", button1 = "Yes", button2 = "No", OnAccept = function() if pendingDeleteIndex then BenchTracker:DeleteLogEntry(pendingDeleteIndex) pendingDeleteIndex = nil end end, OnCancel = function() pendingDeleteIndex = nil end, timeout = 0, whileDead = true, hideOnEscape = true, } function BenchTracker:DeleteLogEntry(index) if index >= 1 and index <= table.getn(logEntries) then table.remove(logEntries, index) BenchTrackerDB.log = logEntries DEFAULT_CHAT_FRAME:AddMessage("|cFFFFFF00BenchTracker: Log entry deleted.|r") BenchTracker:UpdateLogDisplay() end end function BenchTracker:UpdateLogDisplay() if not mainFrame or not mainFrame:IsVisible() then return end if activeTab ~= "log" then return end -- Show/hide Clear Log button based on officer status if mainFrame.clearLogButton then if BenchTracker:IsOfficer() then mainFrame.clearLogButton:Show() else mainFrame.clearLogButton:Hide() end end local scrollChild = mainFrame.logScrollChild local isOfficer = BenchTracker:IsOfficer() -- Hide all existing entry frames for i = 1, table.getn(logEntryFrames) do logEntryFrames[i]:Hide() end if emptyLogFS then emptyLogFS:Hide() end local yOffset = 0 local entryIdx = 0 local function getEntryFrame() entryIdx = entryIdx + 1 if not logEntryFrames[entryIdx] then local ef = CreateFrame("Frame", "BenchLogEntryFrame" .. entryIdx, scrollChild) ef:SetWidth(245) ef:SetBackdrop({ bgFile = "Interface\\Tooltips\\UI-Tooltip-Background", edgeFile = nil, tile = true, tileSize = 16, insets = {left = 0, right = 0, top = 0, bottom = 0} }) ef:SetBackdropColor(0, 0, 0, 0) ef:EnableMouse(true) ef:SetScript("OnEnter", function() this:SetBackdropColor(0.25, 0.28, 0.4, 0.35) end) ef:SetScript("OnLeave", function() this:SetBackdropColor(0, 0, 0, 0) end) ef.fontStrings = {} ef.fsCount = 0 ef.deleteBtn = nil logEntryFrames[entryIdx] = ef end local ef = logEntryFrames[entryIdx] for i = 1, table.getn(ef.fontStrings) do ef.fontStrings[i]:Hide() end ef.fsCount = 0 if ef.deleteBtn then ef.deleteBtn:Hide() end ef:ClearAllPoints() ef:SetBackdropColor(0, 0, 0, 0) ef:Show() return ef end local function getEntryFS(ef) ef.fsCount = ef.fsCount + 1 if not ef.fontStrings[ef.fsCount] then ef.fontStrings[ef.fsCount] = ef:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall") end local fs = ef.fontStrings[ef.fsCount] fs:ClearAllPoints() fs:Show() return fs end local function getEntryDeleteBtn(ef) if not ef.deleteBtn then local btn = CreateFrame("Button", nil, ef) btn:SetWidth(12) btn:SetHeight(12) btn:SetBackdrop({ bgFile = "Interface\\Tooltips\\UI-Tooltip-Background", edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border", tile = true, tileSize = 8, edgeSize = 4, insets = {left = 1, right = 1, top = 1, bottom = 1} }) btn:SetBackdropColor(0.6, 0.15, 0.15, 0.8) btn:SetBackdropBorderColor(0.5, 0.5, 0.5, 1) local btnText = btn:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall") btnText:SetPoint("CENTER", btn, "CENTER", 0, 0) btnText:SetText("x") btnText:SetTextColor(1, 1, 1, 1) btn:SetScript("OnEnter", function() this:SetBackdropColor(0.9, 0.2, 0.2, 1) this:GetParent():SetBackdropColor(0.25, 0.28, 0.4, 0.35) GameTooltip:SetOwner(this, "ANCHOR_RIGHT") GameTooltip:SetText("Delete this entry", 1, 0.3, 0.3) GameTooltip:Show() end) btn:SetScript("OnLeave", function() this:SetBackdropColor(0.6, 0.15, 0.15, 0.8) this:GetParent():SetBackdropColor(0, 0, 0, 0) GameTooltip:Hide() end) ef.deleteBtn = btn end ef.deleteBtn:ClearAllPoints() ef.deleteBtn:Show() return ef.deleteBtn end -- Render entries in reverse order (newest first) local numEntries = table.getn(logEntries) for idx = numEntries, 1, -1 do local entry = logEntries[idx] local ef = getEntryFrame() local localY = 0 if entry.entryType == "afk" then -- Header local header = getEntryFS(ef) header:SetPoint("TOPLEFT", ef, "TOPLEFT", 2, localY) header:SetJustifyH("LEFT") local headerWidth = 240 if isOfficer then headerWidth = 220 local delBtn = getEntryDeleteBtn(ef) delBtn:SetPoint("TOPRIGHT", ef, "TOPRIGHT", -2, localY) delBtn.entryIndex = idx delBtn:SetScript("OnClick", function() pendingDeleteIndex = this.entryIndex StaticPopup_Show("BENCH_CONFIRM_DELETE") end) end header:SetWidth(headerWidth) header:SetText("|cFFFFCC00" .. entry.timestamp .. " AFK Check #" .. entry.checkNum .. "|r") header:SetTextColor(1, 0.8, 0, 1) localY = localY - (GetWrappedHeight(header, headerWidth) + 2) -- Ready list if table.getn(entry.ready) > 0 then local readyLabel = getEntryFS(ef) readyLabel:SetPoint("TOPLEFT", ef, "TOPLEFT", 6, localY) readyLabel:SetWidth(236) readyLabel:SetJustifyH("LEFT") local readyStr = "|cFF00CC00Ready:|r " for i = 1, table.getn(entry.ready) do if i > 1 then readyStr = readyStr .. ", " end readyStr = readyStr .. entry.ready[i] end readyLabel:SetText(readyStr) readyLabel:SetTextColor(0.8, 0.8, 0.8, 1) localY = localY - (GetWrappedHeight(readyLabel, 236) + 2) end -- AFK list if table.getn(entry.afk) > 0 then local afkLabel = getEntryFS(ef) afkLabel:SetPoint("TOPLEFT", ef, "TOPLEFT", 6, localY) afkLabel:SetWidth(236) afkLabel:SetJustifyH("LEFT") local afkStr = "|cFFCC0000AFK:|r " for i = 1, table.getn(entry.afk) do if i > 1 then afkStr = afkStr .. ", " end afkStr = afkStr .. entry.afk[i] end afkLabel:SetText(afkStr) afkLabel:SetTextColor(0.8, 0.8, 0.8, 1) localY = localY - (GetWrappedHeight(afkLabel, 236) + 2) end elseif entry.entryType == "ep" then -- EP award header local header = getEntryFS(ef) header:SetPoint("TOPLEFT", ef, "TOPLEFT", 2, localY) header:SetJustifyH("LEFT") local headerWidth = 240 if isOfficer then headerWidth = 220 local delBtn = getEntryDeleteBtn(ef) delBtn:SetPoint("TOPRIGHT", ef, "TOPRIGHT", -2, localY) delBtn.entryIndex = idx delBtn:SetScript("OnClick", function() pendingDeleteIndex = this.entryIndex StaticPopup_Show("BENCH_CONFIRM_DELETE") end) end header:SetWidth(headerWidth) header:SetText("|cFF33BBFF" .. entry.timestamp .. " EP Award: +" .. entry.ep .. " EP|r") header:SetTextColor(0.2, 0.7, 1, 1) localY = localY - (GetWrappedHeight(header, headerWidth) + 2) -- Player list local playerLabel = getEntryFS(ef) playerLabel:SetPoint("TOPLEFT", ef, "TOPLEFT", 6, localY) playerLabel:SetWidth(236) playerLabel:SetJustifyH("LEFT") local pStr = "" for i = 1, table.getn(entry.players) do if i > 1 then pStr = pStr .. ", " end pStr = pStr .. entry.players[i] end playerLabel:SetText(pStr) playerLabel:SetTextColor(0.7, 0.7, 0.7, 1) localY = localY - (GetWrappedHeight(playerLabel, 236) + 2) elseif entry.entryType == "ep_individual" then -- Individual EP adjust header local header = getEntryFS(ef) header:SetPoint("TOPLEFT", ef, "TOPLEFT", 2, localY) header:SetJustifyH("LEFT") local headerWidth = 240 if isOfficer then headerWidth = 220 local delBtn = getEntryDeleteBtn(ef) delBtn:SetPoint("TOPRIGHT", ef, "TOPRIGHT", -2, localY) delBtn.entryIndex = idx delBtn:SetScript("OnClick", function() pendingDeleteIndex = this.entryIndex StaticPopup_Show("BENCH_CONFIRM_DELETE") end) end header:SetWidth(headerWidth) local epSign = "" if entry.ep >= 0 then epSign = "+" end header:SetText("|cFFDDA0DD" .. entry.timestamp .. " EP Adjust: " .. entry.player .. " " .. epSign .. entry.ep .. " EP|r") header:SetTextColor(0.87, 0.63, 0.87, 1) localY = localY - (GetWrappedHeight(header, headerWidth) + 2) elseif entry.entryType == "roster_join" or entry.entryType == "roster_leave" then local header = getEntryFS(ef) header:SetPoint("TOPLEFT", ef, "TOPLEFT", 2, localY) header:SetJustifyH("LEFT") local headerWidth = 240 if isOfficer then headerWidth = 220 local delBtn = getEntryDeleteBtn(ef) delBtn:SetPoint("TOPRIGHT", ef, "TOPRIGHT", -2, localY) delBtn.entryIndex = idx delBtn:SetScript("OnClick", function() pendingDeleteIndex = this.entryIndex StaticPopup_Show("BENCH_CONFIRM_DELETE") end) end header:SetWidth(headerWidth) local color = CLASS_COLORS[entry.class] or {r = 0.6, g = 0.6, b = 0.6} local nameColored = string.format("|cFF%02x%02x%02x%s|r", color.r * 255, color.g * 255, color.b * 255, entry.player) if entry.entryType == "roster_join" then header:SetText("|cFF888888" .. entry.timestamp .. "|r " .. nameColored .. " |cFF00CC00joined|r") header:SetTextColor(0.5, 0.8, 0.5, 1) else header:SetText("|cFF888888" .. entry.timestamp .. "|r " .. nameColored .. " |cFFCC0000left|r") header:SetTextColor(0.8, 0.5, 0.5, 1) end localY = localY - (GetWrappedHeight(header, headerWidth) + 2) end -- Size and position entry frame local entryHeight = math.abs(localY) + 4 ef:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", 0, yOffset) ef:SetHeight(entryHeight) yOffset = yOffset - entryHeight end if numEntries == 0 then if not emptyLogFS then emptyLogFS = scrollChild:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall") end emptyLogFS:ClearAllPoints() emptyLogFS:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", 2, yOffset) emptyLogFS:SetWidth(240) emptyLogFS:SetJustifyH("LEFT") emptyLogFS:SetText("|cFF666666No log entries yet.|r") emptyLogFS:SetTextColor(0.4, 0.4, 0.4, 1) emptyLogFS:Show() yOffset = yOffset - (GetWrappedHeight(emptyLogFS, 240) + 2) end local contentHeight = math.abs(yOffset) + 10 scrollChild:SetHeight(contentHeight) if mainFrame.logScrollFrame then mainFrame.logScrollFrame:UpdateScrollChildRect() end end ---------------------------------------------------------------- -- SLASH COMMAND ---------------------------------------------------------------- SLASH_BENCH1 = "/bench" SlashCmdList["BENCH"] = function(msg) if not mainFrame then BenchTracker:CreateMainFrame() end if mainFrame:IsVisible() then mainFrame:Hide() else mainFrame:Show() BenchTracker:SwitchTab(activeTab) end end ---------------------------------------------------------------- -- EVENT HANDLING ---------------------------------------------------------------- local benchEventFrame = CreateFrame("Frame", "BenchEventFrame", UIParent) benchEventFrame:RegisterEvent("RAID_ROSTER_UPDATE") benchEventFrame:RegisterEvent("PARTY_MEMBERS_CHANGED") benchEventFrame:RegisterEvent("CHAT_MSG_GUILD") benchEventFrame:RegisterEvent("CHAT_MSG_RAID") benchEventFrame:RegisterEvent("CHAT_MSG_RAID_LEADER") benchEventFrame:RegisterEvent("ADDON_LOADED") benchEventFrame:SetScript("OnEvent", function() if event == "ADDON_LOADED" and arg1 == "shootyepgp" then -- Load saved log data if not BenchTrackerDB then BenchTrackerDB = {} end if BenchTrackerDB.log then logEntries = BenchTrackerDB.log else BenchTrackerDB.log = {} end if BenchTrackerDB.checkCounter then checkCounter = BenchTrackerDB.checkCounter else BenchTrackerDB.checkCounter = 0 end DEFAULT_CHAT_FRAME:AddMessage("|cFF00FF00BenchTracker loaded! Type /bench to open.|r") elseif event == "RAID_ROSTER_UPDATE" or event == "PARTY_MEMBERS_CHANGED" then BenchTracker:CheckRosterChanges() if mainFrame and mainFrame:IsVisible() and activeTab == "afk" then BenchTracker:UpdateAFKDisplay() end elseif event == "CHAT_MSG_GUILD" then if isListening and arg1 and arg2 then BenchTracker:OnChatMessage(arg2) end elseif event == "CHAT_MSG_RAID" or event == "CHAT_MSG_RAID_LEADER" then if isListening and arg1 and arg2 then BenchTracker:OnChatMessage(arg2) end end end) ---------------------------------------------------------------- -- HOOK: EP AWARDS ---------------------------------------------------------------- local original_award_raid_ep = nil local original_award_reserve_ep = nil local original_givename_ep = nil local isBulkAward = false local epHookFrame = CreateFrame("Frame", "BenchEPHookFrame", UIParent) epHookFrame:RegisterEvent("ADDON_LOADED") epHookFrame:SetScript("OnEvent", function() if event == "ADDON_LOADED" and arg1 == "shootyepgp" then -- Hook after sepgp is available if sepgp and sepgp.award_reserve_ep then original_award_reserve_ep = sepgp.award_reserve_ep sepgp.award_reserve_ep = function(self, ep) isBulkAward = true original_award_reserve_ep(self, ep) isBulkAward = false BenchTracker:LogEPAward(ep) end end if sepgp and sepgp.award_raid_ep then original_award_raid_ep = sepgp.award_raid_ep sepgp.award_raid_ep = function(self, ep) isBulkAward = true original_award_raid_ep(self, ep) isBulkAward = false BenchTracker:LogEPAward(ep) end end if sepgp and sepgp.givename_ep then original_givename_ep = sepgp.givename_ep sepgp.givename_ep = function(self, getname, ep) original_givename_ep(self, getname, ep) if not isBulkAward then BenchTracker:LogIndividualEP(getname, ep) end end end end end)