ECS Ammo (#5862)
This commit is contained in:
@@ -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
|
||||
/// </summary>
|
||||
[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
|
||||
/// <summary>
|
||||
/// Used for anything without a case that fires itself
|
||||
/// </summary>
|
||||
[DataField("isProjectile")]
|
||||
private bool _ammoIsProjectile;
|
||||
[DataField("isProjectile")] public bool AmmoIsProjectile;
|
||||
|
||||
/// <summary>
|
||||
/// 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<EntityPrototype>))]
|
||||
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<EffectSystem>().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
|
||||
|
||||
@@ -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<TransformComponent>(Owner).Coordinates);
|
||||
var chamberEntity = Entities.SpawnEntity(_fillPrototype, Entities.GetComponent<TransformComponent>(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<AmmoComponent?>(_chamberContainer.ContainedEntity!.Value, out var ammo))
|
||||
if (chamberedExists && Entities.TryGetComponent<AmmoComponent?>(_chamberContainer.ContainedEntity!.Value, out var ammo))
|
||||
{
|
||||
chamber.Item2 = ammo.Spent;
|
||||
}
|
||||
@@ -155,7 +154,7 @@ namespace Content.Server.Weapon.Ranged.Barrels.Components
|
||||
|
||||
_chamberContainer = ContainerHelpers.EnsureContainer<ContainerSlot>(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<AmmoComponent>(chamberEntity)?.TakeBullet(spawnAt);
|
||||
var ammoComponent = Entities.GetComponentOrNull<AmmoComponent>(chamberEntity);
|
||||
|
||||
return ammoComponent == null ? null : EntitySystem.Get<GunSystem>().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<AmmoComponent>(chambered).Caseless)
|
||||
if (!Entities.GetComponent<AmmoComponent>(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<TransformComponent>(Owner).Coordinates);
|
||||
var ammoEntity = Entities.SpawnEntity(_fillPrototype, Entities.GetComponent<TransformComponent>(Owner).Coordinates);
|
||||
_chamberContainer.Insert(ammoEntity);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -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<AmmoComponent?>(_chamberContainer.ContainedEntity!.Value, out var ammo))
|
||||
if (chamberedExists && Entities.TryGetComponent<AmmoComponent?>(_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<AmmoComponent>(chamberEntity)?.TakeBullet(spawnAt);
|
||||
var ammoComponent = Entities.GetComponentOrNull<AmmoComponent>(chamberEntity);
|
||||
|
||||
return ammoComponent == null ? null : EntitySystem.Get<GunSystem>().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<AmmoComponent>(chamberedEntity);
|
||||
var ammoComponent = Entities.GetComponent<AmmoComponent>(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<TransformComponent>(Owner).Coordinates);
|
||||
var ammoEntity = Entities.SpawnEntity(_fillPrototype, Entities.GetComponent<TransformComponent>(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;
|
||||
}
|
||||
|
||||
@@ -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<TransformComponent>(Owner).Coordinates);
|
||||
var entity = Entities.SpawnEntity(_fillPrototype, Entities.GetComponent<TransformComponent>(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<AmmoComponent>(ammo);
|
||||
bullet = ammoComponent.TakeBullet(spawnAt);
|
||||
var ammoComponent = Entities.GetComponent<AmmoComponent>(ammo);
|
||||
bullet = EntitySystem.Get<GunSystem>().TakeBullet(ammoComponent, spawnAt);
|
||||
if (ammoComponent.Caseless)
|
||||
{
|
||||
_ammoSlots[_currentSlot] = default;
|
||||
|
||||
@@ -205,7 +205,7 @@ namespace Content.Server.Weapon.Ranged.Barrels.Components
|
||||
var entity = _chamberContainer.ContainedEntity ?? default;
|
||||
|
||||
Cycle();
|
||||
return entity != default ? _entities.GetComponent<AmmoComponent>(entity).TakeBullet(spawnAt) : null;
|
||||
return entity != default ? EntitySystem.Get<GunSystem>().TakeBullet(_entities.GetComponent<AmmoComponent>(entity), spawnAt) : null;
|
||||
}
|
||||
|
||||
private void Cycle(bool manual = false)
|
||||
|
||||
@@ -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<TransformComponent>(shooter).Coordinates) is not {Valid: true} projectile)
|
||||
if (TakeProjectile(Entities.GetComponent<TransformComponent>(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<TransformComponent>(shooter).WorldPosition).ToAngle();
|
||||
var direction = (targetPos - Entities.GetComponent<TransformComponent>(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<ProjectileComponent>(projectile) &&
|
||||
_entities.TryGetComponent(ammo, out AmmoComponent? ammoComponent))
|
||||
else if (Entities.HasComponent<ProjectileComponent>(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<GunSystem>().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<MetaDataComponent>(baseProjectile).EntityPrototype?.ID,
|
||||
_entities.GetComponent<TransformComponent>(baseProjectile).Coordinates);
|
||||
projectile = Entities.SpawnEntity(
|
||||
Entities.GetComponent<MetaDataComponent>(baseProjectile).EntityPrototype?.ID,
|
||||
Entities.GetComponent<TransformComponent>(baseProjectile).Coordinates);
|
||||
}
|
||||
|
||||
firedProjectiles[i] = projectile;
|
||||
@@ -342,10 +342,10 @@ namespace Content.Server.Weapon.Ranged.Barrels.Components
|
||||
projectileAngle = angle;
|
||||
}
|
||||
|
||||
var physics = _entities.GetComponent<IPhysBody>(projectile);
|
||||
var physics = Entities.GetComponent<IPhysBody>(projectile);
|
||||
physics.BodyStatus = BodyStatus.InAir;
|
||||
|
||||
var projectileComponent = _entities.GetComponent<ProjectileComponent>(projectile);
|
||||
var projectileComponent = Entities.GetComponent<ProjectileComponent>(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<IPhysBody>(projectile)
|
||||
Entities.GetComponent<IPhysBody>(projectile)
|
||||
.LinearVelocity = projectileAngle.ToVec() * velocity;
|
||||
});
|
||||
|
||||
|
||||
_entities.GetComponent<TransformComponent>(projectile).WorldRotation = projectileAngle + MathHelper.PiOver2;
|
||||
Entities.GetComponent<TransformComponent>(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));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -386,9 +386,9 @@ namespace Content.Server.Weapon.Ranged.Barrels.Components
|
||||
/// </summary>
|
||||
private void FireHitscan(EntityUid shooter, HitscanComponent hitscan, Angle angle)
|
||||
{
|
||||
var ray = new CollisionRay(_entities.GetComponent<TransformComponent>(Owner).Coordinates.ToMapPos(_entities), angle.ToVec(), (int) hitscan.CollisionMask);
|
||||
var ray = new CollisionRay(Entities.GetComponent<TransformComponent>(Owner).Coordinates.ToMapPos(Entities), angle.ToVec(), (int) hitscan.CollisionMask);
|
||||
var physicsManager = EntitySystem.Get<SharedPhysicsSystem>();
|
||||
var rayCastResults = physicsManager.IntersectRay(_entities.GetComponent<TransformComponent>(Owner).MapID, ray, hitscan.MaxLength, shooter, false).ToList();
|
||||
var rayCastResults = physicsManager.IntersectRay(Entities.GetComponent<TransformComponent>(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<DamageableSystem>().TryChangeDamage(result.HitEntity, hitscan.Damage);
|
||||
if (dmg != null)
|
||||
EntitySystem.Get<AdminLogSystem>().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
|
||||
{
|
||||
|
||||
95
Content.Server/Weapon/Ranged/GunSystem.Ammo.cs
Normal file
95
Content.Server/Weapon/Ranged/GunSystem.Ammo.cs
Normal file
@@ -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<TransformComponent>(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);
|
||||
}
|
||||
}
|
||||
@@ -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<AmmoBoxComponent, ComponentInit>(OnAmmoBoxInit);
|
||||
SubscribeLocalEvent<AmmoBoxComponent, MapInitEvent>(OnAmmoBoxMapInit);
|
||||
SubscribeLocalEvent<AmmoBoxComponent, ExaminedEvent>(OnAmmoBoxExamine);
|
||||
|
||||
SubscribeLocalEvent<AmmoBoxComponent, InteractUsingEvent>(OnAmmoBoxInteractUsing);
|
||||
SubscribeLocalEvent<AmmoBoxComponent, UseInHandEvent>(OnAmmoBoxUse);
|
||||
SubscribeLocalEvent<AmmoBoxComponent, InteractHandEvent>(OnAmmoBoxInteractHand);
|
||||
SubscribeLocalEvent<AmmoBoxComponent, GetAlternativeVerbsEvent>(OnAmmoBoxAltVerbs);
|
||||
}
|
||||
|
||||
private void OnAmmoBoxAltVerbs(EntityUid uid, AmmoBoxComponent component, GetAlternativeVerbsEvent args)
|
||||
{
|
||||
if (args.Hands == null || !args.CanAccess || !args.CanInteract)
|
||||
|
||||
@@ -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<AmmoComponent, ExaminedEvent>(OnAmmoExamine);
|
||||
|
||||
SubscribeLocalEvent<AmmoBoxComponent, ComponentInit>(OnAmmoBoxInit);
|
||||
SubscribeLocalEvent<AmmoBoxComponent, MapInitEvent>(OnAmmoBoxMapInit);
|
||||
SubscribeLocalEvent<AmmoBoxComponent, ExaminedEvent>(OnAmmoBoxExamine);
|
||||
|
||||
SubscribeLocalEvent<AmmoBoxComponent, InteractUsingEvent>(OnAmmoBoxInteractUsing);
|
||||
SubscribeLocalEvent<AmmoBoxComponent, UseInHandEvent>(OnAmmoBoxUse);
|
||||
SubscribeLocalEvent<AmmoBoxComponent, InteractHandEvent>(OnAmmoBoxInteractHand);
|
||||
SubscribeLocalEvent<AmmoBoxComponent, GetAlternativeVerbsEvent>(OnAmmoBoxAltVerbs);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user