add sborka
This commit is contained in:
199
garrysmod/gamemodes/militaryrp/plugins/admin_magaz/cl_plugin.lua
Normal file
199
garrysmod/gamemodes/militaryrp/plugins/admin_magaz/cl_plugin.lua
Normal file
@@ -0,0 +1,199 @@
|
||||
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 })
|
||||
|
||||
-- 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(450, 40)
|
||||
self.nav:SetPos(self:GetWide() - 520, 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)
|
||||
|
||||
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
|
||||
end
|
||||
end
|
||||
|
||||
vgui.Register("ixAdminShop", PANEL, "DFrame")
|
||||
|
||||
net.Receive("ixAdminShopOpen", function()
|
||||
if (IsValid(ixAdminShop)) then
|
||||
ixAdminShop:Close()
|
||||
end
|
||||
ixAdminShop = vgui.Create("ixAdminShop")
|
||||
end)
|
||||
@@ -0,0 +1,75 @@
|
||||
local PLUGIN = PLUGIN
|
||||
|
||||
PLUGIN.name = "Admin Shop"
|
||||
PLUGIN.author = "Scripty"
|
||||
PLUGIN.description = "Adds an admin shop with a unique currency 'Points', inventory, and admin panel."
|
||||
|
||||
PLUGIN.Items = {
|
||||
["remove_warn"] = {
|
||||
name = "Снятие выговора",
|
||||
desc = "Снимает один активный выговор с вашего аккаунта. Выговор будет удален из базы данных, и это отобразится в истории.",
|
||||
price = 150,
|
||||
category = "Other",
|
||||
icon = "icon16/error_delete.png",
|
||||
oneTime = true
|
||||
},
|
||||
["tacrp_ex_m4a1"] = {
|
||||
name = "Оружие: HK416",
|
||||
desc = "Мощная штурмовая винтовка HK416. Доступ на 10 дней. Оружие выдается через инвентарь.",
|
||||
price = 50,
|
||||
category = "Weapons",
|
||||
duration = 10,
|
||||
class = "tacrp_ex_m4a1",
|
||||
color = Color(30, 144, 255)
|
||||
},
|
||||
["tacrp_mg4"] = {
|
||||
name = "Оружие: M249",
|
||||
desc = "Тяжелый пулемет M249. Доступ на 15 дней. Оружие выдается через инвентарь.",
|
||||
price = 60,
|
||||
category = "Weapons",
|
||||
duration = 15,
|
||||
class = "tacrp_mg4",
|
||||
color = Color(255, 140, 0)
|
||||
},
|
||||
["tacrp_ex_hecate"] = {
|
||||
name = "Оружие: MSR",
|
||||
desc = "Снайперская винтовка MSR. Доступ на 13 дней. Оружие выдается через инвентарь.",
|
||||
price = 60,
|
||||
category = "Weapons",
|
||||
duration = 13,
|
||||
class = "tacrp_ex_hecate",
|
||||
color = Color(138, 43, 226)
|
||||
},
|
||||
["tacrp_ak_ak12"] = {
|
||||
name = "Оружие: AK-12",
|
||||
desc = "Современная штурмовая винтовка АК-12. Доступ на 5 дней. Оружие выдается через инвентарь.",
|
||||
price = 45,
|
||||
category = "Weapons",
|
||||
duration = 5,
|
||||
class = "tacrp_ak_ak12",
|
||||
color = Color(255, 215, 0)
|
||||
},
|
||||
["tacrp_sd_aac_hb"] = {
|
||||
name = "Оружие: LVO-AC",
|
||||
desc = "Превосходная штурмовая винтовка TFA LVO-AC. Доступ на 15 дней. Оружие выдается через инвентарь.",
|
||||
price = 50,
|
||||
category = "Weapons",
|
||||
duration = 15,
|
||||
class = "tacrp_sd_aac_hb",
|
||||
color = Color(255, 165, 0)
|
||||
}
|
||||
}
|
||||
|
||||
-- Point utility functions
|
||||
local playerMeta = debug.getregistry().Player
|
||||
|
||||
function playerMeta:GetAdminPoints()
|
||||
return self:GetNetVar("adminPoints", 0)
|
||||
end
|
||||
|
||||
function playerMeta:GetAdminInventory()
|
||||
return self:GetNetVar("adminInventory", {})
|
||||
end
|
||||
|
||||
ix.util.Include("sv_plugin.lua")
|
||||
ix.util.Include("cl_plugin.lua")
|
||||
184
garrysmod/gamemodes/militaryrp/plugins/admin_magaz/sv_plugin.lua
Normal file
184
garrysmod/gamemodes/militaryrp/plugins/admin_magaz/sv_plugin.lua
Normal file
@@ -0,0 +1,184 @@
|
||||
local PLUGIN = PLUGIN
|
||||
|
||||
util.AddNetworkString("ixAdminShopOpen")
|
||||
util.AddNetworkString("ixAdminShopBuy")
|
||||
util.AddNetworkString("ixAdminShopRetrieve")
|
||||
util.AddNetworkString("ixAdminShopAdminSync")
|
||||
util.AddNetworkString("ixAdminShopAdminAction")
|
||||
|
||||
function PLUGIN:Initialize()
|
||||
self.shopData = ix.data.Get("adminShop", {})
|
||||
end
|
||||
|
||||
function PLUGIN:SaveShopData()
|
||||
ix.data.Set("adminShop", self.shopData)
|
||||
end
|
||||
|
||||
function PLUGIN:PlayerLoaded(client)
|
||||
local steamID = client:SteamID()
|
||||
self.shopData[steamID] = self.shopData[steamID] or {points = 0, inventory = {}}
|
||||
|
||||
client:SetNetVar("adminPoints", self.shopData[steamID].points)
|
||||
client:SetNetVar("adminInventory", self.shopData[steamID].inventory)
|
||||
end
|
||||
|
||||
local playerMeta = debug.getregistry().Player
|
||||
|
||||
function playerMeta:SetAdminPoints(amount)
|
||||
amount = math.max(0, amount)
|
||||
self:SetNetVar("adminPoints", amount)
|
||||
|
||||
local steamID = self:SteamID()
|
||||
PLUGIN.shopData[steamID] = PLUGIN.shopData[steamID] or {points = 0, inventory = {}}
|
||||
PLUGIN.shopData[steamID].points = amount
|
||||
PLUGIN:SaveShopData()
|
||||
end
|
||||
|
||||
function playerMeta:GiveAdminPoints(amount)
|
||||
self:SetAdminPoints(self:GetAdminPoints() + amount)
|
||||
end
|
||||
|
||||
function playerMeta:TakeAdminPoints(amount)
|
||||
self:SetAdminPoints(self:GetAdminPoints() - amount)
|
||||
end
|
||||
|
||||
function playerMeta:SetAdminInventory(data)
|
||||
self:SetNetVar("adminInventory", data)
|
||||
|
||||
local steamID = self:SteamID()
|
||||
PLUGIN.shopData[steamID] = PLUGIN.shopData[steamID] or {points = 0, inventory = {}}
|
||||
PLUGIN.shopData[steamID].inventory = data
|
||||
PLUGIN:SaveShopData()
|
||||
end
|
||||
|
||||
ix.command.Add("AdminShop", {
|
||||
description = "Открыть магазин администратора.",
|
||||
OnRun = function(self, client)
|
||||
if (!client:IsAdmin() and !client:IsSuperAdmin() and !IsAdminRank(client:GetUserGroup())) then
|
||||
client:Notify("Эта команда доступна только администраторам.")
|
||||
return
|
||||
end
|
||||
net.Start("ixAdminShopOpen")
|
||||
net.Send(client)
|
||||
end
|
||||
})
|
||||
|
||||
net.Receive("ixAdminShopBuy", function(len, client)
|
||||
local itemID = net.ReadString()
|
||||
local item = PLUGIN.Items[itemID]
|
||||
|
||||
if (!item) then return end
|
||||
|
||||
local points = client:GetAdminPoints()
|
||||
if (points < item.price) then
|
||||
client:Notify("У вас недостаточно очков!")
|
||||
return
|
||||
end
|
||||
|
||||
if (itemID == "remove_warn") then
|
||||
local warnPlugin = ix.plugin.Get("warn")
|
||||
if (warnPlugin) then
|
||||
local steamID = client:SteamID()
|
||||
local warns = ix.data.Get("warns", {})
|
||||
local targetData = warns[steamID]
|
||||
|
||||
if (targetData and targetData.count > 0) then
|
||||
targetData.count = targetData.count - 1
|
||||
table.insert(targetData.history, {
|
||||
admin = "Admin Shop",
|
||||
adminSteamID = "STEAM_0:0:0",
|
||||
reason = "Покупка в магазине",
|
||||
time = os.time(),
|
||||
type = "remove"
|
||||
})
|
||||
ix.data.Set("warns", warns)
|
||||
warnPlugin.warns = warns
|
||||
client:TakeAdminPoints(item.price)
|
||||
client:Notify("Вы успешно сняли выговор!")
|
||||
else
|
||||
client:Notify("У вас нет активных выговоров для снятия!")
|
||||
end
|
||||
else
|
||||
client:Notify("Система выговоров не найдена!")
|
||||
end
|
||||
else
|
||||
-- Immediate delivery if class exists
|
||||
if (item.class) then
|
||||
client:GiveItem(item.class)
|
||||
client:TakeAdminPoints(item.price)
|
||||
client:Notify("Вы купили " .. item.name .. ". Предмет выдан!")
|
||||
else
|
||||
-- Fallback to inventory just in case (hidden)
|
||||
local inv = client:GetAdminInventory()
|
||||
local expireTime = 0
|
||||
if (item.duration) then
|
||||
expireTime = os.time() + (item.duration * 24 * 60 * 60)
|
||||
end
|
||||
|
||||
table.insert(inv, {
|
||||
id = itemID,
|
||||
buyTime = os.time(),
|
||||
expireTime = expireTime,
|
||||
name = item.name,
|
||||
class = item.class
|
||||
})
|
||||
|
||||
client:SetAdminInventory(inv)
|
||||
client:TakeAdminPoints(item.price)
|
||||
client:Notify("Вы купили " .. item.name .. ". Предмет добавлен в инвентарь (скрыто).")
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
net.Receive("ixAdminShopRetrieve", function(len, client)
|
||||
local index = net.ReadUInt(16)
|
||||
local inv = client:GetAdminInventory()
|
||||
local itemData = inv[index]
|
||||
|
||||
if (!itemData) then return end
|
||||
|
||||
if (itemData.expireTime > 0 and os.time() > itemData.expireTime) then
|
||||
client:Notify("Срок действия предмета истек!")
|
||||
table.remove(inv, index)
|
||||
client:SetAdminInventory(inv)
|
||||
return
|
||||
end
|
||||
|
||||
if (itemData.class) then
|
||||
client:GiveItem(itemData.class)
|
||||
client:Notify("Вы получили: " .. itemData.name)
|
||||
end
|
||||
end)
|
||||
|
||||
local adminRanks = {
|
||||
["super admin"] = true,
|
||||
["superadmin"] = true,
|
||||
["projectteam"] = true,
|
||||
["teh.admin"] = true,
|
||||
["curator"] = true,
|
||||
["sudo-curator"] = true,
|
||||
["asist-sudo"] = true,
|
||||
["admin"] = true,
|
||||
["st.admin"] = true,
|
||||
["ivent"] = true,
|
||||
["st.event"] = true,
|
||||
["event"] = true,
|
||||
["disp"] = true,
|
||||
["assistant"] = true,
|
||||
["prem"] = true,
|
||||
["dsmoder"] = true
|
||||
}
|
||||
|
||||
local function IsAdminRank(rank)
|
||||
if not rank or rank == "user" then return false end
|
||||
|
||||
local lowerRank = string.lower(rank)
|
||||
|
||||
-- Check exact match in the provided list
|
||||
if adminRanks[lowerRank] then return true end
|
||||
|
||||
-- Keep generic string searches just in case
|
||||
if lowerRank == "founder" or lowerRank == "owner" or lowerRank == "manager" then return true end
|
||||
|
||||
return false
|
||||
end
|
||||
Reference in New Issue
Block a user