--- /dev/null
+using Robust.Shared.Audio;
+
+namespace Content.Server.Containers;
+
+/// <summary>
+/// Allows objects to fall inside the Container when thrown
+/// </summary>
+[RegisterComponent]
+[Access(typeof(ThrowInsertContainerSystem))]
+public sealed partial class ThrowInsertContainerComponent : Component
+{
+ [DataField(required: true)]
+ public string? ContainerId;
+
+ /// <summary>
+ /// Throw chance of hitting into the container
+ /// </summary>
+ [DataField]
+ public float Probability = 0.75f;
+
+ /// <summary>
+ /// Sound played when an object is throw into the container.
+ /// </summary>
+ [DataField]
+ public SoundSpecifier? InsertSound = new SoundPathSpecifier("/Audio/Effects/trashbag1.ogg");
+
+ /// <summary>
+ /// Sound played when an item is thrown and misses the container.
+ /// </summary>
+ [DataField]
+ public SoundSpecifier? MissSound = new SoundPathSpecifier("/Audio/Effects/thudswoosh.ogg");
+
+ [DataField]
+ public LocId MissLocString = "container-thrown-missed";
+}
--- /dev/null
+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<ThrowInsertContainerComponent, ThrowHitByEvent>(OnThrowCollide);
+ }
+
+ private void OnThrowCollide(Entity<ThrowInsertContainerComponent> 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)}");
+ }
+}
SubscribeLocalEvent<DisposalUnitComponent, PowerChangedEvent>(OnPowerChange);
SubscribeLocalEvent<DisposalUnitComponent, ComponentInit>(OnDisposalInit);
- SubscribeLocalEvent<DisposalUnitComponent, ThrowHitByEvent>(OnThrowCollide);
-
SubscribeLocalEvent<DisposalUnitComponent, ActivateInWorldEvent>(OnActivate);
SubscribeLocalEvent<DisposalUnitComponent, AfterInteractUsingEvent>(OnAfterInteractUsing);
SubscribeLocalEvent<DisposalUnitComponent, DragDropTargetEvent>(OnDragDropOn);
args.Handled = true;
}
- /// <summary>
- /// Thrown items have a chance of bouncing off the unit and not going in.
- /// </summary>
- 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<Container>(uid, SharedDisposalUnitComponent.ContainerId);
[ViewVariables(VVAccess.ReadWrite), DataField("soundInsert")]
public SoundSpecifier? InsertSound = new SoundPathSpecifier("/Audio/Effects/trashbag1.ogg");
- /// <summary>
- /// Sound played when an item is thrown and misses the disposal unit.
- /// </summary>
- [ViewVariables(VVAccess.ReadWrite), DataField("soundMiss")]
- public SoundSpecifier? MissSound = new SoundPathSpecifier("/Audio/Effects/thudswoosh.ogg");
-
-
/// <summary>
/// State for this disposals unit.
/// </summary>
container-verb-text-enter = Enter
container-verb-text-empty = Empty
+
+## missed
+container-thrown-missed = Missed!
\ No newline at end of file
## 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
graph: DisposalMachine
node: disposal_unit
- type: DisposalUnit
+ - type: ThrowInsertContainer
+ containerId: disposals
- type: UserInterface
interfaces:
enum.DisposalUnitUiKey.Key: