mirror of
https://github.com/lifestorm/wnsrc.git
synced 2025-12-16 21:33:46 +03:00
514 lines
19 KiB
Lua
514 lines
19 KiB
Lua
|
|
--[[
|
||
|
|
| This file was obtained through the combined efforts
|
||
|
|
| of Madbluntz & Plymouth Antiquarian Society.
|
||
|
|
|
|
||
|
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||
|
|
| Maloy, DrPepper10 @ RIP, Atle!
|
||
|
|
|
|
||
|
|
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||
|
|
--]]
|
||
|
|
|
||
|
|
-- ZAPC
|
||
|
|
-- Copyright (c) 2012 Zaubermuffin
|
||
|
|
--
|
||
|
|
-- Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||
|
|
--
|
||
|
|
-- The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||
|
|
--
|
||
|
|
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||
|
|
|
||
|
|
-- Local > global!
|
||
|
|
local Color = Color
|
||
|
|
local surface = surface
|
||
|
|
local draw = draw
|
||
|
|
local LocalPlayer = LocalPlayer
|
||
|
|
local math = math
|
||
|
|
local IsValid = IsValid
|
||
|
|
local util = util
|
||
|
|
local render = render
|
||
|
|
local TimedSin = TimedSin
|
||
|
|
local Lerp = Lerp
|
||
|
|
|
||
|
|
include('shared.lua')
|
||
|
|
|
||
|
|
-- CC
|
||
|
|
local ZAPC_VIEW_UNRELATED, ZAPC_VIEW_DRIVER, ZAPC_VIEW_GUNNER, ZAPC_VIEW_PASSENGER = ZAPC_VIEW_UNRELATED, ZAPC_VIEW_DRIVER, ZAPC_VIEW_GUNNER, ZAPC_VIEW_PASSENGER
|
||
|
|
local ZAPC_MAX_HEALTH = ZAPC_MAX_HEALTH
|
||
|
|
local ZAPC_PRIMARY_RELOAD_TIME, ZAPC_SECONDARY_RELOAD_TIME = ZAPC_PRIMARY_RELOAD_TIME, ZAPC_SECONDARY_RELOAD_TIME
|
||
|
|
local ZAPC_MAX_PASSENGERS = ZAPC_MAX_PASSENGERS
|
||
|
|
|
||
|
|
local ZAPC_HUD_OKAY = Color(8, 91, 181, 255) --Color(44, 110, 235, 255) -- full health
|
||
|
|
local ZAPC_HUD_OKAY_BG = Color(149, 214, 243, 80)
|
||
|
|
local ZAPC_HUD_NOT_OKAY = Color(227, 0, 0, 255) -- absolutely dead
|
||
|
|
local ZAPC_HUD_NOT_OKAY_BG = Color(120, 0, 0, 120)
|
||
|
|
|
||
|
|
local ZAPC_HUD_HEALTH_FLASH_TIME = 0.5 -- seconds the interface flashes red after you were hit.
|
||
|
|
local ZAPC_HUD_BULLET_WARNING_FLASH_FREQ = 1.5 -- the smaller the slower.
|
||
|
|
local ZAPC_MIN_ZOOM = 75 -- FOV when unzoomed
|
||
|
|
local ZAPC_MAX_ZOOM = 25 -- FOV when zoomed
|
||
|
|
local ZAPC_ZOOM_RATE = 2.5 -- FOV/Tick
|
||
|
|
|
||
|
|
-- Get rid of them.
|
||
|
|
for k, v in pairs(_G) do
|
||
|
|
if type(k) == 'string' and k:find('^ZAPC_') then
|
||
|
|
_G[k] = nil
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
-- Are we somehow related to the APC?
|
||
|
|
local ViewMode = 0
|
||
|
|
-- The APC
|
||
|
|
local ZAPC = nil
|
||
|
|
-- Driver, gunner, passengers
|
||
|
|
local Driver, Gunner, Passengers = nil, nil, {}
|
||
|
|
-- Bullets we have and the last reload actions
|
||
|
|
local Bullets, LastPrimary, LastSecondary, NextPrimary, NextSecondary = 0, 0, 0, 0, 0
|
||
|
|
-- Health of the APC
|
||
|
|
local Health = 0
|
||
|
|
-- Last time we were hit by something.
|
||
|
|
local LastHealthLoss = 0
|
||
|
|
-- OH GOD
|
||
|
|
local Destructing = false
|
||
|
|
-- Hatch
|
||
|
|
local HatchOpened = false
|
||
|
|
-- The last velocity we had - to avoid that the user interface is whopping around too badly, we're cheating a little.
|
||
|
|
local lastVel = 0
|
||
|
|
|
||
|
|
-- Our "zoom" status.
|
||
|
|
local Zoom = 75
|
||
|
|
|
||
|
|
-- The viewmode. This used to be gmod_vehicle_viewmode but got dropped in a "recent" update.
|
||
|
|
-- Since we still want this to be possible, I'll re-add it.
|
||
|
|
local viewmode = CreateClientConVar('zapc_viewmode', 1, true, false)
|
||
|
|
|
||
|
|
-- Create the fonts.
|
||
|
|
-- For whatever reason Garry decided it was a sweet idea to make Trebuchet24/18 additive in GM13. :|
|
||
|
|
surface.CreateFont("ZAPC_HUD",
|
||
|
|
{
|
||
|
|
font = "Trebuchet MS",
|
||
|
|
size = 24,
|
||
|
|
antialias = true,
|
||
|
|
weight = 600
|
||
|
|
})
|
||
|
|
|
||
|
|
surface.CreateFont("ZAPC_HUDSmall",
|
||
|
|
{
|
||
|
|
font = "Trebuchet MS",
|
||
|
|
size = 18,
|
||
|
|
antialias = true,
|
||
|
|
weight = 600
|
||
|
|
})
|
||
|
|
|
||
|
|
local function LimitPitch(ang)
|
||
|
|
return math.Clamp(ang, -45, 45)
|
||
|
|
end
|
||
|
|
|
||
|
|
local function ProcessAngle(ang)
|
||
|
|
local apcAngles = ZAPC:GetAngles()
|
||
|
|
ang.pitch = LimitPitch(math.NormalizeAngle(ang.pitch - apcAngles.pitch))
|
||
|
|
ang.yaw = math.NormalizeAngle(ang.yaw + apcAngles.yaw + 180)
|
||
|
|
ang.roll = math.NormalizeAngle(ang.roll)
|
||
|
|
return ang
|
||
|
|
end
|
||
|
|
|
||
|
|
local function CalcView(ply, origin, angles, fov)
|
||
|
|
-- unrelated or unknown APC.
|
||
|
|
if not IsValid(ZAPC) or ViewMode == ZAPC_VIEW_UNRELATED then
|
||
|
|
return
|
||
|
|
end
|
||
|
|
|
||
|
|
-- Gunner.
|
||
|
|
if ViewMode == ZAPC_VIEW_GUNNER then
|
||
|
|
-- Get the attachment.
|
||
|
|
local att = ZAPC:GetAttachment(ZAPC:LookupAttachment('gun_def'))
|
||
|
|
-- In case att doesn't exist...
|
||
|
|
if not att then
|
||
|
|
return
|
||
|
|
end
|
||
|
|
|
||
|
|
local trace = util.TraceLine({ start = att.Pos, endpos = att.Pos + att.Ang:Up()*5, mask = MASK_SOLID_BRUSHONLY})
|
||
|
|
local view = {}
|
||
|
|
view.origin = trace.HitPos
|
||
|
|
if viewmode:GetInt() == 1 then
|
||
|
|
view.angles = ProcessAngle(LocalPlayer():EyeAngles())
|
||
|
|
else
|
||
|
|
view.angles = att.Ang
|
||
|
|
end
|
||
|
|
view.fov = Zoom
|
||
|
|
return view
|
||
|
|
elseif ViewMode == ZAPC_VIEW_DRIVER or ViewMode == ZAPC_VIEW_PASSENGER then
|
||
|
|
-- The next line is a lie.
|
||
|
|
angles = LocalPlayer():EyeAngles()
|
||
|
|
|
||
|
|
local view = {}
|
||
|
|
-- Third person
|
||
|
|
if viewmode:GetInt() == 1 or ViewMode == ZAPC_VIEW_PASSENGER then
|
||
|
|
-- This seems to be 25/35 all the time since a few updates (for whatever reason)
|
||
|
|
angles.pitch = 25
|
||
|
|
-- This should always be zero.
|
||
|
|
angles.roll = 0
|
||
|
|
|
||
|
|
-- If we fuck up, hardcore.
|
||
|
|
if tostring(angles.yaw):find('#', 1, true) then
|
||
|
|
angles.yaw = ZAPC:GetAngles().yaw+90
|
||
|
|
-- Try to "fix" it ourselves...
|
||
|
|
LocalPlayer():SetEyeAngles(angles)
|
||
|
|
end
|
||
|
|
|
||
|
|
local trace = util.TraceLine({ start = origin + ZAPC:GetUp()*5, endpos = origin - angles:Forward() * 350, mask = MASK_SOLID_BRUSHONLY })
|
||
|
|
view = {}
|
||
|
|
view.origin = trace.HitPos + trace.HitNormal * 5
|
||
|
|
view.angles = angles
|
||
|
|
view.fov = fov
|
||
|
|
-- First person
|
||
|
|
else
|
||
|
|
view = { origin = ZAPC:GetPos()+ZAPC:GetUp()*50-ZAPC:GetRight()*100, angles = (-ZAPC:GetRight()):Angle(), fov = 90 }
|
||
|
|
end
|
||
|
|
return view
|
||
|
|
end
|
||
|
|
end
|
||
|
|
hook.Add('CalcView', '_ZAPC.CalcView', CalcView)
|
||
|
|
|
||
|
|
-- UI
|
||
|
|
-- Returns a table to be used with draw.TexturedQuad when working with fixed stuff.
|
||
|
|
-- Let's call it SPRITE.
|
||
|
|
local function TexTable(fileName, _color, _x, _y, _w, _h)
|
||
|
|
local m, w, h = Material(fileName)
|
||
|
|
local tbl = { material = Material(fileName), color = _color, x = _x, y = _y, w = _w, h = _h }
|
||
|
|
return tbl
|
||
|
|
end
|
||
|
|
|
||
|
|
-- Draws the texture table.
|
||
|
|
local function DrawMaterial(tbl, overrideX, overrideY)
|
||
|
|
surface.SetMaterial(tbl.material)
|
||
|
|
surface.DrawTexturedRect(overrideX and overrideX or tbl.x, overrideY and overrideY or tbl.y, tbl.w, tbl.h)
|
||
|
|
end
|
||
|
|
|
||
|
|
-- Textures we are going to use.
|
||
|
|
local CHAIR_GUNNER_TABLE = TexTable('zapc_hud/seat_gunner.png', nil, 10, 20, 64, 64)
|
||
|
|
local CHAIR_DRIVER_TABLE = TexTable('zapc_hud/seat_driver.png', nil, 42, 80, 64, 64)
|
||
|
|
local CHAIR_PASSENGER_TABLE = TexTable('zapc_hud/seat.png', nil, 10, 140, 64, 64)
|
||
|
|
|
||
|
|
local SHELL_TABLE = TexTable('zapc_hud/rocket.png', nil, -30, ScrH() - 190, 128, 128)
|
||
|
|
local CROSSHAIR_TABLE = TexTable('zapc_hud/crosshair.png', nil, ScrW()/2 - 32, ScrH()/2 - 32, 128, 128)
|
||
|
|
|
||
|
|
-- Returns the name of somebody.
|
||
|
|
local function Nick(ply)
|
||
|
|
return IsValid(ply) and ((ply.GetCharacterName and ply:GetCharacterName()) or (ply.GetRPName and ply:GetRPName()) or ply:Nick()) or '(Empty)'
|
||
|
|
end
|
||
|
|
|
||
|
|
-- Draws.. a box.
|
||
|
|
local function DrawBox(x, y, w, h, color)
|
||
|
|
surface.SetDrawColor(color.r, color.g, color.b, color.a)
|
||
|
|
surface.DrawRect(x, y, w, h)
|
||
|
|
end
|
||
|
|
|
||
|
|
-- baboom.
|
||
|
|
local function LerpColor(fract, from, to)
|
||
|
|
return Color(to.r - (to.r-from.r)*fract, to.g - (to.g-from.g)*fract, to.b - (to.b-from.b)*fract, to.a-(to.a-from.a)*fract)
|
||
|
|
end
|
||
|
|
|
||
|
|
|
||
|
|
-- "Temporary" helper function.
|
||
|
|
local function MaxTextSize(currentWidth, currentHeight, text, x, y)
|
||
|
|
local w, h = surface.GetTextSize(text)
|
||
|
|
x, y = x or 0, y or 0
|
||
|
|
if currentWidth < w + x then
|
||
|
|
currentWidth = w + x
|
||
|
|
end
|
||
|
|
|
||
|
|
if currentHeight < h + y then
|
||
|
|
currentHeight = h + y
|
||
|
|
end
|
||
|
|
|
||
|
|
return currentWidth, currentHeight
|
||
|
|
end
|
||
|
|
|
||
|
|
-- woop woop woop woooop
|
||
|
|
local function HUDPaint()
|
||
|
|
if not IsValid(ZAPC) or ViewMode == ZAPC_VIEW_UNRELATED then
|
||
|
|
return
|
||
|
|
end
|
||
|
|
|
||
|
|
-- The prisoner one is easy!
|
||
|
|
if ViewMode == ZAPC_VIEW_PASSENGER then
|
||
|
|
if not HatchOpened then
|
||
|
|
draw.SimpleText('You are inside the APC. The hatch was locked.', 'ZAPC_HUD', ScrW()/2, ScrH()/2, Color(255, 255, 255, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
|
||
|
|
end
|
||
|
|
return
|
||
|
|
end
|
||
|
|
|
||
|
|
-- The color we draw stuff in. TODO: Change this to some fancy fading.
|
||
|
|
local healthFraction = math.Clamp(math.TimeFraction(0, ZAPC_MAX_HEALTH(), Health), 0, 1)
|
||
|
|
-- If we are destructing, we're using SINUS instead!
|
||
|
|
local Bullets, NextPrimary, NextSecondary = Bullets, NextPrimary, NextSecondary
|
||
|
|
local velocity = (7*lastVel + math.min(1, math.TimeFraction(0, 650, ZAPC:GetVelocity():Length()))) / 8 -- abuse of TimeFraction, sue me
|
||
|
|
lastVel = velocity
|
||
|
|
|
||
|
|
if Destructing then
|
||
|
|
healthFraction = math.sin(CurTime()*5)/2 + 0.5
|
||
|
|
Bullets = math.floor(math.sin(CurTime()*3)*25 + 25)
|
||
|
|
NextPrimary = CurTime() - ZAPC_PRIMARY_RELOAD_TIME()*(math.sin(CurTime()*6)/2+0.5)
|
||
|
|
NextSecondary = CurTime() - ZAPC_SECONDARY_RELOAD_TIME()*(math.sin(CurTime()*5)/2+0.5)
|
||
|
|
velocity = math.sin(CurTime()*10)/2 + 0.5
|
||
|
|
HatchOpened = math.sin(CurTime()*30)/4 > 0
|
||
|
|
end
|
||
|
|
|
||
|
|
|
||
|
|
local colorFrac = healthFraction - math.Clamp(1-math.TimeFraction(LastHealthLoss, LastHealthLoss + ZAPC_HUD_HEALTH_FLASH_TIME, CurTime()), 0, healthFraction)
|
||
|
|
local color = LerpColor(colorFrac, ZAPC_HUD_OKAY, ZAPC_HUD_NOT_OKAY)
|
||
|
|
local bgColor = LerpColor(colorFrac, ZAPC_HUD_OKAY_BG, ZAPC_HUD_NOT_OKAY_BG)
|
||
|
|
|
||
|
|
-- Some constants, move them out later
|
||
|
|
local gunnerTextX, gunnerTextY = 80, 40
|
||
|
|
local driverTextX, driverTextY = 112, 100
|
||
|
|
local hatchTextX, hatchTextY = 75, 170
|
||
|
|
|
||
|
|
-- Get the size of the box. As of now, no fancy resizing effect.
|
||
|
|
-- Gunner
|
||
|
|
surface.SetFont('ZAPC_HUD')
|
||
|
|
local boxX, boxY = 5, 15
|
||
|
|
boxW, boxH = 205 + boxX, 195 + boxY -- minimum box size
|
||
|
|
boxW, boxH = MaxTextSize(boxW, boxH, Nick(Gunner), gunnerTextX, gunnerTextY)
|
||
|
|
-- Driver
|
||
|
|
boxW, boxH = MaxTextSize(boxW, boxH, Nick(Driver), driverTextX, driverTextY)
|
||
|
|
|
||
|
|
-- Any passenger we might have
|
||
|
|
surface.SetFont('ZAPC_HUDSmall')
|
||
|
|
for k, v in pairs(Passengers) do
|
||
|
|
boxW, boxH = MaxTextSize(boxW, boxH, Nick(v), 75, 170 + k*22)
|
||
|
|
end
|
||
|
|
|
||
|
|
-- For the main interface.
|
||
|
|
draw.RoundedBoxEx(8, boxX, boxY, boxW - boxX + 5, boxH - boxY + 5, bgColor, true, true, true, true)
|
||
|
|
-- The bottom-left
|
||
|
|
draw.RoundedBoxEx(8, 5, ScrH() - 195, 105, 175, bgColor, true, true, true, false)
|
||
|
|
draw.RoundedBoxEx(8, 110, ScrH() - 70, 450, 50, bgColor, false, true, false, true)
|
||
|
|
-- And the right one
|
||
|
|
draw.RoundedBoxEx(8, ScrW() - 75, 8, 70, ScrH() - 16, bgColor, true, true, true, true)
|
||
|
|
|
||
|
|
-- Set the surface color.
|
||
|
|
surface.SetDrawColor(color)
|
||
|
|
|
||
|
|
-- Draw the seats.
|
||
|
|
DrawMaterial(CHAIR_PASSENGER_TABLE)
|
||
|
|
DrawMaterial(CHAIR_GUNNER_TABLE)
|
||
|
|
DrawMaterial(CHAIR_DRIVER_TABLE)
|
||
|
|
|
||
|
|
-- The names for those.
|
||
|
|
draw.SimpleText(Nick(Gunner), 'ZAPC_HUD', gunnerTextX, gunnerTextY, color, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER)
|
||
|
|
draw.SimpleText(Nick(Driver), 'ZAPC_HUD', driverTextX, driverTextY, color, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER)
|
||
|
|
|
||
|
|
for k, v in pairs(Passengers) do
|
||
|
|
draw.SimpleText(Nick(v), 'ZAPC_HUDSmall', 75, 170 + k*22, color, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER)
|
||
|
|
end
|
||
|
|
|
||
|
|
-- Draw the status
|
||
|
|
draw.SimpleText('Hatch ' .. (HatchOpened and 'opened' or 'locked'), 'ZAPC_HUD', hatchTextX, hatchTextY, HatchOpened and ZAPC_HUD_NOT_OKAY or color, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER)
|
||
|
|
|
||
|
|
-- Bullets.
|
||
|
|
local x, y = 20, ScrH() - 50
|
||
|
|
|
||
|
|
local bulletColor = Color(color.r, color.g, color.b, color.a)
|
||
|
|
local da = 0
|
||
|
|
|
||
|
|
if Bullets == 0 then
|
||
|
|
bulletColor = Color(color.r, color.g, color.b, 0)
|
||
|
|
elseif Bullets <= 20 then
|
||
|
|
bulletColor = LerpColor(math.Clamp(math.TimeFraction(10, 20, Bullets), 0, 1), color, ZAPC_HUD_NOT_OKAY)
|
||
|
|
da = TimedSin(ZAPC_HUD_BULLET_WARNING_FLASH_FREQ * (1.2-math.TimeFraction(1, 20, Bullets)), 0, 25, 0)*2 + -25 -- don't call your god damn parameters "min" and "max" if you aren't going to stick to it
|
||
|
|
end
|
||
|
|
|
||
|
|
local bulletTextColor = Color(bulletColor.r, bulletColor.g, bulletColor.b, bulletColor.a > 0 and (bulletColor.a + da) or 255) -- If we're reloading, just use full transparency.
|
||
|
|
|
||
|
|
for i = 1, 50 do
|
||
|
|
bulletColor.a = ((i <= Bullets and 255) or 120) + da
|
||
|
|
draw.RoundedBoxEx(4, x, y, 8, 12, bulletColor, true, true, false, false)
|
||
|
|
x = x + 10
|
||
|
|
end
|
||
|
|
|
||
|
|
draw.SimpleText(tostring(Bullets), 'ZAPC_HUD', 525, ScrH() - 30, bulletTextColor, TEXT_ALIGN_LEFT, TEXT_ALIGN_TOP)
|
||
|
|
|
||
|
|
-- The reloading bar.
|
||
|
|
local reloadProgress = math.min(math.TimeFraction(LastPrimary, NextPrimary, CurTime()), 1.0)
|
||
|
|
DrawBox(20, ScrH() - 35, Lerp(reloadProgress, 0, 500), 5, bulletTextColor)
|
||
|
|
|
||
|
|
reloadProgress = math.min(math.TimeFraction(LastSecondary, NextSecondary, CurTime()), 1.0)
|
||
|
|
|
||
|
|
local reloadColor = LerpColor(reloadProgress, color, ZAPC_HUD_NOT_OKAY)
|
||
|
|
surface.SetDrawColor(reloadColor)
|
||
|
|
-- Not using that weird, ugly thing that was in the old APC. Clipping for teh win.
|
||
|
|
render.SetScissorRect(SHELL_TABLE.x, SHELL_TABLE.y + SHELL_TABLE.h * (1-reloadProgress), SHELL_TABLE.x + SHELL_TABLE.w, SHELL_TABLE.y + SHELL_TABLE.h, true)
|
||
|
|
DrawMaterial(SHELL_TABLE)
|
||
|
|
render.SetScissorRect(0, 0, 0, 0, false)
|
||
|
|
|
||
|
|
draw.SimpleText(tostring(math.floor(reloadProgress * 100)) .. '%', 'ZAPC_HUD', 50, ScrH() - 73, reloadColor, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER)
|
||
|
|
|
||
|
|
-- Velocity
|
||
|
|
local vel = Lerp(velocity, 0, ScrH()-30)
|
||
|
|
DrawBox(ScrW() - 30, ScrH() - 15 - vel, 15, vel, color)
|
||
|
|
|
||
|
|
-- Health
|
||
|
|
local hbar = Lerp(healthFraction, 0, ScrH() - 30)
|
||
|
|
DrawBox(ScrW() - 65, ScrH() - 15 - hbar, 25, hbar, color)
|
||
|
|
|
||
|
|
-- Crossbar, if gunner
|
||
|
|
if ViewMode == ZAPC_VIEW_GUNNER then
|
||
|
|
local attach = ZAPC:GetAttachment(ZAPC:LookupAttachment('muzzle'))
|
||
|
|
local p = util.TraceLine({ start = attach.Pos - 15 * attach.Ang:Forward() + attach.Ang:Right(), endpos = attach.Pos - 15 * attach.Ang:Forward() + attach.Ang:Right() + attach.Ang:Forward()*16384, filter = { ZAPC }, mask = MASK_SHOT }).HitPos:ToScreen()
|
||
|
|
surface.SetDrawColor(color.r, color.g, color.b, color.a*0.8)
|
||
|
|
DrawMaterial(CROSSHAIR_TABLE, p.x - CROSSHAIR_TABLE.w/2, p.y - CROSSHAIR_TABLE.h/2)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
hook.Add('HUDPaint', '_ZAPC.HUDPaint', HUDPaint)
|
||
|
|
|
||
|
|
local function PreDrawHUD()
|
||
|
|
if ViewMode == ZAPC_VIEW_PASSENGER and not HatchOpened then
|
||
|
|
local color = ZAPC:GetColor()
|
||
|
|
surface.SetDrawColor(color.r/5, color.g/5, color.b/5, 230)
|
||
|
|
-- noo idea!
|
||
|
|
surface.DrawRect(-ScrW(), -ScrH(), ScrW()*2, ScrH()*2)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
hook.Add('PreDrawHUD', '_ZAPC.PreDrawHUD', PreDrawHUD)
|
||
|
|
|
||
|
|
-- I feel bad for abusing this like that.
|
||
|
|
local ToytownMaterial = Material('pp/toytown-top')
|
||
|
|
ToytownMaterial:SetTexture('$fbtexture', render.GetScreenEffectTexture())
|
||
|
|
|
||
|
|
local function RenderScreenspaceEffects()
|
||
|
|
if ViewMode == ZAPC_VIEW_PASSENGER and not HatchOpened then
|
||
|
|
cam.Start2D()
|
||
|
|
surface.SetMaterial(ToytownMaterial)
|
||
|
|
surface.SetDrawColor(255, 255, 255, 255)
|
||
|
|
for i = 1, 25 do
|
||
|
|
render.UpdateScreenEffectTexture()
|
||
|
|
surface.DrawTexturedRect(0, 0, ScrW(), ScrH()*2.5)
|
||
|
|
end
|
||
|
|
cam.End2D()
|
||
|
|
end
|
||
|
|
end
|
||
|
|
hook.Add('RenderScreenspaceEffects', '_ZAPC.RenderScreenspaceEffects', RenderScreenspaceEffects)
|
||
|
|
|
||
|
|
local function Tick()
|
||
|
|
if ViewMode == ZAPC_VIEW_GUNNER then
|
||
|
|
Zoom = math.Clamp(Zoom + (LocalPlayer():KeyDown(IN_ZOOM) and -ZAPC_ZOOM_RATE or ZAPC_ZOOM_RATE), ZAPC_MAX_ZOOM, ZAPC_MIN_ZOOM)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
hook.Add('Tick', '_ZAPC.Tick', Tick)
|
||
|
|
|
||
|
|
local function PlayerBindPress(ply, bind, pressed)
|
||
|
|
if ViewMode ~= ZAPC_VIEW_UNRELATED and bind:find('+duck') and pressed then
|
||
|
|
RunConsoleCommand('zapc_viewmode', math.abs(viewmode:GetInt()-1))
|
||
|
|
return true
|
||
|
|
end
|
||
|
|
end
|
||
|
|
hook.Add('PlayerBindPress', '_ZAPC.PlayerBindPress', PlayerBindPress)
|
||
|
|
|
||
|
|
local function HUDShouldDraw(name)
|
||
|
|
if ViewMode ~= ZAPC_VIEW_UNRELATED and (name == 'CHudHealth' or name == 'CHudBattery') then
|
||
|
|
return false
|
||
|
|
end
|
||
|
|
end
|
||
|
|
hook.Add('HUDShouldDraw', '_ZAPC.HUDShouldDraw', HUDShouldDraw)
|
||
|
|
|
||
|
|
-- Notifications for "new" players.
|
||
|
|
local function Notify(str, length, delay)
|
||
|
|
timer.Simple(delay or 0, function()
|
||
|
|
notification.AddLegacy(str, NOTIFY_HINT, length)
|
||
|
|
end)
|
||
|
|
end
|
||
|
|
|
||
|
|
local notifyDriver, notifyGunner = true, true
|
||
|
|
|
||
|
|
local function DoDriverNotifications()
|
||
|
|
notifyDriver = false
|
||
|
|
Notify('Driver: To start the engine and release the breaks, press the left mouse button (+attack)', 10)
|
||
|
|
--~ Notify('Driver: To switch to the lower/higher gear, press the right mouse button (+attack2)', 8, 8)
|
||
|
|
Notify('Driver: To switch seats, press shift (+speed)', 10, 14)
|
||
|
|
Notify('Driver: To open or close the hatch, press Alt (+walk)', 10, 22)
|
||
|
|
Notify('Driver: To toggle the siren, press R (+reload)', 10, 30)
|
||
|
|
end
|
||
|
|
|
||
|
|
local function DoGunnerNotifications()
|
||
|
|
notifyGunner = false
|
||
|
|
Notify('Gunner: To fire the turret, press your left mouse button (+attack)', 10)
|
||
|
|
Notify('Gunner: To fire rockets, press your right mouse button (+attack2)', 10)
|
||
|
|
Notify('Gunner: To reload, press R (+reload)', 8, 8)
|
||
|
|
end
|
||
|
|
|
||
|
|
--[[ User Messages ]]--
|
||
|
|
-- Updates ViewMode, if necessary.
|
||
|
|
usermessage.Hook('ZAPC_VU', function(msg)
|
||
|
|
ViewMode = tonumber(msg:ReadChar())
|
||
|
|
|
||
|
|
-- Don't deal with notification stuff if we're disabled.
|
||
|
|
if GetConVarNumber( "cl_showhints" ) == 0 then
|
||
|
|
return
|
||
|
|
end
|
||
|
|
|
||
|
|
if notifyDriver and ViewMode == ZAPC_VIEW_DRIVER then
|
||
|
|
DoDriverNotifications()
|
||
|
|
elseif notifyGunner and ViewMode == ZAPC_VIEW_GUNNER then
|
||
|
|
DoGunnerNotifications()
|
||
|
|
end
|
||
|
|
end)
|
||
|
|
|
||
|
|
-- The APC we (were) last in.
|
||
|
|
usermessage.Hook('ZAPC_AU', function(msg) ZAPC = msg:ReadEntity() LocalPlayer():SetEyeAngles(Angle(25, ZAPC:GetAngles().yaw + 90, 0)) LastHealthLoss = 0 Destructing = false lastVel = 0 end) -- reset the health loss because the interface weirds around otherwise.
|
||
|
|
-- Bullet.
|
||
|
|
usermessage.Hook('ZAPC_BU', function(msg) Bullets = tonumber(msg:ReadChar()) end)
|
||
|
|
-- Actions.
|
||
|
|
usermessage.Hook('ZAPC_LPU', function() LastPrimary, NextPrimary = CurTime(), CurTime() + ZAPC_PRIMARY_RELOAD_TIME() end)
|
||
|
|
usermessage.Hook('ZAPC_LSU', function() LastSecondary, NextSecondary = CurTime(), CurTime() + ZAPC_SECONDARY_RELOAD_TIME() end)
|
||
|
|
-- Guys inside the APC.
|
||
|
|
usermessage.Hook('ZAPC_PU', function(msg) Driver = msg:ReadEntity() Gunner = msg:ReadEntity() Passengers = {} for i = 1, ZAPC_MAX_PASSENGERS() do local ent = msg:ReadEntity() if IsValid(ent) then table.insert(Passengers, ent) end end end)
|
||
|
|
-- Health
|
||
|
|
usermessage.Hook('ZAPC_HU', function(msg) Health = msg:ReadShort() LastHealthLoss = CurTime() end)
|
||
|
|
-- Destructoid
|
||
|
|
usermessage.Hook('ZAPC_SD', function(msg) Destructing = true end)
|
||
|
|
-- Hatch opening update.
|
||
|
|
usermessage.Hook('ZAPC_HOU', function(msg) HatchOpened = msg:ReadBool() end)
|
||
|
|
|
||
|
|
--[[ Debugging the APC and other addons. ]]--
|
||
|
|
local function WrapRelated(event, key)
|
||
|
|
local func = hook.GetTable()[event][key]
|
||
|
|
if not func then
|
||
|
|
return
|
||
|
|
end
|
||
|
|
|
||
|
|
hook.Add(event, key, function(...) if ViewMode == ZAPC_VIEW_UNRELATED then return func(...) end end)
|
||
|
|
end
|
||
|
|
|
||
|
|
local function Initialize()
|
||
|
|
--[[
|
||
|
|
The official
|
||
|
|
HALL OF STOOPID
|
||
|
|
]]--
|
||
|
|
|
||
|
|
-- 107985981, disrespecting about everyone as soon as a NWVar was set
|
||
|
|
WrapRelated('CalcView', "RenderWithDifferentNearPlane")
|
||
|
|
end
|
||
|
|
hook.Add('Initialize', '_ZAPC.Initialize', Initialize)
|
||
|
|
|
||
|
|
|
||
|
|
-- In case this happens again, here's a few debuggers.
|
||
|
|
local function DumpHooks(ply, cmd, args)
|
||
|
|
if IsValid(ply) and not game.SinglePlayer() then
|
||
|
|
return
|
||
|
|
end
|
||
|
|
|
||
|
|
local hooks = { 'CalcView', 'HUDPaint', 'PreDrawHUD', 'PlayerBindPress' }
|
||
|
|
|
||
|
|
print("\n[ZAPC] Dumping possible client hook collisions...")
|
||
|
|
for _, h in pairs(hooks) do
|
||
|
|
print("[ZAPC] " .. h)
|
||
|
|
for k, v in pairs(hook.GetTable()[h]) do
|
||
|
|
print('[ZAPC] "' .. tostring(k) .. '"')
|
||
|
|
end
|
||
|
|
print()
|
||
|
|
end
|
||
|
|
|
||
|
|
print("[ZAPC] Hooks dumped.")
|
||
|
|
end
|
||
|
|
concommand.Add('zapc_dumphooks_cl', DumpHooks, nil, "Dumps all hooks that could possibly cause havok on the client.")
|