Files
Horyoshi d858e1174b Bug Fix
2026-01-08 19:58:13 +01:00

785 lines
27 KiB
Lua

-- Matrix - Keeper Gnarlmoon Team Assignment Tool
-- Only usable by Officers and Supreme Leaders
-- Assigns raid members to Red (Left) or Blue (Right) teams
local C = AceLibrary("Crayon-2.0")
local BC = AceLibrary("Babble-Class-2.2")
local L = AceLibrary("AceLocale-2.2"):new("shootyepgp")
-- Module creation
sepgp_matrix = sepgp:NewModule("sepgp_matrix", "AceEvent-2.0")
-- Local state
local playerAssignments = {} -- [playerName] = "red" or "blue" or nil
local raidRoster = {} -- Current raid roster cache
local matrixFrame = nil
local playerFrames = {} -- UI frames for each player
local isUpdating = false
-- Constants
local FRAME_WIDTH = 670
local FRAME_HEIGHT = 410
local PLAYER_WIDTH = 105
local PLAYER_HEIGHT = 16
local CHECKBOX_SIZE = 12
local GROUP_HEADER_HEIGHT = 18
local COLUMNS = 4
local GROUPS_PER_COLUMN = 2
-- Colors
local COLOR_RED = {r = 0.9, g = 0.2, b = 0.2}
local COLOR_BLUE = {r = 0.2, g = 0.4, b = 0.9}
local COLOR_AWKWARD = {r = 0.7, g = 0.7, b = 0.7}
local COLOR_RED_BG = {r = 0.5, g = 0.1, b = 0.1, a = 0.6}
local COLOR_BLUE_BG = {r = 0.1, g = 0.2, b = 0.5, a = 0.6}
-------------------------------------------------------------------------------
-- Permission Check
-------------------------------------------------------------------------------
local function canUseMatrix()
-- Check if player is in a raid
if GetNumRaidMembers() == 0 then
return false, "You must be in a raid to use this feature."
end
-- Check guild rank
local guildName, guildRankName = GetGuildInfo("player")
if not guildName then
return false, "You must be in a guild to use this feature."
end
-- Check for Officer or Supreme leader rank, or raid leader/assistant
if guildRankName == "Officer" or guildRankName == "Supreme leader" then
return true
end
-- Also allow raid leaders and assistants
if IsRaidLeader() or IsRaidOfficer() then
return true
end
return false, "Only Officers or Supreme Leaders can use this feature."
end
-------------------------------------------------------------------------------
-- Raid Roster Management
-------------------------------------------------------------------------------
local function buildRaidRoster()
local roster = {}
local numRaid = GetNumRaidMembers()
if numRaid == 0 then
return roster
end
for i = 1, numRaid do
local name, rank, subgroup, level, class, fileName, zone, online, isDead = GetRaidRosterInfo(i)
if name then
table.insert(roster, {
name = name,
class = fileName or class,
subgroup = subgroup,
online = online,
index = i
})
end
end
-- Sort by subgroup, then by name
table.sort(roster, function(a, b)
if a.subgroup ~= b.subgroup then
return a.subgroup < b.subgroup
end
return a.name < b.name
end)
return roster
end
-------------------------------------------------------------------------------
-- Pill Counter Calculations
-------------------------------------------------------------------------------
local function calculatePillCounts()
local numRaid = GetNumRaidMembers()
local halfCount = math.floor(numRaid / 2)
local awkwardCount = numRaid - (halfCount * 2) -- 0 or 1
-- Count current assignments
local redAssigned = 0
local blueAssigned = 0
for _, player in ipairs(raidRoster) do
local assignment = playerAssignments[player.name]
if assignment == "red" then
redAssigned = redAssigned + 1
elseif assignment == "blue" then
blueAssigned = blueAssigned + 1
end
end
-- Calculate remaining pills
local redRemaining = halfCount - redAssigned
local blueRemaining = halfCount - blueAssigned
-- Handle overflow into awkward
local awkwardUsed = 0
if redRemaining < 0 then
awkwardUsed = awkwardUsed - redRemaining
redRemaining = 0
end
if blueRemaining < 0 then
awkwardUsed = awkwardUsed - blueRemaining
blueRemaining = 0
end
local awkwardRemaining = awkwardCount - awkwardUsed
if awkwardRemaining < 0 then awkwardRemaining = 0 end
return {
redTotal = halfCount,
blueTotal = halfCount,
awkwardTotal = awkwardCount,
redRemaining = redRemaining,
blueRemaining = blueRemaining,
awkwardRemaining = awkwardRemaining,
redAssigned = redAssigned,
blueAssigned = blueAssigned
}
end
-------------------------------------------------------------------------------
-- UI Helper Functions
-------------------------------------------------------------------------------
local function getClassColor(class)
if class and BC:GetHexColor(class) then
return BC:GetHexColor(class)
end
return "ffffff"
end
local function createPillIndicator(parent, color, x, y, name)
local frame = CreateFrame("Frame", name, parent)
frame:SetWidth(80)
frame:SetHeight(24)
frame:SetPoint("TOPLEFT", parent, "TOPLEFT", x, y)
-- Count text
frame.count = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
frame.count:SetPoint("LEFT", 4, 0)
frame.count:SetText("0")
frame.count:SetTextColor(1, 1, 1)
return frame
end
-- Check if a color can be assigned (has remaining pills)
local function canAssignColor(colorType)
local counts = calculatePillCounts()
if colorType == "red" then
-- Can assign red if red pills remain, or if awkward remains and red is full
return counts.redRemaining > 0 or counts.awkwardRemaining > 0
elseif colorType == "blue" then
-- Can assign blue if blue pills remain, or if awkward remains and blue is full
return counts.blueRemaining > 0 or counts.awkwardRemaining > 0
end
return false
end
local function createSmallCheckbox(parent, color, onClick)
local cb = CreateFrame("Button", nil, parent)
cb:SetWidth(CHECKBOX_SIZE)
cb:SetHeight(CHECKBOX_SIZE)
-- Border (outer colored frame)
cb.border = cb:CreateTexture(nil, "BORDER")
cb.border:SetPoint("TOPLEFT", cb, "TOPLEFT", 0, 0)
cb.border:SetPoint("BOTTOMRIGHT", cb, "BOTTOMRIGHT", 0, 0)
cb.border:SetTexture("Interface\\BUTTONS\\WHITE8X8")
cb.border:SetVertexColor(color.r, color.g, color.b, 1)
-- Dark background (inner area)
cb.bg = cb:CreateTexture(nil, "ARTWORK")
cb.bg:SetPoint("TOPLEFT", cb, "TOPLEFT", 1, -1)
cb.bg:SetPoint("BOTTOMRIGHT", cb, "BOTTOMRIGHT", -1, 1)
cb.bg:SetTexture("Interface\\BUTTONS\\WHITE8X8")
cb.bg:SetVertexColor(0.1, 0.1, 0.1, 0.9)
-- Fill (shown when checked)
cb.fill = cb:CreateTexture(nil, "OVERLAY")
cb.fill:SetPoint("TOPLEFT", cb, "TOPLEFT", 1, -1)
cb.fill:SetPoint("BOTTOMRIGHT", cb, "BOTTOMRIGHT", -1, 1)
cb.fill:SetTexture("Interface\\BUTTONS\\WHITE8X8")
cb.fill:SetVertexColor(color.r, color.g, color.b, 1)
cb.fill:Hide()
cb.isChecked = false
cb.color = color
cb:SetScript("OnClick", function()
if onClick then
onClick(this)
end
end)
-- Hover effect - slightly brighten the border
cb:SetScript("OnEnter", function()
local brighten = 0.3
local r = math.min(1, this.color.r + brighten)
local g = math.min(1, this.color.g + brighten)
local b = math.min(1, this.color.b + brighten)
this.border:SetVertexColor(r, g, b, 1)
end)
cb:SetScript("OnLeave", function()
this.border:SetVertexColor(this.color.r, this.color.g, this.color.b, 1)
end)
return cb
end
local function setCheckboxState(cb, checked)
cb.isChecked = checked
if checked then
cb.fill:Show()
else
cb.fill:Hide()
end
end
-------------------------------------------------------------------------------
-- Update Functions
-------------------------------------------------------------------------------
local function updatePillIndicators()
if not matrixFrame then return end
local counts = calculatePillCounts()
-- Update remaining pills (top)
matrixFrame.redPillRemaining.count:SetText(tostring(counts.redRemaining))
matrixFrame.bluePillRemaining.count:SetText(tostring(counts.blueRemaining))
matrixFrame.awkwardRemaining.count:SetText(tostring(counts.awkwardRemaining))
-- Update assigned pills (bottom)
matrixFrame.redPillAssigned.count:SetText(tostring(counts.redAssigned))
matrixFrame.bluePillAssigned.count:SetText(tostring(counts.blueAssigned))
-- Update button state - only enable when all pills are assigned
local allAssigned = (counts.redRemaining == 0 and counts.blueRemaining == 0 and counts.awkwardRemaining == 0)
if allAssigned then
matrixFrame.assignButton:Enable()
matrixFrame.assignButton:SetTextColor(1, 1, 1)
else
matrixFrame.assignButton:Disable()
matrixFrame.assignButton:SetTextColor(0.5, 0.5, 0.5)
end
end
local function updatePlayerFrame(playerFrame, playerData)
if not playerFrame or not playerData then return end
local assignment = playerAssignments[playerData.name]
-- Update background color
if assignment == "red" then
playerFrame.bg:SetVertexColor(COLOR_RED_BG.r, COLOR_RED_BG.g, COLOR_RED_BG.b, COLOR_RED_BG.a)
playerFrame.bg:Show()
elseif assignment == "blue" then
playerFrame.bg:SetVertexColor(COLOR_BLUE_BG.r, COLOR_BLUE_BG.g, COLOR_BLUE_BG.b, COLOR_BLUE_BG.a)
playerFrame.bg:Show()
else
playerFrame.bg:Hide()
end
-- Update checkbox states
setCheckboxState(playerFrame.redCB, assignment == "red")
setCheckboxState(playerFrame.blueCB, assignment == "blue")
end
local function createPlayerFrame(parent, playerData, x, y)
local frame = CreateFrame("Frame", nil, parent)
frame:SetWidth(PLAYER_WIDTH)
frame:SetHeight(PLAYER_HEIGHT)
frame:SetPoint("TOPLEFT", parent, "TOPLEFT", x, y)
-- Background (for assignment highlight)
frame.bg = frame:CreateTexture(nil, "BACKGROUND")
frame.bg:SetAllPoints()
frame.bg:SetTexture("Interface\\BUTTONS\\WHITE8X8")
frame.bg:Hide()
-- Red checkbox
frame.redCB = createSmallCheckbox(frame, COLOR_RED, function(cb)
local name = frame.playerName
if not name then return end
local currentAssignment = playerAssignments[name]
if currentAssignment == "red" then
-- Unassign
playerAssignments[name] = nil
else
-- Check if we can assign red
if not canAssignColor("red") then
return -- No red pills available
end
-- Assign to red
playerAssignments[name] = "red"
end
updatePlayerFrame(frame, {name = name})
updatePillIndicators()
end)
frame.redCB:SetPoint("LEFT", 2, 0)
-- Blue checkbox
frame.blueCB = createSmallCheckbox(frame, COLOR_BLUE, function(cb)
local name = frame.playerName
if not name then return end
local currentAssignment = playerAssignments[name]
if currentAssignment == "blue" then
-- Unassign
playerAssignments[name] = nil
else
-- Check if we can assign blue
if not canAssignColor("blue") then
return -- No blue pills available
end
-- Assign to blue
playerAssignments[name] = "blue"
end
updatePlayerFrame(frame, {name = name})
updatePillIndicators()
end)
frame.blueCB:SetPoint("LEFT", frame.redCB, "RIGHT", 3, 0)
-- Player name
frame.nameText = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
frame.nameText:SetPoint("LEFT", frame.blueCB, "RIGHT", 4, 0)
frame.nameText:SetWidth(PLAYER_WIDTH - 30)
frame.nameText:SetJustifyH("LEFT")
frame.nameText:SetText("")
frame.playerName = nil
return frame
end
local function createGroupHeader(parent, groupNum, x, y)
local header = CreateFrame("Frame", nil, parent)
header:SetWidth(PLAYER_WIDTH)
header:SetHeight(GROUP_HEADER_HEIGHT)
header:SetPoint("TOPLEFT", parent, "TOPLEFT", x, y)
-- Background
header.bg = header:CreateTexture(nil, "BACKGROUND")
header.bg:SetAllPoints()
header.bg:SetTexture("Interface\\BUTTONS\\WHITE8X8")
header.bg:SetVertexColor(0.3, 0.3, 0.3, 0.5)
-- Text
header.text = header:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
header.text:SetPoint("LEFT", 4, 0)
header.text:SetText("Group " .. groupNum)
header.text:SetTextColor(1, 0.82, 0) -- Gold
return header
end
-------------------------------------------------------------------------------
-- Main UI Creation
-------------------------------------------------------------------------------
local function createMatrixFrame()
if matrixFrame then
return matrixFrame
end
-- Main frame
local frame = CreateFrame("Frame", "ShootyMatrixFrame", UIParent)
frame:SetWidth(FRAME_WIDTH)
frame:SetHeight(FRAME_HEIGHT)
frame:SetPoint("CENTER", UIParent, "CENTER", 0, 0)
frame:SetFrameStrata("DIALOG")
frame:SetMovable(true)
frame:EnableMouse(true)
frame:RegisterForDrag("LeftButton")
frame:SetScript("OnDragStart", function() this:StartMoving() end)
frame:SetScript("OnDragStop", function() this:StopMovingOrSizing() end)
frame:Hide()
-- Backdrop
frame:SetBackdrop({
bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
tile = true,
tileSize = 16,
edgeSize = 16,
insets = {left = 4, right = 4, top = 4, bottom = 4}
})
frame:SetBackdropColor(0.05, 0.05, 0.05, 0.95)
frame:SetBackdropBorderColor(0.4, 0.4, 0.4, 1)
-- Title bar
frame.titleBar = CreateFrame("Frame", nil, frame)
frame.titleBar:SetHeight(24)
frame.titleBar:SetPoint("TOPLEFT", frame, "TOPLEFT", 4, -4)
frame.titleBar:SetPoint("TOPRIGHT", frame, "TOPRIGHT", -4, -4)
frame.titleBar.bg = frame.titleBar:CreateTexture(nil, "BACKGROUND")
frame.titleBar.bg:SetAllPoints()
frame.titleBar.bg:SetTexture("Interface\\BUTTONS\\WHITE8X8")
frame.titleBar.bg:SetVertexColor(0.15, 0.15, 0.15, 0.9)
frame.titleText = frame.titleBar:CreateFontString(nil, "OVERLAY", "GameFontNormal")
frame.titleText:SetPoint("LEFT", 8, 0)
frame.titleText:SetText("Matrix - Keeper Gnarlmoon Assignment")
frame.titleText:SetTextColor(1, 0.82, 0) -- Gold
-- Close button
frame.closeBtn = CreateFrame("Button", nil, frame.titleBar, "UIPanelCloseButton")
frame.closeBtn:SetPoint("TOPRIGHT", frame.titleBar, "TOPRIGHT", 3, 3)
frame.closeBtn:SetScript("OnClick", function() frame:Hide() end)
-- Pill indicators section (top) - "Pills to assign"
frame.pillSection = CreateFrame("Frame", nil, frame)
frame.pillSection:SetHeight(50)
frame.pillSection:SetPoint("TOPLEFT", frame, "TOPLEFT", 8, -32)
frame.pillSection:SetPoint("TOPRIGHT", frame, "TOPRIGHT", -8, -32)
frame.pillSection.bg = frame.pillSection:CreateTexture(nil, "BACKGROUND")
frame.pillSection.bg:SetAllPoints()
frame.pillSection.bg:SetTexture("Interface\\BUTTONS\\WHITE8X8")
frame.pillSection.bg:SetVertexColor(0.1, 0.1, 0.1, 0.7)
frame.pillSection.title = frame.pillSection:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
frame.pillSection.title:SetPoint("TOP", 0, -4)
frame.pillSection.title:SetText("Pills to Distribute")
frame.pillSection.title:SetTextColor(0.8, 0.8, 0.8)
-- Pill indicators
frame.redPillRemaining = createPillIndicator(frame.pillSection, COLOR_RED, 175, -20, "MatrixRedPillRemaining")
frame.redPillRemaining.label = frame.redPillRemaining:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
frame.redPillRemaining.label:SetPoint("LEFT", frame.redPillRemaining.count, "RIGHT", 4, 0)
frame.redPillRemaining.label:SetText("Red (Left)")
frame.redPillRemaining.label:SetTextColor(COLOR_RED.r, COLOR_RED.g, COLOR_RED.b)
frame.bluePillRemaining = createPillIndicator(frame.pillSection, COLOR_BLUE, 295, -20, "MatrixBluePillRemaining")
frame.bluePillRemaining.label = frame.bluePillRemaining:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
frame.bluePillRemaining.label:SetPoint("LEFT", frame.bluePillRemaining.count, "RIGHT", 4, 0)
frame.bluePillRemaining.label:SetText("Blue (Right)")
frame.bluePillRemaining.label:SetTextColor(COLOR_BLUE.r, COLOR_BLUE.g, COLOR_BLUE.b)
frame.awkwardRemaining = createPillIndicator(frame.pillSection, COLOR_AWKWARD, 425, -20, "MatrixAwkwardRemaining")
frame.awkwardRemaining.label = frame.awkwardRemaining:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
frame.awkwardRemaining.label:SetPoint("LEFT", frame.awkwardRemaining.count, "RIGHT", 4, 0)
frame.awkwardRemaining.label:SetText("Awkward")
frame.awkwardRemaining.label:SetTextColor(COLOR_AWKWARD.r, COLOR_AWKWARD.g, COLOR_AWKWARD.b)
-- Player list container (scrollable area)
frame.playerContainer = CreateFrame("Frame", nil, frame)
frame.playerContainer:SetPoint("TOPLEFT", frame.pillSection, "BOTTOMLEFT", 0, -8)
frame.playerContainer:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -8, 80)
frame.playerContainer.bg = frame.playerContainer:CreateTexture(nil, "BACKGROUND")
frame.playerContainer.bg:SetAllPoints()
frame.playerContainer.bg:SetTexture("Interface\\BUTTONS\\WHITE8X8")
frame.playerContainer.bg:SetVertexColor(0.08, 0.08, 0.08, 0.5)
-- Assigned section (bottom) - "Pills taken"
frame.assignedSection = CreateFrame("Frame", nil, frame)
frame.assignedSection:SetHeight(40)
frame.assignedSection:SetPoint("BOTTOMLEFT", frame, "BOTTOMLEFT", 8, 36)
frame.assignedSection:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -8, 36)
frame.assignedSection.bg = frame.assignedSection:CreateTexture(nil, "BACKGROUND")
frame.assignedSection.bg:SetAllPoints()
frame.assignedSection.bg:SetTexture("Interface\\BUTTONS\\WHITE8X8")
frame.assignedSection.bg:SetVertexColor(0.1, 0.1, 0.1, 0.7)
frame.assignedSection.title = frame.assignedSection:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
frame.assignedSection.title:SetPoint("TOP", 0, -4)
frame.assignedSection.title:SetText("Pills Taken")
frame.assignedSection.title:SetTextColor(0.8, 0.8, 0.8)
frame.redPillAssigned = createPillIndicator(frame.assignedSection, COLOR_RED, 220, -18, "MatrixRedPillAssigned")
frame.redPillAssigned.label = frame.redPillAssigned:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
frame.redPillAssigned.label:SetPoint("LEFT", frame.redPillAssigned.count, "RIGHT", 4, 0)
frame.redPillAssigned.label:SetText("Red")
frame.redPillAssigned.label:SetTextColor(COLOR_RED.r, COLOR_RED.g, COLOR_RED.b)
frame.bluePillAssigned = createPillIndicator(frame.assignedSection, COLOR_BLUE, 360, -18, "MatrixBluePillAssigned")
frame.bluePillAssigned.label = frame.bluePillAssigned:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
frame.bluePillAssigned.label:SetPoint("LEFT", frame.bluePillAssigned.count, "RIGHT", 4, 0)
frame.bluePillAssigned.label:SetText("Blue")
frame.bluePillAssigned.label:SetTextColor(COLOR_BLUE.r, COLOR_BLUE.g, COLOR_BLUE.b)
-- Reset button
frame.resetButton = CreateFrame("Button", "MatrixResetButton", frame, "UIPanelButtonTemplate")
frame.resetButton:SetWidth(80)
frame.resetButton:SetHeight(24)
frame.resetButton:SetPoint("BOTTOMLEFT", frame, "BOTTOMLEFT", 80, 8)
frame.resetButton:SetText("Reset")
frame.resetButton:SetScript("OnClick", function()
sepgp_matrix:ResetAssignments()
end)
-- Assign button
frame.assignButton = CreateFrame("Button", "MatrixAssignButton", frame, "UIPanelButtonTemplate")
frame.assignButton:SetWidth(140)
frame.assignButton:SetHeight(24)
frame.assignButton:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -80, 8)
frame.assignButton:SetText("Announce Teams")
frame.assignButton:Disable()
frame.assignButton:SetScript("OnClick", function()
sepgp_matrix:AnnounceTeams()
end)
-- Make escapable
sepgp:make_escable("ShootyMatrixFrame", "add")
matrixFrame = frame
return frame
end
-------------------------------------------------------------------------------
-- Refresh Display
-------------------------------------------------------------------------------
local function refreshPlayerList()
if not matrixFrame then return end
if isUpdating then return end
isUpdating = true
-- Hide all existing player frames
for _, pf in pairs(playerFrames) do
if pf and pf.Hide then
pf:Hide()
end
end
-- Get current roster
raidRoster = buildRaidRoster()
-- Clean up assignments for players no longer in raid
local rosterLookup = {}
for _, player in ipairs(raidRoster) do
rosterLookup[player.name] = true
end
for name, _ in pairs(playerAssignments) do
if not rosterLookup[name] then
playerAssignments[name] = nil
end
end
-- Create player frames organized by group
local groups = {}
for i = 1, 8 do
groups[i] = {}
end
for _, player in ipairs(raidRoster) do
local g = player.subgroup
if g and g >= 1 and g <= 8 then
table.insert(groups[g], player)
end
end
-- Layout: 4 columns, 2 groups per column
local COLUMN_WIDTH = 175
local START_Y = -8
local GROUP_SPACING = 4
local playerIndex = 0
for col = 1, 4 do
local x = (col - 1) * COLUMN_WIDTH + 8
local y = START_Y
local startGroup = (col - 1) * 2 + 1
local endGroup = col * 2
for groupNum = startGroup, endGroup do
local groupPlayers = groups[groupNum]
if groupPlayers and table.getn(groupPlayers) > 0 then
-- Create group header
local headerKey = "header_" .. groupNum
if not playerFrames[headerKey] then
playerFrames[headerKey] = createGroupHeader(matrixFrame.playerContainer, groupNum, x, y)
else
playerFrames[headerKey]:SetPoint("TOPLEFT", matrixFrame.playerContainer, "TOPLEFT", x, y)
end
playerFrames[headerKey].text:SetText("Group " .. groupNum)
playerFrames[headerKey]:Show()
y = y - GROUP_HEADER_HEIGHT
-- Create player frames
for _, player in ipairs(groupPlayers) do
playerIndex = playerIndex + 1
local key = "player_" .. playerIndex
if not playerFrames[key] then
playerFrames[key] = createPlayerFrame(matrixFrame.playerContainer, player, x, y)
else
playerFrames[key]:SetPoint("TOPLEFT", matrixFrame.playerContainer, "TOPLEFT", x, y)
end
local pf = playerFrames[key]
pf.playerName = player.name
-- Set name with class color
local colorHex = getClassColor(player.class)
pf.nameText:SetText("|cff" .. colorHex .. player.name .. "|r")
-- Update assignment state
updatePlayerFrame(pf, player)
pf:Show()
y = y - PLAYER_HEIGHT
end
y = y - GROUP_SPACING
end
end
end
-- Update pill indicators
updatePillIndicators()
isUpdating = false
end
-------------------------------------------------------------------------------
-- Announce Teams
-------------------------------------------------------------------------------
function sepgp_matrix:AnnounceTeams()
local redTeam = {}
local blueTeam = {}
for _, player in ipairs(raidRoster) do
local assignment = playerAssignments[player.name]
if assignment == "red" then
table.insert(redTeam, {name = player.name, class = player.class})
elseif assignment == "blue" then
table.insert(blueTeam, {name = player.name, class = player.class})
end
end
-- Sort alphabetically
table.sort(redTeam, function(a, b) return a.name < b.name end)
table.sort(blueTeam, function(a, b) return a.name < b.name end)
-- Build message strings with class colors
local redNames = {}
for _, p in ipairs(redTeam) do
local colorHex = getClassColor(p.class)
table.insert(redNames, "|cff" .. colorHex .. p.name .. "|r")
end
local blueNames = {}
for _, p in ipairs(blueTeam) do
local colorHex = getClassColor(p.class)
table.insert(blueNames, "|cff" .. colorHex .. p.name .. "|r")
end
-- Send messages
local channel = "RAID"
if IsRaidLeader() or IsRaidOfficer() then
channel = "RAID_WARNING"
end
-- Helper function to send names in chunks of 9
local NAMES_PER_MESSAGE = 9
local function sendTeamMessages(names, teamLabel, teamColor)
local totalNames = table.getn(names)
if totalNames == 0 then return end
local chunk = {}
for i, name in ipairs(names) do
table.insert(chunk, name)
if table.getn(chunk) == NAMES_PER_MESSAGE or i == totalNames then
local msg = teamColor .. teamLabel .. "|r: " .. table.concat(chunk, ", ")
SendChatMessage(msg, channel)
chunk = {}
end
end
end
-- Red team announcement
sendTeamMessages(redNames, "RED TEAM (Left)", "|cffff3333")
-- Empty line separator (send a simple divider)
SendChatMessage("---", channel)
-- Blue team announcement
sendTeamMessages(blueNames, "BLUE TEAM (Right)", "|cff3366ff")
-- Also print locally
sepgp:defaultPrint("Matrix teams have been announced!")
end
-------------------------------------------------------------------------------
-- Reset Assignments
-------------------------------------------------------------------------------
function sepgp_matrix:ResetAssignments()
-- Clear all assignments
for name, _ in pairs(playerAssignments) do
playerAssignments[name] = nil
end
-- Refresh the display
refreshPlayerList()
end
-------------------------------------------------------------------------------
-- Toggle Window
-------------------------------------------------------------------------------
function sepgp_matrix:Toggle()
local canUse, errorMsg = canUseMatrix()
if not canUse then
sepgp:defaultPrint(errorMsg)
return
end
if not matrixFrame then
createMatrixFrame()
end
if matrixFrame:IsVisible() then
matrixFrame:Hide()
else
refreshPlayerList()
matrixFrame:Show()
end
end
-------------------------------------------------------------------------------
-- Event Handlers
-------------------------------------------------------------------------------
function sepgp_matrix:OnEnable()
self:RegisterEvent("RAID_ROSTER_UPDATE", "OnRaidRosterUpdate")
self:RegisterEvent("PARTY_MEMBERS_CHANGED", "OnRaidRosterUpdate")
end
function sepgp_matrix:OnDisable()
if matrixFrame then
matrixFrame:Hide()
end
end
function sepgp_matrix:OnRaidRosterUpdate()
if matrixFrame and matrixFrame:IsVisible() then
refreshPlayerList()
end
end
-------------------------------------------------------------------------------
-- Slash Command Registration
-------------------------------------------------------------------------------
SLASH_MATRIX1 = "/matrix"
SlashCmdList["MATRIX"] = function(msg)
sepgp_matrix:Toggle()
end