zombiesurvival-evolved/gamemodes/zombiesurvival/gamemode/cl_init.lua
2019-03-18 18:30:04 -04:00

2246 lines
74 KiB
Lua

-- Sometimes persistent ones don't get created.
local dummy = CreateClientConVar("_zs_dummyconvar", 1, false, false)
local oldCreateClientConVar = CreateClientConVar
function CreateClientConVar(...)
return oldCreateClientConVar(...) or dummy
end
include("sh_globals.lua")
include("obj_entity_extend_cl.lua")
include("obj_player_extend_cl.lua")
include("obj_weapon_extend_cl.lua")
include("loader.lua")
include("shared.lua")
include("cl_draw.lua")
include("cl_util.lua")
include("cl_options.lua")
include("cl_scoreboard.lua")
include("cl_targetid.lua")
include("cl_postprocess.lua")
include("cl_voicesets.lua")
include("cl_net.lua")
include("skillweb/cl_skillweb.lua")
include("vgui/dteamcounter.lua")
include("vgui/dmodelpanelex.lua")
include("vgui/dammocounter.lua")
include("vgui/dteamheading.lua")
include("vgui/dmodelkillicon.lua")
include("vgui/dexroundedpanel.lua")
include("vgui/dexroundedframe.lua")
include("vgui/dexrotatedimage.lua")
include("vgui/dexnotificationslist.lua")
include("vgui/dexchanginglabel.lua")
include("vgui/mainmenu.lua")
include("vgui/pmainmenu.lua")
include("vgui/poptions.lua")
include("vgui/phelp.lua")
include("vgui/pclassselect.lua")
include("vgui/pweapons.lua")
include("vgui/pendboard.lua")
include("vgui/pworth.lua")
include("vgui/parsenal.lua")
include("vgui/premantle.lua")
include("vgui/dpingmeter.lua")
include("vgui/dsidemenu.lua")
include("vgui/dspawnmenu.lua")
include("vgui/zsgamestate.lua")
include("vgui/zshealtharea.lua")
include("vgui/zsstatusarea.lua")
include("cl_dermaskin.lua")
include("cl_deathnotice.lua")
include("cl_floatingscore.lua")
include("cl_hint.lua")
include("cl_thirdperson.lua")
include("itemstocks/cl_stock.lua")
include("cl_zombieescape.lua")
w, h = ScrW(), ScrH()
MySelf = MySelf or NULL
hook.Add("InitPostEntity", "GetLocal", function()
MySelf = LocalPlayer()
GAMEMODE.HookGetLocal = GAMEMODE.HookGetLocal or function(g) end
gamemode.Call("HookGetLocal", MySelf)
RunConsoleCommand("initpostentity")
MySelf:ApplySkills()
end)
-- Remove when model decal crash is fixed.
--[[function util.Decal()
end]]
-- Save on global lookup time.
local collectgarbage = collectgarbage
local render = render
local surface = surface
local draw = draw
local cam = cam
local player = player
local ents = ents
local util = util
local math = math
local string = string
local bit = bit
local gamemode = gamemode
local hook = hook
local Vector = Vector
local VectorRand = VectorRand
local Angle = Angle
local AngleRand = AngleRand
local Entity = Entity
local Color = Color
local FrameTime = FrameTime
local RealTime = RealTime
local CurTime = CurTime
local SysTime = SysTime
local EyePos = EyePos
local EyeAngles = EyeAngles
local pairs = pairs
local ipairs = ipairs
local tostring = tostring
local tonumber = tonumber
local type = type
local ScrW = ScrW
local ScrH = ScrH
local Lerp = Lerp
local EF_DIMLIGHT = EF_DIMLIGHT
local TEXT_ALIGN_CENTER = TEXT_ALIGN_CENTER
local TEXT_ALIGN_LEFT = TEXT_ALIGN_LEFT
local TEXT_ALIGN_RIGHT = TEXT_ALIGN_RIGHT
local TEXT_ALIGN_TOP = TEXT_ALIGN_TOP
local TEXT_ALIGN_BOTTOM = TEXT_ALIGN_BOTTOM
local TEXT_ALIGN_TOP_REAL = TEXT_ALIGN_TOP_REAL
local TEXT_ALIGN_BOTTOM_REAL = TEXT_ALIGN_BOTTOM_REAL
local TEAM_HUMAN = TEAM_HUMAN
local TEAM_UNDEAD = TEAM_UNDEAD
local translate = translate
local COLOR_PURPLE = COLOR_PURPLE
local COLOR_GRAY = COLOR_GRAY
local COLOR_RED = COLOR_RED
local COLOR_DARKRED = COLOR_DARKRED
local COLOR_DARKGREEN = COLOR_DARKGREEN
local COLOR_GREEN = COLOR_GREEN
local COLOR_WHITE = COLOR_WHITE
local vector_up = Vector(0, 0, 1)
local vector_down = Vector(0, 0, 1)
--local surface_SetFont = surface.SetFont
--local surface_SetTexture = surface.SetTexture
local surface_SetMaterial = surface.SetMaterial
local surface_SetDrawColor = surface.SetDrawColor
--local surface_DrawLine = surface.DrawLine
local surface_DrawRect = surface.DrawRect
local surface_DrawOutlinedRect = surface.DrawOutlinedRect
local surface_DrawTexturedRect = surface.DrawTexturedRect
local surface_DrawTexturedRectRotated = surface.DrawTexturedRectRotated
local surface_DrawTexturedRectUV = surface.DrawTexturedRectUV
local surface_PlaySound = surface.PlaySound
local render_SetBlend = render.SetBlend
local render_ModelMaterialOverride = render.ModelMaterialOverride
local render_SetColorModulation = render.SetColorModulation
local render_SuppressEngineLighting = render.SuppressEngineLighting
local cam_IgnoreZ = cam.IgnoreZ
local render_SetMaterial = render.SetMaterial
local render_DrawQuadEasy = render.DrawQuadEasy
local cam_Start3D = cam.Start3D
local cam_End3D = cam.End3D
local cam_Start3D2D = cam.Start3D2D
local cam_End3D2D = cam.End3D2D
local render_FogMode = render.FogMode
local render_FogStart = render.FogStart
local render_FogEnd = render.FogEnd
local render_FogColor = render.FogColor
local render_FogMaxDensity = render.FogMaxDensity
local render_GetFogDistances = render.GetFogDistances
local render_GetFogColor = render.GetFogColor
local render_GetFogMode = render.GetFogMode
local draw_SimpleText = draw.SimpleText
local draw_SimpleTextBlurry = draw.SimpleTextBlurry
local draw_SimpleTextBlur = draw.SimpleTextBlur
local draw_GetFontHeight = draw.GetFontHeight
local MedicalAuraDistance = 800 ^ 2
local M_Player = FindMetaTable("Player")
local P_Team = M_Player.Team
GM.LifeStatsBrainsEaten = 0
GM.LifeStatsHumanDamage = 0
GM.LifeStatsBarricadeDamage = 0
GM.InputMouseX = 0
GM.InputMouseY = 0
GM.LastTimeDead = 0
GM.LastTimeAlive = 0
GM.HeartBeatTime = 0
GM.FOVLerp = 1
GM.HurtEffect = 0
GM.PrevHealth = 0
GM.SuppressArsenalTime = 0
GM.ZombieThirdPerson = false
GM.Beats = {}
GM.CurrentRound = 1
GM.DeathFog = 0
GM.FogStart = 0
GM.FogEnd = 8000
GM.FogRed = 30
GM.FogGreen = 30
GM.FogBlue = 30
function GM:ClickedPlayerButton(pl, button)
end
function GM:ClickedEndBoardPlayerButton(pl, button)
end
function GM:CenterNotify(...)
if self.CenterNotificationHUD and self.CenterNotificationHUD:IsValid() then
return self.CenterNotificationHUD:AddNotification(...)
end
end
function GM:TopNotify(...)
if self.TopNotificationHUD and self.TopNotificationHUD:IsValid() then
return self.TopNotificationHUD:AddNotification(...)
end
end
function GM:_InputMouseApply(cmd, x, y, ang)
if MySelf:KeyDown(IN_WALK) and MySelf:IsHolding() then
self.InputMouseX = math.NormalizeAngle(self.InputMouseX - x * 0.02 * GAMEMODE.PropRotationSensitivity)
self.InputMouseY = math.NormalizeAngle(self.InputMouseY - y * 0.02 * GAMEMODE.PropRotationSensitivity)
local snap = GAMEMODE.PropRotationSnap
local snapanglex, snapangley = self.InputMouseX, self.InputMouseY
if snap > 0 then
snapanglex = Angle(self.InputMouseX, 0, 0):SnapTo("p", snap).p
snapangley = Angle(self.InputMouseY, 0, 0):SnapTo("p", snap).p
end
RunConsoleCommand("_zs_rotateang", snapanglex, snapangley)
return true
end
if self:UseOverTheShoulder() and P_Team(MySelf) == TEAM_HUMAN then
self:InputMouseApplyOTS(cmd, x, y, ang)
end
end
function GM:_GUIMousePressed(mc)
end
function GM:TryHumanPickup(pl, entity)
end
function GM:AddExtraOptions(list, window)
end
function GM:SpawnMenuEnabled()
return false
end
function GM:SpawnMenuOpen()
return false
end
function GM:ContextMenuOpen()
return false
end
function GM:_HUDWeaponPickedUp(wep)
if P_Team(MySelf) == TEAM_HUMAN and not wep.NoPickupNotification then
self:Rewarded(wep:GetClass())
end
end
function GM:HUDItemPickedUp(itemname)
end
function GM:HUDAmmoPickedUp(itemname, amount)
end
function GM:InitPostEntity()
self:CreateLateVGUI()
self:AssignItemProperties()
self:FixWeaponBase()
self:LocalPlayerFound()
gamemode.Call("EvaluateFilmMode")
timer.Simple(2, function() GAMEMODE:GetFogData() end)
RunConsoleCommand("pp_bloom", "0")
end
local fogstart = 0
local fogend = 0
local fogr = 0
local fogg = 0
local fogb = 0
function GM:SetupFog()
local power = self.DeathFog
local rpower = 1 - self.DeathFog
fogstart = self.FogStart * rpower
fogend = self.FogEnd * rpower + 150 * power
fogr = self.FogRed * rpower
fogg = self.FogGreen * rpower + 40 * power
fogb = self.FogBlue * rpower
local dimvision = MySelf.DimVision
if dimvision and dimvision:IsValid() then
power = dimvision:GetDim()
fogstart = Lerp(power, fogstart, 1)
fogend = Lerp(power, fogend, math.min(148 / math.max(0.01, MySelf.DimVisionEffMul), fogend))
fogr = Lerp(power, fogr, 0)
fogg = Lerp(power, fogg, 0)
fogb = Lerp(power, fogb, 0)
end
end
function GM:_SetupWorldFog()
if self.DeathFog == 0 and not MySelf.DimVision then return end
self:SetupFog()
render_FogMode(1)
render_FogStart(fogstart)
render_FogEnd(fogend)
render_FogColor(fogr, fogg, fogb)
render_FogMaxDensity(1)
return true
end
function GM:_SetupSkyboxFog(skyboxscale)
if self.DeathFog == 0 and not MySelf.DimVision then return end
self:SetupFog()
render_FogMode(1)
render_FogStart(fogstart * skyboxscale)
render_FogEnd(fogend * skyboxscale)
render_FogColor(fogr, fogg, fogb)
render_FogMaxDensity(1)
return true
end
function GM:PreDrawSkyBox()
self.DrawingInSky = true
end
local matSky = CreateMaterial("SkyOverride", "UnlitGeneric", {["$basetexture"] = "color/white", ["$vertexcolor"] = 1, ["$vertexalpha"] = 1, ["$model"] = 1})
local colSky = Color(0, 30, 0)
function GM:PostDrawSkyBox()
self.DrawingInSky = false
local dimvision = MySelf.DimVision
dimvision = dimvision and dimvision:IsValid() and dimvision:GetDim()
if self.DeathFog > 0 or dimvision then
colSky.a = math.max(self.DeathFog, dimvision or 0) * 230
colSky.g = self.DeathFog * 30
cam_Start3D(EyePos(), EyeAngles())
render_SuppressEngineLighting(true)
render_SetMaterial(matSky)
render_DrawQuadEasy(Vector(0, 0, 10240), Vector(0, 0, -1), 20480, 20480, colSky, 0)
render_DrawQuadEasy(Vector(0, 10240, 0), Vector(0, -1, 0), 20480, 20480, colSky, 0)
render_DrawQuadEasy(Vector(0, -10240, 0), Vector(0, 1, 0), 20480, 20480, colSky, 0)
render_DrawQuadEasy(Vector(10240, 0, 0), Vector(-1, 0, 0), 20480, 20480, colSky, 0)
render_DrawQuadEasy(Vector(-10240, 0, 0), Vector(1, 0, 0), 20480, 20480, colSky, 0)
render_SuppressEngineLighting(false)
cam_End3D()
end
end
function GM:GetFogData()
local _fogstart, _fogend = render_GetFogDistances()
local _fogr, _fogg, _fogb = render_GetFogColor()
self.FogStart = _fogstart
self.FogEnd = _fogend
self.FogRed = _fogr
self.FogGreen = _fogg
self.FogBlue = _fogb
end
function GM:ShouldDraw3DWeaponHUD()
return GAMEMODE.WeaponHUDMode ~= 1
end
function GM:ShouldDraw2DWeaponHUD()
return GAMEMODE.WeaponHUDMode >= 1 or self:UseOverTheShoulder()
end
local matAura = Material("models/debug/debugwhite")
local skip = false
function GM.PostPlayerDrawMedical(pl)
if not skip and P_Team(pl) == TEAM_HUMAN and pl ~= MySelf then
local eyepos = EyePos()
local dist = pl:NearestPoint(eyepos):DistToSqr(eyepos)
if dist < MedicalAuraDistance then
local green = pl:Health() / pl:GetMaxHealth()
pl.SkipDrawHooks = true
skip = true
render_SuppressEngineLighting(true)
render_ModelMaterialOverride(matAura)
render_SetBlend((1 - dist / MedicalAuraDistance) * 0.1 * (1 + math.abs(math.sin((CurTime() + pl:EntIndex()) * 4)) * 0.05))
render_SetColorModulation(1 - green, green, pl:GetDTBool(DT_PLAYER_BOOL_FRAIL) and 1 or 0)
pl:DrawModel()
render_SetColorModulation(1, 1, 1)
render_SetBlend(1)
render_ModelMaterialOverride()
render_SuppressEngineLighting(false)
skip = false
pl.SkipDrawHooks = false
end
end
end
function GM:OnReloaded()
self.BaseClass.OnReloaded(self)
self:LocalPlayerFound()
end
-- The whole point of this is so we don't need to check if the local player is valid 1000 times a second.
-- Empty functions get filled when the local player is found.
function GM:Think() end
GM.HUDWeaponPickedUp = GM.Think
GM.Think = GM._Think
GM.HUDShouldDraw = GM.Think
GM.CachedFearPower = GM.Think
GM.CalcView = GM.Think
GM.ShouldDrawLocalPlayer = GM.Think
GM.PostDrawOpaqueRenderables = GM.Think
GM.PostDrawTranslucentRenderables = GM.Think
GM.HUDPaint = GM.Think
GM.HUDPaintBackground = GM.Think
GM.CreateMove = GM.Think
GM.PrePlayerDraw = GM.Think
GM.PostPlayerDraw = GM.Think
GM.InputMouseApply = GM.Think
GM.GUIMousePressed = GM.Think
GM.HUDWeaponPickedUp = GM.Think
function GM:LocalPlayerFound()
self.Think = self._Think
self.HUDShouldDraw = self._HUDShouldDraw
self.CachedFearPower = self._CachedFearPower
self.CalcView = self._CalcView
self.ShouldDrawLocalPlayer = self._ShouldDrawLocalPlayer
self.PostDrawTranslucentRenderables = self._PostDrawTranslucentRenderables
self.HUDPaint = self._HUDPaint
self.HUDPaintBackground = self._HUDPaintBackground
self.CreateMove = self._CreateMove
self.PrePlayerDraw = self._PrePlayerDraw
self.PostPlayerDraw = self._PostPlayerDraw
self.InputMouseApply = self._InputMouseApply
self.GUIMousePressed = self._GUIMousePressed
self.HUDWeaponPickedUp = self._HUDWeaponPickedUp
self.RenderScene = self._RenderScene
self.SetupSkyboxFog = self._SetupSkyboxFog
self.SetupWorldFog = self._SetupWorldFog
LocalPlayer().LegDamage = 0
LocalPlayer().ArmDamage = 0
if render.GetDXLevel() >= 80 then
self.RenderScreenspaceEffects = self._RenderScreenspaceEffects
end
end
local LastSigilCorrupted = -math.huge
local LastSigilUncorrupted = -math.huge
local function DrawEyeFlash(x, y, size, islast)
local curtime = CurTime()
local bsize = size * (1 + curtime * 2 % 1)
surface_SetDrawColor(220, 0, 0, 240)
surface_DrawTexturedRectRotated(x, y, bsize, bsize, 0)
if islast then
local dt = (curtime - LastSigilCorrupted) / 3
if dt < 1 then
local idt = 1 - dt
surface_SetDrawColor(idt ^ 0.5 * 255, 0, 0, 255)
surface_DrawTexturedRectRotated(x, y, size * dt * 150, size, dt * 10)
surface_DrawTexturedRectRotated(x, y, size, size * dt * 150, dt * 10)
else
dt = (curtime - LastSigilUncorrupted) / 3
if dt < 1 then
local idt = 1 - dt
surface_SetDrawColor(0, dt ^ 0.5 * 255, 0, 255)
surface_DrawTexturedRectRotated(x, y, size * idt * 150, size, idt * 10)
surface_DrawTexturedRectRotated(x, y, size, size * idt * 150, idt * 10)
end
end
end
end
local currentpower = 0
local spawngreen = 0
local matFearMeter = Material("zombiesurvival/fearometer")
local matNeedle = Material("zombiesurvival/fearometerneedle")
local matEyeGlow = Material("Sprites/light_glow02_add_noz")
local matSigil = Material("zombiesurvival/sigil.png")
local matArsenal = Material("zombiesurvival/arsenalcrate.png")
local matResupply = Material("zombiesurvival/resupply.png")
local matRemantler = Material("zombiesurvival/remantler.png")
local matCrossout = Material("zombiesurvival/crossout.png")
local matNest = Material("zombiesurvival/nest.png")
--local matGradientRight = Material("vgui/gradient-r")
--local matGradientLeft = CreateMaterial("gradient-l", "UnlitGeneric", {["$basetexture"] = "vgui/gradient-l", ["$vertexalpha"] = "1", ["$vertexcolor"] = "1", ["$ignorez"] = "1", ["$nomip"] = "1"})
function GM:DrawFearMeter(power, screenscale)
if currentpower < power then
currentpower = math.min(power, currentpower + FrameTime() * (math.tan(currentpower) * 2 + 0.05))
elseif power < currentpower then
currentpower = math.max(power, currentpower - FrameTime() * (math.tan(currentpower) * 2 + 0.05))
end
local w, h = ScrW(), ScrH()
local size = 192 * screenscale
local half_size = size / 2
local mx, my = w / 2 - half_size, h - size
surface_SetMaterial(matFearMeter)
surface_SetDrawColor(140, 140, 140, 240)
surface_DrawTexturedRect(mx, my, size, size)
if currentpower >= 0.75 then
local pulse = CurTime() % 3 - 1
if pulse > 0 then
pulse = pulse ^ 2
local pulsesize = pulse * screenscale * 28
surface_SetDrawColor(140, 140, 140, 120 - pulse * 120)
surface_DrawTexturedRect(mx - pulsesize, my - pulsesize, size + pulsesize * 2, size + pulsesize * 2)
end
end
surface_SetMaterial(matNeedle)
surface_SetDrawColor(160, 160, 160, 225)
local rot = math.Clamp((0.5 - currentpower) + math.sin(RealTime() * 10) * 0.01, -0.5, 0.5) * 300
surface_DrawTexturedRectRotated(w * 0.5 - math.max(0, rot * size * -0.0001), h - half_size - math.abs(rot) * size * 0.00015, size, size, rot)
if P_Team(MySelf) == TEAM_UNDEAD then
if self:GetDynamicSpawning() and self:ShouldUseAlternateDynamicSpawn() then
local obs = MySelf:GetObserverTarget()
spawngreen = math.Approach(spawngreen, self:DynamicSpawnIsValid(obs and obs:IsValid() and obs:IsPlayer() and obs:Team() == TEAM_UNDEAD and obs or MySelf) and 1 or 0, FrameTime() * 4)
local sy = my + size * 0.6953
local gsize = size * 0.085
surface_SetMaterial(matEyeGlow)
surface_SetDrawColor(220 * (1 - spawngreen), 220 * spawngreen, 0, 240)
surface_DrawTexturedRectRotated(mx + size * 0.459, sy, gsize, gsize, 0)
surface_DrawTexturedRectRotated(mx + size * 0.525, sy, gsize, gsize, 0)
end
if currentpower > 0 and not self.ZombieEscape then
draw_SimpleTextBlurry(translate.Format("resist_x", math.ceil(self:GetDamageResistance(currentpower) * 100)), "ZSDamageResistance", w * 0.5, my + size * 0.75, Color(currentpower * 200, 200 - currentpower * 200, 0, 255), TEXT_ALIGN_CENTER)
end
end
if self:GetUseSigils() and self.MaxSigils > 0 then
local sigwid, sighei = screenscale * 18, screenscale * 36
local extrude = size * 0.25 + sighei / 2
local angle_current = -180
local angle_step = 180 / (self.MaxSigils - 1)
local rad, sigil, health, maxhealth, corrupt, damageflash, sigx, sigy, healthfrac
local sigils = GAMEMODE.CachedSigils
local corruptsigils = 0
for i=1, self.MaxSigils do
sigil = sigils[i]
health = 0
maxhealth = 0
corrupt = false
if sigil and sigil:IsValid() then
health = sigil:GetSigilHealth()
maxhealth = sigil:GetSigilMaxHealth()
corrupt = sigil:GetSigilCorrupted()
corruptsigils = corruptsigils + (corrupt and 1 or 0)
end
if health >= 0 then
rad = math.rad(angle_current)
sigx = mx + half_size + math.cos(rad) * extrude
sigy = my + half_size + math.sin(rad) * extrude
if sigil and sigil:IsValid() then
damageflash = math.min((CurTime() - sigil:GetSigilLastDamaged()) * 2, 1) * 255
else
damageflash = 255
end
healthfrac = health / maxhealth
if corrupt then
surface_SetDrawColor((255 - damageflash) * healthfrac, damageflash * healthfrac, 0, 220)
else
surface_SetDrawColor((255 - damageflash) * healthfrac, damageflash * healthfrac, 220, 220)
end
surface_SetMaterial(matSigil)
surface_DrawTexturedRectRotated(sigx, sigy, sigwid, sighei, angle_current + 90)
if corrupt then
surface_SetMaterial(matCrossout)
surface_SetDrawColor(220, 0, 0, 220)
surface_DrawTexturedRect(sigx - sigwid / 2, sigy - sighei / 2, sigwid, sighei)
end
angle_current = angle_current + angle_step
end
end
local des = corruptsigils / self.MaxSigils --self:GetSigilsDestroyed() / self.MaxSigils
if des >= 0.3333 then
surface_SetMaterial(matEyeGlow)
local eye_size = size * 0.125
local sy = my + size * 0.6953
if des >= 0.6666 then
DrawEyeFlash(mx + size * 0.459, sy, eye_size)
DrawEyeFlash(mx + size * 0.525, sy, eye_size, true)
else
DrawEyeFlash(mx + size * 0.459, sy, eye_size, true)
end
end
end
end
function GM:GetDynamicSpawning()
return not GetGlobalBool("DynamicSpawningDisabled", false)
end
function GM:TrackLastDeath()
if MySelf:Alive() then
self.LastTimeAlive = CurTime()
else
self.LastTimeDead = CurTime()
end
end
function GM:IsClassicMode()
return GetGlobalBool("classicmode", false)
end
function GM:IsBabyMode()
return GetGlobalBool("babymode", false)
end
function GM:PostRender()
end
local lastwarntim = -1
--local NextGas = 0
function GM:_Think()
local time = CurTime()
if self:GetEscapeStage() == ESCAPESTAGE_DEATH then
self.DeathFog = math.min(self.DeathFog + FrameTime() / 5, 1)
--[[if time >= NextGas then
NextGas = time + 0.01
local randdir, emitpos, particle
local eyepos = EyePos()
local emitter = ParticleEmitter(eyepos)
for i=1, 3 do
randdir = VectorRand()
randdir.z = math.abs(randdir.z)
randdir:Normalize()
emitpos = eyepos + randdir * math.Rand(0, 1200)
particle = emitter:Add("particles/smokey", emitpos)
particle:SetVelocity(randdir * math.Rand(8, 256))
particle:SetAirResistance(16)
particle:SetDieTime(math.Rand(2.2, 3.5))
particle:SetStartAlpha(math.Rand(70, 90))
particle:SetEndAlpha(0)
particle:SetStartSize(1)
particle:SetEndSize(math.Rand(150, 325))
particle:SetRoll(math.Rand(0, 360))
particle:SetRollDelta(math.Rand(-1, 1))
particle:SetColor(0, math.Rand(20, 45), 0)
end
emitter:Finish() emitter = nil collectgarbage("step", 64)
end]]
elseif self.DeathFog > 0 then
self.DeathFog = math.max(self.DeathFog - FrameTime() / 5, 0)
end
local health = MySelf:Health()
if self.PrevHealth and health < self.PrevHealth then
self.HurtEffect = math.min(self.HurtEffect + (self.PrevHealth - health) * 0.02, 1.5)
elseif self.HurtEffect > 0 then
self.HurtEffect = math.max(0, self.HurtEffect - FrameTime() * 0.65)
end
self.PrevHealth = health
self:TrackLastDeath()
local endtime = self:GetWaveActive() and self:GetWaveEnd() or self:GetWaveStart()
if endtime ~= -1 then
local timleft = math.max(0, endtime - time)
if timleft <= 10 and lastwarntim ~= math.ceil(timleft) then
lastwarntim = math.ceil(timleft)
if 0 < lastwarntim then
LocalPlayer():EmitSound("buttons/lightswitch2.wav", 100, 110 - lastwarntim * 2)
end
end
end
local myteam = P_Team(MySelf)
self:PlayBeats(myteam, self:CachedFearPower())
local thirdperson
if myteam == TEAM_HUMAN then
local wep = MySelf:GetActiveWeapon()
if wep:IsValid() and wep.GetIronsights and wep:GetIronsights() then
self.FOVLerp = math.Approach(self.FOVLerp, wep.IsScoped and not self.DisableScopes and wep.IronsightsMultiplier or not wep.IsScoped and wep.IronsightsMultiplier or 0.6, FrameTime() * 4)
elseif self.FOVLerp ~= 1 then
self.FOVLerp = math.Approach(self.FOVLerp, 1, FrameTime() * 5)
end
if MySelf:GetBarricadeGhosting() then
MySelf:BarricadeGhostingThink()
end
thirdperson = self.OverTheShoulder
else
self.HeartBeatTime = self.HeartBeatTime + (6 + self:CachedFearPower() * 5) * FrameTime()
thirdperson = self.ZombieThirdPerson
--[[if not MySelf:Alive() then
self:ToggleZombieVision(false)
end]]
end
self.TransparencyRadius = thirdperson and self.TransparencyRadius3p or self.TransparencyRadius1p
local tab
for _, pl in pairs(player.GetAll()) do
if P_Team(pl) == TEAM_UNDEAD then
tab = pl:GetZombieClassTable()
if tab.BuildBonePositions then
if not pl.WasBuildingBonePositions then
pl.BuildingBones = pl:GetBoneCount() - 1
pl.WasBuildingBonePositions = true
end
pl:ResetBones()
tab.BuildBonePositions(tab, pl)
elseif pl.WasBuildingBonePositions then
pl.WasBuildingBonePositions = nil
pl:ResetBones()
end
elseif pl.WasBuildingBonePositions then
pl.WasBuildingBonePositions = nil
pl:ResetBones()
end
end
end
function GM:ShouldPlayBeats(teamid, fear)
return not self.RoundEnded and not self.ZombieEscape and not GetGlobalBool("beatsdisabled", false)
end
local cv_ShouldPlayMusic = CreateClientConVar("zs_playmusic", 1, true, false)
local NextBeat = 0
local LastBeatLevel = 0
function GM:PlayBeats(teamid, fear)
if RealTime() <= NextBeat or not gamemode.Call("ShouldPlayBeats", teamid, fear) then return end
--if (LASTHUMAN or self:GetAllSigilsDestroyed()) and cv_ShouldPlayMusic:GetBool() then
if LASTHUMAN and cv_ShouldPlayMusic:GetBool() then
MySelf:EmitSound(self.LastHumanSound, 0, 100, self.BeatsVolume)
NextBeat = RealTime() + SoundDuration(self.LastHumanSound) - 0.025
return
end
if fear <= 0 or not self.BeatsEnabled then return end
local beats = self.Beats[teamid == TEAM_HUMAN and self.BeatSetHuman or self.BeatSetZombie]
if not beats then return end
LastBeatLevel = math.Approach(LastBeatLevel, math.ceil(fear * 10), 3)
local snd = beats[LastBeatLevel]
if snd then
MySelf:EmitSound(snd, 0, 100, self.BeatsVolume)
NextBeat = RealTime() + (self.SoundDuration[snd] or SoundDuration(snd)) - 0.025
end
end
local colPackUp = Color(20, 255, 20, 220)
local colPackUpNotOwner = Color(255, 240, 10, 220)
function GM:DrawPackUpBar(x, y, fraction, notowner, screenscale)
local col = notowner and colPackUpNotOwner or colPackUp
local maxbarwidth = 270 * screenscale
local barheight = 11 * screenscale
local barwidth = maxbarwidth * math.Clamp(fraction, 0, 1)
local startx = x - maxbarwidth * 0.5
surface_SetDrawColor(0, 0, 0, 220)
surface_DrawRect(startx, y, maxbarwidth, barheight)
surface_SetDrawColor(col)
surface_DrawRect(startx + 3, y + 3, barwidth - 6, barheight - 6)
surface_DrawOutlinedRect(startx, y, maxbarwidth, barheight)
draw_SimpleText(notowner and CurTime() % 2 < 1 and translate.Format("requires_x_people", 4) or notowner and translate.Get("packing_others_object") or translate.Get("packing"), "ZSHUDFontSmall", x, y - draw_GetFontHeight("ZSHUDFontSmall") - 2, col, TEXT_ALIGN_CENTER)
end
local colSigilTeleport = Color(125, 215, 255, 220)
function GM:DrawSigilTeleportBar(x, y, fraction, target, screenscale)
local maxbarwidth = 270 * screenscale
local barheight = 11 * screenscale
local barwidth = maxbarwidth * math.Clamp(fraction, 0, 1)
local startx = x - maxbarwidth * 0.5
local letter = "?"
for i, sigil in pairs(ents.FindByClass("prop_obj_sigil")) do
if target == sigil then
letter = string.char(64 + i)
break
end
end
surface_SetDrawColor(0, 0, 0, 220)
surface_DrawRect(startx, y, maxbarwidth, barheight)
surface_SetDrawColor(colSigilTeleport)
surface_DrawRect(startx + 3, y + 3, barwidth - 6, barheight - 6)
surface_DrawOutlinedRect(startx, y, maxbarwidth, barheight)
draw_SimpleText(translate.Format("teleporting_to_sigil", letter), "ZSHUDFontSmall", x, y - draw_GetFontHeight("ZSHUDFontSmall") - 2, colSigilTeleport, TEXT_ALIGN_CENTER)
draw_SimpleText(translate.Get("press_shift_to_cancel"), "ZSHUDFontSmaller", x, y + draw_GetFontHeight("ZSHUDFontSmaller") - 16, colSigilTeleport, TEXT_ALIGN_CENTER)
draw_SimpleText(translate.Get("point_at_a_sigil_to_choose_destination"), "ZSHUDFontSmaller", x, y + draw_GetFontHeight("ZSHUDFontSmaller") * 2 - 16, colSigilTeleport, TEXT_ALIGN_CENTER)
end
function GM:HumanHUD(screenscale)
local curtime = CurTime()
local w, h = ScrW(), ScrH()
local packup = MySelf.PackUp
local sigiltp = MySelf.SigilTeleport
if packup and packup:IsValid() then
self:DrawPackUpBar(w * 0.5, h * 0.55, 1 - packup:GetTimeRemaining() / packup:GetMaxTime(), packup:GetNotOwner(), screenscale)
elseif sigiltp and sigiltp:IsValid() then
self:DrawSigilTeleportBar(w * 0.5, h * 0.55, 1 - sigiltp:GetTimeRemaining() / sigiltp:GetMaxTime(), sigiltp:GetTargetSigil(), screenscale)
end
if not self.RoundEnded then
if self:GetWave() == 0 and not self:GetWaveActive() then
local txth = draw_GetFontHeight("ZSHUDFontSmall")
local desiredzombies = self:GetDesiredStartingZombies()
draw_SimpleTextBlurry(translate.Get("waiting_for_players").." "..util.ToMinutesSecondsCD(math.max(0, self:GetWaveStart() - curtime)), "ZSHUDFontSmall", w * 0.5, h * 0.25, COLOR_GRAY, TEXT_ALIGN_CENTER)
if desiredzombies > 0 then
draw_SimpleTextBlurry(translate.Get(self:HasSigils() and "humans_furthest_from_sigils_are_zombies" or "humans_closest_to_spawns_are_zombies"), "ZSHUDFontSmall", w * 0.5, h * 0.25 + txth, COLOR_GRAY, TEXT_ALIGN_CENTER)
draw_SimpleTextBlurry(translate.Format("number_of_initial_zombies_this_game", self.WaveOneZombies * 100, desiredzombies), "ZSHUDFontSmall", w * 0.5, h * 0.7, COLOR_GRAY, TEXT_ALIGN_CENTER)
for i, pl in ipairs(self.ZombieVolunteers) do
if pl:IsValid() then
draw_SimpleTextBlurry(translate.Get("zombie_volunteers"), "ZSHUDFontSmall", w * 0.5, h * 0.7 + txth, COLOR_GRAY, TEXT_ALIGN_CENTER)
break
end
end
local y = h * 0.7 + txth * 1.9
txth = draw_GetFontHeight("ZSHUDFontTiny")
for i, pl in ipairs(self.ZombieVolunteers) do
if pl:IsValid() then
draw_SimpleTextBlurry(pl:Name(), "ZSHUDFontTiny", w * 0.5, y, pl == MySelf and COLOR_SOFTRED or COLOR_GRAY, TEXT_ALIGN_CENTER)
y = y + txth * 0.8
end
end
end
end
local drown = MySelf.status_drown
if drown and drown:IsValid() then
surface_SetDrawColor(0, 0, 0, 60)
surface_DrawRect(w * 0.4, h * 0.35, w * 0.2, 12)
surface_SetDrawColor(30, 30, 230, 180)
surface_DrawOutlinedRect(w * 0.4, h * 0.35, w * 0.2, 12)
surface_DrawRect(w * 0.4, h * 0.35, w * 0.2 * (1 - drown:GetDrown()), 12)
draw_SimpleTextBlurry(translate.Get("breath").." ", "ZSHUDFontSmall", w * 0.4, h * 0.35 + 6, COLOR_LBLUE, TEXT_ALIGN_RIGHT, TEXT_ALIGN_CENTER)
end
end
local lockon = self.HumanMenuLockOn
if lockon and self:ValidMenuLockOnTarget(MySelf, lockon) then
local txth = draw_GetFontHeight("ZSHUDFontSmall")
draw_SimpleTextBlurry(translate.Format("giving_items_to", lockon:Name()), "ZSHUDFontSmall", w * 0.5, h * 0.55 + txth, COLOR_GRAY, TEXT_ALIGN_CENTER)
end
if gamemode.Call("PlayerCanPurchase", MySelf) then
draw_SimpleTextBlurry(translate.Get("press_f2_for_the_points_shop"), "ZSHUDFontSmall", w * 0.5, screenscale * 135, COLOR_GRAY, TEXT_ALIGN_CENTER)
end
end
function GM:_HUDPaint()
if self.FilmMode then return end
local screenscale = BetterScreenScale()
local myteam = P_Team(MySelf)
self:HUDDrawTargetID(myteam, screenscale)
if self:GetWave() > 0 then
self:DrawFearMeter(self:CachedFearPower(), screenscale)
end
if myteam == TEAM_UNDEAD then
self:ZombieHUD()
elseif myteam == TEAM_HUMAN then
self:HumanHUD(screenscale)
end
if GetGlobalBool("classicmode") then
draw_SimpleTextBlurry(translate.Get("classic_mode"), "ZSHUDFontSmaller", 4, ScrH() - 4, COLOR_GRAY, TEXT_ALIGN_LEFT, TEXT_ALIGN_BOTTOM_REAL)
end
end
function GM:ZombieObserverHUD(obsmode)
local w, h = ScrW(), ScrH()
local texh = draw_GetFontHeight("ZSHUDFontSmall")
if obsmode == OBS_MODE_CHASE then
local target = MySelf:GetObserverTarget()
if target and target:IsValid() then
if target:IsPlayer() and P_Team(target) == TEAM_UNDEAD then
draw_SimpleTextBlur(translate.Format("observing_x", target:Name(), math.max(0, target:Health())), "ZSHUDFontSmall", w * 0.5, h * 0.75 - texh - 32, COLOR_DARKRED, TEXT_ALIGN_CENTER)
end
if target.IsCreeperNest or target.MinionSpawn then
local txt = target.IsCreeperNest and "Nest" or "Gore Child"
draw_SimpleTextBlur(translate.Format("observing_x_simple", txt), "ZSHUDFontSmall", w * 0.5, h * 0.75 - texh - 32, COLOR_DARKRED, TEXT_ALIGN_CENTER)
end
dyn = self:GetDynamicSpawning() and self:DynamicSpawnIsValid(target)
end
end
local space = texh + 2
local x, y = w / 2, h * 0.68
if self:GetWaveActive() then
draw_SimpleTextBlurry(translate.Get("press_lmb_to_spawn"), "ZSHUDFontSmall", x, y, COLOR_GRAY, TEXT_ALIGN_CENTER)
draw_SimpleTextBlurry(translate.Get("press_rmb_to_spawn_close"), "ZSHUDFontSmall", x, y + space, COLOR_GRAY, TEXT_ALIGN_CENTER)
draw_SimpleTextBlurry(translate.Get("press_reload_to_spawn_far"), "ZSHUDFontSmall", x, y + space * 2, COLOR_GRAY, TEXT_ALIGN_CENTER)
draw_SimpleTextBlurry(translate.Get("press_alt_nest_menu"), "ZSHUDFontSmaller", x, y + space * 4, COLOR_GRAY, TEXT_ALIGN_CENTER)
end
draw_SimpleTextBlurry(translate.Get("press_jump_to_free_roam"), "ZSHUDFontSmall", x, y + space * 3, COLOR_GRAY, TEXT_ALIGN_CENTER)
end
local colLifeStats = Color(255, 50, 50, 255)
function GM:ZombieHUD()
if self.LifeStatsEndTime and CurTime() < self.LifeStatsEndTime and (self.LifeStatsBarricadeDamage > 0 or self.LifeStatsHumanDamage > 0 or self.LifeStatsBrainsEaten > 0) then
colLifeStats.a = math.Clamp((self.LifeStatsEndTime - CurTime()) / (self.LifeStatsLifeTime * 0.33), 0, 1) * 255
local th = draw_GetFontHeight("ZSHUDFontSmall")
local x = ScrW() * 0.75
local y = ScrH() * 0.75
draw_SimpleTextBlur(translate.Get("that_life"), "ZSHUDFontSmall", x, y, colLifeStats, TEXT_ALIGN_LEFT)
y = y + th
if self.LifeStatsBarricadeDamage > 0 then
draw_SimpleTextBlur(translate.Format("x_damage_to_barricades", self.LifeStatsBarricadeDamage), "ZSHUDFontSmall", x, y, colLifeStats, TEXT_ALIGN_LEFT)
y = y + th
end
if self.LifeStatsHumanDamage > 0 then
draw_SimpleTextBlur(translate.Format("x_damage_to_humans", self.LifeStatsHumanDamage), "ZSHUDFontSmall", x, y, colLifeStats, TEXT_ALIGN_LEFT)
y = y + th
end
if self.LifeStatsBrainsEaten > 0 then
draw_SimpleTextBlur(translate.Format("x_brains_eaten", self.LifeStatsBrainsEaten), "ZSHUDFontSmall", x, y, colLifeStats, TEXT_ALIGN_LEFT)
y = y + th
end
end
local obsmode = MySelf:GetObserverMode()
if obsmode ~= OBS_MODE_NONE then
self:ZombieObserverHUD(obsmode)
elseif not MySelf:Alive() then
local x = ScrW() * 0.5
local y = ScrH() * 0.3
if not self:GetWaveActive() then
draw_SimpleTextBlur(translate.Get("waiting_for_next_wave"), "ZSHUDFont", x, y, COLOR_DARKRED, TEXT_ALIGN_CENTER)
end
end
if not self:GetWaveActive() and self:GetWave() ~= 0 then
local pl = GAMEMODE.NextBossZombie
if pl and pl:IsValid() then
local x, y = ScrW() / 2, ScrH() * 0.3 + draw_GetFontHeight("ZSHUDFont")
if pl == MySelf then
draw_SimpleTextBlur(translate.Format("you_will_be_x_soon", GAMEMODE.NextBossZombieClass), "ZSHUDFont", x, y, Color(255, 50, 50), TEXT_ALIGN_CENTER)
else
draw_SimpleTextBlur(translate.Format("x_will_be_y_soon", pl:Name(), GAMEMODE.NextBossZombieClass), "ZSHUDFont", x, y, COLOR_GRAY, TEXT_ALIGN_CENTER)
end
end
end
end
function GM:RequestedDefaultCart()
local defaultcart = GetConVar("zs_defaultcart"):GetString()
if #defaultcart > 0 then
defaultcart = string.lower(defaultcart)
for i, carttab in ipairs(self.SavedCarts) do
if carttab[1] and string.lower(carttab[1]) == defaultcart then
gamemode.Call("SuppressArsenalUpgrades", 1)
RunConsoleCommand("worthcheckout", unpack(carttab[2]))
return
end
end
RunConsoleCommand("worthrandom")
end
end
function GM:_PostDrawTranslucentRenderables()
if not self.DrawingInSky then
self:DrawPointWorldHints()
self:DrawWorldHints()
self:DrawSigilIndicators()
self:DrawCrateIndicators()
self:DrawResupplyIndicators()
self:DrawRemantlerIndicators()
self:DrawHumanIndicators()
self:DrawNestIndicators()
end
end
function GM:DrawCrateIndicators()
if P_Team(MySelf) ~= TEAM_HUMAN or not MySelf:IsSkillActive(SKILL_INSIGHT) then return end
local pos, distance, ang, deployable, alpha
local eyepos = EyePos()
surface_SetMaterial(matArsenal)
for i, arsenal in pairs(GAMEMODE.CachedArsenalEntities) do
if not arsenal:IsValid() then continue end
deployable = arsenal.GetObjectOwner
pos = arsenal:GetPos()
pos.z = pos.z + (arsenal:IsPlayer() and 32 or (deployable and 12 or -8))
distance = eyepos:DistToSqr(pos)
if (distance >= 6400 and distance <= 1048576) and (not deployable or not WorldVisible(eyepos, pos)) then -- Limited to Scavenger's Eyes distance.
ang = (eyepos - pos):Angle()
ang:RotateAroundAxis(ang:Right(), 270)
ang:RotateAroundAxis(ang:Up(), 90)
alpha = math.min(220, math.sqrt(distance / 4))
cam_IgnoreZ(true)
cam_Start3D2D(pos, ang, math.max(250, math.sqrt(distance)) / 5000)
surface_SetDrawColor(255, 255, 255, alpha)
surface_DrawTexturedRect(-123, -113, 248, 228)
draw_SimpleTextBlurry("Arsenal Crate", "ZS3D2DFont2Big", 0, 128, COLOR_GRAY, TEXT_ALIGN_CENTER)
cam_End3D2D()
cam_IgnoreZ(false)
end
end
end
function GM:DrawResupplyIndicators()
if P_Team(MySelf) ~= TEAM_HUMAN or not MySelf:IsSkillActive(SKILL_ACUITY) then return end
local pos, distance, ang, deployable, alpha
local eyepos = EyePos()
surface_SetMaterial(matResupply)
for i, resupply in pairs(GAMEMODE.CachedResupplyEntities) do
if not resupply:IsValid() then continue end
deployable = resupply.GetObjectOwner
pos = resupply:GetPos()
pos.z = pos.z + (resupply:IsPlayer() and 32 or (deployable and 12 or -8))
distance = eyepos:DistToSqr(pos)
if (distance >= 6400 and distance <= 1048576) and (not deployable or not WorldVisible(eyepos, pos)) then -- Limited to Scavenger's Eyes distance.
ang = (eyepos - pos):Angle()
ang:RotateAroundAxis(ang:Right(), 270)
ang:RotateAroundAxis(ang:Up(), 90)
alpha = math.min(220, math.sqrt(distance / 4))
cam_IgnoreZ(true)
cam_Start3D2D(pos, ang, math.max(250, math.sqrt(distance)) / 5000)
surface_SetDrawColor(255, 255, 255, alpha)
surface_DrawTexturedRect(-128, -128, 256, 256)
local timeremain = math.ceil(math.max(0, (MySelf.NextUse or 0) - CurTime()))
local txt = not MySelf.NextUse and translate.Get("ready") or timeremain > 0 and timeremain or translate.Get("ready")
draw_SimpleTextBlurry(txt, "ZS3D2DFont2Big", 0, 128, COLOR_GRAY, TEXT_ALIGN_CENTER)
cam_End3D2D()
cam_IgnoreZ(false)
end
end
end
function GM:DrawRemantlerIndicators()
if P_Team(MySelf) ~= TEAM_HUMAN or not MySelf:IsSkillActive(SKILL_VISION) then return end
local pos, distance, ang, deployable, alpha
local eyepos = EyePos()
surface_SetMaterial(matRemantler)
for i, remantler in pairs(GAMEMODE.CachedRemantlerEntities) do
if not remantler:IsValid() then continue end
deployable = remantler.GetObjectOwner
pos = remantler:GetPos()
pos.z = pos.z + (remantler:IsPlayer() and 32 or (deployable and 12 or -8))
distance = eyepos:DistToSqr(pos)
if (distance >= 6400 and distance <= 1048576) and (not deployable or not WorldVisible(eyepos, pos)) then -- Limited to Scavenger's Eyes distance.
ang = (eyepos - pos):Angle()
ang:RotateAroundAxis(ang:Right(), 270)
ang:RotateAroundAxis(ang:Up(), 90)
alpha = math.min(220, math.sqrt(distance / 4))
cam_IgnoreZ(true)
cam_Start3D2D(pos, ang, math.max(250, math.sqrt(distance)) / 5000)
surface_SetDrawColor(255, 255, 255, alpha)
surface_DrawTexturedRect(-128, -128, 256, 256)
draw_SimpleTextBlurry("Weapon Remantler", "ZS3D2DFont2Big", 0, 128, COLOR_GRAY, TEXT_ALIGN_CENTER)
cam_End3D2D()
cam_IgnoreZ(false)
end
end
end
function GM:DrawNestIndicators()
if P_Team(MySelf) ~= TEAM_ZOMBIE then return end
local pos, distance, ang, alpha
local eyepos = EyePos()
surface_SetMaterial(matNest)
for i, nest in pairs(GAMEMODE.CachedNests) do
if not nest:IsValid() then continue end
pos = nest:GetPos()
pos.z = pos.z + 32
distance = eyepos:DistToSqr(pos)
ang = (eyepos - pos):Angle()
ang:RotateAroundAxis(ang:Right(), 270)
ang:RotateAroundAxis(ang:Up(), 90)
alpha = math.min(220, math.sqrt(distance / 4))
cam_IgnoreZ(true)
cam_Start3D2D(pos, ang, math.max(250, math.sqrt(distance)) / 5000)
surface_SetDrawColor(255, 255, 255, alpha)
surface_DrawTexturedRect(-128, -128, 256, 256)
draw_SimpleTextBlurry("Nest", "ZS3D2DFont2Big", 0, 128, COLOR_GRAY, TEXT_ALIGN_CENTER)
if distance < 80000 then
local nown = nest:GetNestOwner()
local ownname = nown:IsValidZombie() and nown:ClippedName() or ""
draw_SimpleTextBlurry(ownname, "ZS3D2DFont2", 0, 256, COLOR_GRAY, TEXT_ALIGN_CENTER)
end
cam_End3D2D()
cam_IgnoreZ(false)
end
end
function GM:DrawSigilIndicators()
if not self:GetUseSigils() then return end
local health, pos, distance, maxhealth, corrupted, damageflash, missinghealthfrac, ang, alpha
local eyepos = EyePos()
surface_SetMaterial(matSigil)
for i, sigil in pairs(GAMEMODE.CachedSigils) do
if not sigil:IsValid() then continue end
health = sigil:GetSigilHealth()
if health > 0 then
pos = sigil:GetPos()
pos.z = pos.z + 48
distance = eyepos:DistToSqr(pos)
maxhealth = sigil:GetSigilMaxHealth()
corrupted = sigil:GetSigilCorrupted()
damageflash = math.min((CurTime() - sigil:GetSigilLastDamaged()) * 2, 1) * 255
missinghealthfrac = 1 - health / maxhealth
alpha = math.min(220, math.sqrt(distance / 4))
ang = (eyepos - pos):Angle()
ang:RotateAroundAxis(ang:Right(), 270)
ang:RotateAroundAxis(ang:Up(), 90)
cam_IgnoreZ(true)
cam_Start3D2D(pos, ang, math.max(250, math.sqrt(distance)) / 5000)
local oldfogmode = render_GetFogMode()
render_FogMode(0)
if corrupted then
surface_SetDrawColor(255 - damageflash, damageflash, 0, alpha)
else
surface_SetDrawColor(damageflash, 255, damageflash, alpha)
end
surface_DrawTexturedRect(-64, -128, 128, 256)
if missinghealthfrac > 0 then
surface_SetDrawColor(40, 40, 40, 255)
surface_DrawTexturedRectUV(-64, -128, 128, 256 * missinghealthfrac, 0, 0, 1, missinghealthfrac)
end
draw_SimpleTextBlurry(string.char(64 + i), "ZS3D2DFont2Big", 0, 128, COLOR_GRAY, TEXT_ALIGN_CENTER)
render_FogMode(oldfogmode)
cam_End3D2D()
cam_IgnoreZ(false)
end
end
end
function GM:RestartRound()
self.TheLastHuman = nil
self.RoundEnded = nil
LASTHUMAN = nil
if pEndBoard and pEndBoard:IsValid() then
pEndBoard:Remove()
pEndBoard = nil
end
self:ClearItemStocks()
self:InitPostEntity()
self:RevertZombieClasses()
end
function GM:_HUDShouldDraw(name)
if self.FilmMode and name ~= "CHudWeaponSelection" then return false end
return name ~= "CHudHealth" and name ~= "CHudBattery"
and name ~= "CHudAmmo" and name ~= "CHudSecondaryAmmo"
and name ~= "CHudDamageIndicator"
end
local Current = 0
local NextCalculate = 0
function GM:_CachedFearPower()
if CurTime() >= NextCalculate then
NextCalculate = CurTime() + 0.15
Current = self:GetFearMeterPower(EyePos(), TEAM_UNDEAD, MySelf)
end
return Current
end
function surface.CreateLegacyFont(font, size, weight, antialias, additive, name, shadow, outline, blursize)
surface.CreateFont(name, {font = font, size = size, weight = weight, antialias = antialias, additive = additive, shadow = shadow, outline = outline, blursize = blursize})
end
local fontfamily = "Ghoulish Fright AOE"
local fontfamilysm = "Remington Noiseless"
local fontfamily3d = "hidden"
local fontsizeadd = 8
local fontweight = 0
function GM:Create3DFonts()
local fontsizeadd3D = 0
local fontweight3D = 0
surface.CreateLegacyFont(fontfamily3d, 28 + fontsizeadd3D, fontweight3D, false, false, "ZS3D2DFontSmaller", false, true)
surface.CreateLegacyFont(fontfamily3d, 48 + fontsizeadd3D, fontweight3D, false, false, "ZS3D2DFontSmall", false, true)
surface.CreateLegacyFont(fontfamily3d, 72 + fontsizeadd3D, fontweight3D, false, false, "ZS3D2DFont", false, true)
surface.CreateLegacyFont(fontfamily3d, 128 + fontsizeadd3D, fontweight3D, false, false, "ZS3D2DFontBig", false, true)
surface.CreateLegacyFont(fontfamily3d, 28 + fontsizeadd3D, fontweight3D, false, false, "ZS3D2DFontSmallerBlur", false, false, 16)
surface.CreateLegacyFont(fontfamily3d, 48 + fontsizeadd3D, fontweight3D, false, false, "ZS3D2DFontSmallBlur", false, false, 16)
surface.CreateLegacyFont(fontfamily3d, 72 + fontsizeadd3D, fontweight3D, false, false, "ZS3D2DFontBlur", false, false, 16)
surface.CreateLegacyFont(fontfamily3d, 128 + fontsizeadd3D, fontweight3D, false, false, "ZS3D2DFontBigBlur", false, false, 16)
surface.CreateLegacyFont(fontfamily, 40 + fontsizeadd3D, fontweight3D, false, false, "ZS3D2DFont2Smaller", false, true)
surface.CreateLegacyFont(fontfamily, 48 + fontsizeadd3D, fontweight3D, false, false, "ZS3D2DFont2Small", false, true)
surface.CreateLegacyFont(fontfamily, 72 + fontsizeadd3D, fontweight3D, false, false, "ZS3D2DFont2", false, true)
surface.CreateLegacyFont(fontfamily, 128 + fontsizeadd3D, fontweight3D, false, false, "ZS3D2DFont2Big", false, true)
surface.CreateLegacyFont(fontfamily, 40 + fontsizeadd3D, fontweight3D, false, false, "ZS3D2DFont2SmallerBlur", false, false, 16)
surface.CreateLegacyFont(fontfamily, 48 + fontsizeadd3D, fontweight3D, false, false, "ZS3D2DFont2SmallBlur", false, false, 16)
surface.CreateLegacyFont(fontfamily, 72 + fontsizeadd3D, fontweight3D, false, false, "ZS3D2DFont2Blur", false, false, 16)
surface.CreateLegacyFont(fontfamily, 128 + fontsizeadd3D, fontweight3D, false, false, "ZS3D2DFont2BigBlur", false, false, 16)
surface.CreateLegacyFont(fontfamilysm, 14 + fontsizeadd3D, fontweight3D, false, false, "ZS3D2DUnstyleTiny", false, true)
surface.CreateLegacyFont(fontfamilysm, 24 + fontsizeadd3D, fontweight3D, false, false, "ZS3D2DUnstyleSmallest", false, true)
surface.CreateLegacyFont(fontfamilysm, 36 + fontsizeadd3D, fontweight3D, false, false, "ZS3D2DUnstyleSmaller", false, true)
end
function GM:CreateNonScaleFonts()
surface.CreateLegacyFont("tahoma", 96, 1000, true, false, "zshintfont", false, true)
-- Default, DefaultBold, DefaultSmall, etc. were changed when gmod13 hit. These are renamed fonts that have the old values.
surface.CreateFont("DefaultFontVerySmall", {font = "tahoma", size = 10, weight = 0, antialias = false})
surface.CreateFont("DefaultFontSmall", {font = "tahoma", size = 11, weight = 0, antialias = false})
surface.CreateFont("DefaultFontSmallDropShadow", {font = "tahoma", size = 11, weight = 0, shadow = true, antialias = false})
surface.CreateFont("DefaultFont", {font = "tahoma", size = 13, weight = 500, antialias = false})
surface.CreateFont("DefaultFontAA", {font = "tahoma", size = 13, weight = 500, antialias = true})
surface.CreateFont("DefaultFontBold", {font = "tahoma", size = 13, weight = 1000, antialias = false})
surface.CreateFont("DefaultFontLarge", {font = "tahoma", size = 16, weight = 0, antialias = false})
surface.CreateFont("DefaultFontLargeAA", {font = "tahoma", size = 16, weight = 0, antialias = true})
surface.CreateFont("DefaultFontLargest", {font = "tahoma", size = 22, weight = 0, antialias = false})
surface.CreateFont("DefaultFontLargestAA", {font = "tahoma", size = 22, weight = 0, antialias = true})
end
function GM:CreateScalingFonts()
local fontaa = true
local fontshadow = false
local fontoutline = true
local screenscale = BetterScreenScale()
surface.CreateLegacyFont("csd", screenscale * 42, 100, true, false, "zsdeathnoticecs", false, false)
surface.CreateLegacyFont("HL2MP", screenscale * 42, 100, true, false, "zsdeathnotice", false, false)
surface.CreateLegacyFont("csd", screenscale * 96, 100, true, false, "zsdeathnoticecsws", false, false)
surface.CreateLegacyFont("HL2MP", screenscale * 96, 100, true, false, "zsdeathnoticews", false, false)
surface.CreateLegacyFont("csd", screenscale * 72, 100, true, false, "zsdeathnoticecspa", false, false)
surface.CreateLegacyFont("HL2MP", screenscale * 72, 100, true, false, "zsdeathnoticepa", false, false)
surface.CreateLegacyFont(fontfamily, screenscale * (16 + fontsizeadd), fontweight, fontaa, false, "ZSHUDFontTiny", fontshadow, fontoutline)
surface.CreateLegacyFont(fontfamily, screenscale * (20 + fontsizeadd), fontweight, fontaa, false, "ZSHUDFontSmallest", fontshadow, fontoutline)
surface.CreateLegacyFont(fontfamily, screenscale * (22 + fontsizeadd), fontweight, fontaa, false, "ZSHUDFontSmaller", fontshadow, fontoutline)
surface.CreateLegacyFont(fontfamily, screenscale * (28 + fontsizeadd), fontweight, fontaa, false, "ZSHUDFontSmall", fontshadow, fontoutline)
surface.CreateLegacyFont(fontfamily, screenscale * (42 + fontsizeadd), fontweight, fontaa, false, "ZSHUDFont", fontshadow, fontoutline)
surface.CreateLegacyFont(fontfamily, screenscale * (72 + fontsizeadd), fontweight, fontaa, false, "ZSHUDFontBig", fontshadow, fontoutline)
surface.CreateLegacyFont(fontfamily, screenscale * (16 + fontsizeadd), fontweight, fontaa, false, "ZSHUDFontTinyBlur", false, false, 8)
surface.CreateLegacyFont(fontfamily, screenscale * (22 + fontsizeadd), fontweight, fontaa, false, "ZSHUDFontSmallerBlur", false, false, 8)
surface.CreateLegacyFont(fontfamily, screenscale * (28 + fontsizeadd), fontweight, fontaa, false, "ZSHUDFontSmallBlur", false, false, 8)
surface.CreateLegacyFont(fontfamily, screenscale * (42 + fontsizeadd), fontweight, fontaa, false, "ZSHUDFontBlur", false, false, 8)
surface.CreateLegacyFont(fontfamily, screenscale * (72 + fontsizeadd), fontweight, fontaa, false, "ZSHUDFontBigBlur", false, false, 8)
surface.CreateLegacyFont(fontfamily, screenscale * (20 + fontsizeadd/2), 0, fontaa, false, "ZSAmmoName", false, false)
local liscreenscale = math.max(0.95, BetterScreenScale())
surface.CreateLegacyFont(fontfamily, liscreenscale * (32 + fontsizeadd), fontweight, true, false, "ZSScoreBoardTitle", false, true)
surface.CreateLegacyFont(fontfamily, liscreenscale * (22 + fontsizeadd), fontweight, true, false, "ZSScoreBoardSubTitle", false, true)
surface.CreateLegacyFont(fontfamily, liscreenscale * (16 + fontsizeadd), fontweight, true, false, "ZSScoreBoardPlayer", false, true)
surface.CreateLegacyFont(fontfamily, liscreenscale * (24 + fontsizeadd), fontweight, true, false, "ZSScoreBoardHeading", false, false)
surface.CreateLegacyFont("arial", 18 * liscreenscale, 0, true, false, "ZSScoreBoardPlayerSmall", false, true)
surface.CreateLegacyFont("arial", 15 * liscreenscale, 0, true, false, "ZSScoreBoardPlayerSmaller", false, true)
surface.CreateLegacyFont("tahoma", 11 * liscreenscale, 0, true, false, "ZSScoreBoardPing")
surface.CreateLegacyFont(fontfamily, screenscale * (16 + fontsizeadd), fontweight, fontaa, false, "ZSHUDFontTinyNS", false, false)
surface.CreateLegacyFont(fontfamily, screenscale * (20 + fontsizeadd), fontweight, fontaa, false, "ZSHUDFontSmallestNS", false, false)
surface.CreateLegacyFont(fontfamily, screenscale * (22 + fontsizeadd), fontweight, fontaa, false, "ZSHUDFontSmallerNS", false, false)
surface.CreateLegacyFont(fontfamily, screenscale * (28 + fontsizeadd), fontweight, fontaa, false, "ZSHUDFontSmallNS", false, false)
surface.CreateLegacyFont(fontfamily, screenscale * (42 + fontsizeadd), fontweight, fontaa, false, "ZSHUDFontNS", false, false)
surface.CreateLegacyFont(fontfamily, screenscale * (72 + fontsizeadd), fontweight, fontaa, false, "ZSHUDFontBigNS", false, false)
surface.CreateLegacyFont(fontfamilysm, screenscale * 13, fontweight, fontaa, false, "ZSBodyTextFontSmall", fontshadow)
surface.CreateLegacyFont(fontfamilysm, screenscale * 15, fontweight, fontaa, false, "ZSBodyTextFont", fontshadow, fontoutline)
surface.CreateLegacyFont(fontfamilysm, screenscale * 20, fontweight, fontaa, false, "ZSBodyTextFontBig", fontshadow, fontoutline)
surface.CreateLegacyFont(fontfamily, screenscale * (20 + fontsizeadd), 0, true, false, "ZSDamageResistance", false, true)
surface.CreateLegacyFont(fontfamily, screenscale * (20 + fontsizeadd), 0, true, false, "ZSDamageResistanceBlur", false, true)
surface.CreateFont("ZSXPBar", {font = "tahoma", size = screenscale * 14, weight = 500, antialias = false, shadow = true})
end
function GM:CreateFonts()
self:Create3DFonts()
self:CreateNonScaleFonts()
self:CreateScalingFonts()
end
function GM:EvaluateFilmMode()
local visible = not self.FilmMode
if self.GameStatePanel and self.GameStatePanel:IsValid() then
self.GameStatePanel:SetVisible(visible)
end
if self.TopNotificationHUD and self.TopNotificationHUD:IsValid() then
self.TopNotificationHUD:SetVisible(visible)
end
if self.CenterNotificationHUD and self.CenterNotificationHUD:IsValid() then
self.CenterNotificationHUD:SetVisible(visible)
end
if self.XPHUD and self.XPHUD:IsValid() then
self.XPHUD:SetVisible(visible and self.DisplayXPHUD)
end
if self.HealthHUD and self.HealthHUD:IsValid() then
self.HealthHUD:SetVisible(visible)
end
if self.StatusHUD and self.StatusHUD:IsValid() then
self.StatusHUD:SetVisible(visible)
end
end
function GM:CreateVGUI()
local screenscale = BetterScreenScale()
self.GameStatePanel = vgui.Create("ZSGameState")
self.GameStatePanel:SetTextFont("ZSHUDFontSmaller")
self.GameStatePanel:SetAlpha(220)
self.GameStatePanel:SetSize(screenscale * 420, screenscale * 80)
self.GameStatePanel:ParentToHUD()
self.TopNotificationHUD = vgui.Create("DEXNotificationsList")
self.TopNotificationHUD:SetAlign(RIGHT)
self.TopNotificationHUD.PerformLayout = function(pan)
pan:SetSize(ScrW() * 0.4, ScrH() * 0.6)
pan:AlignTop(16 * BetterScreenScale())
pan:AlignRight()
end
self.TopNotificationHUD:InvalidateLayout()
self.TopNotificationHUD:ParentToHUD()
self.CenterNotificationHUD = vgui.Create("DEXNotificationsList")
self.CenterNotificationHUD:SetAlign(CENTER)
self.CenterNotificationHUD:SetMessageHeight(36)
self.CenterNotificationHUD.PerformLayout = function(pan)
pan:SetSize(ScrW() / 2, ScrH() * 0.35)
pan:CenterHorizontal()
pan:AlignBottom(16 * BetterScreenScale())
end
self.CenterNotificationHUD:InvalidateLayout()
self.CenterNotificationHUD:ParentToHUD()
end
function GM:CreateLateVGUI()
if not self.HealthHUD then
self.HealthHUD = vgui.Create("ZSHealthArea")
end
if not self.StatusHUD then
self.StatusHUD = vgui.Create("ZSStatusArea")
end
if not self.XPHUD then
self.XPHUD = vgui.Create("ZSExperienceHUD")
self.XPHUD:ParentToHUD()
self.XPHUD:InvalidateLayout()
end
end
function GM:Initialize()
self:FixSkillConnections()
self:CreateFonts()
self:PrecacheResources()
self:CreateVGUI()
self:InitializeBeats()
self:AddCustomAmmo()
self:RegisterFood()
self:CreateWeaponQualities()
self:CreateSpriteMaterials()
-- Not sure if this still crashes, but whatever.
RunConsoleCommand("r_drawmodeldecals", "0")
-- Flashlight dynamic lights of other players.
RunConsoleCommand("r_dynamic", "0")
self:RefreshMapIsObjective()
end
-- These can be accessed without pointing to the IMaterial by using ! before the material string.
function GM:CreateSpriteMaterials()
local params = {["$translucent"] = "1", ["$vertexcolor"] = "1", ["$vertexalpha"] = "1"}
for i=1, 8 do
params["$basetexture"] = "Decals/blood"..i
CreateMaterial("sprite_bloodspray"..i, "UnlitGeneric", params)
end
end
function GM:ShutDown()
RunConsoleCommand("r_drawmodeldecals", "1")
RunConsoleCommand("r_dynamic", "1")
end
local function FirstOfGoodType(a)
local ext
for _, v in pairs(a) do
ext = string.sub(v, -4)
if ext == ".ogg" or ext == ".wav" or ext == ".mp3" then
return v
end
end
end
function GM:InitializeBeats()
local _, dirs = file.Find("sound/zombiesurvival/beats/*", "GAME")
for _, dirname in pairs(dirs) do
if dirname == "none" or dirname == "default" then continue end
self.Beats[dirname] = {}
local highestexist
for i=1, 10 do
local a, __ = file.Find("sound/zombiesurvival/beats/"..dirname.."/"..i..".*", "GAME")
local a1 = FirstOfGoodType(a)
if a1 then
local filename = "zombiesurvival/beats/"..dirname.."/"..a1
if file.Exists("sound/"..filename, "GAME") then
self.Beats[dirname][i] = Sound(filename)
highestexist = filename
continue
end
end
if highestexist then
self.Beats[dirname][i] = highestexist
end
end
end
end
function GM:PlayerDeath(pl, attacker)
end
function GM:ScalePlayerDamage(pl, hitgroup, dmginfo)
end
function GM:LastHuman(pl)
if not IsValid(pl) then pl = nil end
self.TheLastHuman = pl
if not LASTHUMAN then
LASTHUMAN = true
timer.Simple(0.5, function() GAMEMODE:LastHumanMessage() end)
end
end
function GM:LastHumanMessage()
if self.RoundEnded or not MySelf:IsValid() then return end
local icon = self.PantsMode and "weapon_zs_legs" or "default"
if P_Team(MySelf) == TEAM_UNDEAD or not MySelf:Alive() then
self:CenterNotify({killicon = icon}, {font = "ZSHUDFont"}, " ", COLOR_RED, translate.Get(self.PantsMode and "kick_the_last_human" or "kill_the_last_human"), {killicon = icon})
else
self:CenterNotify({font = "ZSHUDFont"}, " ", COLOR_RED, translate.Get("you_are_the_last_human"))
self:CenterNotify({killicon = icon}, " ", COLOR_RED, translate.Format(self.PantsMode and "x_pants_out_to_get_you" or "x_zombies_out_to_get_you", team.NumPlayers(TEAM_UNDEAD)), {killicon = icon})
end
end
function GM:PlayerShouldTakeDamage(pl, attacker)
return pl == attacker or not attacker:IsPlayer() or P_Team(pl) ~= P_Team(attacker) or pl.AllowTeamDamage or attacker.AllowTeamDamage
end
function GM:SetWave(wave)
SetGlobalInt("wave", wave)
end
local matRing = Material("effects/select_ring")
function GM:DrawCircle(x, y, radius, color)
surface.SetMaterial(matRing)
surface.SetDrawColor(color)
surface.DrawTexturedRect(x - radius, y - radius, radius * 2, radius * 2)
end
local matFilmGrain = Material("zombiesurvival/filmgrain/filmgrain")
function GM:_HUDPaintBackground()
if self.FilmGrainEnabled and P_Team(MySelf) ~= TEAM_UNDEAD then
surface_SetMaterial(matFilmGrain)
surface_SetDrawColor(0, 0, 0, (0.25 + 0.75 * self:CachedFearPower()) * self.FilmGrainOpacity)
surface_DrawTexturedRectUV(0, 0, ScrW(), ScrH(), 2, 2, 0, 0)
end
local wep = MySelf:GetActiveWeapon()
if wep:IsValid() and wep.DrawHUDBackground then
wep:DrawHUDBackground()
end
end
local function GiveWeapon()
if GAMEMODE.HumanMenuLockOn then
RunConsoleCommand("zsgiveweapon", GAMEMODE.HumanMenuLockOn:EntIndex(), GAMEMODE.InventoryMenu.SelInv)
end
end
local function GiveWeaponClip()
if GAMEMODE.HumanMenuLockOn then
RunConsoleCommand("zsgiveweaponclip", GAMEMODE.HumanMenuLockOn:EntIndex(), GAMEMODE.InventoryMenu.SelInv)
end
end
local function DropWeapon()
RunConsoleCommand("zsdropweapon", GAMEMODE.InventoryMenu.SelInv)
end
local function EmptyClip()
RunConsoleCommand("zsemptyclip")
end
local function DismantleWeapon()
RunConsoleCommand("zs_dismantle", GAMEMODE.InventoryMenu.SelInv)
end
local function AltSelItemUpd()
local activeweapon = MySelf:GetActiveWeapon()
if not activeweapon or not activeweapon:IsValid() then return end
local actwclass = activeweapon:GetClass()
GAMEMODE.HumanMenuPanel.SelectedItemLabel:SetText(weapons.Get(actwclass).PrintName)
end
function GM:DoAltSelectedItemUpdate()
if self.InventoryMenu.SelInv then
self.HumanMenuPanel.SelectedItemLabel:SetText(self.ZSInventoryItemData[self.InventoryMenu.SelInv].PrintName)
else
timer.Simple(0.25, AltSelItemUpd)
end
end
function GM:HumanMenu()
if self.ZombieEscape then return end
local ent = MySelf:MeleeTrace(48, 2, nil, nil, true).Entity
if self:ValidMenuLockOnTarget(MySelf, ent) then
self.HumanMenuLockOn = ent
else
self.HumanMenuLockOn = nil
end
self:OpenInventory()
if self.HumanMenuPanel and self.HumanMenuPanel:IsValid() then
self.HumanMenuPanel:SetVisible(true)
self.HumanMenuPanel:OpenMenu()
self:DoAltSelectedItemUpdate()
return
end
local panel = vgui.Create("DSideMenu")
self.HumanMenuPanel = panel
local screenscale = BetterScreenScale()
for k, v in pairs(self.AmmoNames) do
local b = vgui.Create("DAmmoCounter", panel)
b:SetAmmoType(k)
b:SetTall(math.max(32, screenscale * 36))
panel:AddItem(b)
end
local hei = draw_GetFontHeight("ZSHUDFontSmall")
local selecteditemtitle = EasyLabel(panel, "Selected Item", "ZSHUDFontSmall", color_white)
selecteditemtitle:SetContentAlignment(5)
panel:AddItem(selecteditemtitle)
local selecteditemlabel = EasyLabel(panel, "Fists", "ZSHUDFontSmaller", color_white)
selecteditemlabel:SetContentAlignment(5)
panel:AddItem(selecteditemlabel)
panel.SelectedItemLabel = selecteditemlabel
local gwbtn = vgui.Create("DButton")
gwbtn:SetFont("ZSHUDFontSmaller")
gwbtn:SetText("Give Item")
gwbtn:SetSize(panel:GetWide() - 8 * screenscale, hei - 4 * screenscale)
gwbtn:CenterHorizontal()
gwbtn.DoClick = GiveWeapon
panel:AddItem(gwbtn)
gwbtn = vgui.Create("DButton")
gwbtn:SetFont("ZSHUDFontSmaller")
gwbtn:SetText("Give Item and 5 clips")
gwbtn:SetSize(panel:GetWide() - 8 * screenscale, hei - 4 * screenscale)
gwbtn:CenterHorizontal()
gwbtn.DoClick = GiveWeaponClip
panel:AddItem(gwbtn)
gwbtn = vgui.Create("DButton")
gwbtn:SetFont("ZSHUDFontSmaller")
gwbtn:SetText("Drop Item")
gwbtn:SetSize(panel:GetWide() - 8 * screenscale, hei - 4 * screenscale)
gwbtn:CenterHorizontal()
gwbtn.DoClick = DropWeapon
panel:AddItem(gwbtn)
gwbtn = vgui.Create("DButton")
gwbtn:SetFont("ZSHUDFontSmaller")
gwbtn:SetText("Empty Weapon Clip")
gwbtn:SetSize(panel:GetWide() - 8 * screenscale, hei - 4 * screenscale)
gwbtn:CenterHorizontal()
gwbtn.DoClick = EmptyClip
panel:AddItem(gwbtn)
gwbtn = vgui.Create("DButton")
gwbtn:SetFont("ZSHUDFontSmaller")
gwbtn:SetText("Dismantle Item")
gwbtn:SetSize(panel:GetWide() - 8 * screenscale, hei - 4 * screenscale)
gwbtn:CenterHorizontal()
gwbtn.DoClick = DismantleWeapon
panel:AddItem(gwbtn)
panel:AddItem(EasyLabel(panel, "Resupply Ammo Selection", "DefaultFont", color_white))
local dropdown = vgui.Create("DComboBox", panel)
dropdown:SetMouseInputEnabled(true)
dropdown:AddChoice("Resupply Held Weapon")
for k,v in pairs(self.AmmoResupply) do
dropdown:AddChoice(self.AmmoNames[k])
end
dropdown.OnSelect = function(me, index, value, data)
if value == "Resupply Held Weapon" then
MySelf.ResupplyChoice = nil
RunConsoleCommand("zs_resupplyammotype", "default")
return
end
for k,v in pairs(self.AmmoNames) do
if value == v then
MySelf.ResupplyChoice = k
RunConsoleCommand("zs_resupplyammotype", k)
break
end
end
end
dropdown:SetText("Resupply Held Weapon")
dropdown:SetTextColor(color_black)
panel:AddItem(dropdown)
self.HumanMenuSupplyChoice = dropdown
panel:OpenMenu()
end
function GM:ZombieSpawnMenu()
if self.ZombieEscape then return end
if self.ZSpawnMenu and self.ZSpawnMenu:IsValid() then
self.ZSpawnMenu:SetVisible(true)
self.ZSpawnMenu:OpenMenu()
self.ZSpawnMenu:RefreshContents()
return
end
local panel = vgui.Create("DZombieSpawnMenu")
self.ZSpawnMenu = panel
panel:OpenMenu()
end
function GM:PlayerBindPress(pl, bind, wasin)
if bind == "gmod_undo" or bind == "undo" then
RunConsoleCommand("+zoom")
timer.Create("ReleaseZoom", 1, 1, function() RunConsoleCommand("-zoom") end)
elseif bind == "+menu_context" then
if P_Team(pl) == TEAM_UNDEAD then
self.ZombieThirdPerson = not self.ZombieThirdPerson
elseif P_Team(pl) == TEAM_HUMAN then
self:ToggleOTSCamera()
end
elseif bind == "impulse 100" then
if P_Team(pl) == TEAM_UNDEAD and pl:Alive() then
self:ToggleZombieVision()
end
end
end
function GM:_ShouldDrawLocalPlayer(pl)
return FROM_CAMERA or P_Team(pl) == TEAM_UNDEAD and (self.ZombieThirdPerson or pl:CallZombieFunction0("ShouldDrawLocalPlayer"))
or P_Team(pl) == TEAM_HUMAN and self:UseOverTheShoulder()
or pl:IsPlayingTaunt()
or pl.Revive and pl.Revive:IsValid()
or pl.KnockedDown and pl.KnockedDown:IsValid()
end
local roll = 0
function GM:_CalcView(pl, origin, angles, fov, znear, zfar)
if pl.Confusion and pl.Confusion:IsValid() then
pl.Confusion:CalcView(pl, origin, angles, fov, znear, zfar)
end
if pl.Revive and pl.Revive:IsValid() and pl.Revive.GetRagdollEyes then
if self.ThirdPersonKnockdown or self.ZombieThirdPerson then
origin = pl:GetThirdPersonCameraPos(origin, angles)
else
local rpos, rang = pl.Revive:GetRagdollEyes(pl)
if rpos then
origin = rpos
angles = rang
end
end
elseif pl.KnockedDown and pl.KnockedDown:IsValid() then
if self.ThirdPersonKnockdown or self:UseOverTheShoulder() then
origin = pl:GetThirdPersonCameraPos(origin, angles)
else
local rpos, rang = self:GetRagdollEyes(pl)
if rpos then
origin = rpos
angles = rang
end
end
elseif pl:ShouldDrawLocalPlayer() and pl:OldAlive() and not pl:HasWon() then
if P_Team(pl) == TEAM_UNDEAD then
origin = pl:GetThirdPersonCameraPos(origin, angles)
elseif self:UseOverTheShoulder() then
self:CalcViewOTS(pl, origin, angles, fov, znear, zfar)
end
end
local targetroll = 0
if self.MovementViewRoll then
local dir = pl:GetVelocity()
local speed = dir:Length()
dir:Normalize()
targetroll = targetroll + dir:Dot(angles:Right()) * math.min(30, speed / 100)
end
if pl:WaterLevel() >= 3 then
targetroll = targetroll + math.sin(CurTime()) * 7
end
roll = math.Approach(roll, targetroll, math.max(0.25, math.sqrt(math.abs(roll))) * 30 * FrameTime())
angles.roll = angles.roll + roll
if pl:IsPlayingTaunt() then
self:CalcViewTaunt(pl, origin, angles, fov, znear, zfar)
end
local target = pl:GetObserverTarget()
if target and target:IsValid() then
local lasttarget = self.LastObserverTarget
if lasttarget and lasttarget:IsValid() and target ~= lasttarget then
if self.LastObserverTargetLerp then
if CurTime() >= self.LastObserverTargetLerp then
self.LastObserverTarget = nil
self.LastObserverTargetLerp = nil
else
local delta = math.Clamp((self.LastObserverTargetLerp - CurTime()) / 0.3333, 0, 1) ^ 0.5
origin:Set(self.LastObserverTargetPos * delta + origin * (1 - delta))
end
else
self.LastObserverTargetLerp = CurTime() + 0.3333
end
else
self.LastObserverTarget = target
self.LastObserverTargetPos = origin
end
end
if pl:GetObserverMode() ~= OBS_MODE_NONE then
angles.roll = 0 --Fixes babies tilting the screen
end
pl:CallZombieFunction2("CalcView", origin, angles)
return self.BaseClass.CalcView(self, pl, origin, angles, fov, znear, zfar)
end
function GM:CalcViewTaunt(pl, origin, angles, fov, znear, zfar)
local tr = util.TraceHull({start = origin, endpos = origin - angles:Forward() * 72, mins = Vector(-2, -2, -2), maxs = Vector(2, 2, 2), mask = MASK_OPAQUE, filter = pl})
origin:Set(tr.HitPos + tr.HitNormal * 2)
end
function GM:CreateMoveTaunt(cmd)
cmd:ClearButtons(0)
cmd:ClearMovement()
end
function GM:PostProcessPermitted(str)
return false
end
function GM:HUDPaintEndRound()
end
function GM:PreDrawViewModel(vm, pl, wep)
if pl and pl:IsValid() and (pl:IsHolding() or GAMEMODE.HideViewModels) then return true end
if wep and wep:IsValid() and wep.PreDrawViewModel then
return wep:PreDrawViewModel(vm)
end
end
function GM:PostDrawViewModel(vm, pl, wep)
if wep and wep:IsValid() then
if wep.UseHands or not wep:IsScripted() then
local hands = pl:GetHands()
if hands and hands:IsValid() then
hands:DrawModel()
end
end
if wep.PostDrawViewModel then
wep:PostDrawViewModel(vm)
end
end
end
local undo = false
local matWhite = Material("models/debug/debugwhite")
local lowhealthcolor = GM.AuraColorEmpty
local fullhealthcolor = GM.AuraColorFull
function GM:_PrePlayerDraw(pl)
local shadowman = false
if pl ~= MySelf and pl:IsEffectActive(EF_DIMLIGHT) then
pl:RemoveEffects(EF_DIMLIGHT)
end
local myteam = P_Team(MySelf)
local theirteam = P_Team(pl)
local radius = self.TransparencyRadius
if radius > 0 and myteam == theirteam and pl ~= MySelf and not (GAMEMODE.AlwaysDrawFriend and pl:IsFriend()) and not self.MedicalAura then
local dist = pl:GetPos():DistToSqr(EyePos())
if dist < radius then
local blend = (dist / radius) ^ 1.4
if blend <= 0.1 then
pl.ShadowMan = true return true
end
render_SetBlend(blend)
if myteam == TEAM_HUMAN and blend < 0.5 then
render_ModelMaterialOverride(matWhite)
render_SetColorModulation(0.2, 0.2, 0.2)
shadowman = true
end
undo = true
end
end
pl.ShadowMan = shadowman
if pl:CallZombieFunction0("PrePlayerDraw") then return true end
if pl.SpawnProtection and (not (pl.status_overridemodel and pl.status_overridemodel:IsValid()) or pl:GetZombieClassTable().NoHideMainModel) then
undo = true
render_ModelMaterialOverride(matWhite)
render_SetBlend(0.02 + (CurTime() + pl:EntIndex() * 0.2) % 0.05)
render_SetColorModulation(0, 0.3, 0)
render_SuppressEngineLighting(true)
end
if self.m_ZombieVision and myteam == TEAM_UNDEAD and theirteam == TEAM_HUMAN then
local dist = pl:GetPos():DistToSqr(EyePos())
if dist <= pl:GetAuraRangeSqr() and (not pl:GetDTBool(DT_PLAYER_BOOL_NECRO) or dist >= 27500) then
undo = true
local healthfrac = pl:Health() / pl:GetMaxHealth()
render_SetBlend(1)
render_ModelMaterialOverride(matWhite)
render_SetColorModulation(
Lerp(healthfrac, lowhealthcolor.r, fullhealthcolor.r) / 255,
Lerp(healthfrac, lowhealthcolor.g, fullhealthcolor.g) / 255,
Lerp(healthfrac, lowhealthcolor.b, fullhealthcolor.b) / 255
)
render_SuppressEngineLighting(true)
cam_IgnoreZ(true)
end
end
end
local colFriend = Color(10, 255, 10, 60)
local matFriendRing = Material("SGM/playercircle")
local matTargetTri = Material("gui/point.png")
function GM:_PostPlayerDraw(pl)
pl:CallZombieFunction0("PostPlayerDraw")
if undo then
render_SetBlend(1)
render_ModelMaterialOverride()
render_SetColorModulation(1, 1, 1)
render_SuppressEngineLighting(false)
cam_IgnoreZ(false)
undo = false
end
local eyepos, ang, tpos, distance, hpf
if MySelf.TargetLocus and self.TraceTargetTeam == pl and pl:IsValidLivingZombie() and not pl:GetZombieClassTable().IgnoreTargetAssist then
tpos = pl:GetPos()
tpos.z = tpos.z + 80
eyepos = MySelf:EyePos()
distance = eyepos:DistToSqr(tpos)
ang = (eyepos - tpos):Angle()
ang:RotateAroundAxis(ang:Right(), 270)
ang:RotateAroundAxis(ang:Up(), 90)
cam_IgnoreZ(true)
cam_Start3D2D(tpos, ang, math.max(750, math.sqrt(distance)) / 6500)
surface_SetMaterial(matTargetTri)
hpf = pl:Health() / pl:GetMaxZombieHealth()
surface_SetDrawColor(255 - (255 * hpf), 255 * hpf, 0, 230)
surface_DrawTexturedRect(-96, -96, 96, 96)
cam_End3D2D()
cam_IgnoreZ(false)
end
if pl ~= MySelf and P_Team(MySelf) == P_Team(pl) and pl:IsFriend() then
local pos = pl:GetPos()
pos.z = pos.z + 2
render_SetMaterial(matFriendRing)
render_DrawQuadEasy(pos, vector_up, 32, 32, colFriend)
render_DrawQuadEasy(pos, vector_down, 32, 32, colFriend)
end
end
function GM:HUDPaintBackgroundEndRound()
local x, y = ScrW() / 2, ScrH() * 0.8
local timleft = math.max(0, self.EndTime + self.EndGameTime - CurTime())
if timleft <= 0 then
draw_SimpleTextBlur(translate.Get("loading"), "ZSHUDFont", x, y, COLOR_WHITE, TEXT_ALIGN_CENTER)
else
draw_SimpleTextBlur(translate.Format("next_round_in_x", util.ToMinutesSecondsCD(timleft)), "ZSHUDFontSmall", x, y, COLOR_WHITE, TEXT_ALIGN_CENTER)
end
end
local function EndRoundCalcView(pl, origin, angles, fov, znear, zfar)
if GAMEMODE.EndTime and CurTime() < GAMEMODE.EndTime + 5 then
local endposition = GAMEMODE.LastHumanPosition
local override = GetGlobalVector("endcamerapos", vector_origin)
if override ~= vector_origin then
endposition = override
end
if endposition then
local delta = math.Clamp((CurTime() - GAMEMODE.EndTime) * 2, 0, 1)
local start = endposition * delta + origin * (1 - delta)
local tr = util.TraceHull({start = start, endpos = start + delta * 64 * Angle(0, CurTime() * 30, 0):Forward(), mins = Vector(-2, -2, -2), maxs = Vector(2, 2, 2), filter = player.GetAll(), mask = MASK_SOLID})
return {origin = tr.HitPos + tr.HitNormal, angles = (start - tr.HitPos):Angle()}
end
return
end
hook.Remove("CalcView", "EndRoundCalcView")
end
local function EndRoundShouldDrawLocalPlayer(pl)
if GAMEMODE.EndTime and CurTime() < GAMEMODE.EndTime + 5 then
return true
end
hook.Remove("ShouldDrawLocalPlayer", "EndRoundShouldDrawLocalPlayer")
end
function GM:EndRound(winner, nextmap)
if self.RoundEnded then return end
self.RoundEnded = true
ROUNDWINNER = winner
self.EndTime = CurTime()
RunConsoleCommand("stopsound")
self.HUDPaint = self.HUDPaintEndRound
self.HUDPaintBackground = self.HUDPaintBackgroundEndRound
if winner == TEAM_UNDEAD and GetGlobalBool("endcamera", true) then
hook.Add("CalcView", "EndRoundCalcView", EndRoundCalcView)
hook.Add("ShouldDrawLocalPlayer", "EndRoundShouldDrawLocalPlayer", EndRoundShouldDrawLocalPlayer)
end
local dvar = winner == TEAM_UNDEAD and self.AllLoseSound or self.HumanWinSound
local snd = GetGlobalString(winner == TEAM_UNDEAD and "losemusic" or "winmusic", dvar)
if snd == "default" then
snd = dvar
elseif snd == "none" then
snd = nil
end
if snd then
timer.Simple(0.5, function() surface_PlaySound(snd) end)
end
timer.Simple(5, function()
if not (pEndBoard and pEndBoard:IsValid()) then
MakepEndBoard(winner)
end
end)
end
function GM:WeaponDeployed(pl, wep)
self:DoChangeDeploySpeed(wep)
end
function GM:LocalPlayerDied(attackername)
LASTDEATH = RealTime()
surface_PlaySound(self.DeathSound)
if attackername then
self:CenterNotify(COLOR_RED, {font = "ZSHUDFont"}, translate.Get("you_have_died"))
self:CenterNotify(COLOR_RED, translate.Format(self.PantsMode and "you_were_kicked_by_x" or "you_were_killed_by_x", tostring(attackername)))
else
self:CenterNotify(COLOR_RED, {font = "ZSHUDFont"}, translate.Get("you_have_died"))
end
end
function GM:KeyPress(pl, key)
if key == self.MenuKey then
local team = P_Team(pl)
if team == TEAM_HUMAN and pl:Alive() and not pl:IsHolding() then
gamemode.Call("HumanMenu")
elseif team == TEAM_ZOMBIE and not pl:Alive() then
gamemode.Call("ZombieSpawnMenu")
end
elseif key == IN_SPEED then
if pl:Alive() then
if P_Team(pl) == TEAM_HUMAN then
pl:DispatchAltUse()
elseif P_Team(pl) == TEAM_UNDEAD then
pl:CallZombieFunction0("AltUse")
end
end
end
end
function GM:KeyRelease(pl, key)
if key == self.MenuKey then
if self.HumanMenuPanel and self.HumanMenuPanel:IsValid() then
if self.InventoryMenu and self.InventoryMenu:IsValid() then
self.InventoryMenu:SetVisible(false)
if self.m_InvViewer and self.m_InvViewer:IsValid() then
self.m_InvViewer:SetVisible(false)
end
end
if self.HumanMenuSupplyChoice then
self.HumanMenuSupplyChoice:CloseMenu()
end
if self.InventoryMenu.SelInv then
self.InventoryMenu.SelInv = nil
self:DoAltSelectedItemUpdate()
local grid = self.InventoryMenu.Grid
for k, v in pairs(grid:GetChildren()) do
v.On = false
end
end
end
end
end
function GM:PlayerStepSoundTime(pl, iType, bWalking)
local time = pl:CallZombieFunction2("PlayerStepSoundTime", iType, bWalking)
if time then
return time
end
if iType == STEPSOUNDTIME_NORMAL or iType == STEPSOUNDTIME_WATER_FOOT then
return 520 - pl:GetVelocity():Length()
end
if iType == STEPSOUNDTIME_ON_LADDER then
return 500
end
if iType == STEPSOUNDTIME_WATER_KNEE then
return 650
end
return 350
end
function GM:PlayerFootstep(pl, vFootPos, iFoot, strSoundName, fVolume)
return pl:CallZombieFunction4("PlayerFootstep", vFootPos, iFoot, strSoundName, fVolume)
end
function GM:PlayerCanCheckout(pl)
return pl:IsValid() and P_Team(pl) == TEAM_HUMAN and pl:Alive() and self:GetWave() <= 0
end
function GM:OpenWorth()
if gamemode.Call("PlayerCanCheckout", MySelf) then
MakepWorth()
end
end
function GM:CloseWorth()
if pWorth and pWorth:IsValid() then
pWorth:Remove()
pWorth = nil
end
end
function GM:SuppressArsenalUpgrades(suppresstime)
self.SuppressArsenalTime = math.max(CurTime() + suppresstime, self.SuppressArsenalTime)
end
function GM:Rewarded(class, amount)
if CurTime() < self.SuppressArsenalTime then return end
class = class or "0"
local toptext = translate.Get("arsenal_upgraded")
local wep = weapons.Get(class)
if wep and wep.PrintName and #wep.PrintName > 0 then
if killicon.Get(class) == killicon.Get("default") then
self:CenterNotify(COLOR_PURPLE, toptext..": ", color_white, wep.PrintName)
else
self:CenterNotify({killicon = class}, " ", COLOR_PURPLE, toptext..": ", color_white, wep.PrintName)
end
elseif amount then
self:CenterNotify(COLOR_PURPLE, toptext..": ", color_white, amount.." "..class)
else
self:CenterNotify(COLOR_PURPLE, toptext)
end
end
function PlayMenuOpenSound()
MySelf:EmitSound("buttons/lightswitch2.wav", 100, 30)
end
function PlayMenuCloseSound()
MySelf:EmitSound("buttons/lightswitch2.wav", 100, 20)
end