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 Content.Shared.Tools.Components; 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 { public sealed override string Name => "Toilet"; private const float PryLidTime = 1f; private bool _isPrying = false; [DataField("pryingQuality", customTypeSerializer:typeof(PrototypeIdSerializer))] private string _pryingQuality = "Prying"; [ViewVariables] public bool LidOpen { get; private set; } [ViewVariables] public bool IsSeatUp { get; private set; } [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 (IoCManager.Resolve().TryGetComponent(eventArgs.Using.Uid, 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.Uid, eventArgs.User.Uid, Owner.Uid, 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 (IoCManager.Resolve().TryGetComponent(Owner.Uid, 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 (IoCManager.Resolve().TryGetComponent(Owner.Uid, out AppearanceComponent? appearance)) { appearance.SetData(ToiletVisuals.LidOpen, LidOpen); appearance.SetData(ToiletVisuals.SeatUp, IsSeatUp); } } SuicideKind ISuicideAct.Suicide(IEntity victim, IChatManager chat) { // check that victim even have head if (IoCManager.Resolve().TryGetComponent(victim.Uid, out var body) && body.HasPartOfType(BodyPartType.Head)) { var othersMessage = Loc.GetString("toilet-component-suicide-head-message-others", ("victim",Name: IoCManager.Resolve().GetComponent(victim.Uid).EntityName),("owner", Name: IoCManager.Resolve().GetComponent(Owner.Uid).EntityName)); victim.PopupMessageOtherClients(othersMessage); var selfMessage = Loc.GetString("toilet-component-suicide-head-message", ("owner", Name: IoCManager.Resolve().GetComponent(Owner.Uid).EntityName)); victim.PopupMessage(selfMessage); return SuicideKind.Asphyxiation; } else { var othersMessage = Loc.GetString("toilet-component-suicide-message-others",("victim", Name: IoCManager.Resolve().GetComponent(victim.Uid).EntityName),("owner", Name: IoCManager.Resolve().GetComponent(Owner.Uid).EntityName)); victim.PopupMessageOtherClients(othersMessage); var selfMessage = Loc.GetString("toilet-component-suicide-message", ("owner",Name: IoCManager.Resolve().GetComponent(Owner.Uid).EntityName)); victim.PopupMessage(selfMessage); return SuicideKind.Blunt; } } } }