diff --git a/Content.Shared/Containers/ItemSlot/ItemSlotsLockComponent.cs b/Content.Shared/Containers/ItemSlot/ItemSlotsLockComponent.cs
new file mode 100644
index 0000000000..0d8901028d
--- /dev/null
+++ b/Content.Shared/Containers/ItemSlot/ItemSlotsLockComponent.cs
@@ -0,0 +1,13 @@
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Containers.ItemSlots;
+
+///
+/// Updates the relevant ItemSlots locks based on
+///
+[RegisterComponent, NetworkedComponent]
+public sealed partial class ItemSlotsLockComponent : Component
+{
+ [DataField(required: true)]
+ public List Slots = new();
+}
diff --git a/Content.Shared/Containers/ItemSlot/ItemSlotsSystem.Lock.cs b/Content.Shared/Containers/ItemSlot/ItemSlotsSystem.Lock.cs
new file mode 100644
index 0000000000..ee5178df95
--- /dev/null
+++ b/Content.Shared/Containers/ItemSlot/ItemSlotsSystem.Lock.cs
@@ -0,0 +1,36 @@
+using Content.Shared.Lock;
+
+namespace Content.Shared.Containers.ItemSlots;
+
+public sealed partial class ItemSlotsSystem
+{
+ private void InitializeLock()
+ {
+ SubscribeLocalEvent(OnLockMapInit);
+ SubscribeLocalEvent(OnLockToggled);
+ }
+
+ private void OnLockMapInit(Entity ent, ref MapInitEvent args)
+ {
+ if (!TryComp(ent.Owner, out LockComponent? lockComp))
+ return;
+
+ UpdateLocks(ent, lockComp.Locked);
+ }
+
+ private void OnLockToggled(Entity ent, ref LockToggledEvent args)
+ {
+ UpdateLocks(ent, args.Locked);
+ }
+
+ private void UpdateLocks(Entity ent, bool value)
+ {
+ foreach (var slot in ent.Comp.Slots)
+ {
+ if (!TryGetSlot(ent.Owner, slot, out var itemSlot))
+ continue;
+
+ SetLock(ent.Owner, itemSlot, value);
+ }
+ }
+}
diff --git a/Content.Shared/Containers/ItemSlot/ItemSlotsSystem.cs b/Content.Shared/Containers/ItemSlot/ItemSlotsSystem.cs
index 48f4f07cbe..f41fa2b22d 100644
--- a/Content.Shared/Containers/ItemSlot/ItemSlotsSystem.cs
+++ b/Content.Shared/Containers/ItemSlot/ItemSlotsSystem.cs
@@ -24,7 +24,7 @@ namespace Content.Shared.Containers.ItemSlots
/// Note when using popups on entities with many slots with InsertOnInteract, EjectOnInteract or EjectOnUse:
/// A single use will try to insert to/eject from every slot and generate a popup for each that fails.
///
- public sealed class ItemSlotsSystem : EntitySystem
+ public sealed partial class ItemSlotsSystem : EntitySystem
{
[Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
[Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!;
@@ -38,6 +38,8 @@ namespace Content.Shared.Containers.ItemSlots
{
base.Initialize();
+ InitializeLock();
+
SubscribeLocalEvent(OnMapInit);
SubscribeLocalEvent(Oninitialize);
diff --git a/Content.Shared/Item/ItemToggle/Components/ItemToggleComponent.cs b/Content.Shared/Item/ItemToggle/Components/ItemToggleComponent.cs
index 46249fdd0d..47edec135d 100644
--- a/Content.Shared/Item/ItemToggle/Components/ItemToggleComponent.cs
+++ b/Content.Shared/Item/ItemToggle/Components/ItemToggleComponent.cs
@@ -19,6 +19,12 @@ public sealed partial class ItemToggleComponent : Component
[DataField, AutoNetworkedField]
public bool Activated = false;
+ ///
+ /// Can the entity be activated in the world.
+ ///
+ [DataField]
+ public bool OnActivate = true;
+
///
/// If this is set to false then the item can't be toggled by pressing Z.
/// Use another system to do it then.
@@ -52,12 +58,6 @@ public sealed partial class ItemToggleComponent : Component
///
[ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField]
public SoundSpecifier? SoundFailToActivate;
-
- ///
- /// Whether or not to toggle the entity's lights on or off.
- ///
- [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField]
- public bool ToggleLight = true;
}
///
diff --git a/Content.Shared/Item/ItemToggle/ItemToggleSystem.cs b/Content.Shared/Item/ItemToggle/ItemToggleSystem.cs
index 1cc8699d70..33b88dbaf8 100644
--- a/Content.Shared/Item/ItemToggle/ItemToggleSystem.cs
+++ b/Content.Shared/Item/ItemToggle/ItemToggleSystem.cs
@@ -1,8 +1,10 @@
+using Content.Shared.Interaction;
using Content.Shared.Interaction.Events;
using Content.Shared.Item.ItemToggle.Components;
using Content.Shared.Popups;
using Content.Shared.Temperature;
using Content.Shared.Toggleable;
+using Content.Shared.Verbs;
using Content.Shared.Wieldable;
using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
@@ -20,7 +22,6 @@ public sealed class ItemToggleSystem : EntitySystem
[Dependency] private readonly INetManager _netManager = default!;
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
- [Dependency] private readonly SharedPointLightSystem _light = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!;
private EntityQuery _query;
@@ -36,6 +37,8 @@ public sealed class ItemToggleSystem : EntitySystem
SubscribeLocalEvent(TurnOffOnUnwielded);
SubscribeLocalEvent(TurnOnOnWielded);
SubscribeLocalEvent(OnUseInHand);
+ SubscribeLocalEvent>(OnActivateVerb);
+ SubscribeLocalEvent(OnActivate);
SubscribeLocalEvent(OnIsHotEvent);
@@ -66,6 +69,32 @@ public sealed class ItemToggleSystem : EntitySystem
Toggle((ent, ent.Comp), args.User, predicted: ent.Comp.Predictable);
}
+ private void OnActivateVerb(Entity ent, ref GetVerbsEvent args)
+ {
+ if (!args.CanAccess || !args.CanInteract)
+ return;
+
+ var user = args.User;
+
+ args.Verbs.Add(new ActivationVerb()
+ {
+ Text = !ent.Comp.Activated ? Loc.GetString("item-toggle-activate") : Loc.GetString("item-toggle-deactivate"),
+ Act = () =>
+ {
+ Toggle((ent.Owner, ent.Comp), user, predicted: ent.Comp.Predictable);
+ }
+ });
+ }
+
+ private void OnActivate(Entity ent, ref ActivateInWorldEvent args)
+ {
+ if (args.Handled || !ent.Comp.OnActivate)
+ return;
+
+ args.Handled = true;
+ Toggle((ent.Owner, ent.Comp), args.User, predicted: ent.Comp.Predictable);
+ }
+
///
/// Used when an item is attempted to be toggled.
/// Sets its state to the opposite of what it is.
@@ -203,16 +232,7 @@ public sealed class ItemToggleSystem : EntitySystem
if (TryComp(ent, out AppearanceComponent? appearance))
{
_appearance.SetData(ent, ToggleVisuals.Toggled, ent.Comp.Activated, appearance);
-
- if (ent.Comp.ToggleLight)
- _appearance.SetData(ent, ToggleableLightVisuals.Enabled, ent.Comp.Activated, appearance);
}
-
- if (!ent.Comp.ToggleLight)
- return;
-
- if (_light.TryGetLight(ent, out var light))
- _light.SetEnabled(ent, ent.Comp.Activated, light);
}
///
diff --git a/Content.Shared/Light/Components/ItemTogglePointLightComponent.cs b/Content.Shared/Light/Components/ItemTogglePointLightComponent.cs
new file mode 100644
index 0000000000..6ac1bf236d
--- /dev/null
+++ b/Content.Shared/Light/Components/ItemTogglePointLightComponent.cs
@@ -0,0 +1,12 @@
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Light.Components;
+
+///
+/// Toggles point light on an entity whenever ItemToggle hits.
+///
+[RegisterComponent, NetworkedComponent]
+public sealed partial class ItemTogglePointLightComponent : Component
+{
+
+}
diff --git a/Content.Shared/Light/EntitySystems/ItemTogglePointLightSystem.cs b/Content.Shared/Light/EntitySystems/ItemTogglePointLightSystem.cs
new file mode 100644
index 0000000000..7030c538c1
--- /dev/null
+++ b/Content.Shared/Light/EntitySystems/ItemTogglePointLightSystem.cs
@@ -0,0 +1,29 @@
+using Content.Shared.Item.ItemToggle.Components;
+using Content.Shared.Toggleable;
+using ItemTogglePointLightComponent = Content.Shared.Light.Components.ItemTogglePointLightComponent;
+
+namespace Content.Shared.Light.EntitySystems;
+
+///
+/// Handles ItemToggle for PointLight
+///
+public sealed class ItemTogglePointLightSystem : EntitySystem
+{
+ [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
+ [Dependency] private readonly SharedPointLightSystem _light = default!;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+ SubscribeLocalEvent(OnLightToggled);
+ }
+
+ private void OnLightToggled(Entity ent, ref ItemToggledEvent args)
+ {
+ if (!_light.TryGetLight(ent.Owner, out var light))
+ return;
+
+ _appearance.SetData(ent, ToggleableLightVisuals.Enabled, args.Activated);
+ _light.SetEnabled(ent.Owner, args.Activated, comp: light);
+ }
+}
diff --git a/Content.Shared/Power/Components/ItemSlotRequiresPowerComponent.cs b/Content.Shared/Power/Components/ItemSlotRequiresPowerComponent.cs
new file mode 100644
index 0000000000..6e3b9eaca0
--- /dev/null
+++ b/Content.Shared/Power/Components/ItemSlotRequiresPowerComponent.cs
@@ -0,0 +1,9 @@
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Power.Components;
+
+[RegisterComponent, NetworkedComponent]
+public sealed partial class ItemSlotRequiresPowerComponent : Component
+{
+
+}
diff --git a/Content.Shared/Power/EntitySystems/ItemSlotRequiresPowerSystem.cs b/Content.Shared/Power/EntitySystems/ItemSlotRequiresPowerSystem.cs
new file mode 100644
index 0000000000..3df8b91a98
--- /dev/null
+++ b/Content.Shared/Power/EntitySystems/ItemSlotRequiresPowerSystem.cs
@@ -0,0 +1,23 @@
+using Content.Shared.Containers.ItemSlots;
+using Content.Shared.Power.Components;
+
+namespace Content.Shared.Power.EntitySystems;
+
+public sealed class ItemSlotRequiresPowerSystem : EntitySystem
+{
+ [Dependency] private readonly SharedPowerReceiverSystem _receiver = default!;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+ SubscribeLocalEvent(OnInsertAttempt);
+ }
+
+ private void OnInsertAttempt(Entity ent, ref ItemSlotInsertAttemptEvent args)
+ {
+ if (!_receiver.IsPowered(ent.Owner))
+ {
+ args.Cancelled = true;
+ }
+ }
+}
diff --git a/Resources/Locale/en-US/items/toggle.ftl b/Resources/Locale/en-US/items/toggle.ftl
new file mode 100644
index 0000000000..bcf5c161a6
--- /dev/null
+++ b/Resources/Locale/en-US/items/toggle.ftl
@@ -0,0 +1,2 @@
+item-toggle-activate = Activate
+item-toggle-deactivate = Deactivate