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