local menuFrame = nil local factions = {} local function GetPlayerBySteamID(steamID) for _, ply in ipairs(player.GetAll()) do if ply:SteamID() == steamID then return ply end end return nil end local function GetDisplayName(input) if isstring(input) then return input elseif istable(input) then return input[1] or tostring(input) else return tostring(input) end end local selectedPlayer = nil local selectedFaction = nil local selectedPodr = nil local selectedSpec = nil local selectedRank = nil local playerButtons = {} local factionButtons = {} local podrButtons = {} local specButtons = {} local rankButtons = {} local originalPlayers = {} net.Receive("ixWhitelistMenuOpen", function() if menuFrame and menuFrame:IsValid() then menuFrame:Close() end net.Start("ixWhitelistMenuDataRequest") net.SendToServer() end) net.Receive("ixWhitelistMenuData", function() if menuFrame and menuFrame:IsValid() then menuFrame:Close() end originalPlayers = net.ReadTable() factions = net.ReadTable() selectedPlayer = nil selectedFaction = nil selectedPodr = nil selectedSpec = nil selectedRank = nil playerButtons = {} factionButtons = {} podrButtons = {} specButtons = {} rankButtons = {} local scrW, scrH = ScrW(), ScrH() menuFrame = vgui.Create("DFrame") menuFrame:SetSize(900, 650) menuFrame:SetPos(scrW/2 - 450, scrH/2 - 325) menuFrame:SetTitle("") menuFrame:SetDraggable(false) menuFrame:ShowCloseButton(false) menuFrame:MakePopup() menuFrame.Paint = function(s, w, h) -- Фон surface.SetDrawColor(Color(13, 13, 13, 240)) surface.DrawRect(0, 0, w, h) -- Обводка surface.SetDrawColor(Color(1, 67, 29)) surface.DrawOutlinedRect(0, 0, w, h, 2) -- Верхняя панель surface.SetDrawColor(Color(1, 67, 29)) surface.DrawRect(0, 0, w, 40) -- Заголовок draw.SimpleText("МЕНЕДЖЕР ВАЙТЛИСТА", "ixMenuButtonFont", w/2, 20, color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER) end local closeBtn = vgui.Create("DButton", menuFrame) closeBtn:SetText("") closeBtn:SetSize(30, 30) closeBtn:SetPos(menuFrame:GetWide() - 40, 5) closeBtn.Paint = function(s, w, h) surface.SetDrawColor(Color(200, 50, 50)) surface.DrawRect(0, 0, w, h) surface.SetDrawColor(Color(29, 29, 29)) surface.DrawOutlinedRect(0, 0, w, h, 2) draw.SimpleText("×", "ixSmallFont", w/2, h/2, color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER) if s:IsHovered() then surface.SetDrawColor(Color(255, 255, 255, 30)) surface.DrawRect(0, 0, w, h) end end closeBtn.DoClick = function() menuFrame:Close() end local function CreateRow(parent, text, onSelect, data, buttonGroup) local btn = parent:Add("DButton") btn:SetText("") btn:SetTall(30) btn:SetFont("ixSmallFont") btn.Paint = function(s, w, h) if s.isSelected then surface.SetDrawColor(Color(1, 67, 29, 200)) surface.DrawRect(0, 0, w, h) else surface.SetDrawColor(Color(23, 23, 23)) surface.DrawRect(0, 0, w, h) end surface.SetDrawColor(Color(1, 67, 29)) surface.DrawOutlinedRect(0, 0, w, h, 1) local textColor = s.isSelected and color_white or Color(200, 200, 200) draw.SimpleText(text, "ixSmallFont", 8, h/2, textColor, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER) if s:IsHovered() and not s.isSelected then surface.SetDrawColor(Color(255, 255, 255, 20)) surface.DrawRect(0, 0, w, h) end end btn.DoClick = function() for _, otherBtn in ipairs(buttonGroup) do if otherBtn ~= btn then otherBtn.isSelected = false end end btn.isSelected = true if onSelect then onSelect(data) end end btn:DockMargin(2, 2, 2, 2) btn:Dock(TOP) table.insert(buttonGroup, btn) return btn end local colWidth = 160 local colSpacing = 10 local colX = 20 local headerHeight = 30 local scrollHeight = 500 local totalHeight = headerHeight + scrollHeight local startY = 60 local buttonHeight = 40 local function CreateColumnPanel(name, x) local panel = vgui.Create("DPanel", menuFrame) panel:SetSize(colWidth, totalHeight) panel:SetPos(x, startY) panel.Paint = function(s, w, h) surface.SetDrawColor(Color(23, 23, 23)) surface.DrawRect(0, 0, w, h) surface.SetDrawColor(Color(1, 67, 29)) surface.DrawOutlinedRect(0, 0, w, h, 1) end local header = vgui.Create("DLabel", panel) header:SetText(name) header:SetPos(0, 5) header:SetSize(colWidth, 20) header:SetFont("ixSmallFont") header:SetTextColor(color_white) header:SetContentAlignment(5) local scroll = vgui.Create("DScrollPanel", panel) scroll:SetSize(colWidth - 4, scrollHeight) scroll:SetPos(2, headerHeight) return scroll end -- Панель игроков с поиском local playerPanel = vgui.Create("DPanel", menuFrame) playerPanel:SetSize(colWidth, totalHeight) playerPanel:SetPos(colX, startY) playerPanel.Paint = function(s, w, h) surface.SetDrawColor(Color(23, 23, 23)) surface.DrawRect(0, 0, w, h) surface.SetDrawColor(Color(1, 67, 29)) surface.DrawOutlinedRect(0, 0, w, h, 1) end local playerHeader = vgui.Create("DLabel", playerPanel) playerHeader:SetText("ИГРОКИ") playerHeader:SetPos(0, 5) playerHeader:SetSize(colWidth, 20) playerHeader:SetFont("ixSmallFont") playerHeader:SetTextColor(color_white) playerHeader:SetContentAlignment(5) local searchBox = vgui.Create("DTextEntry", playerPanel) searchBox:SetPos(5, 30) searchBox:SetSize(colWidth - 10, 25) searchBox:SetPlaceholderText("Поиск...") searchBox:SetFont("ixSmallFont") searchBox:SetUpdateOnType(true) searchBox.Paint = function(s, w, h) surface.SetDrawColor(Color(23, 23, 23)) surface.DrawRect(0, 0, w, h) surface.SetDrawColor(Color(1, 67, 29)) surface.DrawOutlinedRect(0, 0, w, h, 1) s:DrawTextEntryText(color_white, Color(30, 130, 255), color_white) end local playerScroll = vgui.Create("DScrollPanel", playerPanel) playerScroll:SetSize(colWidth - 4, scrollHeight - 40) playerScroll:SetPos(2, 60) -- Создаем колонки local factionScroll = CreateColumnPanel("ФРАКЦИИ", colX + (colWidth + colSpacing) * 1) local podrScroll = CreateColumnPanel("ПОДРАЗДЕЛЕНИЯ", colX + (colWidth + colSpacing) * 2) local specScroll = CreateColumnPanel("СПЕЦИАЛИЗАЦИИ", colX + (colWidth + colSpacing) * 3) local rankScroll = CreateColumnPanel("ЗВАНИЯ", colX + (colWidth + colSpacing) * 4) local function UpdatePlayerList(filterText) playerScroll:Clear() playerButtons = {} local lowerFilter = string.lower(filterText or "") for _, p in ipairs(originalPlayers) do if filterText == "" or string.find(string.lower(p.name), lowerFilter, 1, true) then CreateRow(playerScroll, p.name, function(data) selectedPlayer = data factionScroll:Clear() podrScroll:Clear() specScroll:Clear() rankScroll:Clear() selectedFaction = nil selectedPodr = nil selectedSpec = nil selectedRank = nil factionButtons = {} podrButtons = {} specButtons = {} rankButtons = {} for id, f in pairs(factions) do CreateRow(factionScroll, GetDisplayName(f.name), function(factionData) selectedFaction = factionData local f = factions[factionData.id] podrScroll:Clear() specScroll:Clear() rankScroll:Clear() selectedPodr = nil selectedSpec = nil selectedRank = nil podrButtons = {} specButtons = {} rankButtons = {} for podId, podr in pairs(f.Podr) do CreateRow(podrScroll, podr.name, function(podrData) selectedPodr = podrData local f2 = factions[selectedFaction.id] -- Update specialties specScroll:Clear() selectedSpec = nil specButtons = {} for specId, spec in pairs(f2.Spec) do if spec.podr == podrData.id then CreateRow(specScroll, spec.name, function(specData) selectedSpec = specData end, { id = specId }, specButtons) end end -- Update ranks based on subdivision rankScroll:Clear() selectedRank = nil rankButtons = {} local targetRanks = (f2.Podr[podrData.id] and f2.Podr[podrData.id].ranks) or f2.Ranks if targetRanks then local keys = {} for k in pairs(targetRanks) do table.insert(keys, k) end table.sort(keys) for _, rankId in ipairs(keys) do local rank = targetRanks[rankId] CreateRow(rankScroll, GetDisplayName(rank[1]), function(rankData) selectedRank = rankData end, { id = rankId }, rankButtons) end end end, { id = podId }, podrButtons) end local factionRanks = f.Ranks if factionRanks then local keys = {} for k in pairs(factionRanks) do table.insert(keys, k) end table.sort(keys) for _, rankId in ipairs(keys) do local rank = factionRanks[rankId] CreateRow(rankScroll, GetDisplayName(rank[1]), function(rankData) selectedRank = rankData end, { id = rankId }, rankButtons) end end end, { id = id }, factionButtons) end end, { steamID = p.steamID }, playerButtons) end end end searchBox.OnValueChange = function(_, value) UpdatePlayerList(value) end UpdatePlayerList("") -- Кнопка назначения local applyBtn = vgui.Create("DButton", menuFrame) applyBtn:SetText("") applyBtn:SetSize(200, 40) applyBtn:SetPos(menuFrame:GetWide()/2 - 100, startY + totalHeight + 10) applyBtn.Paint = function(s, w, h) surface.SetDrawColor(Color(1, 67, 29)) surface.DrawRect(0, 0, w, h) surface.SetDrawColor(Color(29, 29, 29)) surface.DrawOutlinedRect(0, 0, w, h, 2) draw.SimpleText("НАЗНАЧИТЬ", "ixSmallFont", w/2, h/2, color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER) if s:IsHovered() then surface.SetDrawColor(Color(255, 255, 255, 30)) surface.DrawRect(0, 0, w, h) end end applyBtn.DoClick = function() if not (selectedPlayer and selectedFaction and selectedPodr and selectedSpec and selectedRank) then LocalPlayer():Notify("Выберите все поля!") return end net.Start("ixWhitelistMenuApply") net.WriteString(selectedPlayer.steamID) net.WriteUInt(selectedFaction.id, 16) net.WriteUInt(selectedPodr.id, 8) net.WriteUInt(selectedSpec.id, 8) net.WriteUInt(selectedRank.id, 8) net.SendToServer() menuFrame:Close() LocalPlayer():Notify("Вайтлист успешно назначен!") end -- Статус выбора local statusPanel = vgui.Create("DPanel", menuFrame) statusPanel:SetSize(400, 30) statusPanel:SetPos(menuFrame:GetWide()/2 - 200, startY + totalHeight - 553.5) statusPanel.Paint = function(s, w, h) local statusText = "Выберите игрока и все параметры" local statusColor = Color(200, 200, 200) if selectedPlayer and selectedFaction and selectedPodr and selectedSpec and selectedRank then statusText = "Готово к назначению" statusColor = Color(84, 147, 90) end draw.SimpleText(statusText, "ixSmallFont", w/2, h/2, statusColor, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER) end menuFrame.OnCursorEntered = function(s) s:MoveToFront() end end)