diff --git a/Content.Server/Containers/ThrowInsertContainerComponent.cs b/Content.Server/Containers/ThrowInsertContainerComponent.cs
new file mode 100644
index 0000000000..8aa2927773
--- /dev/null
+++ b/Content.Server/Containers/ThrowInsertContainerComponent.cs
@@ -0,0 +1,35 @@
+using Robust.Shared.Audio;
+
+namespace Content.Server.Containers;
+
+///
+/// Allows objects to fall inside the Container when thrown
+///
+[RegisterComponent]
+[Access(typeof(ThrowInsertContainerSystem))]
+public sealed partial class ThrowInsertContainerComponent : Component
+{
+ [DataField(required: true)]
+ public string? ContainerId;
+
+ ///
+ /// Throw chance of hitting into the container
+ ///
+ [DataField]
+ public float Probability = 0.75f;
+
+ ///
+ /// Sound played when an object is throw into the container.
+ ///
+ [DataField]
+ public SoundSpecifier? InsertSound = new SoundPathSpecifier("/Audio/Effects/trashbag1.ogg");
+
+ ///
+ /// Sound played when an item is thrown and misses the container.
+ ///
+ [DataField]
+ public SoundSpecifier? MissSound = new SoundPathSpecifier("/Audio/Effects/thudswoosh.ogg");
+
+ [DataField]
+ public LocId MissLocString = "container-thrown-missed";
+}
diff --git a/Content.Server/Containers/ThrowInsertContainerSystem.cs b/Content.Server/Containers/ThrowInsertContainerSystem.cs
new file mode 100644
index 0000000000..781b808ef9
--- /dev/null
+++ b/Content.Server/Containers/ThrowInsertContainerSystem.cs
@@ -0,0 +1,53 @@
+using Content.Server.Administration.Logs;
+using Content.Shared.Database;
+using Content.Shared.Popups;
+using Content.Shared.Throwing;
+using Robust.Shared.Audio.Systems;
+using Robust.Shared.Containers;
+using Robust.Shared.Random;
+
+namespace Content.Server.Containers;
+
+public sealed class ThrowInsertContainerSystem : EntitySystem
+{
+ [Dependency] private readonly IAdminLogManager _adminLogger = default!;
+ [Dependency] private readonly SharedAudioSystem _audio = default!;
+ [Dependency] private readonly SharedContainerSystem _containerSystem = default!;
+ [Dependency] private readonly SharedPopupSystem _popup = default!;
+ [Dependency] private readonly IRobustRandom _random = default!;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnThrowCollide);
+ }
+
+ private void OnThrowCollide(Entity ent, ref ThrowHitByEvent args)
+ {
+ if (ent.Comp.ContainerId == null)
+ return;
+
+ var container = _containerSystem.GetContainer(ent, ent.Comp.ContainerId);
+
+ if (!_containerSystem.CanInsert(args.Thrown, container))
+ return;
+
+
+ var rand = _random.NextFloat();
+ if (rand > ent.Comp.Probability)
+ {
+ _audio.PlayPvs(ent.Comp.MissSound, ent);
+ _popup.PopupEntity(Loc.GetString(ent.Comp.MissLocString), ent);
+ return;
+ }
+
+ if (_containerSystem.Insert(args.Thrown, container))
+ _audio.PlayPvs(ent.Comp.InsertSound, ent);
+ else
+ throw new InvalidOperationException("Container insertion failed but CanInsert returned true");
+
+ if (args.Component.Thrower != null)
+ _adminLogger.Add(LogType.Landed, LogImpact.Low, $"{ToPrettyString(args.Thrown)} thrown by {ToPrettyString(args.Component.Thrower.Value):player} landed in {ToPrettyString(ent)}");
+ }
+}
diff --git a/Content.Server/Disposal/Unit/EntitySystems/DisposalUnitSystem.cs b/Content.Server/Disposal/Unit/EntitySystems/DisposalUnitSystem.cs
index 416e0744b5..b970ae4b0d 100644
--- a/Content.Server/Disposal/Unit/EntitySystems/DisposalUnitSystem.cs
+++ b/Content.Server/Disposal/Unit/EntitySystems/DisposalUnitSystem.cs
@@ -73,8 +73,6 @@ public sealed class DisposalUnitSystem : SharedDisposalUnitSystem
SubscribeLocalEvent(OnPowerChange);
SubscribeLocalEvent(OnDisposalInit);
- SubscribeLocalEvent(OnThrowCollide);
-
SubscribeLocalEvent(OnActivate);
SubscribeLocalEvent(OnAfterInteractUsing);
SubscribeLocalEvent(OnDragDropOn);
@@ -294,40 +292,6 @@ public sealed class DisposalUnitSystem : SharedDisposalUnitSystem
args.Handled = true;
}
- ///
- /// Thrown items have a chance of bouncing off the unit and not going in.
- ///
- private void OnThrowCollide(EntityUid uid, SharedDisposalUnitComponent component, ThrowHitByEvent args)
- {
- var canInsert = CanInsert(uid, component, args.Thrown);
- var randDouble = _robustRandom.NextDouble();
-
- if (!canInsert)
- {
- return;
- }
-
- if (randDouble > 0.75)
- {
- _audioSystem.PlayPvs(component.MissSound, uid);
-
- _popupSystem.PopupEntity(Loc.GetString("disposal-unit-thrown-missed"), uid);
- return;
- }
-
- var inserted = _containerSystem.Insert(args.Thrown, component.Container);
-
- if (!inserted)
- {
- throw new InvalidOperationException("Container insertion failed but CanInsert returned true");
- }
-
- if (args.Component.Thrower != null)
- _adminLogger.Add(LogType.Landed, LogImpact.Low, $"{ToPrettyString(args.Thrown)} thrown by {ToPrettyString(args.Component.Thrower.Value):player} landed in {ToPrettyString(uid)}");
-
- AfterInsert(uid, component, args.Thrown);
- }
-
private void OnDisposalInit(EntityUid uid, SharedDisposalUnitComponent component, ComponentInit args)
{
component.Container = _containerSystem.EnsureContainer(uid, SharedDisposalUnitComponent.ContainerId);
diff --git a/Content.Shared/Disposal/Components/SharedDisposalUnitComponent.cs b/Content.Shared/Disposal/Components/SharedDisposalUnitComponent.cs
index 4948cb6640..36dd14f9b2 100644
--- a/Content.Shared/Disposal/Components/SharedDisposalUnitComponent.cs
+++ b/Content.Shared/Disposal/Components/SharedDisposalUnitComponent.cs
@@ -36,13 +36,6 @@ public abstract partial class SharedDisposalUnitComponent : Component
[ViewVariables(VVAccess.ReadWrite), DataField("soundInsert")]
public SoundSpecifier? InsertSound = new SoundPathSpecifier("/Audio/Effects/trashbag1.ogg");
- ///
- /// Sound played when an item is thrown and misses the disposal unit.
- ///
- [ViewVariables(VVAccess.ReadWrite), DataField("soundMiss")]
- public SoundSpecifier? MissSound = new SoundPathSpecifier("/Audio/Effects/thudswoosh.ogg");
-
-
///
/// State for this disposals unit.
///
diff --git a/Resources/Locale/en-US/containers/containers.ftl b/Resources/Locale/en-US/containers/containers.ftl
index ab011f64f8..d96383305a 100644
--- a/Resources/Locale/en-US/containers/containers.ftl
+++ b/Resources/Locale/en-US/containers/containers.ftl
@@ -1,2 +1,5 @@
container-verb-text-enter = Enter
container-verb-text-empty = Empty
+
+## missed
+container-thrown-missed = Missed!
\ No newline at end of file
diff --git a/Resources/Locale/en-US/disposal/unit/components/disposal-unit-component.ftl b/Resources/Locale/en-US/disposal/unit/components/disposal-unit-component.ftl
index 288db53668..2b23ee9a4a 100644
--- a/Resources/Locale/en-US/disposal/unit/components/disposal-unit-component.ftl
+++ b/Resources/Locale/en-US/disposal/unit/components/disposal-unit-component.ftl
@@ -18,9 +18,6 @@ disposal-eject-verb-get-data-text = Eject contents
## No hands
disposal-unit-no-hands = You don't have hands!
-## missed
-disposal-unit-thrown-missed = Missed!
-
# state
disposal-unit-state-Ready = Ready
# Yes I want it to always say Pressurizing
diff --git a/Resources/Prototypes/Entities/Structures/Piping/Disposal/units.yml b/Resources/Prototypes/Entities/Structures/Piping/Disposal/units.yml
index b4a5f61ffa..2198c854a0 100644
--- a/Resources/Prototypes/Entities/Structures/Piping/Disposal/units.yml
+++ b/Resources/Prototypes/Entities/Structures/Piping/Disposal/units.yml
@@ -77,6 +77,8 @@
graph: DisposalMachine
node: disposal_unit
- type: DisposalUnit
+ - type: ThrowInsertContainer
+ containerId: disposals
- type: UserInterface
interfaces:
enum.DisposalUnitUiKey.Key: