Files
2026-03-31 10:27:04 +03:00

554 lines
23 KiB
Lua
Raw Permalink 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
local COLOR_BG_DARK = Color(3, 5, 4)
local COLOR_BG_MEDIUM = Color(8, 12, 10)
local COLOR_BG_LIGHT = Color(12, 18, 14)
local COLOR_PRIMARY = Color(27, 94, 32)
local COLOR_PRIMARY_HOVER = Color(33, 110, 38)
local COLOR_ACCENT = Color(56, 102, 35)
local COLOR_ACCENT_HOVER = Color(66, 120, 45)
local COLOR_BORDER = Color(46, 125, 50, 80)
local COLOR_TEXT_PRIMARY = Color(165, 214, 167)
local COLOR_TEXT_SECONDARY = Color(129, 199, 132)
local COLOR_TEXT_DIM = Color(100, 150, 105)
-- Хук для камеры во время анимации
function PLUGIN:CalcView(ply, pos, angles, fov)
local str = ply:GetNW2String('TauntAnim')
if str != "" then
if GetConVar("rp_taunt_firstperson"):GetBool() then
local eye_id = ply:LookupAttachment('eyes')
local att = eye_id > 0 and ply:GetAttachment(eye_id) or nil
if not att then return end
local ang1 = angles
if GetConVar("rp_taunt_realistic_firstperson"):GetBool() then
ang1 = att.Ang
end
local view = {
origin = att.Pos,
angles = ang1,
fov = fov,
drawviewer = true
}
return view
else
local view = {
origin = pos - (angles:Forward() * 100),
angles = angles,
fov = fov,
drawviewer = true
}
return view
end
end
end
function PLUGIN:ShouldDrawLocalPlayer(ply)
local str = ply:GetNW2String('TauntAnim')
if str != "" and not GetConVar("rp_taunt_firstperson"):GetBool() then
return true
end
end
-- Подсказка на экране
function PLUGIN:HUDPaint()
local ply = LocalPlayer()
local str = ply:GetNW2String('TauntAnim')
if str != "" then
draw.SimpleTextOutlined("Нажмите SHIFT, чтобы убрать анимацию.", "Trebuchet18", ScrW()/2, ScrH()-250, color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER, 1, color_black)
end
end
-- Таблица анимаций (импортируем из существующего аддона)
local AnimationCategories = {
{
name = "ЖЕСТЫ",
anims = {
{id = 1, name = "Помахать руками"},
{id = 2, name = "Помахать рукой"},
{id = 3, name = "Показать пальцем вперед"},
{id = 4, name = "Показать пальцем назад"},
{id = 5, name = "Поправить галстук"},
}
},
{
name = "СПОРТ",
anims = {
{id = 6, name = "Приседания"},
{id = 7, name = "Отжимания"},
{id = 8, name = "Подъем корпуса"},
{id = 9, name = "Берпи"},
}
},
{
name = "ПОЗЫ",
anims = {
{id = 10, name = "Стоять злобно"},
{id = 11, name = "Стоять напуганно"},
{id = 12, name = "Стоять, сложив руки"},
{id = 13, name = "Стоять, руки на поясе"},
{id = 14, name = "Стоять, держась за пояс"},
{id = 15, name = "Сидеть, рука на колене"},
{id = 16, name = "Сидеть в позе лотоса"},
{id = 17, name = "Сидеть в сонном состоянии"},
{id = 18, name = "Лежать в плохом состоянии"},
}
},
{
name = "ТАНЦЫ",
anims = {
{id = 19, name = "Танец 1"},
{id = 20, name = "Танец 2"},
{id = 21, name = "Танец 3"},
{id = 22, name = "Танец 4"},
{id = 33, name = "Танец в присядь"},
}
},
{
name = "ДЕЙСТВИЯ",
anims = {
{id = 23, name = "Согласие"},
{id = 24, name = "Несогласие"},
{id = 25, name = "Позвать с собой"},
{id = 26, name = "Поклониться"},
{id = 27, name = "Отдать честь"},
{id = 28, name = "Пить кофе"},
{id = 29, name = "Смотреть на объект"},
{id = 30, name = "Записывать в блокнот"},
{id = 31, name = "Спать"},
{id = 32, name = "Воинское приветствие"},
}
}
}
local animMenu = nil
local animMenuOpen = false
-- Функция создания меню анимаций
local function CreateAnimationMenu()
if IsValid(animMenu) then
animMenu:Remove()
end
-- Невидимая панель на весь экран для перехвата ввода
local basePanel = vgui.Create("DPanel")
basePanel:SetSize(ScrW(), ScrH())
basePanel:SetPos(0, 0)
basePanel:MakePopup()
basePanel.Paint = function() end -- Полностью прозрачная
-- Меню в правом верхнем углу
local menuWidth = 320
local menuHeight = 500
local padding = 20
local menu = vgui.Create("DPanel", basePanel)
menu:SetSize(menuWidth, menuHeight)
menu:SetPos(ScrW() - menuWidth - padding, padding)
menu.Paint = function(s, w, h)
-- Основной фон
draw.RoundedBox(8, 0, 0, w, h, COLOR_BG_DARK)
-- Заголовок
draw.RoundedBoxEx(8, 0, 0, w, 45, COLOR_BG_MEDIUM, true, true, false, false)
surface.SetDrawColor(COLOR_BORDER)
surface.DrawLine(0, 45, w, 45)
-- Текст заголовка
draw.SimpleText("АНИМАЦИИ", "DermaLarge", w/2, 22, COLOR_TEXT_PRIMARY, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
-- Декоративная линия
surface.SetDrawColor(COLOR_ACCENT)
surface.DrawRect(10, 43, w-20, 2)
-- Внешняя граница
surface.SetDrawColor(COLOR_BORDER)
surface.DrawOutlinedRect(0, 0, w, h, 1)
-- Подсказка внизу
draw.SimpleText("C - Закрыть | SHIFT - Остановить анимацию", "DermaDefault", w/2, h-15, COLOR_TEXT_DIM, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
end
-- Кнопка закрытия
local closeBtn = vgui.Create("DButton", menu)
closeBtn:SetPos(menuWidth - 35, 8)
closeBtn:SetSize(28, 28)
closeBtn:SetText("")
closeBtn.Paint = function(s, w, h)
local col = s:IsHovered() and COLOR_ACCENT_HOVER or COLOR_ACCENT
draw.RoundedBox(4, 0, 0, w, h, col)
draw.SimpleText("×", "DermaLarge", w/2, h/2-2, COLOR_TEXT_PRIMARY, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
end
closeBtn.DoClick = function()
basePanel:Remove()
animMenuOpen = false
end
-- Скролл панель для категорий
local scroll = vgui.Create("DScrollPanel", menu)
scroll:SetPos(10, 55)
scroll:SetSize(menuWidth - 20, menuHeight - 90)
local sbar = scroll:GetVBar()
sbar:SetWide(6)
sbar.Paint = function(s, w, h)
draw.RoundedBox(3, 0, 0, w, h, COLOR_BG_MEDIUM)
end
sbar.btnGrip.Paint = function(s, w, h)
draw.RoundedBox(3, 0, 0, w, h, COLOR_ACCENT)
end
sbar.btnUp.Paint = function() end
sbar.btnDown.Paint = function() end
-- Создаем категории с анимациями
for _, category in ipairs(AnimationCategories) do
-- Заголовок категории
local catHeader = vgui.Create("DPanel", scroll)
catHeader:Dock(TOP)
catHeader:DockMargin(0, 5, 0, 3)
catHeader:SetTall(28)
catHeader.Paint = function(s, w, h)
draw.RoundedBox(4, 0, 0, w, h, COLOR_PRIMARY)
surface.SetDrawColor(COLOR_BORDER)
surface.DrawOutlinedRect(0, 0, w, h, 1)
draw.SimpleText(category.name, "DermaDefaultBold", 10, h/2, COLOR_TEXT_PRIMARY, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER)
end
-- Анимации в категории
for _, anim in ipairs(category.anims) do
local animBtn = vgui.Create("DButton", scroll)
animBtn:Dock(TOP)
animBtn:DockMargin(3, 2, 3, 0)
animBtn:SetTall(32)
animBtn:SetText("")
animBtn.Paint = function(s, w, h)
local col = COLOR_BG_MEDIUM
if s:IsHovered() then
col = COLOR_PRIMARY_HOVER
-- Акцентная линия слева
surface.SetDrawColor(COLOR_ACCENT)
surface.DrawRect(0, 0, 3, h)
end
draw.RoundedBox(4, 0, 0, w, h, col)
surface.SetDrawColor(COLOR_BORDER)
surface.DrawOutlinedRect(0, 0, w, h, 1)
-- Иконка
draw.SimpleText("", "DermaDefault", 12, h/2, COLOR_TEXT_SECONDARY, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
-- Название анимации
draw.SimpleText(anim.name, "DermaDefault", 28, h/2, COLOR_TEXT_PRIMARY, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER)
end
animBtn.DoClick = function()
RunConsoleCommand("rp_set_taunt", tostring(anim.id))
surface.PlaySound("buttons/button15.wav")
basePanel:Remove()
animMenuOpen = false
end
end
end
-- Обработка закрытия по нажатию вне меню
basePanel.OnMousePressed = function(s, keyCode)
if keyCode == MOUSE_LEFT then
-- Проверяем, кликнули ли вне меню
local mx, my = input.GetCursorPos()
local x, y = menu:GetPos()
local w, h = menu:GetSize()
if mx < x or mx > x + w or my < y or my > y + h then
basePanel:Remove()
animMenuOpen = false
end
end
end
-- Меню рации в левом верхнем углу
local radioWidth = 320
local radioHeight = 200
local radioMenu = vgui.Create("DPanel", basePanel)
radioMenu:SetSize(radioWidth, radioHeight)
radioMenu:SetPos(padding, padding)
radioMenu.Paint = function(s, w, h)
-- Основной фон
draw.RoundedBox(8, 0, 0, w, h, COLOR_BG_DARK)
-- Заголовок
draw.RoundedBoxEx(8, 0, 0, w, 45, COLOR_BG_MEDIUM, true, true, false, false)
surface.SetDrawColor(COLOR_BORDER)
surface.DrawLine(0, 45, w, 45)
-- Текст заголовка
draw.SimpleText("ЧАСТОТА РАЦИИ", "DermaLarge", w/2, 22, COLOR_TEXT_PRIMARY, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
-- Декоративная линия
surface.SetDrawColor(COLOR_ACCENT)
surface.DrawRect(10, 43, w-20, 2)
-- Внешняя граница
surface.SetDrawColor(COLOR_BORDER)
surface.DrawOutlinedRect(0, 0, w, h, 1)
end
-- Получаем плагин рации
local radioPlugin = ix.plugin.list["radio"]
if not radioPlugin then
radioMenu:SetVisible(false)
else
local currentFreq = radioPlugin:GetFrequency(LocalPlayer())
-- Текущая частота
local freqLabel = vgui.Create("DLabel", radioMenu)
freqLabel:SetPos(20, 60)
freqLabel:SetSize(radioWidth - 40, 25)
freqLabel:SetText("Текущая частота: " .. string.format("%0." .. radioPlugin.frequencyPrecision .. "f", currentFreq))
freqLabel:SetFont("DermaDefault")
freqLabel:SetTextColor(COLOR_TEXT_PRIMARY)
-- Слайдер частоты
local freqSlider = vgui.Create("DNumSlider", radioMenu)
freqSlider:SetPos(10, 90)
freqSlider:SetSize(radioWidth - 20, 40)
freqSlider:SetText("")
freqSlider:SetMin(radioPlugin.minFrequency)
freqSlider:SetMax(radioPlugin.maxFrequency)
freqSlider:SetDecimals(radioPlugin.frequencyPrecision)
freqSlider:SetValue(currentFreq)
freqSlider.Label:SetTextColor(COLOR_TEXT_SECONDARY)
freqSlider.Label:SetFont("DermaDefault")
freqSlider.TextArea:SetTextColor(COLOR_TEXT_PRIMARY)
freqSlider.TextArea:SetFont("DermaDefault")
freqSlider.TextArea:SetEditable(true)
freqSlider.TextArea:SetNumeric(true)
freqSlider.TextArea.Paint = function(panel, w, h)
draw.RoundedBox(4, 0, 0, w, h, COLOR_BG_MEDIUM)
surface.SetDrawColor(COLOR_BORDER)
surface.DrawOutlinedRect(0, 0, w, h, 1)
panel:DrawTextEntryText(COLOR_TEXT_PRIMARY, COLOR_ACCENT, COLOR_TEXT_PRIMARY)
end
-- Обработчик ввода вручную
freqSlider.TextArea.OnEnter = function(panel)
local val = tonumber(panel:GetValue())
if val then
val = math.Clamp(val, radioPlugin.minFrequency, radioPlugin.maxFrequency)
freqSlider:SetValue(val)
end
end
freqSlider.Slider.Paint = function(panel, w, h)
draw.RoundedBox(4, 0, h/2-2, w, 4, COLOR_BG_MEDIUM)
local progress = (freqSlider:GetValue() - freqSlider:GetMin()) / (freqSlider:GetMax() - freqSlider:GetMin())
draw.RoundedBox(4, 0, h/2-2, w * progress, 4, COLOR_ACCENT)
end
freqSlider.Slider.Knob.Paint = function(s, w, h)
draw.RoundedBox(w/2, 0, 0, w, h, COLOR_PRIMARY)
if s:IsHovered() then
draw.RoundedBox(w/2, 2, 2, w-4, h-4, COLOR_ACCENT_HOVER)
end
end
freqSlider.OnValueChanged = function(_, value)
local format = "%0." .. radioPlugin.frequencyPrecision .. "f"
freqLabel:SetText("Текущая частота: " .. string.format(format, value))
end
-- Кнопка применения
local btnWidth = (radioWidth - 50) / 2
local applyBtn = vgui.Create("DButton", radioMenu)
applyBtn:SetPos(20, 150)
applyBtn:SetSize(btnWidth, 35)
applyBtn:SetText("")
applyBtn.Paint = function(s, w, h)
local col = s:IsHovered() and COLOR_PRIMARY_HOVER or COLOR_PRIMARY
draw.RoundedBox(6, 0, 0, w, h, col)
surface.SetDrawColor(COLOR_BORDER)
surface.DrawOutlinedRect(0, 0, w, h, 2)
draw.SimpleText("ПРИМЕНИТЬ", "DermaDefaultBold", w/2, h/2, COLOR_TEXT_PRIMARY, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
end
applyBtn.DoClick = function()
net.Start("ixRadioSetFrequency")
net.WriteFloat(freqSlider:GetValue())
net.SendToServer()
LocalPlayer():Notify("Частота рации изменена на: " .. string.format("%0." .. radioPlugin.frequencyPrecision .. "f", freqSlider:GetValue()))
end
-- Кнопка ручного ввода
local manualBtn = vgui.Create("DButton", radioMenu)
manualBtn:SetPos(30 + btnWidth, 150)
manualBtn:SetSize(btnWidth, 35)
manualBtn:SetText("")
manualBtn.Paint = function(s, w, h)
local col = s:IsHovered() and COLOR_ACCENT_HOVER or COLOR_ACCENT
draw.RoundedBox(6, 0, 0, w, h, col)
surface.SetDrawColor(COLOR_BORDER)
surface.DrawOutlinedRect(0, 0, w, h, 2)
draw.SimpleText("ВВЕСТИ", "DermaDefaultBold", w/2, h/2, COLOR_TEXT_PRIMARY, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
end
manualBtn.DoClick = function()
Derma_StringRequest(
"Ввод частоты",
"Введите частоту рации (от " .. radioPlugin.minFrequency .. " до " .. radioPlugin.maxFrequency .. "):",
tostring(currentFreq),
function(text)
local freq = tonumber(text)
if freq then
freq = math.Clamp(freq, radioPlugin.minFrequency, radioPlugin.maxFrequency)
net.Start("ixRadioSetFrequency")
net.WriteFloat(freq)
net.SendToServer()
freqSlider:SetValue(freq)
LocalPlayer():Notify("Частота рации изменена на: " .. string.format("%0." .. radioPlugin.frequencyPrecision .. "f", freq))
else
LocalPlayer():Notify("Неверный формат частоты!")
end
end,
function() end
)
end
end
-- Кнопки включения/выключения рации (справа от меню рации)
if radioPlugin then
local controlsWidth = 150
local controlsHeight = 200
local controlsPanel = vgui.Create("DPanel", basePanel)
controlsPanel:SetSize(controlsWidth, controlsHeight)
controlsPanel:SetPos(padding + radioWidth + 10, padding)
controlsPanel.Paint = function(s, w, h)
-- Основной фон
draw.RoundedBox(8, 0, 0, w, h, COLOR_BG_DARK)
-- Заголовок
draw.RoundedBoxEx(8, 0, 0, w, 45, COLOR_BG_MEDIUM, true, true, false, false)
surface.SetDrawColor(COLOR_BORDER)
surface.DrawLine(0, 45, w, 45)
-- Текст заголовка
draw.SimpleText("РАЦИЯ", "DermaDefault", w/2, 22, COLOR_TEXT_PRIMARY, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
-- Декоративная линия
surface.SetDrawColor(COLOR_ACCENT)
surface.DrawRect(10, 43, w-20, 2)
-- Внешняя граница
surface.SetDrawColor(COLOR_BORDER)
surface.DrawOutlinedRect(0, 0, w, h, 1)
end
-- Кнопка включения прослушивания
local listenBtn = vgui.Create("DButton", controlsPanel)
listenBtn:SetPos(10, 60)
listenBtn:SetSize(controlsWidth - 20, 40)
listenBtn:SetText("")
listenBtn.Paint = function(s, w, h)
local isListening = radioPlugin:IsListening(LocalPlayer())
local col = isListening and COLOR_ACCENT or COLOR_BG_MEDIUM
if s:IsHovered() then
col = isListening and COLOR_ACCENT_HOVER or COLOR_PRIMARY_HOVER
end
draw.RoundedBox(6, 0, 0, w, h, col)
surface.SetDrawColor(COLOR_BORDER)
surface.DrawOutlinedRect(0, 0, w, h, 2)
local status = isListening and "ВКЛ" or "ВЫКЛ"
draw.SimpleText("Прослушивание", "DermaDefault", w/2, h/2 - 7, COLOR_TEXT_PRIMARY, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
draw.SimpleText(status, "DermaDefaultBold", w/2, h/2 + 7, COLOR_TEXT_SECONDARY, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
end
listenBtn.DoClick = function()
net.Start("ixRadioToggleListen")
net.SendToServer()
timer.Simple(0.1, function()
local status = radioPlugin:IsListening(LocalPlayer()) and "включено" or "выключено"
LocalPlayer():Notify("Прослушивание рации " .. status)
end)
end
-- Кнопка включения передачи
local transmitBtn = vgui.Create("DButton", controlsPanel)
transmitBtn:SetPos(10, 110)
transmitBtn:SetSize(controlsWidth - 20, 40)
transmitBtn:SetText("")
transmitBtn.Paint = function(s, w, h)
local isTransmitting = radioPlugin:IsTransmitting(LocalPlayer())
local col = isTransmitting and COLOR_ACCENT or COLOR_BG_MEDIUM
if s:IsHovered() then
col = isTransmitting and COLOR_ACCENT_HOVER or COLOR_PRIMARY_HOVER
end
draw.RoundedBox(6, 0, 0, w, h, col)
surface.SetDrawColor(COLOR_BORDER)
surface.DrawOutlinedRect(0, 0, w, h, 2)
local status = isTransmitting and "ВКЛ" or "ВЫКЛ"
draw.SimpleText("Передача", "DermaDefault", w/2, h/2 - 7, COLOR_TEXT_PRIMARY, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
draw.SimpleText(status, "DermaDefaultBold", w/2, h/2 + 7, COLOR_TEXT_SECONDARY, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
end
transmitBtn.DoClick = function()
net.Start("ixRadioToggleTransmit")
net.SendToServer()
timer.Simple(0.1, function()
local status = radioPlugin:IsTransmitting(LocalPlayer()) and "включена" or "выключена"
LocalPlayer():Notify("Передача рации " .. status)
end)
end
end
animMenu = basePanel
animMenuOpen = true
end
-- Блокировка стандартного Context Menu и открытие нашего
hook.Add("OnContextMenuOpen", "AnimationMenuOverride", function()
-- Проверка на Alt+C для администраторов (открывает стандартное меню)
if input.IsKeyDown(KEY_LALT) or input.IsKeyDown(KEY_RALT) then
local client = LocalPlayer()
if IsValid(client) and client:GetCharacter() then
-- Проверка на права администратора
if client:IsAdmin() or client:IsSuperAdmin() then
return -- Пропускаем и открываем стандартное меню
end
end
end
if not animMenuOpen then
CreateAnimationMenu()
end
return false -- Блокируем стандартное меню
end)
-- Закрытие меню при закрытии Context Menu
hook.Add("OnContextMenuClose", "AnimationMenuClose", function()
if animMenuOpen and IsValid(animMenu) then
animMenu:Remove()
animMenuOpen = false
end
end)
-- Подсказка на HUD
--hook.Add("HUDPaint", "AnimationMenuHint", function()
-- if not animMenuOpen then
-- draw.SimpleTextOutlined("C - Открыть меню (анимации + рация)", "DermaDefault", ScrW() - 10, ScrH() - 30, COLOR_TEXT_DIM, TEXT_ALIGN_RIGHT, TEXT_ALIGN_CENTER, 1, Color(0, 0, 0, 200))
-- end
--end)