]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
item cabinet rework + stuff (#26779)
authordeltanedas <39013340+deltanedas@users.noreply.github.com>
Wed, 29 May 2024 20:08:33 +0000 (20:08 +0000)
committerGitHub <noreply@github.com>
Wed, 29 May 2024 20:08:33 +0000 (16:08 -0400)
14 files changed:
Content.Client/Cabinet/ItemCabinetSystem.cs [deleted file]
Content.Server/Cabinet/ItemCabinetSystem.cs [deleted file]
Content.Shared/Cabinet/ItemCabinetComponent.cs
Content.Shared/Cabinet/ItemCabinetSystem.cs [new file with mode: 0644]
Content.Shared/Cabinet/SharedItemCabinetSystem.cs [deleted file]
Content.Shared/Lock/LockSystem.cs
Content.Shared/Nutrition/Components/OpenableComponent.cs
Content.Shared/Nutrition/EntitySystems/OpenableSystem.cs
Resources/Prototypes/Entities/Structures/Storage/base_cabinet.yml [new file with mode: 0644]
Resources/Prototypes/Entities/Structures/Storage/glass_box.yml
Resources/Prototypes/Entities/Structures/Wallmounts/defib_cabinet.yml
Resources/Prototypes/Entities/Structures/Wallmounts/extinguisher_cabinet.yml
Resources/Prototypes/Entities/Structures/Wallmounts/fireaxe_cabinet.yml
Resources/Prototypes/Entities/Structures/Wallmounts/shotgun_cabinet.yml

diff --git a/Content.Client/Cabinet/ItemCabinetSystem.cs b/Content.Client/Cabinet/ItemCabinetSystem.cs
deleted file mode 100644 (file)
index aba4fda..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-using Content.Shared.Cabinet;
-using Robust.Client.GameObjects;
-
-namespace Content.Client.Cabinet;
-
-public sealed class ItemCabinetSystem : SharedItemCabinetSystem
-{
-    protected override void UpdateAppearance(EntityUid uid, ItemCabinetComponent? cabinet = null)
-    {
-        if (!Resolve(uid, ref cabinet))
-            return;
-
-        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);
-    }
-}
-
-public enum ItemCabinetVisualLayers
-{
-    Door,
-    ContainsItem
-}
diff --git a/Content.Server/Cabinet/ItemCabinetSystem.cs b/Content.Server/Cabinet/ItemCabinetSystem.cs
deleted file mode 100644 (file)
index a21532a..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-using Content.Shared.Cabinet;
-
-namespace Content.Server.Cabinet;
-
-public sealed class ItemCabinetSystem : SharedItemCabinetSystem
-{
-    // shitposting on main???
-}
-
index dcc276e5651b4421787c56f0a16fd64f9a64e093..b1d7e4a263fb3d1416870687d2f725abcebb2f86 100644 (file)
@@ -1,43 +1,25 @@
-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.
+/// Used for entities that can be opened, closed, and can hold one item. E.g., fire extinguisher cabinets.
+/// Requires <c>OpenableComponent</c>.
 /// </summary>
-[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true)]
+[RegisterComponent, NetworkedComponent, Access(typeof(ItemCabinetSystem))]
 public sealed partial class ItemCabinetComponent : Component
 {
     /// <summary>
-    ///     Sound to be played when the cabinet door is opened.
+    /// Name of the <see cref="ItemSlot"/> that stores the actual item.
     /// </summary>
-    [DataField, AutoNetworkedField, 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, ViewVariables]
-    public ItemSlot CabinetSlot = new();
-
-    /// <summary>
-    ///     Whether the cabinet is currently open or not.
-    /// </summary>
-    [DataField, AutoNetworkedField]
-    public bool Opened;
-
-    /// <summary>
-    /// The state for when the cabinet is open
-    /// </summary>
-    [DataField, AutoNetworkedField, ViewVariables(VVAccess.ReadWrite)]
-    public string? OpenState;
+    [DataField]
+    public string Slot = "ItemCabinet";
+}
 
-    /// <summary>
-    /// The state for when the cabinet is closed
-    /// </summary>
-    [DataField, AutoNetworkedField, ViewVariables(VVAccess.ReadWrite)]
-    public string? ClosedState;
+[Serializable, NetSerializable]
+public enum ItemCabinetVisuals : byte
+{
+    ContainsItem,
+    Layer
 }
