From 404fe818e8dffc9166c8572a4725283a5b88a5cd Mon Sep 17 00:00:00 2001 From: deltanedas <39013340+deltanedas@users.noreply.github.com> Date: Wed, 29 May 2024 20:08:33 +0000 Subject: [PATCH] item cabinet rework + stuff (#26779) --- Content.Client/Cabinet/ItemCabinetSystem.cs | 27 ---- Content.Server/Cabinet/ItemCabinetSystem.cs | 9 -- .../Cabinet/ItemCabinetComponent.cs | 44 ++---- Content.Shared/Cabinet/ItemCabinetSystem.cs | 95 ++++++++++++ .../Cabinet/SharedItemCabinetSystem.cs | 136 ------------------ Content.Shared/Lock/LockSystem.cs | 1 + .../Nutrition/Components/OpenableComponent.cs | 8 +- .../Nutrition/EntitySystems/OpenableSystem.cs | 78 ++++++++-- .../Structures/Storage/base_cabinet.yml | 44 ++++++ .../Entities/Structures/Storage/glass_box.yml | 54 +++---- .../Structures/Wallmounts/defib_cabinet.yml | 128 +++++++---------- .../Wallmounts/extinguisher_cabinet.yml | 67 +++------ .../Structures/Wallmounts/fireaxe_cabinet.yml | 100 +++++-------- .../Structures/Wallmounts/shotgun_cabinet.yml | 40 +++--- 14 files changed, 378 insertions(+), 453 deletions(-) delete mode 100644 Content.Client/Cabinet/ItemCabinetSystem.cs delete mode 100644 Content.Server/Cabinet/ItemCabinetSystem.cs create mode 100644 Content.Shared/Cabinet/ItemCabinetSystem.cs delete mode 100644 Content.Shared/Cabinet/SharedItemCabinetSystem.cs create mode 100644 Resources/Prototypes/Entities/Structures/Storage/base_cabinet.yml diff --git a/Content.Client/Cabinet/ItemCabinetSystem.cs b/Content.Client/Cabinet/ItemCabinetSystem.cs deleted file mode 100644 index aba4fdae00..0000000000 --- a/Content.Client/Cabinet/ItemCabinetSystem.cs +++ /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(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 index a21532ad0c..0000000000 --- a/Content.Server/Cabinet/ItemCabinetSystem.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Content.Shared.Cabinet; - -namespace Content.Server.Cabinet; - -public sealed class ItemCabinetSystem : SharedItemCabinetSystem -{ - // shitposting on main??? -} - diff --git a/Content.Shared/Cabinet/ItemCabinetComponent.cs b/Content.Shared/Cabinet/ItemCabinetComponent.cs index dcc276e565..b1d7e4a263 100644 --- a/Content.Shared/Cabinet/ItemCabinetComponent.cs +++ b/Content.Shared/Cabinet/ItemCabinetComponent.cs @@ -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; /// -/// 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 OpenableComponent. /// -[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true)] +[RegisterComponent, NetworkedComponent, Access(typeof(ItemCabinetSystem))] public sealed partial class ItemCabinetComponent : Component { /// - /// Sound to be played when the cabinet door is opened. + /// Name of the that stores the actual item. /// - [DataField, AutoNetworkedField, ViewVariables(VVAccess.ReadWrite)] - public SoundSpecifier? DoorSound; - - /// - /// The that stores the actual item. The entity whitelist, sounds, and other - /// behaviours are specified by this definition. - /// - [DataField, ViewVariables] - public ItemSlot CabinetSlot = new(); - - /// - /// Whether the cabinet is currently open or not. - /// - [DataField, AutoNetworkedField] - public bool Opened; - - /// - /// The state for when the cabinet is open - /// - [DataField, AutoNetworkedField, ViewVariables(VVAccess.ReadWrite)] - public string? OpenState; + [DataField] + public string Slot = "ItemCabinet"; +} - /// - /// The state for when the cabinet is closed - /// - [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 index 0000000000..749065ac47 --- /dev/null +++ b/Content.Shared/Cabinet/ItemCabinetSystem.cs @@ -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; + +/// +/// Controls ItemCabinet slot locking and visuals. +/// +public sealed class ItemCabinetSystem : EntitySystem +{ + [Dependency] private readonly ItemSlotsSystem _slots = default!; + [Dependency] private readonly OpenableSystem _openable = default!; + [Dependency] private readonly SharedAppearanceSystem _appearance = default!; + + /// + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnStartup); + SubscribeLocalEvent(OnMapInit); + SubscribeLocalEvent(OnContainerModified); + SubscribeLocalEvent(OnContainerModified); + SubscribeLocalEvent(OnOpened); + SubscribeLocalEvent(OnClosed); + } + + private void OnStartup(Entity ent, ref ComponentStartup args) + { + UpdateAppearance(ent); + } + + private void OnMapInit(Entity 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 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 ent, ref OpenableOpenedEvent args) + { + SetSlotLock(ent, false); + } + + private void OnClosed(Entity ent, ref OpenableClosedEvent args) + { + SetSlotLock(ent, true); + } + + /// + /// Tries to get the cabinet's item slot. + /// + public bool TryGetSlot(Entity ent, [NotNullWhen(true)] out ItemSlot? slot) + { + slot = null; + if (!TryComp(ent, out var slots)) + return false; + + return _slots.TryGetSlot(ent, ent.Comp.Slot, out slot, slots); + } + + /// + /// Returns true if the cabinet contains an item. + /// + public bool HasItem(Entity ent) + { + return TryGetSlot(ent, out var slot) && slot.HasItem; + } + + /// + /// Lock or unlock the underlying item slot. + /// + public void SetSlotLock(Entity ent, bool closed) + { + if (!TryComp(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 index ca496814c7..0000000000 --- a/Content.Shared/Cabinet/SharedItemCabinetSystem.cs +++ /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!; - - /// - public override void Initialize() - { - SubscribeLocalEvent(OnComponentInit); - SubscribeLocalEvent(OnComponentRemove); - SubscribeLocalEvent(OnComponentStartup); - SubscribeLocalEvent(OnComponentHandleState); - - SubscribeLocalEvent(OnActivateInWorld); - SubscribeLocalEvent>(AddToggleOpenVerb); - - SubscribeLocalEvent(OnContainerModified); - SubscribeLocalEvent(OnContainerModified); - - SubscribeLocalEvent(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 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 args) - { - if (args.Hands == null || !args.CanAccess || !args.CanInteract) - return; - - if (TryComp(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); - } - - /// - /// Toggles the ItemCabinet's state. - /// - public void ToggleItemCabinet(EntityUid uid, EntityUid? user = null, ItemCabinetComponent? cabinet = null) - { - if (!Resolve(uid, ref cabinet)) - return; - - if (TryComp(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)); - } - } -} diff --git a/Content.Shared/Lock/LockSystem.cs b/Content.Shared/Lock/LockSystem.cs index 36ac5f025b..a25dcea8a7 100644 --- a/Content.Shared/Lock/LockSystem.cs +++ b/Content.Shared/Lock/LockSystem.cs @@ -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! diff --git a/Content.Shared/Nutrition/Components/OpenableComponent.cs b/Content.Shared/Nutrition/Components/OpenableComponent.cs index 0381888e28..58d6665c58 100644 --- a/Content.Shared/Nutrition/Components/OpenableComponent.cs +++ b/Content.Shared/Nutrition/Components/OpenableComponent.cs @@ -26,6 +26,12 @@ public sealed partial class OpenableComponent : Component [DataField, AutoNetworkedField] public bool OpenableByHand = true; + /// + /// If true, tries to open when activated in world. + /// + [DataField, AutoNetworkedField] + public bool OpenOnActivate; + /// /// Text shown when examining and its open. /// @@ -58,7 +64,7 @@ public sealed partial class OpenableComponent : Component /// Sound played when opening. /// [DataField] - public SoundSpecifier Sound = new SoundCollectionSpecifier("canOpenSounds"); + public SoundSpecifier? Sound = new SoundCollectionSpecifier("canOpenSounds"); /// /// Can this item be closed again after opening? diff --git a/Content.Shared/Nutrition/EntitySystems/OpenableSystem.cs b/Content.Shared/Nutrition/EntitySystems/OpenableSystem.cs index 2934ced8b4..0a7a8d88f3 100644 --- a/Content.Shared/Nutrition/EntitySystems/OpenableSystem.cs +++ b/Content.Shared/Nutrition/EntitySystems/OpenableSystem.cs @@ -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; /// 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(OnInit); SubscribeLocalEvent(OnUse); + // always try to unlock first before opening + SubscribeLocalEvent(OnActivated, after: new[] { typeof(LockSystem) }); SubscribeLocalEvent(OnExamined); SubscribeLocalEvent(HandleIfClosed); SubscribeLocalEvent(HandleIfClosed); - SubscribeLocalEvent>(AddOpenCloseVerbs); + SubscribeLocalEvent>(OnGetVerbs); SubscribeLocalEvent(OnTransferAttempt); SubscribeLocalEvent(OnAttemptShake); SubscribeLocalEvent(OnAttemptAddFizziness); + SubscribeLocalEvent(OnLockToggleAttempt); + +#if DEBUG + SubscribeLocalEvent(OnMapInit); } - private void OnInit(EntityUid uid, OpenableComponent comp, ComponentInit args) + private void OnMapInit(Entity 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 ent, ref ComponentInit args) + { + UpdateAppearance(ent, ent.Comp); + } + + private void OnUse(Entity 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 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 args) + private void OnGetVerbs(EntityUid uid, OpenableComponent comp, GetVerbsEvent 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 ent, ref LockToggleAttemptEvent args) + { + // can't lock something while it's open + if (ent.Comp.Opened) + args.Cancelled = true; + } + /// /// 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 /// Whether it got opened 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; } + + /// + /// If opened, tries closing it if it's closeable. + /// If closed, tries opening it. + /// + public bool TryToggle(Entity ent, EntityUid? user) + { + if (ent.Comp.Opened && ent.Comp.Closeable) + return TryClose(ent, ent.Comp, user); + + return TryOpen(ent, ent.Comp, user); + } } /// @@ -224,3 +274,9 @@ public record struct OpenableOpenedEvent(EntityUid? User = null); /// [ByRefEvent] public record struct OpenableClosedEvent(EntityUid? User = null); + +/// +/// Raised before trying to open an Openable. +/// +[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 index 0000000000..9fcbb02416 --- /dev/null +++ b/Resources/Prototypes/Entities/Structures/Storage/base_cabinet.yml @@ -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 } diff --git a/Resources/Prototypes/Entities/Structures/Storage/glass_box.yml b/Resources/Prototypes/Entities/Structures/Storage/glass_box.yml index 8177b6b6f0..c868bbbc33 100644 --- a/Resources/Prototypes/Entities/Structures/Storage/glass_box.yml +++ b/Resources/Prototypes/Entities/Structures/Storage/glass_box.yml @@ -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: @@ -23,13 +20,8 @@ layer: - MidImpassable - LowImpassable - - type: ItemSlots - - type: ContainerContainer - containers: - ItemCabinet: !type:ContainerSlot - type: Anchorable delay: 4 - - type: Appearance - type: entity id: GlassBox @@ -44,10 +36,10 @@ 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"] @@ -118,49 +110,39 @@ - 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 diff --git a/Resources/Prototypes/Entities/Structures/Wallmounts/defib_cabinet.yml b/Resources/Prototypes/Entities/Structures/Wallmounts/defib_cabinet.yml index d9f4a827cc..18b218b351 100644 --- a/Resources/Prototypes/Entities/Structures/Wallmounts/defib_cabinet.yml +++ b/Resources/Prototypes/Entities/Structures/Wallmounts/defib_cabinet.yml @@ -1,100 +1,74 @@ -- 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 diff --git a/Resources/Prototypes/Entities/Structures/Wallmounts/extinguisher_cabinet.yml b/Resources/Prototypes/Entities/Structures/Wallmounts/extinguisher_cabinet.yml index a0775641ef..7e6a1632a7 100644 --- a/Resources/Prototypes/Entities/Structures/Wallmounts/extinguisher_cabinet.yml +++ b/Resources/Prototypes/Entities/Structures/Wallmounts/extinguisher_cabinet.yml @@ -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 @@ -15,25 +20,17 @@ 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 @@ -57,46 +54,26 @@ 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 diff --git a/Resources/Prototypes/Entities/Structures/Wallmounts/fireaxe_cabinet.yml b/Resources/Prototypes/Entities/Structures/Wallmounts/fireaxe_cabinet.yml index acd865aa62..42b528ce68 100644 --- a/Resources/Prototypes/Entities/Structures/Wallmounts/fireaxe_cabinet.yml +++ b/Resources/Prototypes/Entities/Structures/Wallmounts/fireaxe_cabinet.yml @@ -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: @@ -36,68 +40,42 @@ 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 diff --git a/Resources/Prototypes/Entities/Structures/Wallmounts/shotgun_cabinet.yml b/Resources/Prototypes/Entities/Structures/Wallmounts/shotgun_cabinet.yml index fcbceb594b..ae48f2b3dd 100644 --- a/Resources/Prototypes/Entities/Structures/Wallmounts/shotgun_cabinet.yml +++ b/Resources/Prototypes/Entities/Structures/Wallmounts/shotgun_cabinet.yml @@ -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 - -- 2.51.2