using System.Collections.Generic; using Content.Server.GameObjects.Components.Mobs; using Content.Shared.Damage; using Content.Shared.GameObjects.Components.Damage; using Content.Shared.GameObjects.Components.Projectiles; using Robust.Server.GameObjects.EntitySystems; using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Components; using Robust.Shared.GameObjects.Systems; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Serialization; using Robust.Shared.ViewVariables; namespace Content.Server.GameObjects.Components.Projectiles { [RegisterComponent] public class ProjectileComponent : SharedProjectileComponent, ICollideBehavior { protected override EntityUid Shooter => _shooter; private EntityUid _shooter = EntityUid.Invalid; private Dictionary _damages; [ViewVariables] public Dictionary Damages { get => _damages; set => _damages = value; } public bool DeleteOnCollide => _deleteOnCollide; private bool _deleteOnCollide; // Get that juicy FPS hit sound private string _soundHit; private string _soundHitSpecies; private bool _damagedEntity; public override void ExposeData(ObjectSerializer serializer) { base.ExposeData(serializer); serializer.DataField(ref _deleteOnCollide, "delete_on_collide", true); // If not specified 0 damage serializer.DataField(ref _damages, "damages", new Dictionary()); serializer.DataField(ref _soundHit, "soundHit", null); serializer.DataField(ref _soundHitSpecies, "soundHitSpecies", null); } public float TimeLeft { get; set; } = 10; /// /// Function that makes the collision of this object ignore a specific entity so we don't collide with ourselves /// /// public void IgnoreEntity(IEntity shooter) { _shooter = shooter.Uid; Dirty(); } /// /// Applies the damage when our projectile collides with its victim /// /// void ICollideBehavior.CollideWith(IEntity entity) { if (_damagedEntity) { return; } // This is so entities that shouldn't get a collision are ignored. if (entity.TryGetComponent(out ICollidableComponent collidable) && collidable.Hard == false) { _deleteOnCollide = false; return; } else { _deleteOnCollide = true; } if (_soundHitSpecies != null && entity.HasComponent()) { EntitySystem.Get().PlayAtCoords(_soundHitSpecies, entity.Transform.Coordinates); } else if (_soundHit != null) { EntitySystem.Get().PlayAtCoords(_soundHit, entity.Transform.Coordinates); } if (entity.TryGetComponent(out IDamageableComponent damage)) { Owner.EntityManager.TryGetEntity(_shooter, out var shooter); foreach (var (damageType, amount) in _damages) { damage.ChangeDamage(damageType, amount, false, shooter); } _damagedEntity = true; } if (!entity.Deleted && entity.TryGetComponent(out CameraRecoilComponent recoilComponent) && Owner.TryGetComponent(out ICollidableComponent collidableComponent)) { var direction = collidableComponent.LinearVelocity.Normalized; recoilComponent.Kick(direction); } } void ICollideBehavior.PostCollide(int collideCount) { if (collideCount > 0 && DeleteOnCollide) Owner.Delete(); } public override ComponentState GetComponentState() { return new ProjectileComponentState(NetID!.Value, _shooter, IgnoreShooter); } } }