Make chemistry machines and IdCardConsole use item slots (#5428)

* chemistry item slots

* item slots id card console
This commit is contained in:
Leon Friedrich
2021-11-24 20:03:07 +13:00
committed by GitHub
parent 355625bded
commit 3b29ffdfa0
26 changed files with 371 additions and 560 deletions

View File

@@ -133,10 +133,47 @@ namespace Content.Shared.Containers.ItemSlots
[ViewVariables]
public ContainerSlot ContainerSlot = default!;
/// <summary>
/// If this slot belongs to some de-constructible component, should the item inside the slot be ejected upon
/// deconstruction?
/// </summary>
/// <remarks>
/// The actual deconstruction logic is handled by the server-side EmptyOnMachineDeconstructSystem.
/// </remarks>
[DataField("ejectOnDeconstruct")]
public bool EjectOnDeconstruct = true;
/// <summary>
/// If this slot belongs to some breakable or destructible entity, should the item inside the slot be
/// ejected when it is broken or destroyed?
/// </summary>
[DataField("ejectOnBreak")]
public bool EjectOnBreak = false;
/// <summary>
/// If this is not an empty string, this will generate a popup when someone attempts to insert a bad item
/// into this slot. This string will be passed through localization.
/// </summary>
[DataField("whitelistFailPopup")]
public string WhitelistFailPopup = string.Empty;
/// <summary>
/// If the user interacts with an entity with an already-filled item slot, should they attempt to swap out the item?
/// </summary>
/// <remarks>
/// Useful for things like chem dispensers, but undesirable for things like the ID card console, where you
/// want to insert more than one item that matches the same whitelist.
/// </remarks>
[DataField("swap")]
public bool Swap = true;
public string ID => ContainerSlot.ID;
// Convenience properties
public bool HasItem => ContainerSlot.ContainedEntity != null;
public IEntity? Item => ContainerSlot.ContainedEntity;
// and to make it easier for whenever IEntity is removed
public EntityUid? ItemUid => ContainerSlot.ContainedEntity?.Uid;
}
}

View File

@@ -1,6 +1,8 @@
using Content.Shared.ActionBlocker;
using Content.Shared.Acts;
using Content.Shared.Hands.Components;
using Content.Shared.Interaction;
using Content.Shared.Popups;
using Content.Shared.Verbs;
using Robust.Shared.Audio;
using Robust.Shared.Containers;
@@ -22,6 +24,7 @@ namespace Content.Shared.Containers.ItemSlots
public class ItemSlotsSystem : EntitySystem
{
[Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!;
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
public override void Initialize()
{
@@ -36,6 +39,9 @@ namespace Content.Shared.Containers.ItemSlots
SubscribeLocalEvent<ItemSlotsComponent, GetAlternativeVerbsEvent>(AddEjectVerbs);
SubscribeLocalEvent<ItemSlotsComponent, GetInteractionVerbsEvent>(AddInteractionVerbsVerbs);
SubscribeLocalEvent<ItemSlotsComponent, BreakageEventArgs>(OnBreak);
SubscribeLocalEvent<ItemSlotsComponent, DestructionEventArgs>(OnBreak);
SubscribeLocalEvent<ItemSlotsComponent, ComponentGetState>(GetItemSlotsState);
SubscribeLocalEvent<ItemSlotsComponent, ComponentHandleState>(HandleItemSlotsState);
}
@@ -139,7 +145,7 @@ namespace Content.Shared.Containers.ItemSlots
foreach (var slot in itemSlots.Slots.Values)
{
if (!CanInsert(args.UsedUid, slot, swap: true))
if (!CanInsert(uid, args.UsedUid, slot, swap: slot.Swap, popup: args.UserUid))
continue;
// Drop the held item onto the floor. Return if the user cannot drop.
@@ -174,7 +180,11 @@ namespace Content.Shared.Containers.ItemSlots
/// Check whether a given item can be inserted into a slot. Unless otherwise specified, this will return
/// false if the slot is already filled.
/// </summary>
public bool CanInsert(EntityUid uid, ItemSlot slot, bool swap = false)
/// <remarks>
/// If a popup entity is given, and if the item slot is set to generate a popup message when it fails to
/// pass the whitelist, then this will generate a popup.
/// </remarks>
public bool CanInsert(EntityUid uid, EntityUid usedUid, ItemSlot slot, bool swap = false, EntityUid? popup = null)
{
if (slot.Locked)
return false;
@@ -182,8 +192,12 @@ namespace Content.Shared.Containers.ItemSlots
if (!swap && slot.HasItem)
return false;
if (slot.Whitelist != null && !slot.Whitelist.IsValid(uid))
if (slot.Whitelist != null && !slot.Whitelist.IsValid(usedUid))
{
if (popup.HasValue && !string.IsNullOrWhiteSpace(slot.WhitelistFailPopup))
_popupSystem.PopupEntity(Loc.GetString(slot.WhitelistFailPopup), uid, Filter.Entities(popup.Value));
return false;
}
// We should also check ContainerSlot.CanInsert, but that prevents swapping interactions. Given that
// ContainerSlot.CanInsert gets called when the item is actually inserted anyways, we can just get away with
@@ -212,7 +226,30 @@ namespace Content.Shared.Containers.ItemSlots
/// <returns>False if failed to insert item</returns>
public bool TryInsert(EntityUid uid, ItemSlot slot, IEntity item)
{
if (!CanInsert(item.Uid, slot))
if (!CanInsert(uid, item.Uid, slot))
return false;
Insert(uid, slot, item);
return true;
}
/// <summary>
/// Tries to insert item into a specific slot from an entity's hand.
/// </summary>
/// <returns>False if failed to insert item</returns>
public bool TryInsertFromHand(EntityUid uid, ItemSlot slot, EntityUid user, SharedHandsComponent? hands = null)
{
if (!Resolve(user, ref hands, false))
return false;
if (!hands.TryGetActiveHeldEntity(out var item))
return false;
if (!CanInsert(uid, item.Uid, slot))
return false;
// hands.Drop(item) checks CanDrop action blocker
if (!_actionBlockerSystem.CanInteract(user) && hands.Drop(item))
return false;
Insert(uid, slot, item);
@@ -364,7 +401,7 @@ namespace Content.Shared.Containers.ItemSlots
foreach (var slot in itemSlots.Slots.Values)
{
if (!CanInsert(args.Using.Uid, slot))
if (!CanInsert(uid, args.Using.Uid, slot))
continue;
var verbSubject = slot.Name != string.Empty
@@ -397,6 +434,18 @@ namespace Content.Shared.Containers.ItemSlots
}
#endregion
/// <summary>
/// Eject items from (some) slots when the entity is destroyed.
/// </summary>
private void OnBreak(EntityUid uid, ItemSlotsComponent component, EntityEventArgs args)
{
foreach (var slot in component.Slots.Values)
{
if (slot.EjectOnBreak && slot.HasItem)
TryEject(uid, slot, out var _);
}
}
/// <summary>
/// Get the contents of some item slot.
/// </summary>