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

@@ -1,7 +1,9 @@
using System;
using System.Collections.Generic;
using Content.Shared.Containers.ItemSlots;
using Robust.Shared.GameObjects;
using Robust.Shared.Serialization;
using Robust.Shared.Serialization.Manager.Attributes;
namespace Content.Shared.Access
{
@@ -12,6 +14,12 @@ namespace Content.Shared.Access
public const int MaxFullNameLength = 256;
public const int MaxJobTitleLength = 256;
[DataField("privilegedIdSlot")]
public ItemSlot PrivilegedIdSlot = new();
[DataField("targetIdSlot")]
public ItemSlot TargetIdSlot = new();
public enum UiButton
{
PrivilegedId,

View File

@@ -0,0 +1,33 @@
using Content.Shared.Containers.ItemSlots;
using JetBrains.Annotations;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
namespace Content.Shared.Access
{
[UsedImplicitly]
public abstract class SharedIdCardConsoleSystem : EntitySystem
{
[Dependency] private readonly ItemSlotsSystem _itemSlotsSystem = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<SharedIdCardConsoleComponent, ComponentInit>(OnComponentInit);
SubscribeLocalEvent<SharedIdCardConsoleComponent, ComponentRemove>(OnComponentRemove);
}
private void OnComponentInit(EntityUid uid, SharedIdCardConsoleComponent component, ComponentInit args)
{
_itemSlotsSystem.AddItemSlot(uid, $"{component.Name}-privilegedId", component.PrivilegedIdSlot);
_itemSlotsSystem.AddItemSlot(uid, $"{component.Name}-targetId", component.TargetIdSlot);
}
private void OnComponentRemove(EntityUid uid, SharedIdCardConsoleComponent component, ComponentRemove args)
{
_itemSlotsSystem.RemoveItemSlot(uid, component.PrivilegedIdSlot);
_itemSlotsSystem.RemoveItemSlot(uid, component.TargetIdSlot);
}
}
}

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Linq;
using JetBrains.Annotations;
using Robust.Shared.GameObjects;
@@ -17,15 +17,9 @@ namespace Content.Shared.Acts
void OnDestroy(DestructionEventArgs eventArgs);
}
public class DestructionEventArgs : EntityEventArgs
{
public EntityUid Owner { get; init; } = default!;
}
public class DestructionEventArgs : EntityEventArgs { }
public class BreakageEventArgs : EventArgs
{
public EntityUid Owner { get; init; } = default!;
}
public class BreakageEventArgs : EntityEventArgs { }
public interface IBreakAct
{
@@ -55,11 +49,9 @@ namespace Content.Shared.Acts
{
public void HandleDestruction(EntityUid owner)
{
var eventArgs = new DestructionEventArgs
{
Owner = owner
};
var eventArgs = new DestructionEventArgs();
RaiseLocalEvent(owner, eventArgs, false);
var destroyActs = EntityManager.GetComponents<IDestroyAct>(owner).ToList();
foreach (var destroyAct in destroyActs)
@@ -88,10 +80,8 @@ namespace Content.Shared.Acts
public void HandleBreakage(EntityUid owner)
{
var eventArgs = new BreakageEventArgs
{
Owner = owner,
};
var eventArgs = new BreakageEventArgs();
RaiseLocalEvent(owner, eventArgs, false);
var breakActs = EntityManager.GetComponents<IBreakAct>(owner).ToList();
foreach (var breakAct in breakActs)
{

View File

@@ -1,11 +1,11 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.Cloning;
using Content.Shared.Containers.ItemSlots;
using Content.Shared.FixedPoint;
using Robust.Shared.GameObjects;
using Robust.Shared.Serialization;
using Robust.Shared.Serialization.Manager.Attributes;
namespace Content.Shared.Chemistry.Components
{
@@ -15,6 +15,9 @@ namespace Content.Shared.Chemistry.Components
/// </summary>
public class SharedChemMasterComponent : Component
{
[DataField("beakerSlot")]
public ItemSlot BeakerSlot = new();
public override string Name => "ChemMaster";
public const string SolutionName = "buffer";

View File

@@ -1,9 +1,11 @@
using System;
using System;
using System.Collections.Generic;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.Containers.ItemSlots;
using Content.Shared.FixedPoint;
using Robust.Shared.GameObjects;
using Robust.Shared.Serialization;
using Robust.Shared.Serialization.Manager.Attributes;
namespace Content.Shared.Chemistry.Dispenser
{
@@ -17,6 +19,9 @@ namespace Content.Shared.Chemistry.Dispenser
{
public override string Name => "ReagentDispenser";
[DataField("beakerSlot")]
public ItemSlot BeakerSlot = new();
/// <summary>
/// A list of reagents which this may dispense. Defined in yaml prototype, see <see cref="ReagentDispenserInventoryPrototype"/>.
/// </summary>

View File

@@ -0,0 +1,32 @@
using JetBrains.Annotations;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Content.Shared.Containers.ItemSlots;
using Content.Shared.Chemistry.Components;
namespace Content.Shared.Chemistry.EntitySystems
{
[UsedImplicitly]
public abstract class SharedChemMasterSystem : EntitySystem
{
[Dependency] private readonly ItemSlotsSystem _itemSlotsSystem = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<SharedChemMasterComponent, ComponentInit>(OnComponentInit);
SubscribeLocalEvent<SharedChemMasterComponent, ComponentRemove>(OnComponentRemove);
}
private void OnComponentInit(EntityUid uid, SharedChemMasterComponent component, ComponentInit args)
{
_itemSlotsSystem.AddItemSlot(uid, $"{component.Name}-beaker", component.BeakerSlot);
}
private void OnComponentRemove(EntityUid uid, SharedChemMasterComponent component, ComponentRemove args)
{
_itemSlotsSystem.RemoveItemSlot(uid, component.BeakerSlot);
}
}
}

View File

@@ -0,0 +1,32 @@
using JetBrains.Annotations;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Content.Shared.Containers.ItemSlots;
using Content.Shared.Chemistry.Dispenser;
namespace Content.Shared.Chemistry.EntitySystems
{
[UsedImplicitly]
public abstract class SharedReagentDispenserSystem : EntitySystem
{
[Dependency] private readonly ItemSlotsSystem _itemSlotsSystem = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<SharedReagentDispenserComponent, ComponentInit>(OnComponentInit);
SubscribeLocalEvent<SharedReagentDispenserComponent, ComponentRemove>(OnComponentRemove);
}
private void OnComponentInit(EntityUid uid, SharedReagentDispenserComponent component, ComponentInit args)
{
_itemSlotsSystem.AddItemSlot(uid, $"{component.Name}-beaker", component.BeakerSlot);
}
private void OnComponentRemove(EntityUid uid, SharedReagentDispenserComponent component, ComponentRemove args)
{
_itemSlotsSystem.RemoveItemSlot(uid, component.BeakerSlot);
}
}
}

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>