-- 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