diff --git a/Content.Server/Plants/Components/PottedPlantHideComponent.cs b/Content.Server/Plants/Components/PottedPlantHideComponent.cs
index eae2ee3ac3..1254cf94f1 100644
--- a/Content.Server/Plants/Components/PottedPlantHideComponent.cs
+++ b/Content.Server/Plants/Components/PottedPlantHideComponent.cs
@@ -1,54 +1,23 @@
-using System.Threading.Tasks;
+using Content.Server.Plants.Systems;
using Content.Server.Storage.Components;
-using Content.Shared.Audio;
-using Content.Shared.Interaction;
-using Content.Shared.Popups;
using Content.Shared.Sound;
-using Robust.Shared.Audio;
+using Robust.Shared.Analyzers;
using Robust.Shared.GameObjects;
-using Robust.Shared.Localization;
-using Robust.Shared.Player;
using Robust.Shared.Serialization.Manager.Attributes;
-using Robust.Shared.ViewVariables;
namespace Content.Server.Plants.Components
{
+ ///
+ /// Interaction wrapper for .
+ /// Gently rustle after each interaction with plant.
+ ///
[RegisterComponent]
- public class PottedPlantHideComponent : Component, IInteractUsing, IInteractHand
+ [Friend(typeof(PottedPlantHideSystem))]
+ public class PottedPlantHideComponent : Component
{
public override string Name => "PottedPlantHide";
- [ViewVariables] private SecretStashComponent _secretStash = default!;
- [DataField("rustleSound")] private SoundSpecifier _rustleSound = new SoundPathSpecifier("/Audio/Effects/plant_rustle.ogg");
-
- protected override void Initialize()
- {
- base.Initialize();
- _secretStash = Owner.EnsureComponent();
- }
-
- async Task IInteractUsing.InteractUsing(InteractUsingEventArgs eventArgs)
- {
- Rustle();
- return _secretStash.TryHideItem(eventArgs.User, eventArgs.Using);
- }
-
- bool IInteractHand.InteractHand(InteractHandEventArgs eventArgs)
- {
- Rustle();
-
- var gotItem = _secretStash.TryGetItem(eventArgs.User);
- if (!gotItem)
- {
- Owner.PopupMessage(eventArgs.User, Loc.GetString("potted-plant-hide-component-interact-hand-got-no-item-message"));
- }
-
- return gotItem;
- }
-
- private void Rustle()
- {
- SoundSystem.Play(Filter.Pvs(Owner), _rustleSound.GetSound(), Owner, AudioHelpers.WithVariation(0.25f));
- }
+ [DataField("rustleSound")]
+ public SoundSpecifier RustleSound = new SoundPathSpecifier("/Audio/Effects/plant_rustle.ogg");
}
}
diff --git a/Content.Server/Plants/Systems/PottedPlantHideSystem.cs b/Content.Server/Plants/Systems/PottedPlantHideSystem.cs
new file mode 100644
index 0000000000..f0dfe1aae8
--- /dev/null
+++ b/Content.Server/Plants/Systems/PottedPlantHideSystem.cs
@@ -0,0 +1,75 @@
+using Content.Server.Plants.Components;
+using Content.Server.Popups;
+using Content.Server.Storage.Components;
+using Content.Server.Storage.EntitySystems;
+using Content.Shared.ActionBlocker;
+using Content.Shared.Audio;
+using Content.Shared.Interaction;
+using Robust.Shared.Audio;
+using Robust.Shared.GameObjects;
+using Robust.Shared.IoC;
+using Robust.Shared.Localization;
+using Robust.Shared.Player;
+
+namespace Content.Server.Plants.Systems
+{
+ public class PottedPlantHideSystem : EntitySystem
+ {
+ [Dependency] private readonly SecretStashSystem _stashSystem = default!;
+ [Dependency] private readonly PopupSystem _popupSystem = default!;
+ [Dependency] private readonly ActionBlockerSystem _blocker = default!;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+ SubscribeLocalEvent(OnInit);
+ SubscribeLocalEvent(OnInteractUsing);
+ SubscribeLocalEvent(OnInteractHand);
+ }
+
+ private void OnInit(EntityUid uid, PottedPlantHideComponent component, ComponentInit args)
+ {
+ EntityManager.EnsureComponent(uid);
+ }
+
+ private void OnInteractUsing(EntityUid uid, PottedPlantHideComponent component, InteractUsingEvent args)
+ {
+ if (args.Handled)
+ return;
+
+ // standard interaction checks
+ if (!_blocker.CanInteract(args.User)) return;
+
+ Rustle(uid, component);
+ args.Handled = _stashSystem.TryHideItem(uid, args.User, args.Used);
+ }
+
+ private void OnInteractHand(EntityUid uid, PottedPlantHideComponent component, InteractHandEvent args)
+ {
+ if (args.Handled)
+ return;
+
+ // standard interaction checks
+ if (!_blocker.CanInteract(args.User)) return;
+
+ Rustle(uid, component);
+
+ var gotItem = _stashSystem.TryGetItem(uid, args.User);
+ if (!gotItem)
+ {
+ var msg = Loc.GetString("potted-plant-hide-component-interact-hand-got-no-item-message");
+ _popupSystem.PopupEntity(msg, uid, Filter.Entities(args.User));
+ }
+
+ args.Handled = gotItem;
+ }
+
+ private void Rustle(EntityUid uid, PottedPlantHideComponent? component = null)
+ {
+ if (!Resolve(uid, ref component))
+ return;
+
+ SoundSystem.Play(Filter.Pvs(uid), component.RustleSound.GetSound(), uid, AudioHelpers.WithVariation(0.25f));
+ }
+ }
+}
diff --git a/Content.Server/Storage/Components/SecretStashComponent.cs b/Content.Server/Storage/Components/SecretStashComponent.cs
index 30e8992a59..3e4564a1c7 100644
--- a/Content.Server/Storage/Components/SecretStashComponent.cs
+++ b/Content.Server/Storage/Components/SecretStashComponent.cs
@@ -1,120 +1,44 @@
-using Content.Server.Hands.Components;
-using Content.Server.Items;
-using Content.Shared.Acts;
+using Content.Server.Storage.EntitySystems;
+using Content.Server.Toilet;
+using Content.Shared.Containers.ItemSlots;
using Content.Shared.Item;
-using Content.Shared.Popups;
+using Robust.Shared.Analyzers;
using Robust.Shared.Containers;
using Robust.Shared.GameObjects;
-using Robust.Shared.IoC;
-using Robust.Shared.Localization;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.ViewVariables;
namespace Content.Server.Storage.Components
{
///
- /// Logic for secret single slot stash, like plant pot or toilet cistern
+ /// Logic for a secret slot stash, like plant pot or toilet cistern.
+ /// Unlike it doesn't have interaction logic or verbs.
+ /// Other classes like should implement it.
///
[RegisterComponent]
- public class SecretStashComponent : Component, IDestroyAct
+ [Friend(typeof(SecretStashSystem))]
+ public class SecretStashComponent : Component
{
- [Dependency] private readonly IEntityManager _entMan = default!;
-
public override string Name => "SecretStash";
+ ///
+ /// Max item size that can be fitted into secret stash.
+ ///
[ViewVariables] [DataField("maxItemSize")]
- private int _maxItemSize = (int) ReferenceSizes.Pocket;
+ public int MaxItemSize = (int) ReferenceSizes.Pocket;
+ ///
+ /// IC secret stash name. For example "the toilet cistern".
+ /// If empty string, will replace it with entity name in init.
+ ///
[ViewVariables] [DataField("secretPartName")]
- private readonly string? _secretPartNameOverride = null;
-
- [ViewVariables] private ContainerSlot _itemContainer = default!;
-
- public string SecretPartName => _secretPartNameOverride ?? Loc.GetString("comp-secret-stash-secret-part-name", ("name", _entMan.GetComponent(Owner).EntityName));
-
- protected override void Initialize()
- {
- base.Initialize();
- _itemContainer = ContainerHelpers.EnsureContainer(Owner, "stash", out _);
- }
+ public string SecretPartName = "";
///
- /// Tries to hide item inside secret stash from hands of user
+ /// Container used to keep secret stash item.
///
- ///
- ///
- /// True if item was hidden inside stash
- public bool TryHideItem(EntityUid user, EntityUid itemToHide)
- {
- if (_itemContainer.ContainedEntity != null)
- {
- Owner.PopupMessage(user, Loc.GetString("comp-secret-stash-action-hide-container-not-empty"));
- return false;
- }
+ [ViewVariables]
+ public ContainerSlot ItemContainer = default!;
- if (!_entMan.TryGetComponent(itemToHide, out ItemComponent? item))
- return false;
-
- if (item.Size > _maxItemSize)
- {
- Owner.PopupMessage(user,
- Loc.GetString("comp-secret-stash-action-hide-item-too-big",("item", itemToHide),("stash", SecretPartName)));
- return false;
- }
-
- if (!_entMan.TryGetComponent(user, out HandsComponent? hands))
- return false;
-
- if (!hands.Drop(itemToHide, _itemContainer))
- return false;
-
- Owner.PopupMessage(user, Loc.GetString("comp-secret-stash-action-hide-success", ("item", itemToHide), ("this", SecretPartName)));
- return true;
- }
-
- ///
- /// Try get item and place it in users hand
- /// If user can't take it by hands, will drop item from container
- ///
- ///
- /// True if user recieved item
- public bool TryGetItem(EntityUid user)
- {
- if (_itemContainer.ContainedEntity is not {Valid: true} contained)
- return false;
-
- Owner.PopupMessage(user, Loc.GetString("comp-secret-stash-action-get-item-found-something", ("stash", SecretPartName)));
-
- if (_entMan.TryGetComponent(user, out HandsComponent? hands))
- {
- if (!_entMan.TryGetComponent(contained, out ItemComponent? item))
- return false;
- hands.PutInHandOrDrop(item);
- }
- else if (_itemContainer.Remove(contained))
- {
- _entMan.GetComponent(contained).Coordinates = _entMan.GetComponent(Owner).Coordinates;
- }
-
- return true;
- }
-
- ///
- /// Is there something inside secret stash item container?
- ///
- ///
- public bool HasItemInside()
- {
- return _itemContainer.ContainedEntity != null;
- }
-
- public void OnDestroy(DestructionEventArgs eventArgs)
- {
- // drop item inside
- if (_itemContainer.ContainedEntity is {Valid: true} contained)
- {
- _entMan.GetComponent(contained).Coordinates = _entMan.GetComponent(Owner).Coordinates;
- }
- }
}
}
diff --git a/Content.Server/Storage/EntitySystems/SecretStashSystem.cs b/Content.Server/Storage/EntitySystems/SecretStashSystem.cs
new file mode 100644
index 0000000000..fa19fce286
--- /dev/null
+++ b/Content.Server/Storage/EntitySystems/SecretStashSystem.cs
@@ -0,0 +1,136 @@
+using Content.Server.Items;
+using Content.Server.Popups;
+using Content.Server.Storage.Components;
+using Content.Shared.Acts;
+using Content.Shared.Hands.Components;
+using Robust.Shared.Containers;
+using Robust.Shared.GameObjects;
+using Robust.Shared.IoC;
+using Robust.Shared.Localization;
+using Robust.Shared.Player;
+
+namespace Content.Server.Storage.EntitySystems
+{
+ public class SecretStashSystem : EntitySystem
+ {
+ [Dependency] private readonly PopupSystem _popupSystem = default!;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+ SubscribeLocalEvent(OnInit);
+ SubscribeLocalEvent(OnDestroyed);
+ }
+
+ private void OnInit(EntityUid uid, SecretStashComponent component, ComponentInit args)
+ {
+ // set default secret part name
+ if (component.SecretPartName == "")
+ {
+ var meta = EntityManager.GetComponent(uid);
+ var entityName = Loc.GetString("comp-secret-stash-secret-part-name", ("name", meta.EntityName));
+ component.SecretPartName = entityName;
+ }
+
+ component.ItemContainer = ContainerHelpers.EnsureContainer(uid, "stash", out _);
+ }
+
+ private void OnDestroyed(EntityUid uid, SecretStashComponent component, DestructionEventArgs args)
+ {
+ component.ItemContainer.EmptyContainer();
+ }
+
+ ///
+ /// Is there something inside secret stash item container?
+ ///
+ public bool HasItemInside(EntityUid uid, SecretStashComponent? component = null)
+ {
+ if (!Resolve(uid, ref component))
+ return false;
+ return component.ItemContainer.ContainedEntity != null;
+ }
+
+ ///
+ /// Tries to hide item inside secret stash from hands of user.
+ ///
+ /// True if item was hidden inside stash
+ public bool TryHideItem(EntityUid uid, EntityUid userUid, EntityUid itemToHideUid,
+ SecretStashComponent? component = null, ItemComponent? item = null,
+ MetaDataComponent? itemMeta = null, SharedHandsComponent? hands = null)
+ {
+ if (!Resolve(uid, ref component))
+ return false;
+ if (!Resolve(itemToHideUid, ref item, ref itemMeta))
+ return false;
+ if (!Resolve(userUid, ref hands))
+ return false;
+
+ // check if secret stash is already occupied
+ var container = component.ItemContainer;
+ if (container.ContainedEntity != null)
+ {
+ var msg = Loc.GetString("comp-secret-stash-action-hide-container-not-empty");
+ _popupSystem.PopupEntity(msg, uid, Filter.Entities(userUid));
+ return false;
+ }
+
+ // check if item is too big to fit into secret stash
+ var itemName = itemMeta.EntityName;
+ if (item.Size > component.MaxItemSize)
+ {
+ var msg = Loc.GetString("comp-secret-stash-action-hide-item-too-big",
+ ("item", itemName), ("stash", component.SecretPartName));
+ _popupSystem.PopupEntity(msg, uid, Filter.Entities(userUid));
+ return false;
+ }
+
+ // try to move item from hands to stash container
+ if (!hands.Drop(itemToHideUid, container))
+ {
+ return false;
+ }
+
+ // all done, show success message
+ var successMsg = Loc.GetString("comp-secret-stash-action-hide-success",
+ ("item", itemName), ("this", component.SecretPartName));
+ _popupSystem.PopupEntity(successMsg, uid, Filter.Entities(userUid));
+ return true;
+ }
+
+ ///
+ /// Try get item and place it in users hand.
+ /// If user can't take it by hands, will drop item from container.
+ ///
+ /// True if user received item
+ public bool TryGetItem(EntityUid uid, EntityUid userUid, SecretStashComponent? component = null,
+ SharedHandsComponent? hands = null)
+ {
+ if (!Resolve(uid, ref component))
+ return false;
+ if (!Resolve(userUid, ref hands))
+ return false;
+
+ // check if secret stash has something inside
+ var container = component.ItemContainer;
+ if (container.ContainedEntity == null)
+ {
+ return false;
+ }
+
+ // get item inside container
+ var itemUid = container.ContainedEntity;
+ if (!EntityManager.TryGetComponent(itemUid, out ItemComponent? item))
+ {
+ return false;
+ }
+ hands.PutInHandOrDrop(item);
+
+ // show success message
+ var successMsg = Loc.GetString("comp-secret-stash-action-get-item-found-something",
+ ("stash", component.SecretPartName));
+ _popupSystem.PopupEntity(successMsg, uid, Filter.Entities(userUid));
+
+ return true;
+ }
+ }
+}
diff --git a/Content.Server/Toilet/ToiletComponent.cs b/Content.Server/Toilet/ToiletComponent.cs
index b44f600799..5d66ccacbe 100644
--- a/Content.Server/Toilet/ToiletComponent.cs
+++ b/Content.Server/Toilet/ToiletComponent.cs
@@ -1,180 +1,34 @@
-using System.Threading.Tasks;
using Content.Server.Act;
-using Content.Server.Buckle.Components;
using Content.Server.Chat.Managers;
-using Content.Server.Popups;
-using Content.Server.Storage.Components;
-using Content.Server.Tools;
-using Content.Server.Tools.Components;
-using Content.Shared.Audio;
-using Content.Shared.Body.Components;
-using Content.Shared.Body.Part;
-using Content.Shared.Examine;
-using Content.Shared.Interaction;
-using Content.Shared.Popups;
using Content.Shared.Sound;
-using Content.Shared.Toilet;
using Content.Shared.Tools;
-using Robust.Shared.Audio;
using Robust.Shared.GameObjects;
-using Robust.Shared.IoC;
-using Robust.Shared.Localization;
-using Robust.Shared.Player;
-using Robust.Shared.Random;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
-using Robust.Shared.Utility;
-using Robust.Shared.ViewVariables;
namespace Content.Server.Toilet
{
[RegisterComponent]
-#pragma warning disable 618
- public class ToiletComponent : Component, IInteractUsing,
- IInteractHand, IMapInit, IExamine, ISuicideAct
-#pragma warning restore 618
+ [ComponentProtoName("Toilet")]
+ public sealed class ToiletComponent : Component, ISuicideAct
{
- [Dependency] private readonly IEntityManager _entMan = default!;
-
- public sealed override string Name => "Toilet";
-
- private const float PryLidTime = 1f;
-
- private bool _isPrying = false;
+ [DataField("pryLidTime")]
+ public float PryLidTime = 1f;
[DataField("pryingQuality", customTypeSerializer:typeof(PrototypeIdSerializer))]
- private string _pryingQuality = "Prying";
+ public string PryingQuality = "Prying";
- [ViewVariables] public bool LidOpen { get; private set; }
- [ViewVariables] public bool IsSeatUp { get; private set; }
+ [DataField("toggleSound")]
+ public SoundSpecifier ToggleSound = new SoundPathSpecifier("/Audio/Effects/toilet_seat_down.ogg");
- [ViewVariables] private SecretStashComponent _secretStash = default!;
-
- [DataField("toggleSound")] SoundSpecifier _toggleSound = new SoundPathSpecifier("/Audio/Effects/toilet_seat_down.ogg");
-
- protected override void Initialize()
- {
- base.Initialize();
- _secretStash = Owner.EnsureComponent();
- }
-
- public void MapInit()
- {
- // roll is toilet seat will be up or down
- var random = IoCManager.Resolve();
- IsSeatUp = random.Prob(0.5f);
- UpdateSprite();
- }
-
- async Task IInteractUsing.InteractUsing(InteractUsingEventArgs eventArgs)
- {
- // are player trying place or lift of cistern lid?
- if (_entMan.TryGetComponent(eventArgs.Using, out ToolComponent? tool)
- && tool.Qualities.Contains(_pryingQuality))
- {
- // check if someone is already prying this toilet
- if (_isPrying)
- return false;
- _isPrying = true;
-
- if (!await EntitySystem.Get().UseTool(eventArgs.Using, eventArgs.User, Owner, 0f, PryLidTime, _pryingQuality))
- {
- _isPrying = false;
- return false;
- }
-
- _isPrying = false;
-
- // all cool - toggle lid
- LidOpen = !LidOpen;
- UpdateSprite();
-
- return true;
- }
- // maybe player trying to hide something inside cistern?
- else if (LidOpen)
- {
- return _secretStash.TryHideItem(eventArgs.User, eventArgs.Using);
- }
-
- return false;
- }
-
- bool IInteractHand.InteractHand(InteractHandEventArgs eventArgs)
- {
- // trying get something from stash?
- if (LidOpen)
- {
- var gotItem = _secretStash.TryGetItem(eventArgs.User);
-
- if (gotItem)
- return true;
- }
-
- // just want to up/down seat?
- // check that nobody seats on seat right now
- if (_entMan.TryGetComponent(Owner, out StrapComponent? strap))
- {
- if (strap.BuckledEntities.Count != 0)
- return false;
- }
-
- ToggleToiletSeat();
- return true;
- }
-
- public void Examine(FormattedMessage message, bool inDetailsRange)
- {
- if (inDetailsRange && LidOpen)
- {
- if (_secretStash.HasItemInside())
- {
- message.AddMarkup(Loc.GetString("toilet-component-on-examine-found-hidden-item"));
- }
- }
- }
-
- public void ToggleToiletSeat()
- {
- IsSeatUp = !IsSeatUp;
- SoundSystem.Play(Filter.Pvs(Owner), _toggleSound.GetSound(), Owner, AudioHelpers.WithVariation(0.05f));
-
- UpdateSprite();
- }
-
- private void UpdateSprite()
- {
- if (_entMan.TryGetComponent(Owner, out AppearanceComponent? appearance))
- {
- appearance.SetData(ToiletVisuals.LidOpen, LidOpen);
- appearance.SetData(ToiletVisuals.SeatUp, IsSeatUp);
- }
- }
+ public bool LidOpen = false;
+ public bool IsSeatUp = false;
+ public bool IsPrying = false;
+ // todo: move me to ECS
SuicideKind ISuicideAct.Suicide(EntityUid victim, IChatManager chat)
{
- // check that victim even have head
- if (_entMan.TryGetComponent(victim, out var body) &&
- body.HasPartOfType(BodyPartType.Head))
- {
- var othersMessage = Loc.GetString("toilet-component-suicide-head-message-others", ("victim",Name: _entMan.GetComponent(victim).EntityName),("owner", Name: _entMan.GetComponent(Owner).EntityName));
- victim.PopupMessageOtherClients(othersMessage);
-
- var selfMessage = Loc.GetString("toilet-component-suicide-head-message", ("owner", Name: _entMan.GetComponent(Owner).EntityName));
- victim.PopupMessage(selfMessage);
-
- return SuicideKind.Asphyxiation;
- }
- else
- {
- var othersMessage = Loc.GetString("toilet-component-suicide-message-others",("victim", Name: _entMan.GetComponent(victim).EntityName),("owner", Name: _entMan.GetComponent(Owner).EntityName));
- victim.PopupMessageOtherClients(othersMessage);
-
- var selfMessage = Loc.GetString("toilet-component-suicide-message", ("owner",Name: _entMan.GetComponent(Owner).EntityName));
- victim.PopupMessage(selfMessage);
-
- return SuicideKind.Blunt;
- }
+ return EntitySystem.Get().Suicide(Owner, victim, this);
}
}
diff --git a/Content.Server/Toilet/ToiletSystem.cs b/Content.Server/Toilet/ToiletSystem.cs
new file mode 100644
index 0000000000..2113bd5291
--- /dev/null
+++ b/Content.Server/Toilet/ToiletSystem.cs
@@ -0,0 +1,225 @@
+using Content.Server.Act;
+using Content.Server.Buckle.Components;
+using Content.Server.Popups;
+using Content.Server.Storage.Components;
+using Content.Server.Storage.EntitySystems;
+using Content.Server.Tools;
+using Content.Server.Tools.Components;
+using Content.Shared.Audio;
+using Content.Shared.Body.Components;
+using Content.Shared.Body.Part;
+using Content.Shared.Examine;
+using Content.Shared.Interaction;
+using Content.Shared.Toilet;
+using Robust.Shared.Audio;
+using Robust.Shared.GameObjects;
+using Robust.Shared.IoC;
+using Robust.Shared.Localization;
+using Robust.Shared.Player;
+using Robust.Shared.Random;
+
+namespace Content.Server.Toilet
+{
+ public class ToiletSystem : EntitySystem
+ {
+ [Dependency] private readonly IRobustRandom _random = default!;
+ [Dependency] private readonly SecretStashSystem _secretStash = default!;
+ [Dependency] private readonly PopupSystem _popupSystem = default!;
+ [Dependency] private readonly ToolSystem _toolSystem = default!;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+ SubscribeLocalEvent(OnInit);
+ SubscribeLocalEvent(OnMapInit);
+ SubscribeLocalEvent(OnInteractUsing);
+ SubscribeLocalEvent(OnInteractHand);
+ SubscribeLocalEvent(OnExamine);
+ SubscribeLocalEvent(OnToiletPried);
+ SubscribeLocalEvent(OnToiletInterrupt);
+ }
+
+ private void OnInit(EntityUid uid, ToiletComponent component, ComponentInit args)
+ {
+ EntityManager.EnsureComponent(uid);
+ }
+
+ private void OnMapInit(EntityUid uid, ToiletComponent component, MapInitEvent args)
+ {
+ // roll is toilet seat will be up or down
+ component.IsSeatUp = _random.Prob(0.5f);
+ UpdateSprite(uid, component);
+ }
+
+ private void OnInteractUsing(EntityUid uid, ToiletComponent component, InteractUsingEvent args)
+ {
+ if (args.Handled)
+ return;
+
+ // are player trying place or lift of cistern lid?
+ if (EntityManager.TryGetComponent(args.Used, out ToolComponent? tool)
+ && tool.Qualities.Contains(component.PryingQuality))
+ {
+ // check if someone is already prying this toilet
+ if (component.IsPrying)
+ return;
+ component.IsPrying = true;
+
+ // try to pry toilet cistern
+ if (!_toolSystem.UseTool(args.Used, args.User, uid, 0f,
+ component.PryLidTime, component.PryingQuality,
+ new ToiletPryFinished(uid), new ToiletPryInterrupted(uid)))
+ {
+ component.IsPrying = false;
+ return;
+ }
+
+ args.Handled = true;
+ }
+ // maybe player trying to hide something inside cistern?
+ else if (component.LidOpen)
+ {
+ args.Handled = _secretStash.TryHideItem(uid, args.User, args.Used);
+ }
+ }
+
+ private void OnInteractHand(EntityUid uid, ToiletComponent component, InteractHandEvent args)
+ {
+ if (args.Handled)
+ return;
+
+ // trying get something from stash?
+ if (component.LidOpen)
+ {
+ var gotItem = _secretStash.TryGetItem(uid, args.User);
+ if (gotItem)
+ {
+ args.Handled = true;
+ return;
+ }
+ }
+
+ // just want to up/down seat?
+ // check that nobody seats on seat right now
+ if (EntityManager.TryGetComponent(uid, out StrapComponent? strap))
+ {
+ if (strap.BuckledEntities.Count != 0)
+ return;
+ }
+
+ ToggleToiletSeat(uid, component);
+ args.Handled = true;
+ }
+
+ private void OnExamine(EntityUid uid, ToiletComponent component, ExaminedEvent args)
+ {
+ if (args.IsInDetailsRange && component.LidOpen)
+ {
+ if (_secretStash.HasItemInside(uid))
+ {
+ var msg = Loc.GetString("toilet-component-on-examine-found-hidden-item");
+ args.PushMarkup(msg);
+ }
+ }
+ }
+
+ public SuicideKind Suicide(EntityUid uid, EntityUid victimUid, ToiletComponent? component = null,
+ MetaDataComponent? meta = null, MetaDataComponent? victimMeta = null)
+ {
+ if (!Resolve(uid, ref component, ref meta))
+ return SuicideKind.Special;
+
+ if (!Resolve(uid, ref victimMeta))
+ return SuicideKind.Special;
+
+ // check that victim even have head
+ if (EntityManager.TryGetComponent(victimUid, out var body) &&
+ body.HasPartOfType(BodyPartType.Head))
+ {
+ var othersMessage = Loc.GetString("toilet-component-suicide-head-message-others",
+ ("victim",victimMeta.Name),("owner", meta.Name));
+ _popupSystem.PopupEntity(othersMessage, uid, Filter.Pvs(victimUid));
+
+ var selfMessage = Loc.GetString("toilet-component-suicide-head-message",
+ ("owner", meta.Name));
+ _popupSystem.PopupEntity(selfMessage, uid, Filter.Entities(victimUid));
+
+ return SuicideKind.Asphyxiation;
+ }
+ else
+ {
+ var othersMessage = Loc.GetString("toilet-component-suicide-message-others",
+ ("victim", victimMeta.Name),("owner", meta.Name));
+ _popupSystem.PopupEntity(othersMessage, uid, Filter.Pvs(uid));
+
+ var selfMessage = Loc.GetString("toilet-component-suicide-message",
+ ("owner",meta.Name));
+ _popupSystem.PopupEntity(selfMessage, uid, Filter.Entities(victimUid));
+
+ return SuicideKind.Blunt;
+ }
+ }
+
+ private void OnToiletInterrupt(ToiletPryInterrupted ev)
+ {
+ if (!EntityManager.TryGetComponent(ev.Uid, out ToiletComponent? toilet))
+ return;
+
+ toilet.IsPrying = false;
+ }
+
+ private void OnToiletPried(ToiletPryFinished ev)
+ {
+ if (!EntityManager.TryGetComponent(ev.Uid, out ToiletComponent? toilet))
+ return;
+
+ toilet.IsPrying = false;
+ toilet.LidOpen = !toilet.LidOpen;
+ UpdateSprite(ev.Uid, toilet);
+ }
+
+ public void ToggleToiletSeat(EntityUid uid, ToiletComponent? component = null)
+ {
+ if (!Resolve(uid, ref component))
+ return;
+
+ component.IsSeatUp = !component.IsSeatUp;
+ SoundSystem.Play(Filter.Pvs(uid), component.ToggleSound.GetSound(), uid,
+ AudioHelpers.WithVariation(0.05f));
+
+ UpdateSprite(uid, component);
+ }
+
+ private void UpdateSprite(EntityUid uid, ToiletComponent? component = null)
+ {
+ if (!Resolve(uid, ref component))
+ return;
+
+ if (!EntityManager.TryGetComponent(uid,out AppearanceComponent? appearance))
+ return;
+
+ appearance.SetData(ToiletVisuals.LidOpen, component.LidOpen);
+ appearance.SetData(ToiletVisuals.SeatUp, component.IsSeatUp);
+ }
+ }
+
+ public class ToiletPryFinished : EntityEventArgs
+ {
+ public EntityUid Uid;
+
+ public ToiletPryFinished(EntityUid uid)
+ {
+ Uid = uid;
+ }
+ }
+
+ public class ToiletPryInterrupted : EntityEventArgs
+ {
+ public EntityUid Uid;
+
+ public ToiletPryInterrupted(EntityUid uid)
+ {
+ Uid = uid;
+ }
+ }
+}
diff --git a/Resources/Locale/en-US/storage/components/secret-stash-component.ftl b/Resources/Locale/en-US/storage/components/secret-stash-component.ftl
index 57b79b748d..6695088251 100644
--- a/Resources/Locale/en-US/storage/components/secret-stash-component.ftl
+++ b/Resources/Locale/en-US/storage/components/secret-stash-component.ftl
@@ -1,7 +1,7 @@
### Secret stash component. Stuff like potted plants, comfy chair cushions, etc...
comp-secret-stash-secret-part-name = {$name}
-comp-secret-stash-action-hide-success = You hide { THE($item) } in { $this }
+comp-secret-stash-action-hide-success = You hide {$item} in { $this }
comp-secret-stash-action-hide-container-not-empty = There's already something in here?!
comp-secret-stash-action-hide-item-too-big = {$item} is too big to fit in {$stash}!
-comp-secret-stash-action-get-item-found-something = There was something inside {$stash}!
\ No newline at end of file
+comp-secret-stash-action-get-item-found-something = There was something inside {$stash}!