499 lines
18 KiB
Lua
499 lines
18 KiB
Lua
|
||
|
||
-- Масштабирование для меню
|
||
local function GetScale()
|
||
local scale = ScrH() / 1080
|
||
return math.Clamp(scale, 0.5, 2.0)
|
||
end
|
||
local function ScaleSize(val)
|
||
return math.max(1, math.Round(val * GetScale()))
|
||
end
|
||
local function ScalePos(val)
|
||
return math.Round(val * GetScale())
|
||
end
|
||
|
||
local function CreateMenuFonts()
|
||
surface.CreateFont("ixMenuButtonFont_Adaptive", {
|
||
font = "Roboto",
|
||
size = math.max(ScaleSize(18), 12),
|
||
weight = 500,
|
||
antialias = true
|
||
})
|
||
surface.CreateFont("ixMenuButtonHugeFont_Adaptive", {
|
||
font = "Roboto",
|
||
size = math.max(ScaleSize(32), 20),
|
||
weight = 700,
|
||
antialias = true
|
||
})
|
||
end
|
||
CreateMenuFonts()
|
||
hook.Add("OnScreenSizeChanged", "CharMenu_UpdateFonts", CreateMenuFonts)
|
||
|
||
local CharMenu = {}
|
||
|
||
function CharMenu:Init()
|
||
if IsValid(ix.gui.characterMenu) then
|
||
ix.gui.characterMenu:Remove()
|
||
end
|
||
|
||
self:SetSize(ScrW(), ScrH())
|
||
self:SetPos(0, 0)
|
||
|
||
-- Переменные для совместимости
|
||
self.bClosing = false
|
||
self.currentAlpha = 255
|
||
self.bMenuShouldClose = false
|
||
|
||
-- Проверяем наличие персонажа
|
||
self:CheckCharacterAndLoad()
|
||
|
||
ix.gui.characterMenu = self
|
||
ix.gui.menu = self -- Для совместимости
|
||
|
||
self:MakePopup()
|
||
self:SetKeyboardInputEnabled(true)
|
||
self:SetMouseInputEnabled(true)
|
||
end
|
||
|
||
function CharMenu:CheckCharacterAndLoad()
|
||
-- Ждем немного пока загрузятся данные персонажей
|
||
timer.Simple(0.5, function()
|
||
if not IsValid(self) then return end
|
||
|
||
local hasCharacter = LocalPlayer().GetCharacter and LocalPlayer():GetCharacter()
|
||
|
||
if hasCharacter then
|
||
-- Если персонаж уже загружен, закрываем меню
|
||
print("Персонаж уже загружен, закрываем меню")
|
||
self:Close(true)
|
||
return
|
||
end
|
||
|
||
local characters = ix.characters
|
||
if (#characters > 0) then
|
||
local firstChar = characters[1]
|
||
if not firstChar then
|
||
return
|
||
end
|
||
net.Start("ixCharacterChoose")
|
||
net.WriteUInt(firstChar, 32)
|
||
net.SendToServer()
|
||
else
|
||
-- Если персонажей нет, показываем выбор стороны
|
||
print("Персонажей нет, показываем выбор фракции")
|
||
self:ShowFactionSelection()
|
||
end
|
||
end)
|
||
end
|
||
|
||
function CharMenu:ShowFactionSelection()
|
||
-- Очищаем предыдущие панели
|
||
if IsValid(self.currentPanel) then
|
||
self.currentPanel:Remove()
|
||
end
|
||
|
||
-- Создаем панель выбора фракции
|
||
self.currentPanel = vgui.Create("DPanel", self)
|
||
self.currentPanel:SetSize(ScrW(), ScrH())
|
||
self.currentPanel:SetPos(0, 0)
|
||
|
||
-- Фон
|
||
local backgroundImage = vgui.Create("DImage", self.currentPanel)
|
||
backgroundImage:SetSize(ScrW(), ScrH())
|
||
backgroundImage:SetPos(0, 0)
|
||
backgroundImage:SetImage("ft_ui/military/vnu/charcreate/bg.png")
|
||
|
||
-- Верхняя панель
|
||
CreateMenuFonts()
|
||
local topBar = vgui.Create("DPanel", self.currentPanel)
|
||
topBar:SetSize(ScrW() + 2, ScaleSize(100))
|
||
topBar:SetPos(-1, 0)
|
||
topBar.Paint = function(panel, w, h)
|
||
surface.SetDrawColor(Color(13, 13, 13))
|
||
surface.DrawRect(0, 0, w, h)
|
||
end
|
||
|
||
-- Логотип
|
||
local logo = vgui.Create("DImage", self.currentPanel)
|
||
logo:SetSize(ScaleSize(150), ScaleSize(53))
|
||
logo:SetPos(ScrW()/2 - ScaleSize(75), ScalePos(23))
|
||
logo:SetImage("ft_ui/military/vnu/charcreate/logo.png")
|
||
|
||
-- Заголовок
|
||
local title = vgui.Create("DLabel", self.currentPanel)
|
||
title:SetText("ВЫБОР СТОРОНЫ")
|
||
title:SetFont("ixMenuButtonHugeFont_Adaptive")
|
||
title:SetTextColor(color_white)
|
||
title:SizeToContents()
|
||
title:SetPos(ScrW()/2 - title:GetWide()/2, ScalePos(187))
|
||
|
||
-- Панель ВСУ
|
||
local ukrainePanel = vgui.Create("DPanel", self.currentPanel)
|
||
ukrainePanel:SetSize(ScaleSize(425), ScaleSize(500))
|
||
ukrainePanel:SetPos(ScrW()/2 - ScaleSize(425) - ScaleSize(25), ScalePos(310))
|
||
ukrainePanel.Paint = function(panel, w, h)
|
||
surface.SetDrawColor(Color(0, 0, 0, 180))
|
||
surface.DrawRect(0, 0, w, h)
|
||
surface.SetDrawColor(Color(1, 67, 29))
|
||
surface.DrawOutlinedRect(0, 0, w, h, 2)
|
||
end
|
||
|
||
-- Панель России
|
||
local russiaPanel = vgui.Create("DPanel", self.currentPanel)
|
||
russiaPanel:SetSize(ScaleSize(425), ScaleSize(500))
|
||
russiaPanel:SetPos(ScrW()/2 + ScaleSize(25), ScalePos(310))
|
||
russiaPanel.Paint = function(panel, w, h)
|
||
surface.SetDrawColor(Color(0, 0, 0, 180))
|
||
surface.DrawRect(0, 0, w, h)
|
||
surface.SetDrawColor(Color(1, 67, 29))
|
||
surface.DrawOutlinedRect(0, 0, w, h, 2)
|
||
end
|
||
|
||
-- Изображения фракций
|
||
local ukraineImage = vgui.Create("DImage", self.currentPanel)
|
||
ukraineImage:SetSize(ScaleSize(200), ScaleSize(200))
|
||
ukraineImage:SetPos(ScrW()/2 - ScaleSize(425) - ScaleSize(25) + ScaleSize(113), ScalePos(333))
|
||
ukraineImage:SetImage("ft_ui/military/vnu/charcreate/ukraine.png")
|
||
|
||
local russiaImage = vgui.Create("DImage", self.currentPanel)
|
||
russiaImage:SetSize(ScaleSize(295), ScaleSize(200))
|
||
russiaImage:SetPos(ScrW()/2 + ScaleSize(25) + ScaleSize(65), ScalePos(333))
|
||
russiaImage:SetImage("ft_ui/military/vnu/charcreate/russia.png")
|
||
|
||
-- Кнопки выбора
|
||
local ukraineButton = vgui.Create("DButton", self.currentPanel)
|
||
ukraineButton:SetSize(ScaleSize(425), ScaleSize(75))
|
||
ukraineButton:SetPos(ScrW()/2 - ScaleSize(425) - ScaleSize(25), ScalePos(818))
|
||
ukraineButton:SetText("")
|
||
ukraineButton.Paint = function(panel, 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, 3)
|
||
draw.SimpleText("УКРАИНА", "ixMenuButtonHugeFont_Adaptive", w/2, h/2, Color(255, 255, 255, 218), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
|
||
if panel:IsHovered() then
|
||
surface.SetDrawColor(Color(255, 255, 255, 30))
|
||
surface.DrawRect(0, 0, w, h)
|
||
end
|
||
end
|
||
ukraineButton.DoClick = function()
|
||
self:ShowCharacterCreation(FACTION_UKRAINE)
|
||
end
|
||
|
||
local russiaButton = vgui.Create("DButton", self.currentPanel)
|
||
russiaButton:SetSize(ScaleSize(425), ScaleSize(75))
|
||
russiaButton:SetPos(ScrW()/2 + ScaleSize(25), ScalePos(818))
|
||
russiaButton:SetText("")
|
||
russiaButton.Paint = function(panel, 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, 3)
|
||
draw.SimpleText("РОССИЯ", "ixMenuButtonHugeFont_Adaptive", w/2, h/2, Color(255, 255, 255, 218), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
|
||
if panel:IsHovered() then
|
||
surface.SetDrawColor(Color(255, 255, 255, 30))
|
||
surface.DrawRect(0, 0, w, h)
|
||
end
|
||
end
|
||
russiaButton.DoClick = function()
|
||
self:ShowCharacterCreation(FACTION_RUSSIAN)
|
||
end
|
||
end
|
||
|
||
function CharMenu:ShowCharacterCreation(faction)
|
||
-- Очищаем предыдущие панели
|
||
if IsValid(self.currentPanel) then
|
||
self.currentPanel:Remove()
|
||
end
|
||
|
||
self.currentPanel = vgui.Create("DPanel", self)
|
||
self.currentPanel:SetSize(ScrW(), ScrH())
|
||
self.currentPanel:SetPos(0, 0)
|
||
|
||
-- Фон
|
||
local backgroundImage = vgui.Create("DImage", self.currentPanel)
|
||
backgroundImage:SetSize(ScrW(), ScrH())
|
||
backgroundImage:SetPos(0, 0)
|
||
backgroundImage:SetImage("ft_ui/military/vnu/charcreate/bg.png")
|
||
|
||
-- Верхняя панель
|
||
CreateMenuFonts()
|
||
local topBar = vgui.Create("DPanel", self.currentPanel)
|
||
topBar:SetSize(ScrW() + 2, ScaleSize(100))
|
||
topBar:SetPos(-1, 0)
|
||
topBar.Paint = function(panel, w, h)
|
||
surface.SetDrawColor(Color(13, 13, 13))
|
||
surface.DrawRect(0, 0, w, h)
|
||
end
|
||
|
||
-- Логотип
|
||
local logo = vgui.Create("DImage", self.currentPanel)
|
||
logo:SetSize(ScaleSize(150), ScaleSize(53))
|
||
logo:SetPos(ScrW()/2 - ScaleSize(75), ScalePos(23))
|
||
logo:SetImage("ft_ui/military/vnu/charcreate/logo.png")
|
||
|
||
-- Основная панель
|
||
local mainPanel = vgui.Create("DPanel", self.currentPanel)
|
||
mainPanel:SetSize(ScaleSize(1500), ScaleSize(750))
|
||
mainPanel:SetPos(ScrW()/2 - ScaleSize(750), ScalePos(199))
|
||
mainPanel.Paint = function(panel, w, h)
|
||
surface.SetDrawColor(Color(13, 13, 13, 200))
|
||
surface.DrawRect(0, 0, w, h)
|
||
end
|
||
|
||
-- Заголовки
|
||
local title = vgui.Create("DLabel", self.currentPanel)
|
||
title:SetText("СОЗДАНИЕ ПЕРСОНАЖА")
|
||
title:SetFont("ixMenuButtonHugeFont_Adaptive")
|
||
title:SetTextColor(color_white)
|
||
title:SizeToContents()
|
||
title:SetPos(ScrW()/2 - title:GetWide()/2, ScalePos(224))
|
||
|
||
-- Разделители
|
||
local divider1 = vgui.Create("DPanel", self.currentPanel)
|
||
divider1:SetSize(ScaleSize(770), ScaleSize(2))
|
||
divider1:SetPos(ScrW()/2 - ScaleSize(385), ScalePos(314))
|
||
divider1.Paint = function(panel, w, h)
|
||
surface.SetDrawColor(Color(1, 67, 29))
|
||
surface.DrawRect(0, 0, w, h)
|
||
end
|
||
|
||
-- Поля ввода
|
||
local startX = ScrW()/2 - ScaleSize(420)
|
||
|
||
-- Имя
|
||
local nameLabel = vgui.Create("DLabel", self.currentPanel)
|
||
nameLabel:SetText("Ваше имя")
|
||
nameLabel:SetFont("ixMenuButtonFont_Adaptive")
|
||
nameLabel:SetTextColor(color_white)
|
||
nameLabel:SizeToContents()
|
||
nameLabel:SetPos(startX, ScalePos(360))
|
||
|
||
local nameEntry = vgui.Create("DTextEntry", self.currentPanel)
|
||
nameEntry:SetSize(ScaleSize(265), ScaleSize(50))
|
||
nameEntry:SetPos(startX, ScalePos(401))
|
||
nameEntry:SetFont("ixMenuButtonFont_Adaptive")
|
||
nameEntry:SetTextColor(Color(255, 255, 255, 230))
|
||
nameEntry:SetDrawBackground(false)
|
||
nameEntry.Paint = function(panel, 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)
|
||
panel:DrawTextEntryText(Color(255, 255, 255, 230), Color(30, 130, 255), Color(255, 255, 255, 230))
|
||
end
|
||
|
||
-- Фамилия
|
||
local lastNameLabel = vgui.Create("DLabel", self.currentPanel)
|
||
lastNameLabel:SetText("Ваша фамилия")
|
||
lastNameLabel:SetFont("ixMenuButtonFont_Adaptive")
|
||
lastNameLabel:SetTextColor(color_white)
|
||
lastNameLabel:SizeToContents()
|
||
lastNameLabel:SetPos(startX + ScaleSize(285), ScalePos(360))
|
||
|
||
local lastNameEntry = vgui.Create("DTextEntry", self.currentPanel)
|
||
lastNameEntry:SetSize(ScaleSize(265), ScaleSize(50))
|
||
lastNameEntry:SetPos(startX + ScaleSize(285), ScalePos(401))
|
||
lastNameEntry:SetFont("ixMenuButtonFont_Adaptive")
|
||
lastNameEntry:SetTextColor(Color(255, 255, 255, 230))
|
||
lastNameEntry:SetDrawBackground(false)
|
||
lastNameEntry.Paint = nameEntry.Paint
|
||
|
||
-- Позывной
|
||
local callSignLabel = vgui.Create("DLabel", self.currentPanel)
|
||
callSignLabel:SetText("Ваш позывной")
|
||
callSignLabel:SetFont("ixMenuButtonFont_Adaptive")
|
||
callSignLabel:SetTextColor(color_white)
|
||
callSignLabel:SizeToContents()
|
||
callSignLabel:SetPos(startX + ScaleSize(570), ScalePos(360))
|
||
|
||
local callSignEntry = vgui.Create("DTextEntry", self.currentPanel)
|
||
callSignEntry:SetSize(ScaleSize(265), ScaleSize(50))
|
||
callSignEntry:SetPos(startX + ScaleSize(570), ScalePos(401))
|
||
callSignEntry:SetFont("ixMenuButtonFont_Adaptive")
|
||
callSignEntry:SetTextColor(Color(255, 255, 255, 230))
|
||
callSignEntry:SetDrawBackground(false)
|
||
callSignEntry.Paint = nameEntry.Paint
|
||
|
||
-- Кнопка создания
|
||
local createButton = vgui.Create("DButton", self.currentPanel)
|
||
createButton:SetSize(ScaleSize(300), ScaleSize(80))
|
||
createButton:SetPos(ScrW()/2 - ScaleSize(150), ScrH() - ScaleSize(120))
|
||
createButton:SetText("")
|
||
createButton.Paint = function(panel, 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, 3)
|
||
draw.SimpleText("СОЗДАТЬ", "ixMenuButtonHugeFont_Adaptive", w/2, h/2, color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
|
||
if panel:IsHovered() then
|
||
surface.SetDrawColor(Color(255, 255, 255, 30))
|
||
surface.DrawRect(0, 0, w, h)
|
||
end
|
||
end
|
||
createButton.DoClick = function()
|
||
local name = nameEntry:GetText()
|
||
local lastName = lastNameEntry:GetText()
|
||
local callSign = callSignEntry:GetText()
|
||
if name == "" or lastName == "" or callSign == "" then
|
||
print("Ошибка: Заполните все поля!")
|
||
return
|
||
end
|
||
local fullName = name .. " " .. lastName .. " '" .. callSign .. "'"
|
||
print("Создание персонажа: " .. fullName)
|
||
self:CreateCharacter(faction, fullName)
|
||
end
|
||
self.selectedFaction = faction
|
||
end
|
||
|
||
function CharMenu:CreateCharacter(faction, name)
|
||
if self.awaitingResponse then
|
||
print("Уже ожидаем ответ от сервера...")
|
||
return
|
||
end
|
||
|
||
-- Подготавливаем данные для создания персонажа
|
||
local payload = {
|
||
name = name,
|
||
faction = faction,
|
||
model = "models/player/group01/male_04.mdl",
|
||
description = "Солдат"
|
||
}
|
||
|
||
print("Отправка запроса на создание персонажа...")
|
||
PrintTable(payload)
|
||
|
||
-- Отправляем запрос на создание персонажа
|
||
net.Start("ixCharacterCreate")
|
||
net.WriteUInt(table.Count(payload), 8)
|
||
|
||
for k, v in pairs(payload) do
|
||
net.WriteString(k)
|
||
net.WriteType(v)
|
||
end
|
||
|
||
net.SendToServer()
|
||
|
||
-- Ждем ответа от сервера
|
||
self.awaitingResponse = true
|
||
|
||
-- Таймаут на случай проблем с соединением
|
||
timer.Create("CharCreateTimeout", 10, 1, function()
|
||
if IsValid(ix.gui.characterMenu) and ix.gui.characterMenu.awaitingResponse then
|
||
ix.gui.characterMenu.awaitingResponse = false
|
||
Derma_Message("Таймаут создания персонажа! Проверьте соединение.", "Ошибка", "OK")
|
||
end
|
||
end)
|
||
end
|
||
|
||
-- Методы для совместимости с Helix
|
||
function CharMenu:IsClosing()
|
||
return self.bClosing or false
|
||
end
|
||
|
||
function CharMenu:GetAlpha()
|
||
return self.currentAlpha or 255
|
||
end
|
||
|
||
function CharMenu:GetCharacterOverview()
|
||
-- Заглушка для совместимости
|
||
return nil
|
||
end
|
||
|
||
function CharMenu:Close(bFromMenu)
|
||
self.bClosing = true
|
||
if ix.gui.loading then
|
||
ix.gui.loading:Remove()
|
||
end
|
||
|
||
self:Remove()
|
||
end
|
||
|
||
function CharMenu:Paint(w, h)
|
||
-- Черный фон
|
||
surface.SetDrawColor(Color(0, 0, 0, 255))
|
||
surface.DrawRect(0, 0, w, h)
|
||
end
|
||
|
||
vgui.Register("ixCharMenu", CharMenu, "EditablePanel")
|
||
|
||
-- Исправляем CalcView hook
|
||
hook.Add("CalcView", "MilitaryRPMenuFix", function(ply, origin, angles, fov)
|
||
local menu = ix.gui.characterMenu or ix.gui.menu
|
||
if IsValid(menu) and not menu:IsClosing() then
|
||
-- Возвращаем стандартный вид, чтобы избежать ошибок
|
||
return {
|
||
origin = origin,
|
||
angles = angles,
|
||
fov = fov,
|
||
drawviewer = false
|
||
}
|
||
end
|
||
end)
|
||
|
||
-- Глобальные сетевые обработчики (устанавливаются один раз при загрузке файла)
|
||
net.Receive("ixCharacterLoad", function()
|
||
local characters = net.ReadUInt(8)
|
||
local charList = {}
|
||
|
||
for i = 1, characters do
|
||
charList[i] = net.ReadUInt(32)
|
||
end
|
||
|
||
ix.characters = charList
|
||
print("Получен список персонажей: ", table.concat(charList, ", "))
|
||
|
||
-- Если меню открыто, обновляем его
|
||
if IsValid(ix.gui.characterMenu) then
|
||
ix.gui.characterMenu:CheckCharacterAndLoad()
|
||
end
|
||
end)
|
||
|
||
net.Receive("ixCharacterAuthed", function()
|
||
timer.Remove("CharCreateTimeout")
|
||
|
||
local id = net.ReadUInt(32)
|
||
local characters = net.ReadUInt(8)
|
||
local charList = {}
|
||
|
||
for i = 1, characters do
|
||
charList[i] = net.ReadUInt(32)
|
||
end
|
||
|
||
ix.characters = charList
|
||
|
||
print("Персонаж успешно создан! ID: " .. id)
|
||
print("Теперь доступно персонажей: " .. characters)
|
||
|
||
-- Автоматически выбираем созданного персонажа
|
||
if id then
|
||
print("Автовыбор персонажа ID: " .. id)
|
||
net.Start("ixCharacterChoose")
|
||
net.WriteUInt(id, 32)
|
||
net.SendToServer()
|
||
end
|
||
|
||
-- Закрываем меню если оно открыто
|
||
if IsValid(ix.gui.characterMenu) then
|
||
ix.gui.characterMenu.awaitingResponse = false
|
||
ix.gui.characterMenu:Close(true)
|
||
end
|
||
end)
|
||
|
||
net.Receive("ixCharacterAuthFailed", function()
|
||
timer.Remove("CharCreateTimeout")
|
||
|
||
local fault = net.ReadString()
|
||
local args = net.ReadTable()
|
||
|
||
print("Ошибка создания персонажа: " .. fault)
|
||
PrintTable(args)
|
||
|
||
-- Показываем ошибку пользователю
|
||
if IsValid(ix.gui.characterMenu) then
|
||
ix.gui.characterMenu.awaitingResponse = false
|
||
Derma_Message("Ошибка создания персонажа: " .. fault, "Ошибка", "OK")
|
||
end
|
||
end)
|
||
|