Files
shootyepgp/bench.lua
T
2026-02-07 11:04:24 +01:00

981 lines
35 KiB
Lua

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"
-- 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:SetScript("OnEnter", function()
GameTooltip:SetOwner(this, "ANCHOR_RIGHT")
GameTooltip:SetText("Ready", 0.2, 0.8, 0.2)
GameTooltip:Show()
end)
readyBtn:SetScript("OnLeave", function()
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:SetScript("OnEnter", function()
GameTooltip:SetOwner(this, "ANCHOR_RIGHT")
GameTooltip:SetText("AFK", 0.8, 0.2, 0.2)
GameTooltip:Show()
end)
afkBtn:SetScript("OnLeave", function()
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:SetBackdropColor(0.1, 0.7, 0.1, 0.9)
frame.readyBtn:SetBackdropBorderColor(0.1, 0.5, 0.1, 1)
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:SetBackdropColor(0.25, 0.25, 0.25, 0.6)
frame.readyBtn:SetBackdropBorderColor(0.4, 0.4, 0.4, 0.8)
frame.afkBtn:SetBackdropColor(0.8, 0.1, 0.1, 0.9)
frame.afkBtn:SetBackdropBorderColor(0.6, 0.1, 0.1, 1)
else
frame.readyBtn:SetBackdropColor(0.25, 0.25, 0.25, 0.6)
frame.readyBtn:SetBackdropBorderColor(0.4, 0.4, 0.4, 0.8)
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 members = BenchTracker:GetRaidMembers()
local nameList = {}
for i = 1, table.getn(members) do
table.insert(nameList, members[i].name)
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
----------------------------------------------------------------
-- LOG DISPLAY
----------------------------------------------------------------
local logFontStrings = {}
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
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
-- Hide all existing log text
for i = 1, table.getn(logFontStrings) do
logFontStrings[i]:Hide()
end
local yOffset = 0
local fsIndex = 0
local function getFS()
fsIndex = fsIndex + 1
if not logFontStrings[fsIndex] then
logFontStrings[fsIndex] = scrollChild:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
end
local fs = logFontStrings[fsIndex]
fs:ClearAllPoints()
fs:Show()
return fs
end
-- Render entries in reverse order (newest first)
local numEntries = table.getn(logEntries)
for idx = numEntries, 1, -1 do
local entry = logEntries[idx]
if entry.entryType == "afk" then
-- Header
local header = getFS()
header:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", 2, yOffset)
header:SetWidth(240)
header:SetJustifyH("LEFT")
header:SetText("|cFFFFCC00" .. entry.timestamp .. " AFK Check #" .. entry.checkNum .. "|r")
header:SetTextColor(1, 0.8, 0, 1)
yOffset = yOffset - 12
-- Ready list
if table.getn(entry.ready) > 0 then
local readyLabel = getFS()
readyLabel:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", 6, yOffset)
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)
yOffset = yOffset - 12
end
-- AFK list
if table.getn(entry.afk) > 0 then
local afkLabel = getFS()
afkLabel:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", 6, yOffset)
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)
yOffset = yOffset - 12
end
yOffset = yOffset - 4
elseif entry.entryType == "ep" then
-- EP award header
local header = getFS()
header:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", 2, yOffset)
header:SetWidth(240)
header:SetJustifyH("LEFT")
header:SetText("|cFF33BBFF" .. entry.timestamp .. " EP Award: +" .. entry.ep .. " EP|r")
header:SetTextColor(0.2, 0.7, 1, 1)
yOffset = yOffset - 12
-- Player list
local playerLabel = getFS()
playerLabel:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", 6, yOffset)
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)
yOffset = yOffset - 12
yOffset = yOffset - 4
end
end
if numEntries == 0 then
local emptyMsg = getFS()
emptyMsg:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", 2, yOffset)
emptyMsg:SetWidth(240)
emptyMsg:SetJustifyH("LEFT")
emptyMsg:SetText("|cFF666666No log entries yet.|r")
emptyMsg:SetTextColor(0.4, 0.4, 0.4, 1)
yOffset = yOffset - 14
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
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 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)
original_award_reserve_ep(self, ep)
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)
original_award_raid_ep(self, ep)
BenchTracker:LogEPAward(ep)
end
end
end
end)