385 lines
14 KiB
Lua
385 lines
14 KiB
Lua
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)
|