diff --git a/Content.Shared/Cabinet/ItemCabinetSystem.cs b/Content.Shared/Cabinet/ItemCabinetSystem.cs
new file mode 100644 (file)
index 0000000..749065a
--- /dev/null
@@ -0,0 +1,95 @@
+using Content.Shared.Containers.ItemSlots;
+using Content.Shared.Interaction;
+using Content.Shared.Nutrition.Components;
+using Content.Shared.Nutrition.EntitySystems;
+using Robust.Shared.Containers;
+using System.Diagnostics.CodeAnalysis;
+
+namespace Content.Shared.Cabinet;
+
+/// <summary>
+/// Controls ItemCabinet slot locking and visuals.
+/// </summary>
+public sealed class ItemCabinetSystem : EntitySystem
+{
+    [Dependency] private readonly ItemSlotsSystem _slots = default!;
+    [Dependency] private readonly OpenableSystem _openable = default!;
+    [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
+
+    /// <inheritdoc/>
+    public override void Initialize()
+    {
+        base.Initialize();
+
+        SubscribeLocalEvent<ItemCabinetComponent, ComponentStartup>(OnStartup);
+        SubscribeLocalEvent<ItemCabinetComponent, MapInitEvent>(OnMapInit);
+        SubscribeLocalEvent<ItemCabinetComponent, EntInsertedIntoContainerMessage>(OnContainerModified);
+        SubscribeLocalEvent<ItemCabinetComponent, EntRemovedFromContainerMessage>(OnContainerModified);
+        SubscribeLocalEvent<ItemCabinetComponent, OpenableOpenedEvent>(OnOpened);
+        SubscribeLocalEvent<ItemCabinetComponent, OpenableClosedEvent>(OnClosed);
+    }
+
+    private void OnStartup(Entity<ItemCabinetComponent> ent, ref ComponentStartup args)
+    {
+        UpdateAppearance(ent);
+    }
+
+    private void OnMapInit(Entity<ItemCabinetComponent> ent, ref MapInitEvent args)
+    {
+        // update at mapinit to avoid copy pasting locked: true and locked: false for each closed/open prototype
+        SetSlotLock(ent, !_openable.IsOpen(ent));
+    }
+
+    private void UpdateAppearance(Entity<ItemCabinetComponent> ent)
+    {
+        _appearance.SetData(ent, ItemCabinetVisuals.ContainsItem, HasItem(ent));
+    }
+
+    private void OnContainerModified(EntityUid uid, ItemCabinetComponent component, ContainerModifiedMessage args)
+    {
+        if (args.Container.ID == component.Slot)
+            UpdateAppearance((uid, component));
+    }
+
+    private void OnOpened(Entity<ItemCabinetComponent> ent, ref OpenableOpenedEvent args)
+    {
+        SetSlotLock(ent, false);
+    }
+
+    private void OnClosed(Entity<ItemCabinetComponent> ent, ref OpenableClosedEvent args)
+    {
+        SetSlotLock(ent, true);
+    }
+
+    /// <summary>
+    /// Tries to get the cabinet's item slot.
+    /// </summary>
+    public bool TryGetSlot(Entity<ItemCabinetComponent> ent, [NotNullWhen(true)] out ItemSlot? slot)
+    {
+        slot = null;
+        if (!TryComp<ItemSlotsComponent>(ent, out var slots))
+            return false;
+
+        return _slots.TryGetSlot(ent, ent.Comp.Slot, out slot, slots);
+    }
+
+    /// <summary>
+    /// Returns true if the cabinet contains an item.
+    /// </summary>
+    public bool HasItem(Entity<ItemCabinetComponent> ent)
+    {
+        return TryGetSlot(ent, out var slot) && slot.HasItem;
+    }
+
+    /// <summary>
+    /// Lock or unlock the underlying item slot.
+    /// </summary>
+    public void SetSlotLock(Entity<ItemCabinetComponent> ent, bool closed)
+    {
+        if (!TryComp<ItemSlotsComponent>(ent, out var slots))
+            return;
+
+        if (_slots.TryGetSlot(ent, ent.Comp.Slot, out var slot, slots))
+            _slots.SetLock(ent, slot, closed, slots);
+    }
+}
diff --git a/Content.Shared/Cabinet/SharedItemCabinetSystem.cs b/Content.Shared/Cabinet/SharedItemCabinetSystem.cs
deleted file mode 100644 (file)
index ca49681..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-using Content.Shared.Containers.ItemSlots;
-using Content.Shared.Interaction;
-using Content.Shared.Lock;
-using Content.Shared.Verbs;
-using Robust.Shared.Audio;
-using Robust.Shared.Audio.Systems;
-using Robust.Shared.Containers;
-using Robust.Shared.Timing;
-using Robust.Shared.Utility;
-
-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, ComponentInit>(OnComponentInit);
-        SubscribeLocalEvent<ItemCabinetComponent, ComponentRemove>(OnComponentRemove);
-        SubscribeLocalEvent<ItemCabinetComponent, ComponentStartup>(OnComponentStartup);
-        SubscribeLocalEvent<ItemCabinetComponent, AfterAutoHandleStateEvent>(OnComponentHandleState);
-
-        SubscribeLocalEvent<ItemCabinetComponent, ActivateInWorldEvent>(OnActivateInWorld);
-        SubscribeLocalEvent<ItemCabinetComponent, GetVerbsEvent<AlternativeVerb>>(AddToggleOpenVerb);
-
-        SubscribeLocalEvent<ItemCabinetComponent, EntInsertedIntoContainerMessage>(OnContainerModified);
-        SubscribeLocalEvent<ItemCabinetComponent, EntRemovedFromContainerMessage>(OnContainerModified);
-
-        SubscribeLocalEvent<ItemCabinetComponent, LockToggleAttemptEvent>(OnLockToggleAttempt);
-    }
-
-    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);
-    }
-
-    private void OnComponentHandleState(Entity<ItemCabinetComponent> ent, ref AfterAutoHandleStateEvent args)
-    {
-        UpdateAppearance(ent, ent);
-    }
-
-    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.Icon =
-                new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/VerbIcons/close.svg.192dpi.png"));
-        }
-        else
-        {
-            toggleVerb.Text = Loc.GetString("verb-common-open");
-            toggleVerb.Icon =
-                new SpriteSpecifier.Texture(new ResPath("/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(uid, 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));
-        }
-    }
-}
index 36ac5f025b1a74db203022b42c57da5b1eaf7dd0..a25dcea8a78ed207ba0d2d160f57f16675228802 100644 (file)
@@ -235,6 +235,7 @@ public sealed class LockSystem : EntitySystem
         return !ev.Cancelled;
     }
 
