local PLUGIN = PLUGIN surface.CreateFont("ixAdminShopTitle", { font = "Montserrat", size = 28, weight = 900, antialias = true }) surface.CreateFont("ixAdminShopTab", { font = "Montserrat", size = 18, weight = 700, antialias = true }) surface.CreateFont("ixAdminShopItem", { font = "Montserrat", size = 20, weight = 800, antialias = true }) surface.CreateFont("ixAdminShopDesc", { font = "Montserrat", size = 14, weight = 500, antialias = true }) surface.CreateFont("ixAdminShopPrice", { font = "Montserrat", size = 18, weight = 900, antialias = true }) surface.CreateFont("ixAdminShopSmall", { font = "Montserrat", size = 14, weight = 600, antialias = true }) surface.CreateFont("ixAdminShopBold", { font = "Montserrat", size = 16, weight = 800, antialias = true }) surface.CreateFont("ixAdminShopTableHeader", { font = "Montserrat", size = 15, weight = 800, antialias = true }) surface.CreateFont("ixAdminShopTableCell", { font = "Montserrat", size = 14, weight = 500, antialias = true }) -- Modern Color Palette #00431c local COLOR_BASE = Color(0, 67, 28) local COLOR_BG = Color(15, 18, 16, 250) local COLOR_CARD = Color(22, 26, 24, 255) local COLOR_CARD_LIGHT = Color(30, 36, 32, 255) local COLOR_TEXT = Color(240, 245, 240) local COLOR_TEXT_DIM = Color(140, 150, 145) local COLOR_ACCENT = Color(0, 140, 60) local COLOR_DANGER = Color(200, 50, 50) local COLOR_WARN = Color(200, 150, 0) function PLUGIN:WrapText(text, width, font) surface.SetFont(font) local words = string.Explode(" ", text) local lines = {} local currentLine = "" for _, word in ipairs(words) do local testLine = currentLine == "" and word or currentLine .. " " .. word local w, _ = surface.GetTextSize(testLine) if w > width then table.insert(lines, currentLine) currentLine = word else currentLine = testLine end end if currentLine ~= "" then table.insert(lines, currentLine) end return lines end local PANEL = {} function PANEL:Init() self:SetSize(ScrW() * 0.7, ScrH() * 0.75) self:Center() self:MakePopup() self:SetTitle("") self:ShowCloseButton(false) self.currentView = "shop" self:SetAlpha(0) self:AlphaTo(255, 0.2, 0) self.startTime = SysTime() self.Paint = function(s, w, h) Derma_DrawBackgroundBlur(s, s.startTime) draw.RoundedBox(8, 0, 0, w, h, COLOR_BG) surface.SetDrawColor(COLOR_BASE.r, COLOR_BASE.g, COLOR_BASE.b, 150) surface.SetMaterial(Material("vgui/gradient-u")) surface.DrawTexturedRect(0, 0, w, 80) surface.SetDrawColor(COLOR_BASE) surface.DrawRect(0, 80, w, 2) local title = self.currentView == "shop" and "АДМИН МАГАЗИН" or (self.currentView == "inventory" and "МОЙ ИНВЕНТАРЬ" or "УПРАВЛЕНИЕ АДМИНИСТРАТОРАМИ") draw.SimpleText(title, "ixAdminShopTitle", 40, 40, COLOR_TEXT, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER) local points = LocalPlayer():GetAdminPoints() draw.SimpleText("Текущий баланс:", "ixAdminShopSmall", w * 0.45, 40, COLOR_TEXT_DIM, TEXT_ALIGN_RIGHT, TEXT_ALIGN_CENTER) draw.SimpleText(points .. " Очков", "ixAdminShopItem", w * 0.45 + 10, 40, COLOR_ACCENT, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER) end local closeBtn = self:Add("DButton") closeBtn:SetSize(40, 40) closeBtn:SetPos(self:GetWide() - 50, 20) closeBtn:SetText("✕") closeBtn:SetFont("ixAdminShopTitle") closeBtn:SetTextColor(COLOR_TEXT_DIM) closeBtn.Paint = nil closeBtn.DoClick = function() self:AlphaTo(0, 0.2, 0, function() self:Close() end) end closeBtn.OnCursorEntered = function(s) s:SetTextColor(COLOR_DANGER) end closeBtn.OnCursorExited = function(s) s:SetTextColor(COLOR_TEXT_DIM) end self.nav = self:Add("Panel") self.nav:SetSize(600, 40) self.nav:SetPos(self:GetWide() - 670, 20) local function CreateNavBtn(text, view, x, activeColor) local btn = self.nav:Add("DButton") btn:SetSize(140, 40) btn:SetPos(x, 0) btn:SetText(text) btn:SetFont("ixAdminShopBold") btn:SetTextColor(COLOR_TEXT) btn.Paint = function(s, w, h) if self.currentView == view then draw.RoundedBox(4, 0, 0, w, h, activeColor) elseif s:IsHovered() then draw.RoundedBox(4, 0, 0, w, h, Color(255, 255, 255, 10)) end end btn.DoClick = function() surface.PlaySound("ui/buttonclick.wav") self.currentView = view self:Refresh() end return btn end CreateNavBtn("Магазин", "shop", 0, COLOR_BASE) -- Всегда создаем кнопку "Панель", но скрываем для не-superadmin local panelBtn = CreateNavBtn("Панель", "panel", 160, Color(120, 0, 180)) local ply = LocalPlayer() if IsValid(ply) and (ply:IsSuperAdmin() or ply:GetUserGroup() == "superadmin") then panelBtn:SetVisible(true) else panelBtn:SetVisible(false) end -- Проверка через 0.5 секунды на случай если данные еще загружаются timer.Simple(0.5, function() if not IsValid(panelBtn) or not IsValid(self) then return end local ply = LocalPlayer() if IsValid(ply) and (ply:IsSuperAdmin() or ply:GetUserGroup() == "superadmin") then panelBtn:SetVisible(true) end end) self.content = self:Add("DScrollPanel") self.content:Dock(FILL) self.content:DockMargin(40, 100, 40, 40) local sbar = self.content:GetVBar() sbar:SetWide(8) sbar:SetHideButtons(true) sbar.Paint = function(s, w, h) draw.RoundedBox(4, 0, 0, w, h, Color(0, 0, 0, 100)) end sbar.btnGrip.Paint = function(s, w, h) draw.RoundedBox(4, 2, 0, w-4, h, s:IsHovered() and COLOR_ACCENT or COLOR_BASE) end self:Refresh() end function PANEL:Refresh() self.content:Clear() if self.currentView == "shop" then local layout = self.content:Add("DIconLayout") layout:Dock(TOP) layout:SetSpaceX(20) layout:SetSpaceY(20) for id, item in pairs(PLUGIN.Items) do local card = layout:Add("DPanel") card:SetSize(250, 340) card.Paint = function(s, w, h) draw.RoundedBox(8, 0, 0, w, h, COLOR_CARD) surface.SetDrawColor(COLOR_CARD_LIGHT) surface.SetMaterial(Material("vgui/gradient-d")) surface.DrawTexturedRect(0, 0, w, 140) draw.SimpleText(item.name, "ixAdminShopItem", w/2, 160, COLOR_TEXT, TEXT_ALIGN_CENTER) local descLines = PLUGIN:WrapText(item.desc, w - 30, "ixAdminShopDesc") for i, line in ipairs(descLines) do if i > 4 then break end draw.SimpleText(line, "ixAdminShopDesc", w/2, 185 + (i-1)*18, COLOR_TEXT_DIM, TEXT_ALIGN_CENTER) end end local icon = card:Add("DPanel") icon:SetSize(60, 60) icon:SetPos(250/2 - 30, 40) icon.Paint = function(s, w, h) draw.RoundedBox(8, 0, 0, w, h, COLOR_BG) surface.SetDrawColor(item.color or COLOR_ACCENT) surface.DrawOutlinedRect(0, 0, w, h, 2) end local buy = card:Add("DButton") buy:SetSize(210, 45) buy:SetPos(20, 275) buy:SetText("Купить за " .. item.price .. " Очков") buy:SetFont("ixAdminShopBold") buy:SetTextColor(COLOR_TEXT) buy.Paint = function(s, w, h) draw.RoundedBox(6, 0, 0, w, h, s:IsHovered() and COLOR_ACCENT or COLOR_BASE) end buy.DoClick = function() surface.PlaySound("ui/buttonclick.wav") net.Start("ixAdminShopBuy") net.WriteString(id) net.SendToServer() end end elseif self.currentView == "panel" then -- Запрос данных с сервера net.Start("ixAdminShopPanelOpen") net.SendToServer() -- Заголовок панели local headerPanel = self.content:Add("DPanel") headerPanel:Dock(TOP) headerPanel:SetTall(50) headerPanel.Paint = function(s, w, h) draw.SimpleText("Управление очками администраторов", "ixAdminShopBold", 10, h/2, COLOR_TEXT, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER) end -- Таблица self.panelTable = self.content:Add("DListView") self.panelTable:Dock(TOP) self.panelTable:SetTall(400) self.panelTable:DockMargin(0, 10, 0, 10) self.panelTable:SetMultiSelect(false) self.panelTable.Paint = function(s, w, h) draw.RoundedBox(6, 0, 0, w, h, COLOR_CARD) end local col1 = self.panelTable:AddColumn("Игрок") local col2 = self.panelTable:AddColumn("SteamID") local col3 = self.panelTable:AddColumn("Ранг") local col4 = self.panelTable:AddColumn("Очки") col1:SetWidth(160) col2:SetWidth(140) col3:SetWidth(100) col4:SetWidth(80) -- Настройка заголовков таблицы for _, col in ipairs(self.panelTable.Columns) do col.Header:SetFont("ixAdminShopTableHeader") col.Header:SetTextColor(COLOR_TEXT) col.Header.Paint = function(s, w, h) draw.RoundedBox(0, 0, 0, w, h, COLOR_BASE) end end -- Панель управления local controlPanel = self.content:Add("DPanel") controlPanel:Dock(TOP) controlPanel:SetTall(120) controlPanel.Paint = function(s, w, h) draw.RoundedBox(6, 0, 0, w, h, COLOR_CARD) end local selectedSID = nil -- Поле ввода количества очков local amountEntry = controlPanel:Add("DTextEntry") amountEntry:SetSize(200, 40) amountEntry:SetPos(10, 10) amountEntry:SetPlaceholderText("Количество очков...") amountEntry:SetNumeric(true) amountEntry:SetFont("ixAdminShopBold") -- Кнопка выдачи очков local giveBtn = controlPanel:Add("DButton") giveBtn:SetSize(180, 40) giveBtn:SetPos(220, 10) giveBtn:SetText("Выдать очки") giveBtn:SetFont("ixAdminShopBold") giveBtn:SetTextColor(COLOR_TEXT) giveBtn.Paint = function(s, w, h) draw.RoundedBox(6, 0, 0, w, h, s:IsHovered() and Color(0, 180, 80) or COLOR_ACCENT) end giveBtn.DoClick = function() if not selectedSID then surface.PlaySound("buttons/button10.wav") return end local amount = tonumber(amountEntry:GetValue()) or 0 if amount < 1 then surface.PlaySound("buttons/button10.wav") return end surface.PlaySound("ui/buttonclick.wav") net.Start("ixAdminShopPanelGivePoints") net.WriteString(selectedSID) net.WriteUInt(amount, 32) net.SendToServer() amountEntry:SetValue("") end -- Кнопка забирания очков local takeBtn = controlPanel:Add("DButton") takeBtn:SetSize(180, 40) takeBtn:SetPos(410, 10) takeBtn:SetText("Забрать очки") takeBtn:SetFont("ixAdminShopBold") takeBtn:SetTextColor(COLOR_TEXT) takeBtn.Paint = function(s, w, h) draw.RoundedBox(6, 0, 0, w, h, s:IsHovered() and Color(230, 60, 60) or COLOR_DANGER) end takeBtn.DoClick = function() if not selectedSID then surface.PlaySound("buttons/button10.wav") return end local amount = tonumber(amountEntry:GetValue()) or 0 if amount < 1 then surface.PlaySound("buttons/button10.wav") return end surface.PlaySound("ui/buttonclick.wav") net.Start("ixAdminShopPanelTakePoints") net.WriteString(selectedSID) net.WriteUInt(amount, 32) net.SendToServer() amountEntry:SetValue("") end -- Информация о выбранном игроке local infoLabel = controlPanel:Add("DLabel") infoLabel:SetSize(400, 30) infoLabel:SetPos(10, 55) infoLabel:SetFont("ixAdminShopSmall") infoLabel:SetTextColor(COLOR_TEXT_DIM) infoLabel:SetText("Выберите игрока из таблицы") -- Подсказка local hintLabel = controlPanel:Add("DLabel") hintLabel:SetSize(500, 25) hintLabel:SetPos(10, 85) hintLabel:SetFont("ixAdminShopSmall") hintLabel:SetTextColor(COLOR_WARN) hintLabel:SetText("Вводите только положительные числа. Нажмите строку в таблице для выбора.") -- Обработчик выбора строки self.panelTable.OnRowSelected = function(tbl, rowIndex, row) local data = self.panelPlayers and self.panelPlayers[rowIndex] if data then selectedSID = data.steamID infoLabel:SetText("Выбран: " .. data.name .. " (" .. data.steamID .. ") — Очков: " .. data.points) end end end end vgui.Register("ixAdminShop", PANEL, "DFrame") net.Receive("ixAdminShopPanelData", function() local data = net.ReadTable() if IsValid(ixAdminShop) and ixAdminShop.panelTable then ixAdminShop.panelTable:Clear() ixAdminShop.panelPlayers = {} for i, plyData in ipairs(data) do ixAdminShop.panelTable:AddLine(plyData.name, plyData.steamID, plyData.rank, plyData.points) ixAdminShop.panelPlayers[i] = plyData end end end) net.Receive("ixAdminShopOpen", function() if (IsValid(ixAdminShop)) then ixAdminShop:Close() end ixAdminShop = vgui.Create("ixAdminShop") end)