namespace Content.Client.Cabinet;
-public sealed class ItemCabinetSystem : VisualizerSystem<ItemCabinetVisualsComponent>
+public sealed class ItemCabinetSystem : SharedItemCabinetSystem
{
- protected override void OnAppearanceChange(EntityUid uid, ItemCabinetVisualsComponent component, ref AppearanceChangeEvent args)
+ protected override void UpdateAppearance(EntityUid uid, ItemCabinetComponent? cabinet = null)
{
- if (args.Sprite == null)
+ if (!Resolve(uid, ref cabinet))
return;
- if (AppearanceSystem.TryGetData<bool>(uid, ItemCabinetVisuals.IsOpen, out var isOpen, args.Component)
- && AppearanceSystem.TryGetData<bool>(uid, ItemCabinetVisuals.ContainsItem, out var contains, args.Component))
- {
- var state = isOpen ? component.OpenState : component.ClosedState;
- args.Sprite.LayerSetState(ItemCabinetVisualLayers.Door, state);
- args.Sprite.LayerSetVisible(ItemCabinetVisualLayers.ContainsItem, contains);
- }
+ if (!TryComp<SpriteComponent>(uid, out var sprite))
+ return;
+
+ var state = cabinet.Opened ? cabinet.OpenState : cabinet.ClosedState;
+ if (state != null)
+ sprite.LayerSetState(ItemCabinetVisualLayers.Door, state);
+ sprite.LayerSetVisible(ItemCabinetVisualLayers.ContainsItem, cabinet.CabinetSlot.HasItem);
}
}
+++ /dev/null
-namespace Content.Client.Cabinet;
-
-[RegisterComponent]
-public sealed class ItemCabinetVisualsComponent : Component
-{
- [DataField("openState", required: true)]
- public string OpenState = default!;
-
- [DataField("closedState", required: true)]
- public string ClosedState = default!;
-}
+++ /dev/null
-using Content.Shared.Containers.ItemSlots;
-using Robust.Shared.Audio;
-
-namespace Content.Server.Cabinet
-{
- /// <summary>
- /// Used for entities that can be opened, closed, and can hold one item. E.g., fire extinguisher cabinets.
- /// </summary>
- [RegisterComponent]
- public sealed class ItemCabinetComponent : Component
- {
- /// <summary>
- /// Sound to be played when the cabinet door is opened.
- /// </summary>
- [ViewVariables(VVAccess.ReadWrite)]
- [DataField("doorSound", required: true)]
- public SoundSpecifier DoorSound { get; set; } = default!;
-
- /// <summary>
- /// The <see cref="ItemSlot"/> that stores the actual item. The entity whitelist, sounds, and other
- /// behaviours are specified by this <see cref="ItemSlot"/> definition.
- /// </summary>
- [DataField("cabinetSlot")]
- public ItemSlot CabinetSlot = new();
-
- /// <summary>
- /// Whether the cabinet is currently open or not.
- /// </summary>
- [DataField("opened")]
- public bool Opened { get; set; } = false;
- }
-}
-using Content.Server.Storage.Components;
-using Content.Shared.Audio;
using Content.Shared.Cabinet;
-using Content.Shared.Containers.ItemSlots;
-using Content.Shared.Interaction;
-using Content.Shared.Lock;
-using Content.Shared.Verbs;
-using Robust.Server.GameObjects;
-using Robust.Shared.Audio;
-using Robust.Shared.Containers;
-using Robust.Shared.Player;
-namespace Content.Server.Cabinet
-{
- public sealed class ItemCabinetSystem : EntitySystem
- {
- [Dependency] private readonly IComponentFactory _factory = default!;
- [Dependency] private readonly ItemSlotsSystem _itemSlotsSystem = default!;
- [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
-
- public override void Initialize()
- {
- base.Initialize();
-
- SubscribeLocalEvent<ItemCabinetComponent, ComponentInit>(OnComponentInit);
- SubscribeLocalEvent<ItemCabinetComponent, ComponentRemove>(OnComponentRemove);
- SubscribeLocalEvent<ItemCabinetComponent, ComponentStartup>(OnComponentStartup);
-
- SubscribeLocalEvent<ItemCabinetComponent, ActivateInWorldEvent>(OnActivateInWorld);
- SubscribeLocalEvent<ItemCabinetComponent, GetVerbsEvent<ActivationVerb>>(AddToggleOpenVerb);
-
- SubscribeLocalEvent<ItemCabinetComponent, EntInsertedIntoContainerMessage>(OnContainerModified);
- SubscribeLocalEvent<ItemCabinetComponent, EntRemovedFromContainerMessage>(OnContainerModified);
-
- SubscribeLocalEvent<ItemCabinetComponent, LockToggleAttemptEvent>(OnLockToggleAttempt);
- }
-
- private void OnComponentInit(EntityUid uid, ItemCabinetComponent cabinet, ComponentInit args)
- {
- _itemSlotsSystem.AddItemSlot(uid, _factory.GetComponentName(cabinet.GetType()), cabinet.CabinetSlot);
- }
- private void OnComponentRemove(EntityUid uid, ItemCabinetComponent cabinet, ComponentRemove args)
- {
- _itemSlotsSystem.RemoveItemSlot(uid, cabinet.CabinetSlot);
- }
-
- private void OnComponentStartup(EntityUid uid, ItemCabinetComponent cabinet, ComponentStartup args)
- {
- UpdateAppearance(uid, cabinet);
- _itemSlotsSystem.SetLock(uid, cabinet.CabinetSlot, !cabinet.Opened);
- }
-
- private void UpdateAppearance(EntityUid uid,
- ItemCabinetComponent? cabinet = null,
- AppearanceComponent? appearance = null)
- {
- if (!Resolve(uid, ref cabinet, ref appearance, false))
- return;
-
- _appearance.SetData(uid, ItemCabinetVisuals.IsOpen, cabinet.Opened, appearance);
- _appearance.SetData(uid, ItemCabinetVisuals.ContainsItem, cabinet.CabinetSlot.HasItem, appearance);
- }
-
- private void OnContainerModified(EntityUid uid, ItemCabinetComponent cabinet, ContainerModifiedMessage args)
- {
- if (!cabinet.Initialized) return;
-
- if (args.Container.ID == cabinet.CabinetSlot.ID)
- UpdateAppearance(uid, cabinet);
- }
+namespace Content.Server.Cabinet;
- private void OnLockToggleAttempt(EntityUid uid, ItemCabinetComponent cabinet, ref LockToggleAttemptEvent args)
- {
- // Cannot lock or unlock while open.
- if (cabinet.Opened)
- args.Cancelled = true;
- }
-
- private void AddToggleOpenVerb(EntityUid uid, ItemCabinetComponent cabinet, GetVerbsEvent<ActivationVerb> args)
- {
- if (args.Hands == null || !args.CanAccess || !args.CanInteract)
- return;
-
- if (TryComp<LockComponent>(uid, out var lockComponent) && lockComponent.Locked)
- return;
-
- // Toggle open verb
- ActivationVerb toggleVerb = new();
- toggleVerb.Act = () => ToggleItemCabinet(uid, cabinet);
- if (cabinet.Opened)
- {
- toggleVerb.Text = Loc.GetString("verb-common-close");
- toggleVerb.IconTexture = "/Textures/Interface/VerbIcons/close.svg.192dpi.png";
- }
- else
- {
- toggleVerb.Text = Loc.GetString("verb-common-open");
- toggleVerb.IconTexture = "/Textures/Interface/VerbIcons/open.svg.192dpi.png";
- }
- args.Verbs.Add(toggleVerb);
- }
-
- private void OnActivateInWorld(EntityUid uid, ItemCabinetComponent comp, ActivateInWorldEvent args)
- {
- if (args.Handled)
- return;
-
- args.Handled = true;
- ToggleItemCabinet(uid, comp);
- }
-
- /// <summary>
- /// Toggles the ItemCabinet's state.
- /// </summary>
- private void ToggleItemCabinet(EntityUid uid, ItemCabinetComponent? cabinet = null)
- {
- if (!Resolve(uid, ref cabinet))
- return;
-
- if (TryComp<LockComponent>(uid, out var lockComponent) && lockComponent.Locked)
- return;
-
- cabinet.Opened = !cabinet.Opened;
- SoundSystem.Play(cabinet.DoorSound.GetSound(), Filter.Pvs(uid), uid, AudioHelpers.WithVariation(0.15f));
- _itemSlotsSystem.SetLock(uid, cabinet.CabinetSlot, !cabinet.Opened);
-
- UpdateAppearance(uid, cabinet);
- }
- }
+public sealed class ItemCabinetSystem : SharedItemCabinetSystem
+{
+ // shitposting on main???
}
+
--- /dev/null
+using Content.Shared.Containers.ItemSlots;
+using Robust.Shared.Audio;
+using Robust.Shared.GameStates;
+using Robust.Shared.Serialization;
+
+namespace Content.Shared.Cabinet;
+
+/// <summary>
+/// Used for entities that can be opened, closed, and can hold one item. E.g., fire extinguisher cabinets.
+/// </summary>
+[RegisterComponent, NetworkedComponent]
+public sealed class ItemCabinetComponent : Component
+{
+ /// <summary>
+ /// Sound to be played when the cabinet door is opened.
+ /// </summary>
+ [DataField("doorSound"), ViewVariables(VVAccess.ReadWrite)]
+ public SoundSpecifier? DoorSound;
+
+ /// <summary>
+ /// The <see cref="ItemSlot"/> that stores the actual item. The entity whitelist, sounds, and other
+ /// behaviours are specified by this <see cref="ItemSlot"/> definition.
+ /// </summary>
+ [DataField("cabinetSlot"), ViewVariables]
+ public ItemSlot CabinetSlot = new();
+
+ /// <summary>
+ /// Whether the cabinet is currently open or not.
+ /// </summary>
+ [DataField("opened")]
+ public bool Opened;
+
+ /// <summary>
+ /// The state for when the cabinet is open
+ /// </summary>
+ [DataField("openState"), ViewVariables(VVAccess.ReadWrite)]
+ public string? OpenState;
+
+ /// <summary>
+ /// The state for when the cabinet is closed
+ /// </summary>
+ [DataField("closedState"), ViewVariables(VVAccess.ReadWrite)]
+ public string? ClosedState;
+}
+
+[Serializable, NetSerializable]
+public sealed class ItemCabinetComponentState : ComponentState
+{
+ public SoundSpecifier? DoorSound;
+
+ public bool Opened;
+
+ public string? OpenState;
+
+ public string? ClosedState;
+
+ public ItemCabinetComponentState(SoundSpecifier? doorSound, bool opened, string? openState, string? closedState)
+ {
+ DoorSound = doorSound;
+ Opened = opened;
+ OpenState = openState;
+ ClosedState = closedState;
+ }
+}
+
+++ /dev/null
-using Robust.Shared.Serialization;
-
-namespace Content.Shared.Cabinet
-{
- [Serializable, NetSerializable]
- public enum ItemCabinetVisuals : byte
- {
- IsOpen,
- ContainsItem
- }
-}
--- /dev/null
+using Content.Shared.Containers.ItemSlots;
+using Content.Shared.Interaction;
+using Content.Shared.Lock;
+using Content.Shared.Verbs;
+using Robust.Shared.Audio;
+using Robust.Shared.Containers;
+using Robust.Shared.GameStates;
+using Robust.Shared.Timing;
+
+namespace Content.Shared.Cabinet;
+
+public abstract class SharedItemCabinetSystem : EntitySystem
+{
+ [Dependency] private readonly IGameTiming _timing = default!;
+ [Dependency] private readonly ItemSlotsSystem _itemSlots = default!;
+ [Dependency] private readonly SharedAudioSystem _audio = default!;
+
+ /// <inheritdoc/>
+ public override void Initialize()
+ {
+ SubscribeLocalEvent<ItemCabinetComponent, ComponentGetState>(OnGetState);
+ SubscribeLocalEvent<ItemCabinetComponent, ComponentHandleState>(OnHandleState);
+
+ SubscribeLocalEvent<ItemCabinetComponent, ComponentInit>(OnComponentInit);
+ SubscribeLocalEvent<ItemCabinetComponent, ComponentRemove>(OnComponentRemove);
+ SubscribeLocalEvent<ItemCabinetComponent, ComponentStartup>(OnComponentStartup);
+
+ SubscribeLocalEvent<ItemCabinetComponent, ActivateInWorldEvent>(OnActivateInWorld);
+ SubscribeLocalEvent<ItemCabinetComponent, GetVerbsEvent<AlternativeVerb>>(AddToggleOpenVerb);
+
+ SubscribeLocalEvent<ItemCabinetComponent, EntInsertedIntoContainerMessage>(OnContainerModified);
+ SubscribeLocalEvent<ItemCabinetComponent, EntRemovedFromContainerMessage>(OnContainerModified);
+
+ SubscribeLocalEvent<ItemCabinetComponent, LockToggleAttemptEvent>(OnLockToggleAttempt);
+ }
+
+ private void OnGetState(EntityUid uid, ItemCabinetComponent component, ref ComponentGetState args)
+ {
+ args.State = new ItemCabinetComponentState(component.DoorSound,
+ component.Opened,
+ component.OpenState,
+ component.ClosedState);
+ }
+
+ private void OnHandleState(EntityUid uid, ItemCabinetComponent component, ref ComponentHandleState args)
+ {
+ if (args.Current is not ItemCabinetComponentState state)
+ return;
+ component.DoorSound = state.DoorSound;
+ component.Opened = state.Opened;
+ component.OpenState = state.OpenState;
+ component.ClosedState = state.ClosedState;
+ }
+
+ private void OnComponentInit(EntityUid uid, ItemCabinetComponent cabinet, ComponentInit args)
+ {
+ _itemSlots.AddItemSlot(uid, "ItemCabinet", cabinet.CabinetSlot);
+ }
+
+ private void OnComponentRemove(EntityUid uid, ItemCabinetComponent cabinet, ComponentRemove args)
+ {
+ _itemSlots.RemoveItemSlot(uid, cabinet.CabinetSlot);
+ }
+
+ private void OnComponentStartup(EntityUid uid, ItemCabinetComponent cabinet, ComponentStartup args)
+ {
+ UpdateAppearance(uid, cabinet);
+ _itemSlots.SetLock(uid, cabinet.CabinetSlot, !cabinet.Opened);
+ }
+
+ protected virtual void UpdateAppearance(EntityUid uid, ItemCabinetComponent? cabinet = null)
+ {
+ // we don't fuck with appearance data, and instead just manually update the sprite on the client
+ }
+
+ private void OnContainerModified(EntityUid uid, ItemCabinetComponent cabinet, ContainerModifiedMessage args)
+ {
+ if (!cabinet.Initialized)
+ return;
+
+ if (args.Container.ID == cabinet.CabinetSlot.ID)
+ UpdateAppearance(uid, cabinet);
+ }
+
+ private void OnLockToggleAttempt(EntityUid uid, ItemCabinetComponent cabinet, ref LockToggleAttemptEvent args)
+ {
+ // Cannot lock or unlock while open.
+ if (cabinet.Opened)
+ args.Cancelled = true;
+ }
+
+ private void AddToggleOpenVerb(EntityUid uid, ItemCabinetComponent cabinet, GetVerbsEvent<AlternativeVerb> args)
+ {
+ if (args.Hands == null || !args.CanAccess || !args.CanInteract)
+ return;
+
+ if (TryComp<LockComponent>(uid, out var lockComponent) && lockComponent.Locked)
+ return;
+
+ // Toggle open verb
+ AlternativeVerb toggleVerb = new()
+ {
+ Act = () => ToggleItemCabinet(uid, args.User, cabinet)
+ };
+ if (cabinet.Opened)
+ {
+ toggleVerb.Text = Loc.GetString("verb-common-close");
+ toggleVerb.IconTexture = "/Textures/Interface/VerbIcons/close.svg.192dpi.png";
+ }
+ else
+ {
+ toggleVerb.Text = Loc.GetString("verb-common-open");
+ toggleVerb.IconTexture = "/Textures/Interface/VerbIcons/open.svg.192dpi.png";
+ }
+ args.Verbs.Add(toggleVerb);
+ }
+
+ private void OnActivateInWorld(EntityUid uid, ItemCabinetComponent comp, ActivateInWorldEvent args)
+ {
+ if (args.Handled)
+ return;
+
+ args.Handled = true;
+ ToggleItemCabinet(uid, args.User, comp);
+ }
+
+ /// <summary>
+ /// Toggles the ItemCabinet's state.
+ /// </summary>
+ public void ToggleItemCabinet(EntityUid uid, EntityUid? user = null, ItemCabinetComponent? cabinet = null)
+ {
+ if (!Resolve(uid, ref cabinet))
+ return;
+
+ if (TryComp<LockComponent>(uid, out var lockComponent) && lockComponent.Locked)
+ return;
+
+ cabinet.Opened = !cabinet.Opened;
+ Dirty(cabinet);
+ _itemSlots.SetLock(uid, cabinet.CabinetSlot, !cabinet.Opened);
+
+ if (_timing.IsFirstTimePredicted)
+ {
+ UpdateAppearance(uid, cabinet);
+ _audio.PlayPredicted(cabinet.DoorSound, uid, user, AudioParams.Default.WithVariation(0.15f));
+ }
+ }
+}
- FireExtinguisher
doorSound:
path: /Audio/Machines/machine_switch.ogg
- - type: Appearance
- - type: ItemCabinetVisuals
openState: open
closedState: closed
+ - type: Appearance
- type: ItemSlots
- type: ContainerContainer
containers:
components:
- type: ItemCabinet
opened: true
+ doorSound:
+ path: /Audio/Machines/machine_switch.ogg
+ openState: open
+ closedState: closed
- type: entity
id: ExtinguisherCabinetFilled
whitelist:
components:
- FireExtinguisher
+ doorSound:
+ path: /Audio/Machines/machine_switch.ogg
+ openState: open
+ closedState: closed
- type: entity
id: ExtinguisherCabinetFilledOpen
components:
- type: ItemCabinet
opened: true
+ doorSound:
+ path: /Audio/Machines/machine_switch.ogg
+ openState: open
+ closedState: closed
name: fire axe cabinet
description: There is a small label that reads "For Emergency use only" along with details for safe use of the axe. As if.
components:
- - type: MeleeSound
- soundGroups:
- Brute:
- path:
- "/Audio/Effects/glass_hit.ogg"
- - type: WallMount
- - type: Clickable
- - type: InteractionOutline
- - type: Sprite
- sprite: Structures/Wallmounts/fireaxe_cabinet.rsi
- netsync: false
- layers:
- - state: cabinet
- - state: fireaxe
- map: ["enum.ItemCabinetVisualLayers.ContainsItem"]
- visible: true
- - state: glass
- map: ["enum.ItemCabinetVisualLayers.Door"]
- - type: ItemCabinet
- cabinetSlot:
- ejectOnInteract: true
- whitelist:
- tags:
- - FireAxe
- doorSound:
- path: /Audio/Machines/machine_switch.ogg
- - type: Appearance
- - type: ItemCabinetVisuals
- openState: glass-up
- closedState: glass
- - type: Lock
- - type: AccessReader
- access: [["Atmospherics"]]
- - type: ItemSlots
- - type: ContainerContainer
- containers:
- ItemCabinet: !type:ContainerSlot
+ - type: MeleeSound
+ soundGroups:
+ Brute:
+ path:
+ "/Audio/Effects/glass_hit.ogg"
+ - type: WallMount
+ - type: Clickable
+ - type: InteractionOutline
+ - type: Sprite
+ sprite: Structures/Wallmounts/fireaxe_cabinet.rsi
+ netsync: false
+ layers:
+ - state: cabinet
+ - state: fireaxe
+ map: ["enum.ItemCabinetVisualLayers.ContainsItem"]
+ visible: true
+ - state: glass
+ map: ["enum.ItemCabinetVisualLayers.Door"]
+ - type: ItemCabinet
+ cabinetSlot:
+ ejectOnInteract: true
+ whitelist:
+ tags:
+ - FireAxe
+ doorSound:
+ path: /Audio/Machines/machine_switch.ogg
+ openState: glass-up
+ closedState: glass
+ - type: Appearance
+ - type: Lock
+ - type: AccessReader
+ access: [["Atmospherics"]]
+ - type: ItemSlots
+ - type: ContainerContainer
+ containers:
+ ItemCabinet: !type:ContainerSlot
placement:
mode: SnapgridCenter
components:
- type: ItemCabinet
opened: true
+ doorSound:
+ path: /Audio/Machines/machine_switch.ogg
+ openState: glass-up
+ closedState: glass
- type: entity
id: FireAxeCabinetFilled
whitelist:
tags:
- FireAxe
+ doorSound:
+ path: /Audio/Machines/machine_switch.ogg
+ openState: glass-up
+ closedState: glass
- type: entity
id: FireAxeCabinetFilledOpen
components:
- type: ItemCabinet
opened: true
+ doorSound:
+ path: /Audio/Machines/machine_switch.ogg
+ openState: glass-up
+ closedState: glass