zombiesurvival-evolved/gamemodes/zombiesurvival/gamemode/cl_init.lua
2014-12-07 15:02:40 -05:00

1831 lines
59 KiB
Lua

-- Sometimes persistent ones don't get created.
-- 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("shared.lua")
include("cl_draw.lua")
include("cl_util.lua")
include("cl_options.lua")
include("obj_player_extend_cl.lua")
include("cl_scoreboard.lua")
include("cl_targetid.lua")
include("cl_postprocess.lua")
include("vgui/dgamestate.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/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/ppointshop.lua")
include("vgui/dpingmeter.lua")
include("vgui/dsidemenu.lua")
include("vgui/zshealtharea.lua")
include("cl_dermaskin.lua")
include("cl_deathnotice.lua")
include("cl_floatingscore.lua")
include("cl_hint.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")
end)
-- Remove when model decal crash is fixed.
function util.Decal()
end
-- Save on global lookup time.
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 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 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 surface_SetFont = surface.SetFont
local surface_SetTexture = surface.SetTexture
local surface_SetMaterial = surface.SetMaterial
local surface_SetDrawColor = surface.SetDrawColor
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 draw_SimpleText = draw.SimpleText
local draw_SimpleTextBlurry = draw.SimpleTextBlurry
local draw_SimpleTextBlur = draw.SimpleTextBlur
local draw_GetFontHeight = draw.GetFontHeight
local MedicalAuraDistance = 300
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.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:Valid() then
return self.CenterNotificationHUD:AddNotification(...)
end
end
function GM:TopNotify(...)
if self.TopNotificationHUD and self.TopNotificationHUD:Valid() then
return self.TopNotificationHUD:AddNotification(...)
end
end
function GM:_InputMouseApply(cmd, x, y, ang)
self.InputMouseX = x
self.InputMouseY = y
if MySelf:KeyDown(IN_WALK) and MySelf:IsHolding() then
RunConsoleCommand("_zs_rotateang", self.InputMouseX, self.InputMouseY)
return true
end
end
function GM:_GUIMousePressed(mc)
if self.HumanMenuPanel and self.HumanMenuPanel:Valid() and self.HumanMenuPanel:IsVisible() and MySelf:KeyDown(self.MenuKey) then
local dir = gui.ScreenToVector(gui.MousePos())
local ent = util.TraceLine({start = MySelf:EyePos(), endpos = MySelf:EyePos() + dir * self.CraftingRange, filter = MySelf, mask = MASK_SOLID}).Entity
if ent:IsValid() and not ent:IsPlayer() and (ent:GetMoveType() == MOVETYPE_NONE or ent:GetMoveType() == MOVETYPE_VPHYSICS) and ent:GetSolid() == SOLID_VPHYSICS then
if mc == MOUSE_LEFT then
if ent == self.CraftingEntity then
self.CraftingEntity = nil
else
self.CraftingEntity = ent
end
elseif mc == MOUSE_RIGHT and self.CraftingEntity and self.CraftingEntity:IsValid() then
RunConsoleCommand("_zs_craftcombine", self.CraftingEntity:EntIndex(), ent:EntIndex())
self.CraftingEntity = nil
end
end
end
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)
end
function GM:_HUDWeaponPickedUp(wep)
if MySelf:Team() == 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()
if not self.HealthHUD then
self.HealthHUD = vgui.Create("ZSHealthArea")
end
self:LocalPlayerFound()
self:EvaluateFilmMode()
timer.Simple(2, function() GAMEMODE:GetFogData() end)
end
function GM:SetupWorldFog()
if self.DeathFog == 0 then return end
local power = self.DeathFog
local rpower = 1 - self.DeathFog
local fogstart = self.FogStart * rpower
local fogend = self.FogEnd * rpower + 150 * power
local fogr = self.FogRed * rpower
local fogg = self.FogGreen * rpower + 40 * power
local fogb = self.FogBlue * rpower
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 then return end
local power = self.DeathFog
local rpower = 1 - self.DeathFog
local fogstart = self.FogStart * rpower
local fogend = self.FogEnd * rpower + 150 * power
local fogr = self.FogRed * rpower
local fogg = self.FogGreen * rpower + 40 * power
local fogb = self.FogBlue * rpower
local fogdensity = 1 - power * 0.1
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
if self.DeathFog == 0 then return end
colSky.a = self.DeathFog * 230
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
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
local matAura = Material("models/debug/debugwhite")
local skip = false
function GM.PostPlayerDrawMedical(pl)
if not skip and pl:Team() == TEAM_HUMAN and pl ~= LocalPlayer() then
local eyepos = EyePos()
local dist = pl:NearestPoint(eyepos):Distance(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, 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.
function GM:LocalPlayerFound()
self.Think = self._Think
self.HUDShouldDraw = self._HUDShouldDraw
self.CachedFearPower = self._CachedFearPower
self.CalcView = self._CalcView
self.ShouldDrawLocalPlayer = self._ShouldDrawLocalPlayer
self.PostDrawOpaqueRenderables = self._PostDrawOpaqueRenderables
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
if render.GetDXLevel() >= 80 then
self.RenderScreenspaceEffects = self._RenderScreenspaceEffects
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")
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 wid, hei = 192 * screenscale, 192 * screenscale
local mx, my = w * 0.5 - wid * 0.5, h - hei
surface_SetMaterial(matFearMeter)
surface_SetDrawColor(140, 140, 140, 240)
surface_DrawTexturedRect(mx, my, wid, hei)
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, wid + pulsesize * 2, hei + 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 * wid * -0.0001), h - hei * 0.5 - math.abs(rot) * hei * 0.00015, wid, hei, rot)
if MySelf:Team() == 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 + hei * 0.6953
local size = wid * 0.085
surface_SetMaterial(matEyeGlow)
surface_SetDrawColor(220 * (1 - spawngreen), 220 * spawngreen, 0, 240)
surface_DrawTexturedRectRotated(mx + wid * 0.459, sy, size, size, 0)
surface_DrawTexturedRectRotated(mx + wid * 0.525, sy, size, size, 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 + hei * 0.75, Color(currentpower * 200, 200 - currentpower * 200, 0, 255), TEXT_ALIGN_CENTER)
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()
if self.m_ZombieVision and MySelf:IsValid() and MySelf:Team() == TEAM_UNDEAD then
local eyepos = EyePos()
local eyedir = EyeAngles():Forward()
local tr = util.TraceLine({start = eyepos, endpos = eyepos + eyedir * 128, mask = MASK_SOLID_BRUSHONLY})
local dlight = DynamicLight(MySelf:EntIndex())
if dlight then
dlight.Pos = tr.HitPos + tr.HitNormal * 2
dlight.r = 10
dlight.g = 255
dlight.b = 80
dlight.Brightness = 3
dlight.Size = 300
dlight.Decay = 900
dlight.DieTime = CurTime() + 1
end
end
end
local lastwarntim = -1
local NextGas = 0
function GM:_Think()
if self:GetEscapeStage() == ESCAPESTAGE_DEATH then
self.DeathFog = math.min(self.DeathFog + FrameTime() / 5, 1)
if CurTime() >= NextGas then
NextGas = CurTime() + 0.01
local eyepos = EyePos()
local emitter = ParticleEmitter(eyepos)
for i=1, 3 do
local randdir = VectorRand()
randdir.z = math.abs(randdir.z)
randdir:Normalize()
local emitpos = eyepos + randdir * math.Rand(0, 1200)
local 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()
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 - CurTime())
if timleft <= 10 and lastwarntim ~= math.ceil(timleft) then
lastwarntim = math.ceil(timleft)
if 0 < lastwarntim then
surface_PlaySound("buttons/lightswitch2.wav")
end
end
end
local myteam = MySelf:Team()
self:PlayBeats(myteam, self:CachedFearPower())
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.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
else
self.HeartBeatTime = self.HeartBeatTime + (6 + self:CachedFearPower() * 5) * FrameTime()
if not MySelf:Alive() then
self:ToggleZombieVision(false)
end
end
for _, pl in pairs(player.GetAll()) do
if pl:Team() == TEAM_UNDEAD then
local tab = pl:GetZombieClassTable()
if tab.BuildBonePositions then
pl.WasBuildingBonePositions = true
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 and cv_ShouldPlayMusic:GetBool() then
MySelf:EmitSound(self.LastHumanSound, 0, 100, self.BeatsVolume)
NextBeat = RealTime() + (self.SoundDuration[snd] or 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
function GM:HumanHUD(screenscale)
local curtime = CurTime()
local w, h = ScrW(), ScrH()
local packup = MySelf.PackUp
if packup and packup:IsValid() then
self:DrawPackUpBar(w * 0.5, h * 0.55, 1 - packup:GetTimeRemaining() / packup:GetMaxTime(), packup:GetNotOwner(), screenscale)
end
if not self.RoundEnded then
if self:GetWave() == 0 and not self:GetWaveActive() then
local txth = draw_GetFontHeight("ZSHUDFontSmall")
draw_SimpleTextBlurry(translate.Get("waiting_for_players").." "..util.ToMinutesSeconds(math.max(0, self:GetWaveStart() - curtime)), "ZSHUDFontSmall", w * 0.5, h * 0.25, COLOR_GRAY, TEXT_ALIGN_CENTER)
draw_SimpleTextBlurry(translate.Get("humans_closest_to_spawns_are_zombies"), "ZSHUDFontSmall", w * 0.5, h * 0.25 + txth, COLOR_GRAY, TEXT_ALIGN_CENTER)
local desiredzombies = self:GetDesiredStartingZombies()
draw_SimpleTextBlurry(translate.Format("number_of_initial_zombies_this_game", self.WaveOneZombies * 100, desiredzombies), "ZSHUDFontSmall", w * 0.5, h * 0.75, COLOR_GRAY, TEXT_ALIGN_CENTER)
draw_SimpleTextBlurry(translate.Get("zombie_volunteers"), "ZSHUDFontSmall", w * 0.5, h * 0.75 + txth, COLOR_GRAY, TEXT_ALIGN_CENTER)
local y = h * 0.75 + txth * 2
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_RED or COLOR_GRAY, TEXT_ALIGN_CENTER)
y = y + txth
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_BLUE, TEXT_ALIGN_RIGHT, TEXT_ALIGN_CENTER)
end
end
if gamemode.Call("PlayerCanPurchase", MySelf) then
if self:GetWaveActive() then
draw_SimpleTextBlurry(translate.Get("press_f2_for_the_points_shop"), "ZSHUDFontSmall", w * 0.5, 8, COLOR_GRAY, TEXT_ALIGN_CENTER)
else
local th = draw_GetFontHeight("ZSHUDFontSmall")
draw_SimpleTextBlurry(translate.Get("press_f2_for_the_points_shop"), "ZSHUDFontSmall", w * 0.5, 8, COLOR_GRAY, TEXT_ALIGN_CENTER)
draw_SimpleTextBlurry(translate.Format("x_discount_for_buying_between_waves", self.ArsenalCrateDiscountPercentage), "ZSHUDFontSmall", w * 0.5, 9 + th, COLOR_GRAY, TEXT_ALIGN_CENTER)
end
end
end
function GM:HUDPaint()
end
function GM:_HUDPaint()
if self.FilmMode then return end
local screenscale = BetterScreenScale()
local myteam = MySelf:Team()
self:HUDDrawTargetID(myteam, screenscale)
if self:GetWave() > 0 then
self:DrawFearMeter(self:CachedFearPower(), screenscale)
end
if myteam == TEAM_UNDEAD then
self:ZombieHUD()
else
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_TOP)
end
end
function GM:ZombieObserverHUD(obsmode)
local w, h = ScrW(), ScrH()
local texh = draw_GetFontHeight("ZSHUDFontSmall")
local dyn
if obsmode == OBS_MODE_CHASE then
local target = MySelf:GetObserverTarget()
if target and target:IsValid() then
if target:IsPlayer() and target:Team() == 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
dyn = self:GetDynamicSpawning() and self:DynamicSpawnIsValid(target)
end
end
if self:GetWaveActive() then
draw_SimpleTextBlur(dyn and translate.Get("press_lmb_to_spawn_on_them") or translate.Get("press_lmb_to_spawn"), "ZSHUDFontSmall", w * 0.5, h * 0.75, dyn and COLOR_DARKGREEN or COLOR_DARKRED, TEXT_ALIGN_CENTER)
end
local space = texh + 8
draw_SimpleTextBlur(translate.Get("press_rmb_to_cycle_targets"), "ZSHUDFontSmall", w * 0.5, h * 0.75 + space, COLOR_DARKRED, TEXT_ALIGN_CENTER)
draw_SimpleTextBlur(translate.Get("press_reload_to_spawn_at_normal_point"), "ZSHUDFontSmall", w * 0.5, h * 0.75 + space * 2, COLOR_DARKRED, TEXT_ALIGN_CENTER)
draw_SimpleTextBlur(translate.Get("press_jump_to_free_roam"), "ZSHUDFontSmall", w * 0.5, h * 0.75 + space * 3, COLOR_DARKRED, TEXT_ALIGN_CENTER)
for _, ent in pairs(ents.FindByClass("prop_thrownbaby")) do
if ent:GetSettled() then
draw_SimpleTextBlur(translate.Format("press_walk_to_spawn_as_x", self.ZombieClasses["Gore Child"].Name), "ZSHUDFontSmall", w * 0.5, h * 0.75 + space * 3, COLOR_DARKRED, TEXT_ALIGN_CENTER)
break
end
end
end
local matHumanHeadID = Material("zombiesurvival/humanhead")
local matZombieHeadID = Material("zombiesurvival/zombiehead")
local colLifeStats = Color(255, 0, 0, 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 self:GetWaveActive() and not MySelf:Alive() then
draw_SimpleTextBlur(translate.Get("waiting_for_next_wave"), "ZSHUDFont", ScrW() * 0.5, ScrH() * 0.3, COLOR_DARKRED, TEXT_ALIGN_CENTER)
if MySelf:GetZombieClassTable().NeverAlive then
for _, ent in pairs(ents.FindByClass("prop_thrownbaby")) do
if ent:GetSettled() then
draw_SimpleTextBlur(translate.Format("press_walk_to_spawn_as_x", self.ZombieClasses["Gore Child"].Name), "ZSHUDFontSmall", w * 0.5, h * 0.75, COLOR_DARKRED, TEXT_ALIGN_CENTER)
break
end
end
end
end
end
function GM:RequestedDefaultCart()
local defaultcart = GetConVarString("zs_defaultcart")
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()
end
end
function GM:RestartRound()
self.TheLastHuman = nil
self.RoundEnded = nil
LASTHUMAN = nil
if pEndBoard and pEndBoard:Valid() then
pEndBoard:Remove()
pEndBoard = nil
end
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
function GM:CreateFonts()
local fontfamily = "Typenoksidi"
local fontfamily3d = "hidden"
local fontweight = 0
local fontweight3D = 0
local fontaa = true
local fontshadow = false
local fontoutline = true
surface.CreateLegacyFont("csd", 42, 500, true, false, "healthsign", false, true)
surface.CreateLegacyFont("tahoma", 96, 1000, true, false, "zshintfont", false, true)
surface.CreateLegacyFont(fontfamily3d, 48, fontweight3D, false, false, "ZS3D2DFontSmall", false, true)
surface.CreateLegacyFont(fontfamily3d, 72, fontweight3D, false, false, "ZS3D2DFont", false, true)
surface.CreateLegacyFont(fontfamily3d, 128, fontweight3D, false, false, "ZS3D2DFontBig", false, true)
surface.CreateLegacyFont(fontfamily3d, 48, fontweight3D, false, false, "ZS3D2DFontSmallBlur", false, false, 16)
surface.CreateLegacyFont(fontfamily3d, 72, fontweight3D, false, false, "ZS3D2DFontBlur", false, false, 16)
surface.CreateLegacyFont(fontfamily3d, 128, fontweight3D, false, false, "ZS3D2DFontBigBlur", false, false, 16)
surface.CreateLegacyFont(fontfamily, 40, fontweight3D, false, false, "ZS3D2DFont2Smaller", false, true)
surface.CreateLegacyFont(fontfamily, 48, fontweight3D, false, false, "ZS3D2DFont2Small", false, true)
surface.CreateLegacyFont(fontfamily, 72, fontweight3D, false, false, "ZS3D2DFont2", false, true)
surface.CreateLegacyFont(fontfamily, 128, fontweight3D, false, false, "ZS3D2DFont2Big", false, true)
surface.CreateLegacyFont(fontfamily, 40, fontweight3D, false, false, "ZS3D2DFont2SmallerBlur", false, false, 16)
surface.CreateLegacyFont(fontfamily, 48, fontweight3D, false, false, "ZS3D2DFont2SmallBlur", false, false, 16)
surface.CreateLegacyFont(fontfamily, 72, fontweight3D, false, false, "ZS3D2DFont2Blur", false, false, 16)
surface.CreateLegacyFont(fontfamily, 128, fontweight3D, false, false, "ZS3D2DFont2BigBlur", false, false, 16)
local screenscale = BetterScreenScale()
surface.CreateLegacyFont("csd", screenscale * 36, 100, true, false, "zsdeathnoticecs", false, true)
surface.CreateLegacyFont("HL2MP", screenscale * 36, 100, true, false, "zsdeathnotice", false, true)
surface.CreateLegacyFont(fontfamily, screenscale * 16, fontweight, fontaa, false, "ZSHUDFontTiny", fontshadow, fontoutline)
surface.CreateLegacyFont(fontfamily, screenscale * 20, fontweight, fontaa, false, "ZSHUDFontSmallest", fontshadow, fontoutline)
surface.CreateLegacyFont(fontfamily, screenscale * 22, fontweight, fontaa, false, "ZSHUDFontSmaller", fontshadow, fontoutline)
surface.CreateLegacyFont(fontfamily, screenscale * 28, fontweight, fontaa, false, "ZSHUDFontSmall", fontshadow, fontoutline)
surface.CreateLegacyFont(fontfamily, screenscale * 42, fontweight, fontaa, false, "ZSHUDFont", fontshadow, fontoutline)
surface.CreateLegacyFont(fontfamily, screenscale * 72, fontweight, fontaa, false, "ZSHUDFontBig", fontshadow, fontoutline)
surface.CreateLegacyFont(fontfamily, screenscale * 16, fontweight, fontaa, false, "ZSHUDFontTinyBlur", false, false, 8)
surface.CreateLegacyFont(fontfamily, screenscale * 22, fontweight, fontaa, false, "ZSHUDFontSmallerBlur", false, false, 8)
surface.CreateLegacyFont(fontfamily, screenscale * 28, fontweight, fontaa, false, "ZSHUDFontSmallBlur", false, false, 8)
surface.CreateLegacyFont(fontfamily, screenscale * 42, fontweight, fontaa, false, "ZSHUDFontBlur", false, false, 8)
surface.CreateLegacyFont(fontfamily, screenscale * 72, fontweight, fontaa, false, "ZSHUDFontBigBlur", false, false, 8)
surface.CreateLegacyFont(fontfamily, screenscale * 16, 0, fontaa, false, "ZSAmmoName", false, false)
surface.CreateLegacyFont(fontfamily, screenscale * 16, fontweight, fontaa, false, "ZSHUDFontTinyNS", false, false)
surface.CreateLegacyFont(fontfamily, screenscale * 20, fontweight, fontaa, false, "ZSHUDFontSmallestNS", false, false)
surface.CreateLegacyFont(fontfamily, screenscale * 22, fontweight, fontaa, false, "ZSHUDFontSmallerNS", false, false)
surface.CreateLegacyFont(fontfamily, screenscale * 28, fontweight, fontaa, false, "ZSHUDFontSmallNS", false, false)
surface.CreateLegacyFont(fontfamily, screenscale * 42, fontweight, fontaa, false, "ZSHUDFontNS", false, false)
surface.CreateLegacyFont(fontfamily, screenscale * 72, fontweight, fontaa, false, "ZSHUDFontBigNS", false, false)
surface.CreateLegacyFont(fontfamily, screenscale * 16, 0, true, false, "ZSDamageResistance", false, true)
surface.CreateLegacyFont(fontfamily, screenscale * 16, 0, true, false, "ZSDamageResistanceBlur", false, true)
surface.CreateLegacyFont(fontfamily, 32, fontweight, true, false, "ZSScoreBoardTitle", false, true)
surface.CreateLegacyFont(fontfamily, 22, fontweight, true, false, "ZSScoreBoardSubTitle", false, true)
surface.CreateLegacyFont(fontfamily, 16, fontweight, true, false, "ZSScoreBoardPlayer", false, true)
surface.CreateLegacyFont(fontfamily, 24, fontweight, true, false, "ZSScoreBoardHeading", false, false)
surface.CreateLegacyFont("arial", 20, 0, true, false, "ZSScoreBoardPlayerSmall", 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("DefaultFontBold", {font = "tahoma", size = 13, weight = 1000, antialias = false})
surface.CreateFont("DefaultFontLarge", {font = "tahoma", size = 16, weight = 0, antialias = false})
end
function GM:EvaluateFilmMode()
local visible = not self.FilmMode
if self.GameStatePanel and self.GameStatePanel:Valid() then
self.GameStatePanel:SetVisible(visible)
end
if self.TopNotificationHUD and self.TopNotificationHUD:Valid() then
self.TopNotificationHUD:SetVisible(visible)
end
if self.CenterNotificationHUD and self.CenterNotificationHUD:Valid() then
self.CenterNotificationHUD:SetVisible(visible)
end
if self.HealthHUD and self.HealthHUD:Valid() then
self.HealthHUD:SetVisible(visible)
end
end
function GM:CreateVGUI()
local screenscale = BetterScreenScale()
self.GameStatePanel = vgui.Create("DGameState")
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)
local screenscale = BetterScreenScale()
pan:SetSize(ScrW() * 0.4, ScrH() * 0.6)
pan:AlignTop(16 * screenscale)
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)
local screenscale = BetterScreenScale()
pan:SetSize(ScrW() * 0.5, ScrH() * 0.35)
pan:CenterHorizontal()
pan:AlignBottom(16 * screenscale)
end
self.CenterNotificationHUD:InvalidateLayout()
self.CenterNotificationHUD:ParentToHUD()
end
function GM:Initialize()
self:CreateFonts()
self:PrecacheResources()
self:CreateVGUI()
self:InitializeBeats()
self:AddCustomAmmo()
end
local function FirstOfGoodType(a)
for _, v in pairs(a) do
local 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:OnPlayerHitGround(pl, inwater, hitfloater, speed)
if inwater then return true end
if pl:Team() == TEAM_UNDEAD then
if pl:GetZombieClassTable().NoFallDamage then return true end
speed = math.max(0, speed - 200)
end
if pl:Team() ~= TEAM_UNDEAD or not pl:GetZombieClassTable().NoFallSlowdown then
pl:RawCapLegDamage(CurTime() + math.min(2, speed * 0.0035))
end
return true
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 MySelf:Team() == 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 pl:Team() ~= attacker:Team() or pl.AllowTeamDamage or attacker.AllowTeamDamage
end
function GM:SetWave(wave)
SetGlobalInt("wave", wave)
end
--[[local texGradientUp = surface.GetTextureID("vgui/gradient_up")
local texGradientDown = surface.GetTextureID("vgui/gradient_down")
local texGradientRight = surface.GetTextureID("vgui/gradient-r")]]
local matFilmGrain = Material("zombiesurvival/filmgrain/filmgrain")
--local color_black = color_black
function GM:_HUDPaintBackground()
--[[local w, h = ScrW(), ScrH()
local bordersize = BetterScreenScale() * 32
surface_SetDrawColor(color_black)
surface_SetTexture(texGradientDown)
surface_DrawTexturedRect(0, 0, w, bordersize)
surface_SetTexture(texGradientUp)
surface_DrawTexturedRect(0, h - bordersize, w, bordersize)
surface_SetTexture(texGradientRight)
surface_DrawTexturedRectRotated(bordersize / 2, h / 2, bordersize, h, 180)
surface_DrawTexturedRect(w - bordersize, 0, bordersize, h)]]
if self.FilmGrainEnabled and MySelf:Team() == TEAM_HUMAN 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()
RunConsoleCommand("zsgiveweapon")
end
local function GiveWeaponClip()
RunConsoleCommand("zsgiveweaponclip")
end
local function DropWeapon()
RunConsoleCommand("zsdropweapon")
end
local function EmptyClip()
RunConsoleCommand("zsemptyclip")
end
function GM:HumanMenu()
if self.ZombieEscape then return end
local ent = MySelf:MeleeTrace(48, 2).Entity
if self:ValidMenuLockOnTarget(MySelf, ent) then
self.HumanMenuLockOn = ent
else
self.HumanMenuLockOn = nil
end
if self.HumanMenuPanel and self.HumanMenuPanel:Valid() then
self.HumanMenuPanel:SetVisible(true)
self.HumanMenuPanel:OpenMenu()
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(screenscale * 36)
panel:AddItem(b)
end
local b = EasyButton(panel, "Give Weapon", 8, 4)
b.DoClick = GiveWeapon
panel:AddItem(b)
b = EasyButton(panel, "Give Weapon and 5 clips", 8, 4)
b.DoClick = GiveWeaponClip
panel:AddItem(b)
b = EasyButton(panel, "Drop weapon", 8, 4)
b.DoClick = DropWeapon
panel:AddItem(b)
b = EasyButton(panel, "Empty clip", 8, 4)
b.DoClick = EmptyClip
panel:AddItem(b)
panel:OpenMenu()
end
function GM:PlayerBindPress(pl, bind, wasin)
if bind == "gmod_undo" or bind == "undo" then
RunConsoleCommand("+zoom")
timer.CreateEx("ReleaseZoom", 1, 1, RunConsoleCommand, "-zoom")
elseif bind == "+menu_context" then
self.ZombieThirdPerson = not self.ZombieThirdPerson
end
end
function GM:_ShouldDrawLocalPlayer(pl)
return pl:Team() == TEAM_UNDEAD and (self.ZombieThirdPerson or pl:CallZombieFunction("ShouldDrawLocalPlayer")) or pl:IsPlayingTaunt()
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
local rpos, rang = pl.Revive:GetRagdollEyes(pl)
if rpos then
origin = rpos
angles = rang
end
elseif pl.KnockedDown and pl.KnockedDown:IsValid() then
local rpos, rang = self:GetRagdollEyes(pl)
if rpos then
origin = rpos
angles = rang
end
elseif pl:ShouldDrawLocalPlayer() and pl:OldAlive() then
origin = pl:GetThirdPersonCameraPos(origin, angles)
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, zclose, 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
pl:CallZombieFunction("CalcView", origin, angles)
return self.BaseClass.CalcView(self, pl, origin, angles, fov, znear, zfar)
end
function GM:CalcViewTaunt(pl, origin, angles, fov, zclose, 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
local staggerdir = VectorRand():GetNormalized()
function GM:_CreateMove(cmd)
if MySelf:IsPlayingTaunt() and MySelf:Alive() then
self:CreateMoveTaunt(cmd)
return
end
if MySelf:GetLegDamage() >= 0.5 then
local buttons = cmd:GetButtons()
if bit.band(buttons, IN_JUMP) ~= 0 then
cmd:SetButtons(buttons - IN_JUMP)
end
end
if MySelf:Team() == TEAM_HUMAN then
if MySelf:Alive() then
local lockon = self.HumanMenuLockOn
if lockon then
if self:ValidMenuLockOnTarget(MySelf, lockon) and self.HumanMenuPanel and self.HumanMenuPanel:Valid() and self.HumanMenuPanel:IsVisible() and MySelf:KeyDown(self.MenuKey) then
local oldang = cmd:GetViewAngles()
local newang = (lockon:EyePos() - EyePos()):Angle()
--oldang.pitch = math.ApproachAngle(oldang.pitch, newang.pitch, FrameTime() * math.max(45, math.abs(math.AngleDifference(oldang.pitch, newang.pitch)) ^ 1.3))
oldang.yaw = math.ApproachAngle(oldang.yaw, newang.yaw, FrameTime() * math.max(45, math.abs(math.AngleDifference(oldang.yaw, newang.yaw)) ^ 1.3))
cmd:SetViewAngles(oldang)
else
self.HumanMenuLockOn = nil
end
else
local maxhealth = MySelf:GetMaxHealth()
local threshold = MySelf:GetPalsy() and maxhealth - 1 or maxhealth * 0.25
local health = MySelf:Health()
if health <= threshold then
local ft = FrameTime()
staggerdir = (staggerdir + ft * 8 * VectorRand()):GetNormalized()
local ang = cmd:GetViewAngles()
local rate = ft * ((threshold - health) / threshold) * 7
ang.pitch = math.NormalizeAngle(ang.pitch + staggerdir.z * rate)
ang.yaw = math.NormalizeAngle(ang.yaw + staggerdir.x * rate)
cmd:SetViewAngles(ang)
end
end
end
else
local buttons = cmd:GetButtons()
if bit.band(buttons, IN_ZOOM) ~= 0 then
cmd:SetButtons(buttons - IN_ZOOM)
end
MySelf:CallZombieFunction("CreateMove", cmd)
end
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() 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 undomodelblend = false
local undozombievision = false
local matWhite = Material("models/debug/debugwhite")
function GM:_PrePlayerDraw(pl)
if pl:CallZombieFunction("PrePlayerDraw") then return true end
local shadowman = false
if pl.status_overridemodel and pl.status_overridemodel:IsValid() and self:ShouldDrawLocalPlayer(MySelf) then -- We need to do this otherwise the player's real model shows up for some reason.
undomodelblend = true
render.SetBlend(0)
elseif MySelf:Team() == TEAM_HUMAN and pl ~= MySelf and pl:Team() == TEAM_HUMAN and not self.MedicalAura then
local radius = self.TransparencyRadius
if radius > 0 then
local eyepos = EyePos()
local dist = pl:NearestPoint(eyepos):Distance(eyepos)
if dist < radius then
local blend = math.max((dist / radius) ^ 1.4, 0.04)
render.SetBlend(blend)
if blend < 0.4 then
render.ModelMaterialOverride(matWhite)
render.SetColorModulation(0.2, 0.2, 0.2)
shadowman = true
end
undomodelblend = true
end
end
end
pl.ShadowMan = shadowman
if self.m_ZombieVision and MySelf:Team() == TEAM_UNDEAD and pl:Team() == TEAM_HUMAN and pl:GetPos():Distance(EyePos()) <= pl:GetAuraRange() then
undozombievision = true
local green = math.Clamp(pl:Health() / pl:GetMaxHealth(), 0, 1)
render.ModelMaterialOverride(matWhite)
render.SetColorModulation(1 - green, green, 0)
render.SuppressEngineLighting(true)
cam.IgnoreZ(true)
end
end
local colFriend = Color(10, 255, 10, 60)
local matFriendRing = Material("SGM/playercircle")
function GM:_PostPlayerDraw(pl)
pl:CallZombieFunction("PostPlayerDraw")
if undomodelblend then
render.SetBlend(1)
render.ModelMaterialOverride()
render.SetColorModulation(1, 1, 1)
undomodelblend = false
end
if undozombievision then
render.ModelMaterialOverride()
render.SetColorModulation(1, 1, 1)
render.SuppressEngineLighting(false)
cam.IgnoreZ(false)
undozombievision = false
end
if pl ~= MySelf and MySelf:Team() == pl:Team() and pl:IsFriend() then
local pos = pl:GetPos() + Vector(0, 0, 2)
render.SetMaterial(matFriendRing)
render.DrawQuadEasy(pos, Vector(0, 0, 1), 32, 32, colFriend)
render.DrawQuadEasy(pos, Vector(0, 0, -1), 32, 32, colFriend)
end
end
function GM:DrawCraftingEntity()
local craftingentity = self.CraftingEntity
if craftingentity and craftingentity:IsValid() then
if self.HumanMenuPanel and self.HumanMenuPanel:Valid() and self.HumanMenuPanel:IsVisible() and MySelf:KeyDown(self.MenuKey) then
local scale = craftingentity:GetModelScale()
if not scale then return end
render.ModelMaterialOverride(matWhite)
render.SuppressEngineLighting(true)
render.SetBlend(0.025)
local extrascale = 1.05 + math.abs(math.sin(RealTime() * 7)) * 0.1
craftingentity:SetModelScale(scale * extrascale, 0)
local oldpos = craftingentity:GetPos()
craftingentity:SetPos(oldpos - craftingentity:LocalToWorld(oldpos))
craftingentity:DrawModel()
craftingentity:SetPos(oldpos)
craftingentity:SetModelScale(scale, 0)
render.SetBlend(1)
render.SuppressEngineLighting(false)
render.ModelMaterialOverride(0)
else
self.CraftingEntity = nil
end
end
end
function GM:HUDPaintBackgroundEndRound()
local w, h = ScrW(), ScrH()
local timleft = math.max(0, self.EndTime + self.EndGameTime - CurTime())
if timleft <= 0 then
draw_SimpleTextBlur(translate.Get("loading"), "ZSHUDFont", w * 0.5, h * 0.8, COLOR_WHITE, TEXT_ALIGN_CENTER)
else
draw_SimpleTextBlur(translate.Format("next_round_in_x", util.ToMinutesSeconds(timleft)), "ZSHUDFontSmall", w * 0.5, h * 0.8, 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", 1)
if type(override) ~= "number" 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
local function EndRoundGetMeleeFilter(self) return {self} end
function GM:EndRound(winner, nextmap)
if self.RoundEnded then return end
self.RoundEnded = true
ROUNDWINNER = winner
self.EndTime = CurTime()
RunConsoleCommand("stopsound")
FindMetaTable("Player").GetMeleeFilter = EndRoundGetMeleeFilter
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)
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
if pl:Team() == TEAM_HUMAN and pl:Alive() and not pl:IsHolding() then
gamemode.Call("HumanMenu")
end
elseif key == IN_SPEED then
if pl:Alive() then
if pl:Team() == TEAM_HUMAN then
pl:DispatchAltUse()
elseif pl:Team() == TEAM_UNDEAD then
pl:CallZombieFunction("AltUse")
end
end
end
end
function GM:PlayerStepSoundTime(pl, iType, bWalking)
local time = pl:CallZombieFunction("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:CallZombieFunction("PlayerFootstep", vFootPos, iFoot, strSoundName, fVolume)
end
function GM:PlayerCanCheckout(pl)
return pl:IsValid() and pl:Team() == 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:Valid() 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.GetStored(class)
if wep and wep.PrintName 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()
LocalPlayer():EmitSound("buttons/lightswitch2.wav", 100, 30)
end
function PlayMenuCloseSound()
LocalPlayer():EmitSound("buttons/lightswitch2.wav", 100, 20)
end
local DamageFloaters = CreateClientConVar("zs_damagefloaters", "1", true, false):GetBool()
cvars.AddChangeCallback("zs_damagefloaters", function(cvar, oldvalue, newvalue)
DamageFloaters = newvalue ~= "0"
end)
net.Receive("zs_legdamage", function(length)
LocalPlayer().LegDamage = net.ReadFloat()
end)
net.Receive("zs_zvols", function(length)
local volunteers = {}
local count = net.ReadUInt(8)
for i=1, count do
volunteers[i] = net.ReadEntity()
end
GAMEMODE.ZombieVolunteers = volunteers
end)
net.Receive("zs_dmg", function(length)
local damage = net.ReadUInt(16)
local pos = net.ReadVector()
if DamageFloaters then
local effectdata = EffectData()
effectdata:SetOrigin(pos)
effectdata:SetMagnitude(damage)
effectdata:SetScale(0)
util.Effect("damagenumber", effectdata)
end
end)
net.Receive("zs_dmg_prop", function(length)
local damage = net.ReadUInt(16)
local pos = net.ReadVector()
if DamageFloaters then
local effectdata = EffectData()
effectdata:SetOrigin(pos)
effectdata:SetMagnitude(damage)
effectdata:SetScale(1)
util.Effect("damagenumber", effectdata)
end
end)
net.Receive("zs_lifestats", function(length)
local barricadedamage = net.ReadUInt(24)
local humandamage = net.ReadUInt(24)
local brainseaten = net.ReadUInt(16)
GAMEMODE.LifeStatsEndTime = CurTime() + GAMEMODE.LifeStatsLifeTime
GAMEMODE.LifeStatsBarricadeDamage = barricadedamage
GAMEMODE.LifeStatsHumanDamage = humandamage
GAMEMODE.LifeStatsBrainsEaten = brainseaten
end)
net.Receive("zs_lifestatsbd", function(length)
local barricadedamage = net.ReadUInt(24)
GAMEMODE.LifeStatsEndTime = CurTime() + GAMEMODE.LifeStatsLifeTime
GAMEMODE.LifeStatsBarricadeDamage = barricadedamage
end)
net.Receive("zs_lifestatshd", function(length)
local humandamage = net.ReadUInt(24)
GAMEMODE.LifeStatsEndTime = CurTime() + GAMEMODE.LifeStatsLifeTime
GAMEMODE.LifeStatsHumanDamage = humandamage
end)
net.Receive("zs_lifestatsbe", function(length)
local brainseaten = net.ReadUInt(16)
GAMEMODE.LifeStatsEndTime = CurTime() + GAMEMODE.LifeStatsLifeTime
GAMEMODE.LifeStatsBrainsEaten = brainseaten
end)
net.Receive("zs_honmention", function(length)
local pl = net.ReadEntity()
local mentionid = net.ReadUInt(8)
local etc = net.ReadInt(32)
if pl:IsValid() then
gamemode.Call("AddHonorableMention", pl, mentionid, etc)
end
end)
net.Receive("zs_wavestart", function(length)
local wave = net.ReadInt(16)
local time = net.ReadFloat()
gamemode.Call("SetWave", wave)
gamemode.Call("SetWaveEnd", time)
if GAMEMODE.ZombieEscape then
GAMEMODE:CenterNotify(COLOR_RED, {font = "ZSHUDFont"}, translate.Get("escape_from_the_zombies"))
elseif wave == GAMEMODE:GetNumberOfWaves() then
GAMEMODE:CenterNotify({killicon = "default"}, {font = "ZSHUDFont"}, " ", COLOR_RED, translate.Get("final_wave"), {killicon = "default"})
GAMEMODE:CenterNotify(translate.Get("final_wave_sub"))
else
GAMEMODE:CenterNotify({killicon = "default"}, {font = "ZSHUDFont"}, " ", COLOR_RED, translate.Format("wave_x_has_begun", wave), {killicon = "default"})
end
surface_PlaySound("ambient/creatures/town_zombie_call1.wav")
end)
net.Receive("zs_classunlock", function(length)
GAMEMODE:CenterNotify(COLOR_GREEN, net.ReadString())
end)
net.Receive("zs_waveend", function(length)
local wave = net.ReadInt(16)
local time = net.ReadFloat()
gamemode.Call("SetWaveStart", time)
if wave < GAMEMODE:GetNumberOfWaves() and wave > 0 then
GAMEMODE:CenterNotify(COLOR_RED, {font = "ZSHUDFont"}, translate.Format("wave_x_is_over", wave))
GAMEMODE:CenterNotify(translate.Format("wave_x_is_over_sub", GAMEMODE.ArsenalCrateDiscountPercentage))
surface_PlaySound("ambient/atmosphere/cave_hit"..math.random(6)..".wav")
end
end)
net.Receive("zs_gamestate", function(length)
local wave = net.ReadInt(16)
local wavestart = net.ReadFloat()
local waveend = net.ReadFloat()
gamemode.Call("SetWave", wave)
gamemode.Call("SetWaveStart", wavestart)
gamemode.Call("SetWaveEnd", waveend)
end)
local matSkull = Material("zombiesurvival/horderally")
local bossspawnedend
local function BossSpawnedPaint()
if CurTime() > bossspawnedend then
hook.Remove("HUDPaint", "BossSpawnedPaint")
return
end
local delta = math.Clamp(bossspawnedend - CurTime(), 0, 1)
local size = (1 - delta) * math.max(ScrW(), ScrH())
surface_SetMaterial(matSkull)
surface_SetDrawColor(160, 0, 0, math.min(delta * 400, 180))
surface_DrawTexturedRectRotated(ScrW() / 2, ScrH() / 2, size, size, delta * 25)
end
net.Receive("zs_boss_spawned", function(length)
local ent = net.ReadEntity()
local classindex = net.ReadUInt(8)
if ent == MySelf and ent:IsValid() then
GAMEMODE:CenterNotify({killicon = "default"}, " ", COLOR_RED, translate.Format("you_are_x", translate.Get(GAMEMODE.ZombieClasses[classindex].TranslationName)), {killicon = "default"})
elseif ent:IsValid() then
GAMEMODE:CenterNotify({killicon = "default"}, " ", COLOR_RED, (translate.Format("x_has_risen_as_y", ent:Name(), translate.Get(GAMEMODE.ZombieClasses[classindex].TranslationName))), {killicon = "default"})
else
GAMEMODE:CenterNotify({killicon = "default"}, " ", COLOR_RED, translate.Format("x_has_risen", translate.Get(GAMEMODE.ZombieClasses[classindex].TranslationName)), {killicon = "default"})
end
if MySelf:IsValid() then
MySelf:EmitSound("npc/zombie_poison/pz_alert1.wav", 0)
end
bossspawnedend = CurTime() + 1
hook.Add("HUDPaint", "BossSpawnedPaint", BossSpawnedPaint)
end)
net.Receive("zs_centernotify", function(length)
local tab = net.ReadTable()
GAMEMODE:CenterNotify(unpack(tab))
end)
net.Receive("zs_topnotify", function(length)
local tab = net.ReadTable()
GAMEMODE:TopNotify(unpack(tab))
end)
net.Receive("zs_lasthuman", function(length)
local pl = net.ReadEntity()
gamemode.Call("LastHuman", pl)
end)
net.Receive("zs_gamemodecall", function(length)
gamemode.Call(net.ReadString())
end)
net.Receive("zs_lasthumanpos", function(length)
GAMEMODE.LastHumanPosition = net.ReadVector()
end)
net.Receive("zs_endround", function(length)
local winner = net.ReadUInt(8)
local nextmap = net.ReadString()
gamemode.Call("EndRound", winner, nextmap)
end)
-- Temporary fix
function render.DrawQuadEasy(pos, dir, xsize, ysize, color, rotation)
xsize = xsize / 2
ysize = ysize / 2
local ang = dir:Angle()
if rotation then
ang:RotateAroundAxis(ang:Forward(), rotation)
end
local upoffset = ang:Up() * ysize
local rightoffset = ang:Right() * xsize
render.DrawQuad(pos - upoffset - rightoffset, pos - upoffset + rightoffset, pos + upoffset + rightoffset, pos + upoffset - rightoffset, color)
end