aa08d47a35
No longer bothering to update cam pos / look angles on model change. Just do it every paint.
333 lines
9.2 KiB
Lua
333 lines
9.2 KiB
Lua
local PANEL = {}
|
|
|
|
local colHealth = Color(0, 0, 0, 240)
|
|
local function ContentsPaint(self)
|
|
local lp = LocalPlayer()
|
|
if lp:IsValid() then
|
|
local health = math.max(lp:Health(), 0)
|
|
local healthperc = math.Clamp(health / lp:GetMaxHealthEx(), 0, 1)
|
|
|
|
colHealth.r = (1 - healthperc) * 180
|
|
colHealth.g = healthperc * 180
|
|
|
|
draw.SimpleTextBlurry(health, "ZSHUDFont", 8, self:GetTall() - 8, colHealth, TEXT_ALIGN_LEFT, TEXT_ALIGN_TOP)
|
|
end
|
|
end
|
|
|
|
function PANEL:Init()
|
|
self:DockMargin(0, 0, 0, 0)
|
|
self:DockPadding(0, 0, 0, 0)
|
|
|
|
self.HealthModel = vgui.Create("ZSHealthModelPanel", self)
|
|
self.HealthModel:Dock(LEFT)
|
|
|
|
local contents = vgui.Create("Panel", self)
|
|
contents:Dock(FILL)
|
|
contents.Paint = ContentsPaint
|
|
|
|
local poisonstatus = vgui.Create("ZSHealthStatus", contents)
|
|
poisonstatus:SetTall(20)
|
|
poisonstatus:SetAlpha(200)
|
|
poisonstatus:SetColor(Color(180, 180, 0))
|
|
poisonstatus:SetMemberName("POISON!")
|
|
poisonstatus.GetMemberValue = function(me)
|
|
local lp = LocalPlayer()
|
|
if lp:IsValid() then
|
|
return lp:GetPoisonDamage()
|
|
end
|
|
|
|
return 0
|
|
end
|
|
poisonstatus.MemberMaxValue = 50
|
|
poisonstatus:Dock(TOP)
|
|
|
|
local bleedstatus = vgui.Create("ZSHealthStatus", contents)
|
|
bleedstatus:SetTall(20)
|
|
bleedstatus:SetAlpha(200)
|
|
bleedstatus:SetColor(Color(220, 0, 0))
|
|
bleedstatus:SetMemberName("BLEED!")
|
|
bleedstatus.GetMemberValue = function(me)
|
|
local lp = LocalPlayer()
|
|
if lp:IsValid() then
|
|
return lp:GetBleedDamage()
|
|
end
|
|
|
|
return 0
|
|
end
|
|
bleedstatus.MemberMaxValue = 20
|
|
bleedstatus:Dock(TOP)
|
|
|
|
local ghoultouchstatus = vgui.Create("ZSHealthStatus", contents)
|
|
ghoultouchstatus:SetTall(20)
|
|
ghoultouchstatus:SetAlpha(200)
|
|
ghoultouchstatus:SetColor(Color(255, 0, 0))
|
|
ghoultouchstatus:SetMemberName("GHOUL TOUCH!")
|
|
ghoultouchstatus.GetMemberValue = function(me)
|
|
local lp = LocalPlayer()
|
|
if lp:IsValid() then
|
|
local status = lp:GetStatus("ghoultouch")
|
|
if status and status:IsValid() then
|
|
return math.max(status.DieTime - CurTime(), 0)
|
|
end
|
|
end
|
|
|
|
return 0
|
|
end
|
|
ghoultouchstatus.MemberMaxValue = 10
|
|
ghoultouchstatus:Dock(TOP)
|
|
|
|
self:ParentToHUD()
|
|
self:InvalidateLayout()
|
|
end
|
|
|
|
function PANEL:PerformLayout()
|
|
local screenscale = BetterScreenScale()
|
|
|
|
self:SetSize(screenscale * 350, screenscale * 128)
|
|
|
|
self.HealthModel:SetWide(self:GetTall())
|
|
|
|
self:AlignLeft(screenscale * 24)
|
|
self:AlignBottom(screenscale * 24)
|
|
end
|
|
|
|
function PANEL:Paint()
|
|
end
|
|
|
|
vgui.Register("ZSHealthArea", PANEL, "Panel")
|
|
|
|
local PANEL = {}
|
|
|
|
PANEL.ModelLow = 0
|
|
PANEL.ModelHigh = 72
|
|
PANEL.Health = 100
|
|
PANEL.BarricadeGhosting = 0
|
|
|
|
function PANEL:Init()
|
|
self:SetAnimSpeed(0)
|
|
self:SetFOV(55)
|
|
end
|
|
|
|
local function LowestAndHighest(ent)
|
|
local lowest
|
|
local highest
|
|
|
|
local basepos = ent:GetPos()
|
|
for i=0, ent:GetBoneCount() - 1 do
|
|
local bonepos, boneang = ent:GetBonePosition(i)
|
|
if bonepos and bonepos ~= basepos then
|
|
if lowest == nil then
|
|
lowest = bonepos.z
|
|
highest = bonepos.z
|
|
else
|
|
lowest = math.min(lowest, bonepos.z)
|
|
highest = math.max(highest, bonepos.z)
|
|
end
|
|
end
|
|
end
|
|
|
|
highest = (highest or 1) + ent:GetModelScale() * 8
|
|
|
|
return lowest or 0, highest
|
|
end
|
|
|
|
function PANEL:Think()
|
|
local lp = LocalPlayer()
|
|
if lp:IsValid() then
|
|
self.Health = math.Clamp(lp:Health() / lp:GetMaxHealthEx(), 0, 1)
|
|
self.BarricadeGhosting = math.Approach(self.BarricadeGhosting, lp:IsBarricadeGhosting() and 1 or 0, FrameTime() * 5)
|
|
|
|
local model = lp:GetModel()
|
|
local ent = self.Entity
|
|
if not ent or not ent:IsValid() or model ~= ent:GetModel() then
|
|
if IsValid(self.OverrideEntity) then
|
|
self.OverrideEntity:Remove()
|
|
self.OverrideEntity = nil
|
|
end
|
|
|
|
self:SetModel(model)
|
|
end
|
|
|
|
local overridemodel = lp.status_overridemodel
|
|
if overridemodel and overridemodel:IsValid() then
|
|
if IsValid(self.Entity) and not IsValid(self.OverrideEntity) then
|
|
self.OverrideEntity = ClientsideModel(overridemodel:GetModel(), RENDER_GROUP_OPAQUE_ENTITY)
|
|
if IsValid(self.OverrideEntity) then
|
|
self.OverrideEntity:SetPos(self.Entity:GetPos())
|
|
self.OverrideEntity:SetParent(self.Entity)
|
|
self.OverrideEntity:AddEffects(bit.bor(EF_BONEMERGE, EF_BONEMERGE_FASTCULL))
|
|
self.OverrideEntity:SetNoDraw(true)
|
|
end
|
|
end
|
|
elseif self.OverrideEntity and self.OverrideEntity:IsValid() then
|
|
self.OverrideEntity:Remove()
|
|
self.OverrideEntity = nil
|
|
end
|
|
|
|
ent = self.Entity
|
|
if ent and ent:IsValid() then
|
|
ent:SetSequence(lp:GetSequence())
|
|
|
|
ent:SetPoseParameter("move_x", lp:GetPoseParameter("move_x") * 2 - 1)
|
|
ent:SetPoseParameter("move_y", lp:GetPoseParameter("move_y") * 2 - 1)
|
|
ent:SetCycle(lp:GetCycle())
|
|
|
|
local modellow, modelhigh = LowestAndHighest(ent)
|
|
self.ModelLow = math.Approach(self.ModelLow, modellow, FrameTime() * 256)
|
|
self.ModelHigh = math.Approach(self.ModelHigh, modelhigh, FrameTime() * 256)
|
|
self.ModelHigh = math.max(self.ModelLow + 1, self.ModelHigh)
|
|
end
|
|
end
|
|
end
|
|
|
|
function PANEL:OnRemove()
|
|
if IsValid(self.Entity) then
|
|
self.Entity:Remove()
|
|
end
|
|
if IsValid(self.OverrideEntity) then
|
|
self.OverrideEntity:Remove()
|
|
end
|
|
end
|
|
|
|
local matWhite = Material("models/debug/debugwhite")
|
|
local matGlow = Material("sprites/glow04_noz")
|
|
local matShadow = CreateMaterial("zshealthhudshadow", "UnlitGeneric", {["$basetexture"] = "decals/simpleshadow", ["$vertexalpha"] = "1", ["$vertexcolor"] = "1"})
|
|
local colShadow = Color(20, 20, 20, 230)
|
|
function PANEL:Paint()
|
|
local ent = self.OverrideEntity or self.Entity
|
|
if not ent or not ent:IsValid() then return end
|
|
|
|
local lp = LocalPlayer()
|
|
if not lp:IsValid() then return end
|
|
|
|
local x, y = self:LocalToScreen(0, 0)
|
|
local w, h = self:GetSize()
|
|
local health = self.Health
|
|
local entpos = ent:GetPos()
|
|
local mins, maxs = lp:OBBMins(), lp:OBBMaxs()
|
|
maxs.z = maxs.x * 4.5
|
|
local campos = mins:Distance(maxs) * Vector(0, -0.9, 0.4)
|
|
local lookat = (mins + maxs) / 2
|
|
local ang = (lookat - campos):Angle()
|
|
local modelscale = lp:GetModelScale()
|
|
if ent:GetModelScale() ~= modelscale then
|
|
ent:SetModelScale(modelscale, 0)
|
|
end
|
|
|
|
self:LayoutEntity(ent)
|
|
|
|
render.ModelMaterialOverride(matWhite)
|
|
render.SuppressEngineLighting(true)
|
|
cam.IgnoreZ(true)
|
|
|
|
cam.Start3D(campos - ang:Forward() * 16, ang, self.fFOV * 0.75, x, y, w, h, 5, 4096)
|
|
render.OverrideDepthEnable(true, false)
|
|
render.SetColorModulation(0, 0, self.BarricadeGhosting)
|
|
ent:DrawModel()
|
|
render.OverrideDepthEnable(false)
|
|
cam.End3D()
|
|
|
|
cam.Start3D(campos, ang, self.fFOV, x, y, w, h, 5, 4096)
|
|
|
|
render.SetMaterial(matShadow)
|
|
render.DrawQuadEasy(entpos, Vector(0, 0, 1), 45, 90, colShadow)
|
|
|
|
render.SetLightingOrigin(entpos)
|
|
render.ResetModelLighting(0.2, 0.2, 0.2)
|
|
render.SetModelLighting(BOX_FRONT, 0.8, 0.8, 0.8)
|
|
render.SetModelLighting(BOX_TOP, 0.8, 0.8, 0.8)
|
|
|
|
if health == 1 then
|
|
render.SetColorModulation(0, 0.6, 0)
|
|
ent:DrawModel()
|
|
elseif health == 0 then
|
|
render.SetColorModulation(0, 0, 0)
|
|
ent:DrawModel()
|
|
else
|
|
local normal = Vector(0, 0, 1)
|
|
local pos = entpos + Vector(0, 0, self.ModelLow * (1 - health) + self.ModelHigh * health)
|
|
|
|
render.EnableClipping(true)
|
|
|
|
render.PushCustomClipPlane(normal, normal:Dot(pos))
|
|
render.SetColorModulation(health > 0.5 and 0.6 or (0.7 + math.sin(CurTime() * math.pi * 2) * 0.2), 0, 0)
|
|
ent:DrawModel()
|
|
render.PopCustomClipPlane()
|
|
|
|
normal = normal * -1
|
|
render.PushCustomClipPlane(normal, normal:Dot(pos))
|
|
render.SetColorModulation(0, 0.6, 0)
|
|
ent:DrawModel()
|
|
render.PopCustomClipPlane()
|
|
|
|
render.EnableClipping(false)
|
|
end
|
|
|
|
cam.End3D()
|
|
|
|
render.ModelMaterialOverride()
|
|
render.SuppressEngineLighting(false)
|
|
render.SetColorModulation(1, 1, 1)
|
|
cam.IgnoreZ(false)
|
|
end
|
|
|
|
function PANEL:LayoutEntity(ent)
|
|
self:RunAnimation()
|
|
end
|
|
|
|
vgui.Register("ZSHealthModelPanel", PANEL, "DModelPanel")
|
|
|
|
local PANEL = {}
|
|
|
|
PANEL.MemberValue = 0
|
|
PANEL.LerpMemberValue = 0
|
|
PANEL.MemberMaxValue = 100
|
|
PANEL.MemberName = "Unnamed"
|
|
|
|
function PANEL:SetColor(col) self.m_Color = col end
|
|
function PANEL:GetColor() return self.m_Color end
|
|
function PANEL:SetMemberName(n) self.MemberName = n end
|
|
function PANEL:GetMemberName() return self.MemberName end
|
|
|
|
function PANEL:Init()
|
|
self:SetColor(Color(255, 255, 255))
|
|
end
|
|
|
|
function PANEL:Think()
|
|
if self.GetMemberValue then
|
|
self.MemberValue = self:GetMemberValue() or self.MemberValue
|
|
end
|
|
if self.GetMemberMaxValue then
|
|
self.MemberMaxValue = self:GetMemberMaxValue() or self.MemberMaxValue
|
|
end
|
|
|
|
if self.MemberValue > self.LerpMemberValue then
|
|
self.LerpMemberValue = self.MemberValue
|
|
elseif self.MemberValue < self.LerpMemberValue then
|
|
self.LerpMemberValue = math.Approach(self.LerpMemberValue, self.MemberValue, FrameTime() * 10)
|
|
end
|
|
end
|
|
|
|
function PANEL:Paint()
|
|
local value = self.LerpMemberValue
|
|
if value <= 0 then return end
|
|
|
|
local col = self:GetColor()
|
|
local max = self.MemberMaxValue
|
|
local w, h = self:GetSize()
|
|
|
|
surface.SetDrawColor(0, 0, 0, 255)
|
|
surface.DrawRect(0, 0, w, h)
|
|
|
|
surface.SetDrawColor(col)
|
|
surface.DrawOutlinedRect(0, 0, w, h)
|
|
surface.DrawRect(3, 3, (w - 6) * math.Clamp(value / max, 0, 1), h - 6)
|
|
|
|
local t1 = math.ceil(value)
|
|
draw.SimpleText(t1, "ZSHUDFontTinyNS", w - 3, h / 2 + 1, color_black, TEXT_ALIGN_RIGHT, TEXT_ALIGN_CENTER)
|
|
draw.SimpleText(t1, "ZSHUDFontTinyNS", w - 4, h / 2, color_white, TEXT_ALIGN_RIGHT, TEXT_ALIGN_CENTER)
|
|
draw.SimpleText(self.MemberName, "ZSHUDFontTinyNS", 5, h / 2 + 1, color_black, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER)
|
|
draw.SimpleText(self.MemberName, "ZSHUDFontTinyNS", 4, h / 2, color_white, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER)
|
|
end
|
|
|
|
vgui.Register("ZSHealthStatus", PANEL, "Panel")
|