Rollerbeds (#5681)
@@ -299,6 +299,7 @@ namespace Content.Client.Entry
|
|||||||
"IncreaseDamageOnWield",
|
"IncreaseDamageOnWield",
|
||||||
"TabletopGame",
|
"TabletopGame",
|
||||||
"LitOnPowered",
|
"LitOnPowered",
|
||||||
|
"Foldable",
|
||||||
"TriggerOnSignalReceived",
|
"TriggerOnSignalReceived",
|
||||||
"ToggleDoorOnTrigger",
|
"ToggleDoorOnTrigger",
|
||||||
"DeviceNetworkComponent",
|
"DeviceNetworkComponent",
|
||||||
|
|||||||
@@ -23,6 +23,10 @@ namespace Content.Client.Morgue.Visualizers
|
|||||||
{
|
{
|
||||||
sprite.LayerSetVisible(BodyBagVisualLayers.Label, labelVal);
|
sprite.LayerSetVisible(BodyBagVisualLayers.Label, labelVal);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sprite.LayerSetVisible(BodyBagVisualLayers.Label, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,9 @@ namespace Content.Client.Storage.Visualizers
|
|||||||
[UsedImplicitly]
|
[UsedImplicitly]
|
||||||
public sealed class StorageVisualizer : AppearanceVisualizer
|
public sealed class StorageVisualizer : AppearanceVisualizer
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the base sprite to this layer. Exists to make the inheritance tree less boilerplate-y.
|
||||||
|
/// </summary>
|
||||||
[DataField("state")]
|
[DataField("state")]
|
||||||
private string? _stateBase;
|
private string? _stateBase;
|
||||||
[DataField("state_open")]
|
[DataField("state_open")]
|
||||||
@@ -41,9 +44,24 @@ namespace Content.Client.Storage.Visualizers
|
|||||||
}
|
}
|
||||||
|
|
||||||
component.TryGetData(StorageVisuals.Open, out bool open);
|
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)
|
if (component.TryGetData(StorageVisuals.CanLock, out bool canLock) && canLock)
|
||||||
{
|
{
|
||||||
|
|||||||
36
Content.Client/Visualizer/FoldableVisualizer.cs
Normal file
@@ -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<IEntityManager>();
|
||||||
|
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
29
Content.Client/Visualizer/RollerbedVisualizer.cs
Normal file
@@ -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<IEntityManager>();
|
||||||
|
|
||||||
|
if (!entManager.TryGetComponent(appearance.Owner, out SpriteComponent? sprite)) return;
|
||||||
|
|
||||||
|
if (appearance.TryGetData("StrapState", out bool strapped) && strapped)
|
||||||
|
{
|
||||||
|
sprite.LayerSetState(0, $"{_key}_buckled");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -133,7 +133,7 @@ namespace Content.Server.Buckle.Components
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ownTransform.LocalPosition = Vector2.Zero + BuckleOffset;
|
ownTransform.LocalPosition = Vector2.Zero + strap.BuckleOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool CanBuckle(EntityUid user, EntityUid to, [NotNullWhen(true)] out StrapComponent? strap)
|
public bool CanBuckle(EntityUid user, EntityUid to, [NotNullWhen(true)] out StrapComponent? strap)
|
||||||
@@ -317,10 +317,17 @@ namespace Content.Server.Buckle.Components
|
|||||||
|
|
||||||
BuckledTo = null;
|
BuckledTo = null;
|
||||||
|
|
||||||
if (_entMan.GetComponent<TransformComponent>(Owner).Parent == _entMan.GetComponent<TransformComponent>(oldBuckledTo.Owner))
|
var entManager = IoCManager.Resolve<IEntityManager>();
|
||||||
|
var xform = entManager.GetComponent<TransformComponent>(Owner);
|
||||||
|
var oldBuckledXform = entManager.GetComponent<TransformComponent>(oldBuckledTo.Owner);
|
||||||
|
|
||||||
|
if (xform.ParentUid == oldBuckledXform.Owner)
|
||||||
{
|
{
|
||||||
_entMan.GetComponent<TransformComponent>(Owner).AttachParentToContainerOrGrid();
|
xform.AttachParentToContainerOrGrid();
|
||||||
_entMan.GetComponent<TransformComponent>(Owner).WorldRotation = _entMan.GetComponent<TransformComponent>(oldBuckledTo.Owner).WorldRotation;
|
xform.WorldRotation = oldBuckledXform.WorldRotation;
|
||||||
|
|
||||||
|
if (oldBuckledTo.UnbuckleOffset != Vector2.Zero)
|
||||||
|
xform.Coordinates = oldBuckledXform.Coordinates.Offset(oldBuckledTo.UnbuckleOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
Appearance?.SetData(BuckleVisuals.Buckled, false);
|
Appearance?.SetData(BuckleVisuals.Buckled, false);
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Content.Shared.ActionBlocker;
|
||||||
using Content.Shared.Acts;
|
using Content.Shared.Acts;
|
||||||
using Content.Shared.Alert;
|
using Content.Shared.Alert;
|
||||||
|
using Content.Shared.Buckle;
|
||||||
using Content.Shared.Buckle.Components;
|
using Content.Shared.Buckle.Components;
|
||||||
using Content.Shared.DragDrop;
|
using Content.Shared.DragDrop;
|
||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
@@ -9,6 +11,8 @@ using Content.Shared.Sound;
|
|||||||
using Robust.Server.GameObjects;
|
using Robust.Server.GameObjects;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
|
using Robust.Shared.Maths;
|
||||||
|
using Robust.Shared.Players;
|
||||||
using Robust.Shared.Serialization;
|
using Robust.Shared.Serialization;
|
||||||
using Robust.Shared.Serialization.Manager.Attributes;
|
using Robust.Shared.Serialization.Manager.Attributes;
|
||||||
using Robust.Shared.ViewVariables;
|
using Robust.Shared.ViewVariables;
|
||||||
@@ -21,8 +25,6 @@ namespace Content.Server.Buckle.Components
|
|||||||
{
|
{
|
||||||
[ComponentDependency] public readonly SpriteComponent? SpriteComponent = null;
|
[ComponentDependency] public readonly SpriteComponent? SpriteComponent = null;
|
||||||
|
|
||||||
[Dependency] private readonly IEntityManager _entMan = default!;
|
|
||||||
|
|
||||||
private readonly HashSet<EntityUid> _buckledEntities = new();
|
private readonly HashSet<EntityUid> _buckledEntities = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -37,6 +39,50 @@ namespace Content.Server.Buckle.Components
|
|||||||
[ViewVariables] [DataField("size")] private int _size = 100;
|
[ViewVariables] [DataField("size")] private int _size = 100;
|
||||||
private int _occupiedSize;
|
private int _occupiedSize;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 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 <see cref="MaxBuckleDistance"/>
|
||||||
|
/// </summary>
|
||||||
|
[DataField("buckleOffset", required: false)]
|
||||||
|
private Vector2 _buckleOffset = Vector2.Zero;
|
||||||
|
|
||||||
|
private bool _enabled = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If disabled, nothing can be buckled on this object, and it will unbuckle anything that's already buckled
|
||||||
|
/// </summary>
|
||||||
|
public bool Enabled
|
||||||
|
{
|
||||||
|
get => _enabled;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_enabled = value;
|
||||||
|
if (_enabled == value) return;
|
||||||
|
RemoveAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The distance above which a buckled entity will be automatically unbuckled.
|
||||||
|
/// Don't change it unless you really have to
|
||||||
|
/// </summary>
|
||||||
|
[DataField("maxBuckleDistance", required: false)]
|
||||||
|
public float MaxBuckleDistance = 1f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// You can specify the offset the entity will have after unbuckling.
|
||||||
|
/// </summary>
|
||||||
|
[DataField("unbuckleOffset", required: false)]
|
||||||
|
public Vector2 UnbuckleOffset = Vector2.Zero;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets and clamps the buckle offset to MaxBuckleDistance
|
||||||
|
/// </summary>
|
||||||
|
public Vector2 BuckleOffset => Vector2.Clamp(
|
||||||
|
_buckleOffset,
|
||||||
|
Vector2.One * -MaxBuckleDistance,
|
||||||
|
Vector2.One * MaxBuckleDistance);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The entity that is currently buckled here, synced from <see cref="BuckleComponent.BuckledTo"/>
|
/// The entity that is currently buckled here, synced from <see cref="BuckleComponent.BuckledTo"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -96,6 +142,8 @@ namespace Content.Server.Buckle.Components
|
|||||||
/// <returns>True if added, false otherwise</returns>
|
/// <returns>True if added, false otherwise</returns>
|
||||||
public bool TryAdd(BuckleComponent buckle, bool force = false)
|
public bool TryAdd(BuckleComponent buckle, bool force = false)
|
||||||
{
|
{
|
||||||
|
if (!Enabled) return false;
|
||||||
|
|
||||||
if (!force && !HasSpace(buckle))
|
if (!force && !HasSpace(buckle))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@@ -110,6 +158,12 @@ namespace Content.Server.Buckle.Components
|
|||||||
|
|
||||||
buckle.Appearance?.SetData(StrapVisuals.RotationAngle, _rotation);
|
buckle.Appearance?.SetData(StrapVisuals.RotationAngle, _rotation);
|
||||||
|
|
||||||
|
// Update the visuals of the strap object
|
||||||
|
if (IoCManager.Resolve<IEntityManager>().TryGetComponent<AppearanceComponent>(Owner, out var appearance))
|
||||||
|
{
|
||||||
|
appearance.SetData("StrapState", true);
|
||||||
|
}
|
||||||
|
|
||||||
#pragma warning disable 618
|
#pragma warning disable 618
|
||||||
SendMessage(new StrapMessage(buckle.Owner, Owner));
|
SendMessage(new StrapMessage(buckle.Owner, Owner));
|
||||||
#pragma warning restore 618
|
#pragma warning restore 618
|
||||||
@@ -126,6 +180,11 @@ namespace Content.Server.Buckle.Components
|
|||||||
{
|
{
|
||||||
if (_buckledEntities.Remove(buckle.Owner))
|
if (_buckledEntities.Remove(buckle.Owner))
|
||||||
{
|
{
|
||||||
|
if (IoCManager.Resolve<IEntityManager>().TryGetComponent<AppearanceComponent>(Owner, out var appearance))
|
||||||
|
{
|
||||||
|
appearance.SetData("StrapState", false);
|
||||||
|
}
|
||||||
|
|
||||||
_occupiedSize -= buckle.Size;
|
_occupiedSize -= buckle.Size;
|
||||||
#pragma warning disable 618
|
#pragma warning disable 618
|
||||||
SendMessage(new UnStrapMessage(buckle.Owner, Owner));
|
SendMessage(new UnStrapMessage(buckle.Owner, Owner));
|
||||||
@@ -147,9 +206,11 @@ namespace Content.Server.Buckle.Components
|
|||||||
|
|
||||||
private void RemoveAll()
|
private void RemoveAll()
|
||||||
{
|
{
|
||||||
|
var entManager = IoCManager.Resolve<IEntityManager>();
|
||||||
|
|
||||||
foreach (var entity in _buckledEntities.ToArray())
|
foreach (var entity in _buckledEntities.ToArray())
|
||||||
{
|
{
|
||||||
if (_entMan.TryGetComponent<BuckleComponent?>(entity, out var buckle))
|
if (entManager.TryGetComponent<BuckleComponent>(entity, out var buckle))
|
||||||
{
|
{
|
||||||
buckle.TryUnbuckle(entity, true);
|
buckle.TryUnbuckle(entity, true);
|
||||||
}
|
}
|
||||||
@@ -166,7 +227,9 @@ namespace Content.Server.Buckle.Components
|
|||||||
|
|
||||||
bool IInteractHand.InteractHand(InteractHandEventArgs eventArgs)
|
bool IInteractHand.InteractHand(InteractHandEventArgs eventArgs)
|
||||||
{
|
{
|
||||||
if (!_entMan.TryGetComponent<BuckleComponent?>(eventArgs.User, out var buckle))
|
var entManager = IoCManager.Resolve<IEntityManager>();
|
||||||
|
|
||||||
|
if (!entManager.TryGetComponent<BuckleComponent>(eventArgs.User, out var buckle))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -176,7 +239,9 @@ namespace Content.Server.Buckle.Components
|
|||||||
|
|
||||||
public override bool DragDropOn(DragDropEvent eventArgs)
|
public override bool DragDropOn(DragDropEvent eventArgs)
|
||||||
{
|
{
|
||||||
if (!_entMan.TryGetComponent(eventArgs.Dragged, out BuckleComponent? buckleComponent)) return false;
|
var entManager = IoCManager.Resolve<IEntityManager>();
|
||||||
|
|
||||||
|
if (!entManager.TryGetComponent(eventArgs.Dragged, out BuckleComponent? buckleComponent)) return false;
|
||||||
return buckleComponent.TryBuckle(eventArgs.User, Owner);
|
return buckleComponent.TryBuckle(eventArgs.User, Owner);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,10 +42,12 @@ namespace Content.Server.Buckle.Systems
|
|||||||
if (!args.CanAccess || !args.CanInteract || !component.Buckled)
|
if (!args.CanAccess || !args.CanInteract || !component.Buckled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Verb verb = new();
|
Verb verb = new()
|
||||||
verb.Act = () => component.TryUnbuckle(args.User);
|
{
|
||||||
verb.Text = Loc.GetString("verb-categories-unbuckle");
|
Act = () => component.TryUnbuckle(args.User),
|
||||||
verb.IconTexture = "/Textures/Interface/VerbIcons/unbuckle.svg.192dpi.png";
|
Text = Loc.GetString("verb-categories-unbuckle"),
|
||||||
|
IconTexture = "/Textures/Interface/VerbIcons/unbuckle.svg.192dpi.png"
|
||||||
|
};
|
||||||
|
|
||||||
if (args.Target == args.User && args.Using == null)
|
if (args.Target == args.User && args.Using == null)
|
||||||
{
|
{
|
||||||
@@ -81,7 +83,7 @@ namespace Content.Server.Buckle.Systems
|
|||||||
|
|
||||||
var strapPosition = EntityManager.GetComponent<TransformComponent>(strap.Owner).Coordinates.Offset(buckle.BuckleOffset);
|
var strapPosition = EntityManager.GetComponent<TransformComponent>(strap.Owner).Coordinates.Offset(buckle.BuckleOffset);
|
||||||
|
|
||||||
if (ev.NewPosition.InRange(EntityManager, strapPosition, 0.2f))
|
if (ev.NewPosition.InRange(EntityManager, strapPosition, strap.MaxBuckleDistance))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ namespace Content.Server.Buckle.Systems
|
|||||||
|
|
||||||
private void AddStrapVerbs(EntityUid uid, StrapComponent component, GetInteractionVerbsEvent args)
|
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;
|
return;
|
||||||
|
|
||||||
// Note that for whatever bloody reason, buckle component has its own interaction range. Additionally, this
|
// 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))
|
if (!_interactionSystem.InRangeUnobstructed(args.User, args.Target, range: buckledComp.Range))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
Verb verb = new();
|
Verb verb = new()
|
||||||
verb.Act = () => buckledComp.TryUnbuckle(args.User);
|
{
|
||||||
verb.Category = VerbCategory.Unbuckle;
|
Act = () => buckledComp.TryUnbuckle(args.User),
|
||||||
|
Category = VerbCategory.Unbuckle
|
||||||
|
};
|
||||||
|
|
||||||
if (entity == args.User)
|
if (entity == args.User)
|
||||||
verb.Text = Loc.GetString("verb-self-target-pronoun");
|
verb.Text = Loc.GetString("verb-self-target-pronoun");
|
||||||
else
|
else
|
||||||
@@ -64,10 +67,12 @@ namespace Content.Server.Buckle.Systems
|
|||||||
component.HasSpace(buckle) &&
|
component.HasSpace(buckle) &&
|
||||||
_interactionSystem.InRangeUnobstructed(args.User, args.Target, range: buckle.Range))
|
_interactionSystem.InRangeUnobstructed(args.User, args.Target, range: buckle.Range))
|
||||||
{
|
{
|
||||||
Verb verb = new();
|
Verb verb = new()
|
||||||
verb.Act = () => buckle.TryBuckle(args.User, args.Target);
|
{
|
||||||
verb.Category = VerbCategory.Buckle;
|
Act = () => buckle.TryBuckle(args.User, args.Target),
|
||||||
verb.Text = Loc.GetString("verb-self-target-pronoun");
|
Category = VerbCategory.Buckle,
|
||||||
|
Text = Loc.GetString("verb-self-target-pronoun")
|
||||||
|
};
|
||||||
args.Verbs.Add(verb);
|
args.Verbs.Add(verb);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,14 +87,15 @@ namespace Content.Server.Buckle.Systems
|
|||||||
if (!_interactionSystem.InRangeUnobstructed(@using, args.Target, usingBuckle.Range, predicate: Ignored))
|
if (!_interactionSystem.InRangeUnobstructed(@using, args.Target, usingBuckle.Range, predicate: Ignored))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Verb verb = new();
|
Verb verb = new()
|
||||||
verb.Act = () => usingBuckle.TryBuckle(args.User, args.Target);
|
{
|
||||||
verb.Category = VerbCategory.Buckle;
|
Act = () => usingBuckle.TryBuckle(args.User, args.Target),
|
||||||
verb.Text = EntityManager.GetComponent<MetaDataComponent>(@using).EntityName;
|
Category = VerbCategory.Buckle,
|
||||||
|
Text = EntityManager.GetComponent<MetaDataComponent>(@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.
|
||||||
// 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
|
||||||
verb.Priority = EntityManager.HasComponent<ActorComponent>(@using) ? 1 : -1;
|
Priority = EntityManager.HasComponent<ActorComponent>(@using) ? 1 : -1
|
||||||
|
};
|
||||||
|
|
||||||
args.Verbs.Add(verb);
|
args.Verbs.Add(verb);
|
||||||
}
|
}
|
||||||
|
|||||||
25
Content.Server/Foldable/FoldableComponent.cs
Normal file
@@ -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
|
||||||
|
{
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Used to create "foldable structures" that you can pickup like an item when folded. Used for rollerbeds and wheelchairs
|
||||||
|
/// </summary>
|
||||||
|
[RegisterComponent]
|
||||||
|
public class FoldableComponent : Component
|
||||||
|
{
|
||||||
|
public override string Name => "Foldable";
|
||||||
|
|
||||||
|
[DataField("folded")]
|
||||||
|
[ViewVariables]
|
||||||
|
public bool IsFolded = false;
|
||||||
|
|
||||||
|
public bool CanBeFolded = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
131
Content.Server/Foldable/FoldableSystem.cs
Normal file
@@ -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<FoldableComponent, ComponentInit>(OnFoldableInit);
|
||||||
|
SubscribeLocalEvent<FoldableComponent, StorageOpenAttemptEvent>(OnFoldableOpenAttempt);
|
||||||
|
SubscribeLocalEvent<FoldableComponent, AttemptItemPickupEvent>(OnPickedUpAttempt);
|
||||||
|
SubscribeLocalEvent<FoldableComponent, GetAlternativeVerbsEvent>(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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Try to fold/unfold
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="comp"></param>
|
||||||
|
/// <param name="state">Folded state we want</param>
|
||||||
|
/// <returns>True if successful</returns>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Set the folded state of the given <see cref="FoldableComponent"/>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="component"></param>
|
||||||
|
/// <param name="folded">If true, the component will become folded, else unfolded</param>
|
||||||
|
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
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Prevents foldable objects to be picked up when unfolded
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="uid"></param>
|
||||||
|
/// <param name="component"></param>
|
||||||
|
/// <param name="args"></param>
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -193,12 +193,18 @@ namespace Content.Server.Storage.Components
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
var @event = new StorageOpenAttemptEvent();
|
||||||
|
IoCManager.Resolve<IEntityManager>().EventBus.RaiseLocalEvent(Owner, @event);
|
||||||
|
|
||||||
|
return !@event.Cancelled;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual bool CanClose(EntityUid user, bool silent = false)
|
public virtual bool CanClose(EntityUid user, bool silent = false)
|
||||||
{
|
{
|
||||||
return true;
|
var @event = new StorageCloseAttemptEvent();
|
||||||
|
IoCManager.Resolve<IEntityManager>().EventBus.RaiseLocalEvent(Owner, @event);
|
||||||
|
|
||||||
|
return !@event.Cancelled;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ToggleOpen(EntityUid user)
|
public void ToggleOpen(EntityUid user)
|
||||||
@@ -479,4 +485,14 @@ namespace Content.Server.Storage.Components
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public sealed class StorageOpenAttemptEvent : CancellableEntityEventArgs
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class StorageCloseAttemptEvent : CancellableEntityEventArgs
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,11 +57,13 @@ namespace Content.Shared.Buckle.Components
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Serializable, NetSerializable]
|
[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]
|
[Serializable, NetSerializable]
|
||||||
#pragma warning disable 618
|
#pragma warning disable 618
|
||||||
public abstract class StrapChangeMessage : ComponentMessage
|
public abstract class StrapChangeMessage : ComponentMessage
|
||||||
|
|||||||
@@ -615,11 +615,14 @@ namespace Content.Shared.Hands.Components
|
|||||||
protected bool CanInsertEntityIntoHand(Hand hand, EntityUid entity)
|
protected bool CanInsertEntityIntoHand(Hand hand, EntityUid entity)
|
||||||
{
|
{
|
||||||
var handContainer = hand.Container;
|
var handContainer = hand.Container;
|
||||||
if (handContainer == null)
|
if (handContainer == null) return false;
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!handContainer.CanInsert(entity))
|
if (!handContainer.CanInsert(entity)) return false;
|
||||||
return false;
|
|
||||||
|
var @event = new AttemptItemPickupEvent();
|
||||||
|
_entMan.EventBus.RaiseLocalEvent(entity, @event);
|
||||||
|
|
||||||
|
if (@event.Cancelled) return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,9 @@
|
|||||||
|
|
||||||
namespace Content.Shared.Item
|
namespace Content.Shared.Item
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Raised on a *mob* when it tries to pickup something
|
||||||
|
/// </summary>
|
||||||
public class PickupAttemptEvent : CancellableEntityEventArgs
|
public class PickupAttemptEvent : CancellableEntityEventArgs
|
||||||
{
|
{
|
||||||
public PickupAttemptEvent(EntityUid uid)
|
public PickupAttemptEvent(EntityUid uid)
|
||||||
@@ -11,4 +14,14 @@ namespace Content.Shared.Item
|
|||||||
|
|
||||||
public EntityUid Uid { get; }
|
public EntityUid Uid { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Raised on the *item* when tried to be picked up
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Doesn't just handle "items" but calling it "PickedUpAttempt" is too close to "Pickup" for the sleep deprived brain.
|
||||||
|
/// </remarks>
|
||||||
|
public sealed class AttemptItemPickupEvent : CancellableEntityEventArgs
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ using Robust.Shared.GameStates;
|
|||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
using Robust.Shared.Maths;
|
using Robust.Shared.Maths;
|
||||||
using Robust.Shared.Physics;
|
using Robust.Shared.Physics;
|
||||||
using Robust.Shared.Players;
|
|
||||||
using Robust.Shared.Serialization;
|
using Robust.Shared.Serialization;
|
||||||
using Robust.Shared.Serialization.Manager.Attributes;
|
using Robust.Shared.Serialization.Manager.Attributes;
|
||||||
using Robust.Shared.ViewVariables;
|
using Robust.Shared.ViewVariables;
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
# Foldable
|
||||||
|
|
||||||
|
foldable-deploy-fail = You can't deploy the {$object} here.
|
||||||
|
fold-verb = Fold
|
||||||
|
unfold-verb = Unfold
|
||||||
@@ -9,6 +9,7 @@
|
|||||||
sprite: Objects/Specific/Medical/Morgue/bodybags.rsi
|
sprite: Objects/Specific/Medical/Morgue/bodybags.rsi
|
||||||
layers:
|
layers:
|
||||||
- state: bag
|
- state: bag
|
||||||
|
map: ["enum.FoldableVisualLayers.Base"]
|
||||||
- state: open_overlay
|
- state: open_overlay
|
||||||
map: ["enum.StorageVisualLayers.Door"]
|
map: ["enum.StorageVisualLayers.Door"]
|
||||||
- state: label_overlay
|
- state: label_overlay
|
||||||
@@ -27,13 +28,18 @@
|
|||||||
!type:PhysShapeAabb
|
!type:PhysShapeAabb
|
||||||
bounds: "-0.5,-0.45,0.5,0.1"
|
bounds: "-0.5,-0.45,0.5,0.1"
|
||||||
mass: 5
|
mass: 5
|
||||||
|
mask:
|
||||||
|
- Impassable
|
||||||
|
- SmallImpassable
|
||||||
- type: BodyBagEntityStorage
|
- type: BodyBagEntityStorage
|
||||||
CanWeldShut: false
|
CanWeldShut: false
|
||||||
Capacity: 1
|
Capacity: 1
|
||||||
|
IsCollidableWhenOpen: true
|
||||||
closeSound:
|
closeSound:
|
||||||
path: /Audio/Misc/zip.ogg
|
path: /Audio/Misc/zip.ogg
|
||||||
openSound:
|
openSound:
|
||||||
path: /Audio/Misc/zip.ogg
|
path: /Audio/Misc/zip.ogg
|
||||||
|
- type: Foldable
|
||||||
- type: PaperLabel
|
- type: PaperLabel
|
||||||
labelSlot:
|
labelSlot:
|
||||||
insertVerbText: Attach Label
|
insertVerbText: Attach Label
|
||||||
@@ -45,20 +51,20 @@
|
|||||||
visuals:
|
visuals:
|
||||||
- type: StorageVisualizer
|
- type: StorageVisualizer
|
||||||
state_open: open_overlay
|
state_open: open_overlay
|
||||||
state_closed: bag
|
- type: FoldableVisualizer
|
||||||
|
key: bag
|
||||||
- type: BodyBagVisualizer
|
- type: BodyBagVisualizer
|
||||||
- type: Pullable
|
- type: Pullable
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
id: BodyBag_Item
|
id: BodyBag_Folded
|
||||||
name: body bag
|
name: body bag
|
||||||
description: A plastic bag designed for the storage and transportation of cadavers.
|
description: A plastic bag designed for the storage and transportation of cadavers.
|
||||||
parent: BaseItem
|
parent: BodyBag_Container
|
||||||
|
suffix: Folded
|
||||||
components:
|
components:
|
||||||
- type: Sprite
|
- type: Foldable
|
||||||
netsync: false
|
folded: true
|
||||||
sprite: Objects/Specific/Medical/Morgue/bodybags.rsi
|
|
||||||
state: item
|
|
||||||
# - type: BodyBagItem #TODO: we need some kind of generic placable, like thus:
|
# - type: BodyBagItem #TODO: we need some kind of generic placable, like thus:
|
||||||
# - type: Placeable
|
# - type: Placeable
|
||||||
# prototype: someId
|
# prototype: someId
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
noRot: true
|
noRot: true
|
||||||
- type: Strap
|
- type: Strap
|
||||||
position: Stand
|
position: Stand
|
||||||
|
buckleOffset: "0,0.15"
|
||||||
- type: Pullable
|
- type: Pullable
|
||||||
- type: Damageable
|
- type: Damageable
|
||||||
damageContainer: Inorganic
|
damageContainer: Inorganic
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -8,6 +8,9 @@
|
|||||||
visuals:
|
visuals:
|
||||||
- type: StorageVisualizer
|
- type: StorageVisualizer
|
||||||
state: cabinet
|
state: cabinet
|
||||||
|
state_open: cabinet_open
|
||||||
|
state_closed: cabinet_door
|
||||||
|
|
||||||
- type: AccessReader
|
- type: AccessReader
|
||||||
access: [["Bar"]]
|
access: [["Bar"]]
|
||||||
- type: EntityStorage
|
- type: EntityStorage
|
||||||
@@ -26,6 +29,8 @@
|
|||||||
visuals:
|
visuals:
|
||||||
- type: StorageVisualizer
|
- type: StorageVisualizer
|
||||||
state: qm
|
state: qm
|
||||||
|
state_open: qm_open
|
||||||
|
state_closed: qm_door
|
||||||
- type: AccessReader
|
- type: AccessReader
|
||||||
access: [["Cargo"]] # TODO access [["Quartermaster"]]
|
access: [["Cargo"]] # TODO access [["Quartermaster"]]
|
||||||
|
|
||||||
@@ -39,6 +44,8 @@
|
|||||||
visuals:
|
visuals:
|
||||||
- type: StorageVisualizer
|
- type: StorageVisualizer
|
||||||
state: cap
|
state: cap
|
||||||
|
state_open: cap_open
|
||||||
|
state_closed: cap_door
|
||||||
- type: AccessReader
|
- type: AccessReader
|
||||||
access: [["Captain"]]
|
access: [["Captain"]]
|
||||||
|
|
||||||
@@ -51,6 +58,8 @@
|
|||||||
visuals:
|
visuals:
|
||||||
- type: StorageVisualizer
|
- type: StorageVisualizer
|
||||||
state: hop
|
state: hop
|
||||||
|
state_open: hop_open
|
||||||
|
state_closed: hop_door
|
||||||
- type: AccessReader
|
- type: AccessReader
|
||||||
access: [["HeadOfPersonnel"]]
|
access: [["HeadOfPersonnel"]]
|
||||||
|
|
||||||
@@ -64,6 +73,8 @@
|
|||||||
visuals:
|
visuals:
|
||||||
- type: StorageVisualizer
|
- type: StorageVisualizer
|
||||||
state: ce
|
state: ce
|
||||||
|
state_open: ce_open
|
||||||
|
state_closed: ce_door
|
||||||
- type: AccessReader
|
- type: AccessReader
|
||||||
access: [ [ "Engineering", "Command" ] ]
|
access: [ [ "Engineering", "Command" ] ]
|
||||||
|
|
||||||
@@ -77,6 +88,7 @@
|
|||||||
visuals:
|
visuals:
|
||||||
- type: StorageVisualizer
|
- type: StorageVisualizer
|
||||||
state: eng
|
state: eng
|
||||||
|
state_open: eng_open
|
||||||
state_closed: eng_elec_door
|
state_closed: eng_elec_door
|
||||||
- type: AccessReader
|
- type: AccessReader
|
||||||
access: [ [ "Engineering" ] ]
|
access: [ [ "Engineering" ] ]
|
||||||
@@ -91,6 +103,7 @@
|
|||||||
visuals:
|
visuals:
|
||||||
- type: StorageVisualizer
|
- type: StorageVisualizer
|
||||||
state: eng
|
state: eng
|
||||||
|
state_open: eng_open
|
||||||
state_closed: eng_weld_door
|
state_closed: eng_weld_door
|
||||||
- type: AccessReader
|
- type: AccessReader
|
||||||
access: [ [ "Engineering" ] ]
|
access: [ [ "Engineering" ] ]
|
||||||
@@ -105,6 +118,8 @@
|
|||||||
visuals:
|
visuals:
|
||||||
- type: StorageVisualizer
|
- type: StorageVisualizer
|
||||||
state: atmos
|
state: atmos
|
||||||
|
state_open: atmos_open
|
||||||
|
state_closed: atmos_door
|
||||||
- type: AccessReader
|
- type: AccessReader
|
||||||
access: [ [ "Engineering" ] ]
|
access: [ [ "Engineering" ] ]
|
||||||
|
|
||||||
@@ -118,6 +133,8 @@
|
|||||||
visuals:
|
visuals:
|
||||||
- type: StorageVisualizer
|
- type: StorageVisualizer
|
||||||
state: eng_secure
|
state: eng_secure
|
||||||
|
state_open: eng_secure_open
|
||||||
|
state_closed: eng_secure_door
|
||||||
- type: AccessReader
|
- type: AccessReader
|
||||||
access: [ [ "Engineering" ] ]
|
access: [ [ "Engineering" ] ]
|
||||||
|
|
||||||
@@ -131,6 +148,8 @@
|
|||||||
visuals:
|
visuals:
|
||||||
- type: StorageVisualizer
|
- type: StorageVisualizer
|
||||||
state: freezer
|
state: freezer
|
||||||
|
state_open: freezer_open
|
||||||
|
state_closed: freezer_door
|
||||||
- type: AccessReader
|
- type: AccessReader
|
||||||
access: [ [ "Service" ] ]
|
access: [ [ "Service" ] ]
|
||||||
|
|
||||||
@@ -144,6 +163,8 @@
|
|||||||
visuals:
|
visuals:
|
||||||
- type: StorageVisualizer
|
- type: StorageVisualizer
|
||||||
state: hydro
|
state: hydro
|
||||||
|
state_open: hydro_open
|
||||||
|
state_closed: hydro_door
|
||||||
- type: AccessReader
|
- type: AccessReader
|
||||||
access: [ [ "Service" ] ]
|
access: [ [ "Service" ] ]
|
||||||
|
|
||||||
@@ -158,6 +179,8 @@
|
|||||||
visuals:
|
visuals:
|
||||||
- type: StorageVisualizer
|
- type: StorageVisualizer
|
||||||
state: med
|
state: med
|
||||||
|
state_open: med_open
|
||||||
|
state_closed: med_door
|
||||||
- type: AccessReader
|
- type: AccessReader
|
||||||
access: [ [ "Medical" ] ]
|
access: [ [ "Medical" ] ]
|
||||||
|
|
||||||
@@ -171,6 +194,8 @@
|
|||||||
visuals:
|
visuals:
|
||||||
- type: StorageVisualizer
|
- type: StorageVisualizer
|
||||||
state: med_secure
|
state: med_secure
|
||||||
|
state_open: med_secure_open
|
||||||
|
state_closed: med_secure_door
|
||||||
- type: AccessReader
|
- type: AccessReader
|
||||||
access: [ [ "Medical" ] ]
|
access: [ [ "Medical" ] ]
|
||||||
|
|
||||||
@@ -184,6 +209,7 @@
|
|||||||
visuals:
|
visuals:
|
||||||
- type: StorageVisualizer
|
- type: StorageVisualizer
|
||||||
state: med
|
state: med
|
||||||
|
state_open: med_open
|
||||||
state_closed: chemical_door
|
state_closed: chemical_door
|
||||||
- type: AccessReader
|
- type: AccessReader
|
||||||
access: [ [ "Chemistry" ] ]
|
access: [ [ "Chemistry" ] ]
|
||||||
@@ -198,6 +224,8 @@
|
|||||||
visuals:
|
visuals:
|
||||||
- type: StorageVisualizer
|
- type: StorageVisualizer
|
||||||
state: cmo
|
state: cmo
|
||||||
|
state_open: cmo_open
|
||||||
|
state_closed: cmo_door
|
||||||
- type: AccessReader
|
- type: AccessReader
|
||||||
access: [ [ "Medical", "Command" ] ]
|
access: [ [ "Medical", "Command" ] ]
|
||||||
|
|
||||||
@@ -211,6 +239,8 @@
|
|||||||
visuals:
|
visuals:
|
||||||
- type: StorageVisualizer
|
- type: StorageVisualizer
|
||||||
state: rd
|
state: rd
|
||||||
|
state_open: rd_open
|
||||||
|
state_closed: rd_door
|
||||||
- type: AccessReader
|
- type: AccessReader
|
||||||
access: [ [ "Research", "Command" ] ]
|
access: [ [ "Research", "Command" ] ]
|
||||||
|
|
||||||
@@ -223,6 +253,8 @@
|
|||||||
visuals:
|
visuals:
|
||||||
- type: StorageVisualizer
|
- type: StorageVisualizer
|
||||||
state: science
|
state: science
|
||||||
|
state_open: science_open
|
||||||
|
state_closed: science_door
|
||||||
- type: AccessReader
|
- type: AccessReader
|
||||||
access: [ [ "Research" ] ]
|
access: [ [ "Research" ] ]
|
||||||
|
|
||||||
@@ -236,6 +268,8 @@
|
|||||||
visuals:
|
visuals:
|
||||||
- type: StorageVisualizer
|
- type: StorageVisualizer
|
||||||
state: hos
|
state: hos
|
||||||
|
state_open: hos_open
|
||||||
|
state_closed: hos_door
|
||||||
- type: AccessReader
|
- type: AccessReader
|
||||||
access: [["Security", "Command"]]
|
access: [["Security", "Command"]]
|
||||||
|
|
||||||
@@ -249,6 +283,8 @@
|
|||||||
visuals:
|
visuals:
|
||||||
- type: StorageVisualizer
|
- type: StorageVisualizer
|
||||||
state: warden
|
state: warden
|
||||||
|
state_open: warden_open
|
||||||
|
state_closed: warden_door
|
||||||
- type: AccessReader
|
- type: AccessReader
|
||||||
access: [["Security", "Armory"]] # TODO access [["Brig"]]
|
access: [["Security", "Armory"]] # TODO access [["Brig"]]
|
||||||
|
|
||||||
@@ -262,6 +298,8 @@
|
|||||||
visuals:
|
visuals:
|
||||||
- type: StorageVisualizer
|
- type: StorageVisualizer
|
||||||
state: sec
|
state: sec
|
||||||
|
state_open: sec_open
|
||||||
|
state_closed: sec_door
|
||||||
- type: AccessReader
|
- type: AccessReader
|
||||||
access: [["Security"]]
|
access: [["Security"]]
|
||||||
|
|
||||||
@@ -286,3 +324,5 @@
|
|||||||
visuals:
|
visuals:
|
||||||
- type: StorageVisualizer
|
- type: StorageVisualizer
|
||||||
state: syndicate
|
state: syndicate
|
||||||
|
state_open: syndicate_open
|
||||||
|
state_closed: syndicate_door
|
||||||
|
|||||||
@@ -65,5 +65,6 @@
|
|||||||
- type: Appearance
|
- type: Appearance
|
||||||
visuals:
|
visuals:
|
||||||
- type: StorageVisualizer
|
- type: StorageVisualizer
|
||||||
|
state: generic
|
||||||
state_open: generic_open
|
state_open: generic_open
|
||||||
state_closed: generic_door
|
state_closed: generic_door
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
visuals:
|
visuals:
|
||||||
- type: StorageVisualizer
|
- type: StorageVisualizer
|
||||||
state: eng
|
state: eng
|
||||||
|
state_open: eng_open
|
||||||
state_closed: eng_tool_door
|
state_closed: eng_tool_door
|
||||||
|
|
||||||
# Radiation suit closet
|
# Radiation suit closet
|
||||||
@@ -22,6 +23,7 @@
|
|||||||
visuals:
|
visuals:
|
||||||
- type: StorageVisualizer
|
- type: StorageVisualizer
|
||||||
state: eng
|
state: eng
|
||||||
|
state_open: eng_open
|
||||||
state_closed: eng_rad_door
|
state_closed: eng_rad_door
|
||||||
|
|
||||||
# Emergency closet
|
# Emergency closet
|
||||||
@@ -35,6 +37,8 @@
|
|||||||
visuals:
|
visuals:
|
||||||
- type: StorageVisualizer
|
- type: StorageVisualizer
|
||||||
state: emergency
|
state: emergency
|
||||||
|
state_open: emergency_open
|
||||||
|
state_closed: emergency_door
|
||||||
|
|
||||||
# Fire safety closet
|
# Fire safety closet
|
||||||
- type: entity
|
- type: entity
|
||||||
@@ -47,6 +51,8 @@
|
|||||||
visuals:
|
visuals:
|
||||||
- type: StorageVisualizer
|
- type: StorageVisualizer
|
||||||
state: fire
|
state: fire
|
||||||
|
state_open: fire_open
|
||||||
|
state_closed: fire_door
|
||||||
|
|
||||||
# EOD closet
|
# EOD closet
|
||||||
- type: entity
|
- type: entity
|
||||||
@@ -59,6 +65,8 @@
|
|||||||
visuals:
|
visuals:
|
||||||
- type: StorageVisualizer
|
- type: StorageVisualizer
|
||||||
state: bomb
|
state: bomb
|
||||||
|
state_open: bomb_open
|
||||||
|
state_closed: bomb_door
|
||||||
|
|
||||||
# Biohazard
|
# Biohazard
|
||||||
|
|
||||||
@@ -73,6 +81,8 @@
|
|||||||
visuals:
|
visuals:
|
||||||
- type: StorageVisualizer
|
- type: StorageVisualizer
|
||||||
state: bio
|
state: bio
|
||||||
|
state_open: bio_sec_open
|
||||||
|
false: bio_sec_door
|
||||||
|
|
||||||
# Virology variant
|
# Virology variant
|
||||||
- type: entity
|
- type: entity
|
||||||
@@ -83,6 +93,8 @@
|
|||||||
visuals:
|
visuals:
|
||||||
- type: StorageVisualizer
|
- type: StorageVisualizer
|
||||||
state: bio_viro
|
state: bio_viro
|
||||||
|
state_open: bio_viro_open
|
||||||
|
state_closed: bio_viro_door
|
||||||
|
|
||||||
# Security variant
|
# Security variant
|
||||||
- type: entity
|
- type: entity
|
||||||
@@ -93,6 +105,8 @@
|
|||||||
visuals:
|
visuals:
|
||||||
- type: StorageVisualizer
|
- type: StorageVisualizer
|
||||||
state: bio_sec
|
state: bio_sec
|
||||||
|
state_open: bio_sec_open
|
||||||
|
state_closed: bio_sec_door
|
||||||
|
|
||||||
# Janitor variant
|
# Janitor variant
|
||||||
- type: entity
|
- type: entity
|
||||||
@@ -103,11 +117,13 @@
|
|||||||
visuals:
|
visuals:
|
||||||
- type: StorageVisualizer
|
- type: StorageVisualizer
|
||||||
state: bio_jan
|
state: bio_jan
|
||||||
|
state_open: bio_jan_open
|
||||||
|
state_closed: bio_jan_door
|
||||||
|
|
||||||
# Maintenance closet
|
# Maintenance closet
|
||||||
- type: entity
|
- type: entity
|
||||||
id: ClosetMaintenance
|
id: ClosetMaintenance
|
||||||
name: maintenance closet
|
name: maintenance closet
|
||||||
parent: ClosetBase
|
parent: ClosetBase
|
||||||
description: It's a storage unit.
|
description: It's a storage unit.
|
||||||
components:
|
components:
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
visuals:
|
visuals:
|
||||||
- type: StorageVisualizer
|
- type: StorageVisualizer
|
||||||
state: generic
|
state: generic
|
||||||
|
state_open: generic_open
|
||||||
state_closed: blue_door
|
state_closed: blue_door
|
||||||
|
|
||||||
# Pink wardrobe
|
# Pink wardrobe
|
||||||
@@ -29,6 +30,7 @@
|
|||||||
visuals:
|
visuals:
|
||||||
- type: StorageVisualizer
|
- type: StorageVisualizer
|
||||||
state: generic
|
state: generic
|
||||||
|
state_open: generic_open
|
||||||
state_closed: pink_door
|
state_closed: pink_door
|
||||||
|
|
||||||
# Black wardrobe
|
# Black wardrobe
|
||||||
@@ -41,6 +43,7 @@
|
|||||||
visuals:
|
visuals:
|
||||||
- type: StorageVisualizer
|
- type: StorageVisualizer
|
||||||
state: generic
|
state: generic
|
||||||
|
state_open: generic_open
|
||||||
state_closed: black_door
|
state_closed: black_door
|
||||||
|
|
||||||
# Green wardrobe
|
# Green wardrobe
|
||||||
@@ -53,6 +56,7 @@
|
|||||||
visuals:
|
visuals:
|
||||||
- type: StorageVisualizer
|
- type: StorageVisualizer
|
||||||
state: generic
|
state: generic
|
||||||
|
state_open: generic_open
|
||||||
state_closed: green_door
|
state_closed: green_door
|
||||||
|
|
||||||
# Prison wardrobe
|
# Prison wardrobe
|
||||||
@@ -65,6 +69,7 @@
|
|||||||
visuals:
|
visuals:
|
||||||
- type: StorageVisualizer
|
- type: StorageVisualizer
|
||||||
state: generic
|
state: generic
|
||||||
|
state_open: generic_open
|
||||||
state_closed: orange_door
|
state_closed: orange_door
|
||||||
|
|
||||||
# Yellow wardrobe
|
# Yellow wardrobe
|
||||||
@@ -77,6 +82,7 @@
|
|||||||
visuals:
|
visuals:
|
||||||
- type: StorageVisualizer
|
- type: StorageVisualizer
|
||||||
state: generic
|
state: generic
|
||||||
|
state_open: generic_open
|
||||||
state_closed: yellow_door
|
state_closed: yellow_door
|
||||||
|
|
||||||
# White wardrobe
|
# White wardrobe
|
||||||
@@ -89,6 +95,7 @@
|
|||||||
visuals:
|
visuals:
|
||||||
- type: StorageVisualizer
|
- type: StorageVisualizer
|
||||||
state: generic
|
state: generic
|
||||||
|
state_open: generic_open
|
||||||
state_closed: white_door
|
state_closed: white_door
|
||||||
|
|
||||||
# Grey wardrobe
|
# Grey wardrobe
|
||||||
@@ -101,6 +108,7 @@
|
|||||||
visuals:
|
visuals:
|
||||||
- type: StorageVisualizer
|
- type: StorageVisualizer
|
||||||
state: generic
|
state: generic
|
||||||
|
state_open: generic_open
|
||||||
state_closed: grey_door
|
state_closed: grey_door
|
||||||
|
|
||||||
# Mixed wardrobe
|
# Mixed wardrobe
|
||||||
@@ -113,6 +121,7 @@
|
|||||||
visuals:
|
visuals:
|
||||||
- type: StorageVisualizer
|
- type: StorageVisualizer
|
||||||
state: generic
|
state: generic
|
||||||
|
state_open: generic_open
|
||||||
state_closed: mixed_door
|
state_closed: mixed_door
|
||||||
|
|
||||||
# Jobs
|
# Jobs
|
||||||
@@ -126,6 +135,7 @@
|
|||||||
visuals:
|
visuals:
|
||||||
- type: StorageVisualizer
|
- type: StorageVisualizer
|
||||||
state: generic
|
state: generic
|
||||||
|
state_open: generic_open
|
||||||
state_closed: red_door
|
state_closed: red_door
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
@@ -137,6 +147,7 @@
|
|||||||
visuals:
|
visuals:
|
||||||
- type: StorageVisualizer
|
- type: StorageVisualizer
|
||||||
state: generic
|
state: generic
|
||||||
|
state_open: generic_open
|
||||||
state_closed: atmos_wardrobe_door
|
state_closed: atmos_wardrobe_door
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
|
|||||||
@@ -73,9 +73,9 @@
|
|||||||
Steel: 200
|
Steel: 200
|
||||||
|
|
||||||
- type: latheRecipe
|
- type: latheRecipe
|
||||||
id: BodyBag_Item
|
id: BodyBag_Folded
|
||||||
icon: Objects/Specific/Medical/Morgue/bodybags.rsi/item.png
|
icon: Objects/Specific/Medical/Morgue/bodybags.rsi/bag_folded.png
|
||||||
result: BodyBag_Item
|
result: BodyBag_Folded
|
||||||
completetime: 300
|
completetime: 300
|
||||||
materials:
|
materials:
|
||||||
Plastic: 200
|
Plastic: 200
|
||||||
|
|||||||
3
Resources/Textures/Interface/VerbIcons/fold.svg
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg width="100%" height="100%" viewBox="0 0 86 86" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:1.5;"><path d="M41.143,26.614l0,46.157l-26.16,-12.572l0,-46.156l26.16,12.571Z" style="fill:#fff;"/><path d="M41.143,26.85l-14.316,-7.116l-7.741,42.437l22.057,10.836l26.161,-12.572l0,-46.156l-26.161,12.571Zm20.827,-4.091l-18.517,8.899c-1.482,0.712 -3.211,0.7 -4.684,-0.032l-7.968,-3.96l-5.745,31.496l16.113,7.915l20.801,-9.996l0,-34.322Z" style="fill:#fff;"/><path d="M28.829,12.184c3.437,-2.078 7.233,-3.232 11.223,-3.232c3.562,0 6.968,0.919 10.103,2.594" style="fill:none;stroke:#fff;stroke-width:5.33px;"/><path d="M50.985,6.201l2.653,6.831l-6.967,2.706" style="fill:none;stroke:#fff;stroke-width:4px;stroke-linejoin:miter;"/></svg>
|
||||||
|
After Width: | Height: | Size: 1.1 KiB |
BIN
Resources/Textures/Interface/VerbIcons/fold.svg.192dpi.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
@@ -0,0 +1,2 @@
|
|||||||
|
sample:
|
||||||
|
filter: true
|
||||||
|
Before Width: | Height: | Size: 227 B After Width: | Height: | Size: 227 B |
@@ -11,7 +11,7 @@
|
|||||||
"name": "bag"
|
"name": "bag"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "item"
|
"name": "bag_folded"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "label_overlay"
|
"name": "label_overlay"
|
||||||
|
|||||||
|
After Width: | Height: | Size: 326 B |
|
After Width: | Height: | Size: 490 B |
|
After Width: | Height: | Size: 403 B |
|
After Width: | Height: | Size: 449 B |
|
After Width: | Height: | Size: 618 B |
|
After Width: | Height: | Size: 582 B |
@@ -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"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 402 B |
|
After Width: | Height: | Size: 565 B |
|
After Width: | Height: | Size: 401 B |