mirror of
https://github.com/space-wizards/space-station-14.git
synced 2026-02-14 19:29:53 +01:00
Update (MOST) instances of EntityUid, Component in GunSystem to Entity<T> (#41966)
* Entity<T>, skipping Magazine and ChamberMagazine * missed some * AUGH!! * ballistic examine * dotnet hates me * WHY ARE YOU CALLED THAT!!!! * cheers aada
This commit is contained in:
@@ -4,10 +4,8 @@ using Content.Shared.Weapons.Ranged.Components;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.Input;
|
||||
using Robust.Client.Serialization;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Shared.Enums;
|
||||
using Robust.Shared.Graphics;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Client.CombatMode;
|
||||
|
||||
@@ -11,17 +11,20 @@ public sealed partial class MagazineVisualsComponent : Component
|
||||
/// <summary>
|
||||
/// What RsiState we use.
|
||||
/// </summary>
|
||||
[DataField("magState")] public string? MagState;
|
||||
[DataField]
|
||||
public string? MagState;
|
||||
|
||||
/// <summary>
|
||||
/// How many steps there are
|
||||
/// </summary>
|
||||
[DataField("steps")] public int MagSteps;
|
||||
[DataField("steps")]
|
||||
public int MagSteps;
|
||||
|
||||
/// <summary>
|
||||
/// Should we hide when the count is 0
|
||||
/// </summary>
|
||||
[DataField("zeroVisible")] public bool ZeroVisible;
|
||||
[DataField]
|
||||
public bool ZeroVisible;
|
||||
}
|
||||
|
||||
public enum GunVisualLayers : byte
|
||||
|
||||
@@ -8,9 +8,10 @@ public sealed partial class SpentAmmoVisualsComponent : Component
|
||||
/// <summary>
|
||||
/// Should we do "{_state}-spent" or just "spent"
|
||||
/// </summary>
|
||||
[DataField("suffix")] public bool Suffix = true;
|
||||
[DataField]
|
||||
public bool Suffix = true;
|
||||
|
||||
[DataField("state")]
|
||||
[DataField]
|
||||
public string State = "base";
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ public sealed class GunSpreadOverlay : Overlay
|
||||
if (mapPos.MapId == MapId.Nullspace)
|
||||
return;
|
||||
|
||||
if (!_guns.TryGetGun(player.Value, out var gunUid, out var gun))
|
||||
if (!_guns.TryGetGun(player.Value, out var gun))
|
||||
return;
|
||||
|
||||
var mouseScreenPos = _input.MouseScreenPosition;
|
||||
@@ -58,12 +58,12 @@ public sealed class GunSpreadOverlay : Overlay
|
||||
return;
|
||||
|
||||
// (☞゚ヮ゚)☞
|
||||
var maxSpread = gun.MaxAngleModified;
|
||||
var minSpread = gun.MinAngleModified;
|
||||
var timeSinceLastFire = (_timing.CurTime - gun.NextFire).TotalSeconds;
|
||||
var currentAngle = new Angle(MathHelper.Clamp(gun.CurrentAngle.Theta - gun.AngleDecayModified.Theta * timeSinceLastFire,
|
||||
gun.MinAngleModified.Theta, gun.MaxAngleModified.Theta));
|
||||
var direction = (mousePos.Position - mapPos.Position);
|
||||
var maxSpread = gun.Comp.MaxAngleModified;
|
||||
var minSpread = gun.Comp.MinAngleModified;
|
||||
var timeSinceLastFire = (_timing.CurTime - gun.Comp.NextFire).TotalSeconds;
|
||||
var currentAngle = new Angle(MathHelper.Clamp(gun.Comp.CurrentAngle.Theta - gun.Comp.AngleDecayModified.Theta * timeSinceLastFire,
|
||||
gun.Comp.MinAngleModified.Theta, gun.Comp.MaxAngleModified.Theta));
|
||||
var direction = mousePos.Position - mapPos.Position;
|
||||
|
||||
worldHandle.DrawLine(mapPos.Position, mousePos.Position + direction, Color.Orange);
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ public abstract class BaseBulletRenderer : Control
|
||||
{
|
||||
var countPerRow = Math.Min(Capacity, CountPerRow(availableSize.X));
|
||||
|
||||
var rows = Math.Min((int) MathF.Ceiling(Capacity / (float) countPerRow), Rows);
|
||||
var rows = Math.Min((int)MathF.Ceiling(Capacity / (float)countPerRow), Rows);
|
||||
|
||||
var height = _params.ItemHeight * rows + (_params.VerticalSeparation * rows - 1);
|
||||
var width = RowWidth(countPerRow);
|
||||
@@ -110,7 +110,7 @@ public abstract class BaseBulletRenderer : Control
|
||||
|
||||
private int CountPerRow(float width)
|
||||
{
|
||||
return (int) ((width - _params.ItemWidth + _params.ItemSeparation) / _params.ItemSeparation);
|
||||
return (int)((width - _params.ItemWidth + _params.ItemSeparation) / _params.ItemSeparation);
|
||||
}
|
||||
|
||||
private int RowWidth(int count)
|
||||
|
||||
@@ -2,10 +2,8 @@ using Content.Shared.Projectiles;
|
||||
using Content.Shared.Weapons.Ranged.Components;
|
||||
using Content.Shared.Weapons.Ranged.Systems;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.Physics.Events;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Random;
|
||||
|
||||
namespace Content.Client.Weapons.Ranged.Systems;
|
||||
@@ -22,26 +20,26 @@ public sealed class FlyBySoundSystem : SharedFlyBySoundSystem
|
||||
SubscribeLocalEvent<FlyBySoundComponent, StartCollideEvent>(OnCollide);
|
||||
}
|
||||
|
||||
private void OnCollide(EntityUid uid, FlyBySoundComponent component, ref StartCollideEvent args)
|
||||
private void OnCollide(Entity<FlyBySoundComponent> ent, ref StartCollideEvent args)
|
||||
{
|
||||
var attachedEnt = _player.LocalEntity;
|
||||
|
||||
// If it's not our ent or we shot it.
|
||||
if (attachedEnt == null ||
|
||||
args.OtherEntity != attachedEnt ||
|
||||
TryComp<ProjectileComponent>(uid, out var projectile) &&
|
||||
TryComp<ProjectileComponent>(ent, out var projectile) &&
|
||||
projectile.Shooter == attachedEnt)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.OurFixtureId != FlyByFixture ||
|
||||
!_random.Prob(component.Prob))
|
||||
!_random.Prob(ent.Comp.Prob))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Play attached to our entity because the projectile may immediately delete or the likes.
|
||||
_audio.PlayPredicted(component.Sound, attachedEnt.Value, attachedEnt.Value);
|
||||
_audio.PlayPredicted(ent.Comp.Sound, attachedEnt.Value, attachedEnt.Value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,12 +14,12 @@ namespace Content.Client.Weapons.Ranged.Systems;
|
||||
|
||||
public sealed partial class GunSystem
|
||||
{
|
||||
private void OnAmmoCounterCollect(EntityUid uid, AmmoCounterComponent component, ItemStatusCollectMessage args)
|
||||
private void OnAmmoCounterCollect(Entity<AmmoCounterComponent> ent, ref ItemStatusCollectMessage args)
|
||||
{
|
||||
RefreshControl(uid, component);
|
||||
RefreshControl(ent);
|
||||
|
||||
if (component.Control != null)
|
||||
args.Controls.Add(component.Control);
|
||||
if (ent.Comp.Control != null)
|
||||
args.Controls.Add(ent.Comp.Control);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -27,35 +27,32 @@ public sealed partial class GunSystem
|
||||
/// </summary>
|
||||
/// <param name="uid"></param>
|
||||
/// <param name="component"></param>
|
||||
private void RefreshControl(EntityUid uid, AmmoCounterComponent? component = null)
|
||||
private void RefreshControl(Entity<AmmoCounterComponent> ent)
|
||||
{
|
||||
if (!Resolve(uid, ref component, false))
|
||||
return;
|
||||
|
||||
component.Control?.Dispose();
|
||||
component.Control = null;
|
||||
ent.Comp.Control?.Dispose();
|
||||
ent.Comp.Control = null;
|
||||
|
||||
var ev = new AmmoCounterControlEvent();
|
||||
RaiseLocalEvent(uid, ev, false);
|
||||
RaiseLocalEvent(ent, ev, false);
|
||||
|
||||
// Fallback to default if none specified
|
||||
ev.Control ??= new DefaultStatusControl();
|
||||
|
||||
component.Control = ev.Control;
|
||||
UpdateAmmoCount(uid, component);
|
||||
ent.Comp.Control = ev.Control;
|
||||
UpdateAmmoCount(ent);
|
||||
}
|
||||
|
||||
private void UpdateAmmoCount(EntityUid uid, AmmoCounterComponent component)
|
||||
private void UpdateAmmoCount(Entity<AmmoCounterComponent> ent)
|
||||
{
|
||||
if (component.Control == null)
|
||||
if (ent.Comp.Control == null)
|
||||
return;
|
||||
|
||||
var ev = new UpdateAmmoCounterEvent()
|
||||
{
|
||||
Control = component.Control
|
||||
Control = ent.Comp.Control
|
||||
};
|
||||
|
||||
RaiseLocalEvent(uid, ev, false);
|
||||
RaiseLocalEvent(ent, ev, false);
|
||||
}
|
||||
|
||||
protected override void UpdateAmmoCount(EntityUid uid, bool prediction = true)
|
||||
@@ -68,7 +65,7 @@ public sealed partial class GunSystem
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateAmmoCount(uid, clientComp);
|
||||
UpdateAmmoCount((uid, clientComp));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -12,41 +12,41 @@ public sealed partial class GunSystem
|
||||
SubscribeLocalEvent<BallisticAmmoProviderComponent, UpdateAmmoCounterEvent>(OnBallisticAmmoCount);
|
||||
}
|
||||
|
||||
private void OnBallisticAmmoCount(EntityUid uid, BallisticAmmoProviderComponent component, UpdateAmmoCounterEvent args)
|
||||
private void OnBallisticAmmoCount(Entity<BallisticAmmoProviderComponent> ent, ref UpdateAmmoCounterEvent args)
|
||||
{
|
||||
if (args.Control is DefaultStatusControl control)
|
||||
{
|
||||
control.Update(GetBallisticShots(component), component.Capacity);
|
||||
control.Update(GetBallisticShots(ent.Comp), ent.Comp.Capacity);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Cycle(EntityUid uid, BallisticAmmoProviderComponent component, MapCoordinates coordinates)
|
||||
protected override void Cycle(Entity<BallisticAmmoProviderComponent> ent, MapCoordinates coordinates)
|
||||
{
|
||||
if (!Timing.IsFirstTimePredicted)
|
||||
return;
|
||||
|
||||
EntityUid? ent = null;
|
||||
EntityUid? ammoEnt = null;
|
||||
|
||||
// TODO: Combine with TakeAmmo
|
||||
if (component.Entities.Count > 0)
|
||||
if (ent.Comp.Entities.Count > 0)
|
||||
{
|
||||
var existing = component.Entities[^1];
|
||||
component.Entities.RemoveAt(component.Entities.Count - 1);
|
||||
var existing = ent.Comp.Entities[^1];
|
||||
ent.Comp.Entities.RemoveAt(ent.Comp.Entities.Count - 1);
|
||||
|
||||
Containers.Remove(existing, component.Container);
|
||||
Containers.Remove(existing, ent.Comp.Container);
|
||||
EnsureShootable(existing);
|
||||
}
|
||||
else if (component.UnspawnedCount > 0)
|
||||
else if (ent.Comp.UnspawnedCount > 0)
|
||||
{
|
||||
component.UnspawnedCount--;
|
||||
ent = Spawn(component.Proto, coordinates);
|
||||
EnsureShootable(ent.Value);
|
||||
ent.Comp.UnspawnedCount--;
|
||||
ammoEnt = Spawn(ent.Comp.Proto, coordinates);
|
||||
EnsureShootable(ammoEnt.Value);
|
||||
}
|
||||
|
||||
if (ent != null && IsClientSide(ent.Value))
|
||||
Del(ent.Value);
|
||||
if (ammoEnt != null && IsClientSide(ammoEnt.Value))
|
||||
Del(ammoEnt.Value);
|
||||
|
||||
var cycledEvent = new GunCycledEvent();
|
||||
RaiseLocalEvent(uid, ref cycledEvent);
|
||||
RaiseLocalEvent(ent, ref cycledEvent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,11 +10,11 @@ public partial class GunSystem
|
||||
SubscribeLocalEvent<BasicEntityAmmoProviderComponent, UpdateAmmoCounterEvent>(OnBasicEntityAmmoCount);
|
||||
}
|
||||
|
||||
private void OnBasicEntityAmmoCount(EntityUid uid, BasicEntityAmmoProviderComponent component, UpdateAmmoCounterEvent args)
|
||||
private void OnBasicEntityAmmoCount(Entity<BasicEntityAmmoProviderComponent> ent, ref UpdateAmmoCounterEvent args)
|
||||
{
|
||||
if (args.Control is DefaultStatusControl control && component.Count != null && component.Capacity != null)
|
||||
if (args.Control is DefaultStatusControl control && ent.Comp.Count != null && ent.Comp.Capacity != null)
|
||||
{
|
||||
control.Update(component.Count.Value, component.Capacity.Value);
|
||||
control.Update(ent.Comp.Count.Value, ent.Comp.Capacity.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,11 +18,11 @@ public sealed partial class GunSystem
|
||||
SubscribeLocalEvent<ChamberMagazineAmmoProviderComponent, AppearanceChangeEvent>(OnChamberMagazineAppearance);
|
||||
}
|
||||
|
||||
private void OnChamberMagazineAppearance(EntityUid uid, ChamberMagazineAmmoProviderComponent component, ref AppearanceChangeEvent args)
|
||||
private void OnChamberMagazineAppearance(Entity<ChamberMagazineAmmoProviderComponent> ent, ref AppearanceChangeEvent args)
|
||||
{
|
||||
if (args.Sprite == null ||
|
||||
!_sprite.LayerMapTryGet((uid, args.Sprite), GunVisualLayers.Base, out var boltLayer, false) ||
|
||||
!Appearance.TryGetData(uid, AmmoVisuals.BoltClosed, out bool boltClosed))
|
||||
!_sprite.LayerMapTryGet((ent, args.Sprite), GunVisualLayers.Base, out var boltLayer, false) ||
|
||||
!Appearance.TryGetData(ent, AmmoVisuals.BoltClosed, out bool boltClosed))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -30,11 +30,11 @@ public sealed partial class GunSystem
|
||||
// Maybe re-using base layer for this will bite me someday but screw you future sloth.
|
||||
if (boltClosed)
|
||||
{
|
||||
_sprite.LayerSetRsiState((uid, args.Sprite), boltLayer, "base");
|
||||
_sprite.LayerSetRsiState((ent, args.Sprite), boltLayer, "base");
|
||||
}
|
||||
else
|
||||
{
|
||||
_sprite.LayerSetRsiState((uid, args.Sprite), boltLayer, "bolt-open");
|
||||
_sprite.LayerSetRsiState((ent, args.Sprite), boltLayer, "bolt-open");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,17 +55,17 @@ public sealed partial class GunSystem
|
||||
// to avoid 6-7 additional entity spawns.
|
||||
}
|
||||
|
||||
private void OnChamberMagazineCounter(EntityUid uid, ChamberMagazineAmmoProviderComponent component, AmmoCounterControlEvent args)
|
||||
private void OnChamberMagazineCounter(Entity<ChamberMagazineAmmoProviderComponent> ent, ref AmmoCounterControlEvent args)
|
||||
{
|
||||
args.Control = new ChamberMagazineStatusControl();
|
||||
}
|
||||
|
||||
private void OnChamberMagazineAmmoUpdate(EntityUid uid, ChamberMagazineAmmoProviderComponent component, UpdateAmmoCounterEvent args)
|
||||
private void OnChamberMagazineAmmoUpdate(Entity<ChamberMagazineAmmoProviderComponent> ent, ref UpdateAmmoCounterEvent args)
|
||||
{
|
||||
if (args.Control is not ChamberMagazineStatusControl control) return;
|
||||
|
||||
var chambered = GetChamberEntity(uid);
|
||||
var magEntity = GetMagazineEntity(uid);
|
||||
var chambered = GetChamberEntity(ent);
|
||||
var magEntity = GetMagazineEntity(ent);
|
||||
var ammoCountEv = new GetAmmoCountEvent();
|
||||
|
||||
if (magEntity != null)
|
||||
|
||||
@@ -11,11 +11,11 @@ public sealed partial class GunSystem
|
||||
SubscribeLocalEvent<MagazineAmmoProviderComponent, AmmoCounterControlEvent>(OnMagazineControl);
|
||||
}
|
||||
|
||||
private void OnMagazineAmmoUpdate(EntityUid uid, MagazineAmmoProviderComponent component, UpdateAmmoCounterEvent args)
|
||||
private void OnMagazineAmmoUpdate(Entity<MagazineAmmoProviderComponent> ent, ref UpdateAmmoCounterEvent args)
|
||||
{
|
||||
var ent = GetMagazineEntity(uid);
|
||||
var magEnt = GetMagazineEntity(ent);
|
||||
|
||||
if (ent == null)
|
||||
if (magEnt == null)
|
||||
{
|
||||
if (args.Control is DefaultStatusControl control)
|
||||
{
|
||||
@@ -25,14 +25,14 @@ public sealed partial class GunSystem
|
||||
return;
|
||||
}
|
||||
|
||||
RaiseLocalEvent(ent.Value, args, false);
|
||||
RaiseLocalEvent(magEnt.Value, args, false);
|
||||
}
|
||||
|
||||
private void OnMagazineControl(EntityUid uid, MagazineAmmoProviderComponent component, AmmoCounterControlEvent args)
|
||||
private void OnMagazineControl(Entity<MagazineAmmoProviderComponent> ent, ref AmmoCounterControlEvent args)
|
||||
{
|
||||
var ent = GetMagazineEntity(uid);
|
||||
if (ent == null)
|
||||
var magEnt = GetMagazineEntity(ent);
|
||||
if (magEnt == null)
|
||||
return;
|
||||
RaiseLocalEvent(ent.Value, args, false);
|
||||
RaiseLocalEvent(magEnt.Value, args, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,24 +13,24 @@ public sealed partial class GunSystem
|
||||
SubscribeLocalEvent<MagazineVisualsComponent, AppearanceChangeEvent>(OnMagazineVisualsChange);
|
||||
}
|
||||
|
||||
private void OnMagazineVisualsInit(EntityUid uid, MagazineVisualsComponent component, ComponentInit args)
|
||||
private void OnMagazineVisualsInit(Entity<MagazineVisualsComponent> ent, ref ComponentInit args)
|
||||
{
|
||||
if (!TryComp<SpriteComponent>(uid, out var sprite)) return;
|
||||
if (!TryComp<SpriteComponent>(ent, out var sprite)) return;
|
||||
|
||||
if (_sprite.LayerMapTryGet((uid, sprite), GunVisualLayers.Mag, out _, false))
|
||||
if (_sprite.LayerMapTryGet((ent, sprite), GunVisualLayers.Mag, out _, false))
|
||||
{
|
||||
_sprite.LayerSetRsiState((uid, sprite), GunVisualLayers.Mag, $"{component.MagState}-{component.MagSteps - 1}");
|
||||
_sprite.LayerSetVisible((uid, sprite), GunVisualLayers.Mag, false);
|
||||
_sprite.LayerSetRsiState((ent, sprite), GunVisualLayers.Mag, $"{ent.Comp.MagState}-{ent.Comp.MagSteps - 1}");
|
||||
_sprite.LayerSetVisible((ent, sprite), GunVisualLayers.Mag, false);
|
||||
}
|
||||
|
||||
if (_sprite.LayerMapTryGet((uid, sprite), GunVisualLayers.MagUnshaded, out _, false))
|
||||
if (_sprite.LayerMapTryGet((ent, sprite), GunVisualLayers.MagUnshaded, out _, false))
|
||||
{
|
||||
_sprite.LayerSetRsiState((uid, sprite), GunVisualLayers.MagUnshaded, $"{component.MagState}-unshaded-{component.MagSteps - 1}");
|
||||
_sprite.LayerSetVisible((uid, sprite), GunVisualLayers.MagUnshaded, false);
|
||||
_sprite.LayerSetRsiState((ent, sprite), GunVisualLayers.MagUnshaded, $"{ent.Comp.MagState}-unshaded-{ent.Comp.MagSteps - 1}");
|
||||
_sprite.LayerSetVisible((ent, sprite), GunVisualLayers.MagUnshaded, false);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnMagazineVisualsChange(EntityUid uid, MagazineVisualsComponent component, ref AppearanceChangeEvent args)
|
||||
private void OnMagazineVisualsChange(Entity<MagazineVisualsComponent> ent, ref AppearanceChangeEvent args)
|
||||
{
|
||||
// tl;dr
|
||||
// 1.If no mag then hide it OR
|
||||
@@ -45,53 +45,53 @@ public sealed partial class GunSystem
|
||||
{
|
||||
if (!args.AppearanceData.TryGetValue(AmmoVisuals.AmmoMax, out var capacity))
|
||||
{
|
||||
capacity = component.MagSteps;
|
||||
capacity = ent.Comp.MagSteps;
|
||||
}
|
||||
|
||||
if (!args.AppearanceData.TryGetValue(AmmoVisuals.AmmoCount, out var current))
|
||||
{
|
||||
current = component.MagSteps;
|
||||
current = ent.Comp.MagSteps;
|
||||
}
|
||||
|
||||
var step = ContentHelpers.RoundToLevels((int)current, (int)capacity, component.MagSteps);
|
||||
var step = ContentHelpers.RoundToLevels((int)current, (int)capacity, ent.Comp.MagSteps);
|
||||
|
||||
if (step == 0 && !component.ZeroVisible)
|
||||
if (step == 0 && !ent.Comp.ZeroVisible)
|
||||
{
|
||||
if (_sprite.LayerMapTryGet((uid, sprite), GunVisualLayers.Mag, out _, false))
|
||||
if (_sprite.LayerMapTryGet((ent, sprite), GunVisualLayers.Mag, out _, false))
|
||||
{
|
||||
_sprite.LayerSetVisible((uid, sprite), GunVisualLayers.Mag, false);
|
||||
_sprite.LayerSetVisible((ent, sprite), GunVisualLayers.Mag, false);
|
||||
}
|
||||
|
||||
if (_sprite.LayerMapTryGet((uid, sprite), GunVisualLayers.MagUnshaded, out _, false))
|
||||
if (_sprite.LayerMapTryGet((ent, sprite), GunVisualLayers.MagUnshaded, out _, false))
|
||||
{
|
||||
_sprite.LayerSetVisible((uid, sprite), GunVisualLayers.MagUnshaded, false);
|
||||
_sprite.LayerSetVisible((ent, sprite), GunVisualLayers.MagUnshaded, false);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (_sprite.LayerMapTryGet((uid, sprite), GunVisualLayers.Mag, out _, false))
|
||||
if (_sprite.LayerMapTryGet((ent, sprite), GunVisualLayers.Mag, out _, false))
|
||||
{
|
||||
_sprite.LayerSetVisible((uid, sprite), GunVisualLayers.Mag, true);
|
||||
_sprite.LayerSetRsiState((uid, sprite), GunVisualLayers.Mag, $"{component.MagState}-{step}");
|
||||
_sprite.LayerSetVisible((ent, sprite), GunVisualLayers.Mag, true);
|
||||
_sprite.LayerSetRsiState((ent, sprite), GunVisualLayers.Mag, $"{ent.Comp.MagState}-{step}");
|
||||
}
|
||||
|
||||
if (_sprite.LayerMapTryGet((uid, sprite), GunVisualLayers.MagUnshaded, out _, false))
|
||||
if (_sprite.LayerMapTryGet((ent, sprite), GunVisualLayers.MagUnshaded, out _, false))
|
||||
{
|
||||
_sprite.LayerSetVisible((uid, sprite), GunVisualLayers.MagUnshaded, true);
|
||||
_sprite.LayerSetRsiState((uid, sprite), GunVisualLayers.MagUnshaded, $"{component.MagState}-unshaded-{step}");
|
||||
_sprite.LayerSetVisible((ent, sprite), GunVisualLayers.MagUnshaded, true);
|
||||
_sprite.LayerSetRsiState((ent, sprite), GunVisualLayers.MagUnshaded, $"{ent.Comp.MagState}-unshaded-{step}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_sprite.LayerMapTryGet((uid, sprite), GunVisualLayers.Mag, out _, false))
|
||||
if (_sprite.LayerMapTryGet((ent, sprite), GunVisualLayers.Mag, out _, false))
|
||||
{
|
||||
_sprite.LayerSetVisible((uid, sprite), GunVisualLayers.Mag, false);
|
||||
_sprite.LayerSetVisible((ent, sprite), GunVisualLayers.Mag, false);
|
||||
}
|
||||
|
||||
if (_sprite.LayerMapTryGet((uid, sprite), GunVisualLayers.MagUnshaded, out _, false))
|
||||
if (_sprite.LayerMapTryGet((ent, sprite), GunVisualLayers.MagUnshaded, out _, false))
|
||||
{
|
||||
_sprite.LayerSetVisible((uid, sprite), GunVisualLayers.MagUnshaded, false);
|
||||
_sprite.LayerSetVisible((ent, sprite), GunVisualLayers.MagUnshaded, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,25 +14,25 @@ public sealed partial class GunSystem
|
||||
SubscribeLocalEvent<RevolverAmmoProviderComponent, EntRemovedFromContainerMessage>(OnRevolverEntRemove);
|
||||
}
|
||||
|
||||
private void OnRevolverEntRemove(EntityUid uid, RevolverAmmoProviderComponent component, EntRemovedFromContainerMessage args)
|
||||
private void OnRevolverEntRemove(Entity<RevolverAmmoProviderComponent> ent, ref EntRemovedFromContainerMessage args)
|
||||
{
|
||||
if (args.Container.ID != RevolverContainer)
|
||||
return;
|
||||
|
||||
// See ChamberMagazineAmmoProvider
|
||||
// <See ChamberMagazineAmmoProvider>
|
||||
if (!IsClientSide(args.Entity))
|
||||
return;
|
||||
|
||||
QueueDel(args.Entity);
|
||||
}
|
||||
|
||||
private void OnRevolverAmmoUpdate(EntityUid uid, RevolverAmmoProviderComponent component, UpdateAmmoCounterEvent args)
|
||||
private void OnRevolverAmmoUpdate(Entity<RevolverAmmoProviderComponent> ent, ref UpdateAmmoCounterEvent args)
|
||||
{
|
||||
if (args.Control is not RevolverStatusControl control) return;
|
||||
control.Update(component.CurrentIndex, component.Chambers);
|
||||
control.Update(ent.Comp.CurrentIndex, ent.Comp.Chambers);
|
||||
}
|
||||
|
||||
private void OnRevolverCounter(EntityUid uid, RevolverAmmoProviderComponent component, AmmoCounterControlEvent args)
|
||||
private void OnRevolverCounter(Entity<RevolverAmmoProviderComponent> ent, ref AmmoCounterControlEvent args)
|
||||
{
|
||||
args.Control = new RevolverStatusControl();
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ public sealed partial class GunSystem
|
||||
SubscribeLocalEvent<SpentAmmoVisualsComponent, AppearanceChangeEvent>(OnSpentAmmoAppearance);
|
||||
}
|
||||
|
||||
private void OnSpentAmmoAppearance(EntityUid uid, SpentAmmoVisualsComponent component, ref AppearanceChangeEvent args)
|
||||
private void OnSpentAmmoAppearance(Entity<SpentAmmoVisualsComponent> ent, ref AppearanceChangeEvent args)
|
||||
{
|
||||
var sprite = args.Sprite;
|
||||
if (sprite == null) return;
|
||||
@@ -21,15 +21,15 @@ public sealed partial class GunSystem
|
||||
return;
|
||||
}
|
||||
|
||||
var spent = (bool) varSpent;
|
||||
var spent = (bool)varSpent;
|
||||
string state;
|
||||
|
||||
if (spent)
|
||||
state = component.Suffix ? $"{component.State}-spent" : "spent";
|
||||
state = ent.Comp.Suffix ? $"{ent.Comp.State}-spent" : "spent";
|
||||
else
|
||||
state = component.State;
|
||||
state = ent.Comp.State;
|
||||
|
||||
_sprite.LayerSetRsiState((uid, sprite), AmmoVisualLayers.Base, state);
|
||||
_sprite.RemoveLayer((uid, sprite), AmmoVisualLayers.Tip, false);
|
||||
_sprite.LayerSetRsiState((ent, sprite), AmmoVisualLayers.Base, state);
|
||||
_sprite.RemoveLayer((ent, sprite), AmmoVisualLayers.Tip, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,13 +31,13 @@ namespace Content.Client.Weapons.Ranged.Systems;
|
||||
|
||||
public sealed partial class GunSystem : SharedGunSystem
|
||||
{
|
||||
[Dependency] private readonly AnimationPlayerSystem _animPlayer = default!;
|
||||
[Dependency] private readonly IEyeManager _eyeManager = default!;
|
||||
[Dependency] private readonly IInputManager _inputManager = default!;
|
||||
[Dependency] private readonly InputSystem _inputSystem = default!;
|
||||
[Dependency] private readonly IOverlayManager _overlayManager = default!;
|
||||
[Dependency] private readonly IPlayerManager _player = default!;
|
||||
[Dependency] private readonly IStateManager _state = default!;
|
||||
[Dependency] private readonly AnimationPlayerSystem _animPlayer = default!;
|
||||
[Dependency] private readonly InputSystem _inputSystem = default!;
|
||||
[Dependency] private readonly SharedCameraRecoilSystem _recoil = default!;
|
||||
[Dependency] private readonly SharedMapSystem _maps = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _xform = default!;
|
||||
@@ -167,29 +167,29 @@ public sealed partial class GunSystem : SharedGunSystem
|
||||
|
||||
var entity = entityNull.Value;
|
||||
|
||||
if (!TryGetGun(entity, out var gunUid, out var gun))
|
||||
if (!TryGetGun(entity, out var gun))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var useKey = gun.UseKey ? EngineKeyFunctions.Use : EngineKeyFunctions.UseSecondary;
|
||||
var useKey = gun.Comp.UseKey ? EngineKeyFunctions.Use : EngineKeyFunctions.UseSecondary;
|
||||
|
||||
if (_inputSystem.CmdStates.GetState(useKey) != BoundKeyState.Down && !gun.BurstActivated)
|
||||
if (_inputSystem.CmdStates.GetState(useKey) != BoundKeyState.Down && !gun.Comp.BurstActivated)
|
||||
{
|
||||
if (gun.ShotCounter != 0)
|
||||
RaisePredictiveEvent(new RequestStopShootEvent { Gun = GetNetEntity(gunUid) });
|
||||
if (gun.Comp.ShotCounter != 0)
|
||||
RaisePredictiveEvent(new RequestStopShootEvent { Gun = GetNetEntity(gun) });
|
||||
return;
|
||||
}
|
||||
|
||||
if (gun.NextFire > Timing.CurTime)
|
||||
if (gun.Comp.NextFire > Timing.CurTime)
|
||||
return;
|
||||
|
||||
var mousePos = _eyeManager.PixelToMap(_inputManager.MouseScreenPosition);
|
||||
|
||||
if (mousePos.MapId == MapId.Nullspace)
|
||||
{
|
||||
if (gun.ShotCounter != 0)
|
||||
RaisePredictiveEvent(new RequestStopShootEvent { Gun = GetNetEntity(gunUid) });
|
||||
if (gun.Comp.ShotCounter != 0)
|
||||
RaisePredictiveEvent(new RequestStopShootEvent { Gun = GetNetEntity(gun) });
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -207,11 +207,11 @@ public sealed partial class GunSystem : SharedGunSystem
|
||||
{
|
||||
Target = target,
|
||||
Coordinates = GetNetCoordinates(coordinates),
|
||||
Gun = GetNetEntity(gunUid),
|
||||
Gun = GetNetEntity(gun),
|
||||
});
|
||||
}
|
||||
|
||||
public override void Shoot(EntityUid gunUid, GunComponent gun, List<(EntityUid? Entity, IShootable Shootable)> ammo,
|
||||
public override void Shoot(Entity<GunComponent> gun, List<(EntityUid? Entity, IShootable Shootable)> ammo,
|
||||
EntityCoordinates fromCoordinates, EntityCoordinates toCoordinates, out bool userImpulse, EntityUid? user = null, bool throwItems = false)
|
||||
{
|
||||
userImpulse = true;
|
||||
@@ -226,7 +226,7 @@ public sealed partial class GunSystem : SharedGunSystem
|
||||
{
|
||||
if (throwItems)
|
||||
{
|
||||
Recoil(user, direction, gun.CameraRecoilScalarModified);
|
||||
Recoil(user, direction, gun.Comp.CameraRecoilScalarModified);
|
||||
if (IsClientSide(ent!.Value))
|
||||
Del(ent.Value);
|
||||
else
|
||||
@@ -241,9 +241,9 @@ public sealed partial class GunSystem : SharedGunSystem
|
||||
if (!cartridge.Spent)
|
||||
{
|
||||
SetCartridgeSpent(ent!.Value, cartridge, true);
|
||||
MuzzleFlash(gunUid, cartridge, worldAngle, user);
|
||||
Audio.PlayPredicted(gun.SoundGunshotModified, gunUid, user);
|
||||
Recoil(user, direction, gun.CameraRecoilScalarModified);
|
||||
MuzzleFlash(gun, cartridge, worldAngle, user);
|
||||
Audio.PlayPredicted(gun.Comp.SoundGunshotModified, gun, user);
|
||||
Recoil(user, direction, gun.Comp.CameraRecoilScalarModified);
|
||||
// TODO: Can't predict entity deletions.
|
||||
//if (cartridge.DeleteOnSpawn)
|
||||
// Del(cartridge.Owner);
|
||||
@@ -251,7 +251,7 @@ public sealed partial class GunSystem : SharedGunSystem
|
||||
else
|
||||
{
|
||||
userImpulse = false;
|
||||
Audio.PlayPredicted(gun.SoundEmpty, gunUid, user);
|
||||
Audio.PlayPredicted(gun.Comp.SoundEmpty, gun, user);
|
||||
}
|
||||
|
||||
if (IsClientSide(ent!.Value))
|
||||
@@ -259,17 +259,17 @@ public sealed partial class GunSystem : SharedGunSystem
|
||||
|
||||
break;
|
||||
case AmmoComponent newAmmo:
|
||||
MuzzleFlash(gunUid, newAmmo, worldAngle, user);
|
||||
Audio.PlayPredicted(gun.SoundGunshotModified, gunUid, user);
|
||||
Recoil(user, direction, gun.CameraRecoilScalarModified);
|
||||
MuzzleFlash(gun, newAmmo, worldAngle, user);
|
||||
Audio.PlayPredicted(gun.Comp.SoundGunshotModified, gun, user);
|
||||
Recoil(user, direction, gun.Comp.CameraRecoilScalarModified);
|
||||
if (IsClientSide(ent!.Value))
|
||||
Del(ent.Value);
|
||||
else
|
||||
RemoveShootable(ent.Value);
|
||||
break;
|
||||
case HitscanAmmoComponent:
|
||||
Audio.PlayPredicted(gun.SoundGunshotModified, gunUid, user);
|
||||
Recoil(user, direction, gun.CameraRecoilScalarModified);
|
||||
Audio.PlayPredicted(gun.Comp.SoundGunshotModified, gun, user);
|
||||
Recoil(user, direction, gun.Comp.CameraRecoilScalarModified);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -407,5 +407,5 @@ public sealed partial class GunSystem : SharedGunSystem
|
||||
}
|
||||
|
||||
// TODO: Move RangedDamageSoundComponent to shared so this can be predicted.
|
||||
public override void PlayImpactSound(EntityUid otherEntity, DamageSpecifier? modifiedDamage, SoundSpecifier? weaponSound, bool forceWeaponSound) {}
|
||||
public override void PlayImpactSound(EntityUid otherEntity, DamageSpecifier? modifiedDamage, SoundSpecifier? weaponSound, bool forceWeaponSound) { }
|
||||
}
|
||||
|
||||
@@ -478,11 +478,11 @@ public abstract partial class InteractionTest
|
||||
var wasInCombatMode = IsInCombatMode();
|
||||
await SetCombatMode(true);
|
||||
|
||||
Assert.That(SGun.TryGetGun(SPlayer, out var gunUid, out var gunComp), "Player was not holding a gun!");
|
||||
Assert.That(SGun.TryGetGun(SPlayer, out var gun), "Player was not holding a gun!");
|
||||
|
||||
await Server.WaitAssertion(() =>
|
||||
{
|
||||
var success = SGun.AttemptShoot(SPlayer, gunUid, gunComp!, actualTarget);
|
||||
var success = SGun.AttemptShoot(SPlayer, gun, actualTarget);
|
||||
if (assert)
|
||||
Assert.That(success, "Gun failed to shoot.");
|
||||
});
|
||||
@@ -517,11 +517,11 @@ public abstract partial class InteractionTest
|
||||
var wasInCombatMode = IsInCombatMode();
|
||||
await SetCombatMode(true);
|
||||
|
||||
Assert.That(SGun.TryGetGun(SPlayer, out var gunUid, out var gunComp), "Player was not holding a gun!");
|
||||
Assert.That(SGun.TryGetGun(SPlayer, out var gun), "Player was not holding a gun!");
|
||||
|
||||
await Server.WaitAssertion(() =>
|
||||
{
|
||||
var success = SGun.AttemptShoot(SPlayer, gunUid, gunComp!, Position(actualTarget!.Value), ToServer(actualTarget));
|
||||
var success = SGun.AttemptShoot(SPlayer, gun, Position(actualTarget!.Value), ToServer(actualTarget));
|
||||
if (assert)
|
||||
Assert.That(success, "Gun failed to shoot.");
|
||||
});
|
||||
@@ -839,7 +839,7 @@ public abstract partial class InteractionTest
|
||||
/// <param name="uid">The entity at which the events were directed</param>
|
||||
/// <param name="count">How many new events are expected</param>
|
||||
/// <param name="predicate">A predicate that can be used to filter the recorded events</param>
|
||||
protected void AssertEvent<TEvent>(EntityUid? uid = null, int count = 1, Func<TEvent,bool>? predicate = null)
|
||||
protected void AssertEvent<TEvent>(EntityUid? uid = null, int count = 1, Func<TEvent, bool>? predicate = null)
|
||||
where TEvent : notnull
|
||||
{
|
||||
Assert.That(GetEvents(uid, predicate).Count, Is.EqualTo(count));
|
||||
@@ -872,7 +872,7 @@ public abstract partial class InteractionTest
|
||||
where TEvent : notnull
|
||||
{
|
||||
if (_listenerCache.TryGetValue(typeof(TEvent), out var listener))
|
||||
return (TestListenerSystem<TEvent>) listener;
|
||||
return (TestListenerSystem<TEvent>)listener;
|
||||
|
||||
var type = Server.Resolve<IReflectionManager>().GetAllChildren<TestListenerSystem<TEvent>>().Single();
|
||||
if (!SEntMan.EntitySysManager.TryGetEntitySystem(type, out var systemObj))
|
||||
|
||||
@@ -722,7 +722,7 @@ public sealed partial class AdminVerbSystem
|
||||
return;
|
||||
|
||||
_gun.SetBallisticUnspawned((args.Target, ballisticAmmo), result);
|
||||
_gun.UpdateBallisticAppearance(args.Target, ballisticAmmo);
|
||||
_gun.UpdateBallisticAppearance((args.Target, ballisticAmmo));
|
||||
});
|
||||
},
|
||||
Impact = LogImpact.Medium,
|
||||
|
||||
@@ -27,18 +27,18 @@ public sealed partial class GunSignalControlSystem : EntitySystem
|
||||
return;
|
||||
|
||||
if (args.Port == gunControl.Comp.TriggerPort)
|
||||
_gun.AttemptShoot(gunControl, gun);
|
||||
_gun.AttemptShoot((gunControl, gun));
|
||||
|
||||
if (!TryComp<AutoShootGunComponent>(gunControl, out var autoShoot))
|
||||
return;
|
||||
|
||||
if (args.Port == gunControl.Comp.TogglePort)
|
||||
_gun.SetEnabled(gunControl, autoShoot, !autoShoot.Enabled);
|
||||
_gun.SetEnabled((gunControl, autoShoot), !autoShoot.Enabled);
|
||||
|
||||
if (args.Port == gunControl.Comp.OnPort)
|
||||
_gun.SetEnabled(gunControl, autoShoot, true);
|
||||
_gun.SetEnabled((gunControl, autoShoot), true);
|
||||
|
||||
if (args.Port == gunControl.Comp.OffPort)
|
||||
_gun.SetEnabled(gunControl, autoShoot, false);
|
||||
_gun.SetEnabled((gunControl, autoShoot), false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,10 +10,10 @@ public sealed partial class GunAmmoPrecondition : HTNPrecondition
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entManager = default!;
|
||||
|
||||
[DataField("minPercent")]
|
||||
[DataField]
|
||||
public float MinPercent = 0f;
|
||||
|
||||
[DataField("maxPercent")]
|
||||
[DataField]
|
||||
public float MaxPercent = 1f;
|
||||
|
||||
public override bool IsMet(NPCBlackboard blackboard)
|
||||
@@ -21,19 +21,19 @@ public sealed partial class GunAmmoPrecondition : HTNPrecondition
|
||||
var owner = blackboard.GetValue<EntityUid>(NPCBlackboard.Owner);
|
||||
var gunSystem = _entManager.System<GunSystem>();
|
||||
|
||||
if (!gunSystem.TryGetGun(owner, out var gunUid, out _))
|
||||
if (!gunSystem.TryGetGun(owner, out var gun))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var ammoEv = new GetAmmoCountEvent();
|
||||
_entManager.EventBus.RaiseLocalEvent(gunUid, ref ammoEv);
|
||||
_entManager.EventBus.RaiseLocalEvent(gun, ref ammoEv);
|
||||
float percent;
|
||||
|
||||
if (ammoEv.Capacity == 0)
|
||||
percent = 0f;
|
||||
else
|
||||
percent = ammoEv.Count / (float) ammoEv.Capacity;
|
||||
percent = ammoEv.Count / (float)ammoEv.Capacity;
|
||||
|
||||
percent = System.Math.Clamp(percent, 0f, 1f);
|
||||
|
||||
|
||||
@@ -96,7 +96,7 @@ public sealed partial class NPCCombatSystem
|
||||
_combat.SetInCombatMode(uid, true, combatMode);
|
||||
}
|
||||
|
||||
if (!_gun.TryGetGun(uid, out var gunUid, out var gun))
|
||||
if (!_gun.TryGetGun(uid, out var gun))
|
||||
{
|
||||
comp.Status = CombatStatus.NoWeapon;
|
||||
comp.ShootAccumulator = 0f;
|
||||
@@ -104,12 +104,12 @@ public sealed partial class NPCCombatSystem
|
||||
}
|
||||
|
||||
var ammoEv = new GetAmmoCountEvent();
|
||||
RaiseLocalEvent(gunUid, ref ammoEv);
|
||||
RaiseLocalEvent(gun, ref ammoEv);
|
||||
|
||||
if (ammoEv.Count == 0)
|
||||
{
|
||||
// Recharging then?
|
||||
if (_rechargeQuery.HasComponent(gunUid))
|
||||
if (_rechargeQuery.HasComponent(gun))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -200,12 +200,12 @@ public sealed partial class NPCCombatSystem
|
||||
|
||||
comp.Status = CombatStatus.Normal;
|
||||
|
||||
if (gun.NextFire > _timing.CurTime)
|
||||
if (gun.Comp.NextFire > _timing.CurTime)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_gun.AttemptShoot(uid, gunUid, gun, targetCordinates, comp.Target);
|
||||
_gun.AttemptShoot(uid, gun, targetCordinates, comp.Target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -232,7 +232,7 @@ namespace Content.Server.Singularity.EntitySystems
|
||||
|
||||
var targetPos = new EntityCoordinates(uid, new Vector2(0, -1));
|
||||
|
||||
_gun.Shoot(uid, gunComponent, ent, xform.Coordinates, targetPos, out _);
|
||||
_gun.Shoot((uid, gunComponent), ent, xform.Coordinates, targetPos, out _);
|
||||
}
|
||||
|
||||
private void UpdateAppearance(EntityUid uid, EmitterComponent component)
|
||||
|
||||
@@ -84,7 +84,7 @@ public sealed partial class DeployableTurretSystem : SharedDeployableTurretSyste
|
||||
args.Data.TryGetValue(command, out int? armamentState))
|
||||
{
|
||||
if (TryComp<BatteryWeaponFireModesComponent>(ent, out var batteryWeaponFireModes))
|
||||
_fireModes.TrySetFireMode(ent, batteryWeaponFireModes, armamentState.Value);
|
||||
_fireModes.TrySetFireMode((ent, batteryWeaponFireModes), armamentState.Value);
|
||||
|
||||
TrySetState(ent, armamentState.Value >= 0);
|
||||
return;
|
||||
|
||||
@@ -2,7 +2,4 @@ using Content.Shared.Weapons.Marker;
|
||||
|
||||
namespace Content.Server.Weapons;
|
||||
|
||||
public sealed class DamageMarkerSystem : SharedDamageMarkerSystem
|
||||
{
|
||||
|
||||
}
|
||||
public sealed class DamageMarkerSystem : SharedDamageMarkerSystem { }
|
||||
|
||||
@@ -3,4 +3,4 @@ using Content.Shared.Weapons.Ranged.Components;
|
||||
namespace Content.Server.Weapons.Ranged.Components;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class AmmoCounterComponent : SharedAmmoCounterComponent {}
|
||||
public sealed partial class AmmoCounterComponent : SharedAmmoCounterComponent { }
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
namespace Content.Server.Weapons.Ranged.Components
|
||||
{
|
||||
[RegisterComponent]
|
||||
public sealed partial class ChemicalAmmoComponent : Component
|
||||
{
|
||||
public const string DefaultSolutionName = "ammo";
|
||||
namespace Content.Server.Weapons.Ranged.Components;
|
||||
|
||||
[DataField("solution")]
|
||||
public string SolutionName { get; set; } = DefaultSolutionName;
|
||||
}
|
||||
[RegisterComponent]
|
||||
public sealed partial class ChemicalAmmoComponent : Component
|
||||
{
|
||||
public const string DefaultSolutionName = "ammo";
|
||||
|
||||
[DataField("solution")]
|
||||
public string SolutionName { get; set; } = DefaultSolutionName;
|
||||
}
|
||||
|
||||
@@ -16,15 +16,13 @@ public sealed partial class RangedDamageSoundComponent : Component
|
||||
/// Specified sounds to apply when the entity takes damage with the specified group.
|
||||
/// Will fallback to defaults if none specified.
|
||||
/// </summary>
|
||||
[DataField("soundGroups",
|
||||
customTypeSerializer: typeof(PrototypeIdDictionarySerializer<SoundSpecifier, DamageGroupPrototype>))]
|
||||
[DataField(customTypeSerializer: typeof(PrototypeIdDictionarySerializer<SoundSpecifier, DamageGroupPrototype>))]
|
||||
public Dictionary<string, SoundSpecifier>? SoundGroups;
|
||||
|
||||
/// <summary>
|
||||
/// Specified sounds to apply when the entity takes damage with the specified type.
|
||||
/// Will fallback to defaults if none specified.
|
||||
/// </summary>
|
||||
[DataField("soundTypes",
|
||||
customTypeSerializer: typeof(PrototypeIdDictionarySerializer<SoundSpecifier, DamageTypePrototype>))]
|
||||
[DataField(customTypeSerializer: typeof(PrototypeIdDictionarySerializer<SoundSpecifier, DamageTypePrototype>))]
|
||||
public Dictionary<string, SoundSpecifier>? SoundTypes;
|
||||
}
|
||||
|
||||
@@ -1,49 +1,48 @@
|
||||
using Content.Server.Weapons.Ranged.Components;
|
||||
using Content.Shared.Chemistry.Components;
|
||||
using Content.Shared.Weapons.Ranged.Events;
|
||||
using Content.Shared.Chemistry.EntitySystems;
|
||||
using Content.Shared.Weapons.Ranged.Events;
|
||||
using System.Linq;
|
||||
|
||||
namespace Content.Server.Weapons.Ranged.Systems
|
||||
namespace Content.Server.Weapons.Ranged.Systems;
|
||||
|
||||
public sealed class ChemicalAmmoSystem : EntitySystem
|
||||
{
|
||||
public sealed class ChemicalAmmoSystem : EntitySystem
|
||||
[Dependency] private readonly SharedSolutionContainerSystem _solutionContainerSystem = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
[Dependency] private readonly SharedSolutionContainerSystem _solutionContainerSystem = default!;
|
||||
SubscribeLocalEvent<ChemicalAmmoComponent, AmmoShotEvent>(OnFire);
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
private void OnFire(Entity<ChemicalAmmoComponent> entity, ref AmmoShotEvent args)
|
||||
{
|
||||
if (!_solutionContainerSystem.TryGetSolution(entity.Owner, entity.Comp.SolutionName, out var ammoSoln, out var ammoSolution))
|
||||
return;
|
||||
|
||||
var projectiles = args.FiredProjectiles;
|
||||
|
||||
var projectileSolutionContainers = new List<(EntityUid, Entity<SolutionComponent>)>();
|
||||
foreach (var projectile in projectiles)
|
||||
{
|
||||
SubscribeLocalEvent<ChemicalAmmoComponent, AmmoShotEvent>(OnFire);
|
||||
if (_solutionContainerSystem
|
||||
.TryGetSolution(projectile, entity.Comp.SolutionName, out var projectileSoln, out _))
|
||||
{
|
||||
projectileSolutionContainers.Add((projectile, projectileSoln.Value));
|
||||
}
|
||||
}
|
||||
|
||||
private void OnFire(Entity<ChemicalAmmoComponent> entity, ref AmmoShotEvent args)
|
||||
if (!projectileSolutionContainers.Any())
|
||||
return;
|
||||
|
||||
var solutionPerProjectile = ammoSolution.Volume * (1 / projectileSolutionContainers.Count);
|
||||
|
||||
foreach (var (_, projectileSolution) in projectileSolutionContainers)
|
||||
{
|
||||
if (!_solutionContainerSystem.TryGetSolution(entity.Owner, entity.Comp.SolutionName, out var ammoSoln, out var ammoSolution))
|
||||
return;
|
||||
|
||||
var projectiles = args.FiredProjectiles;
|
||||
|
||||
var projectileSolutionContainers = new List<(EntityUid, Entity<SolutionComponent>)>();
|
||||
foreach (var projectile in projectiles)
|
||||
{
|
||||
if (_solutionContainerSystem
|
||||
.TryGetSolution(projectile, entity.Comp.SolutionName, out var projectileSoln, out _))
|
||||
{
|
||||
projectileSolutionContainers.Add((projectile, projectileSoln.Value));
|
||||
}
|
||||
}
|
||||
|
||||
if (!projectileSolutionContainers.Any())
|
||||
return;
|
||||
|
||||
var solutionPerProjectile = ammoSolution.Volume * (1 / projectileSolutionContainers.Count);
|
||||
|
||||
foreach (var (_, projectileSolution) in projectileSolutionContainers)
|
||||
{
|
||||
var solutionToTransfer = _solutionContainerSystem.SplitSolution(ammoSoln.Value, solutionPerProjectile);
|
||||
_solutionContainerSystem.TryAddSolution(projectileSolution, solutionToTransfer);
|
||||
}
|
||||
|
||||
_solutionContainerSystem.RemoveAllSolution(ammoSoln.Value);
|
||||
var solutionToTransfer = _solutionContainerSystem.SplitSolution(ammoSoln.Value, solutionPerProjectile);
|
||||
_solutionContainerSystem.TryAddSolution(projectileSolution, solutionToTransfer);
|
||||
}
|
||||
|
||||
_solutionContainerSystem.RemoveAllSolution(ammoSoln.Value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,4 +2,4 @@ using Content.Shared.Weapons.Ranged.Systems;
|
||||
|
||||
namespace Content.Server.Weapons.Ranged.Systems;
|
||||
|
||||
public sealed class FlyBySoundSystem : SharedFlyBySoundSystem {}
|
||||
public sealed class FlyBySoundSystem : SharedFlyBySoundSystem { }
|
||||
|
||||
@@ -27,15 +27,15 @@ public sealed partial class GunSystem
|
||||
if (!autoShoot.Enabled)
|
||||
continue;
|
||||
|
||||
AttemptShoot(uid, gun);
|
||||
AttemptShoot((uid, gun));
|
||||
}
|
||||
else if (gun.BurstActivated)
|
||||
{
|
||||
var parent = TransformSystem.GetParentUid(uid);
|
||||
if (HasComp<DamageableComponent>(parent))
|
||||
AttemptShoot(parent, uid, gun, gun.ShootCoordinates ?? new EntityCoordinates(uid, gun.DefaultDirection));
|
||||
AttemptShoot(parent, (uid, gun), gun.ShootCoordinates ?? new EntityCoordinates(uid, gun.DefaultDirection));
|
||||
else
|
||||
AttemptShoot(uid, gun);
|
||||
AttemptShoot((uid, gun));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,32 +6,32 @@ namespace Content.Server.Weapons.Ranged.Systems;
|
||||
|
||||
public sealed partial class GunSystem
|
||||
{
|
||||
protected override void Cycle(EntityUid uid, BallisticAmmoProviderComponent component, MapCoordinates coordinates)
|
||||
protected override void Cycle(Entity<BallisticAmmoProviderComponent> ent, MapCoordinates coordinates)
|
||||
{
|
||||
EntityUid? ent = null;
|
||||
EntityUid? ammoEnt = null;
|
||||
|
||||
// TODO: Combine with TakeAmmo
|
||||
if (component.Entities.Count > 0)
|
||||
if (ent.Comp.Entities.Count > 0)
|
||||
{
|
||||
var existing = component.Entities[^1];
|
||||
component.Entities.RemoveAt(component.Entities.Count - 1);
|
||||
DirtyField(uid, component, nameof(BallisticAmmoProviderComponent.Entities));
|
||||
var existing = ent.Comp.Entities[^1];
|
||||
ent.Comp.Entities.RemoveAt(ent.Comp.Entities.Count - 1);
|
||||
DirtyField(ent.AsNullable(), nameof(BallisticAmmoProviderComponent.Entities));
|
||||
|
||||
Containers.Remove(existing, component.Container);
|
||||
Containers.Remove(existing, ent.Comp.Container);
|
||||
EnsureShootable(existing);
|
||||
}
|
||||
else if (component.UnspawnedCount > 0)
|
||||
else if (ent.Comp.UnspawnedCount > 0)
|
||||
{
|
||||
component.UnspawnedCount--;
|
||||
DirtyField(uid, component, nameof(BallisticAmmoProviderComponent.UnspawnedCount));
|
||||
ent = Spawn(component.Proto, coordinates);
|
||||
EnsureShootable(ent.Value);
|
||||
ent.Comp.UnspawnedCount--;
|
||||
DirtyField(ent.AsNullable(), nameof(BallisticAmmoProviderComponent.UnspawnedCount));
|
||||
ammoEnt = Spawn(ent.Comp.Proto, coordinates);
|
||||
EnsureShootable(ammoEnt.Value);
|
||||
}
|
||||
|
||||
if (ent != null)
|
||||
EjectCartridge(ent.Value);
|
||||
if (ammoEnt != null)
|
||||
EjectCartridge(ammoEnt.Value);
|
||||
|
||||
var cycledEvent = new GunCycledEvent();
|
||||
RaiseLocalEvent(uid, ref cycledEvent);
|
||||
RaiseLocalEvent(ent, ref cycledEvent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,15 +4,15 @@ namespace Content.Server.Weapons.Ranged.Systems;
|
||||
|
||||
public sealed partial class GunSystem
|
||||
{
|
||||
protected override void SpinRevolver(EntityUid revolverUid, RevolverAmmoProviderComponent component, EntityUid? user = null)
|
||||
protected override void SpinRevolver(Entity<RevolverAmmoProviderComponent> ent, EntityUid? user = null)
|
||||
{
|
||||
base.SpinRevolver(revolverUid, component, user);
|
||||
var index = Random.Next(component.Capacity);
|
||||
base.SpinRevolver(ent, user);
|
||||
var index = Random.Next(ent.Comp.Capacity);
|
||||
|
||||
if (component.CurrentIndex == index)
|
||||
if (ent.Comp.CurrentIndex == index)
|
||||
return;
|
||||
|
||||
component.CurrentIndex = index;
|
||||
Dirty(revolverUid, component);
|
||||
ent.Comp.CurrentIndex = index;
|
||||
Dirty(ent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,63 +23,63 @@ public sealed partial class GunSystem
|
||||
|
||||
private void OnSolutionMapInit(Entity<SolutionAmmoProviderComponent> entity, ref MapInitEvent args)
|
||||
{
|
||||
UpdateSolutionShots(entity.Owner, entity.Comp);
|
||||
UpdateSolutionShots(entity);
|
||||
}
|
||||
|
||||
private void OnSolutionChanged(Entity<SolutionAmmoProviderComponent> entity, ref SolutionContainerChangedEvent args)
|
||||
{
|
||||
if (args.Solution.Name == entity.Comp.SolutionId)
|
||||
UpdateSolutionShots(entity.Owner, entity.Comp, args.Solution);
|
||||
UpdateSolutionShots(entity, args.Solution);
|
||||
}
|
||||
|
||||
protected override void UpdateSolutionShots(EntityUid uid, SolutionAmmoProviderComponent component, Solution? solution = null)
|
||||
protected override void UpdateSolutionShots(Entity<SolutionAmmoProviderComponent> ent, Solution? solution = null)
|
||||
{
|
||||
var shots = 0;
|
||||
var maxShots = 0;
|
||||
if (solution == null && !_solutionContainer.TryGetSolution(uid, component.SolutionId, out _, out solution))
|
||||
if (solution == null && !_solutionContainer.TryGetSolution(ent.Owner, ent.Comp.SolutionId, out _, out solution))
|
||||
{
|
||||
component.Shots = shots;
|
||||
DirtyField(uid, component, nameof(SolutionAmmoProviderComponent.Shots));
|
||||
component.MaxShots = maxShots;
|
||||
DirtyField(uid, component, nameof(SolutionAmmoProviderComponent.MaxShots));
|
||||
ent.Comp.Shots = shots;
|
||||
DirtyField(ent.AsNullable(), nameof(SolutionAmmoProviderComponent.Shots));
|
||||
ent.Comp.MaxShots = maxShots;
|
||||
DirtyField(ent.AsNullable(), nameof(SolutionAmmoProviderComponent.MaxShots));
|
||||
return;
|
||||
}
|
||||
|
||||
shots = (int) (solution.Volume / component.FireCost);
|
||||
maxShots = (int) (solution.MaxVolume / component.FireCost);
|
||||
shots = (int)(solution.Volume / ent.Comp.FireCost);
|
||||
maxShots = (int)(solution.MaxVolume / ent.Comp.FireCost);
|
||||
|
||||
component.Shots = shots;
|
||||
DirtyField(uid, component, nameof(SolutionAmmoProviderComponent.Shots));
|
||||
ent.Comp.Shots = shots;
|
||||
DirtyField(ent.AsNullable(), nameof(SolutionAmmoProviderComponent.Shots));
|
||||
|
||||
component.MaxShots = maxShots;
|
||||
DirtyField(uid, component, nameof(SolutionAmmoProviderComponent.MaxShots));
|
||||
ent.Comp.MaxShots = maxShots;
|
||||
DirtyField(ent.AsNullable(), nameof(SolutionAmmoProviderComponent.MaxShots));
|
||||
|
||||
UpdateSolutionAppearance(uid, component);
|
||||
UpdateSolutionAppearance(ent);
|
||||
}
|
||||
|
||||
protected override (EntityUid Entity, IShootable) GetSolutionShot(EntityUid uid, SolutionAmmoProviderComponent component, EntityCoordinates position)
|
||||
protected override (EntityUid Entity, IShootable) GetSolutionShot(Entity<SolutionAmmoProviderComponent> ent, EntityCoordinates position)
|
||||
{
|
||||
var (ent, shootable) = base.GetSolutionShot(uid, component, position);
|
||||
var (shot, shootable) = base.GetSolutionShot(ent, position);
|
||||
|
||||
if (!_solutionContainer.TryGetSolution(uid, component.SolutionId, out var solution, out _))
|
||||
return (ent, shootable);
|
||||
if (!_solutionContainer.TryGetSolution(ent.Owner, ent.Comp.SolutionId, out var solution, out _))
|
||||
return (shot, shootable);
|
||||
|
||||
var newSolution = _solutionContainer.SplitSolution(solution.Value, component.FireCost);
|
||||
var newSolution = _solutionContainer.SplitSolution(solution.Value, ent.Comp.FireCost);
|
||||
|
||||
if (newSolution.Volume <= FixedPoint2.Zero)
|
||||
return (ent, shootable);
|
||||
return (shot, shootable);
|
||||
|
||||
if (TryComp<AppearanceComponent>(ent, out var appearance))
|
||||
if (TryComp<AppearanceComponent>(shot, out var appearance))
|
||||
{
|
||||
Appearance.SetData(ent, VaporVisuals.Color, newSolution.GetColor(ProtoManager).WithAlpha(1f), appearance);
|
||||
Appearance.SetData(ent, VaporVisuals.State, true, appearance);
|
||||
Appearance.SetData(shot, VaporVisuals.Color, newSolution.GetColor(ProtoManager).WithAlpha(1f), appearance);
|
||||
Appearance.SetData(shot, VaporVisuals.State, true, appearance);
|
||||
}
|
||||
|
||||
// Add the solution to the vapor and actually send the thing
|
||||
if (_solutionContainer.TryGetSolution(ent, VaporComponent.SolutionName, out var vaporSolution, out _))
|
||||
if (_solutionContainer.TryGetSolution(shot, VaporComponent.SolutionName, out var vaporSolution, out _))
|
||||
{
|
||||
_solutionContainer.TryAddSolution(vaporSolution.Value, newSolution);
|
||||
}
|
||||
return (ent, shootable);
|
||||
return (shot, shootable);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,30 +33,30 @@ public sealed partial class GunSystem : SharedGunSystem
|
||||
SubscribeLocalEvent<BallisticAmmoProviderComponent, PriceCalculationEvent>(OnBallisticPrice);
|
||||
}
|
||||
|
||||
private void OnBallisticPrice(EntityUid uid, BallisticAmmoProviderComponent component, ref PriceCalculationEvent args)
|
||||
private void OnBallisticPrice(Entity<BallisticAmmoProviderComponent> ent, ref PriceCalculationEvent args)
|
||||
{
|
||||
if (string.IsNullOrEmpty(component.Proto) || component.UnspawnedCount == 0)
|
||||
if (string.IsNullOrEmpty(ent.Comp.Proto) || ent.Comp.UnspawnedCount == 0)
|
||||
return;
|
||||
|
||||
if (!ProtoManager.TryIndex<EntityPrototype>(component.Proto, out var proto))
|
||||
if (!ProtoManager.TryIndex<EntityPrototype>(ent.Comp.Proto, out var proto))
|
||||
{
|
||||
Log.Error($"Unable to find fill prototype for price on {component.Proto} on {ToPrettyString(uid)}");
|
||||
Log.Error($"Unable to find fill prototype for price on {ent.Comp.Proto} on {ToPrettyString(ent)}");
|
||||
return;
|
||||
}
|
||||
|
||||
// Probably good enough for most.
|
||||
var price = _pricing.GetEstimatedPrice(proto);
|
||||
args.Price += price * component.UnspawnedCount;
|
||||
args.Price += price * ent.Comp.UnspawnedCount;
|
||||
}
|
||||
|
||||
public override void Shoot(EntityUid gunUid, GunComponent gun, List<(EntityUid? Entity, IShootable Shootable)> ammo,
|
||||
public override void Shoot(Entity<GunComponent> gun, List<(EntityUid? Entity, IShootable Shootable)> ammo,
|
||||
EntityCoordinates fromCoordinates, EntityCoordinates toCoordinates, out bool userImpulse, EntityUid? user = null, bool throwItems = false)
|
||||
{
|
||||
userImpulse = true;
|
||||
|
||||
if (user != null)
|
||||
{
|
||||
var selfEvent = new SelfBeforeGunShotEvent(user.Value, (gunUid, gun), ammo);
|
||||
var selfEvent = new SelfBeforeGunShotEvent(user.Value, gun, ammo);
|
||||
RaiseLocalEvent(user.Value, selfEvent);
|
||||
if (selfEvent.Cancelled)
|
||||
{
|
||||
@@ -90,7 +90,7 @@ public sealed partial class GunSystem : SharedGunSystem
|
||||
// pneumatic cannon doesn't shoot bullets it just throws them, ignore ammo handling
|
||||
if (throwItems && ent != null)
|
||||
{
|
||||
ShootOrThrow(ent.Value, mapDirection, gunVelocity, gun, gunUid, user);
|
||||
ShootOrThrow(ent.Value, mapDirection, gunVelocity, gun, user);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -117,7 +117,7 @@ public sealed partial class GunSystem : SharedGunSystem
|
||||
else
|
||||
{
|
||||
userImpulse = false;
|
||||
Audio.PlayPredicted(gun.SoundEmpty, gunUid, user);
|
||||
Audio.PlayPredicted(gun.Comp.SoundEmpty, gun, user);
|
||||
}
|
||||
|
||||
// Something like ballistic might want to leave it in the container still
|
||||
@@ -141,22 +141,22 @@ public sealed partial class GunSystem : SharedGunSystem
|
||||
{
|
||||
FromCoordinates = fromCoordinates,
|
||||
ShotDirection = mapDirection.Normalized(),
|
||||
Gun = gunUid,
|
||||
Gun = gun,
|
||||
Shooter = user,
|
||||
Target = gun.Target,
|
||||
Target = gun.Comp.Target,
|
||||
};
|
||||
RaiseLocalEvent(ent.Value, ref hitscanEv);
|
||||
|
||||
Del(ent);
|
||||
|
||||
Audio.PlayPredicted(gun.SoundGunshotModified, gunUid, user);
|
||||
Audio.PlayPredicted(gun.Comp.SoundGunshotModified, gun, user);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
RaiseLocalEvent(gunUid, new AmmoShotEvent()
|
||||
RaiseLocalEvent(gun, new AmmoShotEvent()
|
||||
{
|
||||
FiredProjectiles = shotProjectiles,
|
||||
});
|
||||
@@ -166,35 +166,35 @@ public sealed partial class GunSystem : SharedGunSystem
|
||||
if (TryComp<ProjectileSpreadComponent>(ammoEnt, out var ammoSpreadComp))
|
||||
{
|
||||
var spreadEvent = new GunGetAmmoSpreadEvent(ammoSpreadComp.Spread);
|
||||
RaiseLocalEvent(gunUid, ref spreadEvent);
|
||||
RaiseLocalEvent(gun, ref spreadEvent);
|
||||
|
||||
var angles = LinearSpread(mapAngle - spreadEvent.Spread / 2,
|
||||
mapAngle + spreadEvent.Spread / 2, ammoSpreadComp.Count);
|
||||
|
||||
ShootOrThrow(ammoEnt, angles[0].ToVec(), gunVelocity, gun, gunUid, user);
|
||||
ShootOrThrow(ammoEnt, angles[0].ToVec(), gunVelocity, gun, user);
|
||||
shotProjectiles.Add(ammoEnt);
|
||||
|
||||
for (var i = 1; i < ammoSpreadComp.Count; i++)
|
||||
{
|
||||
var newuid = Spawn(ammoSpreadComp.Proto, fromEnt);
|
||||
ShootOrThrow(newuid, angles[i].ToVec(), gunVelocity, gun, gunUid, user);
|
||||
ShootOrThrow(newuid, angles[i].ToVec(), gunVelocity, gun, user);
|
||||
shotProjectiles.Add(newuid);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ShootOrThrow(ammoEnt, mapDirection, gunVelocity, gun, gunUid, user);
|
||||
ShootOrThrow(ammoEnt, mapDirection, gunVelocity, gun, user);
|
||||
shotProjectiles.Add(ammoEnt);
|
||||
}
|
||||
|
||||
MuzzleFlash(gunUid, ammoComp, mapDirection.ToAngle(), user);
|
||||
Audio.PlayPredicted(gun.SoundGunshotModified, gunUid, user);
|
||||
MuzzleFlash(gun, ammoComp, mapDirection.ToAngle(), user);
|
||||
Audio.PlayPredicted(gun.Comp.SoundGunshotModified, gun, user);
|
||||
}
|
||||
}
|
||||
|
||||
private void ShootOrThrow(EntityUid uid, Vector2 mapDirection, Vector2 gunVelocity, GunComponent gun, EntityUid gunUid, EntityUid? user)
|
||||
private void ShootOrThrow(EntityUid uid, Vector2 mapDirection, Vector2 gunVelocity, Entity<GunComponent> gun, EntityUid? user)
|
||||
{
|
||||
if (gun.Target is { } target && !TerminatingOrDeleted(target))
|
||||
if (gun.Comp.Target is { } target && !TerminatingOrDeleted(target))
|
||||
{
|
||||
var targeted = EnsureComp<TargetedProjectileComponent>(uid);
|
||||
targeted.Target = target;
|
||||
@@ -206,11 +206,11 @@ public sealed partial class GunSystem : SharedGunSystem
|
||||
{
|
||||
RemoveShootable(uid);
|
||||
// TODO: Someone can probably yeet this a billion miles so need to pre-validate input somewhere up the call stack.
|
||||
ThrowingSystem.TryThrow(uid, mapDirection, gun.ProjectileSpeedModified, user);
|
||||
ThrowingSystem.TryThrow(uid, mapDirection, gun.Comp.ProjectileSpeedModified, user);
|
||||
return;
|
||||
}
|
||||
|
||||
ShootProjectile(uid, mapDirection, gunVelocity, gunUid, user, gun.ProjectileSpeedModified);
|
||||
ShootProjectile(uid, mapDirection, gunVelocity, gun, user, gun.Comp.ProjectileSpeedModified);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -461,7 +461,7 @@ public abstract class SharedMagicSystem : EntitySystem
|
||||
return;
|
||||
|
||||
if (TryComp<BasicEntityAmmoProviderComponent>(wand, out var basicAmmoComp) && basicAmmoComp.Count != null)
|
||||
_gunSystem.UpdateBasicEntityAmmoCount(wand.Value, basicAmmoComp.Count.Value + ev.Charge, basicAmmoComp);
|
||||
_gunSystem.UpdateBasicEntityAmmoCount((wand.Value, basicAmmoComp), basicAmmoComp.Count.Value + ev.Charge);
|
||||
else if (TryComp<LimitedChargesComponent>(wand, out var charges))
|
||||
_charges.AddCharges((wand.Value, charges), ev.Charge);
|
||||
}
|
||||
|
||||
@@ -13,27 +13,27 @@ public sealed partial class ChamberMagazineAmmoProviderComponent : MagazineAmmoP
|
||||
/// <summary>
|
||||
/// If the gun has a bolt and whether that bolt is closed. Firing is impossible
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("boltClosed"), AutoNetworkedField]
|
||||
[DataField, AutoNetworkedField]
|
||||
public bool? BoltClosed = false;
|
||||
|
||||
/// <summary>
|
||||
/// Does the gun automatically open and close the bolt upon shooting.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("autoCycle"), AutoNetworkedField]
|
||||
[DataField, AutoNetworkedField]
|
||||
public bool AutoCycle = true;
|
||||
|
||||
/// <summary>
|
||||
/// Can the gun be racked, which opens and then instantly closes the bolt to cycle a round.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("canRack"), AutoNetworkedField]
|
||||
[DataField, AutoNetworkedField]
|
||||
public bool CanRack = true;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("soundBoltClosed"), AutoNetworkedField]
|
||||
[DataField("soundBoltClosed"), AutoNetworkedField]
|
||||
public SoundSpecifier? BoltClosedSound = new SoundPathSpecifier("/Audio/Weapons/Guns/Bolt/rifle_bolt_closed.ogg");
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("soundBoltOpened"), AutoNetworkedField]
|
||||
[DataField("soundBoltOpened"), AutoNetworkedField]
|
||||
public SoundSpecifier? BoltOpenedSound = new SoundPathSpecifier("/Audio/Weapons/Guns/Bolt/rifle_bolt_open.ogg");
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("soundRack"), AutoNetworkedField]
|
||||
[DataField("soundRack"), AutoNetworkedField]
|
||||
public SoundSpecifier? RackSound = new SoundPathSpecifier("/Audio/Weapons/Guns/Cock/ltrifle_cock.ogg");
|
||||
}
|
||||
|
||||
@@ -225,7 +225,7 @@ public sealed partial class GunComponent : Component
|
||||
/// When the gun is next available to be shot.
|
||||
/// Can be set multiple times in a single tick due to guns firing faster than a single tick time.
|
||||
/// </summary>
|
||||
[DataField(customTypeSerializer:typeof(TimeOffsetSerializer))]
|
||||
[DataField(customTypeSerializer: typeof(TimeOffsetSerializer))]
|
||||
[AutoNetworkedField]
|
||||
[AutoPausedField]
|
||||
public TimeSpan NextFire = TimeSpan.Zero;
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace Content.Shared.Weapons.Ranged.Components;
|
||||
/// This component modifies the spread of the gun it is attached to.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
||||
public sealed partial class GunSpreadModifierComponent: Component
|
||||
public sealed partial class GunSpreadModifierComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// A scalar value multiplied by the spread built into the ammo itself.
|
||||
|
||||
@@ -11,12 +11,12 @@ namespace Content.Shared.Weapons.Ranged;
|
||||
[Access(typeof(SharedGunSystem))]
|
||||
public partial class MagazineAmmoProviderComponent : AmmoProviderComponent
|
||||
{
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("soundAutoEject")]
|
||||
[DataField]
|
||||
public SoundSpecifier? SoundAutoEject = new SoundPathSpecifier("/Audio/Weapons/Guns/EmptyAlarm/smg_empty_alarm.ogg");
|
||||
|
||||
/// <summary>
|
||||
/// Should the magazine automatically eject when empty.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("autoEject")]
|
||||
[DataField]
|
||||
public bool AutoEject = false;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ using Robust.Shared.Serialization;
|
||||
namespace Content.Shared.Weapons.Ranged.Events;
|
||||
|
||||
/// <summary>
|
||||
/// Raised on the client to request it would like to stop hooting.
|
||||
/// Raised on the client to request it would like to stop shooting.
|
||||
/// </summary>
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class RequestStopShootEvent : EntityEventArgs
|
||||
|
||||
@@ -28,14 +28,14 @@ public sealed class ActionGunSystem : EntitySystem
|
||||
|
||||
private void OnShutdown(Entity<ActionGunComponent> ent, ref ComponentShutdown args)
|
||||
{
|
||||
if (ent.Comp.Gun is {} gun)
|
||||
if (ent.Comp.Gun is { } gun)
|
||||
QueueDel(gun);
|
||||
}
|
||||
|
||||
private void OnShoot(Entity<ActionGunComponent> ent, ref ActionGunShootEvent args)
|
||||
{
|
||||
if (TryComp<GunComponent>(ent.Comp.Gun, out var gun))
|
||||
_gun.AttemptShoot(ent, ent.Comp.Gun.Value, gun, args.Target);
|
||||
_gun.AttemptShoot(ent, (ent.Comp.Gun.Value, gun), args.Target);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using Content.Shared.Access.Components;
|
||||
using Content.Shared.Access.Systems;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.Examine;
|
||||
@@ -6,18 +5,17 @@ using Content.Shared.Interaction.Events;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Verbs;
|
||||
using Content.Shared.Weapons.Ranged.Components;
|
||||
using Content.Shared.Weapons.Ranged.Events;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared.Weapons.Ranged.Systems;
|
||||
|
||||
public sealed class BatteryWeaponFireModesSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
|
||||
[Dependency] private readonly AccessReaderSystem _accessReaderSystem = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
[Dependency] private readonly SharedAppearanceSystem _appearanceSystem = default!;
|
||||
[Dependency] private readonly SharedGunSystem _gun = default!;
|
||||
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -28,12 +26,12 @@ public sealed class BatteryWeaponFireModesSystem : EntitySystem
|
||||
SubscribeLocalEvent<BatteryWeaponFireModesComponent, ExaminedEvent>(OnExamined);
|
||||
}
|
||||
|
||||
private void OnExamined(EntityUid uid, BatteryWeaponFireModesComponent component, ExaminedEvent args)
|
||||
private void OnExamined(Entity<BatteryWeaponFireModesComponent> ent, ref ExaminedEvent args)
|
||||
{
|
||||
if (component.FireModes.Count < 2)
|
||||
if (ent.Comp.FireModes.Count < 2)
|
||||
return;
|
||||
|
||||
var fireMode = GetMode(component);
|
||||
var fireMode = GetMode(ent.Comp);
|
||||
|
||||
if (!_prototypeManager.TryIndex<EntityPrototype>(fireMode.Prototype, out var proto))
|
||||
return;
|
||||
@@ -73,7 +71,7 @@ public sealed class BatteryWeaponFireModesSystem : EntitySystem
|
||||
DoContactInteraction = true,
|
||||
Act = () =>
|
||||
{
|
||||
TrySetFireMode(uid, component, index, args.User);
|
||||
TrySetFireMode((uid, component), index, args.User);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -81,60 +79,60 @@ public sealed class BatteryWeaponFireModesSystem : EntitySystem
|
||||
}
|
||||
}
|
||||
|
||||
private void OnUseInHandEvent(EntityUid uid, BatteryWeaponFireModesComponent component, UseInHandEvent args)
|
||||
private void OnUseInHandEvent(Entity<BatteryWeaponFireModesComponent> ent, ref UseInHandEvent args)
|
||||
{
|
||||
if(args.Handled)
|
||||
if (args.Handled)
|
||||
return;
|
||||
|
||||
args.Handled = true;
|
||||
TryCycleFireMode(uid, component, args.User);
|
||||
TryCycleFireMode(ent, args.User);
|
||||
}
|
||||
|
||||
public void TryCycleFireMode(EntityUid uid, BatteryWeaponFireModesComponent component, EntityUid? user = null)
|
||||
public void TryCycleFireMode(Entity<BatteryWeaponFireModesComponent> ent, EntityUid? user = null)
|
||||
{
|
||||
if (component.FireModes.Count < 2)
|
||||
if (ent.Comp.FireModes.Count < 2)
|
||||
return;
|
||||
|
||||
var index = (component.CurrentFireMode + 1) % component.FireModes.Count;
|
||||
TrySetFireMode(uid, component, index, user);
|
||||
var index = (ent.Comp.CurrentFireMode + 1) % ent.Comp.FireModes.Count;
|
||||
TrySetFireMode(ent, index, user);
|
||||
}
|
||||
|
||||
public bool TrySetFireMode(EntityUid uid, BatteryWeaponFireModesComponent component, int index, EntityUid? user = null)
|
||||
public bool TrySetFireMode(Entity<BatteryWeaponFireModesComponent> ent, int index, EntityUid? user = null)
|
||||
{
|
||||
if (index < 0 || index >= component.FireModes.Count)
|
||||
if (index < 0 || index >= ent.Comp.FireModes.Count)
|
||||
return false;
|
||||
|
||||
if (user != null && !_accessReaderSystem.IsAllowed(user.Value, uid))
|
||||
if (user != null && !_accessReaderSystem.IsAllowed(user.Value, ent))
|
||||
return false;
|
||||
|
||||
SetFireMode(uid, component, index, user);
|
||||
SetFireMode(ent, index, user);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void SetFireMode(EntityUid uid, BatteryWeaponFireModesComponent component, int index, EntityUid? user = null)
|
||||
private void SetFireMode(Entity<BatteryWeaponFireModesComponent> ent, int index, EntityUid? user = null)
|
||||
{
|
||||
var fireMode = component.FireModes[index];
|
||||
component.CurrentFireMode = index;
|
||||
Dirty(uid, component);
|
||||
var fireMode = ent.Comp.FireModes[index];
|
||||
ent.Comp.CurrentFireMode = index;
|
||||
Dirty(ent);
|
||||
|
||||
if (_prototypeManager.TryIndex<EntityPrototype>(fireMode.Prototype, out var prototype))
|
||||
{
|
||||
if (TryComp<AppearanceComponent>(uid, out var appearance))
|
||||
_appearanceSystem.SetData(uid, BatteryWeaponFireModeVisuals.State, prototype.ID, appearance);
|
||||
if (TryComp<AppearanceComponent>(ent, out var appearance))
|
||||
_appearanceSystem.SetData(ent, BatteryWeaponFireModeVisuals.State, prototype.ID, appearance);
|
||||
|
||||
if (user != null)
|
||||
_popupSystem.PopupClient(Loc.GetString("gun-set-fire-mode-popup", ("mode", prototype.Name)), uid, user.Value);
|
||||
_popupSystem.PopupClient(Loc.GetString("gun-set-fire-mode-popup", ("mode", prototype.Name)), ent, user.Value);
|
||||
}
|
||||
|
||||
if (TryComp(uid, out BatteryAmmoProviderComponent? batteryAmmoProviderComponent))
|
||||
if (TryComp(ent, out BatteryAmmoProviderComponent? batteryAmmoProviderComponent))
|
||||
{
|
||||
batteryAmmoProviderComponent.Prototype = fireMode.Prototype;
|
||||
batteryAmmoProviderComponent.FireCost = fireMode.FireCost;
|
||||
|
||||
Dirty(uid, batteryAmmoProviderComponent);
|
||||
Dirty(ent, batteryAmmoProviderComponent);
|
||||
|
||||
_gun.UpdateShots((uid, batteryAmmoProviderComponent));
|
||||
_gun.UpdateShots((ent, batteryAmmoProviderComponent));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,8 +4,7 @@ using Content.Shared.Weapons.Ranged.Events;
|
||||
|
||||
namespace Content.Shared.Weapons.Ranged.Systems;
|
||||
|
||||
|
||||
public sealed class GunSpreadModifierSystem: EntitySystem
|
||||
public sealed class GunSpreadModifierSystem : EntitySystem
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -14,14 +13,14 @@ public sealed class GunSpreadModifierSystem: EntitySystem
|
||||
SubscribeLocalEvent<GunSpreadModifierComponent, ExaminedEvent>(OnExamine);
|
||||
}
|
||||
|
||||
private void OnGunGetAmmoSpread(EntityUid uid, GunSpreadModifierComponent comp, ref GunGetAmmoSpreadEvent args)
|
||||
private void OnGunGetAmmoSpread(Entity<GunSpreadModifierComponent> ent, ref GunGetAmmoSpreadEvent args)
|
||||
{
|
||||
args.Spread *= comp.Spread;
|
||||
args.Spread *= ent.Comp.Spread;
|
||||
}
|
||||
|
||||
private void OnExamine(EntityUid uid, GunSpreadModifierComponent comp, ExaminedEvent args)
|
||||
private void OnExamine(Entity<GunSpreadModifierComponent> ent, ref ExaminedEvent args)
|
||||
{
|
||||
var percentage = Math.Round(comp.Spread * 100);
|
||||
var percentage = Math.Round(ent.Comp.Spread * 100);
|
||||
var loc = percentage < 100 ? "examine-gun-spread-modifier-reduction" : "examine-gun-spread-modifier-increase";
|
||||
percentage = percentage < 100 ? 100 - percentage : percentage - 100;
|
||||
var msg = Loc.GetString(loc, ("percentage", percentage));
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.Weapons.Ranged.Components;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Shared.Weapons.Ranged.Systems;
|
||||
|
||||
@@ -13,9 +10,9 @@ public sealed class RechargeBasicEntityAmmoSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
[Dependency] private readonly INetManager _netManager = default!;
|
||||
[Dependency] private readonly MetaDataSystem _metadata = default!;
|
||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||
[Dependency] private readonly SharedGunSystem _gun = default!;
|
||||
[Dependency] private readonly MetaDataSystem _metadata = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -38,7 +35,7 @@ public sealed class RechargeBasicEntityAmmoSystem : EntitySystem
|
||||
if (recharge.NextCharge > _timing.CurTime)
|
||||
continue;
|
||||
|
||||
if (_gun.UpdateBasicEntityAmmoCount(uid, ammo.Count.Value + 1, ammo))
|
||||
if (_gun.UpdateBasicEntityAmmoCount((uid, ammo), ammo.Count.Value + 1))
|
||||
{
|
||||
// We don't predict this because occasionally on client it may not play.
|
||||
// PlayPredicted will still be predicted on the client.
|
||||
@@ -58,38 +55,38 @@ public sealed class RechargeBasicEntityAmmoSystem : EntitySystem
|
||||
}
|
||||
}
|
||||
|
||||
private void OnInit(EntityUid uid, RechargeBasicEntityAmmoComponent component, MapInitEvent args)
|
||||
private void OnInit(Entity<RechargeBasicEntityAmmoComponent> ent, ref MapInitEvent args)
|
||||
{
|
||||
component.NextCharge = _timing.CurTime;
|
||||
Dirty(uid, component);
|
||||
ent.Comp.NextCharge = _timing.CurTime;
|
||||
Dirty(ent);
|
||||
}
|
||||
|
||||
private void OnExamined(EntityUid uid, RechargeBasicEntityAmmoComponent component, ExaminedEvent args)
|
||||
private void OnExamined(Entity<RechargeBasicEntityAmmoComponent> ent, ref ExaminedEvent args)
|
||||
{
|
||||
if (!component.ShowExamineText)
|
||||
if (!ent.Comp.ShowExamineText)
|
||||
return;
|
||||
|
||||
if (!TryComp<BasicEntityAmmoProviderComponent>(uid, out var ammo)
|
||||
if (!TryComp<BasicEntityAmmoProviderComponent>(ent, out var ammo)
|
||||
|| ammo.Count == ammo.Capacity ||
|
||||
component.NextCharge == null)
|
||||
ent.Comp.NextCharge == null)
|
||||
{
|
||||
args.PushMarkup(Loc.GetString("recharge-basic-entity-ammo-full"));
|
||||
return;
|
||||
}
|
||||
|
||||
var timeLeft = component.NextCharge + _metadata.GetPauseTime(uid) - _timing.CurTime;
|
||||
var timeLeft = ent.Comp.NextCharge + _metadata.GetPauseTime(ent) - _timing.CurTime;
|
||||
args.PushMarkup(Loc.GetString("recharge-basic-entity-ammo-can-recharge", ("seconds", Math.Round(timeLeft.Value.TotalSeconds, 1))));
|
||||
}
|
||||
|
||||
public void Reset(EntityUid uid, RechargeBasicEntityAmmoComponent? recharge = null)
|
||||
public void Reset(Entity<RechargeBasicEntityAmmoComponent?> ent)
|
||||
{
|
||||
if (!Resolve(uid, ref recharge, false))
|
||||
if (!Resolve(ent, ref ent.Comp, false))
|
||||
return;
|
||||
|
||||
if (recharge.NextCharge == null || recharge.NextCharge < _timing.CurTime)
|
||||
if (ent.Comp.NextCharge == null || ent.Comp.NextCharge < _timing.CurTime)
|
||||
{
|
||||
recharge.NextCharge = _timing.CurTime + TimeSpan.FromSeconds(recharge.RechargeCooldown);
|
||||
Dirty(uid, recharge);
|
||||
ent.Comp.NextCharge = _timing.CurTime + TimeSpan.FromSeconds(ent.Comp.RechargeCooldown);
|
||||
Dirty(ent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,19 +16,19 @@ public sealed class RechargeCycleAmmoSystem : EntitySystem
|
||||
SubscribeLocalEvent<RechargeCycleAmmoComponent, ActivateInWorldEvent>(OnRechargeCycled);
|
||||
}
|
||||
|
||||
private void OnRechargeCycled(EntityUid uid, RechargeCycleAmmoComponent component, ActivateInWorldEvent args)
|
||||
private void OnRechargeCycled(Entity<RechargeCycleAmmoComponent> ent, ref ActivateInWorldEvent args)
|
||||
{
|
||||
if (!args.Complex)
|
||||
return;
|
||||
|
||||
if (!TryComp<BasicEntityAmmoProviderComponent>(uid, out var basic) || args.Handled)
|
||||
if (!TryComp<BasicEntityAmmoProviderComponent>(ent, out var basic) || args.Handled)
|
||||
return;
|
||||
|
||||
if (basic.Count >= basic.Capacity || basic.Count == null)
|
||||
return;
|
||||
|
||||
_gun.UpdateBasicEntityAmmoCount(uid, basic.Count.Value + 1, basic);
|
||||
Dirty(uid, basic);
|
||||
_gun.UpdateBasicEntityAmmoCount((ent, basic), basic.Count.Value + 1);
|
||||
Dirty(ent, basic);
|
||||
args.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,24 +24,24 @@ public abstract class SharedFlyBySoundSystem : EntitySystem
|
||||
SubscribeLocalEvent<FlyBySoundComponent, ComponentShutdown>(OnShutdown);
|
||||
}
|
||||
|
||||
private void OnStartup(EntityUid uid, FlyBySoundComponent component, ComponentStartup args)
|
||||
private void OnStartup(Entity<FlyBySoundComponent> ent, ref ComponentStartup args)
|
||||
{
|
||||
if (!TryComp<PhysicsComponent>(uid, out var body))
|
||||
if (!TryComp<PhysicsComponent>(ent, out var body))
|
||||
return;
|
||||
|
||||
var shape = new PhysShapeCircle(component.Range);
|
||||
var shape = new PhysShapeCircle(ent.Comp.Range);
|
||||
|
||||
_fixtures.TryCreateFixture(uid, shape, FlyByFixture, collisionLayer: (int) CollisionGroup.MobMask, hard: false, body: body);
|
||||
_fixtures.TryCreateFixture(ent, shape, FlyByFixture, collisionLayer: (int)CollisionGroup.MobMask, hard: false, body: body);
|
||||
}
|
||||
|
||||
private void OnShutdown(EntityUid uid, FlyBySoundComponent component, ComponentShutdown args)
|
||||
private void OnShutdown(Entity<FlyBySoundComponent> ent, ref ComponentShutdown args)
|
||||
{
|
||||
if (!TryComp<PhysicsComponent>(uid, out var body) ||
|
||||
MetaData(uid).EntityLifeStage >= EntityLifeStage.Terminating)
|
||||
if (!TryComp<PhysicsComponent>(ent, out var body) ||
|
||||
MetaData(ent).EntityLifeStage >= EntityLifeStage.Terminating)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_fixtures.DestroyFixture(uid, FlyByFixture, body: body);
|
||||
_fixtures.DestroyFixture(ent, FlyByFixture, body: body);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,8 +4,8 @@ namespace Content.Shared.Weapons.Ranged.Systems;
|
||||
|
||||
public partial class SharedGunSystem
|
||||
{
|
||||
public void SetEnabled(EntityUid uid, AutoShootGunComponent component, bool status)
|
||||
public void SetEnabled(Entity<AutoShootGunComponent> ent, bool status)
|
||||
{
|
||||
component.Enabled = status;
|
||||
ent.Comp.Enabled = status;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,26 +36,26 @@ public abstract partial class SharedGunSystem
|
||||
SubscribeLocalEvent<BallisticAmmoSelfRefillerComponent, EmpPulseEvent>(OnRefillerEmpPulsed);
|
||||
}
|
||||
|
||||
private void OnBallisticRefillerMapInit(Entity<BallisticAmmoSelfRefillerComponent> entity, ref MapInitEvent args)
|
||||
private void OnBallisticRefillerMapInit(Entity<BallisticAmmoSelfRefillerComponent> entity, ref MapInitEvent _)
|
||||
{
|
||||
entity.Comp.NextAutoRefill = Timing.CurTime + entity.Comp.AutoRefillRate;
|
||||
}
|
||||
|
||||
private void OnBallisticUse(EntityUid uid, BallisticAmmoProviderComponent component, UseInHandEvent args)
|
||||
private void OnBallisticUse(Entity<BallisticAmmoProviderComponent> ent, ref UseInHandEvent args)
|
||||
{
|
||||
if (args.Handled)
|
||||
return;
|
||||
|
||||
ManualCycle(uid, component, TransformSystem.GetMapCoordinates(uid), args.User);
|
||||
ManualCycle(ent, TransformSystem.GetMapCoordinates(ent), args.User);
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private void OnBallisticInteractUsing(EntityUid uid, BallisticAmmoProviderComponent component, InteractUsingEvent args)
|
||||
private void OnBallisticInteractUsing(Entity<BallisticAmmoProviderComponent> ent, ref InteractUsingEvent args)
|
||||
{
|
||||
if (args.Handled)
|
||||
return;
|
||||
|
||||
if (TryBallisticInsert((uid, component), args.Used, args.User))
|
||||
if (TryBallisticInsert(ent, args.Used, args.User))
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
@@ -168,65 +168,65 @@ public abstract partial class SharedGunSystem
|
||||
{
|
||||
Text = Loc.GetString("gun-ballistic-cycle"),
|
||||
Disabled = GetBallisticShots(component) == 0,
|
||||
Act = () => ManualCycle(uid, component, TransformSystem.GetMapCoordinates(uid), args.User),
|
||||
Act = () => ManualCycle((uid, component), TransformSystem.GetMapCoordinates(uid), args.User),
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void OnBallisticExamine(EntityUid uid, BallisticAmmoProviderComponent component, ExaminedEvent args)
|
||||
private void OnBallisticExamine(Entity<BallisticAmmoProviderComponent> ent, ref ExaminedEvent args)
|
||||
{
|
||||
if (!args.IsInDetailsRange)
|
||||
return;
|
||||
|
||||
args.PushMarkup(Loc.GetString("gun-magazine-examine", ("color", AmmoExamineColor), ("count", GetBallisticShots(component))));
|
||||
args.PushMarkup(Loc.GetString("gun-magazine-examine", ("color", AmmoExamineColor), ("count", GetBallisticShots(ent.Comp))));
|
||||
}
|
||||
|
||||
private void ManualCycle(EntityUid uid, BallisticAmmoProviderComponent component, MapCoordinates coordinates, EntityUid? user = null, GunComponent? gunComp = null)
|
||||
private void ManualCycle(Entity<BallisticAmmoProviderComponent> ent, MapCoordinates coordinates, EntityUid? user = null, GunComponent? gunComp = null)
|
||||
{
|
||||
if (!component.Cycleable)
|
||||
if (!ent.Comp.Cycleable)
|
||||
return;
|
||||
|
||||
// Reset shotting for cycling
|
||||
if (Resolve(uid, ref gunComp, false) &&
|
||||
if (Resolve(ent, ref gunComp, false) &&
|
||||
gunComp is { FireRateModified: > 0f } &&
|
||||
!Paused(uid))
|
||||
!Paused(ent))
|
||||
{
|
||||
gunComp.NextFire = Timing.CurTime + TimeSpan.FromSeconds(1 / gunComp.FireRateModified);
|
||||
DirtyField(uid, gunComp, nameof(GunComponent.NextFire));
|
||||
DirtyField(ent, gunComp, nameof(GunComponent.NextFire));
|
||||
}
|
||||
|
||||
Audio.PlayPredicted(component.SoundRack, uid, user);
|
||||
Audio.PlayPredicted(ent.Comp.SoundRack, ent, user);
|
||||
|
||||
var shots = GetBallisticShots(component);
|
||||
Cycle(uid, component, coordinates);
|
||||
var shots = GetBallisticShots(ent.Comp);
|
||||
Cycle(ent, coordinates);
|
||||
|
||||
var text = Loc.GetString(shots == 0 ? "gun-ballistic-cycled-empty" : "gun-ballistic-cycled");
|
||||
|
||||
Popup(text, uid, user);
|
||||
UpdateBallisticAppearance(uid, component);
|
||||
UpdateAmmoCount(uid);
|
||||
Popup(text, ent, user);
|
||||
UpdateBallisticAppearance(ent);
|
||||
UpdateAmmoCount(ent);
|
||||
}
|
||||
|
||||
protected abstract void Cycle(EntityUid uid, BallisticAmmoProviderComponent component, MapCoordinates coordinates);
|
||||
protected abstract void Cycle(Entity<BallisticAmmoProviderComponent> ent, MapCoordinates coordinates);
|
||||
|
||||
private void OnBallisticInit(EntityUid uid, BallisticAmmoProviderComponent component, ComponentInit args)
|
||||
private void OnBallisticInit(Entity<BallisticAmmoProviderComponent> ent, ref ComponentInit args)
|
||||
{
|
||||
component.Container = Containers.EnsureContainer<Container>(uid, "ballistic-ammo");
|
||||
ent.Comp.Container = Containers.EnsureContainer<Container>(ent, "ballistic-ammo");
|
||||
// TODO: This is called twice though we need to support loading appearance data (and we need to call it on MapInit
|
||||
// to ensure it's correct).
|
||||
UpdateBallisticAppearance(uid, component);
|
||||
UpdateBallisticAppearance(ent);
|
||||
}
|
||||
|
||||
private void OnBallisticMapInit(EntityUid uid, BallisticAmmoProviderComponent component, MapInitEvent args)
|
||||
private void OnBallisticMapInit(Entity<BallisticAmmoProviderComponent> ent, ref MapInitEvent args)
|
||||
{
|
||||
// TODO this should be part of the prototype, not set on map init.
|
||||
// Alternatively, just track spawned count, instead of unspawned count.
|
||||
if (component.Proto != null)
|
||||
if (ent.Comp.Proto != null)
|
||||
{
|
||||
component.UnspawnedCount = Math.Max(0, component.Capacity - component.Container.ContainedEntities.Count);
|
||||
UpdateBallisticAppearance(uid, component);
|
||||
DirtyField(uid, component, nameof(BallisticAmmoProviderComponent.UnspawnedCount));
|
||||
ent.Comp.UnspawnedCount = Math.Max(0, ent.Comp.Capacity - ent.Comp.Container.ContainedEntities.Count);
|
||||
UpdateBallisticAppearance(ent);
|
||||
DirtyField(ent.AsNullable(), nameof(BallisticAmmoProviderComponent.UnspawnedCount));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -235,43 +235,43 @@ public abstract partial class SharedGunSystem
|
||||
return component.Entities.Count + component.UnspawnedCount;
|
||||
}
|
||||
|
||||
private void OnBallisticTakeAmmo(EntityUid uid, BallisticAmmoProviderComponent component, TakeAmmoEvent args)
|
||||
private void OnBallisticTakeAmmo(Entity<BallisticAmmoProviderComponent> ent, ref TakeAmmoEvent args)
|
||||
{
|
||||
for (var i = 0; i < args.Shots; i++)
|
||||
{
|
||||
EntityUid? ammoEntity = null;
|
||||
if (component.Entities.Count > 0)
|
||||
if (ent.Comp.Entities.Count > 0)
|
||||
{
|
||||
var existingEnt = component.Entities[^1];
|
||||
component.Entities.RemoveAt(component.Entities.Count - 1);
|
||||
DirtyField(uid, component, nameof(BallisticAmmoProviderComponent.Entities));
|
||||
Containers.Remove(existingEnt, component.Container);
|
||||
var existingEnt = ent.Comp.Entities[^1];
|
||||
ent.Comp.Entities.RemoveAt(ent.Comp.Entities.Count - 1);
|
||||
DirtyField(ent.AsNullable(), nameof(BallisticAmmoProviderComponent.Entities));
|
||||
Containers.Remove(existingEnt, ent.Comp.Container);
|
||||
ammoEntity = existingEnt;
|
||||
}
|
||||
else if (component.UnspawnedCount > 0)
|
||||
else if (ent.Comp.UnspawnedCount > 0)
|
||||
{
|
||||
component.UnspawnedCount--;
|
||||
DirtyField(uid, component, nameof(BallisticAmmoProviderComponent.UnspawnedCount));
|
||||
ammoEntity = Spawn(component.Proto, args.Coordinates);
|
||||
ent.Comp.UnspawnedCount--;
|
||||
DirtyField(ent.AsNullable(), nameof(BallisticAmmoProviderComponent.UnspawnedCount));
|
||||
ammoEntity = Spawn(ent.Comp.Proto, args.Coordinates);
|
||||
}
|
||||
|
||||
if (ammoEntity is { } ent)
|
||||
if (ammoEntity is not { } ammoEnt)
|
||||
continue;
|
||||
|
||||
args.Ammo.Add((ammoEnt, EnsureShootable(ammoEnt)));
|
||||
if (TryComp<BallisticAmmoSelfRefillerComponent>(ent, out var refiller))
|
||||
{
|
||||
args.Ammo.Add((ent, EnsureShootable(ent)));
|
||||
if (TryComp<BallisticAmmoSelfRefillerComponent>(uid, out var refiller))
|
||||
{
|
||||
PauseSelfRefill((uid, refiller));
|
||||
}
|
||||
PauseSelfRefill((ent, refiller));
|
||||
}
|
||||
}
|
||||
|
||||
UpdateBallisticAppearance(uid, component);
|
||||
UpdateBallisticAppearance(ent);
|
||||
}
|
||||
|
||||
private void OnBallisticAmmoCount(EntityUid uid, BallisticAmmoProviderComponent component, ref GetAmmoCountEvent args)
|
||||
private void OnBallisticAmmoCount(Entity<BallisticAmmoProviderComponent> ent, ref GetAmmoCountEvent args)
|
||||
{
|
||||
args.Count = GetBallisticShots(component);
|
||||
args.Capacity = component.Capacity;
|
||||
args.Count = GetBallisticShots(ent.Comp);
|
||||
args.Capacity = ent.Comp.Capacity;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -334,20 +334,20 @@ public abstract partial class SharedGunSystem
|
||||
Audio.PlayPredicted(entity.Comp.SoundInsert, entity, user);
|
||||
}
|
||||
|
||||
UpdateBallisticAppearance(entity, entity.Comp);
|
||||
UpdateBallisticAppearance(entity);
|
||||
UpdateAmmoCount(entity);
|
||||
DirtyField(entity.AsNullable(), nameof(BallisticAmmoProviderComponent.Entities));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void UpdateBallisticAppearance(EntityUid uid, BallisticAmmoProviderComponent component)
|
||||
public void UpdateBallisticAppearance(Entity<BallisticAmmoProviderComponent> ent)
|
||||
{
|
||||
if (!Timing.IsFirstTimePredicted || !TryComp<AppearanceComponent>(uid, out var appearance))
|
||||
if (!Timing.IsFirstTimePredicted || !TryComp<AppearanceComponent>(ent, out var appearance))
|
||||
return;
|
||||
|
||||
Appearance.SetData(uid, AmmoVisuals.AmmoCount, GetBallisticShots(component), appearance);
|
||||
Appearance.SetData(uid, AmmoVisuals.AmmoMax, component.Capacity, appearance);
|
||||
Appearance.SetData(ent, AmmoVisuals.AmmoCount, GetBallisticShots(ent.Comp), appearance);
|
||||
Appearance.SetData(ent, AmmoVisuals.AmmoMax, ent.Comp.Capacity, appearance);
|
||||
}
|
||||
|
||||
public void SetBallisticUnspawned(Entity<BallisticAmmoProviderComponent> entity, int count)
|
||||
@@ -356,7 +356,7 @@ public abstract partial class SharedGunSystem
|
||||
return;
|
||||
|
||||
entity.Comp.UnspawnedCount = count;
|
||||
UpdateBallisticAppearance(entity.Owner, entity.Comp);
|
||||
UpdateBallisticAppearance(entity);
|
||||
UpdateAmmoCount(entity.Owner);
|
||||
Dirty(entity);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using Content.Shared.Weapons.Ranged.Components;
|
||||
using Content.Shared.Weapons.Ranged.Events;
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared.Weapons.Ranged.Systems;
|
||||
|
||||
@@ -13,75 +12,70 @@ public abstract partial class SharedGunSystem
|
||||
SubscribeLocalEvent<BasicEntityAmmoProviderComponent, GetAmmoCountEvent>(OnBasicEntityAmmoCount);
|
||||
}
|
||||
|
||||
private void OnBasicEntityMapInit(EntityUid uid, BasicEntityAmmoProviderComponent component, MapInitEvent args)
|
||||
private void OnBasicEntityMapInit(Entity<BasicEntityAmmoProviderComponent> ent, ref MapInitEvent args)
|
||||
{
|
||||
if (component.Count is null)
|
||||
if (ent.Comp.Count is null)
|
||||
{
|
||||
component.Count = component.Capacity;
|
||||
Dirty(uid, component);
|
||||
ent.Comp.Count = ent.Comp.Capacity;
|
||||
Dirty(ent);
|
||||
}
|
||||
|
||||
UpdateBasicEntityAppearance(uid, component);
|
||||
UpdateBasicEntityAppearance(ent);
|
||||
}
|
||||
|
||||
private void OnBasicEntityTakeAmmo(EntityUid uid, BasicEntityAmmoProviderComponent component, TakeAmmoEvent args)
|
||||
private void OnBasicEntityTakeAmmo(Entity<BasicEntityAmmoProviderComponent> ent, ref TakeAmmoEvent args)
|
||||
{
|
||||
for (var i = 0; i < args.Shots; i++)
|
||||
{
|
||||
if (component.Count <= 0)
|
||||
if (ent.Comp.Count <= 0)
|
||||
return;
|
||||
|
||||
if (component.Count != null)
|
||||
{
|
||||
component.Count--;
|
||||
}
|
||||
if (ent.Comp.Count != null)
|
||||
ent.Comp.Count--;
|
||||
|
||||
var ent = Spawn(component.Proto, args.Coordinates);
|
||||
args.Ammo.Add((ent, EnsureShootable(ent)));
|
||||
var ammoEnt = Spawn(ent.Comp.Proto, args.Coordinates);
|
||||
args.Ammo.Add((ammoEnt, EnsureShootable(ammoEnt)));
|
||||
}
|
||||
|
||||
_recharge.Reset(uid);
|
||||
UpdateBasicEntityAppearance(uid, component);
|
||||
Dirty(uid, component);
|
||||
_recharge.Reset(ent.Owner);
|
||||
UpdateBasicEntityAppearance(ent);
|
||||
Dirty(ent);
|
||||
}
|
||||
|
||||
private void OnBasicEntityAmmoCount(EntityUid uid, BasicEntityAmmoProviderComponent component, ref GetAmmoCountEvent args)
|
||||
private void OnBasicEntityAmmoCount(Entity<BasicEntityAmmoProviderComponent> ent, ref GetAmmoCountEvent args)
|
||||
{
|
||||
args.Capacity = component.Capacity ?? int.MaxValue;
|
||||
args.Count = component.Count ?? int.MaxValue;
|
||||
args.Capacity = ent.Comp.Capacity ?? int.MaxValue;
|
||||
args.Count = ent.Comp.Count ?? int.MaxValue;
|
||||
}
|
||||
|
||||
private void UpdateBasicEntityAppearance(EntityUid uid, BasicEntityAmmoProviderComponent component)
|
||||
private void UpdateBasicEntityAppearance(Entity<BasicEntityAmmoProviderComponent> ent)
|
||||
{
|
||||
if (!Timing.IsFirstTimePredicted || !TryComp<AppearanceComponent>(uid, out var appearance))
|
||||
if (!Timing.IsFirstTimePredicted || !TryComp<AppearanceComponent>(ent, out var appearance))
|
||||
return;
|
||||
|
||||
Appearance.SetData(uid, AmmoVisuals.HasAmmo, component.Count != 0, appearance);
|
||||
Appearance.SetData(uid, AmmoVisuals.AmmoCount, component.Count ?? int.MaxValue, appearance);
|
||||
Appearance.SetData(uid, AmmoVisuals.AmmoMax, component.Capacity ?? int.MaxValue, appearance);
|
||||
Appearance.SetData(ent, AmmoVisuals.HasAmmo, ent.Comp.Count != 0, appearance);
|
||||
Appearance.SetData(ent, AmmoVisuals.AmmoCount, ent.Comp.Count ?? int.MaxValue, appearance);
|
||||
Appearance.SetData(ent, AmmoVisuals.AmmoMax, ent.Comp.Capacity ?? int.MaxValue, appearance);
|
||||
}
|
||||
|
||||
#region Public API
|
||||
public bool ChangeBasicEntityAmmoCount(EntityUid uid, int delta, BasicEntityAmmoProviderComponent? component = null)
|
||||
public bool ChangeBasicEntityAmmoCount(Entity<BasicEntityAmmoProviderComponent?> ent, int delta)
|
||||
{
|
||||
if (!Resolve(uid, ref component, false) || component.Count == null)
|
||||
if (!Resolve(ent, ref ent.Comp, false) || ent.Comp.Count == null)
|
||||
return false;
|
||||
|
||||
return UpdateBasicEntityAmmoCount(uid, component.Count.Value + delta, component);
|
||||
return UpdateBasicEntityAmmoCount((ent.Owner, ent.Comp), ent.Comp.Count.Value + delta);
|
||||
}
|
||||
|
||||
public bool UpdateBasicEntityAmmoCount(EntityUid uid, int count, BasicEntityAmmoProviderComponent? component = null)
|
||||
public bool UpdateBasicEntityAmmoCount(Entity<BasicEntityAmmoProviderComponent?> ent, int count)
|
||||
{
|
||||
if (!Resolve(uid, ref component, false))
|
||||
if (!Resolve(ent, ref ent.Comp, false) || count > ent.Comp.Capacity)
|
||||
return false;
|
||||
|
||||
if (count > component.Capacity)
|
||||
return false;
|
||||
|
||||
component.Count = count;
|
||||
UpdateBasicEntityAppearance(uid, component);
|
||||
UpdateAmmoCount(uid);
|
||||
Dirty(uid, component);
|
||||
ent.Comp.Count = count;
|
||||
UpdateBasicEntityAppearance((ent.Owner, ent.Comp));
|
||||
UpdateAmmoCount(ent);
|
||||
Dirty(ent);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -26,9 +26,9 @@ public abstract partial class SharedGunSystem
|
||||
: Loc.GetString("gun-cartridge-unspent"));
|
||||
}
|
||||
|
||||
private void OnCartridgeDamageExamine(EntityUid uid, CartridgeAmmoComponent component, ref DamageExamineEvent args)
|
||||
private void OnCartridgeDamageExamine(Entity<CartridgeAmmoComponent> ent, ref DamageExamineEvent args)
|
||||
{
|
||||
var damageSpec = GetProjectileDamage(component.Prototype);
|
||||
var damageSpec = GetProjectileDamage(ent.Comp.Prototype);
|
||||
|
||||
if (damageSpec == null)
|
||||
return;
|
||||
|
||||
@@ -12,8 +12,6 @@ namespace Content.Shared.Weapons.Ranged.Systems;
|
||||
|
||||
public abstract partial class SharedGunSystem
|
||||
{
|
||||
protected const string ChamberSlot = "gun_chamber";
|
||||
|
||||
protected virtual void InitializeChamberMagazine()
|
||||
{
|
||||
SubscribeLocalEvent<ChamberMagazineAmmoProviderComponent, ComponentStartup>(OnChamberStartup);
|
||||
@@ -42,7 +40,7 @@ public abstract partial class SharedGunSystem
|
||||
// Appearance data doesn't get serialized and want to make sure this is correct on spawn (regardless of MapInit) so.
|
||||
if (component.BoltClosed != null)
|
||||
{
|
||||
Appearance.SetData(uid, AmmoVisuals.BoltClosed, component.BoltClosed.Value);
|
||||
Appearance.SetData(uid, AmmoVisuals.BoltClosed, component.BoltClosed.Value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ public partial class SharedGunSystem
|
||||
{
|
||||
var getConnectedContainerEvent = new GetConnectedContainerEvent();
|
||||
RaiseLocalEvent(uid, ref getConnectedContainerEvent);
|
||||
if(!getConnectedContainerEvent.ContainerEntity.HasValue)
|
||||
if (!getConnectedContainerEvent.ContainerEntity.HasValue)
|
||||
return;
|
||||
|
||||
RaiseLocalEvent(getConnectedContainerEvent.ContainerEntity.Value, args);
|
||||
|
||||
@@ -14,10 +14,10 @@ public partial class SharedGunSystem
|
||||
SubscribeLocalEvent<ContainerAmmoProviderComponent, GetAmmoCountEvent>(OnContainerAmmoCount);
|
||||
}
|
||||
|
||||
private void OnContainerTakeAmmo(EntityUid uid, ContainerAmmoProviderComponent component, TakeAmmoEvent args)
|
||||
private void OnContainerTakeAmmo(Entity<ContainerAmmoProviderComponent> ent, ref TakeAmmoEvent args)
|
||||
{
|
||||
component.ProviderUid ??= uid;
|
||||
if (!Containers.TryGetContainer(component.ProviderUid.Value, component.Container, out var container))
|
||||
ent.Comp.ProviderUid ??= ent;
|
||||
if (!Containers.TryGetContainer(ent.Comp.ProviderUid.Value, ent.Comp.Container, out var container))
|
||||
return;
|
||||
|
||||
for (var i = 0; i < args.Shots; i++)
|
||||
@@ -25,19 +25,19 @@ public partial class SharedGunSystem
|
||||
if (!container.ContainedEntities.Any())
|
||||
break;
|
||||
|
||||
var ent = container.ContainedEntities[0];
|
||||
var ammoEnt = container.ContainedEntities[0];
|
||||
|
||||
if (_netManager.IsServer)
|
||||
Containers.Remove(ent, container);
|
||||
Containers.Remove(ammoEnt, container);
|
||||
|
||||
args.Ammo.Add((ent, EnsureShootable(ent)));
|
||||
args.Ammo.Add((ammoEnt, EnsureShootable(ammoEnt)));
|
||||
}
|
||||
}
|
||||
|
||||
private void OnContainerAmmoCount(EntityUid uid, ContainerAmmoProviderComponent component, ref GetAmmoCountEvent args)
|
||||
private void OnContainerAmmoCount(Entity<ContainerAmmoProviderComponent> ent, ref GetAmmoCountEvent args)
|
||||
{
|
||||
component.ProviderUid ??= uid;
|
||||
if (!Containers.TryGetContainer(component.ProviderUid.Value, component.Container, out var container))
|
||||
ent.Comp.ProviderUid ??= ent;
|
||||
if (!Containers.TryGetContainer(ent.Comp.ProviderUid.Value, ent.Comp.Container, out var container))
|
||||
{
|
||||
args.Capacity = 0;
|
||||
args.Count = 0;
|
||||
|
||||
@@ -66,7 +66,7 @@ public abstract partial class SharedGunSystem
|
||||
if (component.SelectedMode == fire)
|
||||
return;
|
||||
|
||||
DebugTools.Assert((component.AvailableModes & fire) != 0x0);
|
||||
DebugTools.Assert((component.AvailableModes & fire) != 0x0);
|
||||
component.SelectedMode = fire;
|
||||
|
||||
if (!Paused(uid))
|
||||
@@ -113,7 +113,7 @@ public abstract partial class SharedGunSystem
|
||||
private void OnGunSelected(EntityUid uid, GunComponent component, HandSelectedEvent args)
|
||||
{
|
||||
if (Timing.ApplyingState)
|
||||
return;
|
||||
return;
|
||||
|
||||
if (component.FireRateModified <= 0)
|
||||
return;
|
||||
|
||||
@@ -8,8 +8,6 @@ namespace Content.Shared.Weapons.Ranged.Systems;
|
||||
|
||||
public abstract partial class SharedGunSystem
|
||||
{
|
||||
protected const string MagazineSlot = "gun_magazine";
|
||||
|
||||
protected virtual void InitializeMagazine()
|
||||
{
|
||||
SubscribeLocalEvent<MagazineAmmoProviderComponent, MapInitEvent>(OnMagazineMapInit);
|
||||
|
||||
@@ -31,82 +31,82 @@ public partial class SharedGunSystem
|
||||
SubscribeLocalEvent<RevolverAmmoProviderComponent, UseInHandEvent>(OnRevolverUse);
|
||||
}
|
||||
|
||||
private void OnRevolverUse(EntityUid uid, RevolverAmmoProviderComponent component, UseInHandEvent args)
|
||||
private void OnRevolverUse(Entity<RevolverAmmoProviderComponent> ent, ref UseInHandEvent args)
|
||||
{
|
||||
if (args.Handled)
|
||||
return;
|
||||
|
||||
if (!_useDelay.TryResetDelay(uid))
|
||||
if (!_useDelay.TryResetDelay(ent))
|
||||
return;
|
||||
|
||||
args.Handled = true;
|
||||
|
||||
Cycle(component);
|
||||
UpdateAmmoCount(uid, prediction: false);
|
||||
Dirty(uid, component);
|
||||
Cycle(ent.Comp);
|
||||
UpdateAmmoCount(ent, prediction: false);
|
||||
Dirty(ent);
|
||||
}
|
||||
|
||||
private void OnRevolverGetAmmoCount(EntityUid uid, RevolverAmmoProviderComponent component, ref GetAmmoCountEvent args)
|
||||
private void OnRevolverGetAmmoCount(Entity<RevolverAmmoProviderComponent> ent, ref GetAmmoCountEvent args)
|
||||
{
|
||||
args.Count += GetRevolverCount(component);
|
||||
args.Capacity += component.Capacity;
|
||||
args.Count += GetRevolverCount(ent.Comp);
|
||||
args.Capacity += ent.Comp.Capacity;
|
||||
}
|
||||
|
||||
private void OnRevolverInteractUsing(EntityUid uid, RevolverAmmoProviderComponent component, InteractUsingEvent args)
|
||||
private void OnRevolverInteractUsing(Entity<RevolverAmmoProviderComponent> ent, ref InteractUsingEvent args)
|
||||
{
|
||||
if (args.Handled)
|
||||
return;
|
||||
|
||||
if (TryRevolverInsert(uid, component, args.Used, args.User))
|
||||
if (TryRevolverInsert(ent, args.Used, args.User))
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private void OnRevolverGetState(EntityUid uid, RevolverAmmoProviderComponent component, ref ComponentGetState args)
|
||||
private void OnRevolverGetState(Entity<RevolverAmmoProviderComponent> ent, ref ComponentGetState args)
|
||||
{
|
||||
args.State = new RevolverAmmoProviderComponentState
|
||||
{
|
||||
CurrentIndex = component.CurrentIndex,
|
||||
AmmoSlots = GetNetEntityList(component.AmmoSlots),
|
||||
Chambers = component.Chambers,
|
||||
CurrentIndex = ent.Comp.CurrentIndex,
|
||||
AmmoSlots = GetNetEntityList(ent.Comp.AmmoSlots),
|
||||
Chambers = ent.Comp.Chambers,
|
||||
};
|
||||
}
|
||||
|
||||
private void OnRevolverHandleState(EntityUid uid, RevolverAmmoProviderComponent component, ref ComponentHandleState args)
|
||||
private void OnRevolverHandleState(Entity<RevolverAmmoProviderComponent> ent, ref ComponentHandleState args)
|
||||
{
|
||||
if (args.Current is not RevolverAmmoProviderComponentState state)
|
||||
return;
|
||||
|
||||
var oldIndex = component.CurrentIndex;
|
||||
component.CurrentIndex = state.CurrentIndex;
|
||||
component.Chambers = new bool?[state.Chambers.Length];
|
||||
var oldIndex = ent.Comp.CurrentIndex;
|
||||
ent.Comp.CurrentIndex = state.CurrentIndex;
|
||||
ent.Comp.Chambers = new bool?[state.Chambers.Length];
|
||||
|
||||
// Need to copy across the state rather than the ref.
|
||||
for (var i = 0; i < component.AmmoSlots.Count; i++)
|
||||
for (var i = 0; i < ent.Comp.AmmoSlots.Count; i++)
|
||||
{
|
||||
component.AmmoSlots[i] = EnsureEntity<RevolverAmmoProviderComponent>(state.AmmoSlots[i], uid);
|
||||
component.Chambers[i] = state.Chambers[i];
|
||||
ent.Comp.AmmoSlots[i] = EnsureEntity<RevolverAmmoProviderComponent>(state.AmmoSlots[i], ent);
|
||||
ent.Comp.Chambers[i] = state.Chambers[i];
|
||||
}
|
||||
|
||||
// Handle spins
|
||||
if (oldIndex != state.CurrentIndex)
|
||||
{
|
||||
UpdateAmmoCount(uid, prediction: false);
|
||||
UpdateAmmoCount(ent, prediction: false);
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryRevolverInsert(EntityUid revolverUid, RevolverAmmoProviderComponent component, EntityUid uid, EntityUid? user)
|
||||
public bool TryRevolverInsert(Entity<RevolverAmmoProviderComponent> ent, EntityUid insertEnt, EntityUid? user)
|
||||
{
|
||||
if (_whitelistSystem.IsWhitelistFail(component.Whitelist, uid))
|
||||
if (_whitelistSystem.IsWhitelistFail(ent.Comp.Whitelist, insertEnt))
|
||||
return false;
|
||||
|
||||
// If it's a speedloader try to get ammo from it.
|
||||
if (HasComp<SpeedLoaderComponent>(uid))
|
||||
if (HasComp<SpeedLoaderComponent>(insertEnt))
|
||||
{
|
||||
var freeSlots = 0;
|
||||
|
||||
for (var i = 0; i < component.Capacity; i++)
|
||||
for (var i = 0; i < ent.Comp.Capacity; i++)
|
||||
{
|
||||
if (component.AmmoSlots[i] != null || component.Chambers[i] != null)
|
||||
if (ent.Comp.AmmoSlots[i] != null || ent.Comp.Chambers[i] != null)
|
||||
continue;
|
||||
|
||||
freeSlots++;
|
||||
@@ -114,94 +114,94 @@ public partial class SharedGunSystem
|
||||
|
||||
if (freeSlots == 0)
|
||||
{
|
||||
Popup(Loc.GetString("gun-revolver-full"), revolverUid, user);
|
||||
Popup(Loc.GetString("gun-revolver-full"), ent, user);
|
||||
return false;
|
||||
}
|
||||
|
||||
var xformQuery = GetEntityQuery<TransformComponent>();
|
||||
var xform = xformQuery.GetComponent(uid);
|
||||
var xform = xformQuery.GetComponent(insertEnt);
|
||||
var ammo = new List<(EntityUid? Entity, IShootable Shootable)>(freeSlots);
|
||||
var ev = new TakeAmmoEvent(freeSlots, ammo, xform.Coordinates, user);
|
||||
RaiseLocalEvent(uid, ev);
|
||||
RaiseLocalEvent(insertEnt, ev);
|
||||
|
||||
if (ev.Ammo.Count == 0)
|
||||
{
|
||||
Popup(Loc.GetString("gun-speedloader-empty"), revolverUid, user);
|
||||
Popup(Loc.GetString("gun-speedloader-empty"), ent, user);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (var i = 0; i < component.Capacity; i++)
|
||||
for (var i = 0; i < ent.Comp.Capacity; i++)
|
||||
{
|
||||
var index = (component.CurrentIndex + i) % component.Capacity;
|
||||
var index = (ent.Comp.CurrentIndex + i) % ent.Comp.Capacity;
|
||||
|
||||
if (component.AmmoSlots[index] != null ||
|
||||
component.Chambers[index] != null)
|
||||
if (ent.Comp.AmmoSlots[index] != null ||
|
||||
ent.Comp.Chambers[index] != null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var ent = ev.Ammo.Last().Entity;
|
||||
var ammoEnt = ev.Ammo.Last().Entity;
|
||||
ev.Ammo.RemoveAt(ev.Ammo.Count - 1);
|
||||
|
||||
if (ent == null)
|
||||
if (ammoEnt == null)
|
||||
{
|
||||
Log.Error($"Tried to load hitscan into a revolver which is unsupported");
|
||||
continue;
|
||||
}
|
||||
|
||||
component.AmmoSlots[index] = ent.Value;
|
||||
Containers.Insert(ent.Value, component.AmmoContainer);
|
||||
SetChamber(index, component, uid);
|
||||
ent.Comp.AmmoSlots[index] = ammoEnt.Value;
|
||||
Containers.Insert(ammoEnt.Value, ent.Comp.AmmoContainer);
|
||||
SetChamber(ent, insertEnt, index);
|
||||
|
||||
if (ev.Ammo.Count == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
DebugTools.Assert(ammo.Count == 0);
|
||||
UpdateRevolverAppearance(revolverUid, component);
|
||||
UpdateAmmoCount(revolverUid);
|
||||
Dirty(revolverUid, component);
|
||||
UpdateRevolverAppearance(ent);
|
||||
UpdateAmmoCount(ent);
|
||||
Dirty(ent);
|
||||
|
||||
Audio.PlayPredicted(component.SoundInsert, revolverUid, user);
|
||||
Popup(Loc.GetString("gun-revolver-insert"), revolverUid, user);
|
||||
Audio.PlayPredicted(ent.Comp.SoundInsert, ent, user);
|
||||
Popup(Loc.GetString("gun-revolver-insert"), ent, user);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Try to insert the entity directly.
|
||||
for (var i = 0; i < component.Capacity; i++)
|
||||
for (var i = 0; i < ent.Comp.Capacity; i++)
|
||||
{
|
||||
var index = (component.CurrentIndex + i) % component.Capacity;
|
||||
var index = (ent.Comp.CurrentIndex + i) % ent.Comp.Capacity;
|
||||
|
||||
if (component.AmmoSlots[index] != null ||
|
||||
component.Chambers[index] != null)
|
||||
if (ent.Comp.AmmoSlots[index] != null ||
|
||||
ent.Comp.Chambers[index] != null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
component.AmmoSlots[index] = uid;
|
||||
Containers.Insert(uid, component.AmmoContainer);
|
||||
SetChamber(index, component, uid);
|
||||
Audio.PlayPredicted(component.SoundInsert, revolverUid, user);
|
||||
Popup(Loc.GetString("gun-revolver-insert"), revolverUid, user);
|
||||
UpdateRevolverAppearance(revolverUid, component);
|
||||
UpdateAmmoCount(revolverUid);
|
||||
Dirty(revolverUid, component);
|
||||
ent.Comp.AmmoSlots[index] = insertEnt;
|
||||
Containers.Insert(insertEnt, ent.Comp.AmmoContainer);
|
||||
SetChamber(ent, insertEnt, index);
|
||||
Audio.PlayPredicted(ent.Comp.SoundInsert, ent, user);
|
||||
Popup(Loc.GetString("gun-revolver-insert"), ent, user);
|
||||
UpdateRevolverAppearance(ent);
|
||||
UpdateAmmoCount(ent);
|
||||
Dirty(ent);
|
||||
return true;
|
||||
}
|
||||
|
||||
Popup(Loc.GetString("gun-revolver-full"), revolverUid, user);
|
||||
Popup(Loc.GetString("gun-revolver-full"), ent, user);
|
||||
return false;
|
||||
}
|
||||
|
||||
private void SetChamber(int index, RevolverAmmoProviderComponent component, EntityUid uid)
|
||||
private void SetChamber(Entity<RevolverAmmoProviderComponent> ent, Entity<CartridgeAmmoComponent?> ammo, int index)
|
||||
{
|
||||
if (TryComp<CartridgeAmmoComponent>(uid, out var cartridge) && cartridge.Spent)
|
||||
if (!Resolve(ammo, ref ammo.Comp, false) || ammo.Comp.Spent)
|
||||
{
|
||||
component.Chambers[index] = false;
|
||||
ent.Comp.Chambers[index] = false;
|
||||
return;
|
||||
}
|
||||
|
||||
component.Chambers[index] = true;
|
||||
ent.Comp.Chambers[index] = true;
|
||||
}
|
||||
|
||||
private void OnRevolverVerbs(EntityUid uid, RevolverAmmoProviderComponent component, GetVerbsEvent<AlternativeVerb> args)
|
||||
@@ -213,7 +213,7 @@ public partial class SharedGunSystem
|
||||
{
|
||||
Text = Loc.GetString("gun-revolver-empty"),
|
||||
Disabled = !AnyRevolverCartridges(component),
|
||||
Act = () => EmptyRevolver(uid, component, args.User),
|
||||
Act = () => EmptyRevolver((uid, component), args.User),
|
||||
Priority = 1
|
||||
});
|
||||
|
||||
@@ -221,7 +221,7 @@ public partial class SharedGunSystem
|
||||
{
|
||||
Text = Loc.GetString("gun-revolver-spin"),
|
||||
// Category = VerbCategory.G,
|
||||
Act = () => SpinRevolver(uid, component, args.User)
|
||||
Act = () => SpinRevolver((uid, component), args.User)
|
||||
});
|
||||
}
|
||||
|
||||
@@ -281,15 +281,15 @@ public partial class SharedGunSystem
|
||||
return count;
|
||||
}
|
||||
|
||||
public void EmptyRevolver(EntityUid revolverUid, RevolverAmmoProviderComponent component, EntityUid? user = null)
|
||||
public void EmptyRevolver(Entity<RevolverAmmoProviderComponent> ent, EntityUid? user = null)
|
||||
{
|
||||
var mapCoordinates = TransformSystem.GetMapCoordinates(revolverUid);
|
||||
var mapCoordinates = TransformSystem.GetMapCoordinates(ent);
|
||||
var anyEmpty = false;
|
||||
|
||||
for (var i = 0; i < component.Capacity; i++)
|
||||
for (var i = 0; i < ent.Comp.Capacity; i++)
|
||||
{
|
||||
var chamber = component.Chambers[i];
|
||||
var slot = component.AmmoSlots[i];
|
||||
var chamber = ent.Comp.Chambers[i];
|
||||
var slot = ent.Comp.AmmoSlots[i];
|
||||
|
||||
if (slot == null)
|
||||
{
|
||||
@@ -299,22 +299,22 @@ public partial class SharedGunSystem
|
||||
// Too lazy to make a new method don't sue me.
|
||||
if (!_netManager.IsClient)
|
||||
{
|
||||
var uid = Spawn(component.FillPrototype, mapCoordinates);
|
||||
var uid = Spawn(ent.Comp.FillPrototype, mapCoordinates);
|
||||
|
||||
if (TryComp<CartridgeAmmoComponent>(uid, out var cartridge))
|
||||
SetCartridgeSpent(uid, cartridge, !(bool) chamber);
|
||||
SetCartridgeSpent(uid, cartridge, !(bool)chamber);
|
||||
|
||||
EjectCartridge(uid);
|
||||
}
|
||||
|
||||
component.Chambers[i] = null;
|
||||
ent.Comp.Chambers[i] = null;
|
||||
anyEmpty = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
component.AmmoSlots[i] = null;
|
||||
Containers.Remove(slot.Value, component.AmmoContainer);
|
||||
component.Chambers[i] = null;
|
||||
ent.Comp.AmmoSlots[i] = null;
|
||||
Containers.Remove(slot.Value, ent.Comp.AmmoContainer);
|
||||
ent.Comp.Chambers[i] = null;
|
||||
|
||||
if (!_netManager.IsClient)
|
||||
EjectCartridge(slot.Value);
|
||||
@@ -325,47 +325,47 @@ public partial class SharedGunSystem
|
||||
|
||||
if (anyEmpty)
|
||||
{
|
||||
Audio.PlayPredicted(component.SoundEject, revolverUid, user);
|
||||
UpdateAmmoCount(revolverUid, prediction: false);
|
||||
UpdateRevolverAppearance(revolverUid, component);
|
||||
Dirty(revolverUid, component);
|
||||
Audio.PlayPredicted(ent.Comp.SoundEject, ent, user);
|
||||
UpdateAmmoCount(ent, prediction: false);
|
||||
UpdateRevolverAppearance(ent);
|
||||
Dirty(ent);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateRevolverAppearance(EntityUid uid, RevolverAmmoProviderComponent component)
|
||||
private void UpdateRevolverAppearance(Entity<RevolverAmmoProviderComponent> ent)
|
||||
{
|
||||
if (!TryComp<AppearanceComponent>(uid, out var appearance))
|
||||
if (!TryComp<AppearanceComponent>(ent, out var appearance))
|
||||
return;
|
||||
|
||||
var count = GetRevolverCount(component);
|
||||
Appearance.SetData(uid, AmmoVisuals.HasAmmo, count != 0, appearance);
|
||||
Appearance.SetData(uid, AmmoVisuals.AmmoCount, count, appearance);
|
||||
Appearance.SetData(uid, AmmoVisuals.AmmoMax, component.Capacity, appearance);
|
||||
var count = GetRevolverCount(ent.Comp);
|
||||
Appearance.SetData(ent, AmmoVisuals.HasAmmo, count != 0, appearance);
|
||||
Appearance.SetData(ent, AmmoVisuals.AmmoCount, count, appearance);
|
||||
Appearance.SetData(ent, AmmoVisuals.AmmoMax, ent.Comp.Capacity, appearance);
|
||||
}
|
||||
|
||||
protected virtual void SpinRevolver(EntityUid revolverUid, RevolverAmmoProviderComponent component, EntityUid? user = null)
|
||||
protected virtual void SpinRevolver(Entity<RevolverAmmoProviderComponent> ent, EntityUid? user = null)
|
||||
{
|
||||
Audio.PlayPredicted(component.SoundSpin, revolverUid, user);
|
||||
Popup(Loc.GetString("gun-revolver-spun"), revolverUid, user);
|
||||
Audio.PlayPredicted(ent.Comp.SoundSpin, ent, user);
|
||||
Popup(Loc.GetString("gun-revolver-spun"), ent, user);
|
||||
}
|
||||
|
||||
private void OnRevolverTakeAmmo(EntityUid uid, RevolverAmmoProviderComponent component, TakeAmmoEvent args)
|
||||
private void OnRevolverTakeAmmo(Entity<RevolverAmmoProviderComponent> ent, ref TakeAmmoEvent args)
|
||||
{
|
||||
var currentIndex = component.CurrentIndex;
|
||||
Cycle(component, args.Shots);
|
||||
var currentIndex = ent.Comp.CurrentIndex;
|
||||
Cycle(ent.Comp, args.Shots);
|
||||
|
||||
// Revolvers provide the bullets themselves rather than the cartridges so they stay in the revolver.
|
||||
for (var i = 0; i < args.Shots; i++)
|
||||
{
|
||||
var index = (currentIndex + i) % component.Capacity;
|
||||
var chamber = component.Chambers[index];
|
||||
EntityUid? ent = null;
|
||||
var index = (currentIndex + i) % ent.Comp.Capacity;
|
||||
var chamber = ent.Comp.Chambers[index];
|
||||
EntityUid? ammoEnt = null;
|
||||
|
||||
// Get contained entity if it exists.
|
||||
if (component.AmmoSlots[index] != null)
|
||||
if (ent.Comp.AmmoSlots[index] != null)
|
||||
{
|
||||
ent = component.AmmoSlots[index]!;
|
||||
component.Chambers[index] = false;
|
||||
ammoEnt = ent.Comp.AmmoSlots[index]!;
|
||||
ent.Comp.Chambers[index] = false;
|
||||
}
|
||||
// Try to spawn a round if it's available.
|
||||
else if (chamber != null)
|
||||
@@ -373,55 +373,55 @@ public partial class SharedGunSystem
|
||||
if (chamber == true)
|
||||
{
|
||||
// Pretend it's always been there.
|
||||
ent = Spawn(component.FillPrototype, args.Coordinates);
|
||||
ammoEnt = Spawn(ent.Comp.FillPrototype, args.Coordinates);
|
||||
|
||||
if (!_netManager.IsClient)
|
||||
{
|
||||
component.AmmoSlots[index] = ent;
|
||||
Containers.Insert(ent.Value, component.AmmoContainer);
|
||||
ent.Comp.AmmoSlots[index] = ammoEnt;
|
||||
Containers.Insert(ammoEnt.Value, ent.Comp.AmmoContainer);
|
||||
}
|
||||
|
||||
component.Chambers[index] = false;
|
||||
ent.Comp.Chambers[index] = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Chamber empty or spent
|
||||
if (ent == null)
|
||||
if (ammoEnt == null)
|
||||
continue;
|
||||
|
||||
if (TryComp<CartridgeAmmoComponent>(ent, out var cartridge))
|
||||
if (TryComp<CartridgeAmmoComponent>(ammoEnt, out var cartridge))
|
||||
{
|
||||
if (cartridge.Spent)
|
||||
continue;
|
||||
|
||||
// Mark cartridge as spent and if it's caseless delete from the chamber slot.
|
||||
SetCartridgeSpent(ent.Value, cartridge, true);
|
||||
SetCartridgeSpent(ammoEnt.Value, cartridge, true);
|
||||
var spawned = Spawn(cartridge.Prototype, args.Coordinates);
|
||||
args.Ammo.Add((spawned, EnsureComp<AmmoComponent>(spawned)));
|
||||
|
||||
if (cartridge.DeleteOnSpawn)
|
||||
{
|
||||
component.AmmoSlots[index] = null;
|
||||
component.Chambers[index] = null;
|
||||
ent.Comp.AmmoSlots[index] = null;
|
||||
ent.Comp.Chambers[index] = null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
component.AmmoSlots[index] = null;
|
||||
component.Chambers[index] = null;
|
||||
args.Ammo.Add((ent.Value, EnsureComp<AmmoComponent>(ent.Value)));
|
||||
ent.Comp.AmmoSlots[index] = null;
|
||||
ent.Comp.Chambers[index] = null;
|
||||
args.Ammo.Add((ammoEnt.Value, EnsureComp<AmmoComponent>(ammoEnt.Value)));
|
||||
}
|
||||
|
||||
// Delete the cartridge entity on client
|
||||
if (_netManager.IsClient)
|
||||
{
|
||||
QueueDel(ent);
|
||||
QueueDel(ammoEnt);
|
||||
}
|
||||
}
|
||||
|
||||
UpdateAmmoCount(uid, prediction: false);
|
||||
UpdateRevolverAppearance(uid, component);
|
||||
Dirty(uid, component);
|
||||
UpdateAmmoCount(ent, prediction: false);
|
||||
UpdateRevolverAppearance(ent);
|
||||
Dirty(ent);
|
||||
}
|
||||
|
||||
private void Cycle(RevolverAmmoProviderComponent component, int count = 1)
|
||||
@@ -429,34 +429,34 @@ public partial class SharedGunSystem
|
||||
component.CurrentIndex = (component.CurrentIndex + count) % component.Capacity;
|
||||
}
|
||||
|
||||
private void OnRevolverInit(EntityUid uid, RevolverAmmoProviderComponent component, ComponentInit args)
|
||||
private void OnRevolverInit(Entity<RevolverAmmoProviderComponent> ent, ref ComponentInit args)
|
||||
{
|
||||
component.AmmoContainer = Containers.EnsureContainer<Container>(uid, RevolverContainer);
|
||||
component.AmmoSlots.EnsureCapacity(component.Capacity);
|
||||
var remainder = component.Capacity - component.AmmoSlots.Count;
|
||||
ent.Comp.AmmoContainer = Containers.EnsureContainer<Container>(ent, RevolverContainer);
|
||||
ent.Comp.AmmoSlots.EnsureCapacity(ent.Comp.Capacity);
|
||||
var remainder = ent.Comp.Capacity - ent.Comp.AmmoSlots.Count;
|
||||
|
||||
for (var i = 0; i < remainder; i++)
|
||||
{
|
||||
component.AmmoSlots.Add(null);
|
||||
ent.Comp.AmmoSlots.Add(null);
|
||||
}
|
||||
|
||||
component.Chambers = new bool?[component.Capacity];
|
||||
ent.Comp.Chambers = new bool?[ent.Comp.Capacity];
|
||||
|
||||
if (component.FillPrototype != null)
|
||||
if (ent.Comp.FillPrototype != null)
|
||||
{
|
||||
for (var i = 0; i < component.Capacity; i++)
|
||||
for (var i = 0; i < ent.Comp.Capacity; i++)
|
||||
{
|
||||
if (component.AmmoSlots[i] != null)
|
||||
if (ent.Comp.AmmoSlots[i] != null)
|
||||
{
|
||||
component.Chambers[i] = null;
|
||||
ent.Comp.Chambers[i] = null;
|
||||
continue;
|
||||
}
|
||||
|
||||
component.Chambers[i] = true;
|
||||
ent.Comp.Chambers[i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
DebugTools.Assert(component.AmmoSlots.Count == component.Capacity);
|
||||
DebugTools.Assert(ent.Comp.AmmoSlots.Count == ent.Comp.Capacity);
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
|
||||
@@ -13,9 +13,9 @@ public partial class SharedGunSystem
|
||||
SubscribeLocalEvent<SolutionAmmoProviderComponent, GetAmmoCountEvent>(OnSolutionAmmoCount);
|
||||
}
|
||||
|
||||
private void OnSolutionTakeAmmo(EntityUid uid, SolutionAmmoProviderComponent component, TakeAmmoEvent args)
|
||||
private void OnSolutionTakeAmmo(Entity<SolutionAmmoProviderComponent> ent, ref TakeAmmoEvent args)
|
||||
{
|
||||
var shots = Math.Min(args.Shots, component.Shots);
|
||||
var shots = Math.Min(args.Shots, ent.Comp.Shots);
|
||||
|
||||
// Don't dirty if it's an empty fire.
|
||||
if (shots == 0)
|
||||
@@ -23,38 +23,35 @@ public partial class SharedGunSystem
|
||||
|
||||
for (var i = 0; i < shots; i++)
|
||||
{
|
||||
args.Ammo.Add(GetSolutionShot(uid, component, args.Coordinates));
|
||||
component.Shots--;
|
||||
args.Ammo.Add(GetSolutionShot(ent, args.Coordinates));
|
||||
ent.Comp.Shots--;
|
||||
}
|
||||
|
||||
UpdateSolutionShots(uid, component);
|
||||
UpdateSolutionAppearance(uid, component);
|
||||
UpdateSolutionShots(ent);
|
||||
UpdateSolutionAppearance(ent);
|
||||
}
|
||||
|
||||
private void OnSolutionAmmoCount(EntityUid uid, SolutionAmmoProviderComponent component, ref GetAmmoCountEvent args)
|
||||
private void OnSolutionAmmoCount(Entity<SolutionAmmoProviderComponent> ent, ref GetAmmoCountEvent args)
|
||||
{
|
||||
args.Count = component.Shots;
|
||||
args.Capacity = component.MaxShots;
|
||||
args.Count = ent.Comp.Shots;
|
||||
args.Capacity = ent.Comp.MaxShots;
|
||||
}
|
||||
|
||||
protected virtual void UpdateSolutionShots(EntityUid uid, SolutionAmmoProviderComponent component, Solution? solution = null)
|
||||
{
|
||||
protected virtual void UpdateSolutionShots(Entity<SolutionAmmoProviderComponent> ent, Solution? solution = null) { }
|
||||
|
||||
protected virtual (EntityUid Entity, IShootable) GetSolutionShot(Entity<SolutionAmmoProviderComponent> ent, EntityCoordinates position)
|
||||
{
|
||||
var shot = Spawn(ent.Comp.Prototype, position);
|
||||
return (shot, EnsureShootable(shot));
|
||||
}
|
||||
|
||||
protected virtual (EntityUid Entity, IShootable) GetSolutionShot(EntityUid uid, SolutionAmmoProviderComponent component, EntityCoordinates position)
|
||||
protected void UpdateSolutionAppearance(Entity<SolutionAmmoProviderComponent> ent)
|
||||
{
|
||||
var ent = Spawn(component.Prototype, position);
|
||||
return (ent, EnsureShootable(ent));
|
||||
}
|
||||
|
||||
protected void UpdateSolutionAppearance(EntityUid uid, SolutionAmmoProviderComponent component)
|
||||
{
|
||||
if (!TryComp<AppearanceComponent>(uid, out var appearance))
|
||||
if (!TryComp<AppearanceComponent>(ent, out var appearance))
|
||||
return;
|
||||
|
||||
Appearance.SetData(uid, AmmoVisuals.HasAmmo, component.Shots != 0, appearance);
|
||||
Appearance.SetData(uid, AmmoVisuals.AmmoCount, component.Shots, appearance);
|
||||
Appearance.SetData(uid, AmmoVisuals.AmmoMax, component.MaxShots, appearance);
|
||||
Appearance.SetData(ent, AmmoVisuals.HasAmmo, ent.Comp.Shots != 0, appearance);
|
||||
Appearance.SetData(ent, AmmoVisuals.AmmoCount, ent.Comp.Shots, appearance);
|
||||
Appearance.SetData(ent, AmmoVisuals.AmmoMax, ent.Comp.MaxShots, appearance);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,38 +40,48 @@ namespace Content.Shared.Weapons.Ranged.Systems;
|
||||
|
||||
public abstract partial class SharedGunSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!;
|
||||
[Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!;
|
||||
[Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!;
|
||||
[Dependency] private readonly INetManager _netManager = default!;
|
||||
[Dependency] private readonly ItemSlotsSystem _slots = default!;
|
||||
[Dependency] private readonly RechargeBasicEntityAmmoSystem _recharge = default!;
|
||||
[Dependency] private readonly SharedCombatModeSystem _combatMode = default!;
|
||||
[Dependency] private readonly SharedHandsSystem _hands = default!;
|
||||
[Dependency] private readonly UseDelaySystem _useDelay = default!;
|
||||
[Dependency] protected readonly DamageableSystem Damageable = default!;
|
||||
[Dependency] protected readonly ExamineSystemShared Examine = default!;
|
||||
[Dependency] protected readonly IGameTiming Timing = default!;
|
||||
[Dependency] protected readonly IMapManager MapManager = default!;
|
||||
[Dependency] private readonly INetManager _netManager = default!;
|
||||
[Dependency] protected readonly IPrototypeManager ProtoManager = default!;
|
||||
[Dependency] protected readonly IRobustRandom Random = default!;
|
||||
[Dependency] protected readonly ISharedAdminLogManager Logs = default!;
|
||||
[Dependency] protected readonly DamageableSystem Damageable = default!;
|
||||
[Dependency] protected readonly ExamineSystemShared Examine = default!;
|
||||
[Dependency] private readonly SharedHandsSystem _hands = default!;
|
||||
[Dependency] private readonly ItemSlotsSystem _slots = default!;
|
||||
[Dependency] private readonly RechargeBasicEntityAmmoSystem _recharge = default!;
|
||||
[Dependency] protected readonly SharedActionsSystem Actions = default!;
|
||||
[Dependency] protected readonly SharedAppearanceSystem Appearance = default!;
|
||||
[Dependency] protected readonly SharedAudioSystem Audio = default!;
|
||||
[Dependency] private readonly SharedCombatModeSystem _combatMode = default!;
|
||||
[Dependency] protected readonly SharedContainerSystem Containers = default!;
|
||||
[Dependency] protected readonly SharedPhysicsSystem Physics = default!;
|
||||
[Dependency] protected readonly SharedPointLightSystem Lights = default!;
|
||||
[Dependency] protected readonly SharedPopupSystem PopupSystem = default!;
|
||||
[Dependency] protected readonly SharedPhysicsSystem Physics = default!;
|
||||
[Dependency] protected readonly SharedProjectileSystem Projectiles = default!;
|
||||
[Dependency] protected readonly SharedTransformSystem TransformSystem = default!;
|
||||
[Dependency] protected readonly TagSystem TagSystem = default!;
|
||||
[Dependency] protected readonly ThrowingSystem ThrowingSystem = default!;
|
||||
[Dependency] private readonly UseDelaySystem _useDelay = default!;
|
||||
[Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!;
|
||||
|
||||
/// <summary>
|
||||
/// Default projectile speed
|
||||
/// </summary>
|
||||
public const float ProjectileSpeed = 40f;
|
||||
|
||||
/// <summary>
|
||||
/// Name of the container slot used as the gun's chamber
|
||||
/// </summary>
|
||||
public const string ChamberSlot = "gun_chamber";
|
||||
|
||||
/// <summary>
|
||||
/// Name of the container slot used as the gun's magazine
|
||||
/// </summary>
|
||||
public const string MagazineSlot = "gun_magazine";
|
||||
|
||||
private static readonly ProtoId<TagPrototype> TrashTag = "Trash";
|
||||
|
||||
private const float InteractNextFire = 0.3f;
|
||||
@@ -119,15 +129,15 @@ public abstract partial class SharedGunSystem : EntitySystem
|
||||
RefreshModifiers((gun, gun));
|
||||
}
|
||||
|
||||
private void OnGunMelee(EntityUid uid, GunComponent component, MeleeHitEvent args)
|
||||
private void OnGunMelee(Entity<GunComponent> ent, ref MeleeHitEvent args)
|
||||
{
|
||||
if (!TryComp<MeleeWeaponComponent>(uid, out var melee))
|
||||
if (!TryComp<MeleeWeaponComponent>(ent, out var melee))
|
||||
return;
|
||||
|
||||
if (melee.NextAttack > component.NextFire)
|
||||
if (melee.NextAttack > ent.Comp.NextFire)
|
||||
{
|
||||
component.NextFire = melee.NextAttack;
|
||||
DirtyField(uid, component, nameof(GunComponent.NextFire));
|
||||
ent.Comp.NextFire = melee.NextAttack;
|
||||
DirtyField(ent.AsNullable(), nameof(GunComponent.NextFire));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,17 +147,17 @@ public abstract partial class SharedGunSystem : EntitySystem
|
||||
|
||||
if (user == null ||
|
||||
!_combatMode.IsInCombatMode(user) ||
|
||||
!TryGetGun(user.Value, out var ent, out var gun))
|
||||
!TryGetGun(user.Value, out var gun))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (ent != GetEntity(msg.Gun))
|
||||
if (gun.Owner != GetEntity(msg.Gun))
|
||||
return;
|
||||
|
||||
gun.ShootCoordinates = GetCoordinates(msg.Coordinates);
|
||||
gun.Target = GetEntity(msg.Target);
|
||||
AttemptShoot(user.Value, ent, gun);
|
||||
gun.Comp.ShootCoordinates = GetCoordinates(msg.Coordinates);
|
||||
gun.Comp.Target = GetEntity(msg.Target);
|
||||
AttemptShoot(user.Value, gun);
|
||||
}
|
||||
|
||||
private void OnStopShootRequest(RequestStopShootEvent ev, EntitySessionEventArgs args)
|
||||
@@ -156,15 +166,15 @@ public abstract partial class SharedGunSystem : EntitySystem
|
||||
|
||||
if (args.SenderSession.AttachedEntity == null ||
|
||||
!TryComp<GunComponent>(gunUid, out var gun) ||
|
||||
!TryGetGun(args.SenderSession.AttachedEntity.Value, out _, out var userGun))
|
||||
!TryGetGun(args.SenderSession.AttachedEntity.Value, out var userGun))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (userGun != gun)
|
||||
if (userGun != (gunUid, gun))
|
||||
return;
|
||||
|
||||
StopShooting(gunUid, gun);
|
||||
StopShooting(userGun);
|
||||
}
|
||||
|
||||
public bool CanShoot(GunComponent component)
|
||||
@@ -175,75 +185,78 @@ public abstract partial class SharedGunSystem : EntitySystem
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool TryGetGun(EntityUid entity, out EntityUid gunEntity, [NotNullWhen(true)] out GunComponent? gunComp)
|
||||
/// <summary>
|
||||
/// Tries to get an entity with <see cref="GunComponent"/> from the specified entity's hands, or from the entity itself.
|
||||
/// </summary>
|
||||
/// <param name="entity">Entity that is holding the gun, or is the gun</param>
|
||||
/// <param name="gun">Gun entity to return</param>
|
||||
/// <returns>True if gun was found</returns>
|
||||
public bool TryGetGun(EntityUid entity, out Entity<GunComponent> gun)
|
||||
{
|
||||
gunEntity = default;
|
||||
gunComp = null;
|
||||
gun = default;
|
||||
|
||||
if (_hands.GetActiveItem(entity) is { } held &&
|
||||
TryComp(held, out GunComponent? gun))
|
||||
TryComp(held, out GunComponent? gunComp))
|
||||
{
|
||||
gunEntity = held;
|
||||
gunComp = gun;
|
||||
gun = (held, gunComp);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Last resort is check if the entity itself is a gun.
|
||||
if (TryComp(entity, out gun))
|
||||
if (TryComp(entity, out gunComp))
|
||||
{
|
||||
gunEntity = entity;
|
||||
gunComp = gun;
|
||||
gun = (entity, gunComp);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void StopShooting(EntityUid uid, GunComponent gun)
|
||||
private void StopShooting(Entity<GunComponent> ent)
|
||||
{
|
||||
if (gun.ShotCounter == 0)
|
||||
if (ent.Comp.ShotCounter == 0)
|
||||
return;
|
||||
|
||||
gun.ShotCounter = 0;
|
||||
gun.ShootCoordinates = null;
|
||||
gun.Target = null;
|
||||
DirtyField(uid, gun, nameof(GunComponent.ShotCounter));
|
||||
ent.Comp.ShotCounter = 0;
|
||||
ent.Comp.ShootCoordinates = null;
|
||||
ent.Comp.Target = null;
|
||||
DirtyField(ent.AsNullable(), nameof(GunComponent.ShotCounter));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to shoot at the target coordinates. Resets the shot counter after every shot.
|
||||
/// </summary>
|
||||
public bool AttemptShoot(EntityUid user, EntityUid gunUid, GunComponent gun, EntityCoordinates toCoordinates, EntityUid? target = null)
|
||||
public bool AttemptShoot(EntityUid user, Entity<GunComponent> gun, EntityCoordinates toCoordinates, EntityUid? target = null)
|
||||
{
|
||||
gun.ShootCoordinates = toCoordinates;
|
||||
gun.Target = target;
|
||||
var result = AttemptShoot(user, gunUid, gun);
|
||||
gun.ShotCounter = 0;
|
||||
DirtyField(gunUid, gun, nameof(GunComponent.ShotCounter));
|
||||
gun.Comp.ShootCoordinates = toCoordinates;
|
||||
gun.Comp.Target = target;
|
||||
var result = AttemptShoot(user, gun);
|
||||
gun.Comp.ShotCounter = 0;
|
||||
DirtyField(gun.AsNullable(), nameof(GunComponent.ShotCounter));
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shoots by assuming the gun is the user at default coordinates.
|
||||
/// </summary>
|
||||
public bool AttemptShoot(EntityUid gunUid, GunComponent gun)
|
||||
public bool AttemptShoot(Entity<GunComponent> gun)
|
||||
{
|
||||
var coordinates = new EntityCoordinates(gunUid, gun.DefaultDirection);
|
||||
gun.ShootCoordinates = coordinates;
|
||||
var result = AttemptShoot(gunUid, gunUid, gun);
|
||||
gun.ShotCounter = 0;
|
||||
var coordinates = new EntityCoordinates(gun, gun.Comp.DefaultDirection);
|
||||
gun.Comp.ShootCoordinates = coordinates;
|
||||
var result = AttemptShoot(gun, gun);
|
||||
gun.Comp.ShotCounter = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
private bool AttemptShoot(EntityUid user, EntityUid gunUid, GunComponent gun)
|
||||
private bool AttemptShoot(EntityUid user, Entity<GunComponent> gun)
|
||||
{
|
||||
if (gun.FireRateModified <= 0f ||
|
||||
if (gun.Comp.FireRateModified <= 0f ||
|
||||
!_actionBlockerSystem.CanAttack(user))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var toCoordinates = gun.ShootCoordinates;
|
||||
var toCoordinates = gun.Comp.ShootCoordinates;
|
||||
|
||||
if (toCoordinates == null)
|
||||
return false;
|
||||
@@ -254,9 +267,9 @@ public abstract partial class SharedGunSystem : EntitySystem
|
||||
var prevention = new ShotAttemptedEvent
|
||||
{
|
||||
User = user,
|
||||
Used = (gunUid, gun)
|
||||
Used = gun
|
||||
};
|
||||
RaiseLocalEvent(gunUid, ref prevention);
|
||||
RaiseLocalEvent(gun, ref prevention);
|
||||
if (prevention.Cancelled)
|
||||
return false;
|
||||
|
||||
@@ -266,95 +279,96 @@ public abstract partial class SharedGunSystem : EntitySystem
|
||||
|
||||
// Need to do this to play the clicking sound for empty automatic weapons
|
||||
// but not play anything for burst fire.
|
||||
if (gun.NextFire > curTime)
|
||||
if (gun.Comp.NextFire > curTime)
|
||||
return false;
|
||||
|
||||
var fireRate = TimeSpan.FromSeconds(1f / gun.FireRateModified);
|
||||
var fireRate = TimeSpan.FromSeconds(1f / gun.Comp.FireRateModified);
|
||||
|
||||
if (gun.SelectedMode == SelectiveFire.Burst || gun.BurstActivated)
|
||||
fireRate = TimeSpan.FromSeconds(1f / gun.BurstFireRate);
|
||||
if (gun.Comp.SelectedMode == SelectiveFire.Burst || gun.Comp.BurstActivated)
|
||||
fireRate = TimeSpan.FromSeconds(1f / gun.Comp.BurstFireRate);
|
||||
|
||||
// First shot
|
||||
// Previously we checked shotcounter but in some cases all the bullets got dumped at once
|
||||
// curTime - fireRate is insufficient because if you time it just right you can get a 3rd shot out slightly quicker.
|
||||
if (gun.NextFire < curTime - fireRate || gun.ShotCounter == 0 && gun.NextFire < curTime)
|
||||
gun.NextFire = curTime;
|
||||
if (gun.Comp.NextFire < curTime - fireRate || gun.Comp.ShotCounter == 0 && gun.Comp.NextFire < curTime)
|
||||
gun.Comp.NextFire = curTime;
|
||||
|
||||
var shots = 0;
|
||||
var lastFire = gun.NextFire;
|
||||
var lastFire = gun.Comp.NextFire;
|
||||
|
||||
while (gun.NextFire <= curTime)
|
||||
while (gun.Comp.NextFire <= curTime)
|
||||
{
|
||||
gun.NextFire += fireRate;
|
||||
gun.Comp.NextFire += fireRate;
|
||||
shots++;
|
||||
}
|
||||
|
||||
// NextFire has been touched regardless so need to dirty the gun.
|
||||
DirtyField(gunUid, gun, nameof(GunComponent.NextFire));
|
||||
DirtyField(gun.AsNullable(), nameof(GunComponent.NextFire));
|
||||
|
||||
// Get how many shots we're actually allowed to make, due to clip size or otherwise.
|
||||
// Don't do this in the loop so we still reset NextFire.
|
||||
if (!gun.BurstActivated)
|
||||
if (!gun.Comp.BurstActivated)
|
||||
{
|
||||
switch (gun.SelectedMode)
|
||||
switch (gun.Comp.SelectedMode)
|
||||
{
|
||||
case SelectiveFire.SemiAuto:
|
||||
shots = Math.Min(shots, 1 - gun.ShotCounter);
|
||||
shots = Math.Min(shots, 1 - gun.Comp.ShotCounter);
|
||||
break;
|
||||
case SelectiveFire.Burst:
|
||||
shots = Math.Min(shots, gun.ShotsPerBurstModified - gun.ShotCounter);
|
||||
shots = Math.Min(shots, gun.Comp.ShotsPerBurstModified - gun.Comp.ShotCounter);
|
||||
break;
|
||||
case SelectiveFire.FullAuto:
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException($"No implemented shooting behavior for {gun.SelectedMode}!");
|
||||
throw new ArgumentOutOfRangeException($"No implemented shooting behavior for {gun.Comp.SelectedMode}!");
|
||||
}
|
||||
} else
|
||||
}
|
||||
else
|
||||
{
|
||||
shots = Math.Min(shots, gun.ShotsPerBurstModified - gun.ShotCounter);
|
||||
shots = Math.Min(shots, gun.Comp.ShotsPerBurstModified - gun.Comp.ShotCounter);
|
||||
}
|
||||
|
||||
var attemptEv = new AttemptShootEvent(user, null);
|
||||
RaiseLocalEvent(gunUid, ref attemptEv);
|
||||
RaiseLocalEvent(gun, ref attemptEv);
|
||||
|
||||
if (attemptEv.Cancelled)
|
||||
{
|
||||
if (attemptEv.Message != null)
|
||||
{
|
||||
PopupSystem.PopupClient(attemptEv.Message, gunUid, user);
|
||||
PopupSystem.PopupClient(attemptEv.Message, gun, user);
|
||||
}
|
||||
gun.BurstActivated = false;
|
||||
gun.BurstShotsCount = 0;
|
||||
gun.NextFire = TimeSpan.FromSeconds(Math.Max(lastFire.TotalSeconds + SafetyNextFire, gun.NextFire.TotalSeconds));
|
||||
gun.Comp.BurstActivated = false;
|
||||
gun.Comp.BurstShotsCount = 0;
|
||||
gun.Comp.NextFire = TimeSpan.FromSeconds(Math.Max(lastFire.TotalSeconds + SafetyNextFire, gun.Comp.NextFire.TotalSeconds));
|
||||
return false;
|
||||
}
|
||||
|
||||
var fromCoordinates = Transform(user).Coordinates;
|
||||
// Remove ammo
|
||||
var ev = new TakeAmmoEvent(shots, new List<(EntityUid? Entity, IShootable Shootable)>(), fromCoordinates, user);
|
||||
var ev = new TakeAmmoEvent(shots, [], fromCoordinates, user);
|
||||
|
||||
// Listen it just makes the other code around it easier if shots == 0 to do this.
|
||||
if (shots > 0)
|
||||
RaiseLocalEvent(gunUid, ev);
|
||||
RaiseLocalEvent(gun, ev);
|
||||
|
||||
DebugTools.Assert(ev.Ammo.Count <= shots);
|
||||
DebugTools.Assert(shots >= 0);
|
||||
UpdateAmmoCount(gunUid);
|
||||
UpdateAmmoCount(gun);
|
||||
|
||||
// Even if we don't actually shoot update the ShotCounter. This is to avoid spamming empty sounds
|
||||
// where the gun may be SemiAuto or Burst.
|
||||
gun.ShotCounter += shots;
|
||||
DirtyField(gunUid, gun, nameof(GunComponent.ShotCounter));
|
||||
gun.Comp.ShotCounter += shots;
|
||||
DirtyField(gun.AsNullable(), nameof(GunComponent.ShotCounter));
|
||||
|
||||
if (ev.Ammo.Count <= 0)
|
||||
{
|
||||
// triggers effects on the gun if it's empty
|
||||
var emptyGunShotEvent = new OnEmptyGunShotEvent(user);
|
||||
RaiseLocalEvent(gunUid, ref emptyGunShotEvent);
|
||||
RaiseLocalEvent(gun, ref emptyGunShotEvent);
|
||||
|
||||
gun.BurstActivated = false;
|
||||
gun.BurstShotsCount = 0;
|
||||
gun.NextFire += TimeSpan.FromSeconds(gun.BurstCooldown);
|
||||
gun.Comp.BurstActivated = false;
|
||||
gun.Comp.BurstShotsCount = 0;
|
||||
gun.Comp.NextFire += TimeSpan.FromSeconds(gun.Comp.BurstCooldown);
|
||||
|
||||
// Play empty gun sounds if relevant
|
||||
// If they're firing an existing clip then don't play anything.
|
||||
@@ -364,8 +378,8 @@ public abstract partial class SharedGunSystem : EntitySystem
|
||||
|
||||
// Don't spam safety sounds at gun fire rate, play it at a reduced rate.
|
||||
// May cause prediction issues? Needs more tweaking
|
||||
gun.NextFire = TimeSpan.FromSeconds(Math.Max(lastFire.TotalSeconds + SafetyNextFire, gun.NextFire.TotalSeconds));
|
||||
Audio.PlayPredicted(gun.SoundEmpty, gunUid, user);
|
||||
gun.Comp.NextFire = TimeSpan.FromSeconds(Math.Max(lastFire.TotalSeconds + SafetyNextFire, gun.Comp.NextFire.TotalSeconds));
|
||||
Audio.PlayPredicted(gun.Comp.SoundEmpty, gun, user);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -373,25 +387,25 @@ public abstract partial class SharedGunSystem : EntitySystem
|
||||
}
|
||||
|
||||
// Handle burstfire
|
||||
if (gun.SelectedMode == SelectiveFire.Burst)
|
||||
if (gun.Comp.SelectedMode == SelectiveFire.Burst)
|
||||
{
|
||||
gun.BurstActivated = true;
|
||||
gun.Comp.BurstActivated = true;
|
||||
}
|
||||
if (gun.BurstActivated)
|
||||
if (gun.Comp.BurstActivated)
|
||||
{
|
||||
gun.BurstShotsCount += shots;
|
||||
if (gun.BurstShotsCount >= gun.ShotsPerBurstModified)
|
||||
gun.Comp.BurstShotsCount += shots;
|
||||
if (gun.Comp.BurstShotsCount >= gun.Comp.ShotsPerBurstModified)
|
||||
{
|
||||
gun.NextFire += TimeSpan.FromSeconds(gun.BurstCooldown);
|
||||
gun.BurstActivated = false;
|
||||
gun.BurstShotsCount = 0;
|
||||
gun.Comp.NextFire += TimeSpan.FromSeconds(gun.Comp.BurstCooldown);
|
||||
gun.Comp.BurstActivated = false;
|
||||
gun.Comp.BurstShotsCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Shoot confirmed - sounds also played here in case it's invalid (e.g. cartridge already spent).
|
||||
Shoot(gunUid, gun, ev.Ammo, fromCoordinates, toCoordinates.Value, out var userImpulse, user, throwItems: attemptEv.ThrowItems);
|
||||
Shoot(gun, ev.Ammo, fromCoordinates, toCoordinates.Value, out var userImpulse, user, throwItems: attemptEv.ThrowItems);
|
||||
var shotEv = new GunShotEvent(user, ev.Ammo);
|
||||
RaiseLocalEvent(gunUid, ref shotEv);
|
||||
RaiseLocalEvent(gun, ref shotEv);
|
||||
|
||||
if (!userImpulse || !TryComp<PhysicsComponent>(user, out var userPhysics))
|
||||
return true;
|
||||
@@ -400,13 +414,12 @@ public abstract partial class SharedGunSystem : EntitySystem
|
||||
RaiseLocalEvent(user, ref shooterEv);
|
||||
|
||||
if (shooterEv.Push)
|
||||
CauseImpulse(fromCoordinates, toCoordinates.Value, user, userPhysics);
|
||||
CauseImpulse(fromCoordinates, toCoordinates.Value, (user, userPhysics));
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Shoot(
|
||||
EntityUid gunUid,
|
||||
GunComponent gun,
|
||||
Entity<GunComponent> gun,
|
||||
EntityUid ammo,
|
||||
EntityCoordinates fromCoordinates,
|
||||
EntityCoordinates toCoordinates,
|
||||
@@ -415,12 +428,11 @@ public abstract partial class SharedGunSystem : EntitySystem
|
||||
bool throwItems = false)
|
||||
{
|
||||
var shootable = EnsureShootable(ammo);
|
||||
Shoot(gunUid, gun, new List<(EntityUid? Entity, IShootable Shootable)>(1) { (ammo, shootable) }, fromCoordinates, toCoordinates, out userImpulse, user, throwItems);
|
||||
Shoot(gun, new List<(EntityUid? Entity, IShootable Shootable)>(1) { (ammo, shootable) }, fromCoordinates, toCoordinates, out userImpulse, user, throwItems);
|
||||
}
|
||||
|
||||
public abstract void Shoot(
|
||||
EntityUid gunUid,
|
||||
GunComponent gun,
|
||||
Entity<GunComponent> gun,
|
||||
List<(EntityUid? Entity, IShootable Shootable)> ammo,
|
||||
EntityCoordinates fromCoordinates,
|
||||
EntityCoordinates toCoordinates,
|
||||
@@ -452,7 +464,7 @@ public abstract partial class SharedGunSystem : EntitySystem
|
||||
/// <summary>
|
||||
/// Call this whenever the ammo count for a gun changes.
|
||||
/// </summary>
|
||||
protected virtual void UpdateAmmoCount(EntityUid uid, bool prediction = true) {}
|
||||
protected virtual void UpdateAmmoCount(EntityUid uid, bool prediction = true) { }
|
||||
|
||||
protected void SetCartridgeSpent(EntityUid uid, CartridgeAmmoComponent cartridge, bool spent)
|
||||
{
|
||||
@@ -492,7 +504,7 @@ public abstract partial class SharedGunSystem : EntitySystem
|
||||
// decides direction the casing ejects and only when not cycling
|
||||
if (angle != null)
|
||||
{
|
||||
Angle ejectAngle = angle.Value;
|
||||
var ejectAngle = angle.Value;
|
||||
ejectAngle += 3.7f; // 212 degrees; casings should eject slightly to the right and behind of a gun
|
||||
ThrowingSystem.TryThrow(entity, ejectAngle.ToVec().Normalized() / 100, 5f);
|
||||
}
|
||||
@@ -535,15 +547,15 @@ public abstract partial class SharedGunSystem : EntitySystem
|
||||
CreateEffect(gun, ev, user);
|
||||
}
|
||||
|
||||
public void CauseImpulse(EntityCoordinates fromCoordinates, EntityCoordinates toCoordinates, EntityUid user, PhysicsComponent userPhysics)
|
||||
public void CauseImpulse(EntityCoordinates fromCoordinates, EntityCoordinates toCoordinates, Entity<PhysicsComponent> user)
|
||||
{
|
||||
var fromMap = TransformSystem.ToMapCoordinates(fromCoordinates).Position;
|
||||
var toMap = TransformSystem.ToMapCoordinates(toCoordinates).Position;
|
||||
var shotDirection = (toMap - fromMap).Normalized();
|
||||
|
||||
const float impulseStrength = 25.0f;
|
||||
var impulseVector = shotDirection * impulseStrength;
|
||||
Physics.ApplyLinearImpulse(user, -impulseVector, body: userPhysics);
|
||||
var impulseVector = shotDirection * impulseStrength;
|
||||
Physics.ApplyLinearImpulse(user, -impulseVector, body: user.Comp);
|
||||
}
|
||||
|
||||
public void RefreshModifiers(Entity<GunComponent?> gun)
|
||||
@@ -632,7 +644,7 @@ public abstract partial class SharedGunSystem : EntitySystem
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class HitscanEvent : EntityEventArgs
|
||||
{
|
||||
public List<(NetCoordinates coordinates, Angle angle, SpriteSpecifier Sprite, float Distance)> Sprites = new();
|
||||
public List<(NetCoordinates coordinates, Angle angle, SpriteSpecifier Sprite, float Distance)> Sprites = [];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -13,9 +13,9 @@ public sealed class UseDelayOnShootSystem : EntitySystem
|
||||
SubscribeLocalEvent<UseDelayOnShootComponent, GunShotEvent>(OnUseShoot);
|
||||
}
|
||||
|
||||
private void OnUseShoot(EntityUid uid, UseDelayOnShootComponent component, ref GunShotEvent args)
|
||||
private void OnUseShoot(Entity<UseDelayOnShootComponent> ent, ref GunShotEvent args)
|
||||
{
|
||||
if (TryComp(uid, out UseDelayComponent? useDelay))
|
||||
_delay.TryResetDelay((uid, useDelay));
|
||||
if (TryComp(ent, out UseDelayComponent? useDelay))
|
||||
_delay.TryResetDelay((ent, useDelay));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user