+    // TODO: this should be a helper on AccessReaderSystem since so many systems copy paste it
     private bool HasUserAccess(EntityUid uid, EntityUid user, AccessReaderComponent? reader = null, bool quiet = true)
     {
         // Not having an AccessComponent means you get free access. woo!
index 0381888e28244b86f6f13084aeadebe360a5a689..58d6665c588d07426c0ce8bb97f330e74491a1a6 100644 (file)
@@ -26,6 +26,12 @@ public sealed partial class OpenableComponent : Component
     [DataField, AutoNetworkedField]
     public bool OpenableByHand = true;
 
+    /// <summary>
+    /// If true, tries to open when activated in world.
+    /// </summary>
+    [DataField, AutoNetworkedField]
+    public bool OpenOnActivate;
+
     /// <summary>
     /// Text shown when examining and its open.
     /// </summary>
@@ -58,7 +64,7 @@ public sealed partial class OpenableComponent : Component
     /// Sound played when opening.
     /// </summary>
     [DataField]
-    public SoundSpecifier Sound = new SoundCollectionSpecifier("canOpenSounds");
+    public SoundSpecifier? Sound = new SoundCollectionSpecifier("canOpenSounds");
 
     /// <summary>
     /// Can this item be closed again after opening?
index 2934ced8b4a7107e7e034e08453ad60cec115d65..0a7a8d88f33caadad81a44cf41f0d28c25f892cb 100644 (file)
@@ -1,5 +1,6 @@
 using Content.Shared.Chemistry.EntitySystems;
 using Content.Shared.Examine;
+using Content.Shared.Lock;
 using Content.Shared.Interaction;
 using Content.Shared.Interaction.Events;
 using Content.Shared.Nutrition.Components;
@@ -16,6 +17,7 @@ namespace Content.Shared.Nutrition.EntitySystems;
 /// </summary>
 public sealed partial class OpenableSystem : EntitySystem
 {
+    [Dependency] private readonly LockSystem _lock = default!;
     [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
     [Dependency] private readonly SharedAudioSystem _audio = default!;
     [Dependency] private readonly SharedPopupSystem _popup = default!;
@@ -26,26 +28,49 @@ public sealed partial class OpenableSystem : EntitySystem
 
         SubscribeLocalEvent<OpenableComponent, ComponentInit>(OnInit);
         SubscribeLocalEvent<OpenableComponent, UseInHandEvent>(OnUse);
+        // always try to unlock first before opening
+        SubscribeLocalEvent<OpenableComponent, ActivateInWorldEvent>(OnActivated, after: new[] { typeof(LockSystem) });
         SubscribeLocalEvent<OpenableComponent, ExaminedEvent>(OnExamined);
         SubscribeLocalEvent<OpenableComponent, MeleeHitEvent>(HandleIfClosed);
         SubscribeLocalEvent<OpenableComponent, AfterInteractEvent>(HandleIfClosed);
-        SubscribeLocalEvent<OpenableComponent, GetVerbsEvent<Verb>>(AddOpenCloseVerbs);
+        SubscribeLocalEvent<OpenableComponent, GetVerbsEvent<AlternativeVerb>>(OnGetVerbs);
         SubscribeLocalEvent<OpenableComponent, SolutionTransferAttemptEvent>(OnTransferAttempt);
         SubscribeLocalEvent<OpenableComponent, AttemptShakeEvent>(OnAttemptShake);
         SubscribeLocalEvent<OpenableComponent, AttemptAddFizzinessEvent>(OnAttemptAddFizziness);
+        SubscribeLocalEvent<OpenableComponent, LockToggleAttemptEvent>(OnLockToggleAttempt);
+
+#if DEBUG
+        SubscribeLocalEvent<OpenableComponent, MapInitEvent>(OnMapInit);
     }
 
-    private void OnInit(EntityUid uid, OpenableComponent comp, ComponentInit args)
+    private void OnMapInit(Entity<OpenableComponent> ent, ref MapInitEvent args)
     {
-        UpdateAppearance(uid, comp);
+        if (ent.Comp.Opened && _lock.IsLocked(ent.Owner))
+            Log.Error($"Entity {ent} spawned locked open, this is a prototype mistake.");
+    }
+#else
+    }
+#endif
+
+    private void OnInit(Entity<OpenableComponent> ent, ref ComponentInit args)
+    {
+        UpdateAppearance(ent, ent.Comp);
+    }
+
+    private void OnUse(Entity<OpenableComponent> ent, ref UseInHandEvent args)
+    {
+        if (args.Handled || !ent.Comp.OpenableByHand)
+            return;
+
+        args.Handled = TryToggle(ent, args.User);
     }
 
-    private void OnUse(EntityUid uid, OpenableComponent comp, UseInHandEvent args)
+    private void OnActivated(Entity<OpenableComponent> ent, ref ActivateInWorldEvent args)
     {
-        if (args.Handled || !comp.OpenableByHand)
+        if (args.Handled || !ent.Comp.OpenOnActivate)
             return;
 
-        args.Handled = TryOpen(uid, comp, args.User);
+        args.Handled = TryToggle(ent, args.User);
     }
 
     private void OnExamined(EntityUid uid, OpenableComponent comp, ExaminedEvent args)
@@ -63,12 +88,12 @@ public sealed partial class OpenableSystem : EntitySystem
         args.Handled = !comp.Opened;
     }
 
