602 lines
18 KiB
Lua
602 lines
18 KiB
Lua
AddCSLuaFile()
|
|
|
|
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"
|
|
|
|
--Main info
|
|
ENT.Type = "anim"
|
|
ENT.Spawnable = false
|
|
ENT.AdminSpawnable = false
|
|
ENT.AdminOnly = false
|
|
ENT.PrintName = "Bomb basescript V3"
|
|
ENT.Author = "Shermann Wolf"
|
|
ENT.Contact = "shermannwolf@gmail.com"
|
|
ENT.Category = "SW Bombs V3"
|
|
ENT.Editable = true
|
|
ENT.SWBombV3 = true
|
|
|
|
--Visual
|
|
ENT.Model = "models/sw/rus/bombs/ao25m1.mdl"
|
|
ENT.Effect = "ins_m203_explosion"
|
|
ENT.EffectAir = "ins_m203_explosion"
|
|
ENT.EffectWater = "ins_water_explosion"
|
|
ENT.Decal = "scorch_25kg"
|
|
ENT.AngEffect = true
|
|
|
|
--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
|
|
|
|
--Physics
|
|
ENT.TraceLength = 500
|
|
ENT.ImpactSpeed = 100
|
|
ENT.ImpactDepth = 25
|
|
ENT.Mass = 0
|
|
ENT.Durability = 10
|
|
ENT.DetonateHeight = 0
|
|
|
|
--Explosion
|
|
ENT.DamageType = DMG_BURN
|
|
ENT.ExplosionDamage = 10000
|
|
ENT.ExplosionRadius = 300
|
|
ENT.BlastRadius = 450
|
|
ENT.FragDamage = 25
|
|
ENT.FragRadius = 600
|
|
ENT.FragCount = 100
|
|
|
|
--Guidance
|
|
ENT.DiveHeight = 1000
|
|
ENT.Agility = 100
|
|
ENT.HaveGuidance = false
|
|
ENT.GuidanceActive = false
|
|
ENT.LaserGuided = false
|
|
ENT.LaserCode = "view"
|
|
|
|
function ENT:SetupDataTables()
|
|
self:NetworkVar("Bool",0,"Timed", {KeyName = "timed", Edit = { type = "Boolean", category = "Fuze"}})
|
|
self:NetworkVar("Int",1,"Timer", { KeyName = "timer", Edit = { type = "Int", min = 0, max = 120, category = "Fuze"} } )
|
|
self:NetworkVar("Bool",2,"AirDetonate", {KeyName = "airdetonate", Edit = { type = "Boolean", category = "Fuze"}})
|
|
self:NetworkVar("Int",3,"DetonateHeight", { KeyName = "detonateheight", Edit = { type = "Int", min = 0, max = 2000, 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.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_WORLD )
|
|
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.FreefallTicks=0
|
|
self:OnSpawn()
|
|
end
|
|
|
|
function ENT:OnSpawn()
|
|
end
|
|
|
|
--Arming
|
|
function ENT:Use( activator, caller )
|
|
if !self.Exploded and !self.Armed then
|
|
self:EmitSound(self.ArmSound)
|
|
self.Armed = true
|
|
end
|
|
end
|
|
|
|
--Think
|
|
function ENT:Think()
|
|
self:NextThink(CurTime())
|
|
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 >= 15 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.GuidanceActive then
|
|
self:LaserGuidance()
|
|
self:Guidance(self:GetPhysicsObject())
|
|
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 )
|
|
phys:Wake()
|
|
local ForceLinear, ForceAngle = phys:CalculateForceOffset( physenv.GetGravity(), phys:LocalToWorld( phys:GetMassCenter() + Vector(10,0,0) ) )
|
|
if self.WingsOpen then
|
|
ForceAngle = ForceAngle - phys:GetAngleVelocity() * 30
|
|
else
|
|
ForceAngle = ForceAngle - phys:GetAngleVelocity() * 5
|
|
if not self.GuidanceActive then
|
|
phys:AddAngleVelocity(Vector(self:GetVelocity():Length()*0.01,0,0))
|
|
end
|
|
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.TraceHull( {
|
|
start = Attachment.Pos,
|
|
endpos = (Attachment.Pos + TargetDir * 999999),
|
|
mins = Vector( -1, -1, -1 ),
|
|
maxs = Vector( 1, 1, 1 ),
|
|
filter = {self,Parent,Parent.wheel_C,Parent.wheel_R,Parent.wheel_L}
|
|
} )
|
|
self.target = tr.Entity
|
|
self.targetOffset = tr.Entity:WorldToLocal(tr.HitPos)
|
|
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 - 50,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
|
|
ph:AddAngleVelocity(
|
|
ph:GetAngleVelocity()*-0.4
|
|
+ Vector(math.Rand(-1,1), math.Rand(-1,1), math.Rand(-1,1))*5
|
|
+ Vector(0,-vel.z,vel.y)
|
|
+ Vector(0,-v.z,v.y)
|
|
)
|
|
ph:AddVelocity(self:GetForward()*10 - 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
|
|
if IsValid(attacker) and (attacker.IsGredBomb or attacker.lvsProjectile or attacker.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
|
|
self:EmitSound(self.ArmSound)
|
|
self.Armed = true
|
|
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
|
|
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
|
|
|
|
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
|
|
local tr = util.TraceLine({
|
|
start = self:LocalToWorld(self:OBBCenter()),
|
|
endpos =self:LocalToWorld(self:OBBCenter())+self:GetAngles():Forward()*self.TraceLength,
|
|
filter = self,
|
|
})
|
|
if not (self.InGround or self.InEntity) then
|
|
if tr.Hit and tr.HitWorld and not tr.HitSky then
|
|
if self:WaterLevel() <= 0 then
|
|
self:EmitSound(self.ImpactSound)
|
|
self:EmitSound(self.DebrisSound)
|
|
else
|
|
self:EmitSound(self.WaterImpactSound)
|
|
end
|
|
self:SetPos(self:GetPos()+self:GetAngles():Forward()*(self.ImpactDepth))
|
|
self:SetAngles(self:GetAngles())
|
|
self:GetPhysicsObject():EnableMotion(false)
|
|
self.InGround = true
|
|
elseif tr.Hit and not tr.HitWorld and not tr.HitSky then
|
|
if IsValid(tr.Entity) then
|
|
if self:WaterLevel() <= 0 then
|
|
self:EmitSound(self.ImpactSound)
|
|
self:EmitSound(self.DebrisSound)
|
|
else
|
|
self:EmitSound(self.WaterImpactSound)
|
|
end
|
|
self:SetPos(self:GetPos()+self:GetAngles():Forward()*(self.ImpactDepth))
|
|
self:SetAngles(self:GetAngles())
|
|
self:SetParent(tr.Entity)
|
|
self.InEntity = true
|
|
end
|
|
end
|
|
end
|
|
|
|
if self.Armed then
|
|
if self:GetTimed() then
|
|
timer.Simple(self:GetTimer(),function()
|
|
if IsValid(self) then
|
|
self.Exploded = true
|
|
self:Explode(self:GetPos())
|
|
end
|
|
end)
|
|
else
|
|
self.Exploded = true
|
|
self:Explode(self:GetPos())
|
|
end
|
|
else
|
|
self:EmitSound(self.ArmSound)
|
|
self.Armed = true
|
|
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)
|
|
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
|
|
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
|