--[[ | 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/ --]] AddCSLuaFile() ENT.Type = "anim" ENT.ExplosionEffect = "lvs_explosion_bomb" ENT.lvsProjectile = true function ENT:SetupDataTables() self:NetworkVar( "Bool", 0, "Active" ) self:NetworkVar( "Bool", 1, "MaskSolid" ) self:NetworkVar( "Vector", 0, "Speed" ) end if SERVER then util.AddNetworkString( "lvs_bomb_hud" ) function ENT:SetEntityFilter( filter ) if not istable( filter ) then return end self._FilterEnts = {} for _, ent in pairs( filter ) do self._FilterEnts[ ent ] = true end end function ENT:GetEntityFilter() return self._FilterEnts or {} end function ENT:SetDamage( num ) self._dmg = num end function ENT:SetThrust( num ) self._thrust = num end function ENT:SetRadius( num ) self._radius = num end function ENT:SetAttacker( ent ) self._attacker = ent if not IsValid( ent ) or not ent:IsPlayer() then return end net.Start( "lvs_bomb_hud", true ) net.WriteEntity( self ) net.Send( ent ) end function ENT:GetAttacker() return self._attacker or NULL end function ENT:GetDamage() return (self._dmg or 2000) end function ENT:GetRadius() return (self._radius or 400) end function ENT:Initialize() self:SetModel( "models/props_phx/ww2bomb.mdl" ) self:SetMoveType( MOVETYPE_NONE ) end function ENT:OnTakeDamage( dmginfo ) end function ENT:Enable() if self.IsEnabled then return end local Parent = self:GetParent() if IsValid( Parent ) then self:SetOwner( Parent ) self:SetParent( NULL ) end self:PhysicsInit( SOLID_VPHYSICS ) self:SetMoveType( MOVETYPE_VPHYSICS ) self:SetSolid( SOLID_VPHYSICS ) self:SetCollisionGroup( COLLISION_GROUP_WORLD ) self:PhysWake() timer.Simple(1, function() if not IsValid( self ) then return end self:SetCollisionGroup( COLLISION_GROUP_NONE ) end ) self.IsEnabled = true local pObj = self:GetPhysicsObject() if not IsValid( pObj ) then self:Remove() print("LVS: missing model. Missile terminated.") return end pObj:SetMass( 500 ) pObj:EnableGravity( false ) pObj:EnableMotion( true ) pObj:EnableDrag( false ) pObj:SetVelocityInstantaneous( self:GetSpeed() ) self:SetTrigger( true ) self:StartMotionController() self:PhysWake() self.SpawnTime = CurTime() self:SetActive( true ) end function ENT:PhysicsSimulate( phys, deltatime ) phys:Wake() local ForceLinear, ForceAngle = phys:CalculateForceOffset( physenv.GetGravity(), phys:LocalToWorld( phys:GetMassCenter() + Vector(10,0,0) ) ) ForceAngle = ForceAngle - phys:GetAngleVelocity() * 5 return ForceAngle, ForceLinear, SIM_GLOBAL_ACCELERATION end function ENT:Think() local T = CurTime() self:NextThink( T ) self:UpdateTrajectory() if not self.SpawnTime then return true end if (self.SpawnTime + 12) < T then self:Detonate() end return true end function ENT:UpdateTrajectory() local base = self:GetParent() if not IsValid( base ) then return end self:SetSpeed( base:GetVelocity() ) end ENT.IgnoreCollisionGroup = { [COLLISION_GROUP_NONE] = true, [COLLISION_GROUP_WORLD] = true, } function ENT:StartTouch( entity ) if entity == self:GetAttacker() then return end if istable( self._FilterEnts ) and self._FilterEnts[ entity ] then return end if entity.GetCollisionGroup and self.IgnoreCollisionGroup[ entity:GetCollisionGroup() ] then return end if entity.lvsProjectile then return end self:Detonate( entity ) end function ENT:EndTouch( entity ) end function ENT:Touch( entity ) end function ENT:PhysicsCollide( data ) if istable( self._FilterEnts ) and self._FilterEnts[ data.HitEntity ] then return end self:Detonate() end function ENT:OnTakeDamage( dmginfo ) end function ENT:Detonate( target ) if not self.IsEnabled or self.IsDetonated then return end self.IsDetonated = true local Pos = self:GetPos() local effectdata = EffectData() effectdata:SetOrigin( Pos ) util.Effect( self.ExplosionEffect, effectdata ) if IsValid( target ) and not target:IsNPC() then Pos = target:GetPos() -- place explosion inside the hit targets location so they receive full damage. This fixes all the garbage code the LFS' missile required in order to deliver its damage end local attacker = self:GetAttacker() util.BlastDamage( self, IsValid( attacker ) and attacker or game.GetWorld(), Pos, self:GetRadius(), self:GetDamage() ) SafeRemoveEntityDelayed( self, FrameTime() ) end return end function ENT:Enable() if self.IsEnabled then return end self.IsEnabled = true self.snd = CreateSound(self, "lvs/weapons/bomb_whistle_loop.wav") self.snd:SetSoundLevel( 110 ) self.snd:PlayEx(0,150) end function ENT:CalcDoppler() local Ent = LocalPlayer() local ViewEnt = Ent:GetViewEntity() if Ent:lvsGetVehicle() == self then if ViewEnt == Ent then Ent = self else Ent = ViewEnt end else Ent = ViewEnt end local sVel = self:GetVelocity() local oVel = Ent:GetVelocity() local SubVel = oVel - sVel local SubPos = self:GetPos() - Ent:GetPos() local DirPos = SubPos:GetNormalized() local DirVel = SubVel:GetNormalized() local A = math.acos( math.Clamp( DirVel:Dot( DirPos ) ,-1,1) ) return (1 + math.cos( A ) * SubVel:Length() / 13503.9) end function ENT:Think() if self.snd then self.snd:ChangePitch( 100 * self:CalcDoppler(), 1 ) self.snd:ChangeVolume(math.Clamp(-(self:GetVelocity().z + 1000) / 3000,0,1), 2) end if self.IsEnabled then return end if self:GetActive() then self:Enable() end end function ENT:Draw() local T = CurTime() if not self:GetActive() then self._PreventDrawTime = T + 0.1 return end if (self._PreventDrawTime or 0) > T then return end self:DrawModel() end function ENT:SoundStop() if self.snd then self.snd:Stop() end end function ENT:OnRemove() self:SoundStop() end local color_red = Color(255,0,0,255) local HudTargets = {} hook.Add( "HUDPaint", "!!!!lvs_bomb_hud", function() for ID, _ in pairs( HudTargets ) do local Missile = Entity( ID ) if not IsValid( Missile ) or Missile:GetActive() then HudTargets[ ID ] = nil continue end local Grav = physenv.GetGravity() local FT = 0.05 -- RealFrameTime() local Pos = Missile:GetPos() local Vel = Missile:GetSpeed() local Mask = Missile.GetMaskSolid and (Missile:GetMaskSolid() and MASK_SOLID or MASK_SOLID_BRUSHONLY) or MASK_SOLID_BRUSHONLY cam.Start3D() local Iteration = 0 while Iteration < 1000 do Iteration = Iteration + 1 Vel = Vel + Grav * FT local StartPos = Pos local EndPos = Pos + Vel * FT local trace = util.TraceLine( { start = StartPos, endpos = EndPos, mask = Mask, } ) render.DrawLine( StartPos, EndPos, color_red ) Pos = EndPos if trace.Hit then break end end cam.End3D() local TargetPos = Pos:ToScreen() if not TargetPos.visible then continue end surface.DrawCircle( TargetPos.x, TargetPos.y, 20, color_red ) end end ) net.Receive( "lvs_bomb_hud", function( len ) local ent = net.ReadEntity() if not IsValid( ent ) then return end HudTargets[ ent:EntIndex() ] = true end )