add sborka
This commit is contained in:
949
garrysmod/addons/swbombs/lua/entities/sw_base_rocket_v3.lua
Normal file
949
garrysmod/addons/swbombs/lua/entities/sw_base_rocket_v3.lua
Normal file
@@ -0,0 +1,949 @@
|
||||
AddCSLuaFile()
|
||||
|
||||
local StartSnds = {}
|
||||
StartSnds[1] = "sw/rocket/rocket_start_01.wav"
|
||||
StartSnds[2] = "sw/rocket/rocket_start_02.wav"
|
||||
StartSnds[3] = "sw/rocket/rocket_start_03.wav"
|
||||
StartSnds[4] = "sw/rocket/rocket_start_04.wav"
|
||||
|
||||
local ImpSnds = {}
|
||||
ImpSnds[1] = "sw/bomb/impact_1.wav"
|
||||
ImpSnds[2] = "sw/bomb/impact_2.wav"
|
||||
ImpSnds[3] = "sw/bomb/impact_3.wav"
|
||||
|
||||
local WtrImpSnds = {}
|
||||
WtrImpSnds[1] = "sw/bomb/impact_wtr_1.wav"
|
||||
WtrImpSnds[2] = "sw/bomb/impact_wtr_2.wav"
|
||||
WtrImpSnds[3] = "sw/bomb/impact_wtr_3.wav"
|
||||
|
||||
local DbrSnds = {}
|
||||
DbrSnds[1] = "sw/bomb/debris_1.wav"
|
||||
DbrSnds[2] = "sw/bomb/debris_2.wav"
|
||||
DbrSnds[3] = "sw/bomb/debris_3.wav"
|
||||
DbrSnds[4] = "sw/bomb/debris_4.wav"
|
||||
|
||||
local ExpSnds = {}
|
||||
ExpSnds[1] = "sw/explosion/exp_tny_1.wav"
|
||||
ExpSnds[2] = "sw/explosion/exp_tny_2.wav"
|
||||
ExpSnds[3] = "sw/explosion/exp_tny_3.wav"
|
||||
|
||||
local FarExpSnds = {}
|
||||
FarExpSnds[1] = "sw/explosion/exp_sml_dst_1.wav"
|
||||
FarExpSnds[2] = "sw/explosion/exp_sml_dst_2.wav"
|
||||
FarExpSnds[3] = "sw/explosion/exp_sml_dst_3.wav"
|
||||
FarExpSnds[4] = "sw/explosion/exp_sml_dst_4.wav"
|
||||
FarExpSnds[5] = "sw/explosion/exp_sml_dst_5.wav"
|
||||
FarExpSnds[6] = "sw/explosion/exp_sml_dst_6.wav"
|
||||
FarExpSnds[7] = "sw/explosion/exp_sml_dst_7.wav"
|
||||
FarExpSnds[8] = "sw/explosion/exp_sml_dst_8.wav"
|
||||
|
||||
local DstExpSnds = {}
|
||||
DstExpSnds[1] = "sw/explosion/exp_sml_far_1.wav"
|
||||
DstExpSnds[2] = "sw/explosion/exp_sml_far_2.wav"
|
||||
DstExpSnds[3] = "sw/explosion/exp_sml_far_3.wav"
|
||||
DstExpSnds[4] = "sw/explosion/exp_sml_far_4.wav"
|
||||
DstExpSnds[5] = "sw/explosion/exp_sml_far_5.wav"
|
||||
DstExpSnds[6] = "sw/explosion/exp_sml_far_6.wav"
|
||||
DstExpSnds[7] = "sw/explosion/exp_sml_far_7.wav"
|
||||
DstExpSnds[8] = "sw/explosion/exp_sml_far_8.wav"
|
||||
|
||||
local WtrExpSnds = {}
|
||||
WtrExpSnds[1] = "sw/explosion/exp_trp_1.wav"
|
||||
WtrExpSnds[2] = "sw/explosion/exp_trp_2.wav"
|
||||
WtrExpSnds[3] = "sw/explosion/exp_trp_3.wav"
|
||||
|
||||
sound.Add( {
|
||||
name = "SW_ROCKET_ENG_LOOP",
|
||||
channel = CHAN_AUTO,
|
||||
volume = 1.0,
|
||||
level = 80,
|
||||
sound = "sw/rocket/rocket_fly_loop.wav"
|
||||
} )
|
||||
|
||||
--Main info
|
||||
ENT.Type = "anim"
|
||||
ENT.Spawnable = false
|
||||
ENT.AdminSpawnable = false
|
||||
ENT.AdminOnly = false
|
||||
ENT.PrintName = "Rocket basescript V3"
|
||||
ENT.Author = "Shermann Wolf"
|
||||
ENT.Contact = "shermannwolf@gmail.com"
|
||||
ENT.Category = "SW Bombs V3"
|
||||
ENT.Editable = true
|
||||
ENT.SWBombV3 = true
|
||||
ENT.IsRocket = true
|
||||
|
||||
--Visual
|
||||
ENT.Model = "models/sw/rus/rockets/s1of.mdl"
|
||||
ENT.Effect = "ins_m203_explosion"
|
||||
ENT.EffectAir = "ins_m203_explosion"
|
||||
ENT.EffectWater = "ins_water_explosion"
|
||||
ENT.Decal = "scorch_25kg"
|
||||
ENT.AngEffect = true
|
||||
ENT.RocketTrail = "Small_mis_thrust"
|
||||
ENT.RocketBurnoutTrail = "Small_mis_burnout"
|
||||
ENT.Tracer1Att = nil
|
||||
ENT.Tracer2Att = nil
|
||||
ENT.Engine1Att = nil
|
||||
ENT.Engine2Att = nil
|
||||
|
||||
--Sounds
|
||||
ENT.ArmSound = "sw/bomb/arm.wav"
|
||||
ENT.ImpactSound = table.Random(ImpSnds)
|
||||
ENT.WaterImpactSound = table.Random(WtrImpSnds)
|
||||
ENT.DebrisSound = table.Random(DbrSnds)
|
||||
ENT.WhistleSound = "sw/bomb/whistle.wav"
|
||||
ENT.ExplosionSound = table.Random(ExpSnds)
|
||||
ENT.FarExplosionSound = table.Random(FarExpSnds)
|
||||
ENT.DistExplosionSound = table.Random(DstExpSnds)
|
||||
ENT.WaterExplosionSound = table.Random(WtrExpSnds)
|
||||
ENT.WaterFarExplosionSound = nil
|
||||
ENT.StartSound = table.Random(StartSnds)
|
||||
ENT.EngineSound = "SW_ROCKET_ENG_LOOP"
|
||||
|
||||
--Physics
|
||||
ENT.TraceLength = 150
|
||||
ENT.ImpactSpeed = 500
|
||||
ENT.ImpactDepth = 0
|
||||
ENT.Mass = 100
|
||||
ENT.Durability = 100
|
||||
ENT.DetonateHeight = 0
|
||||
ENT.MaxVelocity = 100
|
||||
ENT.FuelBurnoutTime = 1
|
||||
ENT.RotationalForce = 1000
|
||||
|
||||
--Explosion
|
||||
ENT.DamageType = DMG_BURN
|
||||
ENT.ExplosionDamage = 1000
|
||||
ENT.ExplosionRadius = 300
|
||||
ENT.BlastRadius = 450
|
||||
ENT.FragDamage = 25
|
||||
ENT.FragRadius = 600
|
||||
ENT.FragCount = 100
|
||||
ENT.ArmorPenetration = 1000
|
||||
ENT.PenetrationDamage = 1000
|
||||
|
||||
--Guidance
|
||||
ENT.DiveHeight = 0
|
||||
ENT.Agility = 100
|
||||
ENT.HaveGuidance = false
|
||||
ENT.GuidanceActive = false
|
||||
ENT.LaserGuided = false
|
||||
ENT.LaserCode = "view"
|
||||
ENT.SpiralRate = -0.4
|
||||
ENT.SpiralRadius = 0
|
||||
ENT.IRunstable = false
|
||||
ENT.IRradius = 0
|
||||
|
||||
function ENT:SetupDataTables()
|
||||
self:NetworkVar("Bool",0,"AirDetonate", {KeyName = "airdetonate", Edit = { type = "Boolean", category = "Fuze"}})
|
||||
self:NetworkVar("Int",1,"DetonateHeight", { KeyName = "detonateheight", Edit = { type = "Int", min = 0, max = 2000, category = "Fuze"} } )
|
||||
self:NetworkVar("Int",2,"TracerScale")
|
||||
self:NetworkVar("Bool",3,"RadioFuze", {KeyName = "radiofuze", Edit = { type = "Boolean", category = "Fuze"}})
|
||||
self:NetworkVar("Int",4,"RadioFuzeRadius", { KeyName = "radiofuzeradius", Edit = { type = "Int", min = 0, max = 5000, category = "Fuze"} })
|
||||
end
|
||||
|
||||
if SERVER then
|
||||
local angle_reg = Angle(0,0,0)
|
||||
local angle_dif = Angle(-90,0,0)
|
||||
local Normal = Vector(1,1,0)
|
||||
local Normal2 = Vector(0.1,1,1)
|
||||
local trlength = Vector(0,0,9000)
|
||||
local angle_zero = Angle()
|
||||
local angle_1 = Angle(-90,0,0)
|
||||
|
||||
function ENT:SpawnFunction( ply, tr, ClassName )
|
||||
if not tr.Hit then return end
|
||||
local ent = ents.Create( ClassName )
|
||||
ent:SetPos( tr.HitPos + tr.HitNormal )
|
||||
ent:SetAngles( Angle(0, ply:EyeAngles().y, 0 ) )
|
||||
ent:Spawn()
|
||||
ent:Activate()
|
||||
|
||||
ent.StartSound = table.Random(StartSnds)
|
||||
ent.ImpactSound = table.Random(ImpSnds)
|
||||
ent.WaterImpactSoundSound = table.Random(WtrImpSnds)
|
||||
ent.DebrisSound = table.Random(DbrSnds)
|
||||
ent.ExplosionSound = table.Random(ExpSnds)
|
||||
ent.FarExplosionSound = table.Random(FarExpSnds)
|
||||
ent.DistExplosionSound = table.Random(DstExpSnds)
|
||||
ent.WaterExplosionSound = table.Random(WtrExpSnds)
|
||||
|
||||
return ent
|
||||
end
|
||||
|
||||
function ENT:Initialize()
|
||||
self:SetModel(self.Model)
|
||||
self:SetSolid(SOLID_VPHYSICS)
|
||||
self:PhysicsInit(SOLID_VPHYSICS)
|
||||
self:SetCollisionGroup( COLLISION_GROUP_NONE )
|
||||
self:PhysWake()
|
||||
local pObj = self:GetPhysicsObject()
|
||||
pObj:SetMass( self.Mass )
|
||||
pObj:EnableGravity( false )
|
||||
pObj:EnableMotion( true )
|
||||
pObj:EnableDrag( false )
|
||||
self:StartMotionController()
|
||||
self:PhysWake()
|
||||
self.InGround = false
|
||||
self.InEntity = false
|
||||
self.Exploded = false
|
||||
self.Armed = false
|
||||
self.CurDurability = self.Durability
|
||||
self.AirDetTicks = 0
|
||||
self.MaxVelocityUnitsSquared = self.MaxVelocity and self:ConvertMetersToUnits(self.MaxVelocity^2) or nil
|
||||
end
|
||||
|
||||
--Arming
|
||||
function ENT:Use( activator, caller )
|
||||
if !self.Exploded and !self.Armed then
|
||||
self:EmitSound(self.ArmSound)
|
||||
self.Armed = true
|
||||
self:Launch()
|
||||
end
|
||||
end
|
||||
function ENT:Launch()
|
||||
if self.Exploded or self.Burnt or self.Fired then return end
|
||||
|
||||
self:SetCollisionGroup(COLLISION_GROUP_PROJECTILE)
|
||||
|
||||
local phys = self:GetPhysicsObject()
|
||||
|
||||
if !IsValid(phys) then return end
|
||||
|
||||
self.ImpactSpeed = 10
|
||||
|
||||
self.Fired = true
|
||||
self:SetNWBool("Fired",true)
|
||||
|
||||
constraint.RemoveAll(self)
|
||||
|
||||
phys:Wake()
|
||||
phys:EnableMotion(true)
|
||||
|
||||
|
||||
self:InitLaunch(phys)
|
||||
end
|
||||
function ENT:InitLaunch(phys)
|
||||
|
||||
self:EmitSound(self.StartSound)
|
||||
util.ScreenShake( self:GetPos(), 1, 10, 1, 150+self.ExplosionRadius, true, nil )
|
||||
self:SetBodygroup(1,1)
|
||||
|
||||
phys:AddAngleVelocity(Vector(self.RotationalForce or 0,0,0))
|
||||
|
||||
if self.RocketTrail then
|
||||
timer.Simple(0,function()
|
||||
if !IsValid(self) then return end
|
||||
|
||||
if self.Engine1Att then
|
||||
local ID = self:LookupAttachment( self.Engine1Att )
|
||||
ParticleEffectAttach(self.RocketTrail,PATTACH_POINT_FOLLOW,self,ID)
|
||||
end
|
||||
if self.Engine2Att then
|
||||
local ID = self:LookupAttachment( self.Engine2Att )
|
||||
ParticleEffectAttach(self.RocketTrail,PATTACH_POINT_FOLLOW,self,ID)
|
||||
end
|
||||
if not self.Engine1Att and not self.Engine2Att then
|
||||
ParticleEffectAttach(self.RocketTrail,PATTACH_ABSORIGIN_FOLLOW,self,1)
|
||||
end
|
||||
|
||||
if self.Tracer1Att then
|
||||
if self.TracerEffect then
|
||||
local ID = self:LookupAttachment( self.Tracer1Att )
|
||||
ParticleEffectAttach(self.TracerEffect,PATTACH_POINT_FOLLOW,self,ID)
|
||||
end
|
||||
end
|
||||
if self.Tracer2Att then
|
||||
if self.TracerEffect then
|
||||
local ID = self:LookupAttachment( self.Tracer2Att )
|
||||
ParticleEffectAttach(self.TracerEffect,PATTACH_POINT_FOLLOW,self,ID)
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
if self.FuelBurnoutTime and self.FuelBurnoutTime != 0 then
|
||||
timer.Simple(self.FuelBurnoutTime,function()
|
||||
if !IsValid(self) then return end
|
||||
|
||||
self.Burnt = true
|
||||
self:SetNWBool("Burnt",true)
|
||||
self:StopParticles()
|
||||
self:StopSound(self.EngineSound)
|
||||
self:StopSound(self.StartSound)
|
||||
|
||||
if self.Engine1Att then
|
||||
local ID = self:LookupAttachment( self.Engine1Att )
|
||||
ParticleEffectAttach(self.RocketBurnoutTrail,PATTACH_POINT_FOLLOW,self,ID)
|
||||
end
|
||||
if self.Engine2Att then
|
||||
local ID = self:LookupAttachment( self.Engine2Att )
|
||||
ParticleEffectAttach(self.RocketBurnoutTrail,PATTACH_POINT_FOLLOW,self,ID)
|
||||
end
|
||||
if not self.Engine1Att and not self.Engine2Att then
|
||||
ParticleEffectAttach(self.RocketBurnoutTrail,PATTACH_ABSORIGIN_FOLLOW,self,1)
|
||||
end
|
||||
if self.Tracer1Att then
|
||||
if self.TracerEffect then
|
||||
local ID = self:LookupAttachment( self.Tracer1Att )
|
||||
ParticleEffectAttach(self.TracerEffect,PATTACH_POINT_FOLLOW,self,ID)
|
||||
end
|
||||
end
|
||||
if self.Tracer2Att then
|
||||
if self.TracerEffect then
|
||||
local ID = self:LookupAttachment( self.Tracer2Att )
|
||||
ParticleEffectAttach(self.TracerEffect,PATTACH_POINT_FOLLOW,self,ID)
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
--Think
|
||||
function ENT:ConvertMetersToUnits(Meters)
|
||||
return Meters / 0.01905
|
||||
end
|
||||
function ENT:ConvertUnitsToMeters(Units)
|
||||
return Units * 0.01905
|
||||
end
|
||||
function ENT:Think()
|
||||
self:NextThink(CurTime())
|
||||
if self:IsPlayerHolding() then
|
||||
self:SetNWBool("IsPlayerHolding",true)
|
||||
else
|
||||
self:SetNWBool("IsPlayerHolding",false)
|
||||
end
|
||||
if self.Armed then
|
||||
if self:GetAirDetonate() then
|
||||
if IsValid(self) and (self:GetVelocity():Length() > self.ImpactSpeed) and not self:IsPlayerHolding() then
|
||||
self.AirDetTicks = self.AirDetTicks + 1
|
||||
if self.AirDetTicks >= 50 then
|
||||
local tr = util.TraceLine({
|
||||
start = self:LocalToWorld(self:OBBCenter()),
|
||||
endpos = self:LocalToWorld(self:OBBCenter()) - Vector(0,0,self:GetDetonateHeight()),
|
||||
filter = self,
|
||||
})
|
||||
if tr.Hit then
|
||||
self.Exploded = true
|
||||
self:Explode(self:GetPos())
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if self.CruiseMode and self.GuidanceActive then
|
||||
local ph = self:GetPhysicsObject()
|
||||
local target = self.target:LocalToWorld(self.targetOffset)
|
||||
local tr = util.TraceLine( {
|
||||
start = self:GetPos(),
|
||||
endpos = (self:GetPos() + (self:GetAngles():Forward()*7500) - (self:GetAngles():Up()*2500) ),
|
||||
filter = {self}
|
||||
} )
|
||||
if tr.Hit then
|
||||
local distance = self:GetPos():Distance(target)
|
||||
if distance > 10000 then
|
||||
ph:AddVelocity(self:GetAngles():Up()*500)
|
||||
end
|
||||
end
|
||||
end
|
||||
if self.GuidanceActive then
|
||||
self:LaserGuidance()
|
||||
self:Guidance(self:GetPhysicsObject())
|
||||
if IsValid(self.target) then
|
||||
if self.WithOffset then
|
||||
self.TargetForwardOffset = self:GetPos():Distance(self.target:GetPos())/(self.OffsetMultiplier or 2)
|
||||
self.targetOffset = self.target:WorldToLocal(self.target:GetPos()+(self.target:GetForward()*self.TargetForwardOffset))
|
||||
end
|
||||
end
|
||||
if self.IRunstable == true then
|
||||
for _, e in pairs(ents.FindInCone(self:GetPos(),self:GetForward(),1500,math.cos(math.rad(self.SeekerCone)))) do
|
||||
if IsValid( e ) and e:GetClass() == "misc_flare" then
|
||||
local tr = util.TraceLine( {
|
||||
start = self:GetPos(),
|
||||
endpos = e:GetPos(),
|
||||
} )
|
||||
if tr.Hit and tr.Entity == e then
|
||||
self.LaserGuided = false
|
||||
self.target = e
|
||||
end
|
||||
end
|
||||
if IsValid( e ) and e:GetClass() == "sw_flr" then
|
||||
local tr = util.TraceLine( {
|
||||
start = self:GetPos(),
|
||||
endpos = e:GetPos(),
|
||||
} )
|
||||
if tr.Hit and tr.Entity == e then
|
||||
self.LaserGuided = false
|
||||
self.target = e
|
||||
end
|
||||
end
|
||||
if IsValid( e ) and e:GetClass() == "sw_flare_v3" then
|
||||
local tr = util.TraceLine( {
|
||||
start = self:GetPos(),
|
||||
endpos = e:GetPos(),
|
||||
} )
|
||||
if tr.Hit and tr.Entity == e then
|
||||
self.LaserGuided = false
|
||||
self.target = e
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if self:GetRadioFuze() then
|
||||
for _, e in pairs(ents.FindInSphere(self:GetPos(), self:GetRadioFuzeRadius())) do
|
||||
if IsValid( e ) and e != self.Launcher then
|
||||
if self.LaserGuided == true then
|
||||
if e.IsRocket == true and e.Launcher != self.Launcher then
|
||||
self.Exploded = true
|
||||
self:Explode()
|
||||
end
|
||||
if e.Fired == true and e.Launcher != self.Launcher then
|
||||
self.Exploded = true
|
||||
self:Explode()
|
||||
end
|
||||
if e.Armed == true and e.Launcher != self.Launcher then
|
||||
self.Exploded = true
|
||||
self:Explode()
|
||||
end
|
||||
if e.Burnt == true and e.Launcher != self.Launcher then
|
||||
self.Exploded = true
|
||||
self:Explode()
|
||||
end
|
||||
if ((e.LFS and e:GetEngineActive()) or ((e:GetClass() == "lvs_helicopter_engine" or e:GetClass() == "lvs_fighterplane_engine") and e:GetBase():GetEngineActive()) or (e.isWacAircraft and e.active)) then
|
||||
self.Exploded = true
|
||||
self:Explode()
|
||||
end
|
||||
else
|
||||
if ((e.LFS and e:GetEngineActive()) or ((e:GetClass() == "lvs_helicopter_engine" or e:GetClass() == "lvs_fighterplane_engine") and e:GetBase():GetEngineActive()) or (e.isWacAircraft and e.active)) then
|
||||
self.Exploded = true
|
||||
self:Explode()
|
||||
end
|
||||
|
||||
if e.IsRocket == true and e.Launcher != self.Launcher then
|
||||
self.Exploded = true
|
||||
self:Explode()
|
||||
end
|
||||
if e.Fired == true and e.Launcher != self.Launcher then
|
||||
self.Exploded = true
|
||||
self:Explode()
|
||||
end
|
||||
if e.Armed == true and e.Launcher != self.Launcher then
|
||||
self.Exploded = true
|
||||
self:Explode()
|
||||
end
|
||||
if e.Burnt == true and e.Launcher != self.Launcher then
|
||||
self.Exploded = true
|
||||
self:Explode()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if self:GetNWBool("Fired") == true then
|
||||
if not self.Burnt then
|
||||
local phys = self:GetPhysicsObject()
|
||||
|
||||
if IsValid(phys) then
|
||||
if self.MaxVelocityUnitsSquared and phys:GetVelocity():LengthSqr() < self.MaxVelocityUnitsSquared then
|
||||
phys:ApplyForceCenter(self:GetForward() * 500000)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if self.InGround or self.InEntity then
|
||||
if self:IsPlayerHolding() then
|
||||
self.InGround = false
|
||||
self.InEntity = false
|
||||
end
|
||||
end
|
||||
|
||||
self:OnTick()
|
||||
return true
|
||||
end
|
||||
function ENT:OnTick()
|
||||
end
|
||||
|
||||
--Flight physics
|
||||
function ENT:PhysicsSimulate( phys, deltatime )
|
||||
if self.GuidanceActive or IsValid(self.target) then return end
|
||||
phys:Wake()
|
||||
local ForceLinear, ForceAngle = phys:CalculateForceOffset( physenv.GetGravity(), phys:LocalToWorld( phys:GetMassCenter() + Vector(10,0,0) ) )
|
||||
ForceAngle = ForceAngle - phys:GetAngleVelocity() * 30
|
||||
if self.RotationalForce and self.Fired then
|
||||
phys:AddAngleVelocity(Vector(self.RotationalForce,0,0))
|
||||
end
|
||||
return ForceAngle, ForceLinear, SIM_GLOBAL_ACCELERATION
|
||||
end
|
||||
|
||||
--Guidance
|
||||
function ENT:LaserGuidance()
|
||||
if self.Armed and not (self.InGround or self.InEntity) then
|
||||
if self.LaserGuided then
|
||||
if IsValid(self.Launcher) then
|
||||
local Parent = self.Launcher
|
||||
local phys = self:GetPhysicsObject()
|
||||
local ID = Parent:LookupAttachment( self.LaserCode )
|
||||
local Attachment = Parent:GetAttachment( ID )
|
||||
if Parent:GetAttachment( ID ) then
|
||||
local TargetDir = Attachment.Ang:Forward()
|
||||
local tr = util.TraceLine( {
|
||||
start = Attachment.Pos,
|
||||
endpos = (Attachment.Pos + TargetDir * 999999),
|
||||
filter = {self,Parent,Parent.wheel_C,Parent.wheel_R,Parent.wheel_L}
|
||||
} )
|
||||
self.target = tr.Entity
|
||||
self.targetOffset = tr.Entity:WorldToLocal(tr.HitPos)
|
||||
phys:SetVelocity( self:GetVelocity() + self:GetAngles():Forward() * 50 )
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
function ENT:Guidance(ph)
|
||||
if self.target != NULL then
|
||||
if IsValid(self.target) or self.target:GetClass() == "worldspawn" then
|
||||
if not (self.InGround or self.Armed or self.InEntity) then return end
|
||||
local pos = self:GetPos()
|
||||
local vel = self:WorldToLocal(pos+ph:GetVelocity())*0.4
|
||||
vel.x = 0
|
||||
local target = self.target:LocalToWorld(self.targetOffset)
|
||||
local v = self:WorldToLocal(target + Vector(0,0,math.Clamp((pos*Normal):Distance(target*Normal)/5 - 10,0,self.DiveHeight or 0))):GetNormal()
|
||||
if isnumber(self.Agility) then
|
||||
v.y = math.Clamp(v.y*10,-1,1)*self.Agility
|
||||
v.z = math.Clamp(v.z*10,-1,1)*self.Agility
|
||||
else
|
||||
v.y = math.Clamp(v.y*10,-1,1)*10
|
||||
v.z = math.Clamp(v.z*10,-1,1)*10
|
||||
end
|
||||
if self.Fired then
|
||||
if self.SpiralRadius > 0 then
|
||||
self.SpiralRadius = self.SpiralRadius - FrameTime()*(self.StabilisationTime or 50)
|
||||
end
|
||||
if self.SpiralRadius < 0 then
|
||||
self.SpiralRadius = self.SpiralRadius + FrameTime()*(self.StabilisationTime or 50)
|
||||
end
|
||||
if self.SpiralRate > 0 then
|
||||
self.SpiralRate = self.SpiralRate - FrameTime()
|
||||
end
|
||||
if self.SpiralRate < 0 then
|
||||
self.SpiralRate = self.SpiralRate + FrameTime()
|
||||
end
|
||||
end
|
||||
if self.SpiralRadnom then
|
||||
ph:AddAngleVelocity(
|
||||
ph:GetAngleVelocity()*self.SpiralRate
|
||||
+ Vector(math.Rand(-self.SpiralRadius,self.SpiralRadius), math.Rand(-self.SpiralRadius,self.SpiralRadius), math.Rand(-self.SpiralRadius,self.SpiralRadius))
|
||||
+ Vector(0,-vel.z,vel.y)
|
||||
+ Vector(0,-v.z,v.y)
|
||||
)
|
||||
else
|
||||
ph:AddAngleVelocity(
|
||||
ph:GetAngleVelocity()*self.SpiralRate
|
||||
+ Vector(self.SpiralRadius, self.SpiralRadius, self.SpiralRadius)
|
||||
+ Vector(0,-vel.z,vel.y)
|
||||
+ Vector(0,-v.z,v.y)
|
||||
)
|
||||
end
|
||||
ph:AddVelocity(self:GetForward() - self:LocalToWorld(vel*Normal2) + pos)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--Taking damage
|
||||
function ENT:OnTakeDamage(dmginfo)
|
||||
if self.Exploded then return end
|
||||
local inflictor = dmginfo:GetInflictor()
|
||||
local attacker = dmginfo:GetAttacker()
|
||||
if IsValid(inflictor) and (inflictor.IsGredBomb or inflictor.lvsProjectile or inflictor.SWBombV3 ) then return end
|
||||
self:TakePhysicsDamage(dmginfo)
|
||||
self.CurDurability = self.CurDurability - dmginfo:GetDamage()
|
||||
if self.Armed then
|
||||
if self.CurDurability <= 0 then
|
||||
self.Exploded = true
|
||||
self:Explode(self:GetPos())
|
||||
end
|
||||
else
|
||||
if !self.Armed and !self.Fired then
|
||||
self:EmitSound(self.ArmSound)
|
||||
self.Armed = true
|
||||
self:Launch()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--Explosion
|
||||
function ENT:Explode(pos)
|
||||
if !self.Exploded then return end
|
||||
if !self.Armed then return end
|
||||
pos = self:LocalToWorld(self:OBBCenter())
|
||||
if(self:WaterLevel() >= 1) then
|
||||
local tr = util.TraceLine({
|
||||
start = pos,
|
||||
endpos = pos + Vector(0,0,9000),
|
||||
filter = self,
|
||||
})
|
||||
local tr2 = util.TraceLine({
|
||||
start = tr.HitPos,
|
||||
endpos = tr.HitPos - Vector(0,0,9000),
|
||||
filter = self,
|
||||
mask = MASK_WATER + CONTENTS_TRANSLUCENT,
|
||||
})
|
||||
if tr2.Hit then
|
||||
ParticleEffect(self.EffectWater, tr2.HitPos,(self.AngEffect and angle_dif or angle_reg), nil)
|
||||
end
|
||||
else
|
||||
local tr = util.TraceLine({
|
||||
start = pos,
|
||||
endpos = pos - Vector(0, 0, self.TraceLength),
|
||||
filter = self,
|
||||
})
|
||||
if tr.HitWorld then
|
||||
ParticleEffect(self.Effect,pos,(self.AngEffect and angle_dif or angle_reg),nil)
|
||||
else
|
||||
ParticleEffect(self.EffectAir,pos,(self.AngEffect and angle_dif or angle_reg),nil)
|
||||
end
|
||||
end
|
||||
|
||||
if self.HEAT then
|
||||
local heat = {}
|
||||
heat.Src = self:GetPos()
|
||||
heat.Dir = self:GetAngles():Forward()
|
||||
heat.Spread = Vector(0,0,0)
|
||||
heat.Force = self.ArmorPenetration+math.Rand(-self.ArmorPenetration/10,self.ArmorPenetration/10)
|
||||
heat.HullSize = self.HEATRadius or 0
|
||||
heat.Damage = self.PenetrationDamage+math.Rand(-self.PenetrationDamage/5,self.PenetrationDamage/5)
|
||||
heat.Velocity = 10000
|
||||
heat.Attacker = self.Owner
|
||||
LVS:FireBullet( heat )
|
||||
|
||||
--Blast wave
|
||||
if self.ExplosionRadius > 0 then
|
||||
util.BlastDamage( self, ((IsValid(self:GetCreator()) and self:GetCreator()) or self.Attacker or game.GetWorld()), pos, self.ExplosionRadius,self.ExplosionDamage )
|
||||
self:BlastDoors(self, pos, 10)
|
||||
end
|
||||
|
||||
--Frags
|
||||
if self.FragCount > 0 then
|
||||
self:Fragmentation(self,pos,10000,self.FragDamage,self.FragRadius,((IsValid(self:GetCreator()) and self:GetCreator()) or self.Attacker or game.GetWorld()))
|
||||
end
|
||||
|
||||
debugoverlay.Text(pos+Vector(0,0,10),"Penetration: "..heat.Force,5)
|
||||
debugoverlay.Text(pos-Vector(0,0,10),"Damage: "..heat.Damage,5)
|
||||
debugoverlay.Sphere(pos,self.ExplosionRadius,5,Color(200,150,0,100),false)
|
||||
debugoverlay.Sphere(pos,self.FragRadius,5,Color(200,200,0,100),false)
|
||||
else
|
||||
debugoverlay.Sphere(pos,self.ExplosionRadius,5,Color(255,0,0,100),false)
|
||||
debugoverlay.Sphere(pos,self.BlastRadius,5,Color(200,150,0,100),false)
|
||||
debugoverlay.Sphere(pos,self.FragRadius,5,Color(200,200,0,100),false)
|
||||
|
||||
--Deadly zone
|
||||
if self.ExplosionRadius > 0 then
|
||||
for k, v in pairs(ents.FindInSphere(pos,self.ExplosionRadius)) do
|
||||
if v:IsValid() and not v.SWBombV3 then
|
||||
local dmg = DamageInfo()
|
||||
dmg:SetInflictor(self)
|
||||
dmg:SetDamage(self.ExplosionDamage)
|
||||
dmg:SetDamageType(self.DamageType)
|
||||
dmg:SetAttacker((IsValid(self:GetCreator()) and self:GetCreator()) or self.Attacker or game.GetWorld())
|
||||
v:TakeDamageInfo(dmg)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--Blast wave
|
||||
if self.BlastRadius > 0 then
|
||||
util.BlastDamage( self, ((IsValid(self:GetCreator()) and self:GetCreator()) or self.Attacker or game.GetWorld()), pos, self.BlastRadius,self.ExplosionDamage/2 )
|
||||
self:BlastDoors(self, pos, 10)
|
||||
end
|
||||
|
||||
--Frags
|
||||
if self.FragCount > 0 then
|
||||
self:Fragmentation(self,pos,10000,self.FragDamage,self.FragRadius,((IsValid(self:GetCreator()) and self:GetCreator()) or self.Attacker or game.GetWorld()))
|
||||
end
|
||||
end
|
||||
|
||||
swv3.CreateSound(pos,false,self.ExplosionSound,self.FarExplosionSound,self.DistExplosionSound)
|
||||
timer.Simple(0,function()
|
||||
if !IsValid(self) then return end
|
||||
self:Remove()
|
||||
end)
|
||||
end
|
||||
|
||||
--Impact
|
||||
function ENT:PhysicsCollide( data, physobj )
|
||||
if self:GetVelocity():Length() >= self.ImpactSpeed then
|
||||
if self.Armed then
|
||||
self.Exploded = true
|
||||
self:Explode(self:GetPos())
|
||||
else
|
||||
if !self.Armed and !self.Fired then
|
||||
self:EmitSound(self.ArmSound)
|
||||
self.Armed = true
|
||||
self:Launch()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--Door blasting
|
||||
function ENT:IsDoor(ent)
|
||||
local Class = ent:GetClass()
|
||||
|
||||
return (Class == "prop_door") or (Class == "prop_door_rotating") or (Class == "func_door") or (Class == "func_door_rotating")
|
||||
end
|
||||
function ENT:BlastDoors(blaster, pos, power, range, ignoreVisChecks)
|
||||
for k, door in pairs(ents.FindInSphere(pos, 40 * power * (range or 1))) do
|
||||
if self:IsDoor(door) then
|
||||
local proceed = ignoreVisChecks
|
||||
|
||||
if not proceed then
|
||||
local tr = util.QuickTrace(pos, door:LocalToWorld(door:OBBCenter()) - pos, blaster)
|
||||
proceed = IsValid(tr.Entity) and (tr.Entity == door)
|
||||
end
|
||||
|
||||
if proceed then
|
||||
self:BlastDoor(door, (door:LocalToWorld(door:OBBCenter()) - pos):GetNormalized() * 1000)
|
||||
end
|
||||
end
|
||||
if door:GetClass() == "func_breakable_surf" then
|
||||
door:Fire("Break")
|
||||
end
|
||||
end
|
||||
end
|
||||
function ENT:BlastDoor(ent, vel)
|
||||
local Moddel, Pozishun, Ayngul, Muteeriul, Skin = ent:GetModel(), ent:GetPos(), ent:GetAngles(), ent:GetMaterial(), ent:GetSkin()
|
||||
sound.Play("Wood_Crate.Break", Pozishun, 60, 100)
|
||||
sound.Play("Wood_Furniture.Break", Pozishun, 60, 100)
|
||||
ent:Fire("unlock", "", 0)
|
||||
ent:Fire("open", "", 0)
|
||||
ent:SetNoDraw(true)
|
||||
ent:SetNotSolid(true)
|
||||
|
||||
if Moddel and Pozishun and Ayngul then
|
||||
local Replacement = ents.Create("prop_physics")
|
||||
Replacement:SetModel(Moddel)
|
||||
Replacement:SetPos(Pozishun + Vector(0, 0, 1))
|
||||
Replacement:SetAngles(Ayngul)
|
||||
|
||||
if Muteeriul then
|
||||
Replacement:SetMaterial(Muteeriul)
|
||||
end
|
||||
|
||||
if Skin then
|
||||
Replacement:SetSkin(Skin)
|
||||
end
|
||||
|
||||
Replacement:SetModelScale(.9, 0)
|
||||
Replacement:Spawn()
|
||||
Replacement:Activate()
|
||||
|
||||
if vel then
|
||||
Replacement:GetPhysicsObject():SetVelocity(vel)
|
||||
|
||||
timer.Simple(0, function()
|
||||
if IsValid(Replacement) then
|
||||
Replacement:GetPhysicsObject():ApplyForceCenter(vel * 100)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
timer.Simple(3, function()
|
||||
if IsValid(Replacement) then
|
||||
Replacement:SetCollisionGroup(COLLISION_GROUP_WEAPON)
|
||||
end
|
||||
end)
|
||||
|
||||
timer.Simple(30, function()
|
||||
if IsValid(ent) then
|
||||
ent:SetNotSolid(false)
|
||||
ent:SetNoDraw(false)
|
||||
end
|
||||
|
||||
if IsValid(Replacement) then
|
||||
Replacement:Remove()
|
||||
end
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
--Frags
|
||||
function ENT:Fragmentation(shooter, origin, fragNum, fragDmg, fragMaxDist, attacker, direction, spread, zReduction)
|
||||
shooter = shooter or game.GetWorld()
|
||||
zReduction = zReduction or 2
|
||||
|
||||
local Spred = Vector(0, 0, 0)
|
||||
local BulletsFired, MaxBullets, disperseTime = 0, self.FragCount, .5
|
||||
|
||||
if fragNum >= 12000 then
|
||||
disperseTime = 2
|
||||
elseif fragNum >= 6000 then
|
||||
disperseTime = 1
|
||||
end
|
||||
|
||||
for i = 1, fragNum do
|
||||
timer.Simple((i / fragNum) * disperseTime, function()
|
||||
local Dir
|
||||
|
||||
if direction and spread then
|
||||
Dir = Vector(direction.x, direction.y, direction.z)
|
||||
Dir = Dir + VectorRand() * math.Rand(0, spread)
|
||||
Dir:Normalize()
|
||||
else
|
||||
Dir = VectorRand()
|
||||
end
|
||||
|
||||
if zReduction then
|
||||
Dir.z = Dir.z / zReduction
|
||||
Dir:Normalize()
|
||||
end
|
||||
|
||||
local Tr = util.QuickTrace(origin, Dir * fragMaxDist, shooter)
|
||||
|
||||
if Tr.Hit and not Tr.HitSky and not Tr.HitWorld and (BulletsFired < MaxBullets) then
|
||||
local LowFrag = (Tr.Entity.IsVehicle and Tr.Entity:IsVehicle()) or Tr.Entity.LFS or Tr.Entity.LVS or Tr.Entity.EZlowFragPlease
|
||||
|
||||
if (not LowFrag) or (LowFrag and math.random(1, 4) == 2) then
|
||||
|
||||
local firer = (IsValid(shooter) and shooter) or game.GetWorld()
|
||||
|
||||
firer:FireBullets({
|
||||
Attacker = attacker,
|
||||
Damage = fragDmg,
|
||||
Force = fragDmg / 8,
|
||||
Num = 1,
|
||||
Src = origin,
|
||||
Tracer = 0,
|
||||
Dir = Dir,
|
||||
Spread = Spred,
|
||||
AmmoType = "Buckshot"
|
||||
})
|
||||
BulletsFired = BulletsFired + 1
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if CLIENT then
|
||||
function ENT:Initialize()
|
||||
self.snd = CreateSound(self, self.WhistleSound)
|
||||
self.snd:SetSoundLevel( 110 )
|
||||
self.snd:PlayEx(0,150)
|
||||
|
||||
self.EngSND = CreateSound( self, self.EngineSound )
|
||||
end
|
||||
function ENT:CalcDoppler()
|
||||
local Ent = LocalPlayer()
|
||||
local ViewEnt = Ent:GetViewEntity()
|
||||
|
||||
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.Fired then
|
||||
self.EngSND:Play()
|
||||
end
|
||||
if self:GetNWBool("Fired",false) and not self:GetNWBool("IsPlayerHolding",true) then
|
||||
if self:GetTracerScale() then
|
||||
if self.Tracer1Att and not self.TracerEffect then
|
||||
self.Tracer = Material("sprites/animglow02")
|
||||
self.Tracer:SetVector("$color", Vector(255,0,0))
|
||||
if IsValid(self.Emitter) then
|
||||
local particle
|
||||
for i = 0,1 do
|
||||
local ID = self:LookupAttachment( self.Tracer1Att )
|
||||
local Attachment = self:GetAttachment( ID )
|
||||
particle = self.Emitter:Add(self.Tracer,Attachment.Pos)
|
||||
if particle then
|
||||
particle:SetVelocity(self:GetVelocity())
|
||||
particle:SetDieTime(0.015)
|
||||
particle:SetAirResistance(0)
|
||||
particle:SetStartAlpha(255)
|
||||
particle:SetStartSize(self:GetTracerScale()*2)
|
||||
particle:SetEndSize(self:GetTracerScale()*2)
|
||||
particle:SetRoll(math.Rand(-1,1))
|
||||
particle:SetGravity(Vector(0,0,0))
|
||||
particle:SetCollide(false)
|
||||
end
|
||||
end
|
||||
else
|
||||
self.Emitter = ParticleEmitter(self:GetPos(),false)
|
||||
end
|
||||
end
|
||||
if self.Tracer2Att and not self.TracerEffect then
|
||||
self.Tracer = Material("sprites/animglow02")
|
||||
self.Tracer:SetVector("$color", Vector(255,0,0))
|
||||
if IsValid(self.Emitter) then
|
||||
local particle
|
||||
for i = 0,1 do
|
||||
local ID = self:LookupAttachment( self.Tracer2Att )
|
||||
local Attachment = self:GetAttachment( ID )
|
||||
particle = self.Emitter:Add(self.Tracer,Attachment.Pos)
|
||||
if particle then
|
||||
particle:SetVelocity(self:GetVelocity())
|
||||
particle:SetDieTime(0.015)
|
||||
particle:SetAirResistance(0)
|
||||
particle:SetStartAlpha(255)
|
||||
particle:SetStartSize(self:GetTracerScale()*2)
|
||||
particle:SetEndSize(self:GetTracerScale()*2)
|
||||
particle:SetRoll(math.Rand(-1,1))
|
||||
particle:SetGravity(Vector(0,0,0))
|
||||
particle:SetCollide(false)
|
||||
end
|
||||
end
|
||||
else
|
||||
self.Emitter = ParticleEmitter(self:GetPos(),false)
|
||||
end
|
||||
end
|
||||
if not self.Tracer1Att and not self.Tracer2Att then
|
||||
self.Tracer = Material("sprites/animglow02")
|
||||
self.Tracer:SetVector("$color", Vector(255,0,0))
|
||||
if IsValid(self.Emitter) then
|
||||
local particle
|
||||
for i = 0,1 do
|
||||
particle = self.Emitter:Add(self.Tracer,self:GetPos())
|
||||
if particle then
|
||||
particle:SetVelocity(self:GetVelocity())
|
||||
particle:SetDieTime(0.015)
|
||||
particle:SetAirResistance(0)
|
||||
particle:SetStartAlpha(255)
|
||||
particle:SetStartSize(self:GetTracerScale()*2)
|
||||
particle:SetEndSize(self:GetTracerScale()*2)
|
||||
particle:SetRoll(math.Rand(-1,1))
|
||||
particle:SetGravity(Vector(0,0,0))
|
||||
particle:SetCollide(false)
|
||||
end
|
||||
end
|
||||
else
|
||||
self.Emitter = ParticleEmitter(self:GetPos(),false)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
function ENT:Draw()
|
||||
self:DrawModel()
|
||||
end
|
||||
function ENT:SoundStop()
|
||||
if self.snd then
|
||||
self.snd:Stop()
|
||||
end
|
||||
end
|
||||
function ENT:OnRemove()
|
||||
self:SoundStop()
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user