diff --git a/Content.Client/GameObjects/Components/Morgue/BodyBagVisualizer.cs b/Content.Client/GameObjects/Components/Morgue/BodyBagVisualizer.cs new file mode 100644 index 0000000000..a8aa86b777 --- /dev/null +++ b/Content.Client/GameObjects/Components/Morgue/BodyBagVisualizer.cs @@ -0,0 +1,30 @@ +#nullable enable +using Content.Shared.GameObjects.Components.Morgue; +using Robust.Client.GameObjects; +using Robust.Client.Interfaces.GameObjects.Components; + +namespace Content.Client.GameObjects.Components.Morgue +{ + public sealed class BodyBagVisualizer : AppearanceVisualizer + { + public override void OnChangeData(AppearanceComponent component) + { + base.OnChangeData(component); + + if (!component.Owner.TryGetComponent(out ISpriteComponent? sprite)) + { + return; + } + + if (component.TryGetData(BodyBagVisuals.Label, out bool labelVal)) + { + sprite.LayerSetVisible(BodyBagVisualLayers.Label, labelVal); + } + } + } + + public enum BodyBagVisualLayers + { + Label, + } +} diff --git a/Content.Client/GameObjects/Components/Morgue/CrematoriumVisualizer.cs b/Content.Client/GameObjects/Components/Morgue/CrematoriumVisualizer.cs new file mode 100644 index 0000000000..b7b5b9d8c8 --- /dev/null +++ b/Content.Client/GameObjects/Components/Morgue/CrematoriumVisualizer.cs @@ -0,0 +1,75 @@ +#nullable enable +using Content.Shared.GameObjects.Components.Morgue; +using Robust.Client.GameObjects; +using Robust.Client.Interfaces.GameObjects.Components; +using Robust.Shared.Utility; +using YamlDotNet.RepresentationModel; + +namespace Content.Client.GameObjects.Components.Storage +{ + public sealed class CrematoriumVisualizer : AppearanceVisualizer + { + private string _stateOpen = ""; + private string _stateClosed = ""; + + private string _lightContents = ""; + private string _lightBurning = ""; + + public override void LoadData(YamlMappingNode node) + { + base.LoadData(node); + + if (node.TryGetNode("state_open", out var child)) + { + _stateOpen = child.AsString(); + } + if (node.TryGetNode("state_closed", out child)) + { + _stateClosed = child.AsString(); + } + + if (node.TryGetNode("light_contents", out child)) + { + _lightContents = child.AsString(); + } + if (node.TryGetNode("light_burning", out child)) + { + _lightBurning = child.AsString(); + } + } + + public override void OnChangeData(AppearanceComponent component) + { + base.OnChangeData(component); + + if (!component.Owner.TryGetComponent(out ISpriteComponent? sprite)) return; + + sprite.LayerSetState( + CrematoriumVisualLayers.Base, + component.GetData(MorgueVisuals.Open) + ? _stateOpen + : _stateClosed + ); + + var lightState = ""; + if (component.TryGetData(MorgueVisuals.HasContents, out bool hasContents) && hasContents) lightState = _lightContents; + if (component.TryGetData(CrematoriumVisuals.Burning, out bool isBurning) && isBurning) lightState = _lightBurning; + + if (!string.IsNullOrEmpty(lightState)) + { + sprite.LayerSetState(CrematoriumVisualLayers.Light, lightState); + sprite.LayerSetVisible(CrematoriumVisualLayers.Light, true); + } + else + { + sprite.LayerSetVisible(CrematoriumVisualLayers.Light, false); + } + } + } + + public enum CrematoriumVisualLayers + { + Base, + Light, + } +} diff --git a/Content.Client/GameObjects/Components/Morgue/MorgueVisualizer.cs b/Content.Client/GameObjects/Components/Morgue/MorgueVisualizer.cs new file mode 100644 index 0000000000..9f0a10305e --- /dev/null +++ b/Content.Client/GameObjects/Components/Morgue/MorgueVisualizer.cs @@ -0,0 +1,81 @@ +#nullable enable +using Content.Shared.GameObjects.Components.Morgue; +using Robust.Client.GameObjects; +using Robust.Client.Interfaces.GameObjects.Components; +using Robust.Shared.Utility; +using YamlDotNet.RepresentationModel; + +namespace Content.Client.GameObjects.Components.Storage +{ + public sealed class MorgueVisualizer : AppearanceVisualizer + { + private string _stateOpen = ""; + private string _stateClosed = ""; + + private string _lightContents = ""; + private string _lightMob = ""; + private string _lightSoul = ""; + + public override void LoadData(YamlMappingNode node) + { + base.LoadData(node); + + if (node.TryGetNode("state_open", out var child)) + { + _stateOpen = child.AsString(); + } + if (node.TryGetNode("state_closed", out child)) + { + _stateClosed = child.AsString(); + } + + if (node.TryGetNode("light_contents", out child)) + { + _lightContents = child.AsString(); + } + if (node.TryGetNode("light_mob", out child)) + { + _lightMob = child.AsString(); + } + if (node.TryGetNode("light_soul", out child)) + { + _lightSoul = child.AsString(); + } + } + + public override void OnChangeData(AppearanceComponent component) + { + base.OnChangeData(component); + + if (!component.Owner.TryGetComponent(out ISpriteComponent? sprite)) return; + + sprite.LayerSetState( + MorgueVisualLayers.Base, + component.GetData(MorgueVisuals.Open) + ? _stateOpen + : _stateClosed + ); + + var lightState = ""; + if (component.TryGetData(MorgueVisuals.HasContents, out bool hasContents) && hasContents) lightState = _lightContents; + if (component.TryGetData(MorgueVisuals.HasMob, out bool hasMob) && hasMob) lightState = _lightMob; + if (component.TryGetData(MorgueVisuals.HasSoul, out bool hasSoul) && hasSoul) lightState = _lightSoul; + + if (!string.IsNullOrEmpty(lightState)) + { + sprite.LayerSetState(MorgueVisualLayers.Light, lightState); + sprite.LayerSetVisible(MorgueVisualLayers.Light, true); + } + else + { + sprite.LayerSetVisible(MorgueVisualLayers.Light, false); + } + } + } + + public enum MorgueVisualLayers + { + Base, + Light, + } +} diff --git a/Content.Client/GameObjects/Components/Storage/StorageVisualizer.cs b/Content.Client/GameObjects/Components/Storage/StorageVisualizer.cs index 926d4e5c7a..e47c035bba 100644 --- a/Content.Client/GameObjects/Components/Storage/StorageVisualizer.cs +++ b/Content.Client/GameObjects/Components/Storage/StorageVisualizer.cs @@ -1,4 +1,4 @@ -using Content.Shared.GameObjects.Components.Storage; +using Content.Shared.GameObjects.Components.Storage; using Robust.Client.GameObjects; using Robust.Client.Interfaces.GameObjects.Components; using Robust.Shared.Interfaces.GameObjects; @@ -74,9 +74,12 @@ namespace Content.Client.GameObjects.Components.Storage } } - if (component.TryGetData(StorageVisuals.Welded, out bool weldedVal)) + if (component.TryGetData(StorageVisuals.CanWeld, out bool canWeld) && canWeld) { - sprite.LayerSetVisible(StorageVisualLayers.Welded, weldedVal); + if (component.TryGetData(StorageVisuals.Welded, out bool weldedVal)) + { + sprite.LayerSetVisible(StorageVisualLayers.Welded, weldedVal); + } } } } diff --git a/Content.Client/IgnoredComponents.cs b/Content.Client/IgnoredComponents.cs index ae8bd8da7c..78b885b449 100644 --- a/Content.Client/IgnoredComponents.cs +++ b/Content.Client/IgnoredComponents.cs @@ -206,7 +206,11 @@ "ParticleAcceleratorEmitter", "ParticleAcceleratorEndCap", "ParticleAcceleratorFuelChamber", - "ParticleAcceleratorPowerBox" + "ParticleAcceleratorPowerBox", + "BodyBagEntityStorage", + "MorgueEntityStorage", + "MorgueTray", + "CrematoriumEntityStorage", }; } } diff --git a/Content.Server/GameObjects/Components/Items/Storage/CursedEntityStorageComponent.cs b/Content.Server/GameObjects/Components/Items/Storage/CursedEntityStorageComponent.cs index f3068de5ce..8f8f1c4eee 100644 --- a/Content.Server/GameObjects/Components/Items/Storage/CursedEntityStorageComponent.cs +++ b/Content.Server/GameObjects/Components/Items/Storage/CursedEntityStorageComponent.cs @@ -22,7 +22,7 @@ namespace Content.Server.GameObjects.Components.Items.Storage public override string Name => "CursedEntityStorage"; - public override void CloseStorage() + protected override void CloseStorage() { base.CloseStorage(); @@ -41,7 +41,7 @@ namespace Content.Server.GameObjects.Components.Items.Storage var locker = lockerEnt.GetComponent(); if(locker.Open) - locker.CloseStorage(); + locker.TryCloseStorage(Owner); foreach (var entity in Contents.ContainedEntities.ToArray()) { diff --git a/Content.Server/GameObjects/Components/Items/Storage/EntityStorageComponent.cs b/Content.Server/GameObjects/Components/Items/Storage/EntityStorageComponent.cs index da88408b93..a99cb7e586 100644 --- a/Content.Server/GameObjects/Components/Items/Storage/EntityStorageComponent.cs +++ b/Content.Server/GameObjects/Components/Items/Storage/EntityStorageComponent.cs @@ -47,11 +47,15 @@ namespace Content.Server.GameObjects.Components.Items.Storage [ViewVariables] private bool _isCollidableWhenOpen; [ViewVariables] - private IEntityQuery _entityQuery; + protected IEntityQuery EntityQuery; + private bool _showContents; private bool _occludesLight; private bool _open; + private bool _canWeldShut; private bool _isWeldedShut; + private string _closeSound = "/Audio/Machines/closetclose.ogg"; + private string _openSound = "/Audio/Machines/closetopen.ogg"; [ViewVariables] protected Container Contents; @@ -104,14 +108,24 @@ namespace Content.Server.GameObjects.Components.Items.Storage } [ViewVariables(VVAccess.ReadWrite)] - public bool CanWeldShut { get; set; } + public bool CanWeldShut { + get => _canWeldShut; + set + { + _canWeldShut = value; + if (Owner.TryGetComponent(out AppearanceComponent appearance)) + { + appearance.SetData(StorageVisuals.CanWeld, value); + } + } + } /// public override void Initialize() { base.Initialize(); Contents = ContainerManagerComponent.Ensure(nameof(EntityStorageComponent), Owner); - _entityQuery = new IntersectingEntityQuery(Owner); + EntityQuery = new IntersectingEntityQuery(Owner); Contents.ShowContents = _showContents; Contents.OccludesLight = _occludesLight; @@ -134,6 +148,8 @@ namespace Content.Server.GameObjects.Components.Items.Storage serializer.DataField(ref _open, "open", false); serializer.DataField(this, a => a.IsWeldedShut, "IsWeldedShut", false); serializer.DataField(this, a => a.CanWeldShut, "CanWeldShut", true); + serializer.DataField(this, x => _closeSound, "closeSound", "/Audio/Machines/closetclose.ogg"); + serializer.DataField(this, x => _openSound, "openSound", "/Audio/Machines/closetopen.ogg"); } public virtual void Activate(ActivateEventArgs eventArgs) @@ -141,17 +157,26 @@ namespace Content.Server.GameObjects.Components.Items.Storage ToggleOpen(eventArgs.User); } - private void ToggleOpen(IEntity user) + public virtual bool CanOpen(IEntity user, bool silent = false) { if (IsWeldedShut) { - Owner.PopupMessage(user, Loc.GetString("It's welded completely shut!")); - return; + if(!silent) Owner.PopupMessage(user, Loc.GetString("It's welded completely shut!")); + return false; } + return true; + } + public virtual bool CanClose(IEntity user, bool silent = false) + { + return true; + } + + private void ToggleOpen(IEntity user) + { if (Open) { - CloseStorage(); + TryCloseStorage(user); } else { @@ -159,10 +184,10 @@ namespace Content.Server.GameObjects.Components.Items.Storage } } - public virtual void CloseStorage() + protected virtual void CloseStorage() { Open = false; - var entities = Owner.EntityManager.GetEntities(_entityQuery); + var entities = Owner.EntityManager.GetEntities(EntityQuery); var count = 0; foreach (var entity in entities) { @@ -187,16 +212,16 @@ namespace Content.Server.GameObjects.Components.Items.Storage } ModifyComponents(); - EntitySystem.Get().PlayFromEntity("/Audio/Machines/closetclose.ogg", Owner); + EntitySystem.Get().PlayFromEntity(_closeSound, Owner); _lastInternalOpenAttempt = default; } - private void OpenStorage() + protected virtual void OpenStorage() { Open = true; EmptyContents(); ModifyComponents(); - EntitySystem.Get().PlayFromEntity("/Audio/Machines/closetopen.ogg", Owner); + EntitySystem.Get().PlayFromEntity(_openSound, Owner); } private void ModifyComponents() @@ -224,8 +249,9 @@ namespace Content.Server.GameObjects.Components.Items.Storage } } - private bool AddToContents(IEntity entity) + protected virtual bool AddToContents(IEntity entity) { + if (entity == Owner) return false; if (entity.TryGetComponent(out IPhysicsComponent entityPhysicsComponent)) { if(MaxSize < entityPhysicsComponent.WorldAABB.Size.X @@ -247,12 +273,18 @@ namespace Content.Server.GameObjects.Components.Items.Storage return false; } + public virtual Vector2 ContentsDumpPosition() + { + return Owner.Transform.WorldPosition; + } + private void EmptyContents() { foreach (var contained in Contents.ContainedEntities.ToArray()) { if(Contents.Remove(contained)) { + contained.Transform.WorldPosition = ContentsDumpPosition(); if (contained.TryGetComponent(out var physics)) { physics.CanCollide = true; @@ -284,14 +316,18 @@ namespace Content.Server.GameObjects.Components.Items.Storage } } - protected virtual void TryOpenStorage(IEntity user) + public virtual bool TryOpenStorage(IEntity user) { - if (IsWeldedShut) - { - Owner.PopupMessage(user, Loc.GetString("It's welded completely shut!")); - return; - } + if (!CanOpen(user)) return false; OpenStorage(); + return true; + } + + public virtual bool TryCloseStorage(IEntity user) + { + if (!CanClose(user)) return false; + CloseStorage(); + return true; } /// diff --git a/Content.Server/GameObjects/Components/Items/Storage/SecureEntityStorageComponent.cs b/Content.Server/GameObjects/Components/Items/Storage/SecureEntityStorageComponent.cs index 9c37fd850c..1f7228d25a 100644 --- a/Content.Server/GameObjects/Components/Items/Storage/SecureEntityStorageComponent.cs +++ b/Content.Server/GameObjects/Components/Items/Storage/SecureEntityStorageComponent.cs @@ -69,15 +69,14 @@ namespace Content.Server.GameObjects.Components.Items.Storage base.Activate(eventArgs); } - protected override void TryOpenStorage(IEntity user) + public override bool CanOpen(IEntity user, bool silent = false) { if (Locked) { Owner.PopupMessage(user, "It's locked!"); - return; + return false; } - - base.TryOpenStorage(user); + return base.CanOpen(user, silent); } protected override void OpenVerbGetData(IEntity user, EntityStorageComponent component, VerbData data) diff --git a/Content.Server/GameObjects/Components/Morgue/BodyBagEntityStorageComponent.cs b/Content.Server/GameObjects/Components/Morgue/BodyBagEntityStorageComponent.cs new file mode 100644 index 0000000000..ef3e1bb8d3 --- /dev/null +++ b/Content.Server/GameObjects/Components/Morgue/BodyBagEntityStorageComponent.cs @@ -0,0 +1,123 @@ +#nullable enable +using Content.Server.GameObjects.Components.GUI; +using Content.Server.GameObjects.Components.Items.Storage; +using Content.Server.GameObjects.Components.Paper; +using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects.Components.Items; +using Content.Shared.GameObjects.Components.Body; +using Content.Shared.GameObjects.Components.Morgue; +using Content.Shared.GameObjects.EntitySystems; +using Content.Shared.GameObjects.Verbs; +using Content.Shared.Interfaces; +using Content.Shared.Interfaces.GameObjects.Components; +using Robust.Server.GameObjects; +using Robust.Server.GameObjects.Components.Container; +using Robust.Shared.GameObjects; +using Robust.Shared.GameObjects.ComponentDependencies; +using Robust.Shared.GameObjects.Systems; +using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.Localization; +using Robust.Shared.Utility; +using Robust.Shared.ViewVariables; +using System.Threading.Tasks; + +namespace Content.Server.GameObjects.Components.Morgue +{ + [RegisterComponent] + [ComponentReference(typeof(EntityStorageComponent))] + [ComponentReference(typeof(IActivate))] + [ComponentReference(typeof(IStorageComponent))] + public class BodyBagEntityStorageComponent : EntityStorageComponent, IExamine, IInteractUsing + { + public override string Name => "BodyBagEntityStorage"; + + [ViewVariables] + [ComponentDependency] private AppearanceComponent? _appearance = null; + + [ViewVariables] public ContainerSlot? LabelContainer { get; private set; } + + public override void Initialize() + { + base.Initialize(); + _appearance?.SetData(BodyBagVisuals.Label, false); + LabelContainer = ContainerManagerComponent.Ensure("body_bag_label", Owner, out _); + } + + protected override bool AddToContents(IEntity entity) + { + if (entity.HasComponent() && !EntitySystem.Get().IsDown(entity)) return false; + return base.AddToContents(entity); + } + + void IExamine.Examine(FormattedMessage message, bool inDetailsRange) + { + if (inDetailsRange) + { + if (LabelContainer?.ContainedEntity != null && LabelContainer.ContainedEntity.TryGetComponent(out var paper)) + { + message.AddText(Loc.GetString("The label reads: {0}", paper.Content)); + } + } + } + + async Task IInteractUsing.InteractUsing(InteractUsingEventArgs eventArgs) + { + if (LabelContainer == null) return false; + + if (LabelContainer.ContainedEntity != null) + { + Owner.PopupMessage(eventArgs.User, Loc.GetString("There's already a label attached.")); + return false; + } + + var handsComponent = eventArgs.User.GetComponent(); + if (!handsComponent.Drop(eventArgs.Using, LabelContainer)) + { + return false; + } + + _appearance?.SetData(BodyBagVisuals.Label, true); + + Owner.PopupMessage(eventArgs.User, Loc.GetString("You attach {0:theName} to the body bag.", eventArgs.Using)); + return true; + } + + public void RemoveLabel(IEntity user) + { + if (LabelContainer == null) return; + + if (user.TryGetComponent(out HandsComponent? hands)) + { + hands.PutInHandOrDrop(LabelContainer.ContainedEntity.GetComponent()); + _appearance?.SetData(BodyBagVisuals.Label, false); + } + else if (LabelContainer.Remove(LabelContainer.ContainedEntity)) + { + LabelContainer.ContainedEntity.Transform.Coordinates = Owner.Transform.Coordinates; + _appearance?.SetData(BodyBagVisuals.Label, false); + } + } + + + [Verb] + private sealed class RemoveLabelVerb : Verb + { + protected override void GetData(IEntity user, BodyBagEntityStorageComponent component, VerbData data) + { + if (!ActionBlockerSystem.CanInteract(user) || component.LabelContainer?.ContainedEntity == null) + { + data.Visibility = VerbVisibility.Invisible; + return; + } + + data.Text = Loc.GetString("Remove label"); + } + + /// + protected override void Activate(IEntity user, BodyBagEntityStorageComponent component) + { + component.RemoveLabel(user); + } + } + } +} diff --git a/Content.Server/GameObjects/Components/Morgue/CrematoriumEntityStorageComponent.cs b/Content.Server/GameObjects/Components/Morgue/CrematoriumEntityStorageComponent.cs new file mode 100644 index 0000000000..761c64561c --- /dev/null +++ b/Content.Server/GameObjects/Components/Morgue/CrematoriumEntityStorageComponent.cs @@ -0,0 +1,104 @@ +#nullable enable +using Content.Server.GameObjects.Components.Items.Storage; +using Content.Shared.GameObjects.Components.Morgue; +using Content.Shared.GameObjects.EntitySystems; +using Content.Shared.GameObjects.Verbs; +using Content.Shared.Interfaces.GameObjects.Components; +using Robust.Server.GameObjects.EntitySystems; +using Robust.Shared.GameObjects; +using Robust.Shared.GameObjects.Systems; +using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.Localization; +using Robust.Shared.Timers; +using Robust.Shared.Utility; +using Robust.Shared.ViewVariables; + +namespace Content.Server.GameObjects.Components.Morgue +{ + [RegisterComponent] + [ComponentReference(typeof(MorgueEntityStorageComponent))] + [ComponentReference(typeof(EntityStorageComponent))] + [ComponentReference(typeof(IActivate))] + [ComponentReference(typeof(IStorageComponent))] + public class CrematoriumEntityStorageComponent : MorgueEntityStorageComponent, IExamine + { + public override string Name => "CrematoriumEntityStorage"; + + [ViewVariables] + public bool Cooking { get; private set; } + + [ViewVariables(VVAccess.ReadWrite)] + private int _burnMilis = 3000; + + void IExamine.Examine(FormattedMessage message, bool inDetailsRange) + { + if (Appearance == null) return; + + if (inDetailsRange) + { + if (Appearance.TryGetData(CrematoriumVisuals.Burning, out bool isBurning) && isBurning) + { + message.AddMarkup(Loc.GetString("The {0:theName} is [color=red]active[/color]!\n", Owner)); + } + + if (Appearance.TryGetData(MorgueVisuals.HasContents, out bool hasContents) && hasContents) + { + message.AddMarkup(Loc.GetString("The content light is [color=green]on[/color], there's something in here.")); + } + else + { + message.AddText(Loc.GetString("The content light is off, there's nothing in here.")); + } + } + } + + public void Cremate() + { + if (Cooking) return; + + Appearance?.SetData(CrematoriumVisuals.Burning, true); + Cooking = true; + + Timer.Spawn(_burnMilis, () => + { + Appearance?.SetData(CrematoriumVisuals.Burning, false); + Cooking = false; + + for (var i = Contents.ContainedEntities.Count - 1; i >= 0; i--) + { + var item = Contents.ContainedEntities[i]; + Contents.Remove(item); + item.Delete(); + } + + var ash = Owner.EntityManager.SpawnEntity("Ash", Owner.Transform.Coordinates); + Contents.Insert(ash); + + TryOpenStorage(Owner); + + EntitySystem.Get().PlayFromEntity("/Audio/Machines/ding.ogg", Owner); + }); + } + + [Verb] + private sealed class CremateVerb : Verb + { + protected override void GetData(IEntity user, CrematoriumEntityStorageComponent component, VerbData data) + { + if (!ActionBlockerSystem.CanInteract(user) || component.Cooking) + { + data.Visibility = VerbVisibility.Invisible; + return; + } + + data.Text = Loc.GetString("Cremate"); + } + + /// + protected override void Activate(IEntity user, CrematoriumEntityStorageComponent component) + { + component.Cremate(); + } + } + } +} diff --git a/Content.Server/GameObjects/Components/Morgue/MorgueEntityStorageComponent.cs b/Content.Server/GameObjects/Components/Morgue/MorgueEntityStorageComponent.cs new file mode 100644 index 0000000000..2dd2b6673f --- /dev/null +++ b/Content.Server/GameObjects/Components/Morgue/MorgueEntityStorageComponent.cs @@ -0,0 +1,178 @@ +#nullable enable +using Content.Server.GameObjects.Components.Items.Storage; +using Content.Server.GameObjects.EntitySystems; +using Content.Shared.GameObjects.Components.Body; +using Content.Shared.GameObjects.Components.Morgue; +using Content.Shared.GameObjects.EntitySystems; +using Content.Shared.Interfaces; +using Content.Shared.Interfaces.GameObjects.Components; +using Content.Shared.Physics; +using Content.Shared.Utility; +using Robust.Server.GameObjects; +using Robust.Server.GameObjects.Components.Container; +using Robust.Server.GameObjects.EntitySystems; +using Robust.Shared.GameObjects; +using Robust.Shared.GameObjects.ComponentDependencies; +using Robust.Shared.GameObjects.Systems; +using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.Localization; +using Robust.Shared.Maths; +using Robust.Shared.Serialization; +using Robust.Shared.Utility; +using Robust.Shared.ViewVariables; + +namespace Content.Server.GameObjects.Components.Morgue +{ + [RegisterComponent] + [ComponentReference(typeof(EntityStorageComponent))] + [ComponentReference(typeof(IActivate))] + [ComponentReference(typeof(IStorageComponent))] + public class MorgueEntityStorageComponent : EntityStorageComponent, IExamine + { + public override string Name => "MorgueEntityStorage"; + + [ViewVariables(VVAccess.ReadWrite)] + private string? _trayPrototypeId; + + [ViewVariables] + private IEntity? _tray; + + [ViewVariables] + public ContainerSlot? TrayContainer { get; private set; } + + [ViewVariables(VVAccess.ReadWrite)] + public bool DoSoulBeep = true; + + [ViewVariables] + [ComponentDependency] protected readonly AppearanceComponent? Appearance = null; + + + public override void Initialize() + { + base.Initialize(); + Appearance?.SetData(MorgueVisuals.Open, false); + TrayContainer = ContainerManagerComponent.Ensure("morgue_tray", Owner, out _); + } + + /// + public override void ExposeData(ObjectSerializer serializer) + { + base.ExposeData(serializer); + serializer.DataField(ref _trayPrototypeId, "trayPrototype", ""); + serializer.DataField(ref DoSoulBeep, "doSoulBeep", true); + } + + public override Vector2 ContentsDumpPosition() + { + if (_tray != null) return _tray.Transform.WorldPosition; + return base.ContentsDumpPosition(); + } + + protected override bool AddToContents(IEntity entity) + { + if (entity.HasComponent() && !EntitySystem.Get().IsDown(entity)) return false; + return base.AddToContents(entity); + } + + public override bool CanOpen(IEntity user, bool silent = false) + { + if (!Owner.InRangeUnobstructed( + Owner.Transform.Coordinates.Offset(Owner.Transform.LocalRotation.GetCardinalDir()), + collisionMask: CollisionGroup.Impassable | CollisionGroup.VaultImpassable + )) + { + if(!silent) Owner.PopupMessage(user, Loc.GetString("There's no room for the tray to extend!")); + return false; + } + + return base.CanOpen(user, silent); + } + + protected override void OpenStorage() + { + Appearance?.SetData(MorgueVisuals.Open, true); + Appearance?.SetData(MorgueVisuals.HasContents, false); + Appearance?.SetData(MorgueVisuals.HasMob, false); + Appearance?.SetData(MorgueVisuals.HasSoul, false); + + if (_tray == null) + { + _tray = Owner.EntityManager.SpawnEntity(_trayPrototypeId, Owner.Transform.Coordinates); + var trayComp = _tray.EnsureComponent(); + trayComp.Morgue = Owner; + EntityQuery = new IntersectingEntityQuery(_tray); + } + else + { + TrayContainer?.Remove(_tray); + } + + _tray.Transform.WorldPosition = Owner.Transform.WorldPosition + Owner.Transform.LocalRotation.GetCardinalDir().ToVec(); + _tray.Transform.AttachParent(Owner); + + base.OpenStorage(); + } + + private void CheckContents() + { + var count = 0; + var hasMob = false; + var hasSoul = false; + foreach (var entity in Contents.ContainedEntities) + { + count++; + if (!hasMob && entity.HasComponent()) hasMob = true; + if (!hasSoul && entity.TryGetComponent(out var actor) && actor.playerSession != null) hasSoul = true; + } + Appearance?.SetData(MorgueVisuals.HasContents, count > 0); + Appearance?.SetData(MorgueVisuals.HasMob, hasMob); + Appearance?.SetData(MorgueVisuals.HasSoul, hasSoul); + } + + protected override void CloseStorage() + { + base.CloseStorage(); + + Appearance?.SetData(MorgueVisuals.Open, false); + CheckContents(); + + if (_tray != null) + { + TrayContainer?.Insert(_tray); + } + } + + //Called every 10 seconds + public void Update() + { + CheckContents(); + + if(DoSoulBeep && Appearance !=null && Appearance.TryGetData(MorgueVisuals.HasSoul, out bool hasSoul) && hasSoul) + EntitySystem.Get().PlayFromEntity("/Audio/Weapons/Guns/EmptyAlarm/smg_empty_alarm.ogg", Owner); + } + + void IExamine.Examine(FormattedMessage message, bool inDetailsRange) + { + if (Appearance == null) return; + + if (inDetailsRange) + { + if (Appearance.TryGetData(MorgueVisuals.HasSoul, out bool hasSoul) && hasSoul) + { + message.AddMarkup(Loc.GetString("The content light is [color=green]green[/color], this body might still be saved!")); + } + else if (Appearance.TryGetData(MorgueVisuals.HasMob, out bool hasMob) && hasMob) + { + message.AddMarkup(Loc.GetString("The content light is [color=red]red[/color], there's a dead body in here! Oh wait...")); + } + else if (Appearance.TryGetData(MorgueVisuals.HasContents, out bool hasContents) && hasContents) + { + message.AddMarkup(Loc.GetString("The content light is [color=yellow]yellow[/color], there's something in here.")); + } else + { + message.AddMarkup(Loc.GetString("The content light is off, there's nothing in here.")); + } + } + } + } +} diff --git a/Content.Server/GameObjects/Components/Morgue/MorgueTrayComponent.cs b/Content.Server/GameObjects/Components/Morgue/MorgueTrayComponent.cs new file mode 100644 index 0000000000..7e314b7c37 --- /dev/null +++ b/Content.Server/GameObjects/Components/Morgue/MorgueTrayComponent.cs @@ -0,0 +1,29 @@ +using Content.Shared.Interfaces.GameObjects.Components; +using Robust.Shared.GameObjects; +using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.ViewVariables; + +namespace Content.Server.GameObjects.Components.Morgue +{ + [RegisterComponent] + [ComponentReference(typeof(IActivate))] + public class MorgueTrayComponent : Component, IActivate + { + public override string Name => "MorgueTray"; + + [ViewVariables] + public IEntity Morgue { get; set; } + + void IActivate.Activate(ActivateEventArgs eventArgs) + { + if(Morgue != null && !Morgue.Deleted && Morgue.TryGetComponent(out var comp)) + { + comp.Activate(new ActivateEventArgs() + { + User = eventArgs.User, + Target = Morgue + }); + } + } + } +} diff --git a/Content.Server/GameObjects/Components/Paper/PaperComponent.cs b/Content.Server/GameObjects/Components/Paper/PaperComponent.cs index 3070172259..10e3dd0c6e 100644 --- a/Content.Server/GameObjects/Components/Paper/PaperComponent.cs +++ b/Content.Server/GameObjects/Components/Paper/PaperComponent.cs @@ -16,8 +16,8 @@ namespace Content.Server.GameObjects.Components.Paper [RegisterComponent] public class PaperComponent : SharedPaperComponent, IExamine, IInteractUsing, IUse { - private string _content = ""; private PaperAction _mode; + public string Content { get; private set; } = ""; [ViewVariables] private BoundUserInterface? UserInterface => Owner.GetUIOrNull(PaperUiKey.Key); @@ -35,7 +35,7 @@ namespace Content.Server.GameObjects.Components.Paper } private void UpdateUserInterface() { - UserInterface?.SetState(new PaperBoundUserInterfaceState(_content, _mode)); + UserInterface?.SetState(new PaperBoundUserInterfaceState(Content, _mode)); } public void Examine(FormattedMessage message, bool inDetailsRange) @@ -43,7 +43,7 @@ namespace Content.Server.GameObjects.Components.Paper if (!inDetailsRange) return; - message.AddMarkup(_content); + message.AddMarkup(Content); } public bool UseEntity(UseEntityEventArgs eventArgs) @@ -63,7 +63,7 @@ namespace Content.Server.GameObjects.Components.Paper if (string.IsNullOrEmpty(msg.Text)) return; - _content += msg.Text + '\n'; + Content += msg.Text + '\n'; if (Owner.TryGetComponent(out SpriteComponent? sprite)) { diff --git a/Content.Server/GameObjects/EntitySystems/MorgueSystem.cs b/Content.Server/GameObjects/EntitySystems/MorgueSystem.cs new file mode 100644 index 0000000000..bbb18adca2 --- /dev/null +++ b/Content.Server/GameObjects/EntitySystems/MorgueSystem.cs @@ -0,0 +1,27 @@ +using Content.Server.GameObjects.Components.Morgue; +using JetBrains.Annotations; +using Robust.Shared.GameObjects.Systems; + +namespace Content.Server.GameObjects.EntitySystems +{ + [UsedImplicitly] + public class MorgueSystem : EntitySystem + { + + private float _accumulatedFrameTime; + + public override void Update(float frameTime) + { + _accumulatedFrameTime += frameTime; + + if (_accumulatedFrameTime >= 10) + { + foreach (var morgue in ComponentManager.EntityQuery()) + { + morgue.Update(); + } + _accumulatedFrameTime -= 10; + } + } + } +} diff --git a/Content.Server/GameObjects/EntitySystems/StandingStateSystem.cs b/Content.Server/GameObjects/EntitySystems/StandingStateSystem.cs index 49165efd87..74f99551c3 100644 --- a/Content.Server/GameObjects/EntitySystems/StandingStateSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/StandingStateSystem.cs @@ -61,5 +61,21 @@ namespace Content.Server.GameObjects.EntitySystems hands.Drop(heldItem.Owner, doMobChecks); } } + + //TODO: RotationState can be null and I want to burn all lifeforms in the universe for this!!! + //If you use these it's atleast slightly less painful (null is treated as false) + public bool IsStanding(IEntity entity) + { + return entity.TryGetComponent(out var appearance) + && appearance.TryGetData(RotationVisuals.RotationState, out var rotation) + && rotation == RotationState.Vertical; + } + + public bool IsDown(IEntity entity) + { + return entity.TryGetComponent(out var appearance) + && appearance.TryGetData(RotationVisuals.RotationState, out var rotation) + && rotation == RotationState.Horizontal; + } } } diff --git a/Content.Shared/GameObjects/Components/Storage/SharedMorgue.cs b/Content.Shared/GameObjects/Components/Storage/SharedMorgue.cs new file mode 100644 index 0000000000..09699d8c89 --- /dev/null +++ b/Content.Shared/GameObjects/Components/Storage/SharedMorgue.cs @@ -0,0 +1,26 @@ +using System; +using Robust.Shared.Serialization; + +namespace Content.Shared.GameObjects.Components.Morgue +{ + [Serializable, NetSerializable] + public enum MorgueVisuals + { + Open, + HasContents, + HasMob, + HasSoul, + } + + [Serializable, NetSerializable] + public enum CrematoriumVisuals + { + Burning, + } + + [Serializable, NetSerializable] + public enum BodyBagVisuals + { + Label, + } +} diff --git a/Content.Shared/GameObjects/Components/Storage/SharedStorageComponent.cs b/Content.Shared/GameObjects/Components/Storage/SharedStorageComponent.cs index 45f69c6636..2bbdb8ffe1 100644 --- a/Content.Shared/GameObjects/Components/Storage/SharedStorageComponent.cs +++ b/Content.Shared/GameObjects/Components/Storage/SharedStorageComponent.cs @@ -144,8 +144,9 @@ namespace Content.Shared.GameObjects.Components.Storage public enum StorageVisuals { Open, - CanLock, + CanWeld, Welded, + CanLock, Locked } } diff --git a/Resources/Audio/Machines/ding.ogg b/Resources/Audio/Machines/ding.ogg new file mode 100644 index 0000000000..24bce5d8d7 Binary files /dev/null and b/Resources/Audio/Machines/ding.ogg differ diff --git a/Resources/Audio/Misc/zip.ogg b/Resources/Audio/Misc/zip.ogg new file mode 100644 index 0000000000..d437d486ea Binary files /dev/null and b/Resources/Audio/Misc/zip.ogg differ diff --git a/Resources/Prototypes/Entities/Objects/Specific/medical.yml b/Resources/Prototypes/Entities/Objects/Specific/medical.yml index 578a550161..4b12c1b339 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/medical.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/medical.yml @@ -84,4 +84,4 @@ - type: Stack max: 5 count: 5 - stacktype: enum.StackType.Gauze + stacktype: enum.StackType.Gauze \ No newline at end of file diff --git a/Resources/Prototypes/Entities/Objects/Specific/morgue.yml b/Resources/Prototypes/Entities/Objects/Specific/morgue.yml new file mode 100644 index 0000000000..efbd62ae2c --- /dev/null +++ b/Resources/Prototypes/Entities/Objects/Specific/morgue.yml @@ -0,0 +1,202 @@ +- type: entity + id: BodyBag_Container + name: body bag + description: A plastic bag designed for the storage and transportation of cadavers. + components: + - type: Sprite + netsync: false + sprite: Objects/Specific/Morgue/bodybags.rsi + layers: + - state: bag + - state: open_overlay + map: ["enum.StorageVisualLayers.Door"] + - state: label_overlay + map: ["enum.BodyBagVisualLayers.Label"] + - type: Icon + sprite: Objects/Specific/Morgue/bodybags.rsi + state: bag + - type: Clickable + - type: InteractionOutline + - type: MovedByPressure + - type: Physics + mass: 5 + anchored: false + shapes: + - !type:PhysShapeAabb + bounds: "-0.45,-0.5,0.1,0.5" + layer: + - Clickable + - type: BodyBagEntityStorage + CanWeldShut: false + Capacity: 1 + closeSound: /Audio/Misc/zip.ogg + openSound: /Audio/Misc/zip.ogg + - type: Appearance + visuals: + - type: StorageVisualizer + state_open: open_overlay + state_closed: bag + - type: BodyBagVisualizer + - type: Pullable + +- type: entity + id: BodyBag_Item + name: body bag + description: A plastic bag designed for the storage and transportation of cadavers. + parent: BaseItem + components: + - type: Sprite + netsync: false + sprite: Objects/Specific/Morgue/bodybags.rsi + state: item +# - type: BodyBagItem #TODO: we need some kind of generic placable, like thus: +# - type: Placeable +# prototype: someId +# snap: Center + + +- type: entity + id: Morgue + name: morgue + description: Used to keep bodies in until someone fetches them. Includes a high-tech alert system for false-positives! + components: + - type: Sprite + netsync: false + sprite: Objects/Specific/Morgue/morgue.rsi + layers: + - state: morgue_closed + map: ["enum.MorgueVisualLayers.Base"] + - state: morgue_nomob_light + visible: false + map: ["enum.MorgueVisualLayers.Light"] + shader: unshaded + - type: Clickable + - type: InteractionOutline + - type: Physics + mass: 25 + anchored: true + shapes: + - !type:PhysShapeAabb + bounds: "-0.5, -0.5, 0.5, 0.5" + mask: + - Impassable + - MobImpassable + - VaultImpassable + - SmallImpassable + layer: + - Opaque + - MobImpassable + - VaultImpassable + - SmallImpassable + - type: MorgueEntityStorage + CanWeldShut: false + IsCollidableWhenOpen: true + Capacity: 1 + closeSound: /Audio/Items/deconstruct.ogg + openSound: /Audio/Items/deconstruct.ogg + trayPrototype: MorgueTray + - type: Appearance + visuals: + - type: MorgueVisualizer + state_open: morgue_open + state_closed: morgue_closed + light_contents: morgue_nomob_light + light_mob: morgue_nosoul_light + light_soul: morgue_soul_light + - type: SnapGrid + offset: Center + +- type: entity + id: MorgueTray + name: morgue tray + description: If you lay down to have a rest on this, you'll soon have a problem. + components: + - type: Sprite + netsync: false + sprite: Objects/Specific/Morgue/morgue.rsi + state: morgue_tray + - type: Clickable + - type: InteractionOutline + - type: Physics + mass: 15 + anchored: true + shapes: + - !type:PhysShapeAabb + bounds: "-0.5, -0.5, 0.5, 0.5" + layer: + - Clickable + - type: MorgueTray + + +- type: entity + id: Crematorium + name: crematorium + description: A human incinerator. Works well on barbecue nights. + components: + - type: Sprite + netsync: false + sprite: Objects/Specific/Morgue/morgue.rsi + layers: + - state: crema_closed + map: ["enum.CrematoriumVisualLayers.Base"] + - state: crema_contents_light + visible: false + map: ["enum.CrematoriumVisualLayers.Light"] + shader: unshaded + - type: Clickable + - type: InteractionOutline + - type: Physics + mass: 25 + anchored: true + shapes: + - !type:PhysShapeAabb + bounds: "-0.5, -0.5, 0.5, 0.5" + mask: + - Impassable + - MobImpassable + - VaultImpassable + - SmallImpassable + layer: + - Opaque + - MobImpassable + - VaultImpassable + - SmallImpassable + - type: CrematoriumEntityStorage + CanWeldShut: false + IsCollidableWhenOpen: true + Capacity: 1 + closeSound: /Audio/Items/deconstruct.ogg + openSound: /Audio/Items/deconstruct.ogg + trayPrototype: CrematoriumTray + doSoulBeep: false + - type: LoopingSound + - type: Appearance + visuals: + - type: CrematoriumVisualizer + state_open: crema_open + state_closed: crema_closed + light_contents: crema_contents_light + light_burning: crema_active_light + - type: SnapGrid + offset: Center + +- type: entity + id: CrematoriumTray + name: crematorium tray + parent: MorgueTray + components: + - type: Sprite + netsync: false + sprite: Objects/Specific/Morgue/morgue.rsi + state: crema_tray + +- type: entity + id: Ash + name: ash + description: This used to be something, but now it's not. + parent: BaseItem + components: + - type: Sprite + netsync: false + sprite: Objects/Consumable/Trash/ash.rsi + state: icon \ No newline at end of file diff --git a/Resources/Textures/Objects/Specific/Morgue/bodybags.rsi/bag.png b/Resources/Textures/Objects/Specific/Morgue/bodybags.rsi/bag.png new file mode 100644 index 0000000000..d7b0baefd0 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Morgue/bodybags.rsi/bag.png differ diff --git a/Resources/Textures/Objects/Specific/Morgue/bodybags.rsi/item.png b/Resources/Textures/Objects/Specific/Morgue/bodybags.rsi/item.png new file mode 100644 index 0000000000..99ac0ce453 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Morgue/bodybags.rsi/item.png differ diff --git a/Resources/Textures/Objects/Specific/Morgue/bodybags.rsi/label_overlay.png b/Resources/Textures/Objects/Specific/Morgue/bodybags.rsi/label_overlay.png new file mode 100644 index 0000000000..b0c5a78d23 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Morgue/bodybags.rsi/label_overlay.png differ diff --git a/Resources/Textures/Objects/Specific/Morgue/bodybags.rsi/meta.json b/Resources/Textures/Objects/Specific/Morgue/bodybags.rsi/meta.json new file mode 100644 index 0000000000..9eaad9e7d7 --- /dev/null +++ b/Resources/Textures/Objects/Specific/Morgue/bodybags.rsi/meta.json @@ -0,0 +1,47 @@ +{ + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "license": "CC BY-SA 3.0", + "copyright": "Taken from https://github.com/tgstation/tgstation at commit 39659000f380583c35fb814ee2fadab24c2f8076", + "states": [ + { + "name": "bag", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "item", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "label_overlay", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "open_overlay", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/Objects/Specific/Morgue/bodybags.rsi/open_overlay.png b/Resources/Textures/Objects/Specific/Morgue/bodybags.rsi/open_overlay.png new file mode 100644 index 0000000000..48e9bbc6c2 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Morgue/bodybags.rsi/open_overlay.png differ diff --git a/Resources/Textures/Objects/Specific/Morgue/morgue.rsi/crema_active_light.png b/Resources/Textures/Objects/Specific/Morgue/morgue.rsi/crema_active_light.png new file mode 100644 index 0000000000..8846f209cb Binary files /dev/null and b/Resources/Textures/Objects/Specific/Morgue/morgue.rsi/crema_active_light.png differ diff --git a/Resources/Textures/Objects/Specific/Morgue/morgue.rsi/crema_closed.png b/Resources/Textures/Objects/Specific/Morgue/morgue.rsi/crema_closed.png new file mode 100644 index 0000000000..540b15234b Binary files /dev/null and b/Resources/Textures/Objects/Specific/Morgue/morgue.rsi/crema_closed.png differ diff --git a/Resources/Textures/Objects/Specific/Morgue/morgue.rsi/crema_contents_light.png b/Resources/Textures/Objects/Specific/Morgue/morgue.rsi/crema_contents_light.png new file mode 100644 index 0000000000..5626219773 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Morgue/morgue.rsi/crema_contents_light.png differ diff --git a/Resources/Textures/Objects/Specific/Morgue/morgue.rsi/crema_open.png b/Resources/Textures/Objects/Specific/Morgue/morgue.rsi/crema_open.png new file mode 100644 index 0000000000..32730eedcb Binary files /dev/null and b/Resources/Textures/Objects/Specific/Morgue/morgue.rsi/crema_open.png differ diff --git a/Resources/Textures/Objects/Specific/Morgue/morgue.rsi/crema_tray.png b/Resources/Textures/Objects/Specific/Morgue/morgue.rsi/crema_tray.png new file mode 100644 index 0000000000..57f9c47271 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Morgue/morgue.rsi/crema_tray.png differ diff --git a/Resources/Textures/Objects/Specific/Morgue/morgue.rsi/meta.json b/Resources/Textures/Objects/Specific/Morgue/morgue.rsi/meta.json new file mode 100644 index 0000000000..c6b02159b8 --- /dev/null +++ b/Resources/Textures/Objects/Specific/Morgue/morgue.rsi/meta.json @@ -0,0 +1,209 @@ +{ + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from https://github.com/tgstation/tgstation at commit 31d88c7454e429a64fbae4a9f7b4aecaf838e9a1", + "states": [ + { + "name": "crema_active_light", + "directions": 4, + "delays": [ + [ + 1.0 + ], + [ + 1.0 + ], + [ + 1.0 + ], + [ + 1.0 + ] + ] + }, + { + "name": "crema_closed", + "directions": 4, + "delays": [ + [ + 1.0 + ], + [ + 1.0 + ], + [ + 1.0 + ], + [ + 1.0 + ] + ] + }, + { + "name": "crema_contents_light", + "directions": 4, + "delays": [ + [ + 1.0 + ], + [ + 1.0 + ], + [ + 1.0 + ], + [ + 1.0 + ] + ] + }, + { + "name": "crema_open", + "directions": 4, + "delays": [ + [ + 1.0 + ], + [ + 1.0 + ], + [ + 1.0 + ], + [ + 1.0 + ] + ] + }, + { + "name": "crema_tray", + "directions": 4, + "delays": [ + [ + 1.0 + ], + [ + 1.0 + ], + [ + 1.0 + ], + [ + 1.0 + ] + ] + }, + { + "name": "morgue_closed", + "directions": 4, + "delays": [ + [ + 1.0 + ], + [ + 1.0 + ], + [ + 1.0 + ], + [ + 1.0 + ] + ] + }, + { + "name": "morgue_nomob_light", + "directions": 4, + "delays": [ + [ + 1.0 + ], + [ + 1.0 + ], + [ + 1.0 + ], + [ + 1.0 + ] + ] + }, + { + "name": "morgue_nosoul_light", + "directions": 4, + "delays": [ + [ + 1.0 + ], + [ + 1.0 + ], + [ + 1.0 + ], + [ + 1.0 + ] + ] + }, + { + "name": "morgue_open", + "directions": 4, + "delays": [ + [ + 1.0 + ], + [ + 1.0 + ], + [ + 1.0 + ], + [ + 1.0 + ] + ] + }, + { + "name": "morgue_soul_light", + "directions": 4, + "delays": [ + [ + 1.0 + ], + [ + 1.0 + ], + [ + 1.0 + ], + [ + 1.0 + ] + ] + }, + { + "name": "morgue_tray", + "directions": 4, + "delays": [ + [ + 1.0 + ], + [ + 1.0 + ], + [ + 1.0 + ], + [ + 1.0 + ] + ] + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/Objects/Specific/Morgue/morgue.rsi/morgue_closed.png b/Resources/Textures/Objects/Specific/Morgue/morgue.rsi/morgue_closed.png new file mode 100644 index 0000000000..d71250933d Binary files /dev/null and b/Resources/Textures/Objects/Specific/Morgue/morgue.rsi/morgue_closed.png differ diff --git a/Resources/Textures/Objects/Specific/Morgue/morgue.rsi/morgue_nomob_light.png b/Resources/Textures/Objects/Specific/Morgue/morgue.rsi/morgue_nomob_light.png new file mode 100644 index 0000000000..88a4126b92 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Morgue/morgue.rsi/morgue_nomob_light.png differ diff --git a/Resources/Textures/Objects/Specific/Morgue/morgue.rsi/morgue_nosoul_light.png b/Resources/Textures/Objects/Specific/Morgue/morgue.rsi/morgue_nosoul_light.png new file mode 100644 index 0000000000..abdd7d8ccb Binary files /dev/null and b/Resources/Textures/Objects/Specific/Morgue/morgue.rsi/morgue_nosoul_light.png differ diff --git a/Resources/Textures/Objects/Specific/Morgue/morgue.rsi/morgue_open.png b/Resources/Textures/Objects/Specific/Morgue/morgue.rsi/morgue_open.png new file mode 100644 index 0000000000..15ca16ae64 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Morgue/morgue.rsi/morgue_open.png differ diff --git a/Resources/Textures/Objects/Specific/Morgue/morgue.rsi/morgue_soul_light.png b/Resources/Textures/Objects/Specific/Morgue/morgue.rsi/morgue_soul_light.png new file mode 100644 index 0000000000..62f5e1c678 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Morgue/morgue.rsi/morgue_soul_light.png differ diff --git a/Resources/Textures/Objects/Specific/Morgue/morgue.rsi/morgue_tray.png b/Resources/Textures/Objects/Specific/Morgue/morgue.rsi/morgue_tray.png new file mode 100644 index 0000000000..d9edb8b218 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Morgue/morgue.rsi/morgue_tray.png differ