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

493 lines
17 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.
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