diff --git a/Content.Server/Toilet/ToiletSystem.cs b/Content.Server/Toilet/ToiletSystem.cs
deleted file mode 100644
index e184ddf0d5..0000000000
--- a/Content.Server/Toilet/ToiletSystem.cs
+++ /dev/null
@@ -1,8 +0,0 @@
-using Content.Shared.Toilet.Systems;
-
-namespace Content.Server.Toilet;
-
-public sealed class ToiletSystem : SharedToiletSystem
-{
-
-}
diff --git a/Content.Shared/Toilet/Components/ToiletComponent.cs b/Content.Shared/Toilet/Components/ToiletComponent.cs
index 5de74e08f6..ab1d390980 100644
--- a/Content.Shared/Toilet/Components/ToiletComponent.cs
+++ b/Content.Shared/Toilet/Components/ToiletComponent.cs
@@ -2,39 +2,36 @@ using Robust.Shared.Audio;
using Robust.Shared.GameStates;
using Robust.Shared.Serialization;
-namespace Content.Shared.Toilet.Components
+namespace Content.Shared.Toilet.Components;
+
+///
+/// Seats that can toggled up and down with visuals to match.
+///
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
+public sealed partial class ToiletComponent : Component
{
///
- /// Toilets that can be flushed, seats toggled up and down, items hidden in cistern.
+ /// Toggles seat state.
///
- [RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
- public sealed partial class ToiletComponent : Component
- {
- ///
- /// Toggles seat state.
- ///
- [DataField, AutoNetworkedField]
- public bool ToggleSeat;
+ [DataField, AutoNetworkedField]
+ public bool ToggleSeat;
-
- ///
- /// Sound to play when toggling toilet seat.
- ///
- [DataField]
- public SoundSpecifier SeatSound = new SoundPathSpecifier("/Audio/Effects/toilet_seat_down.ogg");
- }
-
- [Serializable, NetSerializable]
- public enum ToiletVisuals : byte
- {
- SeatVisualState,
- }
-
- [Serializable, NetSerializable]
- public enum SeatVisualState : byte
- {
- SeatUp,
- SeatDown
- }
+ ///
+ /// Sound to play when toggling toilet seat.
+ ///
+ [DataField]
+ public SoundSpecifier SeatSound = new SoundPathSpecifier("/Audio/Effects/toilet_seat_down.ogg");
}
+[Serializable, NetSerializable]
+public enum ToiletVisuals : byte
+{
+ SeatVisualState,
+}
+
+[Serializable, NetSerializable]
+public enum SeatVisualState : byte
+{
+ SeatUp,
+ SeatDown,
+}
diff --git a/Content.Shared/Toilet/Systems/SharedToiletSystem.cs b/Content.Shared/Toilet/Systems/SharedToiletSystem.cs
deleted file mode 100644
index f11af33552..0000000000
--- a/Content.Shared/Toilet/Systems/SharedToiletSystem.cs
+++ /dev/null
@@ -1,109 +0,0 @@
-using Content.Shared.Buckle.Components;
-using Content.Shared.Interaction;
-using Content.Shared.Verbs;
-using Content.Shared.Plunger.Components;
-using Robust.Shared.Audio.Systems;
-using Robust.Shared.Random;
-using Robust.Shared.Utility;
-using Content.Shared.Toilet.Components;
-
-namespace Content.Shared.Toilet.Systems
-{
- ///
- /// Handles sprite changes for both toilet seat up and down as well as for lid open and closed. Handles interactions with hidden stash
- ///
-
- public abstract class SharedToiletSystem : EntitySystem
- {
- [Dependency] private readonly IRobustRandom _random = default!;
- [Dependency] private readonly SharedAudioSystem _audio = default!;
- [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
-
- public override void Initialize()
- {
- base.Initialize();
-
- SubscribeLocalEvent(OnMapInit);
- SubscribeLocalEvent>(OnToggleSeatVerb);
- SubscribeLocalEvent(OnActivateInWorld);
- }
-
- private void OnMapInit(EntityUid uid, ToiletComponent component, MapInitEvent args)
- {
- if (_random.Prob(0.5f))
- component.ToggleSeat = true;
-
- if (_random.Prob(0.3f))
- {
- TryComp(uid, out var plunger);
-
- if (plunger == null)
- return;
-
- plunger.NeedsPlunger = true;
- }
-
- UpdateAppearance(uid);
- Dirty(uid, component);
- }
-
- public bool CanToggle(EntityUid uid)
- {
- return TryComp(uid, out var strap) && strap.BuckledEntities.Count == 0;
- }
-
- private void OnToggleSeatVerb(EntityUid uid, ToiletComponent component, GetVerbsEvent args)
- {
- if (!args.CanInteract || !args.CanAccess || !CanToggle(uid) || args.Hands == null)
- return;
-
- AlternativeVerb toggleVerb = new()
- {
- Act = () => ToggleToiletSeat(uid, args.User, component)
- };
-
- if (component.ToggleSeat)
- {
- toggleVerb.Text = Loc.GetString("toilet-seat-close");
- toggleVerb.Icon =
- new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/VerbIcons/close.svg.192dpi.png"));
- }
- else
- {
- toggleVerb.Text = Loc.GetString("toilet-seat-open");
- toggleVerb.Icon =
- new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/VerbIcons/open.svg.192dpi.png"));
- }
- args.Verbs.Add(toggleVerb);
- }
-
- private void OnActivateInWorld(EntityUid uid, ToiletComponent comp, ActivateInWorldEvent args)
- {
- if (args.Handled || !args.Complex)
- return;
-
- args.Handled = true;
- ToggleToiletSeat(uid, args.User, comp);
- }
-
- public void ToggleToiletSeat(EntityUid uid, EntityUid? user = null, ToiletComponent? component = null, MetaDataComponent? meta = null)
- {
- if (!Resolve(uid, ref component))
- return;
-
- component.ToggleSeat = !component.ToggleSeat;
-
- _audio.PlayPredicted(component.SeatSound, uid, uid);
- UpdateAppearance(uid, component);
- Dirty(uid, component, meta);
- }
-
- private void UpdateAppearance(EntityUid uid, ToiletComponent? component = null)
- {
- if (!Resolve(uid, ref component))
- return;
-
- _appearance.SetData(uid, ToiletVisuals.SeatVisualState, component.ToggleSeat ? SeatVisualState.SeatUp : SeatVisualState.SeatDown);
- }
- }
-}
diff --git a/Content.Shared/Toilet/Systems/ToiletSystem.cs b/Content.Shared/Toilet/Systems/ToiletSystem.cs
new file mode 100644
index 0000000000..ad08012b11
--- /dev/null
+++ b/Content.Shared/Toilet/Systems/ToiletSystem.cs
@@ -0,0 +1,116 @@
+using Content.Shared.Buckle.Components;
+using Content.Shared.Interaction;
+using Content.Shared.Verbs;
+using Content.Shared.Plunger.Components;
+using Robust.Shared.Audio.Systems;
+using Robust.Shared.Random;
+using Robust.Shared.Utility;
+using Content.Shared.Toilet.Components;
+
+namespace Content.Shared.Toilet.Systems;
+
+///
+/// Handles sprite changes for both toilet seat up and down as well as for lid
+/// open and closed.
+///
+public sealed class ToiletSystem : EntitySystem
+{
+ [Dependency] private readonly IRobustRandom _random = default!;
+ [Dependency] private readonly SharedAudioSystem _audio = default!;
+ [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnMapInit);
+ SubscribeLocalEvent>(OnToggleSeatVerb);
+ SubscribeLocalEvent(OnActivateInWorld);
+ }
+
+ private void OnMapInit(Entity ent, ref MapInitEvent args)
+ {
+ if (_random.Prob(0.5f))
+ {
+ ent.Comp.ToggleSeat = true;
+ Dirty(ent);
+ }
+
+ if (_random.Prob(0.3f)
+ && TryComp(ent, out var plunger))
+ {
+ plunger.NeedsPlunger = true;
+ Dirty(ent, plunger);
+ }
+
+ UpdateAppearance(ent);
+ }
+
+ private void OnToggleSeatVerb(Entity ent, ref GetVerbsEvent args)
+ {
+ if (!args.CanInteract || !args.CanAccess || args.Hands == null || !CanToggle(ent))
+ return;
+
+ var user = args.User;
+ AlternativeVerb toggleVerb = new() { Act = () => ToggleToiletSeat(ent.AsNullable(), user) };
+
+ if (ent.Comp.ToggleSeat)
+ {
+ toggleVerb.Text = Loc.GetString("toilet-seat-close");
+ toggleVerb.Icon =
+ new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/VerbIcons/close.svg.192dpi.png"));
+ }
+ else
+ {
+ toggleVerb.Text = Loc.GetString("toilet-seat-open");
+ toggleVerb.Icon =
+ new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/VerbIcons/open.svg.192dpi.png"));
+ }
+ args.Verbs.Add(toggleVerb);
+ }
+
+ private void OnActivateInWorld(Entity ent, ref ActivateInWorldEvent args)
+ {
+ if (args.Handled || !args.Complex)
+ return;
+
+ args.Handled = true;
+ ToggleToiletSeat(ent.AsNullable(), args.User);
+ }
+
+ private void UpdateAppearance(Entity ent)
+ {
+ _appearance.SetData(ent,
+ ToiletVisuals.SeatVisualState,
+ ent.Comp.ToggleSeat ? SeatVisualState.SeatUp : SeatVisualState.SeatDown);
+ }
+
+
+ ///
+ /// Toggles a toilet's seat. Yup. Doesn't check if anyone is on the seat.
+ ///
+ /// The toilet being seat-toggled.
+ /// The user doing the toggling; used for predicted audio.
+ ///
+ public void ToggleToiletSeat(Entity ent, EntityUid? user = null)
+ {
+ if (!Resolve(ent, ref ent.Comp))
+ return;
+
+ ent.Comp.ToggleSeat = !ent.Comp.ToggleSeat;
+
+ _audio.PlayPredicted(ent.Comp.SeatSound, ent, user);
+ UpdateAppearance((ent, ent.Comp));
+ Dirty(ent);
+ }
+
+ ///
+ /// Whether or not a toilet seat can be toggled without phasing through
+ /// someone's back. (That is, no one is seated on it.)
+ ///
+ ///
+ public bool CanToggle(EntityUid uid)
+ {
+ return TryComp(uid, out var strap) && strap.BuckledEntities.Count == 0;
+ }
+}
diff --git a/Resources/Prototypes/Entities/Structures/Furniture/toilet.yml b/Resources/Prototypes/Entities/Structures/Furniture/toilet.yml
index 1b5ac30a9c..a6753766d5 100644
--- a/Resources/Prototypes/Entities/Structures/Furniture/toilet.yml
+++ b/Resources/Prototypes/Entities/Structures/Furniture/toilet.yml
@@ -75,6 +75,9 @@
autoDrain: false
- type: StaticPrice
price: 100
+ - type: ActivatableUI
+ key: enum.DisposalUnitUiKey.Key
+ verbOnly: true # Not strictly needed, but we want E to toggle lid
- type: UserInterface
interfaces:
enum.DisposalUnitUiKey.Key: