using Content.Server.Administration.Logs; using Content.Server.Camera; using Content.Server.Projectiles.Components; using Content.Shared.Body.Components; using Content.Shared.Damage; using Content.Shared.Database; using JetBrains.Annotations; using Robust.Shared.Audio; using Robust.Shared.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Physics.Dynamics; using Robust.Shared.Player; namespace Content.Server.Projectiles { [UsedImplicitly] internal sealed class ProjectileSystem : EntitySystem { [Dependency] private readonly DamageableSystem _damageableSystem = default!; [Dependency] private readonly AdminLogSystem _adminLogSystem = default!; public override void Initialize() { base.Initialize(); SubscribeLocalEvent(HandleCollide); } private void HandleCollide(EntityUid uid, ProjectileComponent component, StartCollideEvent args) { // This is so entities that shouldn't get a collision are ignored. if (!args.OtherFixture.Hard || component.DamagedEntity) { return; } var otherEntity = args.OtherFixture.Body.Owner; var coordinates = EntityManager.GetComponent(args.OtherFixture.Body.Owner).Coordinates; var playerFilter = Filter.Pvs(coordinates); if (!EntityManager.GetComponent(otherEntity).EntityDeleted && component.SoundHitSpecies != null && EntityManager.HasComponent(otherEntity)) { SoundSystem.Play(playerFilter, component.SoundHitSpecies.GetSound(), coordinates); } else { var soundHit = component.SoundHit?.GetSound(); if (!string.IsNullOrEmpty(soundHit)) SoundSystem.Play(playerFilter, soundHit, coordinates); } if (!EntityManager.GetComponent(otherEntity).EntityDeleted) { var dmg = _damageableSystem.TryChangeDamage(otherEntity, component.Damage); component.DamagedEntity = true; if (dmg is not null && EntityManager.EntityExists(component.Shooter)) _adminLogSystem.Add(LogType.BulletHit, LogImpact.Low, $"Projectile {ToPrettyString(component.Owner):projectile} shot by {ToPrettyString(component.Shooter):user} hit {ToPrettyString(otherEntity):target} and dealt {dmg.Total:damage} damage"); } // Damaging it can delete it if (!EntityManager.GetComponent(otherEntity).EntityDeleted && EntityManager.TryGetComponent(otherEntity, out CameraRecoilComponent? recoilComponent)) { var direction = args.OurFixture.Body.LinearVelocity.Normalized; recoilComponent.Kick(direction); } if (component.DeleteOnCollide) EntityManager.QueueDeleteEntity(uid); } public override void Update(float frameTime) { base.Update(frameTime); foreach (var component in EntityManager.EntityQuery()) { component.TimeLeft -= frameTime; if (component.TimeLeft <= 0) { EntityManager.DeleteEntity(component.Owner); } } } } }