-- Цветовая схема (в стиле остальных интерфейсов) 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)