From e5e144d99c7d2eef76c627a537ce3f541a5c26ca Mon Sep 17 00:00:00 2001 From: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Date: Wed, 29 Dec 2021 15:57:20 +1100 Subject: [PATCH] Rollerbeds (#5681) --- Content.Client/Entry/IgnoredComponents.cs | 1 + .../Morgue/Visualizers/BodyBagVisualizer.cs | 4 + .../Storage/Visualizers/StorageVisualizer.cs | 22 ++- .../Visualizer/FoldableVisualizer.cs | 36 +++++ .../Visualizer/RollerbedVisualizer.cs | 29 ++++ .../Buckle/Components/BuckleComponent.cs | 15 +- .../Buckle/Components/StrapComponent.cs | 75 +++++++++- Content.Server/Buckle/Systems/BuckleSystem.cs | 12 +- Content.Server/Buckle/Systems/StrapSystem.cs | 38 ++--- Content.Server/Foldable/FoldableComponent.cs | 25 ++++ Content.Server/Foldable/FoldableSystem.cs | 131 ++++++++++++++++++ .../Components/EntityStorageComponent.cs | 20 ++- .../Buckle/Components/SharedStrapComponent.cs | 6 +- .../Hands/Components/SharedHandsComponent.cs | 11 +- Content.Shared/Item/PickupAttemptEvent.cs | 13 ++ Content.Shared/Item/SharedItemComponent.cs | 1 - .../components/foldable-component.ftl | 5 + .../Objects/Specific/Medical/morgue.yml | 20 ++- .../Entities/Structures/Furniture/chairs.yml | 1 + .../Structures/Furniture/rollerbeds.yml | 94 +++++++++++++ .../Storage/Closets/Lockers/lockers.yml | 40 ++++++ .../Storage/Closets/base_structureclosets.yml | 1 + .../Structures/Storage/Closets/closets.yml | 18 ++- .../Structures/Storage/Closets/wardrobe.yml | 11 ++ .../Prototypes/Recipes/Lathes/medical.yml | 6 +- .../Textures/Interface/VerbIcons/fold.svg | 3 + .../Interface/VerbIcons/fold.svg.192dpi.png | Bin 0 -> 2619 bytes .../VerbIcons/fold.svg.192dpi.png.yml | 2 + .../bodybags.rsi/{item.png => bag_folded.png} | Bin .../Medical/Morgue/bodybags.rsi/meta.json | 2 +- .../rollerbeds.rsi/cheap_rollerbed.png | Bin 0 -> 326 bytes .../cheap_rollerbed_buckled.png | Bin 0 -> 490 bytes .../rollerbeds.rsi/cheap_rollerbed_folded.png | Bin 0 -> 403 bytes .../rollerbeds.rsi/emergency_rollerbed.png | Bin 0 -> 449 bytes .../emergency_rollerbed_buckled.png | Bin 0 -> 618 bytes .../emergency_rollerbed_folded.png | Bin 0 -> 582 bytes .../Furniture/rollerbeds.rsi/meta.json | 38 +++++ .../Furniture/rollerbeds.rsi/rollerbed.png | Bin 0 -> 402 bytes .../rollerbeds.rsi/rollerbed_buckled.png | Bin 0 -> 565 bytes .../rollerbeds.rsi/rollerbed_folded.png | Bin 0 -> 401 bytes 40 files changed, 627 insertions(+), 53 deletions(-) create mode 100644 Content.Client/Visualizer/FoldableVisualizer.cs create mode 100644 Content.Client/Visualizer/RollerbedVisualizer.cs create mode 100644 Content.Server/Foldable/FoldableComponent.cs create mode 100644 Content.Server/Foldable/FoldableSystem.cs create mode 100644 Resources/Locale/en-US/foldable/components/foldable-component.ftl create mode 100644 Resources/Prototypes/Entities/Structures/Furniture/rollerbeds.yml create mode 100644 Resources/Textures/Interface/VerbIcons/fold.svg create mode 100644 Resources/Textures/Interface/VerbIcons/fold.svg.192dpi.png create mode 100644 Resources/Textures/Interface/VerbIcons/fold.svg.192dpi.png.yml rename Resources/Textures/Objects/Specific/Medical/Morgue/bodybags.rsi/{item.png => bag_folded.png} (100%) create mode 100644 Resources/Textures/Structures/Furniture/rollerbeds.rsi/cheap_rollerbed.png create mode 100644 Resources/Textures/Structures/Furniture/rollerbeds.rsi/cheap_rollerbed_buckled.png create mode 100644 Resources/Textures/Structures/Furniture/rollerbeds.rsi/cheap_rollerbed_folded.png create mode 100644 Resources/Textures/Structures/Furniture/rollerbeds.rsi/emergency_rollerbed.png create mode 100644 Resources/Textures/Structures/Furniture/rollerbeds.rsi/emergency_rollerbed_buckled.png create mode 100644 Resources/Textures/Structures/Furniture/rollerbeds.rsi/emergency_rollerbed_folded.png create mode 100644 Resources/Textures/Structures/Furniture/rollerbeds.rsi/meta.json create mode 100644 Resources/Textures/Structures/Furniture/rollerbeds.rsi/rollerbed.png create mode 100644 Resources/Textures/Structures/Furniture/rollerbeds.rsi/rollerbed_buckled.png create mode 100644 Resources/Textures/Structures/Furniture/rollerbeds.rsi/rollerbed_folded.png diff --git a/Content.Client/Entry/IgnoredComponents.cs b/Content.Client/Entry/IgnoredComponents.cs index 5741ee1b8f..452f5be09f 100644 --- a/Content.Client/Entry/IgnoredComponents.cs +++ b/Content.Client/Entry/IgnoredComponents.cs @@ -299,6 +299,7 @@ namespace Content.Client.Entry "IncreaseDamageOnWield", "TabletopGame", "LitOnPowered", + "Foldable", "TriggerOnSignalReceived", "ToggleDoorOnTrigger", "DeviceNetworkComponent", diff --git a/Content.Client/Morgue/Visualizers/BodyBagVisualizer.cs b/Content.Client/Morgue/Visualizers/BodyBagVisualizer.cs index 1aeff3e8c8..b64ce7d8d8 100644 --- a/Content.Client/Morgue/Visualizers/BodyBagVisualizer.cs +++ b/Content.Client/Morgue/Visualizers/BodyBagVisualizer.cs @@ -23,6 +23,10 @@ namespace Content.Client.Morgue.Visualizers { sprite.LayerSetVisible(BodyBagVisualLayers.Label, labelVal); } + else + { + sprite.LayerSetVisible(BodyBagVisualLayers.Label, false); + } } } diff --git a/Content.Client/Storage/Visualizers/StorageVisualizer.cs b/Content.Client/Storage/Visualizers/StorageVisualizer.cs index cd1a73927e..a48e0535db 100644 --- a/Content.Client/Storage/Visualizers/StorageVisualizer.cs +++ b/Content.Client/Storage/Visualizers/StorageVisualizer.cs @@ -10,6 +10,9 @@ namespace Content.Client.Storage.Visualizers [UsedImplicitly] public sealed class StorageVisualizer : AppearanceVisualizer { + /// + /// Sets the base sprite to this layer. Exists to make the inheritance tree less boilerplate-y. + /// [DataField("state")] private string? _stateBase; [DataField("state_open")] @@ -41,9 +44,24 @@ namespace Content.Client.Storage.Visualizers } component.TryGetData(StorageVisuals.Open, out bool open); - var state = open ? _stateOpen ?? $"{_stateBase}_open" : _stateClosed ?? $"{_stateBase}_door"; - sprite.LayerSetState(StorageVisualLayers.Door, state); + if (sprite.LayerMapTryGet(StorageVisualLayers.Door, out _)) + { + sprite.LayerSetVisible(StorageVisualLayers.Door, true); + + if (open && _stateOpen != null) + { + sprite.LayerSetState(StorageVisualLayers.Door, _stateOpen); + } + else if (!open && _stateClosed != null) + { + sprite.LayerSetState(StorageVisualLayers.Door, _stateClosed); + } + else + { + sprite.LayerSetVisible(StorageVisualLayers.Door, false); + } + } if (component.TryGetData(StorageVisuals.CanLock, out bool canLock) && canLock) { diff --git a/Content.Client/Visualizer/FoldableVisualizer.cs b/Content.Client/Visualizer/FoldableVisualizer.cs new file mode 100644 index 0000000000..6b2861dc7b --- /dev/null +++ b/Content.Client/Visualizer/FoldableVisualizer.cs @@ -0,0 +1,36 @@ +using Robust.Client.GameObjects; +using Robust.Shared.GameObjects; +using Robust.Shared.IoC; +using Robust.Shared.Serialization.Manager.Attributes; + +namespace Content.Client.Visualizer; + + +public sealed class FoldableVisualizer : AppearanceVisualizer +{ + [DataField("key")] + private string _key = default!; + + public override void OnChangeData(AppearanceComponent appearance) + { + base.OnChangeData(appearance); + + var entManager = IoCManager.Resolve(); + + if (!entManager.TryGetComponent(appearance.Owner, out SpriteComponent? sprite)) return; + + if (appearance.TryGetData("FoldedState", out bool folded) && folded) + { + sprite.LayerSetState(FoldableVisualLayers.Base, $"{_key}_folded"); + } + else + { + sprite.LayerSetState(FoldableVisualLayers.Base, $"{_key}"); + } + } + + public enum FoldableVisualLayers : byte + { + Base, + } +} diff --git a/Content.Client/Visualizer/RollerbedVisualizer.cs b/Content.Client/Visualizer/RollerbedVisualizer.cs new file mode 100644 index 0000000000..053d521d57 --- /dev/null +++ b/Content.Client/Visualizer/RollerbedVisualizer.cs @@ -0,0 +1,29 @@ +using JetBrains.Annotations; +using Robust.Client.GameObjects; +using Robust.Shared.GameObjects; +using Robust.Shared.IoC; +using Robust.Shared.Serialization.Manager.Attributes; + +namespace Content.Client.Visualizer +{ + [UsedImplicitly] + public sealed class RollerbedVisualizer : AppearanceVisualizer + { + [DataField("key")] + private string _key = default!; + + public override void OnChangeData(AppearanceComponent appearance) + { + base.OnChangeData(appearance); + + var entManager = IoCManager.Resolve(); + + if (!entManager.TryGetComponent(appearance.Owner, out SpriteComponent? sprite)) return; + + if (appearance.TryGetData("StrapState", out bool strapped) && strapped) + { + sprite.LayerSetState(0, $"{_key}_buckled"); + } + } + } +} diff --git a/Content.Server/Buckle/Components/BuckleComponent.cs b/Content.Server/Buckle/Components/BuckleComponent.cs index 0c40c6c768..d140e264fb 100644 --- a/Content.Server/Buckle/Components/BuckleComponent.cs +++ b/Content.Server/Buckle/Components/BuckleComponent.cs @@ -133,7 +133,7 @@ namespace Content.Server.Buckle.Components break; } - ownTransform.LocalPosition = Vector2.Zero + BuckleOffset; + ownTransform.LocalPosition = Vector2.Zero + strap.BuckleOffset; } public bool CanBuckle(EntityUid user, EntityUid to, [NotNullWhen(true)] out StrapComponent? strap) @@ -317,10 +317,17 @@ namespace Content.Server.Buckle.Components BuckledTo = null; - if (_entMan.GetComponent(Owner).Parent == _entMan.GetComponent(oldBuckledTo.Owner)) + var entManager = IoCManager.Resolve(); + var xform = entManager.GetComponent(Owner); + var oldBuckledXform = entManager.GetComponent(oldBuckledTo.Owner); + + if (xform.ParentUid == oldBuckledXform.Owner) { - _entMan.GetComponent(Owner).AttachParentToContainerOrGrid(); - _entMan.GetComponent(Owner).WorldRotation = _entMan.GetComponent(oldBuckledTo.Owner).WorldRotation; + xform.AttachParentToContainerOrGrid(); + xform.WorldRotation = oldBuckledXform.WorldRotation; + + if (oldBuckledTo.UnbuckleOffset != Vector2.Zero) + xform.Coordinates = oldBuckledXform.Coordinates.Offset(oldBuckledTo.UnbuckleOffset); } Appearance?.SetData(BuckleVisuals.Buckled, false); diff --git a/Content.Server/Buckle/Components/StrapComponent.cs b/Content.Server/Buckle/Components/StrapComponent.cs index 3d06c638e0..21d1588225 100644 --- a/Content.Server/Buckle/Components/StrapComponent.cs +++ b/Content.Server/Buckle/Components/StrapComponent.cs @@ -1,7 +1,9 @@ using System.Collections.Generic; using System.Linq; +using Content.Shared.ActionBlocker; using Content.Shared.Acts; using Content.Shared.Alert; +using Content.Shared.Buckle; using Content.Shared.Buckle.Components; using Content.Shared.DragDrop; using Content.Shared.Interaction; @@ -9,6 +11,8 @@ using Content.Shared.Sound; using Robust.Server.GameObjects; using Robust.Shared.GameObjects; using Robust.Shared.IoC; +using Robust.Shared.Maths; +using Robust.Shared.Players; using Robust.Shared.Serialization; using Robust.Shared.Serialization.Manager.Attributes; using Robust.Shared.ViewVariables; @@ -21,8 +25,6 @@ namespace Content.Server.Buckle.Components { [ComponentDependency] public readonly SpriteComponent? SpriteComponent = null; - [Dependency] private readonly IEntityManager _entMan = default!; - private readonly HashSet _buckledEntities = new(); /// @@ -37,6 +39,50 @@ namespace Content.Server.Buckle.Components [ViewVariables] [DataField("size")] private int _size = 100; private int _occupiedSize; + /// + /// The buckled entity will be offset by this amount from the center of the strap object. + /// If this offset it too big, it will be clamped to + /// + [DataField("buckleOffset", required: false)] + private Vector2 _buckleOffset = Vector2.Zero; + + private bool _enabled = true; + + /// + /// If disabled, nothing can be buckled on this object, and it will unbuckle anything that's already buckled + /// + public bool Enabled + { + get => _enabled; + set + { + _enabled = value; + if (_enabled == value) return; + RemoveAll(); + } + } + + /// + /// The distance above which a buckled entity will be automatically unbuckled. + /// Don't change it unless you really have to + /// + [DataField("maxBuckleDistance", required: false)] + public float MaxBuckleDistance = 1f; + + /// + /// You can specify the offset the entity will have after unbuckling. + /// + [DataField("unbuckleOffset", required: false)] + public Vector2 UnbuckleOffset = Vector2.Zero; + + /// + /// Gets and clamps the buckle offset to MaxBuckleDistance + /// + public Vector2 BuckleOffset => Vector2.Clamp( + _buckleOffset, + Vector2.One * -MaxBuckleDistance, + Vector2.One * MaxBuckleDistance); + /// /// The entity that is currently buckled here, synced from /// @@ -96,6 +142,8 @@ namespace Content.Server.Buckle.Components /// True if added, false otherwise public bool TryAdd(BuckleComponent buckle, bool force = false) { + if (!Enabled) return false; + if (!force && !HasSpace(buckle)) { return false; @@ -110,6 +158,12 @@ namespace Content.Server.Buckle.Components buckle.Appearance?.SetData(StrapVisuals.RotationAngle, _rotation); + // Update the visuals of the strap object + if (IoCManager.Resolve().TryGetComponent(Owner, out var appearance)) + { + appearance.SetData("StrapState", true); + } + #pragma warning disable 618 SendMessage(new StrapMessage(buckle.Owner, Owner)); #pragma warning restore 618 @@ -126,6 +180,11 @@ namespace Content.Server.Buckle.Components { if (_buckledEntities.Remove(buckle.Owner)) { + if (IoCManager.Resolve().TryGetComponent(Owner, out var appearance)) + { + appearance.SetData("StrapState", false); + } + _occupiedSize -= buckle.Size; #pragma warning disable 618 SendMessage(new UnStrapMessage(buckle.Owner, Owner)); @@ -147,9 +206,11 @@ namespace Content.Server.Buckle.Components private void RemoveAll() { + var entManager = IoCManager.Resolve(); + foreach (var entity in _buckledEntities.ToArray()) { - if (_entMan.TryGetComponent(entity, out var buckle)) + if (entManager.TryGetComponent(entity, out var buckle)) { buckle.TryUnbuckle(entity, true); } @@ -166,7 +227,9 @@ namespace Content.Server.Buckle.Components bool IInteractHand.InteractHand(InteractHandEventArgs eventArgs) { - if (!_entMan.TryGetComponent(eventArgs.User, out var buckle)) + var entManager = IoCManager.Resolve(); + + if (!entManager.TryGetComponent(eventArgs.User, out var buckle)) { return false; } @@ -176,7 +239,9 @@ namespace Content.Server.Buckle.Components public override bool DragDropOn(DragDropEvent eventArgs) { - if (!_entMan.TryGetComponent(eventArgs.Dragged, out BuckleComponent? buckleComponent)) return false; + var entManager = IoCManager.Resolve(); + + if (!entManager.TryGetComponent(eventArgs.Dragged, out BuckleComponent? buckleComponent)) return false; return buckleComponent.TryBuckle(eventArgs.User, Owner); } } diff --git a/Content.Server/Buckle/Systems/BuckleSystem.cs b/Content.Server/Buckle/Systems/BuckleSystem.cs index 0135e3aea0..8ec67713a6 100644 --- a/Content.Server/Buckle/Systems/BuckleSystem.cs +++ b/Content.Server/Buckle/Systems/BuckleSystem.cs @@ -42,10 +42,12 @@ namespace Content.Server.Buckle.Systems if (!args.CanAccess || !args.CanInteract || !component.Buckled) return; - Verb verb = new(); - verb.Act = () => component.TryUnbuckle(args.User); - verb.Text = Loc.GetString("verb-categories-unbuckle"); - verb.IconTexture = "/Textures/Interface/VerbIcons/unbuckle.svg.192dpi.png"; + Verb verb = new() + { + Act = () => component.TryUnbuckle(args.User), + Text = Loc.GetString("verb-categories-unbuckle"), + IconTexture = "/Textures/Interface/VerbIcons/unbuckle.svg.192dpi.png" + }; if (args.Target == args.User && args.Using == null) { @@ -81,7 +83,7 @@ namespace Content.Server.Buckle.Systems var strapPosition = EntityManager.GetComponent(strap.Owner).Coordinates.Offset(buckle.BuckleOffset); - if (ev.NewPosition.InRange(EntityManager, strapPosition, 0.2f)) + if (ev.NewPosition.InRange(EntityManager, strapPosition, strap.MaxBuckleDistance)) { return; } diff --git a/Content.Server/Buckle/Systems/StrapSystem.cs b/Content.Server/Buckle/Systems/StrapSystem.cs index 9acd58d2db..c1d8ebe784 100644 --- a/Content.Server/Buckle/Systems/StrapSystem.cs +++ b/Content.Server/Buckle/Systems/StrapSystem.cs @@ -27,7 +27,7 @@ namespace Content.Server.Buckle.Systems private void AddStrapVerbs(EntityUid uid, StrapComponent component, GetInteractionVerbsEvent args) { - if (args.Hands == null || !args.CanAccess || !args.CanInteract) + if (args.Hands == null || !args.CanAccess || !args.CanInteract || !component.Enabled) return; // Note that for whatever bloody reason, buckle component has its own interaction range. Additionally, this @@ -41,9 +41,12 @@ namespace Content.Server.Buckle.Systems if (!_interactionSystem.InRangeUnobstructed(args.User, args.Target, range: buckledComp.Range)) continue; - Verb verb = new(); - verb.Act = () => buckledComp.TryUnbuckle(args.User); - verb.Category = VerbCategory.Unbuckle; + Verb verb = new() + { + Act = () => buckledComp.TryUnbuckle(args.User), + Category = VerbCategory.Unbuckle + }; + if (entity == args.User) verb.Text = Loc.GetString("verb-self-target-pronoun"); else @@ -64,10 +67,12 @@ namespace Content.Server.Buckle.Systems component.HasSpace(buckle) && _interactionSystem.InRangeUnobstructed(args.User, args.Target, range: buckle.Range)) { - Verb verb = new(); - verb.Act = () => buckle.TryBuckle(args.User, args.Target); - verb.Category = VerbCategory.Buckle; - verb.Text = Loc.GetString("verb-self-target-pronoun"); + Verb verb = new() + { + Act = () => buckle.TryBuckle(args.User, args.Target), + Category = VerbCategory.Buckle, + Text = Loc.GetString("verb-self-target-pronoun") + }; args.Verbs.Add(verb); } @@ -82,14 +87,15 @@ namespace Content.Server.Buckle.Systems if (!_interactionSystem.InRangeUnobstructed(@using, args.Target, usingBuckle.Range, predicate: Ignored)) return; - Verb verb = new(); - verb.Act = () => usingBuckle.TryBuckle(args.User, args.Target); - verb.Category = VerbCategory.Buckle; - verb.Text = EntityManager.GetComponent(@using).EntityName; - - // If the used entity is a person being pulled, prioritize this verb. Conversely, if it is - // just a held object, the user is probably just trying to sit down. - verb.Priority = EntityManager.HasComponent(@using) ? 1 : -1; + Verb verb = new() + { + Act = () => usingBuckle.TryBuckle(args.User, args.Target), + Category = VerbCategory.Buckle, + Text = EntityManager.GetComponent(@using).EntityName, + // just a held object, the user is probably just trying to sit down. + // If the used entity is a person being pulled, prioritize this verb. Conversely, if it is + Priority = EntityManager.HasComponent(@using) ? 1 : -1 + }; args.Verbs.Add(verb); } diff --git a/Content.Server/Foldable/FoldableComponent.cs b/Content.Server/Foldable/FoldableComponent.cs new file mode 100644 index 0000000000..514d4eddb5 --- /dev/null +++ b/Content.Server/Foldable/FoldableComponent.cs @@ -0,0 +1,25 @@ +#nullable enable + +using Robust.Shared.Containers; +using Robust.Shared.GameObjects; +using Robust.Shared.Serialization.Manager.Attributes; +using Robust.Shared.ViewVariables; + +namespace Content.Server.Foldable +{ + + /// + /// Used to create "foldable structures" that you can pickup like an item when folded. Used for rollerbeds and wheelchairs + /// + [RegisterComponent] + public class FoldableComponent : Component + { + public override string Name => "Foldable"; + + [DataField("folded")] + [ViewVariables] + public bool IsFolded = false; + + public bool CanBeFolded = true; + } +} diff --git a/Content.Server/Foldable/FoldableSystem.cs b/Content.Server/Foldable/FoldableSystem.cs new file mode 100644 index 0000000000..380b9f29b5 --- /dev/null +++ b/Content.Server/Foldable/FoldableSystem.cs @@ -0,0 +1,131 @@ +using System.Linq; +using Content.Server.Buckle.Components; +using Content.Server.Storage.Components; +using Content.Shared.Interaction; +using Content.Shared.Item; +using Content.Shared.Verbs; +using JetBrains.Annotations; +using Robust.Shared.Containers; +using Robust.Shared.GameObjects; +using Robust.Shared.IoC; +using Robust.Shared.Localization; + +namespace Content.Server.Foldable +{ + [UsedImplicitly] + public sealed class FoldableSystem : EntitySystem + { + [Dependency] private SharedContainerSystem _container = default!; + + private const string FoldKey = "FoldedState"; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnFoldableInit); + SubscribeLocalEvent(OnFoldableOpenAttempt); + SubscribeLocalEvent(OnPickedUpAttempt); + SubscribeLocalEvent(AddFoldVerb); + } + + private void OnFoldableOpenAttempt(EntityUid uid, FoldableComponent component, StorageOpenAttemptEvent args) + { + if (component.IsFolded) + args.Cancel(); + } + + private void OnFoldableInit(EntityUid uid, FoldableComponent component, ComponentInit args) + { + SetFolded(component, component.IsFolded); + } + + private bool TryToggleFold(FoldableComponent comp) + { + return TrySetFolded(comp, !comp.IsFolded); + } + + /// + /// Try to fold/unfold + /// + /// + /// Folded state we want + /// True if successful + private bool TrySetFolded(FoldableComponent comp, bool state) + { + if (state == comp.IsFolded) + return false; + + if (_container.IsEntityInContainer(comp.Owner)) + return false; + + // First we check if the foldable object has a strap component + if (EntityManager.TryGetComponent(comp.Owner, out StrapComponent? strap)) + { + // If an entity is buckled to the object we can't pick it up or fold it + if (strap.BuckledEntities.Any()) + return false; + } + + SetFolded(comp, state); + return true; + } + + /// + /// Set the folded state of the given + /// + /// + /// If true, the component will become folded, else unfolded + private void SetFolded(FoldableComponent component, bool folded) + { + component.IsFolded = folded; + component.CanBeFolded = !_container.IsEntityInContainer(component.Owner); + + // You can't buckle an entity to a folded object + if (EntityManager.TryGetComponent(component.Owner, out StrapComponent? strap)) + strap.Enabled = !component.IsFolded; + + // Update visuals only if the value has changed + if (EntityManager.TryGetComponent(component.Owner, out AppearanceComponent? appearance)) + appearance.SetData(FoldKey, folded); + } + + #region Event handlers + + /// + /// Prevents foldable objects to be picked up when unfolded + /// + /// + /// + /// + private void OnPickedUpAttempt(EntityUid uid, FoldableComponent component, AttemptItemPickupEvent args) + { + if (!component.IsFolded) + args.Cancel(); + } + + #endregion + + #region Verb + + private void AddFoldVerb(EntityUid uid, FoldableComponent component, GetAlternativeVerbsEvent args) + { + if (!args.CanAccess || !args.CanInteract) + return; + + Verb verb = new() + { + Act = () => TryToggleFold(component), + Text = component.IsFolded ? Loc.GetString("unfold-verb") : Loc.GetString("fold-verb"), + IconTexture = "/Textures/Interface/VerbIcons/fold.svg.192dpi.png", + + // If the object is unfolded and they click it, they want to fold it, if it's folded, they want to pick it up + Priority = component.IsFolded ? 0 : 2, + }; + + args.Verbs.Add(verb); + } + + #endregion + } +} diff --git a/Content.Server/Storage/Components/EntityStorageComponent.cs b/Content.Server/Storage/Components/EntityStorageComponent.cs index 7ff590084a..bada7c58ca 100644 --- a/Content.Server/Storage/Components/EntityStorageComponent.cs +++ b/Content.Server/Storage/Components/EntityStorageComponent.cs @@ -193,12 +193,18 @@ namespace Content.Server.Storage.Components return false; } - return true; + var @event = new StorageOpenAttemptEvent(); + IoCManager.Resolve().EventBus.RaiseLocalEvent(Owner, @event); + + return !@event.Cancelled; } public virtual bool CanClose(EntityUid user, bool silent = false) { - return true; + var @event = new StorageCloseAttemptEvent(); + IoCManager.Resolve().EventBus.RaiseLocalEvent(Owner, @event); + + return !@event.Cancelled; } public void ToggleOpen(EntityUid user) @@ -479,4 +485,14 @@ namespace Content.Server.Storage.Components } } } + + public sealed class StorageOpenAttemptEvent : CancellableEntityEventArgs + { + + } + + public sealed class StorageCloseAttemptEvent : CancellableEntityEventArgs + { + + } } diff --git a/Content.Shared/Buckle/Components/SharedStrapComponent.cs b/Content.Shared/Buckle/Components/SharedStrapComponent.cs index d396eacf32..38aeb1f341 100644 --- a/Content.Shared/Buckle/Components/SharedStrapComponent.cs +++ b/Content.Shared/Buckle/Components/SharedStrapComponent.cs @@ -57,11 +57,13 @@ namespace Content.Shared.Buckle.Components } [Serializable, NetSerializable] - public enum StrapVisuals + public enum StrapVisuals : byte { - RotationAngle + RotationAngle, + BuckledState } + // TODO : Convert this to an Entity Message. Careful, it will Break ShuttleControllerComponent (only place where it's used) [Serializable, NetSerializable] #pragma warning disable 618 public abstract class StrapChangeMessage : ComponentMessage diff --git a/Content.Shared/Hands/Components/SharedHandsComponent.cs b/Content.Shared/Hands/Components/SharedHandsComponent.cs index 67028d1353..398aec3203 100644 --- a/Content.Shared/Hands/Components/SharedHandsComponent.cs +++ b/Content.Shared/Hands/Components/SharedHandsComponent.cs @@ -615,11 +615,14 @@ namespace Content.Shared.Hands.Components protected bool CanInsertEntityIntoHand(Hand hand, EntityUid entity) { var handContainer = hand.Container; - if (handContainer == null) - return false; + if (handContainer == null) return false; - if (!handContainer.CanInsert(entity)) - return false; + if (!handContainer.CanInsert(entity)) return false; + + var @event = new AttemptItemPickupEvent(); + _entMan.EventBus.RaiseLocalEvent(entity, @event); + + if (@event.Cancelled) return false; return true; } diff --git a/Content.Shared/Item/PickupAttemptEvent.cs b/Content.Shared/Item/PickupAttemptEvent.cs index 1d922a6d04..e52c0722a9 100644 --- a/Content.Shared/Item/PickupAttemptEvent.cs +++ b/Content.Shared/Item/PickupAttemptEvent.cs @@ -2,6 +2,9 @@ namespace Content.Shared.Item { + /// + /// Raised on a *mob* when it tries to pickup something + /// public class PickupAttemptEvent : CancellableEntityEventArgs { public PickupAttemptEvent(EntityUid uid) @@ -11,4 +14,14 @@ namespace Content.Shared.Item public EntityUid Uid { get; } } + + /// + /// Raised on the *item* when tried to be picked up + /// + /// + /// Doesn't just handle "items" but calling it "PickedUpAttempt" is too close to "Pickup" for the sleep deprived brain. + /// + public sealed class AttemptItemPickupEvent : CancellableEntityEventArgs + { + } } diff --git a/Content.Shared/Item/SharedItemComponent.cs b/Content.Shared/Item/SharedItemComponent.cs index bd86f8e983..5c83bb95c7 100644 --- a/Content.Shared/Item/SharedItemComponent.cs +++ b/Content.Shared/Item/SharedItemComponent.cs @@ -9,7 +9,6 @@ using Robust.Shared.GameStates; using Robust.Shared.IoC; using Robust.Shared.Maths; using Robust.Shared.Physics; -using Robust.Shared.Players; using Robust.Shared.Serialization; using Robust.Shared.Serialization.Manager.Attributes; using Robust.Shared.ViewVariables; diff --git a/Resources/Locale/en-US/foldable/components/foldable-component.ftl b/Resources/Locale/en-US/foldable/components/foldable-component.ftl new file mode 100644 index 0000000000..d3e4ecefb5 --- /dev/null +++ b/Resources/Locale/en-US/foldable/components/foldable-component.ftl @@ -0,0 +1,5 @@ +# Foldable + +foldable-deploy-fail = You can't deploy the {$object} here. +fold-verb = Fold +unfold-verb = Unfold diff --git a/Resources/Prototypes/Entities/Objects/Specific/Medical/morgue.yml b/Resources/Prototypes/Entities/Objects/Specific/Medical/morgue.yml index f9d3b4f2b3..201928f6d2 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Medical/morgue.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Medical/morgue.yml @@ -9,6 +9,7 @@ sprite: Objects/Specific/Medical/Morgue/bodybags.rsi layers: - state: bag + map: ["enum.FoldableVisualLayers.Base"] - state: open_overlay map: ["enum.StorageVisualLayers.Door"] - state: label_overlay @@ -27,13 +28,18 @@ !type:PhysShapeAabb bounds: "-0.5,-0.45,0.5,0.1" mass: 5 + mask: + - Impassable + - SmallImpassable - type: BodyBagEntityStorage CanWeldShut: false Capacity: 1 + IsCollidableWhenOpen: true closeSound: path: /Audio/Misc/zip.ogg openSound: path: /Audio/Misc/zip.ogg + - type: Foldable - type: PaperLabel labelSlot: insertVerbText: Attach Label @@ -45,20 +51,20 @@ visuals: - type: StorageVisualizer state_open: open_overlay - state_closed: bag + - type: FoldableVisualizer + key: bag - type: BodyBagVisualizer - type: Pullable - type: entity - id: BodyBag_Item + id: BodyBag_Folded name: body bag description: A plastic bag designed for the storage and transportation of cadavers. - parent: BaseItem + parent: BodyBag_Container + suffix: Folded components: - - type: Sprite - netsync: false - sprite: Objects/Specific/Medical/Morgue/bodybags.rsi - state: item + - type: Foldable + folded: true # - type: BodyBagItem #TODO: we need some kind of generic placable, like thus: # - type: Placeable # prototype: someId diff --git a/Resources/Prototypes/Entities/Structures/Furniture/chairs.yml b/Resources/Prototypes/Entities/Structures/Furniture/chairs.yml index 1ea3b3c08e..10081edb36 100644 --- a/Resources/Prototypes/Entities/Structures/Furniture/chairs.yml +++ b/Resources/Prototypes/Entities/Structures/Furniture/chairs.yml @@ -24,6 +24,7 @@ noRot: true - type: Strap position: Stand + buckleOffset: "0,0.15" - type: Pullable - type: Damageable damageContainer: Inorganic diff --git a/Resources/Prototypes/Entities/Structures/Furniture/rollerbeds.yml b/Resources/Prototypes/Entities/Structures/Furniture/rollerbeds.yml new file mode 100644 index 0000000000..524c812043 --- /dev/null +++ b/Resources/Prototypes/Entities/Structures/Furniture/rollerbeds.yml @@ -0,0 +1,94 @@ +- type: entity + id: RollerBed + parent: BaseItem + name: rollerbed + description: Used to carry patients around without damaging them. + components: + - type: Transform + noRot: true + - type: Item + size: 5 + - type: Sprite + sprite: Structures/Furniture/rollerbeds.rsi + netsync: false + noRot: true + layers: + - state: rollerbed + map: ["enum.FoldableVisualLayers.Base"] + - type: MovedByPressure + - type: DamageOnHighSpeedImpact + soundHit: /Audio/Effects/bang.ogg + - type: InteractionOutline + - type: Physics + - type: Fixtures + fixtures: + - shape: + !type:PhysShapeCircle + radius: 0.35 + mass: 30 + mask: + - Impassable + - SmallImpassable + layer: + - Opaque + - type: Damageable + - type: Destructible + thresholds: + - trigger: + !type:DamageTrigger + damage: 50 + behaviors: + - !type:DoActsBehavior + acts: ["Destruction"] + - !type:SpawnEntitiesBehavior + spawn: + SheetSteel1: + min: 1 + max: 1 + - type: Pullable + - type: Strap + position: Down + rotation: -90 + buckleOffset: "0,0.15" + unbuckleOffset: "0,0.15" + - type: Foldable + - type: Appearance + visuals: + - type: FoldableVisualizer + key: rollerbed + - type: RollerbedVisualizer + key: rollerbed + +- type: entity + id: CheapRollerBed + name: rollerbed + parent: RollerBed + description: A run-down rollerbed. Used to carry patients around. + components: + - type: Sprite + layers: + - state: cheap_rollerbed + map: [ "enum.FoldableVisualLayers.Base" ] + - type: Appearance + visuals: + - type: FoldableVisualizer + key: cheap_rollerbed + - type: RollerbedVisualizer + key: cheap_rollerbed + +- type: entity + id: EmergencyRollerBed + name: rollerbed + parent: RollerBed + description: A robust looking rollerbed used for emergencies. + components: + - type: Sprite + layers: + - state: emergency_rollerbed + map: [ "enum.FoldableVisualLayers.Base" ] + - type: Appearance + visuals: + - type: FoldableVisualizer + key: emergency_rollerbed + - type: RollerbedVisualizer + key: emergency_rollerbed diff --git a/Resources/Prototypes/Entities/Structures/Storage/Closets/Lockers/lockers.yml b/Resources/Prototypes/Entities/Structures/Storage/Closets/Lockers/lockers.yml index d8073e3104..e2b05bd992 100644 --- a/Resources/Prototypes/Entities/Structures/Storage/Closets/Lockers/lockers.yml +++ b/Resources/Prototypes/Entities/Structures/Storage/Closets/Lockers/lockers.yml @@ -8,6 +8,9 @@ visuals: - type: StorageVisualizer state: cabinet + state_open: cabinet_open + state_closed: cabinet_door + - type: AccessReader access: [["Bar"]] - type: EntityStorage @@ -26,6 +29,8 @@ visuals: - type: StorageVisualizer state: qm + state_open: qm_open + state_closed: qm_door - type: AccessReader access: [["Cargo"]] # TODO access [["Quartermaster"]] @@ -39,6 +44,8 @@ visuals: - type: StorageVisualizer state: cap + state_open: cap_open + state_closed: cap_door - type: AccessReader access: [["Captain"]] @@ -51,6 +58,8 @@ visuals: - type: StorageVisualizer state: hop + state_open: hop_open + state_closed: hop_door - type: AccessReader access: [["HeadOfPersonnel"]] @@ -64,6 +73,8 @@ visuals: - type: StorageVisualizer state: ce + state_open: ce_open + state_closed: ce_door - type: AccessReader access: [ [ "Engineering", "Command" ] ] @@ -77,6 +88,7 @@ visuals: - type: StorageVisualizer state: eng + state_open: eng_open state_closed: eng_elec_door - type: AccessReader access: [ [ "Engineering" ] ] @@ -91,6 +103,7 @@ visuals: - type: StorageVisualizer state: eng + state_open: eng_open state_closed: eng_weld_door - type: AccessReader access: [ [ "Engineering" ] ] @@ -105,6 +118,8 @@ visuals: - type: StorageVisualizer state: atmos + state_open: atmos_open + state_closed: atmos_door - type: AccessReader access: [ [ "Engineering" ] ] @@ -118,6 +133,8 @@ visuals: - type: StorageVisualizer state: eng_secure + state_open: eng_secure_open + state_closed: eng_secure_door - type: AccessReader access: [ [ "Engineering" ] ] @@ -131,6 +148,8 @@ visuals: - type: StorageVisualizer state: freezer + state_open: freezer_open + state_closed: freezer_door - type: AccessReader access: [ [ "Service" ] ] @@ -144,6 +163,8 @@ visuals: - type: StorageVisualizer state: hydro + state_open: hydro_open + state_closed: hydro_door - type: AccessReader access: [ [ "Service" ] ] @@ -158,6 +179,8 @@ visuals: - type: StorageVisualizer state: med + state_open: med_open + state_closed: med_door - type: AccessReader access: [ [ "Medical" ] ] @@ -171,6 +194,8 @@ visuals: - type: StorageVisualizer state: med_secure + state_open: med_secure_open + state_closed: med_secure_door - type: AccessReader access: [ [ "Medical" ] ] @@ -184,6 +209,7 @@ visuals: - type: StorageVisualizer state: med + state_open: med_open state_closed: chemical_door - type: AccessReader access: [ [ "Chemistry" ] ] @@ -198,6 +224,8 @@ visuals: - type: StorageVisualizer state: cmo + state_open: cmo_open + state_closed: cmo_door - type: AccessReader access: [ [ "Medical", "Command" ] ] @@ -211,6 +239,8 @@ visuals: - type: StorageVisualizer state: rd + state_open: rd_open + state_closed: rd_door - type: AccessReader access: [ [ "Research", "Command" ] ] @@ -223,6 +253,8 @@ visuals: - type: StorageVisualizer state: science + state_open: science_open + state_closed: science_door - type: AccessReader access: [ [ "Research" ] ] @@ -236,6 +268,8 @@ visuals: - type: StorageVisualizer state: hos + state_open: hos_open + state_closed: hos_door - type: AccessReader access: [["Security", "Command"]] @@ -249,6 +283,8 @@ visuals: - type: StorageVisualizer state: warden + state_open: warden_open + state_closed: warden_door - type: AccessReader access: [["Security", "Armory"]] # TODO access [["Brig"]] @@ -262,6 +298,8 @@ visuals: - type: StorageVisualizer state: sec + state_open: sec_open + state_closed: sec_door - type: AccessReader access: [["Security"]] @@ -286,3 +324,5 @@ visuals: - type: StorageVisualizer state: syndicate + state_open: syndicate_open + state_closed: syndicate_door diff --git a/Resources/Prototypes/Entities/Structures/Storage/Closets/base_structureclosets.yml b/Resources/Prototypes/Entities/Structures/Storage/Closets/base_structureclosets.yml index 4df4cb70cb..a68b891b68 100644 --- a/Resources/Prototypes/Entities/Structures/Storage/Closets/base_structureclosets.yml +++ b/Resources/Prototypes/Entities/Structures/Storage/Closets/base_structureclosets.yml @@ -65,5 +65,6 @@ - type: Appearance visuals: - type: StorageVisualizer + state: generic state_open: generic_open state_closed: generic_door diff --git a/Resources/Prototypes/Entities/Structures/Storage/Closets/closets.yml b/Resources/Prototypes/Entities/Structures/Storage/Closets/closets.yml index 41c491a005..0deada2727 100644 --- a/Resources/Prototypes/Entities/Structures/Storage/Closets/closets.yml +++ b/Resources/Prototypes/Entities/Structures/Storage/Closets/closets.yml @@ -9,6 +9,7 @@ visuals: - type: StorageVisualizer state: eng + state_open: eng_open state_closed: eng_tool_door # Radiation suit closet @@ -22,6 +23,7 @@ visuals: - type: StorageVisualizer state: eng + state_open: eng_open state_closed: eng_rad_door # Emergency closet @@ -35,6 +37,8 @@ visuals: - type: StorageVisualizer state: emergency + state_open: emergency_open + state_closed: emergency_door # Fire safety closet - type: entity @@ -47,6 +51,8 @@ visuals: - type: StorageVisualizer state: fire + state_open: fire_open + state_closed: fire_door # EOD closet - type: entity @@ -59,6 +65,8 @@ visuals: - type: StorageVisualizer state: bomb + state_open: bomb_open + state_closed: bomb_door # Biohazard @@ -73,6 +81,8 @@ visuals: - type: StorageVisualizer state: bio + state_open: bio_sec_open + false: bio_sec_door # Virology variant - type: entity @@ -83,6 +93,8 @@ visuals: - type: StorageVisualizer state: bio_viro + state_open: bio_viro_open + state_closed: bio_viro_door # Security variant - type: entity @@ -93,6 +105,8 @@ visuals: - type: StorageVisualizer state: bio_sec + state_open: bio_sec_open + state_closed: bio_sec_door # Janitor variant - type: entity @@ -103,11 +117,13 @@ visuals: - type: StorageVisualizer state: bio_jan + state_open: bio_jan_open + state_closed: bio_jan_door # Maintenance closet - type: entity id: ClosetMaintenance - name: maintenance closet + name: maintenance closet parent: ClosetBase description: It's a storage unit. components: diff --git a/Resources/Prototypes/Entities/Structures/Storage/Closets/wardrobe.yml b/Resources/Prototypes/Entities/Structures/Storage/Closets/wardrobe.yml index c288d5641a..4404185472 100644 --- a/Resources/Prototypes/Entities/Structures/Storage/Closets/wardrobe.yml +++ b/Resources/Prototypes/Entities/Structures/Storage/Closets/wardrobe.yml @@ -17,6 +17,7 @@ visuals: - type: StorageVisualizer state: generic + state_open: generic_open state_closed: blue_door # Pink wardrobe @@ -29,6 +30,7 @@ visuals: - type: StorageVisualizer state: generic + state_open: generic_open state_closed: pink_door # Black wardrobe @@ -41,6 +43,7 @@ visuals: - type: StorageVisualizer state: generic + state_open: generic_open state_closed: black_door # Green wardrobe @@ -53,6 +56,7 @@ visuals: - type: StorageVisualizer state: generic + state_open: generic_open state_closed: green_door # Prison wardrobe @@ -65,6 +69,7 @@ visuals: - type: StorageVisualizer state: generic + state_open: generic_open state_closed: orange_door # Yellow wardrobe @@ -77,6 +82,7 @@ visuals: - type: StorageVisualizer state: generic + state_open: generic_open state_closed: yellow_door # White wardrobe @@ -89,6 +95,7 @@ visuals: - type: StorageVisualizer state: generic + state_open: generic_open state_closed: white_door # Grey wardrobe @@ -101,6 +108,7 @@ visuals: - type: StorageVisualizer state: generic + state_open: generic_open state_closed: grey_door # Mixed wardrobe @@ -113,6 +121,7 @@ visuals: - type: StorageVisualizer state: generic + state_open: generic_open state_closed: mixed_door # Jobs @@ -126,6 +135,7 @@ visuals: - type: StorageVisualizer state: generic + state_open: generic_open state_closed: red_door - type: entity @@ -137,6 +147,7 @@ visuals: - type: StorageVisualizer state: generic + state_open: generic_open state_closed: atmos_wardrobe_door - type: entity diff --git a/Resources/Prototypes/Recipes/Lathes/medical.yml b/Resources/Prototypes/Recipes/Lathes/medical.yml index 05d6931950..24d6431f47 100644 --- a/Resources/Prototypes/Recipes/Lathes/medical.yml +++ b/Resources/Prototypes/Recipes/Lathes/medical.yml @@ -73,9 +73,9 @@ Steel: 200 - type: latheRecipe - id: BodyBag_Item - icon: Objects/Specific/Medical/Morgue/bodybags.rsi/item.png - result: BodyBag_Item + id: BodyBag_Folded + icon: Objects/Specific/Medical/Morgue/bodybags.rsi/bag_folded.png + result: BodyBag_Folded completetime: 300 materials: Plastic: 200 diff --git a/Resources/Textures/Interface/VerbIcons/fold.svg b/Resources/Textures/Interface/VerbIcons/fold.svg new file mode 100644 index 0000000000..b931cd45ae --- /dev/null +++ b/Resources/Textures/Interface/VerbIcons/fold.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/Resources/Textures/Interface/VerbIcons/fold.svg.192dpi.png b/Resources/Textures/Interface/VerbIcons/fold.svg.192dpi.png new file mode 100644 index 0000000000000000000000000000000000000000..c0afa2c5259406986825094cda1acc06c3e6ca05 GIT binary patch literal 2619 zcmai0dt4J&8odechZF@7rP45f*dj>?f-)o^COiTJ0Z|^JNeB}dLNYNKOwcHZx<#uz zVnKXXx==x>TEyxKuKA&&t|*Eux+;R8#rgtVf5n!lI|&wR)$SiNlY7tk&V1kb?!A+Z zaj_8-tfyH6048uFISIsbp5d}IC+_>v<#zxuZ9o%~@nl{MEW)HzVFs3tP}Nd7fdjw{ zQOkuQ34&A7kxW#^f(DyTK@>ED1tt0O=sYVRx#Yn*=EGU^5M`2?MgyK*2r_!NdYYJ15A%+t;;ctS8 z5ev$~aXCz*sZ=Ve%8!aEGHJenfq^tSgT`R^5DXt>o(vbNePl{^gT$By2T_U?s2oQz z8O5L}OviF@76cJE<&8L^M&GK-lyAx>jG!41nlF`3`y(Ak#UG&?koV~FEDXn#S(tph zfOlRo4!;*j*!STOwNU;cGLQGybgA^6GL(4O3c`ptroNNY?=Mg$=E)IS0;0rn6(S^T z1tP=UjZPSRf#Xm$l9S9qrHD*PxXXe9X8#FH`3T6yaxle0Vo@P1$k!NSa1Q25g_%ea znt^AHYrUP1L1dYK1`L_y)Rg^I-}VP_tN*g9yY z3{g;gsdK4gR*c7}vJgV=x!;px(%ws-X(aq%lM-=bbHwH+P7&JpF+vQ+ z4hOR@<9p=FRo-nMFIdJ@$Ti&uAqL-GqqQlbX&1UA3B|D_O^Fbv}CzoMw#5`)d{~ zPP{Opzt>(`o)#u9Cr|VCh}53;%wD$toJVU|$%V*x`snLphgNE?EZKkOp2e-L!sc9d zx0BE;~U9Cm=c6!UUR({XH$9|V| zj)E!W?YkTn@3}*+jQY>Pr7JXG4cjE&=aBi|YHEWf+*ra4>N_6Zq9W_NYaTLBn$NY; zo6Ir`uBZPb5qMuoV|Vxaez&TCt-BpnWx~^?_cE_6J9Mbi(WL0ORU_GiQQK5o{q!5% z2-ka44_4tc#T^;}&{MLvBxShr#LI%+FQVH#H$URrz6{@NcLYEuhIjTpFmJn+X8WtG zMgJ3t<5;jzH!!trPNQ?SYE#}L>%DcyAdy`A9ruK#-Y%y0D0nr}BIeHV_`YnmhiJ>| zt3@CREyJDWTErX-aDLsNwXgb-c1`K?__o7d+8-ltZrh*>x3C|ssphXeRgiMuVr_fD zYAx)!+N&-c|2Kh znRPie?hc8wxg2kNaiT*ySW$gR`wKj<$3LoQ5lBG#w|PpnxGr#{;VLxCWadC&^%kvN z(7>|${&l&a-E((EBfDebK$;sysvxD6&!(1KV{UAgty}I`e<}J$QuCDcpx!Lmfqd9W zz_Zk)7WlgX390KtlP3iNr?6Kl5;#&I(%x*S&3w5p>x-e1wo}^1s1Dm`H)TPwi`(q4P8`U%UZPY z?*-j8adwC8d;AiU4AlF&C+mmJdNcQ)?T|paX2%0lu5QHYq+b6JKI02Q=yz`Nvxj!x zula)1Z0hRqX+G&OsWo}D&PB6Czv1gl&Y6XRAo{;j^Tohn_{lRa69kk-oZB~9r`A}c zRGoRj(g)LTr1E9p8*;?Z^s4QeeV>?;*UqEZTXvq8SbN@;0mqgU!+$<*SS;t@d_m#= E0Cd{ncK`qY literal 0 HcmV?d00001 diff --git a/Resources/Textures/Interface/VerbIcons/fold.svg.192dpi.png.yml b/Resources/Textures/Interface/VerbIcons/fold.svg.192dpi.png.yml new file mode 100644 index 0000000000..5c43e23305 --- /dev/null +++ b/Resources/Textures/Interface/VerbIcons/fold.svg.192dpi.png.yml @@ -0,0 +1,2 @@ +sample: + filter: true diff --git a/Resources/Textures/Objects/Specific/Medical/Morgue/bodybags.rsi/item.png b/Resources/Textures/Objects/Specific/Medical/Morgue/bodybags.rsi/bag_folded.png similarity index 100% rename from Resources/Textures/Objects/Specific/Medical/Morgue/bodybags.rsi/item.png rename to Resources/Textures/Objects/Specific/Medical/Morgue/bodybags.rsi/bag_folded.png diff --git a/Resources/Textures/Objects/Specific/Medical/Morgue/bodybags.rsi/meta.json b/Resources/Textures/Objects/Specific/Medical/Morgue/bodybags.rsi/meta.json index fab67ad463..b6feb49959 100644 --- a/Resources/Textures/Objects/Specific/Medical/Morgue/bodybags.rsi/meta.json +++ b/Resources/Textures/Objects/Specific/Medical/Morgue/bodybags.rsi/meta.json @@ -11,7 +11,7 @@ "name": "bag" }, { - "name": "item" + "name": "bag_folded" }, { "name": "label_overlay" diff --git a/Resources/Textures/Structures/Furniture/rollerbeds.rsi/cheap_rollerbed.png b/Resources/Textures/Structures/Furniture/rollerbeds.rsi/cheap_rollerbed.png new file mode 100644 index 0000000000000000000000000000000000000000..c5dbd975b9736fb72d3b88845eec05738696959e GIT binary patch literal 326 zcmV-M0lEH(P)f@5TNq>PJkQ>R@;pD4*Y`c*I0mJZ0KokyUzWwYfwMS=F~(9# z$xR4hj~iFuTtWzYyUhB6(7@h+*7`E((RFtV&N-A)-bJ%4J1ys&@83iSVHsl|f(e=kqIiFbf$eZ4Ndm1kq?BG0`Hs4-cgLUM Y4W(pg3D@y#rT_o{07*qoM6N<$f^zAKn*aa+ literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Furniture/rollerbeds.rsi/cheap_rollerbed_buckled.png b/Resources/Textures/Structures/Furniture/rollerbeds.rsi/cheap_rollerbed_buckled.png new file mode 100644 index 0000000000000000000000000000000000000000..61330875a56334ad9e5008c9c7052a62a96a9170 GIT binary patch literal 490 zcmVaBksZRvVS(LE z8eV1W@q2H^BO8DjGiJ<~@nH}g6h)z~*Xv{=O6j0DDJ3ix3$SgQ005YE@!Rb-*}zbs zMo|>Xwrygx7v6!omeCXU7R&}J16h{6O|-6M;vfhD;G9n;U9Z=J#e*QIzDXE{%5j{= zl&Q%^3^8Caeig44y>~4x<;PoWpxDG?UuxGtfZ8k zP51j9eBbYF*vsVt007J7Qk%$TvjKp|jTuD|5kfp~LPQirq`eVMNhuq|l+w!7;czJH z#!*CPWWV1xzD-?FpD7^(LBYByG~{`nYK!z?^gZBtp2Ey2rPU*Z;$!)KtbndBk|b%A zIgVqMBuU8_t77_&;iUncn3PgWRxfjV4S5)2or<)%Dg#0Yf|=<$9=moR4Bz)Vlh`}h zM*!bHBw-kiI=l1v{Bq5*tie3H-R_xGnx={|rqVPW-AF^B(=f5L$Kw$!%lg+xDa*31 gh7f{`Jl{XX7e0*S%_@ZHTmS$707*qoM6N<$f_yvPwEzGB literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Furniture/rollerbeds.rsi/cheap_rollerbed_folded.png b/Resources/Textures/Structures/Furniture/rollerbeds.rsi/cheap_rollerbed_folded.png new file mode 100644 index 0000000000000000000000000000000000000000..c0a7bec080a4be5dbf560faea1792532dcca6f78 GIT binary patch literal 403 zcmV;E0c`$>P)3sO4uS4dfQ3gufoy`RYpRf>xJlOF`UJ=AiA%{{(x0Uq z!Ss`x*_kghy8}HvJv}`=J#WUb4a~C4*um9Ce|oDxk|Y2`QDiMp;y4cb z{l2?Ek|b!Yna}5(PN&);B7!m1(+b0o)oN8Q*{BCBmrDabbM-v$PvJVMWHy^k#e&P_f`~jP0L?!_L@LjeQUC)Hxjiiq1cCWIf=8$; x{xae?HbD@WIF4KQ$V*mnp67U;_t5Tm8{fTai!F4cR(=2g002ovPDHLkV1iXdxMKhS literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Furniture/rollerbeds.rsi/emergency_rollerbed.png b/Resources/Textures/Structures/Furniture/rollerbeds.rsi/emergency_rollerbed.png new file mode 100644 index 0000000000000000000000000000000000000000..809a1b04996617aaf0a8e17ce65b4f76d64cc71f GIT binary patch literal 449 zcmV;y0Y3hTP)zvdEF>A*yxSrZL2NX4N5eWFDhUs@V!f9dvK0UWio?^%nP=z~!5#91zCr@D**dNu(P`Ip`D9Z`y zf!P6b1QQ|4sSR$OJjI}9ZpJX}!)=5E=w&&&Bj64gNHFSv!QlYpL_rULoak8?7#J9` z1XLNOK^;MCZuq=tHHH{(Tqx0&!^#1&O2V_*r3?%V3=GCoyW#4P#Yid%VG;vc7uZ=i z5M7HsfAx%kfq{WRQcQ|0d1P?t!~sT>`WqGsFrey{z+kV2*=9hlc42J*Y+|IC$uMWa zg8!;YYX9vl9RAx`IQ&0&i{bylTMQ)E@1&XuF9%?8!oYwOPe^f24j{%%l%P;mQu~h_ rch6rvqqvzx$V{T*mr_6rGpPmuanJ0h44Nmu00000NkvXXu0mjf{HeR} literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Furniture/rollerbeds.rsi/emergency_rollerbed_buckled.png b/Resources/Textures/Structures/Furniture/rollerbeds.rsi/emergency_rollerbed_buckled.png new file mode 100644 index 0000000000000000000000000000000000000000..afad4c3fe014f4e6ad9ac6089dcafd8ac56a7fc9 GIT binary patch literal 618 zcmV-w0+s!VP)PMH3OOVmLcx;= z;>927rAvX0!F-eX5qBqvM4`S*mTzX>d-?X8Z+3ut{O^c#y3mQb zT#xxbSjT*Ai|Ynj#cUuP7q*KW0CKNAx%fw!m2^GxwCP_b<99( zp1Nw5b)ASD%-4OmlM@Q*%aLc;{eB>RZ4k7ERcn|Za6l#^x;U%W48pDSIu^@oR^nl6 zNP|rDg^AxZShWUsasv6f-!#xGaovP4aGSU{a5oIdMbQh$Mc)qq^8*g@4HLGz;qTtQ z5qpq%ZY@rIprcOs_0=)}VC>x+F;9-Q)d^`pHUTuUQuncyUPm`)!D4w$a1k$wiwwkL z3FQ>aq&z_e0K-EM#q*zw-$qP^JWkJKc<)0|nfvkcc{2m)WVYo|`sLdv6pk4H;Qdlo z#0cY~PmCDN&&|4GTu1q^)XYGb2>^KUwq(S}P|#SAxM3j7#C4{E#Dc_u#x}G8rI^wy z3(FaxLcK2aIs#w8^vsk}jJBk5J*+IO;`HQ98E^Rt(#b6Ub@|gE%cMMmz!uXpQ%2+J+KoJuO3sLS=X+wE;9jME^OZ#Oq})e7SL2bTjsz|gK5CIA2c07*qoM6N<$ Eg5t6wssI20 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Furniture/rollerbeds.rsi/emergency_rollerbed_folded.png b/Resources/Textures/Structures/Furniture/rollerbeds.rsi/emergency_rollerbed_folded.png new file mode 100644 index 0000000000000000000000000000000000000000..f1e3a2b82023dbdb92cc578b1e20907c446f341c GIT binary patch literal 582 zcmV-M0=fN(P)*0D!YGaL=O7msYI2w+DWOF9Q(P3gwOpjEl*AsSxX8sxNck5B z}C}WGINF?J~`vG8XVu2GNEJK$3_3b5%XnJ&p^AE3tXuq8ZT{CQXa_$4K zZ!gd_1Cfsy0N^vahww@WrFt**`Hb!X0JY8c1u?!en>J45BZgtO0$6gXu_0w_Y{2cv zBqg;_x4M+}PyJauzH=sF4k)rpSaS2~I-6EUxSI=dd^wYli+}?R`Ma_9bimm=9^WxA zW;jbifF2%XSThiD69GSLBi2zC;B1c10#O#*!PxU7$&Q{(GbV@>hPr{OUEl(ul!neVnKTHbv2Kd*{ UiU+qUX8-^I07*qoM6N<$g4;L@r~m)} literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Furniture/rollerbeds.rsi/meta.json b/Resources/Textures/Structures/Furniture/rollerbeds.rsi/meta.json new file mode 100644 index 0000000000..669e74f8e2 --- /dev/null +++ b/Resources/Textures/Structures/Furniture/rollerbeds.rsi/meta.json @@ -0,0 +1,38 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from cev-eris at https://github.com/discordia-space/CEV-Eris/commit/59fe5dd2841f47a8abce60eecb9fafad34282bd0, Baystation 12 and AuroraStation", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "rollerbed" + }, + { + "name": "rollerbed_buckled" + }, + { + "name": "rollerbed_folded" + }, + { + "name": "cheap_rollerbed" + }, + { + "name": "cheap_rollerbed_buckled" + }, + { + "name": "cheap_rollerbed_folded" + }, + { + "name": "emergency_rollerbed" + }, + { + "name": "emergency_rollerbed_buckled" + }, + { + "name": "emergency_rollerbed_folded" + } + ] +} diff --git a/Resources/Textures/Structures/Furniture/rollerbeds.rsi/rollerbed.png b/Resources/Textures/Structures/Furniture/rollerbeds.rsi/rollerbed.png new file mode 100644 index 0000000000000000000000000000000000000000..846341ca498b7fd858760bfd154301746c6c1b4b GIT binary patch literal 402 zcmV;D0d4+?P)!VdD`55d{7R*3up%(KR@@+aS`P5JaO}9S4y#q)tL} zXD&?^L0pq^gWi3ofQACC+)tZ;fXCoOuKeZ^Iore0W zqK1v@n@9n+cQQhA3P5(Z>_u{45Ut0Gq85wCUVq)BVCWNvY{#8?7DkZPc3g`3z*7MV zhK}vH69t{2r44>4gk;$u|gU;&G9p=#8kgP)Hn)(8Xc5MwYHQW(FpbRrM=Ak zC^0Q@39y;jvIg%T9Br&}+xw+nigVKVBAH&BYr! literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Furniture/rollerbeds.rsi/rollerbed_buckled.png b/Resources/Textures/Structures/Furniture/rollerbeds.rsi/rollerbed_buckled.png new file mode 100644 index 0000000000000000000000000000000000000000..eaf05429e086a45b9c85bba9001c8f12a6a716fb GIT binary patch literal 565 zcmV-50?Pe~P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0m?~4K~z{rV;BXa zU=$2AV1&|mL2Kuf|7I4ZP#$sM)QQs!)#W(^%_rIc7tdaT@`wZa#(Km%z|^k#KbS{n zaQaXyBV$-t+W(iz(G0fM5>R1OaQNs8oN|N!KD{70@w-bIzz$H0D+UW-1K*DBV&JlN zgYrlN`1FDtc56{D0~3@#U|`e%qYfBw2N0DF1H2^}$SI09Y<*5J8xmCz)p&3)RMl>R ziVz1tj^6b_mtaA}0_Eck0R|60Fq_x{39JW7A7;R>2OI+TUx-4v*g;#fA6X#)iUNE< zQQ|cNBdDf>@&^QfLjcMi5CE=@O)PA|j<|B^as!Bl0Y9Ix22i~Y0-*N5rY);b!r8KfZlvggXF4 zi;Idk1gkMKtiAP@VP+~PL;CFRa1G=FkmcxRzI^=>>{*Zl;3Xk404dyc@E4ekD`64~ zK%N58$Yvq~a0q|^awvcWfB@!FN&z-ALB3~TU|;|MUw;JYlCioS00000NkvXXu0mjf DAE(s8 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Furniture/rollerbeds.rsi/rollerbed_folded.png b/Resources/Textures/Structures/Furniture/rollerbeds.rsi/rollerbed_folded.png new file mode 100644 index 0000000000000000000000000000000000000000..5783eaef98ff83a0ade2515e6e4eedd70537ee58 GIT binary patch literal 401 zcmV;C0dD?@P)i-Gp zA?QMwkCfyz@v6J`=sLse=dTzvz%Oui3M04fSizM4XBz3hol2osBPf-^(*1*z`$^V>am6ZF$D-VFl*Xm z2IO*J*0jk4^$;Bb7tdb8D}V3NbvQeH_IHMvshkXJZ+%A*#|Civ6uAr_WC$?;SEynQ z0a!Lfwm2{_oWab(lq5?}oj8q>CWv+b0|NuRIE4W-3sZ*5@)D99KujVeITsMB6JUVY zXv67%dylR&U`qqkNDs(>s6fdw?8(+zNX5@FvyGr#b)tK1qQ-SXS7;00000NkvXXu0mjf`r)bc literal 0 HcmV?d00001