-    private void AddOpenCloseVerbs(EntityUid uid, OpenableComponent comp, GetVerbsEvent<Verb> args)
+    private void OnGetVerbs(EntityUid uid, OpenableComponent comp, GetVerbsEvent<AlternativeVerb> args)
     {
-        if (args.Hands == null || !args.CanAccess || !args.CanInteract)
+        if (args.Hands == null || !args.CanAccess || !args.CanInteract || _lock.IsLocked(uid))
             return;
 
-        Verb verb;
+        AlternativeVerb verb;
         if (comp.Opened)
         {
             if (!comp.Closeable)
@@ -78,7 +103,8 @@ public sealed partial class OpenableSystem : EntitySystem
             {
                 Text = Loc.GetString(comp.CloseVerbText),
                 Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/close.svg.192dpi.png")),
-                Act = () => TryClose(args.Target, comp, args.User)
+                Act = () => TryClose(args.Target, comp, args.User),
+                // this verb is lower priority than drink verb (2) so it doesn't conflict
             };
         }
         else
@@ -116,6 +142,13 @@ public sealed partial class OpenableSystem : EntitySystem
             args.Cancelled = true;
     }
 
+    private void OnLockToggleAttempt(Entity<OpenableComponent> ent, ref LockToggleAttemptEvent args)
+    {
+        // can't lock something while it's open
+        if (ent.Comp.Opened)
+            args.Cancelled = true;
+    }
+
     /// <summary>
     /// Returns true if the entity either does not have OpenableComponent or it is opened.
     /// Drinks that don't have OpenableComponent are automatically open, so it returns true.
@@ -189,7 +222,12 @@ public sealed partial class OpenableSystem : EntitySystem
     /// <returns>Whether it got opened</returns>
     public bool TryOpen(EntityUid uid, OpenableComponent? comp = null, EntityUid? user = null)
     {
-        if (!Resolve(uid, ref comp, false) || comp.Opened)
+        if (!Resolve(uid, ref comp, false) || comp.Opened || _lock.IsLocked(uid))
+            return false;
+
+        var ev = new OpenableOpenAttemptEvent(user);
+        RaiseLocalEvent(uid, ref ev);
+        if (ev.Cancelled)
             return false;
 
         SetOpen(uid, true, comp, user);
@@ -211,6 +249,18 @@ public sealed partial class OpenableSystem : EntitySystem
             _audio.PlayPredicted(comp.CloseSound, uid, user);
         return true;
     }
+
+    /// <summary>
+    /// If opened, tries closing it if it's closeable.
+    /// If closed, tries opening it.
+    /// </summary>
+    public bool TryToggle(Entity<OpenableComponent> ent, EntityUid? user)
+    {
+        if (ent.Comp.Opened && ent.Comp.Closeable)
+            return TryClose(ent, ent.Comp, user);
+
+        return TryOpen(ent, ent.Comp, user);
+    }
 }
 
 /// <summary>
