diff --git a/Content.Server/Storage/Components/SpawnTableOnUseComponent.cs b/Content.Server/Storage/Components/SpawnTableOnUseComponent.cs new file mode 100644 index 00000000000000..a7cbac725439fa --- /dev/null +++ b/Content.Server/Storage/Components/SpawnTableOnUseComponent.cs @@ -0,0 +1,17 @@ +using Content.Server.Storage.EntitySystems; +using Content.Shared.EntityTable.EntitySelectors; + +namespace Content.Server.Storage.Components; + +/// +/// Spawns items from an entity table when used in hand. +/// +[RegisterComponent, Access(typeof(SpawnTableOnUseSystem))] +public sealed partial class SpawnTableOnUseComponent : Component +{ + /// + /// The entity table to select entities from. + /// + [DataField(required: true)] + public EntityTableSelector Table = default!; +} diff --git a/Content.Server/Storage/EntitySystems/SpawnTableOnUseSystem.cs b/Content.Server/Storage/EntitySystems/SpawnTableOnUseSystem.cs new file mode 100644 index 00000000000000..96556ed7b25624 --- /dev/null +++ b/Content.Server/Storage/EntitySystems/SpawnTableOnUseSystem.cs @@ -0,0 +1,41 @@ +using Content.Server.Administration.Logs; +using Content.Server.Storage.Components; +using Content.Shared.Database; +using Content.Shared.EntityTable; +using Content.Shared.Hands.EntitySystems; +using Content.Shared.Interaction.Events; + +namespace Content.Server.Storage.EntitySystems; + +public sealed class SpawnTableOnUseSystem : EntitySystem +{ + [Dependency] private readonly EntityTableSystem _entityTable = default!; + [Dependency] private readonly IAdminLogManager _adminLogger = default!; + [Dependency] private readonly SharedHandsSystem _hands = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnUseInHand); + } + + private void OnUseInHand(Entity ent, ref UseInHandEvent args) + { + if (args.Handled) + return; + + args.Handled = true; + + var coords = Transform(ent).Coordinates; + var spawns = _entityTable.GetSpawns(ent.Comp.Table); + foreach (var id in spawns) + { + var spawned = Spawn(id, coords); + _adminLogger.Add(LogType.EntitySpawn, LogImpact.Low, $"{ToPrettyString(args.User):user} used {ToPrettyString(ent):spawner} which spawned {ToPrettyString(spawned)}"); + _hands.TryPickupAnyHand(args.User, spawned); + } + + Del(ent); + } +} diff --git a/Content.Shared/Sound/Components/BaseEmitSoundComponent.cs b/Content.Shared/Sound/Components/BaseEmitSoundComponent.cs index 4e6ebb23d21644..870d20457ef761 100644 --- a/Content.Shared/Sound/Components/BaseEmitSoundComponent.cs +++ b/Content.Shared/Sound/Components/BaseEmitSoundComponent.cs @@ -14,4 +14,11 @@ public abstract partial class BaseEmitSoundComponent : Component [ViewVariables(VVAccess.ReadWrite)] [DataField(required: true)] public SoundSpecifier? Sound; + + /// + /// Play the sound at the position instead of parented to the source entity. + /// Useful if the entity is deleted after. + /// + [DataField] + public bool Positional; } diff --git a/Content.Shared/Sound/SharedEmitSoundSystem.cs b/Content.Shared/Sound/SharedEmitSoundSystem.cs index 3e051fff317770..30744b68644cbc 100644 --- a/Content.Shared/Sound/SharedEmitSoundSystem.cs +++ b/Content.Shared/Sound/SharedEmitSoundSystem.cs @@ -145,14 +145,22 @@ protected void TryEmitSound(EntityUid uid, BaseEmitSoundComponent component, Ent if (component.Sound == null) return; - if (predict) + if (component.Positional) { - _audioSystem.PlayPredicted(component.Sound, uid, user); + var coords = Transform(uid).Coordinates; + if (predict) + _audioSystem.PlayPredicted(component.Sound, coords, user); + else if (_netMan.IsServer) + // don't predict sounds that client couldn't have played already + _audioSystem.PlayPvs(component.Sound, coords); } - else if (_netMan.IsServer) + else { - // don't predict sounds that client couldn't have played already - _audioSystem.PlayPvs(component.Sound, uid); + if (predict) + _audioSystem.PlayPredicted(component.Sound, uid, user); + else if (_netMan.IsServer) + // don't predict sounds that client couldn't have played already + _audioSystem.PlayPvs(component.Sound, uid); } }