gmod-addons/addons/llb_ball/lua/entities/llb_baseball/init.lua
Chev 6a6db8fa01
LLB Baseball: Support new AirShake parameter in util.ScreenShake
(cherry picked from commit 7ebd38618b2116a98291037137d73d962cb75e3b)
2023-09-18 20:38:04 -07:00

248 lines
7.6 KiB
Lua

AddCSLuaFile("cl_init.lua")
AddCSLuaFile("shared.lua")
include("shared.lua")
-- Internal size of the ball--do not touch this
ENT.BallSize = 18
-- If ball is being initially served or not
ENT.ServingPitch = false
util.AddNetworkString("llb_baseball.DrawInvertedColors")
util.AddNetworkString("llb_baseball.ChangeBallColor")
util.AddNetworkString("llb_baseball.ScreenShake")
local NEW_VEL_VECTOR = Vector()
function ENT:Initialize()
self:SetModel("models/llb/baseball.mdl")
self:SetModelScale(0.55)
self:SetCollisionGroup(COLLISION_GROUP_PASSABLE_DOOR)
self:PhysicsInit(SOLID_VPHYSICS)
self:SetMoveType(MOVETYPE_VPHYSICS)
self:SetSolid(SOLID_VPHYSICS)
self:SetTrigger(true)
self.ServingPitch = true
local size = self.BallSize / 2.1
self:PhysicsInitSphere(size, "metal_bouncy")
self:SetCollisionBounds(Vector(-size, -size, -size), Vector(size, size, size))
local trailTexture = "trails/smoke"
if IsMounted("tf") then trailTexture = "effects/beam_generic01" end
self.BallTrail = util.SpriteTrail(self, 0, Color(255, 0, 0), false, 17, 17, 0.03, 1 / 17, trailTexture)
local phys = self:GetPhysicsObject()
if phys:IsValid() then
phys:Wake()
phys:EnableGravity(false)
end
hook.Add("KeyPress", self, function(ent, ply, key)
if not IsValid(ply) or not IsValid(ent) or not IsFirstTimePredicted() then return end
local plyPos = ply:GetPos()
local entPos = ent:GetPos()
-- The player will hit the ball if they're within 120 hammer units.
-- They don't need to look directly at the ball
if key == IN_ATTACK and plyPos:Distance(entPos) < 120 then
local dmginfo = DamageInfo()
dmginfo:SetAttacker(ply)
ent:OnTakeDamage(dmginfo)
end
end)
end
function ENT:Think()
local phys = self:GetPhysicsObject()
if not IsValid(phys) then return end
local vel = self:GetVelocity()
vel.x = self:GetLockXAxis() and 0 or vel.x
vel.y = self:GetLockYAxis() and 0 or vel.y
vel.z = self:GetLockZAxis() and 0 or vel.z
-- Use a preinitialized vector so we don't create a vector every frame
NEW_VEL_VECTOR:SetUnpacked(vel.x, vel.y, vel.z)
phys:SetVelocity(NEW_VEL_VECTOR)
self:NextThink(CurTime())
return true
end
function ENT:PhysicsCollide(data, physobj)
-- Play sound and screen shake on bounce
if data.DeltaTime > 0.02 then
sound.Play(self.BounceSound, self:GetPos(), 80, 100, 1)
self:ScreenShake(2, 4, 0.2, 1500)
end
end
function ENT:SpawnFunction(ply, tr, ClassName)
if not tr.Hit then return end
local ent = ents.Create(ClassName)
ent:SetPos(tr.HitPos + tr.HitNormal * self.BallSize * 2)
ent:Spawn()
ent:Activate()
local phys = ent:GetPhysicsObject()
phys:SetVelocity(Vector(0, 0, 0))
phys:SetAngles(Angle(0, 0, 0))
phys:AddAngleVelocity(Vector(256, 0, 0))
return ent
end
function ENT:OnTakeDamage(dmginfo)
-- Prevents multiple damage events from overlapping and causing issues
if self.IsPaused then return end
-- Attacker must be an alive player
local att = dmginfo:GetAttacker()
if not att:IsPlayer() or not att:Alive() then return end
-- Ball needs valid physics, otherwise we can't temporarily freeze it
local phys = self:GetPhysicsObject()
if not IsValid(phys) then return end
local newvel = self:GetVelocity() * 1.5
local speed = newvel:Length() ^ 0.8
-- Freeze the ball
phys:EnableMotion(false)
self.IsPaused = true
-- Set new ball owner
self.BallOwner = att
-- Set the color of the ball trail
local plycol = att:GetPlayerColor():ToColor()
local newplycol = math.Round(plycol.r) .. " " .. math.Round(plycol.g) .. " " .. math.Round(plycol.b)
self.BallTrail:Fire("Color", newplycol)
-- Let clients know about the ball's new color
net.Start("llb_baseball.ChangeBallColor")
net.WriteEntity(self)
net.WriteEntity(self.BallOwner)
net.Broadcast()
-- Fixes issues where velocity gets nulled out if ball is locked to an axis and player fires perpendicular to it
local aimAng = att:GetAimVector():Angle()
aimAng:Normalize()
if self:GetLockXAxis() then
aimAng.y = aimAng.y > 0 and 90 or -90
end
if self:GetLockYAxis() then
aimAng.y = math.abs(aimAng.y) > 90 and 180 or 0
end
if self:GetLockZAxis() then
aimAng.p = 0
end
local aimVecFixed = aimAng:Forward()
local ballPauseTime = math.Clamp(0.00205 * speed, 0, 1.2)
-- Play different sounds based on ball speed
if speed > 1000 then
-- Tell clients in PVS to invert their screen colors
net.Start("llb_baseball.DrawInvertedColors")
net.WriteEntity(self)
net.WriteFloat(math.Clamp(0.00205 * speed, 0, 1.2))
net.SendPVS(self:GetPos())
sound.Play(self.StrongHitSound, self:GetPos(), 80, 100, 1)
self:ScreenShake(25, 4, ballPauseTime, 300)
elseif speed > 500 then
sound.Play(self.StrongHitSound, self:GetPos(), 80, 100, 1)
self:ScreenShake(20, 4, ballPauseTime, 300)
else
sound.Play(self.HitSound, self:GetPos(), 80, speed * 0.0295 + 100, 1)
self:ScreenShake(2, 4, ballPauseTime, 300)
end
-- Lock the player until ball unfreezes.
att:Lock()
timer.Simple(ballPauseTime, function()
if not IsValid(att) then return end
att:UnLock()
end)
-- Unfreeze the ball after it was temporarily frozen.
timer.Simple(ballPauseTime, function()
if not IsValid(self) or not IsValid(phys) then return end
self.IsPaused = false
phys:EnableMotion(true)
if self.ServingPitch then
phys:SetVelocity(aimVecFixed * 50 * 3.4)
self.ServingPitch = false
else
if speed == 0 then return end
-- *May need some more testing
phys:SetVelocity(aimVecFixed * speed * 3.8)
end
phys:AddAngleVelocity(Vector(-512, 0, 0))
end)
end
function ENT:StartTouch(ent)
local speed = self:GetVelocity():Length() ^ 0.8
-- Damage a player if they touch the ball
if ent:IsPlayer() and self.BallOwner != ent and speed > 16 then
if not self:GetDamagePlayers() then return end
local dmginf = DamageInfo()
dmginf:SetDamage(speed / 8)
dmginf:SetDamageType(DMG_GENERIC)
dmginf:SetAttacker(self)
dmginf:SetInflictor(self)
dmginf:SetDamageForce(Vector(0, 0, 1))
ent:TakeDamageInfo(dmginf)
self:ScreenShake(2, 30, 0.5, 300)
-- If player is still alive after taking damage
if ent:Health() > 0 then
sound.Play("llb/takedmg_" .. math.random(1, 4) .. ".ogg", self:GetPos(), 80, 100, 1)
-- Reset ball speed when a player dies
else
local phys = self:GetPhysicsObject()
phys:SetVelocity(Vector(0, 0, 0))
phys:SetAngles(Angle(90, 0, 0))
phys:AddAngleVelocity(-phys:GetAngleVelocity() + Vector(256, 0, 0))
self.ServingPitch = true
sound.Play(self.KnockoutSound, self:GetPos(), 80, 100, 1)
end
end
end
function ENT:ScreenShake(amplitude, frequency, duration, radius)
--util.ScreenShake(self:GetPos(), amplitude, frequency, duration, radius, true)
-- New AirShake parameter only works on clientside at the moment, so we have to network it
net.Start("llb_baseball.ScreenShake")
net.WriteVector(self:GetPos())
net.WriteUInt(amplitude, 8)
net.WriteUInt(frequency, 8)
net.WriteFloat(duration)
net.WriteFloat(radius)
net.SendPVS(self:GetPos())
end