Implement human pockets and ID card slot correctly.
Pockets & ID need uniform equipped. Pockets accept any sufficiently small item.
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
using Robust.Server.GameObjects.Components.Container;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.Network;
|
||||
using Robust.Shared.Timers;
|
||||
using static Content.Shared.GameObjects.Components.Inventory.EquipmentSlotDefines;
|
||||
|
||||
namespace Content.Server.GameObjects
|
||||
{
|
||||
// Handles the special behavior of pockets/ID card slot and their relation to uniforms.
|
||||
[RegisterComponent]
|
||||
[ComponentReference(typeof(IInventoryController))]
|
||||
public class HumanInventoryControllerComponent : Component, IInventoryController
|
||||
{
|
||||
public override string Name => "HumanInventoryController";
|
||||
|
||||
private InventoryComponent _inventory;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
_inventory = Owner.GetComponent<InventoryComponent>();
|
||||
}
|
||||
|
||||
bool IInventoryController.CanEquip(Slots slot, IEntity entity, bool flagsCheck)
|
||||
{
|
||||
var slotMask = SlotMasks[slot];
|
||||
|
||||
if ((slotMask & (SlotFlags.POCKET | SlotFlags.IDCARD)) != SlotFlags.NONE)
|
||||
{
|
||||
// Can't wear stuff in ID card or pockets unless you have a uniform.
|
||||
if (_inventory.GetSlotItem(Slots.INNERCLOTHING) == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (slotMask == SlotFlags.POCKET)
|
||||
{
|
||||
var itemComponent = entity.GetComponent<ItemComponent>();
|
||||
|
||||
// If this item is small enough then it always fits in pockets.
|
||||
if (itemComponent.ObjectSize <= (int) ReferenceSizes.Pocket)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Standard flag check.
|
||||
return flagsCheck;
|
||||
}
|
||||
|
||||
public override void HandleMessage(ComponentMessage message, INetChannel netChannel = null, IComponent component = null)
|
||||
{
|
||||
base.HandleMessage(message, netChannel, component);
|
||||
|
||||
switch (message)
|
||||
{
|
||||
case ContainerContentsModifiedMessage contentsModified:
|
||||
Timer.Spawn(0, DropIdAndPocketsIfWeNoLongerHaveAUniform);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Hey, it's descriptive.
|
||||
private void DropIdAndPocketsIfWeNoLongerHaveAUniform()
|
||||
{
|
||||
if (_inventory.GetSlotItem(Slots.INNERCLOTHING) != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void DropMaybe(Slots slot)
|
||||
{
|
||||
if (_inventory.GetSlotItem(slot) != null)
|
||||
{
|
||||
_inventory.Unequip(slot);
|
||||
}
|
||||
}
|
||||
|
||||
DropMaybe(Slots.POCKET1);
|
||||
DropMaybe(Slots.POCKET2);
|
||||
DropMaybe(Slots.IDCARD);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using static Content.Shared.GameObjects.Components.Inventory.EquipmentSlotDefines;
|
||||
|
||||
namespace Content.Server.GameObjects
|
||||
{
|
||||
/// <summary>
|
||||
/// Allows for overriding inventory-related behavior on an entity.
|
||||
/// </summary>
|
||||
public interface IInventoryController
|
||||
{
|
||||
/// <summary>
|
||||
/// Can be implemented to override "can this item be equipped" behavior.
|
||||
/// </summary>
|
||||
/// <param name="slot">The slot to be equipped into.</param>
|
||||
/// <param name="entity">The entity to equip.</param>
|
||||
/// <param name="flagsCheck">Whether the entity passes default slot masks & flags checks.</param>
|
||||
/// <returns>True if the entity can be equipped, false otherwise</returns>
|
||||
bool CanEquip(Slots slot, IEntity entity, bool flagsCheck) => flagsCheck;
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,9 @@
|
||||
// Only unused on .NET Core due to KeyValuePair.Deconstruct
|
||||
// ReSharper disable once RedundantUsingDirective
|
||||
using Robust.Shared.Utility;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Shared.GameObjects;
|
||||
using Robust.Server.GameObjects.Components.Container;
|
||||
using Robust.Server.Interfaces.GameObjects;
|
||||
using Robust.Server.Interfaces.Player;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
@@ -92,30 +88,43 @@ namespace Content.Server.GameObjects
|
||||
/// This will fail if there is already an item in the specified slot.
|
||||
/// </remarks>
|
||||
/// <param name="slot">The slot to put the item in.</param>
|
||||
/// <param name="clothing">The item to insert into the slot.</param>
|
||||
/// <param name="item">The item to insert into the slot.</param>
|
||||
/// <returns>True if the item was successfully inserted, false otherwise.</returns>
|
||||
public bool Equip(Slots slot, ClothingComponent clothing)
|
||||
public bool Equip(Slots slot, ItemComponent item)
|
||||
{
|
||||
if (clothing == null)
|
||||
if (item == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(clothing),
|
||||
throw new ArgumentNullException(nameof(item),
|
||||
"Clothing must be passed here. To remove some clothing from a slot, use Unequip()");
|
||||
}
|
||||
|
||||
if (clothing.SlotFlags == SlotFlags.PREVENTEQUIP //Flag to prevent equipping at all
|
||||
|| (clothing.SlotFlags & SlotMasks[slot]) == 0
|
||||
) //Does the clothing flag have any of our requested slot flags
|
||||
var pass = false;
|
||||
|
||||
if (item is ClothingComponent clothing)
|
||||
{
|
||||
if (clothing.SlotFlags != SlotFlags.PREVENTEQUIP && (clothing.SlotFlags & SlotMasks[slot]) != 0)
|
||||
{
|
||||
pass = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (Owner.TryGetComponent(out IInventoryController controller))
|
||||
{
|
||||
pass = controller.CanEquip(slot, item.Owner, pass);
|
||||
}
|
||||
|
||||
if (!pass)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var inventorySlot = SlotContainers[slot];
|
||||
if (!inventorySlot.Insert(clothing.Owner))
|
||||
if (!inventorySlot.Insert(item.Owner))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
clothing.EquippedToSlot();
|
||||
item.EquippedToSlot();
|
||||
|
||||
Dirty();
|
||||
return true;
|
||||
@@ -256,7 +265,7 @@ namespace Content.Server.GameObjects
|
||||
{
|
||||
var hands = Owner.GetComponent<HandsComponent>();
|
||||
var activeHand = hands.GetActiveHand;
|
||||
if (activeHand != null && activeHand.Owner.TryGetComponent(out ClothingComponent clothing))
|
||||
if (activeHand != null && activeHand.Owner.TryGetComponent(out ItemComponent clothing))
|
||||
{
|
||||
hands.Drop(hands.ActiveIndex);
|
||||
if (!Equip(msg.Inventoryslot, clothing))
|
||||
|
||||
@@ -28,6 +28,8 @@ namespace Content.Shared.GameObjects
|
||||
|
||||
private static readonly Dictionary<Slots, int> _slotDrawingOrder = new Dictionary<Slots, int>
|
||||
{
|
||||
{Slots.POCKET1, 12},
|
||||
{Slots.POCKET2, 11},
|
||||
{Slots.HEAD, 10},
|
||||
{Slots.MASK, 9},
|
||||
{Slots.EARS, 8},
|
||||
@@ -46,7 +48,7 @@ namespace Content.Shared.GameObjects
|
||||
Slots.EYES, Slots.HEAD, Slots.EARS,
|
||||
Slots.OUTERCLOTHING, Slots.MASK, Slots.INNERCLOTHING,
|
||||
Slots.BACKPACK, Slots.BELT, Slots.GLOVES,
|
||||
Slots.NONE, Slots.SHOES, Slots.IDCARD
|
||||
Slots.NONE, Slots.SHOES, Slots.IDCARD, Slots.POCKET1, Slots.POCKET2
|
||||
};
|
||||
|
||||
public override int SlotDrawingOrder(Slots slot)
|
||||
|
||||
@@ -84,6 +84,7 @@
|
||||
- type: CharacterInfo
|
||||
- type: FootstepSound
|
||||
- type: HumanoidAppearance
|
||||
- type: HumanInventoryController
|
||||
|
||||
- type: entity
|
||||
save: false
|
||||
|
||||
Reference in New Issue
Block a user