Files
VnUtest/garrysmod/gamemodes/militaryrp/plugins/admin_magaz/cl_plugin.lua
2026-03-31 23:30:56 +03:00

375 lines
14 KiB
Lua
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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)