197 lines
7.6 KiB
Lua
197 lines
7.6 KiB
Lua
ACF.Bullet = {}
|
|
ACF.CurBulletIndex = 0
|
|
ACF.BulletIndexLimt = 1000 --The maximum number of bullets in flight at any one time
|
|
|
|
function ACF_CreateBullet( BulletData )
|
|
|
|
ACF.CurBulletIndex = ACF.CurBulletIndex + 1 --Increment the index
|
|
if ACF.CurBulletIndex > ACF.BulletIndexLimt then
|
|
ACF.CurBulletIndex = 1
|
|
end
|
|
|
|
local cvarGrav = GetConVar("sv_gravity")
|
|
BulletData["Accel"] = Vector(0,0,cvarGrav:GetInt()*-1) --Those are BulletData settings that are global and shouldn't change round to round
|
|
BulletData["LastThink"] = SysTime()
|
|
BulletData["FlightTime"] = 0
|
|
BulletData["TraceBackComp"] = 0
|
|
if BulletData["FuseLength"] then
|
|
print("Has fuse")
|
|
BulletData["InitTime"] = SysTime()
|
|
end
|
|
if BulletData["Gun"]:IsValid() then --Check the Gun's velocity and add a modifier to the flighttime so the traceback system doesn't hit the originating contraption if it's moving along the shell path
|
|
BulletData["TraceBackComp"] = BulletData["Gun"]:GetPhysicsObject():GetVelocity():Dot(BulletData["Flight"]:GetNormalized())
|
|
if BulletData["Gun"].sitp_inspace then
|
|
BulletData["Accel"] = Vector(0, 0, 0)
|
|
BulletData["DragCoef"] = 0
|
|
end
|
|
--print(BulletData["TraceBackComp"])
|
|
end
|
|
BulletData["Filter"] = { BulletData["Gun"] }
|
|
BulletData["Index"] = ACF.CurBulletIndex
|
|
|
|
ACF.Bullet[ACF.CurBulletIndex] = table.Copy(BulletData) --Place the bullet at the current index pos
|
|
ACF_BulletClient( ACF.CurBulletIndex, ACF.Bullet[ACF.CurBulletIndex], "Init" , 0 )
|
|
ACF_CalcBulletFlight( ACF.CurBulletIndex, ACF.Bullet[ACF.CurBulletIndex] )
|
|
|
|
end
|
|
|
|
function ACF_ManageBullets()
|
|
|
|
for Index,Bullet in pairs(ACF.Bullet) do
|
|
ACF_CalcBulletFlight( Index, Bullet ) --This is the bullet entry in the table, the Index var omnipresent refers to this
|
|
end
|
|
|
|
end
|
|
hook.Add("Think", "ACF_ManageBullets", ACF_ManageBullets)
|
|
|
|
function ACF_RemoveBullet( Index )
|
|
|
|
ACF.Bullet[Index] = nil
|
|
|
|
end
|
|
|
|
function ACF_CalcBulletFlight( Index, Bullet, BackTraceOverride )
|
|
|
|
if not Bullet.LastThink then ACF_RemoveBullet( Index ) return end
|
|
if BackTraceOverride then Bullet.FlightTime = 0 end
|
|
local Time = SysTime()
|
|
local DeltaTime = Time - Bullet.LastThink
|
|
|
|
local Speed = Bullet.Flight:Length()
|
|
local Drag = Bullet.Flight:GetNormalized() * (Bullet.DragCoef * Speed^2)/ACF.DragDiv
|
|
Bullet.NextPos = Bullet.Pos + (Bullet.Flight * ACF.VelScale * DeltaTime) --Calculates the next shell position
|
|
Bullet.Flight = Bullet.Flight + (Bullet.Accel - Drag)*DeltaTime --Calculates the next shell vector
|
|
Bullet.StartTrace = Bullet.Pos - Bullet.Flight:GetNormalized()*math.min(ACF.PhysMaxVel*DeltaTime,Bullet.FlightTime*Speed-Bullet.TraceBackComp*DeltaTime)
|
|
|
|
Bullet.LastThink = Time
|
|
Bullet.FlightTime = Bullet.FlightTime + DeltaTime
|
|
|
|
ACF_DoBulletsFlight( Index, Bullet )
|
|
|
|
end
|
|
|
|
function ACF_DoBulletsFlight( Index, Bullet )
|
|
local CanDo = hook.Run("ACF_BulletsFlight", Index, Bullet )
|
|
if CanDo == false then return end
|
|
if Bullet.FuseLength then
|
|
local Time = SysTime() - Bullet.IniTime
|
|
if Time > Bullet.FuseLength then
|
|
print("Explode")
|
|
if not util.IsInWorld(Bullet.Pos) then
|
|
ACF_RemoveBullet( Index )
|
|
else
|
|
ACF_BulletClient( Index, Bullet, "Update" , 1 , Bullet.Pos )
|
|
ACF_BulletEndFlight = ACF.RoundTypes[Bullet.Type]["endflight"]
|
|
ACF_BulletEndFlight( Index, Bullet, Bullet.Pos, Bullet.Flight:GetNormalized() )
|
|
end
|
|
end
|
|
end
|
|
|
|
if Bullet.SkyLvL then
|
|
if (CurTime() - Bullet.LifeTime) > 500 then -- We don't want to calculate bullets that will never come back to map.
|
|
ACF_RemoveBullet( Index )
|
|
return
|
|
end
|
|
|
|
if Bullet.NextPos.z > Bullet.SkyLvL then
|
|
Bullet.Pos = Bullet.NextPos
|
|
return
|
|
elseif not util.IsInWorld(Bullet.NextPos) then
|
|
ACF_RemoveBullet( Index )
|
|
return
|
|
else
|
|
Bullet.SkyLvL = nil
|
|
Bullet.LifeTime = nil
|
|
Bullet.Pos = Bullet.NextPos
|
|
return
|
|
end
|
|
end
|
|
|
|
local FlightTr = { }
|
|
FlightTr.start = Bullet.StartTrace
|
|
FlightTr.endpos = Bullet.NextPos
|
|
FlightTr.filter = Bullet.Filter
|
|
local FlightRes = util.TraceLine(FlightTr) --Trace to see if it will hit anything
|
|
|
|
if FlightRes.HitNonWorld then
|
|
ACF_BulletPropImpact = ACF.RoundTypes[Bullet.Type]["propimpact"]
|
|
local Retry = ACF_BulletPropImpact( Index, Bullet, FlightRes.Entity , FlightRes.HitNormal , FlightRes.HitPos , FlightRes.HitGroup ) --If we hit stuff then send the resolution to the damage function
|
|
if Retry == "Penetrated" then --If we should do the same trace again, then do so
|
|
ACF_BulletClient( Index, Bullet, "Update" , 2 , FlightRes.HitPos )
|
|
ACF_DoBulletsFlight( Index, Bullet )
|
|
--Msg("Retrying\n")
|
|
elseif Retry == "Ricochet" then
|
|
ACF_BulletClient( Index, Bullet, "Update" , 3 , FlightRes.HitPos )
|
|
ACF_CalcBulletFlight( Index, Bullet, true )
|
|
else --Else end the flight here
|
|
ACF_BulletClient( Index, Bullet, "Update" , 1 , FlightRes.HitPos )
|
|
ACF_BulletEndFlight = ACF.RoundTypes[Bullet.Type]["endflight"]
|
|
ACF_BulletEndFlight( Index, Bullet, FlightRes.HitPos, FlightRes.HitNormal )
|
|
end
|
|
elseif FlightRes.HitWorld and not FlightRes.HitSky then --If we hit the world then try to see if it's thin enough to penetrate
|
|
ACF_BulletWorldImpact = ACF.RoundTypes[Bullet.Type]["worldimpact"]
|
|
local Retry = ACF_BulletWorldImpact( Index, Bullet, FlightRes.HitPos, FlightRes.HitNormal )
|
|
if Retry == "Penetrated" then --if it is, we soldier on
|
|
ACF_BulletClient( Index, Bullet, "Update" , 2 , FlightRes.HitPos )
|
|
ACF_CalcBulletFlight( Index, Bullet, true ) --The world ain't going to move, so we say True for the backtrace override
|
|
else --If not, end of the line, boyo
|
|
ACF_BulletClient( Index, Bullet, "Update" , 1 , FlightRes.HitPos )
|
|
ACF_BulletEndFlight = ACF.RoundTypes[Bullet.Type]["endflight"]
|
|
ACF_BulletEndFlight( Index, Bullet, FlightRes.HitPos, FlightRes.HitNormal )
|
|
end
|
|
elseif FlightRes.HitSky then
|
|
if FlightRes.HitNormal == Vector(0,0,-1) then
|
|
Bullet.SkyLvL = FlightRes.HitPos.z -- Lets save height on which bullet went through skybox. So it will start tracing after falling bellow this level. This will prevent from hitting higher levels of map
|
|
Bullet.LifeTime = CurTime()
|
|
Bullet.Pos = Bullet.NextPos
|
|
else
|
|
ACF_RemoveBullet( Index )
|
|
end
|
|
else --If we didn't hit anything, move the shell and schedule next think
|
|
Bullet.Pos = Bullet.NextPos
|
|
end
|
|
|
|
end
|
|
|
|
function ACF_BulletClient( Index, Bullet, Type, Hit, HitPos )
|
|
|
|
if Type == "Update" then
|
|
local Effect = EffectData()
|
|
Effect:SetAttachment( Index ) --Bulet Index
|
|
Effect:SetStart( Bullet.Flight/10 ) --Bullet Direction
|
|
if Hit > 0 then -- If there is a hit then set the effect pos to the impact pos instead of the retry pos
|
|
Effect:SetOrigin( HitPos ) --Bullet Pos
|
|
else
|
|
Effect:SetOrigin( Bullet.Pos )
|
|
end
|
|
Effect:SetScale( Hit ) --Hit Type
|
|
util.Effect( "ACF_BulletEffect", Effect, true, true )
|
|
|
|
else
|
|
local Effect = EffectData()
|
|
local Filler = 0
|
|
if Bullet["FillerMass"] then Filler = Bullet["FillerMass"]*15 end
|
|
Effect:SetAttachment( Index ) --Bulet Index
|
|
Effect:SetStart( Bullet.Flight/10 ) --Bullet Direction
|
|
Effect:SetOrigin( Bullet.Pos )
|
|
Effect:SetMagnitude( Bullet["Crate"] ) --Encodes the crate the ammo originates from so clientside knows the crate from wich to pull ammo data
|
|
Effect:SetScale( 0 )
|
|
util.Effect( "ACF_BulletEffect", Effect, true, true )
|
|
|
|
end
|
|
|
|
end
|
|
|
|
function ACF_BulletWorldImpact( Bullet, Index, HitPos, HitNormal )
|
|
--You overwrite this with your own function, defined in the ammo definition file
|
|
end
|
|
|
|
function ACF_BulletPropImpact( Bullet, Index, Target, HitNormal, HitPos )
|
|
--You overwrite this with your own function, defined in the ammo definition file
|
|
end
|
|
|
|
function ACF_BulletEndFlight( Bullet, Index, HitPos )
|
|
--You overwrite this with your own function, defined in the ammo definition file
|
|
end
|
|
|