diff --git a/Content.Server/Weapon/Ranged/Ammunition/Components/AmmoComponent.cs b/Content.Server/Weapon/Ranged/Ammunition/Components/AmmoComponent.cs index a12ca95d19..4481e6a1a5 100644 --- a/Content.Server/Weapon/Ranged/Ammunition/Components/AmmoComponent.cs +++ b/Content.Server/Weapon/Ranged/Ammunition/Components/AmmoComponent.cs @@ -3,14 +3,18 @@ using Content.Shared.Examine; using Content.Shared.Sound; using Content.Shared.Weapons.Ranged.Barrels.Components; using Robust.Server.GameObjects; +using Robust.Shared.Analyzers; using Robust.Shared.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Localization; using Robust.Shared.Log; using Robust.Shared.Map; using Robust.Shared.Maths; +using Robust.Shared.Prototypes; using Robust.Shared.Serialization; using Robust.Shared.Serialization.Manager.Attributes; +using Robust.Shared.Serialization.TypeSerializers.Implementations; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; using Robust.Shared.Timing; using Robust.Shared.Utility; @@ -21,15 +25,10 @@ namespace Content.Server.Weapon.Ranged.Ammunition.Components /// Generally used for bullets but can be used for other things like bananas /// [RegisterComponent] -#pragma warning disable 618 - public class AmmoComponent : Component, IExamine, ISerializationHooks -#pragma warning restore 618 + [ComponentProtoName("Ammo")] + [Friend(typeof(GunSystem))] + public sealed class AmmoComponent : Component, ISerializationHooks { - [Dependency] private readonly IEntityManager _entMan = default!; - [Dependency] private readonly IGameTiming _gameTiming = default!; - - public override string Name => "Ammo"; - [DataField("caliber")] public BallisticCaliber Caliber { get; } = BallisticCaliber.Unspecified; @@ -37,22 +36,23 @@ namespace Content.Server.Weapon.Ranged.Ammunition.Components { get { - if (_ammoIsProjectile) + if (AmmoIsProjectile) { return false; } return _spent; } + set => _spent = value; } private bool _spent; + // TODO: Make it so null projectile = dis /// /// Used for anything without a case that fires itself /// - [DataField("isProjectile")] - private bool _ammoIsProjectile; + [DataField("isProjectile")] public bool AmmoIsProjectile; /// /// Used for something that is deleted when the projectile is retrieved @@ -69,8 +69,8 @@ namespace Content.Server.Weapon.Ranged.Ammunition.Components [DataField("projectilesFired")] public int ProjectilesFired { get; } = 1; - [DataField("projectile")] - private string? _projectileId; + [DataField("projectile", customTypeSerializer: typeof(PrototypeIdSerializer))] + public string? ProjectileId; // How far apart each entity is if multiple are shot [DataField("ammoSpread")] @@ -82,8 +82,8 @@ namespace Content.Server.Weapon.Ranged.Ammunition.Components [DataField("ammoVelocity")] public float Velocity { get; } = 20f; - [DataField("muzzleFlash")] - private string _muzzleFlashSprite = "Objects/Weapons/Guns/Projectiles/bullet_muzzle.png"; + [DataField("muzzleFlash", customTypeSerializer:typeof(ResourcePathSerializer))] + public ResourcePath? MuzzleFlashSprite = new("Objects/Weapons/Guns/Projectiles/bullet_muzzle.png"); [DataField("soundCollectionEject")] public SoundSpecifier SoundCollectionEject { get; } = new SoundCollectionSpecifier("CasingEject"); @@ -91,7 +91,7 @@ namespace Content.Server.Weapon.Ranged.Ammunition.Components void ISerializationHooks.AfterDeserialization() { // Being both caseless and shooting yourself doesn't make sense - DebugTools.Assert(!(_ammoIsProjectile == true && Caseless == true)); + DebugTools.Assert(!(AmmoIsProjectile && Caseless)); if (ProjectilesFired < 1) { @@ -104,63 +104,6 @@ namespace Content.Server.Weapon.Ranged.Ammunition.Components throw new InvalidOperationException(); } } - - public EntityUid? TakeBullet(EntityCoordinates spawnAt) - { - if (_ammoIsProjectile) - { - return Owner; - } - - if (_spent) - { - return null; - } - - _spent = true; - if (_entMan.TryGetComponent(Owner, out AppearanceComponent? appearanceComponent)) - { - appearanceComponent.SetData(AmmoVisuals.Spent, true); - } - - var entity = _entMan.SpawnEntity(_projectileId, spawnAt); - - return entity; - } - - public void MuzzleFlash(EntityUid entity, Angle angle) - { - if (_muzzleFlashSprite == null) - { - return; - } - - var time = _gameTiming.CurTime; - var deathTime = time + TimeSpan.FromMilliseconds(200); - // Offset the sprite so it actually looks like it's coming from the gun - var offset = angle.ToVec().Normalized / 2; - - var message = new EffectSystemMessage - { - EffectSprite = _muzzleFlashSprite, - Born = time, - DeathTime = deathTime, - AttachedEntityUid = entity, - AttachedOffset = offset, - //Rotated from east facing - Rotation = (float) angle.Theta, - Color = Vector4.Multiply(new Vector4(255, 255, 255, 255), 1.0f), - ColorDelta = new Vector4(0, 0, 0, -1500f), - Shaded = false - }; - EntitySystem.Get().CreateParticle(message); - } - - public void Examine(FormattedMessage message, bool inDetailsRange) - { - var text = Loc.GetString("ammo-component-on-examine",("caliber", Caliber)); - message.AddMarkup(text); - } } public enum BallisticCaliber diff --git a/Content.Server/Weapon/Ranged/Barrels/Components/BoltActionBarrelComponent.cs b/Content.Server/Weapon/Ranged/Barrels/Components/BoltActionBarrelComponent.cs index dc6012d76b..d5d6a8a17c 100644 --- a/Content.Server/Weapon/Ranged/Barrels/Components/BoltActionBarrelComponent.cs +++ b/Content.Server/Weapon/Ranged/Barrels/Components/BoltActionBarrelComponent.cs @@ -26,12 +26,11 @@ namespace Content.Server.Weapon.Ranged.Barrels.Components [RegisterComponent] [NetworkedComponent()] #pragma warning disable 618 - public sealed class BoltActionBarrelComponent : ServerRangedBarrelComponent, IUse, IInteractUsing, IMapInit, IExamine + public sealed class BoltActionBarrelComponent : ServerRangedBarrelComponent, IUse, IInteractUsing, IMapInit #pragma warning restore 618 { // Originally I had this logic shared with PumpBarrel and used a couple of variables to control things // but it felt a lot messier to play around with, especially when adding verbs - [Dependency] private readonly IEntityManager _entities = default!; public override string Name => "BoltActionBarrel"; @@ -111,7 +110,7 @@ namespace Content.Server.Weapon.Ranged.Barrels.Components if (_unspawnedCount > 0) { _unspawnedCount--; - var chamberEntity = _entities.SpawnEntity(_fillPrototype, _entities.GetComponent(Owner).Coordinates); + var chamberEntity = Entities.SpawnEntity(_fillPrototype, Entities.GetComponent(Owner).Coordinates); _chamberContainer.Insert(chamberEntity); } } @@ -125,7 +124,7 @@ namespace Content.Server.Weapon.Ranged.Barrels.Components // (Is one chambered?, is the bullet spend) var chamber = (chamberedExists, false); - if (chamberedExists && _entities.TryGetComponent(_chamberContainer.ContainedEntity!.Value, out var ammo)) + if (chamberedExists && Entities.TryGetComponent(_chamberContainer.ContainedEntity!.Value, out var ammo)) { chamber.Item2 = ammo.Spent; } @@ -155,7 +154,7 @@ namespace Content.Server.Weapon.Ranged.Barrels.Components _chamberContainer = ContainerHelpers.EnsureContainer(Owner, $"{Name}-chamber-container"); - if (_entities.TryGetComponent(Owner, out AppearanceComponent? appearanceComponent)) + if (Entities.TryGetComponent(Owner, out AppearanceComponent? appearanceComponent)) { _appearanceComponent = appearanceComponent; } @@ -188,10 +187,11 @@ namespace Content.Server.Weapon.Ranged.Barrels.Components Dirty(); } - if (_chamberContainer.ContainedEntity is not {Valid: true} chamberEntity) - return null; + if (_chamberContainer.ContainedEntity is not {Valid: true} chamberEntity) return null; - return _entities.GetComponentOrNull(chamberEntity)?.TakeBullet(spawnAt); + var ammoComponent = Entities.GetComponentOrNull(chamberEntity); + + return ammoComponent == null ? null : EntitySystem.Get().TakeBullet(ammoComponent, spawnAt); } protected override bool WeaponCanFire() @@ -229,7 +229,7 @@ namespace Content.Server.Weapon.Ranged.Barrels.Components public bool TryInsertBullet(EntityUid user, EntityUid ammo) { - if (!_entities.TryGetComponent(ammo, out AmmoComponent? ammoComponent)) + if (!Entities.TryGetComponent(ammo, out AmmoComponent? ammoComponent)) { return false; } @@ -297,7 +297,7 @@ namespace Content.Server.Weapon.Ranged.Barrels.Components { return false; } - if (!_entities.GetComponent(chambered).Caseless) + if (!Entities.GetComponent(chambered).Caseless) { EjectCasing(chambered); } @@ -321,7 +321,7 @@ namespace Content.Server.Weapon.Ranged.Barrels.Components else if (_unspawnedCount > 0) { _unspawnedCount--; - var ammoEntity = _entities.SpawnEntity(_fillPrototype, _entities.GetComponent(Owner).Coordinates); + var ammoEntity = Entities.SpawnEntity(_fillPrototype, Entities.GetComponent(Owner).Coordinates); _chamberContainer.Insert(ammoEntity); return true; } diff --git a/Content.Server/Weapon/Ranged/Barrels/Components/PumpBarrelComponent.cs b/Content.Server/Weapon/Ranged/Barrels/Components/PumpBarrelComponent.cs index 6b90cf9917..ebfd57b9ce 100644 --- a/Content.Server/Weapon/Ranged/Barrels/Components/PumpBarrelComponent.cs +++ b/Content.Server/Weapon/Ranged/Barrels/Components/PumpBarrelComponent.cs @@ -27,8 +27,6 @@ namespace Content.Server.Weapon.Ranged.Barrels.Components [NetworkedComponent()] public sealed class PumpBarrelComponent : ServerRangedBarrelComponent, IUse, IInteractUsing, IMapInit, ISerializationHooks { - [Dependency] private readonly IEntityManager _entMan = default!; - public override string Name => "PumpBarrel"; public override int ShotsLeft @@ -87,7 +85,7 @@ namespace Content.Server.Weapon.Ranged.Barrels.Components // (Is one chambered?, is the bullet spend) var chamber = (chamberedExists, false); - if (chamberedExists && _entMan.TryGetComponent(_chamberContainer.ContainedEntity!.Value, out var ammo)) + if (chamberedExists && Entities.TryGetComponent(_chamberContainer.ContainedEntity!.Value, out var ammo)) { chamber.Item2 = ammo.Spent; } @@ -126,7 +124,7 @@ namespace Content.Server.Weapon.Ranged.Barrels.Components _unspawnedCount--; } - if (_entMan.TryGetComponent(Owner, out AppearanceComponent? appearanceComponent)) + if (Entities.TryGetComponent(Owner, out AppearanceComponent? appearanceComponent)) { _appearanceComponent = appearanceComponent; } @@ -158,10 +156,11 @@ namespace Content.Server.Weapon.Ranged.Barrels.Components Dirty(); } - if (_chamberContainer.ContainedEntity is not {Valid: true} chamberEntity) - return null; + if (_chamberContainer.ContainedEntity is not {Valid: true} chamberEntity) return null; - return _entMan.GetComponentOrNull(chamberEntity)?.TakeBullet(spawnAt); + var ammoComponent = Entities.GetComponentOrNull(chamberEntity); + + return ammoComponent == null ? null : EntitySystem.Get().TakeBullet(ammoComponent, spawnAt); } private void Cycle(bool manual = false) @@ -169,7 +168,7 @@ namespace Content.Server.Weapon.Ranged.Barrels.Components if (_chamberContainer.ContainedEntity is {Valid: true} chamberedEntity) { _chamberContainer.Remove(chamberedEntity); - var ammoComponent = _entMan.GetComponent(chamberedEntity); + var ammoComponent = Entities.GetComponent(chamberedEntity); if (!ammoComponent.Caseless) { EjectCasing(chamberedEntity); @@ -185,7 +184,7 @@ namespace Content.Server.Weapon.Ranged.Barrels.Components if (_unspawnedCount > 0) { _unspawnedCount--; - var ammoEntity = _entMan.SpawnEntity(_fillPrototype, _entMan.GetComponent(Owner).Coordinates); + var ammoEntity = Entities.SpawnEntity(_fillPrototype, Entities.GetComponent(Owner).Coordinates); _chamberContainer.Insert(ammoEntity); } @@ -200,7 +199,7 @@ namespace Content.Server.Weapon.Ranged.Barrels.Components public bool TryInsertBullet(InteractUsingEventArgs eventArgs) { - if (!_entMan.TryGetComponent(eventArgs.Using, out AmmoComponent? ammoComponent)) + if (!Entities.TryGetComponent(eventArgs.Using, out AmmoComponent? ammoComponent)) { return false; } diff --git a/Content.Server/Weapon/Ranged/Barrels/Components/RevolverBarrelComponent.cs b/Content.Server/Weapon/Ranged/Barrels/Components/RevolverBarrelComponent.cs index 6966a64f88..07ec5d877f 100644 --- a/Content.Server/Weapon/Ranged/Barrels/Components/RevolverBarrelComponent.cs +++ b/Content.Server/Weapon/Ranged/Barrels/Components/RevolverBarrelComponent.cs @@ -24,7 +24,6 @@ namespace Content.Server.Weapon.Ranged.Barrels.Components [NetworkedComponent()] public sealed class RevolverBarrelComponent : ServerRangedBarrelComponent, IUse, IInteractUsing, ISerializationHooks { - [Dependency] private readonly IEntityManager _entMan = default!; [Dependency] private readonly IRobustRandom _random = default!; public override string Name => "RevolverBarrel"; @@ -82,7 +81,7 @@ namespace Content.Server.Weapon.Ranged.Barrels.Components { slotsSpent[i] = null; var ammoEntity = _ammoSlots[i]; - if (ammoEntity != default && _entMan.TryGetComponent(ammoEntity, out AmmoComponent? ammo)) + if (ammoEntity != default && Entities.TryGetComponent(ammoEntity, out AmmoComponent? ammo)) { slotsSpent[i] = ammo.Spent; } @@ -114,7 +113,7 @@ namespace Content.Server.Weapon.Ranged.Barrels.Components for (var i = 0; i < _unspawnedCount; i++) { - var entity = _entMan.SpawnEntity(_fillPrototype, _entMan.GetComponent(Owner).Coordinates); + var entity = Entities.SpawnEntity(_fillPrototype, Entities.GetComponent(Owner).Coordinates); _ammoSlots[idx] = entity; _ammoContainer.Insert(entity); idx++; @@ -126,7 +125,7 @@ namespace Content.Server.Weapon.Ranged.Barrels.Components private void UpdateAppearance() { - if (!_entMan.TryGetComponent(Owner, out AppearanceComponent? appearance)) + if (!Entities.TryGetComponent(Owner, out AppearanceComponent? appearance)) { return; } @@ -139,7 +138,7 @@ namespace Content.Server.Weapon.Ranged.Barrels.Components public bool TryInsertBullet(EntityUid user, EntityUid entity) { - if (!_entMan.TryGetComponent(entity, out AmmoComponent? ammoComponent)) + if (!Entities.TryGetComponent(entity, out AmmoComponent? ammoComponent)) { return false; } @@ -209,8 +208,8 @@ namespace Content.Server.Weapon.Ranged.Barrels.Components EntityUid? bullet = null; if (ammo != default) { - var ammoComponent = _entMan.GetComponent(ammo); - bullet = ammoComponent.TakeBullet(spawnAt); + var ammoComponent = Entities.GetComponent(ammo); + bullet = EntitySystem.Get().TakeBullet(ammoComponent, spawnAt); if (ammoComponent.Caseless) { _ammoSlots[_currentSlot] = default; diff --git a/Content.Server/Weapon/Ranged/Barrels/Components/ServerMagazineBarrelComponent.cs b/Content.Server/Weapon/Ranged/Barrels/Components/ServerMagazineBarrelComponent.cs index 7e0a30b51f..243d3b1ad6 100644 --- a/Content.Server/Weapon/Ranged/Barrels/Components/ServerMagazineBarrelComponent.cs +++ b/Content.Server/Weapon/Ranged/Barrels/Components/ServerMagazineBarrelComponent.cs @@ -205,7 +205,7 @@ namespace Content.Server.Weapon.Ranged.Barrels.Components var entity = _chamberContainer.ContainedEntity ?? default; Cycle(); - return entity != default ? _entities.GetComponent(entity).TakeBullet(spawnAt) : null; + return entity != default ? EntitySystem.Get().TakeBullet(_entities.GetComponent(entity), spawnAt) : null; } private void Cycle(bool manual = false) diff --git a/Content.Server/Weapon/Ranged/Barrels/Components/ServerRangedBarrelComponent.cs b/Content.Server/Weapon/Ranged/Barrels/Components/ServerRangedBarrelComponent.cs index 6577172f3a..0f84af3763 100644 --- a/Content.Server/Weapon/Ranged/Barrels/Components/ServerRangedBarrelComponent.cs +++ b/Content.Server/Weapon/Ranged/Barrels/Components/ServerRangedBarrelComponent.cs @@ -42,7 +42,7 @@ namespace Content.Server.Weapon.Ranged.Barrels.Components // it's just when I re-organised it changed me as the contributor [Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly IRobustRandom _robustRandom = default!; - [Dependency] private readonly IEntityManager _entities = default!; + [Dependency] protected readonly IEntityManager Entities = default!; public override FireRateSelector FireRateSelector => _fireRateSelector; @@ -147,7 +147,7 @@ namespace Content.Server.Weapon.Ranged.Barrels.Components protected override void OnRemove() { base.OnRemove(); - if (_entities.TryGetComponent(Owner, out ServerRangedWeaponComponent? rangedWeaponComponent)) + if (Entities.TryGetComponent(Owner, out ServerRangedWeaponComponent? rangedWeaponComponent)) { rangedWeaponComponent.Barrel = null; rangedWeaponComponent.FireHandler -= Fire; @@ -198,39 +198,39 @@ namespace Content.Server.Weapon.Ranged.Barrels.Components } var ammo = PeekAmmo(); - if (TakeProjectile(_entities.GetComponent(shooter).Coordinates) is not {Valid: true} projectile) + if (TakeProjectile(Entities.GetComponent(shooter).Coordinates) is not {Valid: true} projectile) { SoundSystem.Play(Filter.Broadcast(), SoundEmpty.GetSound(), Owner); return; } // At this point firing is confirmed - var direction = (targetPos - _entities.GetComponent(shooter).WorldPosition).ToAngle(); + var direction = (targetPos - Entities.GetComponent(shooter).WorldPosition).ToAngle(); var angle = GetRecoilAngle(direction); // This should really be client-side but for now we'll just leave it here - if (_entities.TryGetComponent(shooter, out CameraRecoilComponent? recoilComponent)) + if (Entities.TryGetComponent(shooter, out CameraRecoilComponent? recoilComponent)) { recoilComponent.Kick(-angle.ToVec() * 0.15f); } // This section probably needs tweaking so there can be caseless hitscan etc. - if (_entities.TryGetComponent(projectile, out HitscanComponent? hitscan)) + if (Entities.TryGetComponent(projectile, out HitscanComponent? hitscan)) { FireHitscan(shooter, hitscan, angle); } - else if (_entities.HasComponent(projectile) && - _entities.TryGetComponent(ammo, out AmmoComponent? ammoComponent)) + else if (Entities.HasComponent(projectile) && + Entities.TryGetComponent(ammo, out AmmoComponent? ammoComponent)) { FireProjectiles(shooter, projectile, ammoComponent.ProjectilesFired, ammoComponent.EvenSpreadAngle, angle, ammoComponent.Velocity, ammo.Value); if (CanMuzzleFlash) { - ammoComponent.MuzzleFlash(Owner, angle); + EntitySystem.Get().MuzzleFlash(Owner, ammoComponent, angle); } if (ammoComponent.Caseless) { - _entities.DeleteEntity(ammo.Value); + Entities.DeleteEntity(ammo.Value); } } else @@ -324,9 +324,9 @@ namespace Content.Server.Weapon.Ranged.Barrels.Components } else { - projectile = _entities.SpawnEntity( - _entities.GetComponent(baseProjectile).EntityPrototype?.ID, - _entities.GetComponent(baseProjectile).Coordinates); + projectile = Entities.SpawnEntity( + Entities.GetComponent(baseProjectile).EntityPrototype?.ID, + Entities.GetComponent(baseProjectile).Coordinates); } firedProjectiles[i] = projectile; @@ -342,10 +342,10 @@ namespace Content.Server.Weapon.Ranged.Barrels.Components projectileAngle = angle; } - var physics = _entities.GetComponent(projectile); + var physics = Entities.GetComponent(projectile); physics.BodyStatus = BodyStatus.InAir; - var projectileComponent = _entities.GetComponent(projectile); + var projectileComponent = Entities.GetComponent(projectile); projectileComponent.IgnoreEntity(shooter); // FIXME: Work around issue where inserting and removing an entity from a container, @@ -353,16 +353,16 @@ namespace Content.Server.Weapon.Ranged.Barrels.Components // See SharedBroadphaseSystem.HandleContainerInsert()... It sets Awake to false, which causes this. projectile.SpawnTimer(TimeSpan.FromMilliseconds(25), () => { - _entities.GetComponent(projectile) + Entities.GetComponent(projectile) .LinearVelocity = projectileAngle.ToVec() * velocity; }); - _entities.GetComponent(projectile).WorldRotation = projectileAngle + MathHelper.PiOver2; + Entities.GetComponent(projectile).WorldRotation = projectileAngle + MathHelper.PiOver2; } - _entities.EventBus.RaiseLocalEvent(Owner, new GunShotEvent(firedProjectiles)); - _entities.EventBus.RaiseLocalEvent(ammo, new AmmoShotEvent(firedProjectiles)); + Entities.EventBus.RaiseLocalEvent(Owner, new GunShotEvent(firedProjectiles)); + Entities.EventBus.RaiseLocalEvent(ammo, new AmmoShotEvent(firedProjectiles)); } /// @@ -386,9 +386,9 @@ namespace Content.Server.Weapon.Ranged.Barrels.Components /// private void FireHitscan(EntityUid shooter, HitscanComponent hitscan, Angle angle) { - var ray = new CollisionRay(_entities.GetComponent(Owner).Coordinates.ToMapPos(_entities), angle.ToVec(), (int) hitscan.CollisionMask); + var ray = new CollisionRay(Entities.GetComponent(Owner).Coordinates.ToMapPos(Entities), angle.ToVec(), (int) hitscan.CollisionMask); var physicsManager = EntitySystem.Get(); - var rayCastResults = physicsManager.IntersectRay(_entities.GetComponent(Owner).MapID, ray, hitscan.MaxLength, shooter, false).ToList(); + var rayCastResults = physicsManager.IntersectRay(Entities.GetComponent(Owner).MapID, ray, hitscan.MaxLength, shooter, false).ToList(); if (rayCastResults.Count >= 1) { @@ -398,7 +398,7 @@ namespace Content.Server.Weapon.Ranged.Barrels.Components var dmg = EntitySystem.Get().TryChangeDamage(result.HitEntity, hitscan.Damage); if (dmg != null) EntitySystem.Get().Add(LogType.HitScanHit, - $"{_entities.ToPrettyString(shooter):user} hit {_entities.ToPrettyString(result.HitEntity):target} using {_entities.ToPrettyString(hitscan.Owner):used} and dealt {dmg.Total:damage} damage"); + $"{Entities.ToPrettyString(shooter):user} hit {Entities.ToPrettyString(result.HitEntity):target} using {Entities.ToPrettyString(hitscan.Owner):used} and dealt {dmg.Total:damage} damage"); } else { diff --git a/Content.Server/Weapon/Ranged/GunSystem.Ammo.cs b/Content.Server/Weapon/Ranged/GunSystem.Ammo.cs new file mode 100644 index 0000000000..23b36b4201 --- /dev/null +++ b/Content.Server/Weapon/Ranged/GunSystem.Ammo.cs @@ -0,0 +1,95 @@ +using System; +using Content.Server.Weapon.Ranged.Ammunition.Components; +using Content.Shared.Examine; +using Content.Shared.Weapons.Ranged.Barrels.Components; +using Robust.Shared.GameObjects; +using Robust.Shared.Localization; +using Robust.Shared.Map; +using Robust.Shared.Maths; + +namespace Content.Server.Weapon.Ranged; + +public sealed partial class GunSystem +{ + private void OnAmmoExamine(EntityUid uid, AmmoComponent component, ExaminedEvent args) + { + var text = Loc.GetString("ammo-component-on-examine",("caliber", component.Caliber)); + args.PushMarkup(text); + } + + public EntityUid? TakeBullet(AmmoComponent component, EntityCoordinates spawnAt) + { + if (component.AmmoIsProjectile) + { + return component.Owner; + } + + if (component.Spent) + { + return null; + } + + component.Spent = true; + + if (TryComp(component.Owner, out AppearanceComponent? appearanceComponent)) + { + appearanceComponent.SetData(AmmoVisuals.Spent, true); + } + + var entity = EntityManager.SpawnEntity(component.ProjectileId, spawnAt); + + return entity; + } + + public void MuzzleFlash(EntityUid entity, AmmoComponent component, Angle angle) + { + if (component.MuzzleFlashSprite == null) + { + return; + } + + var time = _gameTiming.CurTime; + var deathTime = time + TimeSpan.FromMilliseconds(200); + // Offset the sprite so it actually looks like it's coming from the gun + var offset = new Vector2(0.0f, -0.5f); + + var message = new EffectSystemMessage + { + EffectSprite = component.MuzzleFlashSprite.ToString(), + Born = time, + DeathTime = deathTime, + AttachedEntityUid = entity, + AttachedOffset = offset, + //Rotated from east facing + Rotation = -MathF.PI / 2f, + Color = Vector4.Multiply(new Vector4(255, 255, 255, 255), 1.0f), + ColorDelta = new Vector4(0, 0, 0, -1500f), + Shaded = false + }; + + /* TODO: Fix rotation when shooting sideways. This was the closest I got but still had issues. + * var time = _gameTiming.CurTime; + var deathTime = time + TimeSpan.FromMilliseconds(200); + var entityRotation = EntityManager.GetComponent(entity).WorldRotation; + var localAngle = entityRotation - (angle + MathF.PI / 2f); + // Offset the sprite so it actually looks like it's coming from the gun + var offset = localAngle.RotateVec(new Vector2(0.0f, -0.5f)); + + var message = new EffectSystemMessage + { + EffectSprite = component.MuzzleFlashSprite.ToString(), + Born = time, + DeathTime = deathTime, + AttachedEntityUid = entity, + AttachedOffset = offset, + //Rotated from east facing + Rotation = (float) (localAngle - MathF.PI / 2), + Color = Vector4.Multiply(new Vector4(255, 255, 255, 255), 1.0f), + ColorDelta = new Vector4(0, 0, 0, -1500f), + Shaded = false + }; + */ + + _effects.CreateParticle(message); + } +} diff --git a/Content.Server/Weapon/Ranged/GunSystem.AmmoBox.cs b/Content.Server/Weapon/Ranged/GunSystem.AmmoBox.cs index d9c5024f41..e93cc22db2 100644 --- a/Content.Server/Weapon/Ranged/GunSystem.AmmoBox.cs +++ b/Content.Server/Weapon/Ranged/GunSystem.AmmoBox.cs @@ -19,20 +19,6 @@ public sealed partial class GunSystem { // Probably needs combining with magazines in future given the common functionality. - public override void Initialize() - { - base.Initialize(); - - SubscribeLocalEvent(OnAmmoBoxInit); - SubscribeLocalEvent(OnAmmoBoxMapInit); - SubscribeLocalEvent(OnAmmoBoxExamine); - - SubscribeLocalEvent(OnAmmoBoxInteractUsing); - SubscribeLocalEvent(OnAmmoBoxUse); - SubscribeLocalEvent(OnAmmoBoxInteractHand); - SubscribeLocalEvent(OnAmmoBoxAltVerbs); - } - private void OnAmmoBoxAltVerbs(EntityUid uid, AmmoBoxComponent component, GetAlternativeVerbsEvent args) { if (args.Hands == null || !args.CanAccess || !args.CanInteract) diff --git a/Content.Server/Weapon/Ranged/GunSystem.cs b/Content.Server/Weapon/Ranged/GunSystem.cs index 872a37ff1d..56e0c495b0 100644 --- a/Content.Server/Weapon/Ranged/GunSystem.cs +++ b/Content.Server/Weapon/Ranged/GunSystem.cs @@ -1,10 +1,34 @@ +using Content.Server.Weapon.Ranged.Ammunition.Components; +using Content.Shared.Examine; +using Content.Shared.Interaction; using Content.Shared.Popups; +using Content.Shared.Verbs; +using Robust.Server.GameObjects; using Robust.Shared.GameObjects; using Robust.Shared.IoC; +using Robust.Shared.Timing; namespace Content.Server.Weapon.Ranged; public sealed partial class GunSystem : EntitySystem { + [Dependency] private readonly IGameTiming _gameTiming = default!; + [Dependency] private readonly EffectSystem _effects = default!; [Dependency] private readonly SharedPopupSystem _popup = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnAmmoExamine); + + SubscribeLocalEvent(OnAmmoBoxInit); + SubscribeLocalEvent(OnAmmoBoxMapInit); + SubscribeLocalEvent(OnAmmoBoxExamine); + + SubscribeLocalEvent(OnAmmoBoxInteractUsing); + SubscribeLocalEvent(OnAmmoBoxUse); + SubscribeLocalEvent(OnAmmoBoxInteractHand); + SubscribeLocalEvent(OnAmmoBoxAltVerbs); + } }