@@ -224,3 +274,9 @@ public record struct OpenableOpenedEvent(EntityUid? User = null);
 /// </summary>
 [ByRefEvent]
 public record struct OpenableClosedEvent(EntityUid? User = null);
+
+/// <summary>
+/// Raised before trying to open an Openable.
+/// </summary>
+[ByRefEvent]
+public record struct OpenableOpenAttemptEvent(EntityUid? User, bool Cancelled = false);
diff --git a/Resources/Prototypes/Entities/Structures/Storage/base_cabinet.yml b/Resources/Prototypes/Entities/Structures/Storage/base_cabinet.yml
new file mode 100644 (file)
index 0000000..9fcbb02
--- /dev/null
@@ -0,0 +1,44 @@
+- type: entity
+  abstract: true
+  id: BaseItemCabinet
+  components:
+  - type: Openable
+    openOnActivate: true
+    closeable: true
+    sound:
+      path: /Audio/Machines/machine_switch.ogg
+    closeSound:
+      path: /Audio/Machines/machine_switch.ogg
+  - type: ItemCabinet
+  - type: ItemSlots
+  - type: ContainerContainer
+    containers:
+      ItemCabinet: !type:ContainerSlot
+  - type: Appearance
+  # perfect for most things but you can always replace it
+  - type: GenericVisualizer
+    visuals:
+      enum.ItemCabinetVisuals.ContainsItem:
+        enum.ItemCabinetVisuals.Layer:
+          True: { visible: true }
+          False: { visible: false }
+      enum.OpenableVisuals.Opened:
+        enum.OpenableVisuals.Layer:
+          True: { state: open }
+          False: { state: closed }
+
+- type: entity
+  abstract: true
+  parent: BaseItemCabinet
+  id: BaseItemCabinetGlass
+  components:
+  - type: GenericVisualizer
+    visuals:
+      enum.ItemCabinetVisuals.ContainsItem:
+        enum.ItemCabinetVisuals.Layer:
+          True: { visible: true }
+          False: { visible: false }
+      enum.OpenableVisuals.Opened:
+        enum.OpenableVisuals.Layer:
+          True: { state: glass-up }
+          False: { state: glass }
index 8177b6b6f0d340ccdc930c69d03f2902533b7160..c868bbbc332d057bb1b64c6d1e75b0c9472612d7 100644 (file)
@@ -1,15 +1,12 @@
 - type: entity
+  parent: [BaseStructureDynamic, BaseItemCabinetGlass]
   id: BaseGlassBox
-  parent: BaseStructureDynamic
   abstract: true
-  placement:
-    mode: SnapgridCenter
   components:
   - type: Transform
     anchored: true
   - type: Physics
     bodyType: Static
-  - type: Clickable
   - type: InteractionOutline
   - type: Fixtures
     fixtures:
         layer:
         - MidImpassable
         - LowImpassable
-  - type: ItemSlots
-  - type: ContainerContainer
-    containers:
-      ItemCabinet: !type:ContainerSlot
   - type: Anchorable
     delay: 4
-  - type: Appearance
 
 - type: entity
   id: GlassBox
     layers:
     - state: base
     - state: caplaser # TODO: Remove it after item scaling in cabinets is implemented.
-      map: ["enum.ItemCabinetVisualLayers.ContainsItem"]
+      map: ["enum.ItemCabinetVisuals.Layer"]
       visible: true
     - state: glass
-      map: ["enum.ItemCabinetVisualLayers.Door"]
+      map: ["enum.OpenableVisuals.Layer"]
     - state: locked
       shader: unshaded
       map: ["enum.LockVisualLayers.Lock"]
   - type: Construction
     graph: GlassBox
     node: glassBox
-  - type: ItemCabinet
-    cabinetSlot:
-      ejectOnInteract: true
-      whitelist:
-        tags:
-        - WeaponAntiqueLaser
-    doorSound:
-      path: /Audio/Machines/machine_switch.ogg
-    openState: glass-up
-    closedState: glass
+  - type: ItemSlots
+    slots:
+      ItemCabinet:
+        ejectOnInteract: true
+        whitelist:
+          tags:
+          - WeaponAntiqueLaser
+        ejectSound: /Audio/Machines/machine_switch.ogg
 
 - type: entity
   id: GlassBoxLaserOpen
   parent: GlassBoxLaser
   suffix: AntiqueLaser, Open
   components:
+  - type: Openable
+    opened: true
   - type: Lock
     locked: false
-  - type: ItemCabinet
-    opened: true
 
 - type: entity
   id: GlassBoxLaserFilled
   parent: GlassBoxLaser
   suffix: AntiqueLaser, Filled
   components:
