Remove gun .Owners (#14585)
This commit is contained in:
@@ -7,16 +7,16 @@ namespace Content.Shared.Weapons.Ranged.Events;
|
||||
/// </summary>
|
||||
public sealed class TakeAmmoEvent : EntityEventArgs
|
||||
{
|
||||
public EntityUid? User;
|
||||
public readonly EntityUid? User;
|
||||
public readonly int Shots;
|
||||
public List<IShootable> Ammo;
|
||||
public List<(EntityUid? Entity, IShootable Shootable)> Ammo;
|
||||
|
||||
/// <summary>
|
||||
/// Coordinates to spawn the ammo at.
|
||||
/// </summary>
|
||||
public EntityCoordinates Coordinates;
|
||||
|
||||
public TakeAmmoEvent(int shots, List<IShootable> ammo, EntityCoordinates coordinates, EntityUid? user)
|
||||
public TakeAmmoEvent(int shots, List<(EntityUid? Entity, IShootable Shootable)> ammo, EntityCoordinates coordinates, EntityUid? user)
|
||||
{
|
||||
Shots = shots;
|
||||
Ammo = ammo;
|
||||
|
||||
@@ -8,7 +8,6 @@ using Robust.Shared.Containers;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Shared.Weapons.Ranged.Systems;
|
||||
|
||||
@@ -32,22 +31,24 @@ public abstract partial class SharedGunSystem
|
||||
|
||||
private void OnBallisticUse(EntityUid uid, BallisticAmmoProviderComponent component, UseInHandEvent args)
|
||||
{
|
||||
ManualCycle(component, Transform(uid).MapPosition, args.User);
|
||||
ManualCycle(uid, component, Transform(uid).MapPosition, args.User);
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private void OnBallisticInteractUsing(EntityUid uid, BallisticAmmoProviderComponent component, InteractUsingEvent args)
|
||||
{
|
||||
if (args.Handled || component.Whitelist?.IsValid(args.Used, EntityManager) != true) return;
|
||||
if (args.Handled || component.Whitelist?.IsValid(args.Used, EntityManager) != true)
|
||||
return;
|
||||
|
||||
if (GetBallisticShots(component) >= component.Capacity) return;
|
||||
if (GetBallisticShots(component) >= component.Capacity)
|
||||
return;
|
||||
|
||||
component.Entities.Add(args.Used);
|
||||
component.Container.Insert(args.Used);
|
||||
// Not predicted so
|
||||
Audio.PlayPredicted(component.SoundInsert, uid, args.User);
|
||||
args.Handled = true;
|
||||
UpdateBallisticAppearance(component);
|
||||
UpdateBallisticAppearance(uid, component);
|
||||
Dirty(component);
|
||||
}
|
||||
|
||||
@@ -93,20 +94,20 @@ public abstract partial class SharedGunSystem
|
||||
RaiseLocalEvent(ammoProvider, evInsert);
|
||||
}
|
||||
|
||||
List<IShootable> ammo = new();
|
||||
List<(EntityUid? Entity, IShootable Shootable)> ammo = new();
|
||||
var evTakeAmmo = new TakeAmmoEvent(1, ammo, Transform(args.Used).Coordinates, args.User);
|
||||
RaiseLocalEvent(args.Used, evTakeAmmo);
|
||||
|
||||
foreach (var shot in ammo)
|
||||
foreach (var (ent, _) in ammo)
|
||||
{
|
||||
if (shot is not AmmoComponent cast)
|
||||
if (ent == null)
|
||||
continue;
|
||||
|
||||
if (!targetComponent.Whitelist.IsValid(cast.Owner))
|
||||
if (!targetComponent.Whitelist.IsValid(ent.Value))
|
||||
{
|
||||
Popup(
|
||||
Loc.GetString("gun-ballistic-transfer-invalid",
|
||||
("ammoEntity", cast.Owner),
|
||||
("ammoEntity", ent.Value),
|
||||
("targetEntity", args.Target.Value)),
|
||||
args.Used,
|
||||
args.User);
|
||||
@@ -114,27 +115,28 @@ public abstract partial class SharedGunSystem
|
||||
// TODO: For better or worse, this will play a sound, but it's the
|
||||
// more future-proof thing to do than copying the same code
|
||||
// that OnBallisticInteractUsing has, sans sound.
|
||||
SimulateInsertAmmo(cast.Owner, args.Used, Transform(args.Used).Coordinates);
|
||||
SimulateInsertAmmo(ent.Value, args.Used, Transform(args.Used).Coordinates);
|
||||
}
|
||||
else
|
||||
{
|
||||
SimulateInsertAmmo(cast.Owner, args.Target.Value, Transform(args.Target.Value).Coordinates);
|
||||
SimulateInsertAmmo(ent.Value, args.Target.Value, Transform(args.Target.Value).Coordinates);
|
||||
}
|
||||
|
||||
if (cast.Owner.IsClientSide())
|
||||
Del(cast.Owner);
|
||||
if (ent.Value.IsClientSide())
|
||||
Del(ent.Value);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnBallisticVerb(EntityUid uid, BallisticAmmoProviderComponent component, GetVerbsEvent<Verb> args)
|
||||
{
|
||||
if (!args.CanAccess || !args.CanInteract || args.Hands == null) return;
|
||||
if (!args.CanAccess || !args.CanInteract || args.Hands == null)
|
||||
return;
|
||||
|
||||
args.Verbs.Add(new Verb()
|
||||
{
|
||||
Text = Loc.GetString("gun-ballistic-cycle"),
|
||||
Disabled = GetBallisticShots(component) == 0,
|
||||
Act = () => ManualCycle(component, Transform(uid).MapPosition, args.User),
|
||||
Act = () => ManualCycle(uid, component, Transform(uid).MapPosition, args.User),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -146,17 +148,17 @@ public abstract partial class SharedGunSystem
|
||||
args.PushMarkup(Loc.GetString("gun-magazine-examine", ("color", AmmoExamineColor), ("count", GetBallisticShots(component))));
|
||||
}
|
||||
|
||||
private void ManualCycle(BallisticAmmoProviderComponent component, MapCoordinates coordinates, EntityUid? user = null)
|
||||
private void ManualCycle(EntityUid uid, BallisticAmmoProviderComponent component, MapCoordinates coordinates, EntityUid? user = null, GunComponent? gunComp = null)
|
||||
{
|
||||
// Reset shotting for cycling
|
||||
if (TryComp<GunComponent>(component.Owner, out var gunComp) &&
|
||||
if (Resolve(uid, ref gunComp, false) &&
|
||||
gunComp is { FireRate: > 0f })
|
||||
{
|
||||
gunComp.NextFire = Timing.CurTime + TimeSpan.FromSeconds(1 / gunComp.FireRate);
|
||||
}
|
||||
|
||||
Dirty(component);
|
||||
Audio.PlayPredicted(component.SoundRack, component.Owner, user);
|
||||
Audio.PlayPredicted(component.SoundRack, uid, user);
|
||||
|
||||
var shots = GetBallisticShots(component);
|
||||
component.Cycled = true;
|
||||
@@ -165,9 +167,9 @@ public abstract partial class SharedGunSystem
|
||||
|
||||
var text = Loc.GetString(shots == 0 ? "gun-ballistic-cycled-empty" : "gun-ballistic-cycled");
|
||||
|
||||
Popup(text, component.Owner, user);
|
||||
UpdateBallisticAppearance(component);
|
||||
UpdateAmmoCount(component.Owner);
|
||||
Popup(text, uid, user);
|
||||
UpdateBallisticAppearance(uid, component);
|
||||
UpdateAmmoCount(uid);
|
||||
}
|
||||
|
||||
protected abstract void Cycle(BallisticAmmoProviderComponent component, MapCoordinates coordinates);
|
||||
@@ -184,7 +186,8 @@ public abstract partial class SharedGunSystem
|
||||
|
||||
private void OnBallisticHandleState(EntityUid uid, BallisticAmmoProviderComponent component, ref ComponentHandleState args)
|
||||
{
|
||||
if (args.Current is not BallisticAmmoProviderComponentState state) return;
|
||||
if (args.Current is not BallisticAmmoProviderComponentState state)
|
||||
return;
|
||||
|
||||
component.Cycled = state.Cycled;
|
||||
component.UnspawnedCount = state.UnspawnedCount;
|
||||
@@ -222,7 +225,8 @@ public abstract partial class SharedGunSystem
|
||||
{
|
||||
for (var i = 0; i < args.Shots; i++)
|
||||
{
|
||||
if (!component.Cycled) break;
|
||||
if (!component.Cycled)
|
||||
break;
|
||||
|
||||
EntityUid entity;
|
||||
|
||||
@@ -230,7 +234,7 @@ public abstract partial class SharedGunSystem
|
||||
{
|
||||
entity = component.Entities[^1];
|
||||
|
||||
args.Ammo.Add(EnsureComp<AmmoComponent>(entity));
|
||||
args.Ammo.Add((entity, EnsureComp<AmmoComponent>(entity)));
|
||||
|
||||
// Leave the entity as is if it doesn't auto cycle
|
||||
// TODO: Suss this out with NewAmmoComponent as I don't think it gets removed from container properly
|
||||
@@ -246,7 +250,7 @@ public abstract partial class SharedGunSystem
|
||||
{
|
||||
component.UnspawnedCount--;
|
||||
entity = Spawn(component.FillProto, args.Coordinates);
|
||||
args.Ammo.Add(EnsureComp<AmmoComponent>(entity));
|
||||
args.Ammo.Add((entity, EnsureComp<AmmoComponent>(entity)));
|
||||
|
||||
// Put it back in if it doesn't auto-cycle
|
||||
if (HasComp<CartridgeAmmoComponent>(entity) && !component.AutoCycle)
|
||||
@@ -269,7 +273,7 @@ public abstract partial class SharedGunSystem
|
||||
}
|
||||
}
|
||||
|
||||
UpdateBallisticAppearance(component);
|
||||
UpdateBallisticAppearance(uid, component);
|
||||
Dirty(component);
|
||||
}
|
||||
|
||||
@@ -279,13 +283,13 @@ public abstract partial class SharedGunSystem
|
||||
args.Capacity = component.Capacity;
|
||||
}
|
||||
|
||||
private void UpdateBallisticAppearance(BallisticAmmoProviderComponent component)
|
||||
private void UpdateBallisticAppearance(EntityUid uid, BallisticAmmoProviderComponent component)
|
||||
{
|
||||
if (!Timing.IsFirstTimePredicted || !TryComp<AppearanceComponent>(component.Owner, out var appearance))
|
||||
if (!Timing.IsFirstTimePredicted || !TryComp<AppearanceComponent>(uid, out var appearance))
|
||||
return;
|
||||
|
||||
Appearance.SetData(appearance.Owner, AmmoVisuals.AmmoCount, GetBallisticShots(component), appearance);
|
||||
Appearance.SetData(appearance.Owner, AmmoVisuals.AmmoMax, component.Capacity, appearance);
|
||||
Appearance.SetData(uid, AmmoVisuals.AmmoCount, GetBallisticShots(component), appearance);
|
||||
Appearance.SetData(uid, AmmoVisuals.AmmoMax, component.Capacity, appearance);
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
|
||||
@@ -38,7 +38,7 @@ public abstract partial class SharedGunSystem
|
||||
Dirty(component);
|
||||
}
|
||||
|
||||
UpdateBasicEntityAppearance(component);
|
||||
UpdateBasicEntityAppearance(uid, component);
|
||||
}
|
||||
|
||||
private void OnBasicEntityTakeAmmo(EntityUid uid, BasicEntityAmmoProviderComponent component, TakeAmmoEvent args)
|
||||
@@ -54,10 +54,10 @@ public abstract partial class SharedGunSystem
|
||||
}
|
||||
|
||||
var ent = Spawn(component.Proto, args.Coordinates);
|
||||
args.Ammo.Add(EnsureComp<AmmoComponent>(ent));
|
||||
args.Ammo.Add((ent, EnsureComp<AmmoComponent>(ent)));
|
||||
}
|
||||
|
||||
UpdateBasicEntityAppearance(component);
|
||||
UpdateBasicEntityAppearance(uid, component);
|
||||
Dirty(component);
|
||||
}
|
||||
|
||||
@@ -67,13 +67,14 @@ public abstract partial class SharedGunSystem
|
||||
args.Count = component.Count ?? int.MaxValue;
|
||||
}
|
||||
|
||||
private void UpdateBasicEntityAppearance(BasicEntityAmmoProviderComponent component)
|
||||
private void UpdateBasicEntityAppearance(EntityUid uid, BasicEntityAmmoProviderComponent component)
|
||||
{
|
||||
if (!Timing.IsFirstTimePredicted || !TryComp<AppearanceComponent>(component.Owner, out var appearance)) return;
|
||||
if (!Timing.IsFirstTimePredicted || !TryComp<AppearanceComponent>(uid, out var appearance))
|
||||
return;
|
||||
|
||||
Appearance.SetData(appearance.Owner, AmmoVisuals.HasAmmo, component.Count != 0, appearance);
|
||||
Appearance.SetData(appearance.Owner, AmmoVisuals.AmmoCount, component.Count ?? int.MaxValue, appearance);
|
||||
Appearance.SetData(appearance.Owner, AmmoVisuals.AmmoMax, component.Capacity ?? int.MaxValue, appearance);
|
||||
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);
|
||||
}
|
||||
|
||||
#region Public API
|
||||
@@ -88,7 +89,7 @@ public abstract partial class SharedGunSystem
|
||||
|
||||
component.Count = count;
|
||||
Dirty(component);
|
||||
UpdateBasicEntityAppearance(component);
|
||||
UpdateBasicEntityAppearance(uid, component);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -29,7 +29,8 @@ public abstract partial class SharedGunSystem
|
||||
|
||||
private void OnBatteryHandleState(EntityUid uid, BatteryAmmoProviderComponent component, ref ComponentHandleState args)
|
||||
{
|
||||
if (args.Current is not BatteryAmmoProviderComponentState state) return;
|
||||
if (args.Current is not BatteryAmmoProviderComponentState state)
|
||||
return;
|
||||
|
||||
component.Shots = state.Shots;
|
||||
component.Capacity = state.MaxShots;
|
||||
@@ -56,7 +57,8 @@ public abstract partial class SharedGunSystem
|
||||
var shots = Math.Min(args.Shots, component.Shots);
|
||||
|
||||
// Don't dirty if it's an empty fire.
|
||||
if (shots == 0) return;
|
||||
if (shots == 0)
|
||||
return;
|
||||
|
||||
for (var i = 0; i < shots; i++)
|
||||
{
|
||||
@@ -90,15 +92,15 @@ public abstract partial class SharedGunSystem
|
||||
Appearance.SetData(uid, AmmoVisuals.AmmoMax, component.Capacity, appearance);
|
||||
}
|
||||
|
||||
private IShootable GetShootable(BatteryAmmoProviderComponent component, EntityCoordinates coordinates)
|
||||
private (EntityUid? Entity, IShootable) GetShootable(BatteryAmmoProviderComponent component, EntityCoordinates coordinates)
|
||||
{
|
||||
switch (component)
|
||||
{
|
||||
case ProjectileBatteryAmmoProviderComponent proj:
|
||||
var ent = Spawn(proj.Prototype, coordinates);
|
||||
return EnsureComp<AmmoComponent>(ent);
|
||||
return (ent, EnsureComp<AmmoComponent>(ent));
|
||||
case HitscanBatteryAmmoProviderComponent hitscan:
|
||||
return ProtoManager.Index<HitscanPrototype>(hitscan.Prototype);
|
||||
return (null, ProtoManager.Index<HitscanPrototype>(hitscan.Prototype));
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
@@ -14,7 +14,9 @@ public abstract partial class SharedGunSystem
|
||||
|
||||
private void OnCartridgeHandleState(EntityUid uid, CartridgeAmmoComponent component, ref ComponentHandleState args)
|
||||
{
|
||||
if (args.Current is not CartridgeAmmoComponentState state) return;
|
||||
if (args.Current is not CartridgeAmmoComponentState state)
|
||||
return;
|
||||
|
||||
component.Spent = state.Spent;
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ public abstract partial class SharedGunSystem
|
||||
if (!args.IsInDetailsRange)
|
||||
return;
|
||||
|
||||
var (count, _) = GetChamberMagazineCountCapacity(component);
|
||||
var (count, _) = GetChamberMagazineCountCapacity(uid, component);
|
||||
args.PushMarkup(Loc.GetString("gun-magazine-examine", ("color", AmmoExamineColor), ("count", count)));
|
||||
}
|
||||
|
||||
@@ -41,7 +41,9 @@ public abstract partial class SharedGunSystem
|
||||
}
|
||||
|
||||
entity = slot.ContainedEntity;
|
||||
if (entity == null) return false;
|
||||
if (entity == null)
|
||||
return false;
|
||||
|
||||
container.Remove(entity.Value);
|
||||
return true;
|
||||
}
|
||||
@@ -57,10 +59,10 @@ public abstract partial class SharedGunSystem
|
||||
return slot.ContainedEntity;
|
||||
}
|
||||
|
||||
protected (int, int) GetChamberMagazineCountCapacity(ChamberMagazineAmmoProviderComponent component)
|
||||
protected (int, int) GetChamberMagazineCountCapacity(EntityUid uid, ChamberMagazineAmmoProviderComponent component)
|
||||
{
|
||||
var count = GetChamberEntity(component.Owner) != null ? 1 : 0;
|
||||
var (magCount, magCapacity) = GetMagazineCountCapacity(component);
|
||||
var count = GetChamberEntity(uid) != null ? 1 : 0;
|
||||
var (magCount, magCapacity) = GetMagazineCountCapacity(uid, component);
|
||||
return (count + magCount, magCapacity);
|
||||
}
|
||||
|
||||
@@ -81,7 +83,7 @@ public abstract partial class SharedGunSystem
|
||||
|
||||
if (TryTakeChamberEntity(uid, out var chamberEnt))
|
||||
{
|
||||
args.Ammo.Add(EnsureComp<AmmoComponent>(chamberEnt.Value));
|
||||
args.Ammo.Add((chamberEnt.Value, EnsureComp<AmmoComponent>(chamberEnt.Value)));
|
||||
}
|
||||
|
||||
var magEnt = GetMagazineEntity(uid);
|
||||
@@ -90,15 +92,15 @@ public abstract partial class SharedGunSystem
|
||||
if (magEnt != null)
|
||||
{
|
||||
// We pass in Shots not Shots - 1 as we'll take the last entity and move it into the chamber.
|
||||
var relayedArgs = new TakeAmmoEvent(args.Shots, new List<IShootable>(), args.Coordinates, args.User);
|
||||
RaiseLocalEvent(magEnt.Value, relayedArgs, false);
|
||||
var relayedArgs = new TakeAmmoEvent(args.Shots, new List<(EntityUid? Entity, IShootable Shootable)>(), args.Coordinates, args.User);
|
||||
RaiseLocalEvent(magEnt.Value, relayedArgs);
|
||||
|
||||
// Put in the nth slot back into the chamber
|
||||
// Rest of the ammo gets shot
|
||||
if (relayedArgs.Ammo.Count > 0)
|
||||
{
|
||||
var newChamberEnt = ((AmmoComponent) relayedArgs.Ammo[^1]).Owner;
|
||||
TryInsertChamber(uid, newChamberEnt);
|
||||
var newChamberEnt = relayedArgs.Ammo[^1].Entity;
|
||||
TryInsertChamber(uid, newChamberEnt!.Value);
|
||||
}
|
||||
|
||||
// Anything above the chamber-refill amount gets fired.
|
||||
@@ -117,7 +119,7 @@ public abstract partial class SharedGunSystem
|
||||
const int capacity = 1;
|
||||
|
||||
var ammoEv = new GetAmmoCountEvent();
|
||||
RaiseLocalEvent(magEnt.Value, ref ammoEv, false);
|
||||
RaiseLocalEvent(magEnt.Value, ref ammoEv);
|
||||
|
||||
FinaliseMagazineTakeAmmo(uid, component, args, count + ammoEv.Count, capacity + ammoEv.Capacity, appearance);
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ public partial class SharedGunSystem
|
||||
if (_netMan.IsServer)
|
||||
container.Remove(ent);
|
||||
|
||||
args.Ammo.Add(EnsureComp<AmmoComponent>(ent));
|
||||
args.Ammo.Add((ent, EnsureComp<AmmoComponent>(ent)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ public abstract partial class SharedGunSystem
|
||||
|
||||
AlternativeVerb verb = new()
|
||||
{
|
||||
Act = () => SelectFire(component, nextMode, args.User),
|
||||
Act = () => SelectFire(uid, component, nextMode, args.User),
|
||||
Text = Loc.GetString("gun-selector-verb", ("mode", GetLocSelector(nextMode))),
|
||||
Icon = new SpriteSpecifier.Texture(new ResourcePath("/Textures/Interface/VerbIcons/fold.svg.192dpi.png")),
|
||||
};
|
||||
@@ -47,7 +47,9 @@ public abstract partial class SharedGunSystem
|
||||
|
||||
foreach (var mode in Enum.GetValues<SelectiveFire>())
|
||||
{
|
||||
if ((mode & component.AvailableModes) == 0x0) continue;
|
||||
if ((mode & component.AvailableModes) == 0x0)
|
||||
continue;
|
||||
|
||||
modes.Add(mode);
|
||||
}
|
||||
|
||||
@@ -55,9 +57,10 @@ public abstract partial class SharedGunSystem
|
||||
return modes[(index + 1) % modes.Count];
|
||||
}
|
||||
|
||||
private void SelectFire(GunComponent component, SelectiveFire fire, EntityUid? user = null)
|
||||
private void SelectFire(EntityUid uid, GunComponent component, SelectiveFire fire, EntityUid? user = null)
|
||||
{
|
||||
if (component.SelectedMode == fire) return;
|
||||
if (component.SelectedMode == fire)
|
||||
return;
|
||||
|
||||
DebugTools.Assert((component.AvailableModes & fire) != 0x0);
|
||||
component.SelectedMode = fire;
|
||||
@@ -69,22 +72,23 @@ public abstract partial class SharedGunSystem
|
||||
else
|
||||
component.NextFire += cooldown;
|
||||
|
||||
Audio.PlayPredicted(component.SoundModeToggle, component.Owner, user);
|
||||
Popup(Loc.GetString("gun-selected-mode", ("mode", GetLocSelector(fire))), component.Owner, user);
|
||||
Audio.PlayPredicted(component.SoundModeToggle, uid, user);
|
||||
Popup(Loc.GetString("gun-selected-mode", ("mode", GetLocSelector(fire))), uid, user);
|
||||
Dirty(component);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cycles the gun's <see cref="SelectiveFire"/> to the next available one.
|
||||
/// </summary>
|
||||
public void CycleFire(GunComponent component, EntityUid? user = null)
|
||||
public void CycleFire(EntityUid uid, GunComponent component, EntityUid? user = null)
|
||||
{
|
||||
// Noop
|
||||
if (component.SelectedMode == component.AvailableModes) return;
|
||||
if (component.SelectedMode == component.AvailableModes)
|
||||
return;
|
||||
|
||||
DebugTools.Assert((component.AvailableModes & component.SelectedMode) == component.SelectedMode);
|
||||
var nextMode = GetNextMode(component);
|
||||
SelectFire(component, nextMode, user);
|
||||
SelectFire(uid, component, nextMode, user);
|
||||
}
|
||||
|
||||
// TODO: Actions need doing for guns anyway.
|
||||
@@ -95,6 +99,6 @@ public abstract partial class SharedGunSystem
|
||||
|
||||
private void OnCycleMode(EntityUid uid, GunComponent component, CycleModeEvent args)
|
||||
{
|
||||
SelectFire(component, args.Mode, args.Performer);
|
||||
SelectFire(uid, component, args.Mode, args.Performer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ public abstract partial class SharedGunSystem
|
||||
if (!args.IsInDetailsRange)
|
||||
return;
|
||||
|
||||
var (count, _) = GetMagazineCountCapacity(component);
|
||||
var (count, _) = GetMagazineCountCapacity(uid, component);
|
||||
args.PushMarkup(Loc.GetString("gun-magazine-examine", ("color", AmmoExamineColor), ("count", count)));
|
||||
}
|
||||
|
||||
@@ -34,23 +34,25 @@ public abstract partial class SharedGunSystem
|
||||
{
|
||||
var magEnt = GetMagazineEntity(uid);
|
||||
|
||||
if (magEnt == null) return;
|
||||
if (magEnt == null)
|
||||
return;
|
||||
|
||||
RaiseLocalEvent(magEnt.Value, args);
|
||||
UpdateAmmoCount(uid);
|
||||
UpdateMagazineAppearance(component, magEnt.Value);
|
||||
UpdateMagazineAppearance(uid, component, magEnt.Value);
|
||||
}
|
||||
|
||||
private void OnMagazineVerb(EntityUid uid, MagazineAmmoProviderComponent component, GetVerbsEvent<AlternativeVerb> args)
|
||||
{
|
||||
if (!args.CanInteract || !args.CanAccess) return;
|
||||
if (!args.CanInteract || !args.CanAccess)
|
||||
return;
|
||||
|
||||
var magEnt = GetMagazineEntity(uid);
|
||||
|
||||
if (magEnt != null)
|
||||
{
|
||||
RaiseLocalEvent(magEnt.Value, args);
|
||||
UpdateMagazineAppearance(component, magEnt.Value);
|
||||
UpdateMagazineAppearance(magEnt.Value, component, magEnt.Value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,11 +68,11 @@ public abstract partial class SharedGunSystem
|
||||
Appearance.SetData(uid, AmmoVisuals.MagLoaded, GetMagazineEntity(uid) != null, appearance);
|
||||
}
|
||||
|
||||
protected (int, int) GetMagazineCountCapacity(MagazineAmmoProviderComponent component)
|
||||
protected (int, int) GetMagazineCountCapacity(EntityUid uid, MagazineAmmoProviderComponent component)
|
||||
{
|
||||
var count = 0;
|
||||
var capacity = 1;
|
||||
var magEnt = GetMagazineEntity(component.Owner);
|
||||
var magEnt = GetMagazineEntity(uid);
|
||||
|
||||
if (magEnt != null)
|
||||
{
|
||||
@@ -86,7 +88,11 @@ public abstract partial class SharedGunSystem
|
||||
protected EntityUid? GetMagazineEntity(EntityUid uid)
|
||||
{
|
||||
if (!Containers.TryGetContainer(uid, MagazineSlot, out var container) ||
|
||||
container is not ContainerSlot slot) return null;
|
||||
container is not ContainerSlot slot)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return slot.ContainedEntity;
|
||||
}
|
||||
|
||||
@@ -102,11 +108,11 @@ public abstract partial class SharedGunSystem
|
||||
}
|
||||
|
||||
// Pass the event onwards.
|
||||
RaiseLocalEvent(magEntity.Value, args, false);
|
||||
RaiseLocalEvent(magEntity.Value, args);
|
||||
// Should be Dirtied by what other ammoprovider is handling it.
|
||||
|
||||
var ammoEv = new GetAmmoCountEvent();
|
||||
RaiseLocalEvent(magEntity.Value, ref ammoEv, false);
|
||||
RaiseLocalEvent(magEntity.Value, ref ammoEv);
|
||||
FinaliseMagazineTakeAmmo(uid, component, args, ammoEv.Count, ammoEv.Capacity, appearance);
|
||||
}
|
||||
|
||||
@@ -115,23 +121,23 @@ public abstract partial class SharedGunSystem
|
||||
// If no ammo then check for autoeject
|
||||
if (component.AutoEject && args.Ammo.Count == 0)
|
||||
{
|
||||
EjectMagazine(component);
|
||||
EjectMagazine(uid, component);
|
||||
Audio.PlayPredicted(component.SoundAutoEject, uid, args.User);
|
||||
}
|
||||
|
||||
UpdateMagazineAppearance(appearance, true, count, capacity);
|
||||
UpdateMagazineAppearance(uid, appearance, true, count, capacity);
|
||||
}
|
||||
|
||||
private void UpdateMagazineAppearance(MagazineAmmoProviderComponent component, EntityUid magEnt)
|
||||
private void UpdateMagazineAppearance(EntityUid uid, MagazineAmmoProviderComponent component, EntityUid magEnt)
|
||||
{
|
||||
TryComp<AppearanceComponent>(component.Owner, out var appearance);
|
||||
TryComp<AppearanceComponent>(uid, out var appearance);
|
||||
|
||||
var count = 0;
|
||||
var capacity = 0;
|
||||
|
||||
if (component is ChamberMagazineAmmoProviderComponent chamber)
|
||||
{
|
||||
count = GetChamberEntity(chamber.Owner) != null ? 1 : 0;
|
||||
count = GetChamberEntity(uid) != null ? 1 : 0;
|
||||
capacity = 1;
|
||||
}
|
||||
|
||||
@@ -143,27 +149,28 @@ public abstract partial class SharedGunSystem
|
||||
capacity += addCapacity;
|
||||
}
|
||||
|
||||
UpdateMagazineAppearance(appearance, true, count, capacity);
|
||||
UpdateMagazineAppearance(uid, appearance, true, count, capacity);
|
||||
}
|
||||
|
||||
private void UpdateMagazineAppearance(AppearanceComponent? appearance, bool magLoaded, int count, int capacity)
|
||||
private void UpdateMagazineAppearance(EntityUid uid, AppearanceComponent? appearance, bool magLoaded, int count, int capacity)
|
||||
{
|
||||
if (appearance == null)
|
||||
return;
|
||||
|
||||
// Copy the magazine's appearance data
|
||||
Appearance.SetData(appearance.Owner, AmmoVisuals.MagLoaded, magLoaded, appearance);
|
||||
Appearance.SetData(appearance.Owner, AmmoVisuals.HasAmmo, count != 0, appearance);
|
||||
Appearance.SetData(appearance.Owner, AmmoVisuals.AmmoCount, count, appearance);
|
||||
Appearance.SetData(appearance.Owner, AmmoVisuals.AmmoMax, capacity, appearance);
|
||||
Appearance.SetData(uid, AmmoVisuals.MagLoaded, magLoaded, appearance);
|
||||
Appearance.SetData(uid, AmmoVisuals.HasAmmo, count != 0, appearance);
|
||||
Appearance.SetData(uid, AmmoVisuals.AmmoCount, count, appearance);
|
||||
Appearance.SetData(uid, AmmoVisuals.AmmoMax, capacity, appearance);
|
||||
}
|
||||
|
||||
private void EjectMagazine(MagazineAmmoProviderComponent component)
|
||||
private void EjectMagazine(EntityUid uid, MagazineAmmoProviderComponent component)
|
||||
{
|
||||
var ent = GetMagazineEntity(component.Owner);
|
||||
var ent = GetMagazineEntity(uid);
|
||||
|
||||
if (ent == null) return;
|
||||
if (ent == null)
|
||||
return;
|
||||
|
||||
_slots.TryEject(component.Owner, MagazineSlot, null, out var a, excludeUserAudio: true);
|
||||
_slots.TryEject(uid, MagazineSlot, null, out var a, excludeUserAudio: true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,9 +34,10 @@ public partial class SharedGunSystem
|
||||
|
||||
private void OnRevolverInteractUsing(EntityUid uid, RevolverAmmoProviderComponent component, InteractUsingEvent args)
|
||||
{
|
||||
if (args.Handled) return;
|
||||
if (args.Handled)
|
||||
return;
|
||||
|
||||
if (TryRevolverInsert(component, args.Used, args.User))
|
||||
if (TryRevolverInsert(uid, component, args.Used, args.User))
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
@@ -52,7 +53,8 @@ public partial class SharedGunSystem
|
||||
|
||||
private void OnRevolverHandleState(EntityUid uid, RevolverAmmoProviderComponent component, ref ComponentHandleState args)
|
||||
{
|
||||
if (args.Current is not RevolverAmmoProviderComponentState state) return;
|
||||
if (args.Current is not RevolverAmmoProviderComponentState state)
|
||||
return;
|
||||
|
||||
var oldIndex = component.CurrentIndex;
|
||||
component.CurrentIndex = state.CurrentIndex;
|
||||
@@ -73,7 +75,7 @@ public partial class SharedGunSystem
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryRevolverInsert(RevolverAmmoProviderComponent component, EntityUid uid, EntityUid? user)
|
||||
public bool TryRevolverInsert(EntityUid revolverUid, RevolverAmmoProviderComponent component, EntityUid uid, EntityUid? user)
|
||||
{
|
||||
if (component.Whitelist?.IsValid(uid, EntityManager) == false)
|
||||
return false;
|
||||
@@ -93,19 +95,19 @@ public partial class SharedGunSystem
|
||||
|
||||
if (freeSlots == 0)
|
||||
{
|
||||
Popup(Loc.GetString("gun-revolver-full"), component.Owner, user);
|
||||
Popup(Loc.GetString("gun-revolver-full"), revolverUid, user);
|
||||
return false;
|
||||
}
|
||||
|
||||
var xformQuery = GetEntityQuery<TransformComponent>();
|
||||
var xform = xformQuery.GetComponent(uid);
|
||||
var ammo = new List<IShootable>(freeSlots);
|
||||
var ammo = new List<(EntityUid? Entity, IShootable Shootable)>(freeSlots);
|
||||
var ev = new TakeAmmoEvent(freeSlots, ammo, xform.Coordinates, user);
|
||||
RaiseLocalEvent(uid, ev);
|
||||
|
||||
if (ev.Ammo.Count == 0)
|
||||
{
|
||||
Popup(Loc.GetString("gun-speedloader-empty"), component.Owner, user);
|
||||
Popup(Loc.GetString("gun-speedloader-empty"), revolverUid, user);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -119,29 +121,29 @@ public partial class SharedGunSystem
|
||||
continue;
|
||||
}
|
||||
|
||||
var ent = ev.Ammo.Last();
|
||||
var ent = ev.Ammo.Last().Entity;
|
||||
ev.Ammo.RemoveAt(ev.Ammo.Count - 1);
|
||||
|
||||
if (ent is not AmmoComponent ammoComp)
|
||||
if (ent == null)
|
||||
{
|
||||
Sawmill.Error($"Tried to load hitscan into a revolver which is unsupported");
|
||||
continue;
|
||||
}
|
||||
|
||||
component.AmmoSlots[index] = ammoComp.Owner;
|
||||
component.AmmoContainer.Insert(ammoComp.Owner, EntityManager);
|
||||
component.AmmoSlots[index] = ent.Value;
|
||||
component.AmmoContainer.Insert(ent.Value, EntityManager);
|
||||
|
||||
if (ev.Ammo.Count == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
DebugTools.Assert(ammo.Count == 0);
|
||||
UpdateRevolverAppearance(component);
|
||||
UpdateRevolverAppearance(revolverUid, component);
|
||||
UpdateAmmoCount(uid);
|
||||
Dirty(component);
|
||||
|
||||
Audio.PlayPredicted(component.SoundInsert, component.Owner, user);
|
||||
Popup(Loc.GetString("gun-revolver-insert"), component.Owner, user);
|
||||
Audio.PlayPredicted(component.SoundInsert, revolverUid, user);
|
||||
Popup(Loc.GetString("gun-revolver-insert"), revolverUid, user);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -151,30 +153,35 @@ public partial class SharedGunSystem
|
||||
var index = (component.CurrentIndex + i) % component.Capacity;
|
||||
|
||||
if (component.AmmoSlots[index] != null ||
|
||||
component.Chambers[index] != null) continue;
|
||||
component.Chambers[index] != null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
component.AmmoSlots[index] = uid;
|
||||
component.AmmoContainer.Insert(uid);
|
||||
Audio.PlayPredicted(component.SoundInsert, component.Owner, user);
|
||||
Popup(Loc.GetString("gun-revolver-insert"), component.Owner, user);
|
||||
UpdateRevolverAppearance(component);
|
||||
Audio.PlayPredicted(component.SoundInsert, revolverUid, user);
|
||||
Popup(Loc.GetString("gun-revolver-insert"), revolverUid, user);
|
||||
UpdateRevolverAppearance(revolverUid, component);
|
||||
UpdateAmmoCount(uid);
|
||||
Dirty(component);
|
||||
return true;
|
||||
}
|
||||
Popup(Loc.GetString("gun-revolver-full"), component.Owner, user);
|
||||
|
||||
Popup(Loc.GetString("gun-revolver-full"), revolverUid, user);
|
||||
return false;
|
||||
}
|
||||
|
||||
private void OnRevolverVerbs(EntityUid uid, RevolverAmmoProviderComponent component, GetVerbsEvent<AlternativeVerb> args)
|
||||
{
|
||||
if (!args.CanAccess || !args.CanInteract || args.Hands == null) return;
|
||||
if (!args.CanAccess || !args.CanInteract || args.Hands == null)
|
||||
return;
|
||||
|
||||
args.Verbs.Add(new AlternativeVerb()
|
||||
{
|
||||
Text = Loc.GetString("gun-revolver-empty"),
|
||||
Disabled = !AnyRevolverCartridges(component),
|
||||
Act = () => EmptyRevolver(component, args.User),
|
||||
Act = () => EmptyRevolver(uid, component, args.User),
|
||||
Priority = 1
|
||||
});
|
||||
|
||||
@@ -182,7 +189,7 @@ public partial class SharedGunSystem
|
||||
{
|
||||
Text = Loc.GetString("gun-revolver-spin"),
|
||||
// Category = VerbCategory.G,
|
||||
Act = () => SpinRevolver(component, args.User)
|
||||
Act = () => SpinRevolver(uid, component, args.User)
|
||||
});
|
||||
}
|
||||
|
||||
@@ -191,7 +198,10 @@ public partial class SharedGunSystem
|
||||
for (var i = 0; i < component.Capacity; i++)
|
||||
{
|
||||
if (component.Chambers[i] != null ||
|
||||
component.AmmoSlots[i] != null) return true;
|
||||
component.AmmoSlots[i] != null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -238,9 +248,9 @@ public partial class SharedGunSystem
|
||||
return count;
|
||||
}
|
||||
|
||||
public void EmptyRevolver(RevolverAmmoProviderComponent component, EntityUid? user = null)
|
||||
public void EmptyRevolver(EntityUid revolverUid, RevolverAmmoProviderComponent component, EntityUid? user = null)
|
||||
{
|
||||
var xform = Transform(component.Owner);
|
||||
var xform = Transform(revolverUid);
|
||||
var mapCoordinates = xform.MapPosition;
|
||||
var anyEmpty = false;
|
||||
|
||||
@@ -259,7 +269,7 @@ public partial class SharedGunSystem
|
||||
var uid = Spawn(component.FillPrototype, mapCoordinates);
|
||||
|
||||
if (TryComp<CartridgeAmmoComponent>(uid, out var cartridge))
|
||||
SetCartridgeSpent(cartridge, !(bool) chamber);
|
||||
SetCartridgeSpent(uid, cartridge, !(bool) chamber);
|
||||
|
||||
EjectCartridge(uid);
|
||||
}
|
||||
@@ -281,28 +291,28 @@ public partial class SharedGunSystem
|
||||
|
||||
if (anyEmpty)
|
||||
{
|
||||
Audio.PlayPredicted(component.SoundEject, component.Owner, user);
|
||||
UpdateAmmoCount(component.Owner);
|
||||
UpdateRevolverAppearance(component);
|
||||
Audio.PlayPredicted(component.SoundEject, revolverUid, user);
|
||||
UpdateAmmoCount(revolverUid);
|
||||
UpdateRevolverAppearance(revolverUid, component);
|
||||
Dirty(component);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateRevolverAppearance(RevolverAmmoProviderComponent component)
|
||||
private void UpdateRevolverAppearance(EntityUid uid, RevolverAmmoProviderComponent component)
|
||||
{
|
||||
if (!TryComp<AppearanceComponent>(component.Owner, out var appearance))
|
||||
if (!TryComp<AppearanceComponent>(uid, out var appearance))
|
||||
return;
|
||||
|
||||
var count = GetRevolverCount(component);
|
||||
Appearance.SetData(component.Owner, AmmoVisuals.HasAmmo, count != 0, appearance);
|
||||
Appearance.SetData(component.Owner, AmmoVisuals.AmmoCount, count, appearance);
|
||||
Appearance.SetData(component.Owner, AmmoVisuals.AmmoMax, component.Capacity, appearance);
|
||||
Appearance.SetData(uid, AmmoVisuals.HasAmmo, count != 0, appearance);
|
||||
Appearance.SetData(uid, AmmoVisuals.AmmoCount, count, appearance);
|
||||
Appearance.SetData(uid, AmmoVisuals.AmmoMax, component.Capacity, appearance);
|
||||
}
|
||||
|
||||
protected virtual void SpinRevolver(RevolverAmmoProviderComponent component, EntityUid? user = null)
|
||||
protected virtual void SpinRevolver(EntityUid revolverUid, RevolverAmmoProviderComponent component, EntityUid? user = null)
|
||||
{
|
||||
Audio.PlayPredicted(component.SoundSpin, component.Owner, user);
|
||||
Popup(Loc.GetString("gun-revolver-spun"), component.Owner, user);
|
||||
Audio.PlayPredicted(component.SoundSpin, revolverUid, user);
|
||||
Popup(Loc.GetString("gun-revolver-spun"), revolverUid, user);
|
||||
}
|
||||
|
||||
private void OnRevolverTakeAmmo(EntityUid uid, RevolverAmmoProviderComponent component, TakeAmmoEvent args)
|
||||
@@ -327,14 +337,15 @@ public partial class SharedGunSystem
|
||||
if (TryComp<CartridgeAmmoComponent>(ent, out var cartridge))
|
||||
{
|
||||
component.Chambers[index] = false;
|
||||
SetCartridgeSpent(cartridge, true);
|
||||
args.Ammo.Add(EnsureComp<AmmoComponent>(Spawn(cartridge.Prototype, args.Coordinates)));
|
||||
SetCartridgeSpent(ent, cartridge, true);
|
||||
var spawned = Spawn(cartridge.Prototype, args.Coordinates);
|
||||
args.Ammo.Add((spawned, EnsureComp<AmmoComponent>(spawned)));
|
||||
Del(ent);
|
||||
continue;
|
||||
}
|
||||
|
||||
component.Chambers[i] = null;
|
||||
args.Ammo.Add(EnsureComp<AmmoComponent>(ent));
|
||||
args.Ammo.Add((ent, EnsureComp<AmmoComponent>(ent)));
|
||||
}
|
||||
}
|
||||
else if (component.AmmoSlots[index] != null)
|
||||
@@ -343,21 +354,23 @@ public partial class SharedGunSystem
|
||||
|
||||
if (TryComp<CartridgeAmmoComponent>(ent, out var cartridge))
|
||||
{
|
||||
if (cartridge.Spent) continue;
|
||||
if (cartridge.Spent)
|
||||
continue;
|
||||
|
||||
SetCartridgeSpent(cartridge, true);
|
||||
args.Ammo.Add(EnsureComp<AmmoComponent>(Spawn(cartridge.Prototype, args.Coordinates)));
|
||||
SetCartridgeSpent(ent.Value, cartridge, true);
|
||||
var spawned = Spawn(cartridge.Prototype, args.Coordinates);
|
||||
args.Ammo.Add((spawned, EnsureComp<AmmoComponent>(spawned)));
|
||||
continue;
|
||||
}
|
||||
|
||||
component.AmmoContainer.Remove(ent.Value);
|
||||
component.AmmoSlots[index] = null;
|
||||
args.Ammo.Add(EnsureComp<AmmoComponent>(ent.Value));
|
||||
args.Ammo.Add((ent.Value, EnsureComp<AmmoComponent>(ent.Value)));
|
||||
Transform(ent.Value).Coordinates = args.Coordinates;
|
||||
}
|
||||
}
|
||||
|
||||
UpdateRevolverAppearance(component);
|
||||
UpdateRevolverAppearance(uid, component);
|
||||
Dirty(component);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Content.Shared.Actions;
|
||||
using Content.Shared.Administration.Logs;
|
||||
using Content.Shared.Audio;
|
||||
using Content.Shared.CombatMode;
|
||||
using Content.Shared.Containers.ItemSlots;
|
||||
using Content.Shared.Damage;
|
||||
@@ -22,7 +22,6 @@ using Robust.Shared.Map;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Physics.Systems;
|
||||
using Robust.Shared.Physics.Components;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Serialization;
|
||||
@@ -53,6 +52,7 @@ public abstract partial class SharedGunSystem : EntitySystem
|
||||
[Dependency] protected readonly SharedAudioSystem Audio = default!;
|
||||
[Dependency] private readonly SharedGravitySystem _gravity = default!;
|
||||
[Dependency] protected readonly SharedProjectileSystem Projectiles = default!;
|
||||
[Dependency] protected readonly SharedTransformSystem Transform = default!;
|
||||
|
||||
protected ISawmill Sawmill = default!;
|
||||
|
||||
@@ -107,27 +107,31 @@ public abstract partial class SharedGunSystem : EntitySystem
|
||||
{
|
||||
var user = args.SenderSession.AttachedEntity;
|
||||
|
||||
if (user == null) return;
|
||||
if (user == null ||
|
||||
!TryGetGun(user.Value, out var ent, out var gun))
|
||||
return;
|
||||
|
||||
var gun = GetGun(user.Value);
|
||||
|
||||
if (gun?.Owner != msg.Gun) return;
|
||||
if (ent != msg.Gun)
|
||||
return;
|
||||
|
||||
gun.ShootCoordinates = msg.Coordinates;
|
||||
Sawmill.Debug($"Set shoot coordinates to {gun.ShootCoordinates}");
|
||||
AttemptShoot(user.Value, gun);
|
||||
AttemptShoot(user.Value, ent, gun);
|
||||
}
|
||||
|
||||
private void OnStopShootRequest(RequestStopShootEvent ev, EntitySessionEventArgs args)
|
||||
{
|
||||
if (args.SenderSession.AttachedEntity == null ||
|
||||
!TryComp<GunComponent>(ev.Gun, out var gun)) return;
|
||||
!TryComp<GunComponent>(ev.Gun, out var gun) ||
|
||||
!TryGetGun(args.SenderSession.AttachedEntity.Value, out _, out var userGun))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var userGun = GetGun(args.SenderSession.AttachedEntity.Value);
|
||||
if (userGun != gun)
|
||||
return;
|
||||
|
||||
if (userGun != gun) return;
|
||||
|
||||
StopShooting(gun);
|
||||
StopShooting(ev.Gun, gun);
|
||||
}
|
||||
|
||||
private void OnGetState(EntityUid uid, GunComponent component, ref ComponentGetState args)
|
||||
@@ -147,7 +151,8 @@ public abstract partial class SharedGunSystem : EntitySystem
|
||||
|
||||
private void OnHandleState(EntityUid uid, GunComponent component, ref ComponentHandleState args)
|
||||
{
|
||||
if (args.Current is not GunComponentState state) return;
|
||||
if (args.Current is not GunComponentState state)
|
||||
return;
|
||||
|
||||
Sawmill.Debug($"Handle state: setting shot count from {component.ShotCounter} to {state.ShotCounter}");
|
||||
component.FireRate = state.FireRate;
|
||||
@@ -168,27 +173,40 @@ public abstract partial class SharedGunSystem : EntitySystem
|
||||
return true;
|
||||
}
|
||||
|
||||
public GunComponent? GetGun(EntityUid entity)
|
||||
public bool TryGetGun(EntityUid entity, out EntityUid gunEntity, [NotNullWhen(true)] out GunComponent? gunComp)
|
||||
{
|
||||
gunEntity = default;
|
||||
gunComp = null;
|
||||
|
||||
if (!_combatMode.IsInCombatMode(entity))
|
||||
return null;
|
||||
return false;
|
||||
|
||||
if (EntityManager.TryGetComponent(entity, out SharedHandsComponent? hands) &&
|
||||
hands.ActiveHandEntity is { } held &&
|
||||
TryComp(held, out GunComponent? gun))
|
||||
{
|
||||
return gun;
|
||||
gunEntity = held;
|
||||
gunComp = gun;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Last resort is check if the entity itself is a gun.
|
||||
return !TryComp(entity, out gun) ? null : gun;
|
||||
if (TryComp(entity, out gun))
|
||||
{
|
||||
gunEntity = entity;
|
||||
gunComp = gun;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void StopShooting(GunComponent gun)
|
||||
private void StopShooting(EntityUid uid, GunComponent gun)
|
||||
{
|
||||
if (gun.ShotCounter == 0) return;
|
||||
if (gun.ShotCounter == 0)
|
||||
return;
|
||||
|
||||
Sawmill.Debug($"Stopped shooting {ToPrettyString(gun.Owner)}");
|
||||
Sawmill.Debug($"Stopped shooting {ToPrettyString(uid)}");
|
||||
gun.ShotCounter = 0;
|
||||
gun.ShootCoordinates = null;
|
||||
Dirty(gun);
|
||||
@@ -197,14 +215,14 @@ public abstract partial class SharedGunSystem : EntitySystem
|
||||
/// <summary>
|
||||
/// Attempts to shoot at the target coordinates. Resets the shot counter after every shot.
|
||||
/// </summary>
|
||||
public void AttemptShoot(EntityUid user, GunComponent gun, EntityCoordinates toCoordinates)
|
||||
public void AttemptShoot(EntityUid user, EntityUid gunUid, GunComponent gun, EntityCoordinates toCoordinates)
|
||||
{
|
||||
gun.ShootCoordinates = toCoordinates;
|
||||
AttemptShoot(user, gun);
|
||||
AttemptShoot(user, gunUid, gun);
|
||||
gun.ShotCounter = 0;
|
||||
}
|
||||
|
||||
private void AttemptShoot(EntityUid user, GunComponent gun)
|
||||
private void AttemptShoot(EntityUid user, EntityUid gunUid, GunComponent gun)
|
||||
{
|
||||
if (gun.FireRate <= 0f)
|
||||
return;
|
||||
@@ -260,22 +278,22 @@ public abstract partial class SharedGunSystem : EntitySystem
|
||||
|
||||
var fromCoordinates = Transform(user).Coordinates;
|
||||
// Remove ammo
|
||||
var ev = new TakeAmmoEvent(shots, new List<IShootable>(), fromCoordinates, user);
|
||||
var ev = new TakeAmmoEvent(shots, new List<(EntityUid? Entity, IShootable Shootable)>(), fromCoordinates, user);
|
||||
|
||||
// Listen it just makes the other code around it easier if shots == 0 to do this.
|
||||
if (shots > 0)
|
||||
RaiseLocalEvent(gun.Owner, ev, false);
|
||||
RaiseLocalEvent(gunUid, ev);
|
||||
|
||||
DebugTools.Assert(ev.Ammo.Count <= shots);
|
||||
DebugTools.Assert(shots >= 0);
|
||||
UpdateAmmoCount(gun.Owner);
|
||||
UpdateAmmoCount(gunUid);
|
||||
|
||||
// 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;
|
||||
|
||||
var attemptEv = new AttemptShootEvent(user);
|
||||
RaiseLocalEvent(gun.Owner, ref attemptEv);
|
||||
RaiseLocalEvent(gunUid, ref attemptEv);
|
||||
|
||||
if (ev.Ammo.Count <= 0 || attemptEv.Cancelled)
|
||||
{
|
||||
@@ -286,7 +304,7 @@ 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, gun.Owner, user);
|
||||
Audio.PlayPredicted(gun.SoundEmpty, gunUid, user);
|
||||
Dirty(gun);
|
||||
return;
|
||||
}
|
||||
@@ -295,19 +313,20 @@ public abstract partial class SharedGunSystem : EntitySystem
|
||||
}
|
||||
|
||||
// Shoot confirmed - sounds also played here in case it's invalid (e.g. cartridge already spent).
|
||||
Shoot(gun, ev.Ammo, fromCoordinates, toCoordinates.Value, user);
|
||||
Shoot(gunUid, gun, ev.Ammo, fromCoordinates, toCoordinates.Value, user);
|
||||
var shotEv = new GunShotEvent(user);
|
||||
RaiseLocalEvent(gun.Owner, ref shotEv);
|
||||
RaiseLocalEvent(gunUid, ref shotEv);
|
||||
// Projectiles cause impulses especially important in non gravity environments
|
||||
if (TryComp<PhysicsComponent>(user, out var userPhysics))
|
||||
{
|
||||
if (_gravity.IsWeightless(user, userPhysics))
|
||||
CauseImpulse(fromCoordinates, toCoordinates.Value, userPhysics);
|
||||
CauseImpulse(fromCoordinates, toCoordinates.Value, user, userPhysics);
|
||||
}
|
||||
Dirty(gun);
|
||||
}
|
||||
|
||||
public void Shoot(
|
||||
EntityUid gunUid,
|
||||
GunComponent gun,
|
||||
EntityUid ammo,
|
||||
EntityCoordinates fromCoordinates,
|
||||
@@ -315,26 +334,17 @@ public abstract partial class SharedGunSystem : EntitySystem
|
||||
EntityUid? user = null)
|
||||
{
|
||||
var shootable = EnsureComp<AmmoComponent>(ammo);
|
||||
Shoot(gun, new List<IShootable>(1) { shootable }, fromCoordinates, toCoordinates, user);
|
||||
Shoot(gunUid, gun, new List<(EntityUid? Entity, IShootable Shootable)>(1) { (ammo, shootable) }, fromCoordinates, toCoordinates, user);
|
||||
}
|
||||
|
||||
public abstract void Shoot(
|
||||
EntityUid gunUid,
|
||||
GunComponent gun,
|
||||
List<IShootable> ammo,
|
||||
List<(EntityUid? Entity, IShootable Shootable)> ammo,
|
||||
EntityCoordinates fromCoordinates,
|
||||
EntityCoordinates toCoordinates,
|
||||
EntityUid? user = null);
|
||||
|
||||
public void Shoot(
|
||||
GunComponent gun,
|
||||
IShootable ammo,
|
||||
EntityCoordinates fromCoordinates,
|
||||
EntityCoordinates toCoordinates,
|
||||
EntityUid? user = null)
|
||||
{
|
||||
Shoot(gun, new List<IShootable>(1) { ammo }, fromCoordinates, toCoordinates, user);
|
||||
}
|
||||
|
||||
protected abstract void Popup(string message, EntityUid? uid, EntityUid? user);
|
||||
|
||||
/// <summary>
|
||||
@@ -342,13 +352,13 @@ public abstract partial class SharedGunSystem : EntitySystem
|
||||
/// </summary>
|
||||
protected virtual void UpdateAmmoCount(EntityUid uid) {}
|
||||
|
||||
protected void SetCartridgeSpent(CartridgeAmmoComponent cartridge, bool spent)
|
||||
protected void SetCartridgeSpent(EntityUid uid, CartridgeAmmoComponent cartridge, bool spent)
|
||||
{
|
||||
if (cartridge.Spent != spent)
|
||||
Dirty(cartridge);
|
||||
|
||||
cartridge.Spent = spent;
|
||||
Appearance.SetData(cartridge.Owner, AmmoVisuals.Spent, spent);
|
||||
Appearance.SetData(uid, AmmoVisuals.Spent, spent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -385,15 +395,15 @@ public abstract partial class SharedGunSystem : EntitySystem
|
||||
CreateEffect(gun, ev, user);
|
||||
}
|
||||
|
||||
public void CauseImpulse(EntityCoordinates fromCoordinates, EntityCoordinates toCoordinates, PhysicsComponent userPhysics)
|
||||
public void CauseImpulse(EntityCoordinates fromCoordinates, EntityCoordinates toCoordinates, EntityUid user, PhysicsComponent userPhysics)
|
||||
{
|
||||
var fromMap = fromCoordinates.ToMapPos(EntityManager);
|
||||
var toMap = toCoordinates.ToMapPos(EntityManager);
|
||||
var fromMap = fromCoordinates.ToMapPos(EntityManager, Transform);
|
||||
var toMap = toCoordinates.ToMapPos(EntityManager, Transform);
|
||||
var shotDirection = (toMap - fromMap).Normalized;
|
||||
|
||||
const float impulseStrength = 5.0f;
|
||||
var impulseVector = shotDirection * impulseStrength;
|
||||
Physics.ApplyLinearImpulse(userPhysics.Owner, -impulseVector, body: userPhysics);
|
||||
Physics.ApplyLinearImpulse(user, -impulseVector, body: userPhysics);
|
||||
}
|
||||
protected abstract void CreateEffect(EntityUid uid, MuzzleFlashEvent message, EntityUid? user = null);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user