surface.CreateFont("MilitaryHUD_Small", { font = "Montserrat", size = 16, weight = 400 }) surface.CreateFont("MilitaryHUD_SmallBold", { font = "Montserrat", size = 16, weight = 500 }) surface.CreateFont("MilitaryHUD_Medium", { font = "Montserrat", size = 18, weight = 400 }) surface.CreateFont("MilitaryHUD_MediumBold", { font = "Montserrat", size = 18, weight = 500 }) surface.CreateFont("MilitaryHUD_Large", { font = "Montserrat", size = 28, weight = 500 }) local Colors = { white = Color(255, 255, 255), white_half = Color(255, 255, 255, 128), green = Color(84, 147, 90), dark_green = Color(52, 91, 60), darker_green = Color(35, 53, 29), gray = Color(193, 193, 193), gray_dark = Color(94, 94, 94), gray_light = Color(213, 213, 213) } local PLUGIN = PLUGIN -- Масштабирование HUD function GetScale() local scale = ScrH() / 1080 return math.Clamp(scale, 0.5, 2.0) end function ScaleSize(val) return math.max(1, math.Round(val * GetScale())) end function ScalePos(val) return math.Round(val * GetScale()) end Colors = { white = Color(255, 255, 255), white_half = Color(255, 255, 255, 128), green = Color(84, 147, 90), dark_green = Color(52, 91, 60), darker_green = Color(35, 53, 29), gray = Color(193, 193, 193), gray_dark = Color(94, 94, 94), gray_light = Color(213, 213, 213), overlay = Color(0, 0, 0, 180) } local cachedScale = 0 function CreateHUDFonts() local currentScale = GetScale() if math.abs(currentScale - cachedScale) < 0.01 then return end cachedScale = currentScale surface.CreateFont("MilitaryHUD_Small", { font = "Montserrat", size = ScaleSize(16), weight = 400 }) surface.CreateFont("MilitaryHUD_SmallBold", { font = "Montserrat", size = ScaleSize(16), weight = 500 }) surface.CreateFont("MilitaryHUD_Medium", { font = "Montserrat", size = ScaleSize(18), weight = 400 }) surface.CreateFont("MilitaryHUD_MediumBold", { font = "Montserrat", size = ScaleSize(18), weight = 500 }) surface.CreateFont("MilitaryHUD_Large", { font = "Montserrat", size = ScaleSize(28), weight = 500 }) end CreateHUDFonts() hook.Add("OnScreenSizeChanged", "MilitaryHUD_UpdateFonts", CreateHUDFonts) local healthLerp = 100 local armorLerp = 100 local ammoLerp = 30 local hungerLerp = 100 local thirstLerp = 100 local staminaLerp = 100 -- Материалы (пути будут заполнены позже) local logoMaterial = Material("materials/ft_ui/military/vnu/hud/logo.png") local radioMaterial = Material("materials/ft_ui/military/vnu/hud/radio.png") local clockMaterial = Material("materials/ft_ui/military/vnu/hud/cloak.png") local rankMaterial = Material("materials/ft_ui/military/vnu/hud/rank.png") local foodMaterial = Material("materials/ft_ui/military/vnu/hud/food.png") local thirstMaterial = Material("materials/ft_ui/military/vnu/hud/thirst.png") function PLUGIN:GetRadioStatus() if ix.plugin and ix.plugin.list and ix.plugin.list["radio"] then return ix.plugin.list["radio"]:IsListening(LocalPlayer()) end return false end function PLUGIN:GetFormattedTime() if StormFox2 and StormFox2.Time then local hours = StormFox2.Time.GetHours() or 12 local minutes = StormFox2.Time.GetMinutes() or 0 local seconds = StormFox2.Time.GetSeconds() or 0 return string.format("%02d:%02d:%02d", hours, minutes, seconds) else -- Fallback на системное время return os.date("%H:%M:%S") end end function PLUGIN:LerpColor(progress, color1, color2) return Color( Lerp(progress, color1.r, color2.r), Lerp(progress, color1.g, color2.g), Lerp(progress, color1.b, color2.b), Lerp(progress, color1.a, color2.a) ) end function PLUGIN:DrawHealthBar(x, y, w, h) local health = LocalPlayer():Health() healthLerp = Lerp(FrameTime() * 5, healthLerp, health) local healthPercent = math.Clamp(healthLerp / 100, 0, 1) draw.SimpleText("Здоровье", "MilitaryHUD_Small", x, y - ScalePos(25), Colors.white_half, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER) draw.SimpleText(math.Round(healthLerp), "MilitaryHUD_SmallBold", x + w, y - ScalePos(25), Colors.white, TEXT_ALIGN_RIGHT, TEXT_ALIGN_CENTER) local barWidth = w * healthPercent surface.SetDrawColor(Colors.gray) surface.DrawRect(x, y, w, h) for i = 0, barWidth - 1 do local progress = i / w local color = self:LerpColor(progress, Colors.darker_green, Colors.dark_green) surface.SetDrawColor(color) surface.DrawRect(x + i, y, 1, h) end local segmentWidth = w / 3 for i = 1, 2 do surface.SetDrawColor(Color(0, 0, 0, 100)) surface.DrawRect(x + segmentWidth * i, y, 1, h) end end function PLUGIN:DrawArmorBar(x, y, w, h) local armor = LocalPlayer():Armor() armorLerp = Lerp(FrameTime() * 5, armorLerp, armor) local armorPercent = math.Clamp(armorLerp / 100, 0, 1) draw.SimpleText("Броня", "MilitaryHUD_Small", x, y - ScalePos(25), Colors.white_half, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER) draw.SimpleText(math.Round(armorLerp), "MilitaryHUD_SmallBold", x + w, y - ScalePos(25), Colors.white, TEXT_ALIGN_RIGHT, TEXT_ALIGN_CENTER) local barWidth = w * armorPercent surface.SetDrawColor(Colors.gray) surface.DrawRect(x, y, w, h) for i = 0, barWidth - 1 do local progress = i / w local color = self:LerpColor(progress, Colors.darker_green, Colors.dark_green) surface.SetDrawColor(color) surface.DrawRect(x + i, y, 1, h) end local segmentWidth = w / 3 for i = 1, 2 do surface.SetDrawColor(Color(0, 0, 0, 100)) surface.DrawRect(x + segmentWidth * i, y, 1, h) end end function PLUGIN:DrawStaminaBar(x, y, w, h) local stamina = LocalPlayer():GetLocalVar("stm", 100) staminaLerp = Lerp(FrameTime() * 5, staminaLerp, stamina) local staminaPercent = math.Clamp(staminaLerp / 100, 0, 1) draw.SimpleText("Выносливость", "MilitaryHUD_Small", x, y - ScalePos(25), Colors.white_half, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER) draw.SimpleText(math.Round(staminaLerp), "MilitaryHUD_SmallBold", x + w, y - ScalePos(25), Colors.white, TEXT_ALIGN_RIGHT, TEXT_ALIGN_CENTER) local barWidth = w * staminaPercent surface.SetDrawColor(Colors.gray) surface.DrawRect(x, y, w, h) local staminaColor = Color(0, 67, 28) -- #00431c local staminaColorDark = Color(0, 30, 10) for i = 0, barWidth - 1 do local progress = i / w local color = self:LerpColor(progress, staminaColorDark, staminaColor) surface.SetDrawColor(color) surface.DrawRect(x + i, y, 1, h) end local segmentWidth = w / 3 for i = 1, 2 do surface.SetDrawColor(Color(0, 0, 0, 100)) surface.DrawRect(x + segmentWidth * i, y, 1, h) end end function PLUGIN:DrawRankInfo(x, y, w, h) local iconSize = ScaleSize(32) if rankMaterial then surface.SetMaterial(rankMaterial) surface.SetDrawColor(Colors.white) surface.DrawTexturedRect(x, y, iconSize, iconSize) else surface.SetDrawColor(Colors.gray_light) surface.DrawRect(x, y, iconSize, iconSize) draw.SimpleText("R", "MilitaryHUD_Medium", x + iconSize/2, y + iconSize/2, Colors.gray_dark, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER) end draw.SimpleText(LocalPlayer():GetSpecName(), "MilitaryHUD_SmallBold", x + iconSize + ScalePos(10), y + iconSize/2, Colors.white, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER) end function PLUGIN:DrawHungerIndicator(x, y) local hunger = LocalPlayer():GetLocalVar("hunger", 100) hungerLerp = Lerp(FrameTime() * 5, hungerLerp, hunger) -- Иконка голода local iconSize = ScaleSize(24) if foodMaterial then surface.SetMaterial(foodMaterial) surface.SetDrawColor(255, 255, 255, 255) surface.DrawTexturedRect(x, y, iconSize, iconSize) else surface.SetDrawColor(Color(205, 133, 63)) surface.DrawRect(x, y, iconSize, iconSize) end -- Значение local hungerColor = hungerLerp > 50 and Colors.white or Color(200, 50, 50) draw.SimpleText(math.Round(hungerLerp) .. "%", "MilitaryHUD_SmallBold", x + iconSize + ScalePos(5), y + iconSize/2, hungerColor, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER) end function PLUGIN:DrawThirstIndicator(x, y) local thirst = LocalPlayer():GetLocalVar("thirst", 100) thirstLerp = Lerp(FrameTime() * 5, thirstLerp, thirst) -- Иконка жажды local iconSize = ScaleSize(24) if thirstMaterial then surface.SetMaterial(thirstMaterial) surface.SetDrawColor(255, 255, 255, 255) surface.DrawTexturedRect(x, y, iconSize, iconSize) else surface.SetDrawColor(Color(30, 144, 255)) surface.DrawRect(x, y, iconSize, iconSize) end -- Значение local thirstColor = thirstLerp > 50 and Colors.white or Color(200, 50, 50) draw.SimpleText(math.Round(thirstLerp) .. "%", "MilitaryHUD_SmallBold", x + iconSize + ScalePos(5), y + iconSize/2, thirstColor, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER) end function PLUGIN:DrawRadio() local x, y = ScalePos(40), ScalePos(240) local iconSize = ScaleSize(32) local radioStatus = self:GetRadioStatus() if radioMaterial then surface.SetMaterial(radioMaterial) surface.SetDrawColor(Colors.white) surface.DrawTexturedRect(x, y, iconSize, iconSize) else surface.SetDrawColor(Colors.gray_light) surface.DrawRect(x, y, iconSize, iconSize) draw.SimpleText("R", "MilitaryHUD_Medium", x + iconSize/2, y + iconSize/2, Colors.gray_dark, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER) end local radioText = radioStatus and "Включена" or "Выключена" local radioColor = radioStatus and Colors.green or Color(200, 50, 50) draw.SimpleText("Рация:", "MilitaryHUD_MediumBold", x + iconSize + ScalePos(10), y + ScalePos(11), Colors.white, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER) draw.SimpleText(radioText, "MilitaryHUD_MediumBold", x + iconSize + ScalePos(78), y + ScalePos(11), radioColor, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER) end function PLUGIN:DrawTime() local x, y = ScalePos(40), ScalePos(290) local iconSize = ScaleSize(32) local timeText = self:GetFormattedTime() if clockMaterial then surface.SetMaterial(clockMaterial) surface.SetDrawColor(Colors.white) surface.DrawTexturedRect(x, y, iconSize, iconSize) else surface.SetDrawColor(Colors.gray_light) surface.DrawRect(x, y, iconSize, iconSize) draw.SimpleText("T", "MilitaryHUD_Medium", x + iconSize/2, y + iconSize/2, Colors.gray_dark, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER) end draw.SimpleText(timeText, "MilitaryHUD_MediumBold", x + iconSize + ScalePos(10), y + iconSize/2, Color(255, 255, 255, 165), TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER) end function PLUGIN:DrawLogo() local x, y = ScalePos(20), ScalePos(39) local logoWidth, logoHeight = ScaleSize(128), ScaleSize(72) if logoMaterial then surface.SetMaterial(logoMaterial) surface.SetDrawColor(Colors.white) surface.DrawTexturedRect(x, y, logoWidth, logoHeight) else surface.SetDrawColor(Colors.dark_green) surface.DrawRect(x, y, logoWidth/2, logoHeight) draw.SimpleText("ЛОГО", "MilitaryHUD_Small", x + logoWidth/4, y + logoHeight/2, Colors.white, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER) end --draw.SimpleText("Война на Украине", "MilitaryHUD_MediumBold", x + ScalePos(120), y + ScalePos(35), Colors.white, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER) end function PLUGIN:DrawAmmoInfo() local weapon = LocalPlayer():GetActiveWeapon() if not IsValid(weapon) then return end local clip = weapon:Clip1() local ammoType = weapon:GetPrimaryAmmoType() local reserve = LocalPlayer():GetAmmoCount(ammoType) -- Пропускаем оружие без патронов (например, руки, граната) if clip < 0 and (ammoType == -1 or reserve == 0) then return end local x, y = ScrW() - ScalePos(90), ScrH() - ScalePos(50) -- Отображаем патроны в обойме if clip >= 0 then draw.SimpleText(clip, "MilitaryHUD_Large", x, y, Colors.white, TEXT_ALIGN_RIGHT, TEXT_ALIGN_CENTER) -- Разделитель draw.SimpleText("/", "MilitaryHUD_Medium", x + ScalePos(10), y, Colors.white_half, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER) -- Запасные патроны draw.SimpleText(reserve, "MilitaryHUD_Medium", x + ScalePos(30), y, Colors.white_half, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER) else -- Если нет обоймы (например, РПГ), показываем только запас draw.SimpleText(reserve, "MilitaryHUD_Large", x, y, Colors.white, TEXT_ALIGN_RIGHT, TEXT_ALIGN_CENTER) end -- Название оружия local weaponName = weapon:GetPrintName() or weapon:GetClass() draw.SimpleText(weaponName, "MilitaryHUD_Small", x + ScalePos(15), y - ScalePos(30), Colors.white_half, TEXT_ALIGN_RIGHT, TEXT_ALIGN_CENTER) end function PLUGIN:DrawPlayerInfo() local x, y = ScalePos(40), ScrH() - ScalePos(210) local infoWidth = ScaleSize(420) -- Индикаторы голода и жажды НАД здоровьем self:DrawHungerIndicator(x, y - ScalePos(35)) self:DrawThirstIndicator(x + ScalePos(100), y - ScalePos(35)) -- Полоски здоровья, брони и выносливости self:DrawHealthBar(x, y + ScalePos(22), infoWidth, ScaleSize(12)) self:DrawArmorBar(x, y + ScalePos(74), infoWidth, ScaleSize(12)) self:DrawStaminaBar(x, y + ScalePos(126), infoWidth, ScaleSize(12)) -- Информация о ранге self:DrawRankInfo(x, y + ScalePos(152), ScaleSize(223), ScaleSize(32)) end function PLUGIN:HUDPaint() local lp = LocalPlayer() if (!lp:GetCharacter() or !lp:Alive() or ix.option.Get("disablehud", false)) then return end CreateHUDFonts() self:DrawPlayerInfo() self:DrawAmmoInfo() self:DrawRadio() self:DrawTime() self:DrawLogo() end function PLUGIN:PostDrawTranslucentRenderables() local target = self:GetLookTarget() if IsValid(target) then self:DrawTargetPlayerInfo(target) end end -- Шрифты для информации о цели surface.CreateFont("TargetInfo_Name", { font = "Montserrat", size = 38, weight = 600 }) surface.CreateFont("TargetInfo_Detail", { font = "Montserrat", size = 30, weight = 400 }) surface.CreateFont("TargetInfo_Rank", { font = "Montserrat", size = 26, weight = 500 }) -- Получение цели function PLUGIN:GetLookTarget() local trace = LocalPlayer():GetEyeTrace() if not trace.Hit then return nil end if not IsValid(trace.Entity) then return nil end if not trace.Entity:IsPlayer() then return nil end if trace.Entity == LocalPlayer() then return nil end if trace.Entity:Team() != LocalPlayer():Team() then return nil end local distance = LocalPlayer():GetPos():Distance(trace.Entity:GetPos()) if distance > 250 then return nil end return trace.Entity end -- Отрисовка информации о цели function PLUGIN:DrawTargetPlayerInfo() -- Проверка настройки if ix.option.Get("disableplayerinfo", false) then return end local target = self:GetLookTarget() if not target then return end local char = target:GetCharacter() if not char then return end -- Получаем данные local name = target:Name() local podrName = target:GetPodrName() if not podrName or podrName == false then podrName = "Неизвестно" end local specName = target:GetSpecName() if not specName or specName == false then specName = "Неизвестно" end local rankName = target:GetRankName() if not rankName or rankName == false then rankName = "Неизвестно" end -- Позиция 3D2D над головой local pos = target:GetPos() + Vector(0, 0, 85) -- Угол всегда смотрит на игрока local ang = Angle(0, LocalPlayer():EyeAngles().y - 90, 90) -- Масштаб для 3D2D local scale = 0.1 cam.Start3D2D(pos, ang, scale) -- Настройки текста local lineHeight = 42 local yOffset = 0 -- Имя (крупно, по центру) draw.SimpleText(name, "TargetInfo_Name", 0, yOffset, Color(0, 146, 12), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER) yOffset = yOffset + lineHeight if podrName and podrName != "Новоприбывшие" then local unitText = podrName .. " | " .. specName draw.SimpleText(unitText, "TargetInfo_Detail", 0, yOffset, Color(0, 146, 12), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER) yOffset = yOffset + lineHeight -- Звание draw.SimpleText(rankName, "TargetInfo_Rank", 0, yOffset, Color(0, 146, 12), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER) else draw.SimpleText(rankName, "TargetInfo_Rank", 0, yOffset, Color(0, 146, 12), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER) end cam.End3D2D() end