add sborka

This commit is contained in:
2026-03-31 10:27:04 +03:00
commit f5e5f56c84
2345 changed files with 382127 additions and 0 deletions

View File

@@ -0,0 +1,460 @@
local PLUGIN = PLUGIN
-- Создание шрифтов
surface.CreateFont("ScoreboardHeader", {
font = "Exo 2",
size = 24,
weight = 600
})
surface.CreateFont("ScoreboardPlayer", {
font = "Exo 2",
size = 22,
weight = 500
})
surface.CreateFont("ScoreboardButton", {
font = "Exo 2",
size = 20,
weight = 600
})
surface.CreateFont("ScoreboardButtonSmall", {
font = "Exo 2",
size = 16,
weight = 600
})
-- Фоновый материал
local bgMaterial = Material("materials/ft_ui/military/vnu/charcreate/bg.png")
local logoMaterial = Material("materials/ft_ui/military/vnu/charcreate/logo.png")
-- Переменные
PLUGIN.scoreboardFrame = nil
PLUGIN.selectedPlayer = nil
-- Получение иконки фракции
local function GetFactionIcon(faction)
if faction == FACTION_RUSSIAN then
return Material("materials/ft_ui/military/vnu/scoreboard/rf.png")
elseif faction == FACTION_UKRAINE then
return Material("materials/ft_ui/military/vnu/scoreboard/ua.png")
end
return nil
end
-- Создание заголовка секции
local function CreateSectionHeader(parent, y, faction)
local header = vgui.Create("DPanel", parent)
header:SetPos(200, y)
header:SetSize(1520, 40)
header.Paint = function(s, w, h)
surface.SetDrawColor(1, 54, 23)
draw.RoundedBox(5, 0, 0, w, h, Color(1, 54, 23))
surface.SetDrawColor(1, 104, 44)
surface.DrawOutlinedRect(0, 0, w, h, 1)
end
-- Иконка фракции
local icon = vgui.Create("DImage", header)
icon:SetPos(4, 5)
icon:SetSize(45, 30)
local mat = GetFactionIcon(faction)
if mat then
icon:SetMaterial(mat)
end
-- Заголовки колонок
local columns = {
{text = "Имя", x = 55},
{text = "Подразделение", x = 320},
{text = "Специализация", x = 640},
{text = "Звание", x = 960},
{text = "Привилегия", x = 1200},
{text = "Пинг", x = 1420}
}
for _, col in ipairs(columns) do
local label = vgui.Create("DLabel", header)
label:SetPos(col.x, 5)
label:SetFont("ScoreboardHeader")
label:SetText(col.text)
label:SetTextColor(Color(255, 255, 255))
label:SizeToContents()
end
return header
end
-- Создание строки игрока
local function CreatePlayerRow(parent, y, ply, isExpanded)
local height = isExpanded and 100 or 40
local row = vgui.Create("DButton", parent)
row:SetPos(200, y)
row:SetSize(1520, height)
row:SetText("")
row.Player = ply
row.Paint = function(s, w, h)
local bgColor = Color(13, 13, 13, 217)
if PLUGIN.selectedPlayer == ply then
bgColor = Color(1, 54, 23, 150)
elseif s:IsHovered() then
bgColor = Color(20, 20, 20, 217)
end
draw.RoundedBox(3, 0, 0, w, h, bgColor)
end
row.DoClick = function()
if PLUGIN.selectedPlayer == ply then
PLUGIN.selectedPlayer = nil
else
PLUGIN.selectedPlayer = ply
end
end
-- Проверка на противоположную фракцию
local localChar = LocalPlayer():GetCharacter()
local targetChar = ply:GetCharacter()
local isEnemyFaction = false
if localChar and targetChar then
local localFaction = localChar:GetFaction()
local targetFaction = targetChar:GetFaction()
local iAmAdmin = LocalPlayer().IsAdminMode and LocalPlayer():IsAdminMode()
local targetIsAdmin = (ply.IsAdminMode and ply:IsAdminMode()) or (FACTION_ADMIN and targetFaction == FACTION_ADMIN)
isEnemyFaction = (localFaction ~= targetFaction) and not iAmAdmin and not targetIsAdmin
end
-- Аватар (скрыт для противоположной фракции)
if not isEnemyFaction then
local avatar = vgui.Create("AvatarImage", row)
avatar:SetPos(4, 3)
avatar:SetSize(33, 34)
avatar:SetPlayer(ply, 64)
end
-- Имя (скрыт для противоположной фракции)
local name = vgui.Create("DLabel", row)
name:SetPos(55, 7)
name:SetFont("ScoreboardPlayer")
name:SetText(isEnemyFaction and "???" or ply:Nick())
name:SetTextColor(Color(255, 255, 255))
name:SizeToContents()
-- Подразделение
local char = ply:GetCharacter()
if char then
local podrID = char:GetPodr()
local factionTable = ix.faction.Get(char:GetFaction())
local podrName = ""
if not isEnemyFaction and factionTable and factionTable.Podr and factionTable.Podr[podrID] then
podrName = factionTable.Podr[podrID].name or ""
elseif isEnemyFaction then
podrName = "???"
end
local podr = vgui.Create("DLabel", row)
podr:SetPos(320, 7)
podr:SetFont("ScoreboardPlayer")
podr:SetText(podrName)
podr:SetTextColor(Color(255, 255, 255))
podr:SizeToContents()
-- Специализация
local specID = char:GetSpec()
local specName = ""
if not isEnemyFaction and factionTable and factionTable.Spec and factionTable.Spec[specID] then
specName = factionTable.Spec[specID].name or ""
elseif isEnemyFaction then
specName = "???"
end
local spec = vgui.Create("DLabel", row)
spec:SetPos(640, 7)
spec:SetFont("ScoreboardPlayer")
spec:SetText(specName)
spec:SetTextColor(Color(255, 255, 255))
spec:SizeToContents()
-- Звание
local rankName = ""
if not isEnemyFaction then
rankName = ply.GetRankName and ply:GetRankName() or ""
else
rankName = "???"
end
local rank = vgui.Create("DLabel", row)
rank:SetPos(960, 7)
rank:SetFont("ScoreboardPlayer")
rank:SetText(rankName)
rank:SetTextColor(Color(255, 255, 255))
rank:SizeToContents()
end
-- Привилегия
local usergroup = ply:GetUserGroup()
local priv = vgui.Create("DLabel", row)
priv:SetPos(1200, 7)
priv:SetFont("ScoreboardPlayer")
priv:SetText(PLUGIN.NiceUserGroupName[usergroup] or usergroup)
priv:SetTextColor(Color(255, 255, 255))
priv:SizeToContents()
-- Пинг
local ping = vgui.Create("DLabel", row)
ping:SetPos(1420, 7)
ping:SetFont("ScoreboardPlayer")
ping:SetText(tostring(ply:Ping()))
ping:SetTextColor(Color(255, 255, 255))
ping:SizeToContents()
-- Кнопки действий (появляются при клике на игрока)
if isExpanded then
local buttons = {
{text = "Скопировать SteamID", x = 204, w = 200, action = "copy_steamid"},
{text = "Скопировать SteamID64", x = 414, w = 200, action = "copy_steamid64"},
{text = "Скопировать никнейм", x = 624, w = 200, action = "copy_nick"},
{text = "Открыть профиль", x = 834, w = 200, action = "open_profile"}
}
for _, btn in ipairs(buttons) do
local button = vgui.Create("DButton", row)
button:SetPos(btn.x, 47)
button:SetSize(btn.w, 28)
button:SetText("")
button.Paint = function(s, w, h)
surface.SetDrawColor(1, 54, 23)
draw.RoundedBox(3, 0, 0, w, h, Color(1, 54, 23))
surface.SetDrawColor(1, 104, 44)
surface.DrawOutlinedRect(0, 0, w, h, 1)
if s:IsHovered() then
surface.SetDrawColor(255, 255, 255, 20)
surface.DrawRect(0, 0, w, h)
end
draw.SimpleText(btn.text, "ScoreboardButtonSmall", w/2, h/2, Color(255, 255, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
end
button.DoClick = function()
if btn.action == "copy_steamid" then
SetClipboardText(ply:SteamID())
chat.AddText(Color(0, 255, 0), "SteamID скопирован: " .. ply:SteamID())
elseif btn.action == "copy_steamid64" then
SetClipboardText(ply:SteamID64())
chat.AddText(Color(0, 255, 0), "SteamID64 скопирован: " .. ply:SteamID64())
elseif btn.action == "copy_nick" then
SetClipboardText(ply:Nick())
chat.AddText(Color(0, 255, 0), "Никнейм скопирован: " .. ply:Nick())
elseif btn.action == "open_profile" then
ply:ShowProfile()
chat.AddText(Color(0, 255, 0), "Открыт профиль игрока: " .. ply:Nick())
end
end
end
end
return row
end
-- Создание скроллпанели
local function CreatePlayerList(parent)
local scroll = vgui.Create("DScrollPanel", parent)
scroll:SetPos(0, 179)
scroll:SetSize(1920, 754)
-- Кастомный скроллбар
local vbar = scroll:GetVBar()
vbar:SetWide(7)
vbar:SetPos(1714, 0)
function vbar:Paint(w, h)
draw.RoundedBox(10, 0, 0, 3, h, Color(0, 0, 0, 191))
end
function vbar.btnUp:Paint(w, h) end
function vbar.btnDown:Paint(w, h) end
function vbar.btnGrip:Paint(w, h)
draw.RoundedBox(10, 0, 0, w, h, Color(1, 104, 44))
end
return scroll
end
-- Обновление списка игроков
local function UpdatePlayerList(scroll)
scroll:Clear()
local yPos = 0
local players = player.GetAll()
-- Группируем игроков по фракциям
local factions = {}
local factionKeys = {}
for _, ply in ipairs(players) do
local char = ply:GetCharacter()
if char then
local faction = char:GetFaction()
if not factions[faction] then
factions[faction] = {}
table.insert(factionKeys, faction)
end
table.insert(factions[faction], ply)
end
end
-- Сортируем фракции (Админы всегда первые)
table.sort(factionKeys, function(a, b)
if a == FACTION_ADMIN then return true end
if b == FACTION_ADMIN then return false end
return a < b
end)
-- Отображаем каждую фракцию
for _, faction in ipairs(factionKeys) do
local plyList = factions[faction]
-- Сортировка игроков внутри фракции
table.sort(plyList, function(a, b)
local charA = a:GetCharacter()
local charB = b:GetCharacter()
if charA and charB then
local podrA = charA:GetPodr() or 0
local podrB = charB:GetPodr() or 0
-- Веса для подразделений: 8 (Штаб) первый, 1 (Новоприбывшие) последний
local function GetPodrWeight(id)
if id == 8 then return 0 end
if id == 1 then return 999 end
return id
end
local weightA = GetPodrWeight(podrA)
local weightB = GetPodrWeight(podrB)
if weightA ~= weightB then
return weightA < weightB
end
-- Если подразделения одинаковые, сортируем по рангу
local rankA = charA:GetRank() or 0
local rankB = charB:GetRank() or 0
if rankA ~= rankB then
return rankA > rankB -- Высший ранг выше
end
end
return a:Nick() < b:Nick()
end)
-- Заголовок секции
local header = CreateSectionHeader(scroll, yPos, faction)
yPos = yPos + 49
-- Игроки
for _, ply in ipairs(plyList) do
local isExpanded = (PLUGIN.selectedPlayer == ply)
local row = CreatePlayerRow(scroll, yPos, ply, isExpanded)
yPos = yPos + (isExpanded and 103 or 43)
end
yPos = yPos + 10 -- Отступ между секциями
end
end
-- Создание скорборда
function PLUGIN:CreateScoreboard()
if IsValid(self.scoreboardFrame) then
return
end
local scrW, scrH = ScrW(), ScrH()
self.scoreboardFrame = vgui.Create("DFrame")
self.scoreboardFrame:SetSize(scrW, scrH)
self.scoreboardFrame:SetPos(0, 0)
self.scoreboardFrame:SetTitle("")
self.scoreboardFrame:SetDraggable(false)
self.scoreboardFrame:ShowCloseButton(false)
self.scoreboardFrame:SetKeyboardInputEnabled(false)
self.scoreboardFrame:SetMouseInputEnabled(true)
self.scoreboardFrame:MakePopup()
gui.EnableScreenClicker(true)
self.scoreboardFrame.Paint = function(s, w, h)
-- Затемнение
surface.SetDrawColor(10, 10, 10, 140)
surface.DrawRect(0, 0, w, h)
end
-- Верхняя панель
local topBar = vgui.Create("DPanel", self.scoreboardFrame)
topBar:SetPos(0, 0)
topBar:SetSize(scrW, 100)
topBar.Paint = function(s, w, h)
surface.SetDrawColor(13, 13, 13)
surface.DrawRect(0, 0, w, h)
end
-- Логотип
local logo = vgui.Create("DImage", topBar)
logo:SetPos((scrW - 150) / 2, 23)
logo:SetSize(150, 53)
if logoMaterial then
logo:SetMaterial(logoMaterial)
end
-- Список игроков
local scroll = CreatePlayerList(self.scoreboardFrame)
self.scoreboardScroll = scroll
UpdatePlayerList(scroll)
-- Таймер обновления
timer.Create("ScoreboardUpdate", 1, 0, function()
if IsValid(self.scoreboardFrame) then
UpdatePlayerList(scroll)
else
timer.Remove("ScoreboardUpdate")
end
end)
end
-- Удаление скорборда
function PLUGIN:RemoveScoreboard()
if IsValid(self.scoreboardFrame) then
self.scoreboardFrame:Remove()
self.scoreboardFrame = nil
end
gui.EnableScreenClicker(false)
timer.Remove("ScoreboardUpdate")
self.selectedPlayer = nil
end
-- Хуки
function PLUGIN:ScoreboardShow()
self:CreateScoreboard()
end
function PLUGIN:ScoreboardHide()
self:RemoveScoreboard()
end
-- Закрытие при смерти
function PLUGIN:OnCharacterDeleted()
self:RemoveScoreboard()
end

View File

@@ -0,0 +1,24 @@
PLUGIN.name = "Custom Scoreboard"
PLUGIN.author = "Server"
PLUGIN.description = "Custom TAB menu scoreboard"
ix.util.Include("sv_plugin.lua")
ix.util.Include("cl_plugin.lua")
PLUGIN.NiceUserGroupName = {
["superadmin"] = "Супер Администратор",
["teh.admin"] = "Тех. Администратор",
["projectteam"] = "Команда Проекта",
["curator"] = "Куратор",
["disp"] = "Дисциплинёр",
["sudo-curator"] = "Судо-Куратор",
["assistant"] = "Ассистент Куратора",
["st.admin"] = "Старший Администратор",
["admin"] = "Администратор",
["st.event"] = "Старший Ивентолог",
["event"] = "Ивентолог",
["media"] = "Медиа-Партнёр",
["sponsor"] = "Спонсор",
["vip"] = "VIP",
["user"] = "Игрок"
}

View File

@@ -0,0 +1,47 @@
local PLUGIN = PLUGIN
-- Обработка действий администратора
net.Receive("ixScoreboardAction", function(len, client)
if not IsValid(client) or not client:IsAdmin() then return end
local action = net.ReadString()
local target = net.ReadEntity()
if not IsValid(target) or not target:IsPlayer() then return end
if action == "goto" then
client:SetPos(target:GetPos())
client:Notify("Телепортирован к " .. target:Nick())
elseif action == "bring" then
target:SetPos(client:GetPos() + client:GetForward() * 100)
client:Notify("Телепортирован " .. target:Nick())
elseif action == "respawn" then
target:Spawn()
client:Notify("Респавн " .. target:Nick())
elseif action == "return" then
local char = target:GetCharacter()
if char and char.lastPos then
target:SetPos(char.lastPos)
client:Notify("Возвращен " .. target:Nick())
end
elseif action == "whitelist" then
-- Открыть меню whitelist для целевого игрока
-- Реализация зависит от вашей системы whitelist
elseif action == "mute" then
target:SetNWBool("IsMuted", not target:GetNWBool("IsMuted", false))
client:Notify((target:GetNWBool("IsMuted") and "Замучен " or "Размучен ") .. target:Nick())
elseif action == "ban" then
-- Открыть меню бана
-- Реализация через SAM или другую систему администрирования
elseif action == "kick" then
target:Kick("Kicked by " .. client:Nick())
client:Notify("Кикнут " .. target:Nick())
end
end)