Refactor ExtinguisherCabinet->ItemCabinet and actually maps them in, adds EntityWhitelist (#4154)
* i probably shouldnt have done this in one commit * map nonsense * fix example code * unnecessary * test * reviews * little fix for open datafield * add soul
This commit is contained in:
@@ -1,40 +0,0 @@
|
|||||||
using Content.Shared.GameObjects.Components;
|
|
||||||
using JetBrains.Annotations;
|
|
||||||
using Robust.Client.GameObjects;
|
|
||||||
|
|
||||||
namespace Content.Client.GameObjects.Components
|
|
||||||
{
|
|
||||||
[UsedImplicitly]
|
|
||||||
public class ExtinguisherCabinetVisualizer : AppearanceVisualizer
|
|
||||||
{
|
|
||||||
public override void OnChangeData(AppearanceComponent component)
|
|
||||||
{
|
|
||||||
base.OnChangeData(component);
|
|
||||||
|
|
||||||
var sprite = component.Owner.GetComponent<ISpriteComponent>();
|
|
||||||
|
|
||||||
if (component.TryGetData(ExtinguisherCabinetVisuals.IsOpen, out bool isOpen))
|
|
||||||
{
|
|
||||||
if (isOpen)
|
|
||||||
{
|
|
||||||
if (component.TryGetData(ExtinguisherCabinetVisuals.ContainsExtinguisher, out bool contains))
|
|
||||||
{
|
|
||||||
if (contains)
|
|
||||||
{
|
|
||||||
sprite.LayerSetState(0, "extinguisher_full");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sprite.LayerSetState(0, "extinguisher_empty");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sprite.LayerSetState(0, "extinguisher_closed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using Content.Shared.GameObjects.Components;
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
using Robust.Client.GameObjects;
|
||||||
|
using Robust.Shared.Serialization.Manager.Attributes;
|
||||||
|
|
||||||
|
namespace Content.Client.GameObjects.Components
|
||||||
|
{
|
||||||
|
[UsedImplicitly]
|
||||||
|
public class ItemCabinetVisualizer : AppearanceVisualizer
|
||||||
|
{
|
||||||
|
// TODO proper layering
|
||||||
|
[DataField("fullState", required: true)]
|
||||||
|
private string _fullState = default!;
|
||||||
|
|
||||||
|
[DataField("emptyState", required: true)]
|
||||||
|
private string _emptyState = default!;
|
||||||
|
|
||||||
|
[DataField("closedState", required: true)]
|
||||||
|
private string _closedState = default!;
|
||||||
|
|
||||||
|
public override void OnChangeData(AppearanceComponent component)
|
||||||
|
{
|
||||||
|
base.OnChangeData(component);
|
||||||
|
|
||||||
|
if (component.Owner.TryGetComponent<SpriteComponent>(out var sprite)
|
||||||
|
&& component.TryGetData(ItemCabinetVisuals.IsOpen, out bool isOpen))
|
||||||
|
{
|
||||||
|
if (isOpen)
|
||||||
|
{
|
||||||
|
if (component.TryGetData(ItemCabinetVisuals.ContainsItem, out bool contains))
|
||||||
|
{
|
||||||
|
if (contains)
|
||||||
|
{
|
||||||
|
sprite.LayerSetState(0, _fullState);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sprite.LayerSetState(0, _emptyState);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sprite.LayerSetState(0, _closedState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -158,8 +158,7 @@ namespace Content.Client
|
|||||||
"SignalTransmitter",
|
"SignalTransmitter",
|
||||||
"SignalButton",
|
"SignalButton",
|
||||||
"SignalLinker",
|
"SignalLinker",
|
||||||
"ExtinguisherCabinet",
|
"ItemCabinet",
|
||||||
"ExtinguisherCabinetFilled",
|
|
||||||
"FireExtinguisher",
|
"FireExtinguisher",
|
||||||
"Firelock",
|
"Firelock",
|
||||||
"AtmosPlaque",
|
"AtmosPlaque",
|
||||||
|
|||||||
121
Content.IntegrationTests/Tests/Utility/EntityWhitelistTest.cs
Normal file
121
Content.IntegrationTests/Tests/Utility/EntityWhitelistTest.cs
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
using System.IO;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Content.Server.GameObjects.Components;
|
||||||
|
using Content.Server.GameObjects.Components.Items.Storage;
|
||||||
|
using Content.Shared.GameObjects.Components.Tag;
|
||||||
|
using Content.Shared.Prototypes;
|
||||||
|
using Content.Shared.Utility;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using NUnit.Framework.Internal;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
using Robust.Shared.Map;
|
||||||
|
using Robust.Shared.Maths;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
using Robust.Shared.Serialization.Manager;
|
||||||
|
|
||||||
|
namespace Content.IntegrationTests.Tests.Utility
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
[TestOf(typeof(EntityWhitelist))]
|
||||||
|
public class EntityWhitelistTest : ContentIntegrationTest
|
||||||
|
{
|
||||||
|
private const string InvalidComponent = "Sprite";
|
||||||
|
private const string ValidComponent = "Physics";
|
||||||
|
|
||||||
|
private static readonly string Prototypes = $@"
|
||||||
|
- type: Tag
|
||||||
|
id: ValidTag
|
||||||
|
- type: Tag
|
||||||
|
id: InvalidTag
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: WhitelistDummy
|
||||||
|
components:
|
||||||
|
- type: ItemCabinet
|
||||||
|
whitelist:
|
||||||
|
prototypes:
|
||||||
|
- ValidPrototypeDummy
|
||||||
|
components:
|
||||||
|
- {ValidComponent}
|
||||||
|
tags:
|
||||||
|
- ValidTag
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: InvalidComponentDummy
|
||||||
|
components:
|
||||||
|
- type: {InvalidComponent}
|
||||||
|
- type: entity
|
||||||
|
id: InvalidTagDummy
|
||||||
|
components:
|
||||||
|
- type: Tag
|
||||||
|
tags:
|
||||||
|
- InvalidTag
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: ValidComponentDummy
|
||||||
|
components:
|
||||||
|
- type: {ValidComponent}
|
||||||
|
- type: entity
|
||||||
|
id: ValidTagDummy
|
||||||
|
components:
|
||||||
|
- type: Tag
|
||||||
|
tags:
|
||||||
|
- ValidTag";
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task Test()
|
||||||
|
{
|
||||||
|
var serverOptions = new ServerContentIntegrationOption {ExtraPrototypes = Prototypes};
|
||||||
|
var server = StartServer(serverOptions);
|
||||||
|
|
||||||
|
await server.WaitIdleAsync();
|
||||||
|
var mapManager = server.ResolveDependency<IMapManager>();
|
||||||
|
var entityManager = server.ResolveDependency<IEntityManager>();
|
||||||
|
|
||||||
|
await server.WaitAssertion(() =>
|
||||||
|
{
|
||||||
|
var mapId = new MapId(1);
|
||||||
|
var mapCoordinates = new MapCoordinates(0, 0, mapId);
|
||||||
|
|
||||||
|
var validComponent = entityManager.SpawnEntity("ValidComponentDummy", mapCoordinates);
|
||||||
|
var validTag = entityManager.SpawnEntity("ValidTagDummy", mapCoordinates);
|
||||||
|
|
||||||
|
var invalidComponent = entityManager.SpawnEntity("InvalidComponentDummy", mapCoordinates);
|
||||||
|
var invalidTag = entityManager.SpawnEntity("InvalidTagDummy", mapCoordinates);
|
||||||
|
|
||||||
|
// Test instantiated on its own
|
||||||
|
var whitelistInst = new EntityWhitelist
|
||||||
|
{
|
||||||
|
Components = new[] {$"{ValidComponent}"},
|
||||||
|
Tags = new[] {"ValidTag"}
|
||||||
|
};
|
||||||
|
whitelistInst.UpdateRegistrations();
|
||||||
|
Assert.That(whitelistInst, Is.Not.Null);
|
||||||
|
|
||||||
|
Assert.That(whitelistInst.Components, Is.Not.Null);
|
||||||
|
Assert.That(whitelistInst.Tags, Is.Not.Null);
|
||||||
|
|
||||||
|
Assert.That(whitelistInst.IsValid(validComponent), Is.True);
|
||||||
|
Assert.That(whitelistInst.IsValid(validTag), Is.True);
|
||||||
|
|
||||||
|
Assert.That(whitelistInst.IsValid(invalidComponent), Is.False);
|
||||||
|
Assert.That(whitelistInst.IsValid(invalidTag), Is.False);
|
||||||
|
|
||||||
|
// Test from serialized
|
||||||
|
var dummy = entityManager.SpawnEntity("WhitelistDummy", mapCoordinates);
|
||||||
|
var whitelistSer = dummy.GetComponent<ItemCabinetComponent>().Whitelist;
|
||||||
|
Assert.That(whitelistSer, Is.Not.Null);
|
||||||
|
|
||||||
|
Assert.That(whitelistSer.Components, Is.Not.Null);
|
||||||
|
Assert.That(whitelistSer.Tags, Is.Not.Null);
|
||||||
|
|
||||||
|
Assert.That(whitelistSer.IsValid(validComponent), Is.True);
|
||||||
|
Assert.That(whitelistSer.IsValid(validTag), Is.True);
|
||||||
|
|
||||||
|
Assert.That(whitelistSer.IsValid(invalidComponent), Is.False);
|
||||||
|
Assert.That(whitelistSer.IsValid(invalidTag), Is.False);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,121 +0,0 @@
|
|||||||
using System.Threading.Tasks;
|
|
||||||
using Content.Server.GameObjects.Components.GUI;
|
|
||||||
using Content.Server.GameObjects.Components.Items;
|
|
||||||
using Content.Server.GameObjects.Components.Items.Storage;
|
|
||||||
using Content.Server.Interfaces.GameObjects.Components.Items;
|
|
||||||
using Content.Shared.Audio;
|
|
||||||
using Content.Shared.GameObjects.Components;
|
|
||||||
using Content.Shared.Interfaces;
|
|
||||||
using Content.Shared.Interfaces.GameObjects.Components;
|
|
||||||
using Robust.Server.GameObjects;
|
|
||||||
using Robust.Shared.Audio;
|
|
||||||
using Robust.Shared.Containers;
|
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.Localization;
|
|
||||||
using Robust.Shared.Player;
|
|
||||||
using Robust.Shared.Serialization.Manager.Attributes;
|
|
||||||
using Robust.Shared.ViewVariables;
|
|
||||||
|
|
||||||
namespace Content.Server.GameObjects.Components
|
|
||||||
{
|
|
||||||
[RegisterComponent]
|
|
||||||
[ComponentReference(typeof(IActivate))]
|
|
||||||
public class ExtinguisherCabinetComponent : Component, IInteractUsing, IInteractHand, IActivate
|
|
||||||
{
|
|
||||||
public override string Name => "ExtinguisherCabinet";
|
|
||||||
|
|
||||||
private bool _opened = false;
|
|
||||||
[DataField("doorSound")]
|
|
||||||
private string _doorSound = "/Audio/Machines/machine_switch.ogg";
|
|
||||||
|
|
||||||
[ViewVariables] protected ContainerSlot ItemContainer = default!;
|
|
||||||
[ViewVariables] public string DoorSound => _doorSound;
|
|
||||||
|
|
||||||
public override void Initialize()
|
|
||||||
{
|
|
||||||
base.Initialize();
|
|
||||||
|
|
||||||
ItemContainer =
|
|
||||||
ContainerHelpers.EnsureContainer<ContainerSlot>(Owner, "extinguisher_cabinet", out _);
|
|
||||||
}
|
|
||||||
|
|
||||||
async Task<bool> IInteractUsing.InteractUsing(InteractUsingEventArgs eventArgs)
|
|
||||||
{
|
|
||||||
if (!_opened)
|
|
||||||
{
|
|
||||||
_opened = true;
|
|
||||||
ClickLatchSound();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (ItemContainer.ContainedEntity != null || !eventArgs.Using.HasComponent<FireExtinguisherComponent>())
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
var handsComponent = eventArgs.User.GetComponent<IHandsComponent>();
|
|
||||||
|
|
||||||
if (!handsComponent.Drop(eventArgs.Using, ItemContainer))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
UpdateVisuals();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IInteractHand.InteractHand(InteractHandEventArgs eventArgs)
|
|
||||||
{
|
|
||||||
if (_opened)
|
|
||||||
{
|
|
||||||
if (ItemContainer.ContainedEntity == null)
|
|
||||||
{
|
|
||||||
_opened = false;
|
|
||||||
ClickLatchSound();
|
|
||||||
}
|
|
||||||
else if (eventArgs.User.TryGetComponent(out HandsComponent? hands))
|
|
||||||
{
|
|
||||||
Owner.PopupMessage(eventArgs.User,
|
|
||||||
Loc.GetString("You take {0:extinguisherName} from the {1:cabinetName}", ItemContainer.ContainedEntity.Name, Owner.Name));
|
|
||||||
hands.PutInHandOrDrop(ItemContainer.ContainedEntity.GetComponent<ItemComponent>());
|
|
||||||
}
|
|
||||||
else if (ItemContainer.Remove(ItemContainer.ContainedEntity))
|
|
||||||
{
|
|
||||||
ItemContainer.ContainedEntity.Transform.Coordinates = Owner.Transform.Coordinates;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_opened = true;
|
|
||||||
ClickLatchSound();
|
|
||||||
}
|
|
||||||
|
|
||||||
UpdateVisuals();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void IActivate.Activate(ActivateEventArgs eventArgs)
|
|
||||||
{
|
|
||||||
_opened = !_opened;
|
|
||||||
ClickLatchSound();
|
|
||||||
UpdateVisuals();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateVisuals()
|
|
||||||
{
|
|
||||||
if (Owner.TryGetComponent(out AppearanceComponent? appearance))
|
|
||||||
{
|
|
||||||
appearance.SetData(ExtinguisherCabinetVisuals.IsOpen, _opened);
|
|
||||||
appearance.SetData(ExtinguisherCabinetVisuals.ContainsExtinguisher, ItemContainer.ContainedEntity != null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ClickLatchSound()
|
|
||||||
{
|
|
||||||
// Don't have original click, this sounds close
|
|
||||||
SoundSystem.Play(Filter.Pvs(Owner), DoorSound, Owner, AudioHelpers.WithVariation(0.15f));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
using Robust.Shared.GameObjects;
|
|
||||||
|
|
||||||
namespace Content.Server.GameObjects.Components
|
|
||||||
{
|
|
||||||
[RegisterComponent]
|
|
||||||
public class ExtinguisherCabinetFilledComponent : ExtinguisherCabinetComponent
|
|
||||||
{
|
|
||||||
public override string Name => "ExtinguisherCabinetFilled";
|
|
||||||
|
|
||||||
public override void Initialize()
|
|
||||||
{
|
|
||||||
base.Initialize();
|
|
||||||
|
|
||||||
ItemContainer.Insert(Owner.EntityManager.SpawnEntity("FireExtinguisher", Owner.Transform.Coordinates));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Content.Server.GameObjects.EntitySystems;
|
||||||
|
using Content.Shared.GameObjects.EntitySystems.ActionBlocker;
|
||||||
|
using Content.Shared.GameObjects.Verbs;
|
||||||
|
using Content.Shared.Utility;
|
||||||
|
using Robust.Shared.Containers;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.Localization;
|
||||||
|
using Robust.Shared.Serialization.Manager.Attributes;
|
||||||
|
using Robust.Shared.ViewVariables;
|
||||||
|
|
||||||
|
namespace Content.Server.GameObjects.Components
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Used for entities that can hold one item that fits the whitelist, which can be extracted by interacting with
|
||||||
|
/// the entity, and can have an item fitting the whitelist placed back inside
|
||||||
|
/// </summary>
|
||||||
|
[RegisterComponent]
|
||||||
|
public class ItemCabinetComponent : Component
|
||||||
|
{
|
||||||
|
public override string Name => "ItemCabinet";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sound to be played when the cabinet door is opened.
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
[DataField("doorSound")]
|
||||||
|
public string? DoorSound { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The prototype that should be spawned inside the cabinet when it is map initialized.
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables]
|
||||||
|
[DataField("spawnPrototype")]
|
||||||
|
public string? SpawnPrototype { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A whitelist defining which entities are allowed into the cabinet.
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables]
|
||||||
|
[DataField("whitelist")]
|
||||||
|
public EntityWhitelist? Whitelist = null;
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
public ContainerSlot ItemContainer = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether the cabinet is currently open or not.
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables]
|
||||||
|
[DataField("opened")]
|
||||||
|
public bool Opened { get; set; } = false;
|
||||||
|
|
||||||
|
[Verb]
|
||||||
|
public sealed class EjectItemFromCabinetVerb : Verb<ItemCabinetComponent>
|
||||||
|
{
|
||||||
|
protected override void GetData(IEntity user, ItemCabinetComponent component, VerbData data)
|
||||||
|
{
|
||||||
|
if (component.ItemContainer.ContainedEntity == null || !component.Opened || !ActionBlockerSystem.CanInteract(user))
|
||||||
|
data.Visibility = VerbVisibility.Invisible;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
data.Text = Loc.GetString("comp-item-cabinet-eject-verb-text");
|
||||||
|
data.IconTexture = "/Textures/Interface/VerbIcons/eject.svg.192dpi.png";
|
||||||
|
data.Visibility = VerbVisibility.Visible;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Activate(IEntity user, ItemCabinetComponent component)
|
||||||
|
{
|
||||||
|
component.Owner.EntityManager.EventBus.RaiseLocalEvent(component.Owner.Uid, new TryEjectItemCabinetEvent(user), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Verb]
|
||||||
|
public sealed class ToggleItemCabinetVerb : Verb<ItemCabinetComponent>
|
||||||
|
{
|
||||||
|
protected override void GetData(IEntity user, ItemCabinetComponent component, VerbData data)
|
||||||
|
{
|
||||||
|
if (!ActionBlockerSystem.CanInteract(user))
|
||||||
|
data.Visibility = VerbVisibility.Invisible;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
data.Text = Loc.GetString(component.Opened ? "comp-item-cabinet-close-verb-text" : "comp-item-cabinet-open-verb-text");
|
||||||
|
data.IconTexture = component.Opened ? "/Textures/Interface/VerbIcons/close.svg.192dpi.png" : "/Textures/Interface/VerbIcons/open.svg.192dpi.png";
|
||||||
|
data.Visibility = VerbVisibility.Visible;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Activate(IEntity user, ItemCabinetComponent component)
|
||||||
|
{
|
||||||
|
component.Owner.EntityManager.EventBus.RaiseLocalEvent(component.Owner.Uid, new ToggleItemCabinetEvent(), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -25,6 +25,7 @@ namespace Content.Server.GameObjects.Components.Items.Storage
|
|||||||
[RegisterComponent]
|
[RegisterComponent]
|
||||||
public class StorageCounterComponent : Component, ISerializationHooks
|
public class StorageCounterComponent : Component, ISerializationHooks
|
||||||
{
|
{
|
||||||
|
// TODO Convert to EntityWhitelist
|
||||||
[DataField("countTag")]
|
[DataField("countTag")]
|
||||||
private string? _countTag;
|
private string? _countTag;
|
||||||
|
|
||||||
|
|||||||
@@ -31,10 +31,10 @@ namespace Content.Server.GameObjects.EntitySystems
|
|||||||
SubscribeLocalEvent<BuckleComponent, EntRemovedFromContainerMessage>(ContainerModifiedBuckle);
|
SubscribeLocalEvent<BuckleComponent, EntRemovedFromContainerMessage>(ContainerModifiedBuckle);
|
||||||
SubscribeLocalEvent<StrapComponent, EntRemovedFromContainerMessage>(ContainerModifiedStrap);
|
SubscribeLocalEvent<StrapComponent, EntRemovedFromContainerMessage>(ContainerModifiedStrap);
|
||||||
|
|
||||||
SubscribeLocalEvent<BuckleComponent, InteractHandEvent>(HandleAttackHand);
|
SubscribeLocalEvent<BuckleComponent, InteractHandEvent>(HandleInteractHand);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleAttackHand(EntityUid uid, BuckleComponent component, InteractHandEvent args)
|
private void HandleInteractHand(EntityUid uid, BuckleComponent component, InteractHandEvent args)
|
||||||
{
|
{
|
||||||
args.Handled = component.TryUnbuckle(args.User);
|
args.Handled = component.TryUnbuckle(args.User);
|
||||||
}
|
}
|
||||||
|
|||||||
195
Content.Server/GameObjects/EntitySystems/ItemCabinetSystem.cs
Normal file
195
Content.Server/GameObjects/EntitySystems/ItemCabinetSystem.cs
Normal file
@@ -0,0 +1,195 @@
|
|||||||
|
using Content.Server.GameObjects.Components;
|
||||||
|
using Content.Server.GameObjects.Components.GUI;
|
||||||
|
using Content.Server.GameObjects.Components.Items;
|
||||||
|
using Content.Server.GameObjects.Components.Items.Storage;
|
||||||
|
using Content.Shared.Audio;
|
||||||
|
using Content.Shared.GameObjects.Components;
|
||||||
|
using Content.Shared.GameObjects.EntitySystems.ActionBlocker;
|
||||||
|
using Content.Shared.GameObjects.Verbs;
|
||||||
|
using Content.Shared.Interfaces;
|
||||||
|
using Content.Shared.Interfaces.GameObjects.Components;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Robust.Server.GameObjects;
|
||||||
|
using Robust.Shared.Audio;
|
||||||
|
using Robust.Shared.Containers;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.Localization;
|
||||||
|
using Robust.Shared.Log;
|
||||||
|
using Robust.Shared.Player;
|
||||||
|
|
||||||
|
namespace Content.Server.GameObjects.EntitySystems
|
||||||
|
{
|
||||||
|
public class ItemCabinetSystem : EntitySystem
|
||||||
|
{
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeLocalEvent<ItemCabinetComponent, MapInitEvent>(OnMapInitialize);
|
||||||
|
|
||||||
|
SubscribeLocalEvent<ItemCabinetComponent, InteractUsingEvent>(OnInteractUsing);
|
||||||
|
SubscribeLocalEvent<ItemCabinetComponent, InteractHandEvent>(OnInteractHand);
|
||||||
|
SubscribeLocalEvent<ItemCabinetComponent, ActivateInWorldEvent>(OnActivateInWorld);
|
||||||
|
|
||||||
|
SubscribeLocalEvent<ItemCabinetComponent, TryEjectItemCabinetEvent>(OnTryEjectItemCabinet);
|
||||||
|
SubscribeLocalEvent<ItemCabinetComponent, TryInsertItemCabinetEvent>(OnTryInsertItemCabinet);
|
||||||
|
SubscribeLocalEvent<ItemCabinetComponent, ToggleItemCabinetEvent>(OnToggleItemCabinet);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnMapInitialize(EntityUid uid, ItemCabinetComponent comp, MapInitEvent args)
|
||||||
|
{
|
||||||
|
var owner = EntityManager.GetEntity(uid);
|
||||||
|
comp.ItemContainer =
|
||||||
|
owner.EnsureContainer<ContainerSlot>("item_cabinet", out _);
|
||||||
|
|
||||||
|
if(comp.SpawnPrototype != null)
|
||||||
|
comp.ItemContainer.Insert(EntityManager.SpawnEntity(comp.SpawnPrototype, owner.Transform.Coordinates));
|
||||||
|
|
||||||
|
UpdateVisuals(comp);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnInteractUsing(EntityUid uid, ItemCabinetComponent comp, InteractUsingEvent args)
|
||||||
|
{
|
||||||
|
args.Handled = true;
|
||||||
|
if (!comp.Opened)
|
||||||
|
{
|
||||||
|
RaiseLocalEvent(uid, new ToggleItemCabinetEvent(), false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RaiseLocalEvent(uid, new TryInsertItemCabinetEvent(args.User, args.Used), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
args.Handled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnInteractHand(EntityUid uid, ItemCabinetComponent comp, InteractHandEvent args)
|
||||||
|
{
|
||||||
|
args.Handled = true;
|
||||||
|
if (comp.Opened)
|
||||||
|
{
|
||||||
|
if (comp.ItemContainer.ContainedEntity == null)
|
||||||
|
{
|
||||||
|
RaiseLocalEvent(uid, new ToggleItemCabinetEvent(), false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
RaiseLocalEvent(uid, new TryEjectItemCabinetEvent(args.User), false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RaiseLocalEvent(uid, new ToggleItemCabinetEvent(), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnActivateInWorld(EntityUid uid, ItemCabinetComponent comp, ActivateInWorldEvent args)
|
||||||
|
{
|
||||||
|
args.Handled = true;
|
||||||
|
RaiseLocalEvent(uid, new ToggleItemCabinetEvent(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Toggles the ItemCabinet's state.
|
||||||
|
/// </summary>
|
||||||
|
private void OnToggleItemCabinet(EntityUid uid, ItemCabinetComponent comp, ToggleItemCabinetEvent args)
|
||||||
|
{
|
||||||
|
comp.Opened = !comp.Opened;
|
||||||
|
ClickLatchSound(comp);
|
||||||
|
UpdateVisuals(comp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tries to insert an entity into the ItemCabinet's slot from the user's hands.
|
||||||
|
/// </summary>
|
||||||
|
private static void OnTryInsertItemCabinet(EntityUid uid, ItemCabinetComponent comp, TryInsertItemCabinetEvent args)
|
||||||
|
{
|
||||||
|
if (comp.ItemContainer.ContainedEntity != null || args.Cancelled || (comp.Whitelist != null && !comp.Whitelist.IsValid(args.Item)))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!args.User.TryGetComponent<HandsComponent>(out var hands) || !hands.Drop(args.Item, comp.ItemContainer))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateVisuals(comp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tries to eject the ItemCabinet's item, either into the user's hands or onto the floor.
|
||||||
|
/// </summary>
|
||||||
|
private static void OnTryEjectItemCabinet(EntityUid uid, ItemCabinetComponent comp, TryEjectItemCabinetEvent args)
|
||||||
|
{
|
||||||
|
if (comp.ItemContainer.ContainedEntity == null || args.Cancelled)
|
||||||
|
return;
|
||||||
|
if (args.User.TryGetComponent(out HandsComponent? hands))
|
||||||
|
{
|
||||||
|
|
||||||
|
if (comp.ItemContainer.ContainedEntity.TryGetComponent<ItemComponent>(out var item))
|
||||||
|
{
|
||||||
|
comp.Owner.PopupMessage(args.User,
|
||||||
|
Loc.GetString("comp-item-cabinet-successfully-taken",
|
||||||
|
("item", comp.ItemContainer.ContainedEntity),
|
||||||
|
("cabinet", comp.Owner)));
|
||||||
|
hands.PutInHandOrDrop(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (comp.ItemContainer.Remove(comp.ItemContainer.ContainedEntity))
|
||||||
|
{
|
||||||
|
comp.ItemContainer.ContainedEntity.Transform.Coordinates = args.User.Transform.Coordinates;
|
||||||
|
}
|
||||||
|
UpdateVisuals(comp);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void UpdateVisuals(ItemCabinetComponent comp)
|
||||||
|
{
|
||||||
|
if (comp.Owner.TryGetComponent(out SharedAppearanceComponent? appearance))
|
||||||
|
{
|
||||||
|
appearance.SetData(ItemCabinetVisuals.IsOpen, comp.Opened);
|
||||||
|
appearance.SetData(ItemCabinetVisuals.ContainsItem, comp.ItemContainer.ContainedEntity != null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ClickLatchSound(ItemCabinetComponent comp)
|
||||||
|
{
|
||||||
|
if (comp.DoorSound == null) return;
|
||||||
|
SoundSystem.Play(Filter.Pvs(comp.Owner), comp.DoorSound, comp.Owner, AudioHelpers.WithVariation(0.15f));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ToggleItemCabinetEvent : EntityEventArgs
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TryEjectItemCabinetEvent : CancellableEntityEventArgs
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The user who tried to eject the item.
|
||||||
|
/// </summary>
|
||||||
|
public IEntity User;
|
||||||
|
|
||||||
|
public TryEjectItemCabinetEvent(IEntity user)
|
||||||
|
{
|
||||||
|
User = user;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TryInsertItemCabinetEvent : CancellableEntityEventArgs
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The user who tried to eject the item.
|
||||||
|
/// </summary>
|
||||||
|
public IEntity User;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The item to be inserted.
|
||||||
|
/// </summary>
|
||||||
|
public IEntity Item;
|
||||||
|
|
||||||
|
public TryInsertItemCabinetEvent(IEntity user, IEntity item)
|
||||||
|
{
|
||||||
|
User = user;
|
||||||
|
Item = item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,9 +5,9 @@ using Robust.Shared.Serialization;
|
|||||||
namespace Content.Shared.GameObjects.Components
|
namespace Content.Shared.GameObjects.Components
|
||||||
{
|
{
|
||||||
[Serializable, NetSerializable]
|
[Serializable, NetSerializable]
|
||||||
public enum ExtinguisherCabinetVisuals
|
public enum ItemCabinetVisuals : byte
|
||||||
{
|
{
|
||||||
IsOpen,
|
IsOpen,
|
||||||
ContainsExtinguisher
|
ContainsItem
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ namespace Content.Shared.Interfaces.GameObjects.Components
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Raised when clicking on another object and no attack event was handled.
|
/// Raised directed on the used object when clicking on another object and no attack event was handled.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[PublicAPI]
|
[PublicAPI]
|
||||||
public class AfterInteractEvent : HandledEntityEventArgs
|
public class AfterInteractEvent : HandledEntityEventArgs
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ namespace Content.Shared.Interfaces.GameObjects.Components
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called when a player directly interacts with an empty hand when user is in range of the target entity.
|
/// Called when a player directly interacts with an empty hand when user is in range of the target entity.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Obsolete("Use AttackHandMessage instead")]
|
[Obsolete("Use InteractHandEvent instead")]
|
||||||
bool InteractHand(InteractHandEventArgs eventArgs);
|
bool InteractHand(InteractHandEventArgs eventArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,7 +32,7 @@ namespace Content.Shared.Interfaces.GameObjects.Components
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Raised when a target entity is interacted with by a user with an empty hand.
|
/// Raised directed on a target entity when it is interacted with by a user with an empty hand.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[PublicAPI]
|
[PublicAPI]
|
||||||
public class InteractHandEvent : HandledEntityEventArgs
|
public class InteractHandEvent : HandledEntityEventArgs
|
||||||
|
|||||||
85
Content.Shared/Utility/EntityWhitelist.cs
Normal file
85
Content.Shared/Utility/EntityWhitelist.cs
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using Content.Shared.GameObjects.Components.Tag;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
using Robust.Shared.Log;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
using Robust.Shared.Serialization.Manager.Attributes;
|
||||||
|
|
||||||
|
namespace Content.Shared.Utility
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Used to determine whether an entity fits a certain whitelist.
|
||||||
|
/// Does not whitelist by prototypes, since that is undesirable; you're better off just adding a tag to all
|
||||||
|
/// entity prototypes that need to be whitelisted, and checking for that.
|
||||||
|
/// </summary>
|
||||||
|
/// <code>
|
||||||
|
/// whitelist:
|
||||||
|
/// tags:
|
||||||
|
/// - Cigarette
|
||||||
|
/// - FirelockElectronics
|
||||||
|
/// components:
|
||||||
|
/// - Buckle
|
||||||
|
/// - AsteroidRock
|
||||||
|
/// </code>
|
||||||
|
[DataDefinition]
|
||||||
|
public class EntityWhitelist : ISerializationHooks
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Component names that are allowed in the whitelist.
|
||||||
|
/// </summary>
|
||||||
|
[DataField("components")] public string[]? Components = null;
|
||||||
|
|
||||||
|
private List<IComponentRegistration>? _registrations = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tags that are allowed in the whitelist.
|
||||||
|
/// </summary>
|
||||||
|
[DataField("tags")] public string[]? Tags = null;
|
||||||
|
|
||||||
|
void ISerializationHooks.AfterDeserialization()
|
||||||
|
{
|
||||||
|
UpdateRegistrations();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateRegistrations()
|
||||||
|
{
|
||||||
|
if (Components == null) return;
|
||||||
|
|
||||||
|
var compfact = IoCManager.Resolve<IComponentFactory>();
|
||||||
|
_registrations = new List<IComponentRegistration>();
|
||||||
|
foreach (var name in Components)
|
||||||
|
{
|
||||||
|
if (!compfact.TryGetRegistration(name, out var registration))
|
||||||
|
{
|
||||||
|
Logger.Warning($"Invalid component name {name} passed to EntityWhitelist!");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
_registrations.Add(registration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns whether a given entity fits the whitelist.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsValid(IEntity entity)
|
||||||
|
{
|
||||||
|
if (Tags != null)
|
||||||
|
{
|
||||||
|
if (entity.HasAnyTag(Tags))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_registrations != null)
|
||||||
|
{
|
||||||
|
foreach (var reg in _registrations)
|
||||||
|
{
|
||||||
|
if (entity.TryGetComponent(reg.Type, out _))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
13
Resources/Locale/en-US/components/item-cabinet-component.ftl
Normal file
13
Resources/Locale/en-US/components/item-cabinet-component.ftl
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
### Used for item cabinet (fire extinguisher cabinets)
|
||||||
|
|
||||||
|
## Displayed when the item is successfully taken out of the cabinet.
|
||||||
|
|
||||||
|
comp-item-cabinet-successfully-taken = You take { THE($item) } from { THE($cabinet) }.
|
||||||
|
|
||||||
|
## Displayed in the context menu for the item cabinet.
|
||||||
|
|
||||||
|
comp-item-cabinet-eject-verb-text = Eject item
|
||||||
|
|
||||||
|
comp-item-cabinet-open-verb-text = Open
|
||||||
|
comp-item-cabinet-close-verb-text = Close
|
||||||
|
|
||||||
@@ -48006,4 +48006,196 @@ entities:
|
|||||||
type: Transform
|
type: Transform
|
||||||
- canCollide: False
|
- canCollide: False
|
||||||
type: Physics
|
type: Physics
|
||||||
|
- uid: 4921
|
||||||
|
type: ExtinguisherCabinetFilled
|
||||||
|
components:
|
||||||
|
- pos: -26.5,-1.5
|
||||||
|
parent: 853
|
||||||
|
type: Transform
|
||||||
|
- uid: 4922
|
||||||
|
type: ExtinguisherCabinetFilled
|
||||||
|
components:
|
||||||
|
- pos: -26.5,-4.5
|
||||||
|
parent: 853
|
||||||
|
type: Transform
|
||||||
|
- uid: 4923
|
||||||
|
type: ExtinguisherCabinetFilled
|
||||||
|
components:
|
||||||
|
- pos: -15.5,-0.5
|
||||||
|
parent: 853
|
||||||
|
type: Transform
|
||||||
|
- uid: 4924
|
||||||
|
type: ExtinguisherCabinetFilled
|
||||||
|
components:
|
||||||
|
- pos: -18.5,8.5
|
||||||
|
parent: 853
|
||||||
|
type: Transform
|
||||||
|
- uid: 4925
|
||||||
|
type: ExtinguisherCabinetFilled
|
||||||
|
components:
|
||||||
|
- pos: -30.5,10.5
|
||||||
|
parent: 853
|
||||||
|
type: Transform
|
||||||
|
- uid: 4926
|
||||||
|
type: ExtinguisherCabinetFilled
|
||||||
|
components:
|
||||||
|
- pos: -34.5,-2.5
|
||||||
|
parent: 853
|
||||||
|
type: Transform
|
||||||
|
- uid: 4927
|
||||||
|
type: ExtinguisherCabinetFilled
|
||||||
|
components:
|
||||||
|
- pos: -16.5,-8.5
|
||||||
|
parent: 853
|
||||||
|
type: Transform
|
||||||
|
- uid: 4928
|
||||||
|
type: ExtinguisherCabinetFilled
|
||||||
|
components:
|
||||||
|
- pos: -6.5,-16.5
|
||||||
|
parent: 853
|
||||||
|
type: Transform
|
||||||
|
- uid: 4929
|
||||||
|
type: ExtinguisherCabinetFilled
|
||||||
|
components:
|
||||||
|
- pos: -6.5,-18.5
|
||||||
|
parent: 853
|
||||||
|
type: Transform
|
||||||
|
- uid: 4930
|
||||||
|
type: ExtinguisherCabinetFilled
|
||||||
|
components:
|
||||||
|
- pos: 8.5,-17.5
|
||||||
|
parent: 853
|
||||||
|
type: Transform
|
||||||
|
- uid: 4931
|
||||||
|
type: ExtinguisherCabinetFilled
|
||||||
|
components:
|
||||||
|
- pos: 16.5,-16.5
|
||||||
|
parent: 853
|
||||||
|
type: Transform
|
||||||
|
- uid: 4932
|
||||||
|
type: ExtinguisherCabinetFilled
|
||||||
|
components:
|
||||||
|
- pos: 24.5,-16.5
|
||||||
|
parent: 853
|
||||||
|
type: Transform
|
||||||
|
- uid: 4933
|
||||||
|
type: ExtinguisherCabinetFilled
|
||||||
|
components:
|
||||||
|
- pos: 25.5,-7.5
|
||||||
|
parent: 853
|
||||||
|
type: Transform
|
||||||
|
- uid: 4934
|
||||||
|
type: ExtinguisherCabinetFilled
|
||||||
|
components:
|
||||||
|
- pos: 32.5,-5.5
|
||||||
|
parent: 853
|
||||||
|
type: Transform
|
||||||
|
- uid: 4935
|
||||||
|
type: ExtinguisherCabinetFilled
|
||||||
|
components:
|
||||||
|
- pos: 41.5,-1.5
|
||||||
|
parent: 853
|
||||||
|
type: Transform
|
||||||
|
- uid: 4936
|
||||||
|
type: ExtinguisherCabinetFilled
|
||||||
|
components:
|
||||||
|
- pos: 46.5,-11.5
|
||||||
|
parent: 853
|
||||||
|
type: Transform
|
||||||
|
- uid: 4937
|
||||||
|
type: ExtinguisherCabinetFilled
|
||||||
|
components:
|
||||||
|
- pos: 52.5,-11.5
|
||||||
|
parent: 853
|
||||||
|
type: Transform
|
||||||
|
- uid: 4938
|
||||||
|
type: ExtinguisherCabinetFilled
|
||||||
|
components:
|
||||||
|
- pos: 45.5,6.5
|
||||||
|
parent: 853
|
||||||
|
type: Transform
|
||||||
|
- uid: 4939
|
||||||
|
type: ExtinguisherCabinetFilled
|
||||||
|
components:
|
||||||
|
- pos: 17.5,9.5
|
||||||
|
parent: 853
|
||||||
|
type: Transform
|
||||||
|
- uid: 4940
|
||||||
|
type: ExtinguisherCabinetFilled
|
||||||
|
components:
|
||||||
|
- pos: 9.5,12.5
|
||||||
|
parent: 853
|
||||||
|
type: Transform
|
||||||
|
- uid: 4941
|
||||||
|
type: ExtinguisherCabinetFilled
|
||||||
|
components:
|
||||||
|
- pos: -10.5,13.5
|
||||||
|
parent: 853
|
||||||
|
type: Transform
|
||||||
|
- uid: 4942
|
||||||
|
type: ExtinguisherCabinetFilled
|
||||||
|
components:
|
||||||
|
- pos: -6.5,18.5
|
||||||
|
parent: 853
|
||||||
|
type: Transform
|
||||||
|
- uid: 4943
|
||||||
|
type: ExtinguisherCabinetFilled
|
||||||
|
components:
|
||||||
|
- pos: 0.5,16.5
|
||||||
|
parent: 853
|
||||||
|
type: Transform
|
||||||
|
- uid: 4944
|
||||||
|
type: ExtinguisherCabinetFilled
|
||||||
|
components:
|
||||||
|
- pos: 11.5,18.5
|
||||||
|
parent: 853
|
||||||
|
type: Transform
|
||||||
|
- uid: 4945
|
||||||
|
type: ExtinguisherCabinetFilled
|
||||||
|
components:
|
||||||
|
- pos: 5.5,24.5
|
||||||
|
parent: 853
|
||||||
|
type: Transform
|
||||||
|
- uid: 4946
|
||||||
|
type: ExtinguisherCabinetFilled
|
||||||
|
components:
|
||||||
|
- pos: 1.5,26.5
|
||||||
|
parent: 853
|
||||||
|
type: Transform
|
||||||
|
- uid: 4947
|
||||||
|
type: ExtinguisherCabinetFilled
|
||||||
|
components:
|
||||||
|
- pos: -3.5,-25.5
|
||||||
|
parent: 853
|
||||||
|
type: Transform
|
||||||
|
- uid: 4948
|
||||||
|
type: ExtinguisherCabinetFilled
|
||||||
|
components:
|
||||||
|
- pos: -13.5,-23.5
|
||||||
|
parent: 853
|
||||||
|
type: Transform
|
||||||
|
- uid: 4949
|
||||||
|
type: ExtinguisherCabinetFilled
|
||||||
|
components:
|
||||||
|
- pos: 11.5,-28.5
|
||||||
|
parent: 853
|
||||||
|
type: Transform
|
||||||
|
- uid: 4950
|
||||||
|
type: ExtinguisherCabinetFilled
|
||||||
|
components:
|
||||||
|
- pos: 20.5,-20.5
|
||||||
|
parent: 853
|
||||||
|
type: Transform
|
||||||
|
- uid: 4951
|
||||||
|
type: ExtinguisherCabinetFilled
|
||||||
|
components:
|
||||||
|
- pos: 29.5,11.5
|
||||||
|
parent: 853
|
||||||
|
type: Transform
|
||||||
|
- uid: 4952
|
||||||
|
type: ExtinguisherCabinetFilled
|
||||||
|
components:
|
||||||
|
- pos: 44.5,11.5
|
||||||
|
parent: 853
|
||||||
|
type: Transform
|
||||||
...
|
...
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
- type: entity
|
- type: entity
|
||||||
id: ExtinguisherCabinet
|
id: ExtinguisherCabinet
|
||||||
name: extinguisher cabinet
|
name: extinguisher cabinet
|
||||||
abstract: true
|
|
||||||
description: A small wall mounted cabinet designed to hold a fire extinguisher.
|
description: A small wall mounted cabinet designed to hold a fire extinguisher.
|
||||||
components:
|
components:
|
||||||
- type: Clickable
|
- type: Clickable
|
||||||
@@ -9,15 +8,40 @@
|
|||||||
- type: Sprite
|
- type: Sprite
|
||||||
sprite: Constructible/Misc/extinguisher_cabinet.rsi
|
sprite: Constructible/Misc/extinguisher_cabinet.rsi
|
||||||
state: extinguisher_closed
|
state: extinguisher_closed
|
||||||
- type: ExtinguisherCabinet
|
- type: ItemCabinet
|
||||||
|
doorSound: /Audio/Machines/machine_switch.ogg
|
||||||
|
whitelist:
|
||||||
|
components:
|
||||||
|
- FireExtinguisher
|
||||||
- type: Appearance
|
- type: Appearance
|
||||||
visuals:
|
visuals:
|
||||||
- type: ExtinguisherCabinetVisualizer
|
- type: ItemCabinetVisualizer
|
||||||
|
emptyState: extinguisher_empty
|
||||||
|
fullState: extinguisher_full
|
||||||
|
closedState: extinguisher_closed
|
||||||
placement:
|
placement:
|
||||||
mode: SnapgridCenter
|
mode: SnapgridCenter
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: ExtinguisherCabinetOpen
|
||||||
|
parent: ExtinguisherCabinet
|
||||||
|
suffix: Open
|
||||||
|
components:
|
||||||
|
- type: ItemCabinet
|
||||||
|
opened: true
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
id: ExtinguisherCabinetFilled
|
id: ExtinguisherCabinetFilled
|
||||||
parent: ExtinguisherCabinet
|
parent: ExtinguisherCabinet
|
||||||
|
suffix: Filled
|
||||||
components:
|
components:
|
||||||
- type: ExtinguisherCabinetFilled
|
- type: ItemCabinet
|
||||||
|
spawnPrototype: FireExtinguisher
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: ExtinguisherCabinetFilledOpen
|
||||||
|
parent: ExtinguisherCabinetFilled
|
||||||
|
suffix: Filled, Open
|
||||||
|
components:
|
||||||
|
- type: ItemCabinet
|
||||||
|
opened: true
|
||||||
|
|||||||
@@ -31,6 +31,10 @@
|
|||||||
transferAmount: 5
|
transferAmount: 5
|
||||||
impulse: 50.0
|
impulse: 50.0
|
||||||
- type: FireExtinguisher
|
- type: FireExtinguisher
|
||||||
|
- type: MeleeWeapon
|
||||||
|
damage: 10
|
||||||
|
damageType: Blunt
|
||||||
|
hitSound: /Audio/Weapons/smash.ogg
|
||||||
- type: Appearance
|
- type: Appearance
|
||||||
visuals:
|
visuals:
|
||||||
- type: SprayVisualizer
|
- type: SprayVisualizer
|
||||||
|
|||||||
Reference in New Issue
Block a user