-  - type: ItemCabinet
-    cabinetSlot:
-      startingItem: WeaponAntiqueLaser
-      ejectOnInteract: true
-      whitelist:
-        tags:
-        - WeaponAntiqueLaser
+  - type: ContainerFill
+    containers:
+      ItemCabinet:
+      - WeaponAntiqueLaser
 
 - type: entity
+  parent: [GlassBoxLaserFilled, GlassBoxLaserOpen]
   id: GlassBoxLaserFilledOpen
-  parent: GlassBoxLaserFilled
   suffix: AntiqueLaser, Filled, Open
-  components:
-  - type: Lock
-    locked: false
-  - type: ItemCabinet
-    opened: true
 
 - type: entity
   id: GlassBoxFrame
index d9f4a827ccd43dd44b6b8b562f0d482ba8de6f7e..18b218b35169f010dee16cd4fd3d0f2be9e3c119 100644 (file)
-- type: entity
+# TODO: same as other wallmount cabinets they should use a base structure prototype
+- type: entity
+  parent: BaseItemCabinet
   id: DefibrillatorCabinet
   name: defibrillator cabinet
   description: A small wall mounted cabinet designed to hold a defibrillator.
+  placement:
+    mode: SnapgridCenter
   components:
-    - type: WallMount
-      arc: 175
-    - type: Transform
-      anchored: true
-    - type: Clickable
-    - type: InteractionOutline
-    - type: Sprite
-      sprite: Structures/Wallmounts/defib_cabinet.rsi
-      noRot: false
-      layers:
-      - state: frame
-      - state: fill
-        map: ["enum.ItemCabinetVisualLayers.ContainsItem"]
-        visible: true
-      - state: closed
-        map: ["enum.ItemCabinetVisualLayers.Door"]
-    - type: ItemCabinet
-      cabinetSlot:
+  - type: WallMount
+    arc: 175
+  - type: Transform
+    anchored: true
+  - type: Clickable
+  - type: InteractionOutline
+  - type: Sprite
+    sprite: Structures/Wallmounts/defib_cabinet.rsi
+    noRot: false
+    layers:
+    - state: frame
+    - state: fill
+      map: ["enum.ItemCabinetVisuals.Layer"]
+      visible: true
+    - state: closed
+      map: ["enum.OpenableVisuals.Layer"]
+  - type: ItemSlots
+    slots:
+      ItemCabinet:
         ejectOnInteract: true
         whitelist:
           components:
           - Defibrillator
-      doorSound:
-        path: /Audio/Machines/machine_switch.ogg
-      openState: open
-      closedState: closed
-    - type: Appearance
-    - type: ItemSlots
-    - type: ContainerContainer
-      containers:
-        ItemCabinet: !type:ContainerSlot
-    - type: Damageable
-      damageContainer: Inorganic
-      damageModifierSet: Metallic
-    - type: Destructible
-      thresholds:
-        - trigger:
-            !type:DamageTrigger
-            damage: 80
-          behaviors:
-            - !type:DoActsBehavior
-              acts: [ "Destruction" ]
-        - trigger:
-            !type:DamageTrigger
-            damage: 40
-          behaviors:
-            - !type:EmptyAllContainersBehaviour
-            - !type:DoActsBehavior
-              acts: [ "Destruction" ]
-            - !type:PlaySoundBehavior
-              sound:
-                collection: MetalGlassBreak
-  placement:
-    mode: SnapgridCenter
+  - type: Damageable
+    damageContainer: Inorganic
+    damageModifierSet: Metallic
+  - type: Destructible
+    thresholds:
+    - trigger: !type:DamageTrigger
+        damage: 80
+      behaviors:
+      - !type:DoActsBehavior
+        acts: [ "Destruction" ]
+    - trigger: !type:DamageTrigger
+        damage: 40
+      behaviors:
+      - !type:EmptyAllContainersBehaviour
+      - !type:DoActsBehavior
+        acts: [ "Destruction" ]
+      - !type:PlaySoundBehavior
+        sound:
+          collection: MetalGlassBreak
 
 - type: entity
-  id: DefibrillatorCabinetOpen
   parent: DefibrillatorCabinet
+  id: DefibrillatorCabinetOpen
   suffix: Open
   components:
-  - type: ItemCabinet
+  - type: Openable
     opened: true
-    doorSound:
-      path: /Audio/Machines/machine_switch.ogg
-    openState: open
-    closedState: closed
 
 - type: entity
-  id: DefibrillatorCabinetFilled
   parent: DefibrillatorCabinet
+  id: DefibrillatorCabinetFilled
   suffix: Filled
   components:
-  - type: ItemCabinet
-    cabinetSlot:
-      ejectOnInteract: true
-      startingItem: Defibrillator
-      whitelist:
-        components:
-        - Defibrillator
-    doorSound:
-      path: /Audio/Machines/machine_switch.ogg
-    openState: open
-    closedState: closed
+  - type: ContainerFill
+    containers:
+      ItemCabinet:
+      - Defibrillator
 
 - type: entity
