Make chemistry machines and IdCardConsole use item slots (#5428)
* chemistry item slots * item slots id card console
This commit is contained in:
@@ -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,
|
||||
|
||||
33
Content.Shared/Access/SharedIdCardConsoleSystem.cs
Normal file
33
Content.Shared/Access/SharedIdCardConsoleSystem.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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";
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user