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