+  parent: [DefibrillatorCabinetFilled, DefibrillatorCabinetOpen]
   id: DefibrillatorCabinetFilledOpen
-  parent: DefibrillatorCabinetFilled
   suffix: Filled, Open
-  components:
-  - type: ItemCabinet
-    opened: true
-    doorSound:
-      path: /Audio/Machines/machine_switch.ogg
-    openState: open
-    closedState: closed
index a0775641ef2dd8fce481b84ed4e73e7cdb7d52b7..7e6a1632a783c39e225355bd12f915f3e624b84a 100644 (file)
@@ -1,7 +1,12 @@
-- type: entity
+# TODO: this could probably use some kind of base structure prototype
+# every wallmount cabinet copypastes placement and like 8 components
+- type: entity
+  parent: BaseItemCabinet
   id: ExtinguisherCabinet
   name: extinguisher cabinet
   description: A small wall mounted cabinet designed to hold a fire extinguisher.
+  placement:
+    mode: SnapgridCenter
   components:
     - type: WallMount
       arc: 360
       layers:
       - state: frame
       - state: extinguisher
-        map: ["enum.ItemCabinetVisualLayers.ContainsItem"]
+        map: ["enum.ItemCabinetVisuals.Layer"]
         visible: true
       - state: closed
-        map: ["enum.ItemCabinetVisualLayers.Door"]
-    - type: ItemCabinet
-      cabinetSlot:
-        ejectOnInteract: true
-        whitelist:
-          components:
-          - FireExtinguisher
-      doorSound:
-        path: /Audio/Machines/machine_switch.ogg
-      openState: open
-      closedState: closed
-    - type: Appearance
+        map: ["enum.OpenableVisuals.Layer"]
     - type: ItemSlots
-    - type: ContainerContainer
-      containers:
-        ItemCabinet: !type:ContainerSlot
+      slots:
+        ItemCabinet:
+          ejectOnInteract: true
+          whitelist:
+            components:
+            - FireExtinguisher
     - type: Damageable
       damageContainer: Inorganic
       damageModifierSet: Metallic
                 collection: MetalGlassBreak
                 params:
                   volume: -4
-  placement:
-    mode: SnapgridCenter
 
 - type: entity
-  id: ExtinguisherCabinetOpen
   parent: ExtinguisherCabinet
+  id: ExtinguisherCabinetOpen
   suffix: Open
   components:
-  - type: ItemCabinet
+  - type: Openable
     opened: true
-    doorSound:
-      path: /Audio/Machines/machine_switch.ogg
-    openState: open
-    closedState: closed
 
 - type: entity
-  id: ExtinguisherCabinetFilled
   parent: ExtinguisherCabinet
+  id: ExtinguisherCabinetFilled
   suffix: Filled
   components:
-  - type: ItemCabinet
-    cabinetSlot:
-      ejectOnInteract: true
-      startingItem: FireExtinguisher
-      whitelist:
-        components:
-        - FireExtinguisher
-    doorSound:
-      path: /Audio/Machines/machine_switch.ogg
-    openState: open
-    closedState: closed
+  - type: ContainerFill
+    containers:
+      ItemCabinet:
+      - FireExtinguisher
 
 - type: entity
+  parent: [ExtinguisherCabinetFilled, ExtinguisherCabinetOpen]
   id: ExtinguisherCabinetFilledOpen
-  parent: ExtinguisherCabinetFilled
   suffix: Filled, Open
-  components:
-  - type: ItemCabinet
-    opened: true
-    doorSound:
-      path: /Audio/Machines/machine_switch.ogg
-    openState: open
-    closedState: closed
index acd865aa625880a6dfb3dc30657dd4e985f41931..42b528ce68df5fdc2a518e9180784415a2104340 100644 (file)
@@ -1,29 +1,33 @@
+# TODO: same as fire extinguisher make it use a base structure theres lots of copy paste
 - type: entity
+  parent: BaseItemCabinetGlass
   id: FireAxeCabinet
   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.
+  placement:
+    mode: SnapgridCenter
   components:
   - type: Damageable
     damageContainer: Inorganic
     damageModifierSet: Glass
   - type: Destructible
     thresholds:
