dobrograd-13-06-2022/garrysmod/addons/gmod-ents/lua/entities/sent_soccerball.lua
Jonny_Bro (Nikita) e4d5311906 first commit
2023-11-16 15:01:19 +05:00

246 lines
6.5 KiB
Lua

AddCSLuaFile()
ENT.Type = 'anim'
ENT.Base = 'base_anim'
ENT.PrintName = L.soccerball
ENT.Category = L.dobrograd
ENT.Author = 'Jvs'
ENT.Spawnable = true
ENT.AdminOnly = false
if CLIENT then
ENT.HitMaterial = Material(util.DecalMaterial('impact.concrete'))
ENT.RenderGroup = RENDERGROUP_BOTH
else
ENT.CanPickupSoccerball = CreateConVar(
'sv_pickupsoccerball' ,
'1',
{
FCVAR_SERVER_CAN_EXECUTE,
FCVAR_ARCHIVE
},
'When true, it allows anyone to pickup the soccerball'
)
end
function ENT:SpawnFunction(ply , tr , classname)
if not tr.Hit then
return
end
local spawnpos = tr.HitPos + tr.HitNormal * 25
local ent = ents.Create(classname)
ent:SetPos(spawnpos)
ent:Spawn()
return ent
end
function ENT:SetupDataTables()
self:NetworkVar('Float' , 0 , 'LastImpact') --I made this into a dtvar because at some point I'll add some clientside animations for when the ball bounces
self:NetworkVar('Float' , 1 , 'PressureExpireStart')
self:NetworkVar('Float' , 2 , 'PressureExpireEnd')
end
function ENT:Initialize()
if SERVER then
self:SetMaxHealth(50)
self:SetHealth(50)
self:SetLagCompensated(true) --players can shoot at us even with their shitty ping!
self:SetUseType(SIMPLE_USE) --don't let players spam +use on us, that's rude
self:SetModel('models/props_phx/misc/soccerball.mdl')
self:PhysicsInit(SOLID_VPHYSICS)
self:SetMoveType(MOVETYPE_VPHYSICS)
self:SetSolid(SOLID_VPHYSICS)
self:ResetPressure()
self:SetTrigger(true) --allow us to use touch,starttouch and whatever even if we can't collide with the player
local physobj = self:GetPhysicsObject()
if IsValid(physobj) then
physobj:AddGameFlag(FVPHYSICS_NO_IMPACT_DMG)
physobj:AddGameFlag(FVPHYSICS_NO_NPC_IMPACT_DMG)
physobj:SetBuoyancyRatio(0.5)
physobj:SetDamping(0.25 , 1)
physobj:Wake()
end
self:StartMotionController()
end
self:SetCollisionGroup(COLLISION_GROUP_WEAPON)
end
--[[
I wanted to have this complicated system where the soccerball would lose pressure every frame but first off,
that's annoying to code for little to no benefit, and second, I can fake it off by just using a timed variable
that gets decreased everytime
]]
function ENT:GetPressure()
local pressure = math.Clamp(math.TimeFraction(self:GetPressureExpireEnd() , self:GetPressureExpireStart() , CurTime()) , 0 , 1)
return pressure
end
function ENT:ResetPressure()
self:SetPressureExpireStart(0)
self:SetPressureExpireEnd(0)
end
function ENT:IsLosingPressure()
return self:GetPressureExpireStart() ~= 0 and self:GetPressureExpireEnd() ~= 0
end
function ENT:OnRemove()
if CLIENT then
if self.PressureLeakSound then
self.PressureLeakSound:Stop()
self.PressureLeakSound = nil
end
end
end
if SERVER then
function ENT:PhysicsSimulate(physobj , delta)
return SIM_NOTHING
end
function ENT:OnTakeDamage(dmginfo)
if self:IsEFlagSet(EFL_KILLME) then
return
end
self:TakePhysicsDamage(dmginfo)
local dmg = dmginfo:GetDamage()
local healthtoset = math.Clamp(self:Health() - dmg , 0 , self:GetMaxHealth())
self:SetHealth(healthtoset)
local isoverkill = (dmg >= (self:GetMaxHealth() / 2)) or (healthtoset <= 0)
--either overkill
if (isoverkill and not dmginfo:IsDamageType(DMG_BULLET)) or isoverkill then
local effectdata = EffectData()
effectdata:SetOrigin(self:GetPos())
effectdata:SetScale(self:GetPressure())
util.Effect('soccerball_explode', effectdata)
self:Remove()
end
--we haven't been killed yet, start to lose pressure if the damage was coming from a bullet
if not self:IsEFlagSet(EFL_KILLME) and dmginfo:IsDamageType(DMG_BULLET) then
if not self:IsLosingPressure() then
self:SetPressureExpireStart(CurTime())
self:SetPressureExpireEnd(CurTime() + 5)
else
--decrease it a bit for every shot
self:SetPressureExpireEnd(self:GetPressureExpireEnd() - 0.5)
end
end
end
function ENT:Use(ply)
if self:GetVelocity():Length2DSqr() > 100 or not ply.inv or not ply.inv.conts._hand then
ply:Notify('warning', L.take_soccerball)
return
end
local i = ply.inv.conts._hand:AddItem('soccer')
if i and i ~= 0 then self:Remove() end
end
function ENT:PhysicsCollide(data, physobj)
if self:GetLastImpact() < CurTime() and data.DeltaTime > 0.2 and data.OurOldVelocity:Length() > 100 then
self:EmitSound('Rubber.ImpactHard')
self:SetLastImpact(CurTime() + 0.1)
end
end
function ENT:PhysicsUpdate(physobj)
physobj:SetMass(10)
physobj:SetBuoyancyRatio(0.5 * self:GetPressure())
physobj:SetDamping(0.25 , 1)
end
--touch is not called when the physics object hits an entity, but rather when the collision bounds do, which
--is done with traces on the game side
function ENT:StartTouch(ent)
if not SERVER or not IsValid(ent) or self:IsPlayerHolding() then
return
end
--ignore players that might be noclipping or in a vehicle
if ent:IsPlayer() and ent:GetMoveType() ~= MOVETYPE_WALK then
return
end
local tr = self:GetTouchTrace()
local kickmultiplier = 1.5 + 1 * self:GetPressure()
local massmultiplier = 15
local direction = tr.Normal
local normal = (ent:WorldSpaceCenter() - self:GetPos()):GetNormal() * -1
local physobj = self:GetPhysicsObject()
local ourvel = self:GetVelocity()
local theirvel = ent:GetVelocity()
if IsValid(physobj) and (ent:IsPlayer() or ent:IsNPC()) then
local aimvec = ent:EyeAngles()
aimvec.p = 0
aimvec = aimvec:Forward()
aimvec.z = 0
if aimvec:Dot(theirvel:GetNormal()) < 0 then
theirvel = vector_origin
theirvel = normal * physobj:GetMass() * massmultiplier
end
--kick the ball!
if theirvel ~= vector_origin then
self:EmitSound('Rubber.BulletImpact')
physobj:SetVelocityInstantaneous(theirvel * kickmultiplier + Vector(0, 0 , physobj:GetMass() * massmultiplier) )
self:SetLastImpact(CurTime() + 0.1)
else --bounce the ball back
self:EmitSound('Rubber.ImpactHard')
physobj:SetVelocityInstantaneous(-1 * normal * ourvel:Dot(normal))
end
self:SetLastImpact(CurTime() + 0.1) --we just kicked the ball, suppress the bounce sound for a little while
end
end
else
function ENT:Think()
self:HandleSound()
end
function ENT:HandleSound()
if not self.PressureLeakSound then
self.PressureLeakSound = CreateSound(self , 'PhysicsCannister.ThrusterLoop')
end
if self:IsLosingPressure() and self:GetPressure() ~= 0 then
self.PressureLeakSound:Play()
self.PressureLeakSound:ChangeVolume(self:GetPressure())
else
self.PressureLeakSound:Stop()
end
end
function ENT:Draw(flags)
self:DrawModel()
end
function ENT:DrawTranslucent()
end
end