-      - trigger:
-          !type:DamageTrigger
-          damage: 300
-        behaviors:
-        - !type:DoActsBehavior
-          acts: [ "Destruction" ]
-      - trigger:
-          !type:DamageTrigger
-          damage: 200 #20ish crowbar hits
-        behaviors:
-        - !type:EmptyAllContainersBehaviour
-        - !type:DoActsBehavior
-          acts: [ "Destruction" ]
-        - !type:PlaySoundBehavior
-          sound:
-            collection: MetalGlassBreak
+    - trigger:
+        !type:DamageTrigger
+        damage: 300
+      behaviors:
+      - !type:DoActsBehavior
+        acts: [ "Destruction" ]
+    - trigger:
+        !type:DamageTrigger
+        damage: 200 #20ish crowbar hits
+      behaviors:
+      - !type:EmptyAllContainersBehaviour
+      - !type:DoActsBehavior
+        acts: [ "Destruction" ]
+      - !type:PlaySoundBehavior
+        sound:
+          collection: MetalGlassBreak
   - type: MeleeSound
     soundGroups:
       Brute:
     layers:
     - state: cabinet
     - state: fireaxe
-      map: ["enum.ItemCabinetVisualLayers.ContainsItem"]
+      map: ["enum.ItemCabinetVisuals.Layer"]
       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
+      map: ["enum.OpenableVisuals.Layer"]
+  - type: ItemSlots
+    slots:
+      ItemCabinet:
+        ejectOnInteract: true
+        whitelist:
+          tags:
+          - FireAxe
   - type: Lock
   - type: AccessReader
     access: [["Atmospherics"], ["Command"]]
-  - type: ItemSlots
-  - type: ContainerContainer
-    containers:
-      ItemCabinet: !type:ContainerSlot
-  placement:
-    mode: SnapgridCenter
 
 - type: entity
-  id: FireAxeCabinetOpen
   parent: FireAxeCabinet
+  id: FireAxeCabinetOpen
   suffix: Open
   components:
-  - type: ItemCabinet
+  - type: Openable
     opened: true
-    doorSound:
-      path: /Audio/Machines/machine_switch.ogg
-    openState: glass-up
-    closedState: glass
+  - type: Lock
+    locked: false
 
 - type: entity
-  id: FireAxeCabinetFilled
   parent: FireAxeCabinet
+  id: FireAxeCabinetFilled
   suffix: Filled
   components:
-  - type: ItemCabinet
-    cabinetSlot:
-      startingItem: FireAxe
-      ejectOnInteract: true
-      whitelist:
-        tags:
-        - FireAxe
-    doorSound:
-      path: /Audio/Machines/machine_switch.ogg
-    openState: glass-up
-    closedState: glass
+  - type: ContainerFill
+    containers:
+      ItemCabinet:
+      - FireAxe
 
 - type: entity
+  parent: [FireAxeCabinetFilled, FireAxeCabinetOpen]
   id: FireAxeCabinetFilledOpen
-  parent: FireAxeCabinetFilled
   suffix: Filled, Open
-  components:
-  - type: ItemCabinet
-    opened: true
-    doorSound:
-      path: /Audio/Machines/machine_switch.ogg
-    openState: glass-up
-    closedState: glass
index fcbceb594b84d51c98cfbace135d13d198256d9c..ae48f2b3ddc103901b2de71cd5d668caa214c578 100644 (file)
@@ -9,39 +9,41 @@
     layers:
     - state: cabinet
     - state: shotgun
-      map: ["enum.ItemCabinetVisualLayers.ContainsItem"]
+      map: ["enum.ItemCabinetVisuals.Layer"]
       visible: true
     - state: glass
-      map: ["enum.ItemCabinetVisualLayers.Door"]
-  - type: ItemCabinet
-    cabinetSlot:
-      ejectOnInteract: true
-      whitelist:
-        tags:
-        - WeaponShotgunKammerer
+      map: ["enum.OpenableVisuals.Layer"]
+  - type: ItemSlots
+    slots:
+      ItemCabinet:
+        ejectOnInteract: true
+        whitelist:
+          tags:
+          - WeaponShotgunKammerer
   - type: AccessReader
     access: [["Security"], ["Command"]]
 
 - type: entity
+  parent: ShotGunCabinet
   id: ShotGunCabinetOpen
-  parent: [ShotGunCabinet, FireAxeCabinetOpen]
   suffix: Open
+  components:
+  - type: Openable
+    opened: true
+  - type: Lock
+    locked: false
 
 - type: entity
+  parent: ShotGunCabinet
   id: ShotGunCabinetFilled
-  parent: [ShotGunCabinet,FireAxeCabinetFilled]
   suffix: Filled
   components:
-  - type: ItemCabinet
-    cabinetSlot:
-      startingItem: WeaponShotgunKammerer
-      ejectOnInteract: true
-      whitelist:
-        tags:
-        - WeaponShotgunKammerer
+  - type: ContainerFill
+    containers:
+      ItemCabinet:
+      - WeaponShotgunKammerer
 
 - type: entity
+  parent: [ShotGunCabinetFilled, ShotGunCabinetOpen]
   id: ShotGunCabinetFilledOpen
-  parent: [ShotGunCabinetFilled,FireAxeCabinetFilledOpen]
   suffix: Filled, Open
-